From 5a1466d35520b9e6c72f3e54114e9c1b62a8c2f6 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Wed, 11 Jun 2025 15:10:10 -0400 Subject: [PATCH] xwayland: handle rare case of focus_in event occurring before map This fixes a timing-dependent issue where the CLion main window was sometimes not correctly focused at startup. --- include/xwayland.h | 1 + src/xwayland.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/xwayland.h b/include/xwayland.h index c202d37d..b5bd2623 100644 --- a/include/xwayland.h +++ b/include/xwayland.h @@ -39,6 +39,7 @@ struct xwayland_unmanaged { struct xwayland_view { struct view base; struct wlr_xwayland_surface *xwayland_surface; + bool focused_before_map; /* Events unique to XWayland views */ struct wl_listener associate; diff --git a/src/xwayland.c b/src/xwayland.c index 7a4aed9b..dfc38add 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -587,6 +587,25 @@ handle_focus_in(struct wl_listener *listener, void *data) wl_container_of(listener, xwayland_view, focus_in); struct view *view = &xwayland_view->base; struct seat *seat = &view->server->seat; + + if (!view->surface) { + /* + * It is rare but possible for the focus_in event to be + * received before the map event. This has been seen + * during CLion startup, when focus is initially offered + * to the splash screen but accepted later by the main + * window instead. (In this case, the focus transfer is + * client-initiated but allowed by wlroots because the + * same PID owns both windows.) + * + * Set a flag to record this condition, and update the + * seat focus later when the view is actually mapped. + */ + wlr_log(WLR_DEBUG, "focus_in received before map"); + xwayland_view->focused_before_map = true; + return; + } + if (view->surface != seat->seat->keyboard_state.focused_surface) { seat_focus_surface(seat, view->surface); } @@ -805,6 +824,18 @@ xwayland_view_map(struct view *view) wl_signal_add(&xwayland_surface->surface->events.commit, &view->commit); view->commit.notify = handle_commit; + /* + * If the view was focused (on the xwayland server side) before + * being mapped, update the seat focus now. Note that this only + * really matters in the case of Globally Active input windows. + * In all other cases, it's redundant since view_impl_map() + * results in the view being focused anyway. + */ + if (xwayland_view->focused_before_map) { + xwayland_view->focused_before_map = false; + seat_focus_surface(&view->server->seat, view->surface); + } + view_impl_map(view); view->been_mapped = true; -- 2.52.0