wayland: Phase 62 — mapped flag, focus lifecycle, and keyboard clear-focus
Three related fixes to make the WM focus lifecycle work end-to-end in the Wayland path: 1. window.c: set wwin->flags.mapped=1 for Wayland windows (the wWindowMap call in wManageWindow is guarded by if(wwin->frame) which is NULL in Wayland, leaving mapped=0 and causing wSetFocusTo to take the no-focus branch immediately). 2. screen.c: call screen_create_internals in the Wayland goto path; this was skipped by goto screen_done but is needed to set auto_focus=1 and clear initial keyboard focus via wlr_seat. 3. wl_backend.c: implement wl_screen_create_internals (sets no_focus_win=WNATIVE_NONE, auto_focus=1, clears seat focus); wl_focus_set now calls wlr_seat_keyboard_clear_focus and logs "focus_clear" when win==WNATIVE_NONE; remove the redundant direct wl_focus_set call from handle_toplevel_map since wManageWindow now handles focus via wSetFocusTo. Smoke test: add check 20 verifying "focus_clear" is logged after the last managed window unmaps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
04f8a46ae5
commit
6764c14863
|
|
@ -43,6 +43,10 @@
|
|||
* misc.c getCommandForWindow uses the vtable on the Wayland path.
|
||||
* Phase 58: stacking_raise/lower/restack manipulate toplevel_list Z-order;
|
||||
* stacking_query enumerates IDs in order (returns 1 to suppress warning).
|
||||
* Phase 62: wl_screen_create_internals initialises no_focus_win=WNATIVE_NONE
|
||||
* and calls wlr_seat_keyboard_clear_focus; wl_focus_set recognises
|
||||
* WNATIVE_NONE as "clear focus" and calls wlr_seat_keyboard_clear_focus
|
||||
* instead of delivering focus to a nonexistent surface.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
|
@ -242,8 +246,9 @@ handle_toplevel_map(struct wl_listener *listener, void *data)
|
|||
wwin->wm_class ? wwin->wm_class : "(none)",
|
||||
wwin->wm_instance ? wwin->wm_instance : "(none)",
|
||||
wwin->client.width, wwin->client.height, pid);
|
||||
/* Phase 43: focus the newly mapped toplevel. */
|
||||
wl_focus_set(view->id, 0, 0);
|
||||
/* Phase 62: focus delivered by wManageWindow via wSetFocusTo
|
||||
* (auto_focus=1 set in wl_screen_create_internals); the
|
||||
* direct wl_focus_set() call is no longer needed here. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -641,10 +646,16 @@ wl_context_delete(WNativeWindow win, WContextKey key)
|
|||
static void
|
||||
wl_focus_set(WNativeWindow win, int revert_to, unsigned long timestamp)
|
||||
{
|
||||
/* Phase 43: deliver keyboard focus to the XDG toplevel surface. */
|
||||
/* Phase 43/62: deliver keyboard focus to the XDG toplevel, or clear it. */
|
||||
(void)revert_to; (void)timestamp;
|
||||
if (!wl_state.seat || !wl_state.keyboard_dev)
|
||||
return;
|
||||
/* Phase 62: WNATIVE_NONE == no_focus_win means "clear keyboard focus". */
|
||||
if (win == WNATIVE_NONE) {
|
||||
wlr_seat_keyboard_clear_focus(wl_state.seat);
|
||||
wwarning("wl_backend: focus_clear");
|
||||
return;
|
||||
}
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v || !v->xdg_surface || !v->xdg_surface->surface)
|
||||
return;
|
||||
|
|
@ -1193,7 +1204,19 @@ static void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr;
|
|||
static void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }
|
||||
static void wl_screen_setup_noticeboard(WScreen *scr) { (void)scr; }
|
||||
static void wl_screen_alloc_gcs(WScreen *scr) { (void)scr; }
|
||||
static void wl_screen_create_internals(WScreen *scr) { (void)scr; }
|
||||
static void
|
||||
wl_screen_create_internals(WScreen *scr)
|
||||
{
|
||||
/* Phase 62: no_focus_win sentinel — WNATIVE_NONE (0) is the Wayland
|
||||
* equivalent of the X11 InputOnly grab window. Clear keyboard focus
|
||||
* from the seat so the WM starts in the "nobody focused" state.
|
||||
* Enable auto_focus so wManageWindow calls wSetFocusTo for new windows,
|
||||
* ensuring wwin->flags.focused and the full WM focus lifecycle work. */
|
||||
scr->no_focus_win = WNATIVE_NONE;
|
||||
wPreferences.auto_focus = 1;
|
||||
if (wl_state.seat)
|
||||
wlr_seat_keyboard_clear_focus(wl_state.seat);
|
||||
}
|
||||
static void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; }
|
||||
static void wl_screen_load_tech_font(WScreen *scr) { (void)scr; }
|
||||
static void wl_screen_show_mini_screenshot(WScreen *scr, RImage *img) { (void)scr; (void)img; }
|
||||
|
|
|
|||
|
|
@ -169,6 +169,11 @@ WScreen *wScreenInit(int screen_number)
|
|||
scr->workspaces = wmalloc(sizeof(WWorkspace *));
|
||||
scr->workspaces[0] = wspace;
|
||||
scr->workspace_count = 1;
|
||||
/* Phase 62: run backend screen internals (sets no_focus_win,
|
||||
* auto_focus, clears keyboard focus) before leaving the Wayland
|
||||
* fast path — screen_create_internals is normally called at
|
||||
* line 248 which the goto would skip. */
|
||||
wm_backend->screen_create_internals(scr);
|
||||
goto screen_done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1246,6 +1246,8 @@ WWindow *wManageWindow(WScreen *scr, WNativeWindow window)
|
|||
|
||||
if (wwin->frame)
|
||||
wWindowMap(wwin);
|
||||
else if (!dpy)
|
||||
wwin->flags.mapped = 1; /* Wayland: toplevel is visible by definition */
|
||||
}
|
||||
|
||||
/* setup stacking descriptor */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@
|
|||
# 19. (Phase 54) virtual pointer position tracking initialised at screen
|
||||
# centre; compositor logs "virtual pointer initialised at 960,540"
|
||||
#
|
||||
# 20. (Phase 62) wl_screen_create_internals sets no_focus_win=WNATIVE_NONE;
|
||||
# wl_focus_set(WNATIVE_NONE) calls wlr_seat_keyboard_clear_focus and logs
|
||||
# "focus_clear" when the last managed window unmaps.
|
||||
#
|
||||
# This test grows as wl_backend vtable slots are implemented.
|
||||
#
|
||||
# Exit 0 = PASS, non-zero = FAIL.
|
||||
|
|
@ -224,6 +228,11 @@ if command -v weston-simple-shm >/dev/null 2>&1; then
|
|||
|| die "compositor did not log a valid pid= for managed toplevel"
|
||||
echo " pid check: client PID=$PID retrieved via wl_client_get_credentials"
|
||||
|
||||
# -- 16b. Phase 62: keyboard focus cleared after last window unmaps ---
|
||||
grep -q 'focus_clear' /tmp/wl-smoke-stderr \
|
||||
|| die "compositor did not log 'focus_clear' (wl_focus_set WNATIVE_NONE path not reached)"
|
||||
echo " focus_clear check: keyboard focus cleared after last window unmap"
|
||||
|
||||
# -- 15. Phase 51: two simultaneous clients both managed --------------
|
||||
#
|
||||
# Launch two weston-simple-shm processes in parallel (2s and 3s).
|
||||
|
|
|
|||
Loading…
Reference in New Issue