input: workaround GNOME messing up pointer leave/enter after moving window

GNOME doesn’t send pointer enter after finishing a window move.

In subsequent move operations, it is also possible to make it skip sending
pointer leave when starting the move operations.

This caused foot to assert in debug builds, and add the same button multiple
times to the list of buttons currently being pressed.
This commit is contained in:
Daniel Eklöf 2021-08-04 17:27:34 +02:00
parent a3cd8ebf3c
commit a21bf1b4d9
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

48
input.c
View file

@ -1019,12 +1019,12 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial,
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
char sym_name[100];
xkb_keysym_get_name(sym, sym_name, sizeof(sym_name));
#endif
LOG_DBG("%s (%u/0x%x): seat=%s, term=%p, serial=%u, "
"mods=0x%08x, consumed=0x%08x, repeats=%d",
sym_name, sym, sym, seat->name, (void *)term, serial,
mods, consumed, should_repeat);
#endif
/*
* User configurable bindings
@ -1360,6 +1360,8 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
LOG_DBG("pointer-enter: pointer=%p, serial=%u, surface = %p, new-moused = %p",
(void *)wl_pointer, serial, (void *)surface, (void *)term);
xassert(tll_length(seat->mouse.buttons) == 0);
/* Scale may have changed */
wayl_reload_xcursor_theme(seat, term->scale);
@ -1691,6 +1693,50 @@ fdm_csd_move(struct fdm *fdm, int fd, int events, void *data)
struct wl_window *win = seat->mouse_focus->window;
/*
* Workaround GNOME bug
*
* Dragging the window, then stopping the drag (releasing the
* mouse button), *without* moving the mouse, and then clicking
* twice, waiting for the CSD timer, and finally clicking once
* more, results in the follwing sequence (keyboard and other
* irrelevant events filtered out, unless theyre needed to prove
* a point):
*
* dbg: input.c:1551: cancelling drag timer, moving window
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=873, surface=0x6070000036d0
* dbg: input.c:1432: seat0: pointer-leave: pointer=0x607000003660, serial=874, surface = 0x6070000396e0, old-moused = 0x622000006100
*
* --> drag stopped here
*
* --> LMB clicked first time after the drag (generates the enter event on *release*, but no button events)
* dbg: input.c:1360: pointer-enter: pointer=0x607000003660, serial=876, surface = 0x6070000396e0, new-moused = 0x622000006100
*
* --> LMB clicked, and held until the timer times out, second time after the drag
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=877, button=110, state=1
* dbg: input.c:1806: starting move timer
* dbg: input.c:1692: move timer timed out
* dbg: input.c:759: keyboard_leave: keyboard=0x607000003580, serial=878, surface=0x6070000036d0
*
* --> NOTE: ^^ no pointer leave event this time, only the keyboard leave
*
* --> LMB clicked one last time
* dbg: input.c:697: seat0: keyboard_enter: keyboard=0x607000003580, serial=879, surface=0x6070000036d0
* dbg: input.c:1712: BUTTON: pointer=0x607000003660, serial=880, button=110, state=1
* err: input.c:1741: BUG in wl_pointer_button(): assertion failed: 'it->item.button != button'
*
* What are we seeing?
*
* - GNOME does *not* send a pointer *enter* event after the drag
* has stopped
* - The second drag does *not* generate a pointer *leave* event
* - The missing leave event means were still tracking LMB as
* being held down in our seat struct.
* - This leads to an assert (debug builds) when LMB is clicked
* again (seats button list already contains LMB).
*/
tll_free(seat->mouse.buttons);
win->csd.move_timeout_fd = -1;
xdg_toplevel_move(win->xdg_toplevel, seat->wl_seat, win->csd.serial);
return true;