From a3913b045dca49772d2e4037ed02086a025fe773 Mon Sep 17 00:00:00 2001 From: Riteo Date: Wed, 14 May 2025 23:17:43 +0200 Subject: [PATCH] Wayland: Fix stuck pointer buttons on window leave This issue came from the frame-based refactoring done in the multiwin PR. It looks like some (all?) compositors group certain events alongside `wl_pointer::leave`, which I absolutely did not expect. The docs don't seem to mention it either from what I can tell. We now fall-back on the old pointed window if and only if the current window is invalid and the old one isn't. Each state fetch is guarded with an `ERR_FAIL_NULL` so this should still catch any potentially corrupted window with missing data but a valid ID. I also added the usual big comment so that this "quirk" does not get lost to time. --- platform/linuxbsd/wayland/wayland_thread.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 4f5a08e96b6..0b90ee293d7 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -1692,16 +1692,28 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point } } - if (pd.pointed_id == DisplayServer::INVALID_WINDOW_ID) { + WindowState *ws = nullptr; + + // NOTE: At least on sway, with wl_pointer version 5 or greater, + // wl_pointer::leave might be emitted with other events (like + // wl_pointer::button) within the same wl_pointer::frame. Because of this, we + // need to account for when the currently pointed window might be invalid + // (third-party or even none) and fall back to the old one. + if (pd.pointed_id != DisplayServer::INVALID_WINDOW_ID) { + ws = ss->wayland_thread->window_get_state(pd.pointed_id); + ERR_FAIL_NULL(ws); + } else if (old_pd.pointed_id != DisplayServer::INVALID_WINDOW_ID) { + ws = ss->wayland_thread->window_get_state(old_pd.pointed_id); + ERR_FAIL_NULL(ws); + } + + if (ws == nullptr) { // We're probably on a decoration or some other third-party thing. Let's // "commit" the data and call it a day. old_pd = pd; return; } - WindowState *ws = ss->wayland_thread->window_get_state(pd.pointed_id); - ERR_FAIL_NULL(ws); - double scale = window_state_get_scale_factor(ws); wayland_thread->_set_current_seat(ss->wl_seat);