wayland: Phase 43 — focus_set delivers keyboard focus via wlr_seat
Create a headless keyboard input device during wl_display_open and attach it to wlr_seat so wlr_seat_keyboard_notify_enter() can deliver keyboard focus to XDG toplevel surfaces. Implement wl_focus_set: look up the view by synthetic ID, call wlr_seat_keyboard_notify_enter with the xdg_surface->surface. Call wl_focus_set from handle_toplevel_map immediately after wManageWindow so newly mapped toplevels receive keyboard focus. Smoke test: add Phase 43 check — grep "focus_set id=" in stderr. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d9a70e9177
commit
0fe2960995
|
|
@ -21,6 +21,8 @@
|
|||
* Phase 41: prop_get_wm_class and window_fetch_name return XDG app_id/title.
|
||||
* Phase 42: window_get_client_attrs returns WCLIENT_VIEWABLE + surface
|
||||
* geometry for mapped XDG toplevels.
|
||||
* Phase 43: focus_set delivers keyboard focus via wlr_seat; headless keyboard
|
||||
* device created and attached to seat; mapped toplevels auto-focused.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
@ -42,6 +44,7 @@
|
|||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/box.h>
|
||||
/* Generated xdg-shell protocol implementation (Wayland glue code) */
|
||||
|
|
@ -107,6 +110,8 @@ struct wl_compositor_state {
|
|||
struct wl_list toplevel_list; /* wl_toplevel_view.link */
|
||||
struct wl_list ctx_lists[3]; /* one per WContextKey */
|
||||
unsigned long next_synthetic_id; /* >= 0x10000000 */
|
||||
/* Phase 43: headless keyboard device for seat keyboard focus */
|
||||
struct wlr_input_device *keyboard_dev;
|
||||
char socket_name[64]; /* Phase 34: e.g. "wayland-0" */
|
||||
int started; /* non-zero after successful display_open */
|
||||
};
|
||||
|
|
@ -135,6 +140,9 @@ frame_timer_cb(void *data)
|
|||
#define VIEW_FROM_LISTENER(ptr, field) \
|
||||
((struct wl_toplevel_view *)((char *)(ptr) - offsetof(struct wl_toplevel_view, field)))
|
||||
|
||||
/* Phase 43: forward declaration — defined in the focus section below. */
|
||||
static void wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp);
|
||||
|
||||
/* Phase 41: look up the view for a given synthetic WNativeWindow ID. */
|
||||
static struct wl_toplevel_view *
|
||||
wl_find_view_by_id(WNativeWindow id)
|
||||
|
|
@ -166,13 +174,16 @@ handle_toplevel_map(struct wl_listener *listener, void *data)
|
|||
WScreen *scr = wScreenWithNumber(0);
|
||||
if (scr) {
|
||||
WWindow *wwin = wManageWindow(scr, view->id);
|
||||
if (wwin)
|
||||
if (wwin) {
|
||||
wwarning("wl_backend: wManageWindow succeeded id=0x%lx "
|
||||
"class=%s name=%s geo=%dx%d",
|
||||
view->id,
|
||||
wwin->wm_class ? wwin->wm_class : "(none)",
|
||||
wwin->wm_instance ? wwin->wm_instance : "(none)",
|
||||
wwin->client.width, wwin->client.height);
|
||||
/* Phase 43: focus the newly mapped toplevel. */
|
||||
wl_focus_set(view->id, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -342,6 +353,15 @@ wl_display_open(const char *name)
|
|||
if (wl_state.output)
|
||||
wlr_output_create_global(wl_state.output);
|
||||
|
||||
/* Phase 43: create a headless keyboard and attach it to the seat so
|
||||
* wlr_seat_keyboard_notify_enter() can deliver keyboard focus. */
|
||||
wl_state.keyboard_dev =
|
||||
wlr_headless_add_input_device(wl_state.backend, WLR_INPUT_DEVICE_KEYBOARD);
|
||||
if (wl_state.keyboard_dev) {
|
||||
wlr_seat_set_keyboard(wl_state.seat, wl_state.keyboard_dev);
|
||||
wlr_seat_set_capabilities(wl_state.seat, WL_SEAT_CAPABILITY_KEYBOARD);
|
||||
}
|
||||
|
||||
/* Phase 38: initialise per-toplevel tracking and context store. */
|
||||
wl_list_init(&wl_state.toplevel_list);
|
||||
{
|
||||
|
|
@ -533,7 +553,19 @@ wl_context_delete(WNativeWindow win, WContextKey key)
|
|||
|
||||
static void
|
||||
wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp)
|
||||
{ (void)win; (void)revert_to; (void)timestamp; }
|
||||
{
|
||||
/* Phase 43: deliver keyboard focus to the XDG toplevel surface. */
|
||||
(void)revert_to; (void)timestamp;
|
||||
if (!wl_state.seat || !wl_state.keyboard_dev)
|
||||
return;
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v || !v->xdg_surface || !v->xdg_surface->surface)
|
||||
return;
|
||||
wlr_seat_keyboard_notify_enter(wl_state.seat,
|
||||
v->xdg_surface->surface,
|
||||
NULL, 0, NULL);
|
||||
wwarning("wl_backend: focus_set id=0x%lx", win);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Key / button grabs */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
# succeeded" log includes class=org.freedesktop.weston.simple-shm
|
||||
# 12. (Phase 42) window_get_client_attrs returns WCLIENT_VIEWABLE + geometry:
|
||||
# "wManageWindow succeeded" log includes geo= with non-zero size
|
||||
# 13. (Phase 43) focus_set delivers keyboard focus via wlr_seat: compositor
|
||||
# logs "focus_set id=" after wManageWindow succeeds
|
||||
#
|
||||
# This test grows as wl_backend vtable slots are implemented.
|
||||
#
|
||||
|
|
@ -177,6 +179,11 @@ if command -v weston-simple-shm >/dev/null 2>&1; then
|
|||
GEO=$(grep -o 'geo=[0-9]*x[0-9]*' /tmp/wl-smoke-stderr | head -1)
|
||||
[ -n "$GEO" ] || die "wManageWindow did not log geo= geometry"
|
||||
echo " geometry check: client geometry logged as $GEO"
|
||||
|
||||
# -- 13. Phase 43: keyboard focus delivered to toplevel --------------
|
||||
grep -q 'focus_set id=' /tmp/wl-smoke-stderr \
|
||||
|| die "compositor did not log focus_set (keyboard focus not delivered)"
|
||||
echo " focus check: keyboard focus delivered to mapped toplevel"
|
||||
else
|
||||
echo " client check: skipped (weston-simple-shm not installed)"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue