From 1b937ed2471393940b994a8aacbe5e0f2f84fc13 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Wed, 11 Jun 2025 15:40:37 -0400 Subject: [PATCH] xwayland: correctly return seat focus from menus/tooltips in CLion CLion's main window uses the Globally Active input model, and since 8fb2ecefcbd6 it is given focus asynchronously via view_offer_focus(). However, we need to return seat focus immediately after an unmanaged surface (e.g. popup) is unmapped, or focus is lost completely. --- src/xwayland-unmanaged.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index d45937e4..2fc15cfe 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -89,11 +89,29 @@ focus_next_surface(struct server *server, struct wlr_xwayland_surface *xsurface) } /* - * If we don't find a surface to focus fall back - * to the topmost mapped view. This fixes dmenu - * not giving focus back when closed with ESC. + * Unmanaged surfaces do not clear the active view when mapped. + * Therefore, we can simply give the focus back to the active + * view when the last unmanaged surface is unmapped. + * + * Also note that resetting the focus here is only on the + * compositor side. On the xwayland server side, focus is never + * given to unmanaged surfaces to begin with - keyboard grabs + * are used instead. + * + * In the case of Globally Active input windows, calling + * view_offer_focus() at this point is both unnecessary and + * insufficient, since it doesn't update the seat focus + * immediately and ultimately results in a loss of focus. + * + * For the above reasons, we avoid calling desktop_focus_view() + * here and instead call seat_focus_surface() directly. + * + * If modifying this logic, please test for regressions with + * menus/tooltips in JetBrains CLion or similar. */ - desktop_focus_topmost_view(server); + if (server->active_view) { + seat_focus_surface(&server->seat, server->active_view->surface); + } } static void @@ -209,9 +227,12 @@ handle_request_activate(struct wl_listener *listener, void *data) /* * Validate that the unmanaged surface trying to grab focus is actually - * a child of the topmost mapped view before granting the request. + * a child of the active view before granting the request. + * + * FIXME: this logic is a bit incomplete/inconsistent. Refer to + * https://github.com/labwc/labwc/discussions/2821 for more info. */ - struct view *view = desktop_topmost_focusable_view(server); + struct view *view = server->active_view; if (view && view->type == LAB_XWAYLAND_VIEW) { struct wlr_xwayland_surface *surf = wlr_xwayland_surface_try_from_wlr_surface(view->surface); -- 2.52.0