diff --git a/CHANGELOG.md b/CHANGELOG.md index cf13d300..57984c49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,12 @@ ### Deprecated ### Removed ### Fixed + +* Added workaround for GNOME bug where multiple button press events + (for the same button) is sent to the CSDs without any release or + leave events in between (https://codeberg.org/dnkl/foot/issues/709). + + ### Security ### Contributors diff --git a/input.c b/input.c index ec76c42a..853bc495 100644 --- a/input.c +++ b/input.c @@ -1694,50 +1694,6 @@ 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 following sequence (keyboard and other - * irrelevant events filtered out, unless they’re 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 we’re still tracking LMB as - * being held down in our seat struct. - * - This leads to an assert (debug builds) when LMB is clicked - * again (seat’s 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; @@ -1774,6 +1730,62 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, } else seat->mouse.count = 1; + /* + * 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 following sequence + * (keyboard and other irrelevant events filtered out, unless + * they’re 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 we’re still tracking LMB as + * being held down in our seat struct. + * - This leads to an assert (debug builds) when LMB is clicked + * again (seat’s button list already contains LMB). + * + * Note: I’ve also observed variants of the above + */ + tll_foreach(seat->mouse.buttons, it) { + if (it->item.button == button) { + LOG_WARN("multiple button press events for button %d " + "(compositor bug?)", button); + tll_remove(seat->mouse.buttons, it); + break; + } + } + #if defined(_DEBUG) tll_foreach(seat->mouse.buttons, it) xassert(it->item.button != button); @@ -1817,7 +1829,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer, * 4. Release mouse button * 5. BAM! */ - LOG_WARN("stray button release event"); + LOG_WARN("stray button release event (compositor bug?)"); return; }