From 4819f47f980a4138dc81fb03f004bd5584c1c067 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Thu, 29 Jan 2026 18:00:43 +0900 Subject: [PATCH] cycle: fix spurious focus changes on finishing window switcher As described in the `FIXME` comment in `cycle.c`, we had spurious focus changes where the keyboard focus is momentarily given to the previously focused window when finishing the window switcher, an then it is given to the selected window. This commit fixes this by adding a parameter in `seat_focus_override_end()` to avoid restoring the focus to the previously focused window. I also removed the check for `!seat->seat->keyboard_state.focused_surface` in `seat_focus_override_end()`. I thought it was necessary to avoid updating the keyboard focus if the focus was given to a session-lock surface before e.g. finishing window switching, but `seat_focus()` is no-op in that case anyway. --- include/labwc.h | 6 +++--- src/cycle/cycle.c | 3 +-- src/interactive.c | 2 +- src/menu/menu.c | 4 ++-- src/seat.c | 8 +++++--- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index c4848a11..5503af6a 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -397,10 +397,10 @@ void seat_output_layout_changed(struct seat *seat); void seat_focus_override_begin(struct seat *seat, enum input_mode input_mode, enum lab_cursors cursor_shape); /* - * Restore the pointer/keyboard focus which was cleared in - * seat_focus_override_begin(). + * If restore_focus=true, restore the pointer/keyboard focus which was cleared + * in seat_focus_override_begin(). */ -void seat_focus_override_end(struct seat *seat); +void seat_focus_override_end(struct seat *seat, bool restore_focus); /** * interactive_anchor_to_cursor() - repositions the geometry to remain diff --git a/src/cycle/cycle.c b/src/cycle/cycle.c index 2a6f1e86..cec5cac5 100644 --- a/src/cycle/cycle.c +++ b/src/cycle/cycle.c @@ -204,8 +204,7 @@ cycle_finish(struct server *server, bool switch_focus) struct view *selected_view = server->cycle.selected_view; destroy_cycle(server); - /* FIXME: this sets focus to the old surface even with switch_focus=true */ - seat_focus_override_end(&server->seat); + seat_focus_override_end(&server->seat, /*restore_focus*/ false); /* Hiding OSD may need a cursor change */ cursor_update_focus(server); diff --git a/src/interactive.c b/src/interactive.c index 339f974f..88abdbd9 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -325,5 +325,5 @@ interactive_cancel(struct view *view) view->server->grabbed_view = NULL; /* Restore keyboard/pointer focus */ - seat_focus_override_end(&view->server->seat); + seat_focus_override_end(&view->server->seat, /*restore_focus*/ true); } diff --git a/src/menu/menu.c b/src/menu/menu.c index 74b9b4eb..b1dac1d8 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -1430,7 +1430,7 @@ menu_execute_item(struct menuitem *item) struct server *server = item->parent->server; menu_close(server->menu_current); server->menu_current = NULL; - seat_focus_override_end(&server->seat); + seat_focus_override_end(&server->seat, /*restore_focus*/ true); /* * We call the actions after closing the menu so that virtual keyboard @@ -1533,7 +1533,7 @@ menu_close_root(struct server *server) menu_close(server->menu_current); server->menu_current = NULL; reset_pipemenus(server); - seat_focus_override_end(&server->seat); + seat_focus_override_end(&server->seat, /*restore_focus*/ true); } void diff --git a/src/seat.c b/src/seat.c index a5cdf3ee..b19ff88a 100644 --- a/src/seat.c +++ b/src/seat.c @@ -902,12 +902,12 @@ seat_focus_override_begin(struct seat *seat, enum input_mode input_mode, } void -seat_focus_override_end(struct seat *seat) +seat_focus_override_end(struct seat *seat, bool restore_focus) { seat->server->input_mode = LAB_INPUT_STATE_PASSTHROUGH; if (seat->focus_override.surface) { - if (!seat->seat->keyboard_state.focused_surface) { + if (restore_focus) { seat_focus(seat, seat->focus_override.surface, /*replace_exclusive_layer*/ false, /*is_lock_surface*/ false); @@ -916,5 +916,7 @@ seat_focus_override_end(struct seat *seat) seat->focus_override.surface = NULL; } - cursor_update_focus(seat->server); + if (restore_focus) { + cursor_update_focus(seat->server); + } }