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.
This commit is contained in:
Riteo 2025-05-14 23:17:43 +02:00
parent 19bb18716e
commit a3913b045d

View file

@ -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);