diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index ea0fd3b..000de03 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -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 #include #include +#include #include #include /* 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 */ diff --git a/tests/wl-smoke-test.sh b/tests/wl-smoke-test.sh index 3faa3ce..d6ee4be 100755 --- a/tests/wl-smoke-test.sh +++ b/tests/wl-smoke-test.sh @@ -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