From 8730ca9661eaaab83954bca033745b65c60cf4f8 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Mon, 5 Aug 2024 18:28:20 +0300 Subject: [PATCH] seat/pointer: handle duplicate presses/releases correctly --- backend/libinput/pointer.c | 10 ---------- include/wlr/types/wlr_seat.h | 8 +++++++- types/seat/wlr_seat_pointer.c | 35 +++++++++++++++++++++++++++++------ 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 1fe3d479..703ad7b3 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -61,22 +61,12 @@ void handle_pointer_button(struct libinput_event *event, .time_msec = usec_to_msec(libinput_event_pointer_get_time_usec(pevent)), .button = libinput_event_pointer_get_button(pevent), }; - // Ignore events which aren't a seat-wide state change. For instance, if - // the same button is pressed twice on the same seat, ignore the second - // press. - uint32_t seat_count = libinput_event_pointer_get_seat_button_count(pevent); switch (libinput_event_pointer_get_button_state(pevent)) { case LIBINPUT_BUTTON_STATE_PRESSED: wlr_event.state = WL_POINTER_BUTTON_STATE_PRESSED; - if (seat_count != 1) { - return; - } break; case LIBINPUT_BUTTON_STATE_RELEASED: wlr_event.state = WL_POINTER_BUTTON_STATE_RELEASED; - if (seat_count != 0) { - return; - } break; } wl_signal_emit_mutable(&pointer->events.button, &wlr_event); diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 24ed5c92..c04cd5e0 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -172,6 +172,11 @@ struct wlr_seat_pointer_grab { #define WLR_POINTER_BUTTONS_CAP 16 +struct wlr_seat_pointer_button { + uint32_t button; + size_t n_pressed; +}; + struct wlr_seat_pointer_state { struct wlr_seat *seat; struct wlr_seat_client *focused_client; @@ -184,8 +189,9 @@ struct wlr_seat_pointer_state { bool sent_axis_source; enum wl_pointer_axis_source cached_axis_source; - uint32_t buttons[WLR_POINTER_BUTTONS_CAP]; + struct wlr_seat_pointer_button buttons[WLR_POINTER_BUTTONS_CAP]; size_t button_count; + uint32_t grab_button; uint32_t grab_serial; uint32_t grab_time; diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 9618d52b..15075f61 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -6,7 +6,6 @@ #include #include #include "types/wlr_seat.h" -#include "util/set.h" static void default_pointer_enter(struct wlr_seat_pointer_grab *grab, struct wlr_surface *surface, double sx, double sy) { @@ -463,14 +462,38 @@ uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, pointer_state->grab_button = button; pointer_state->grab_time = time; } - set_add(pointer_state->buttons, &pointer_state->button_count, - WLR_POINTER_BUTTONS_CAP, button); + for (size_t i = 0; i < pointer_state->button_count; i++) { + struct wlr_seat_pointer_button *pointer_button = &pointer_state->buttons[i]; + if (pointer_button->button == button) { + ++pointer_button->n_pressed; + return 0; + } + } + if (pointer_state->button_count == WLR_POINTER_BUTTONS_CAP) { + return 0; + } + pointer_state->buttons[pointer_state->button_count++] = (struct wlr_seat_pointer_button){ + .button = button, + .n_pressed = 1, + }; } else { - set_remove(pointer_state->buttons, &pointer_state->button_count, - WLR_POINTER_BUTTONS_CAP, button); + bool found = false; + for (size_t i = 0; i < pointer_state->button_count; i++) { + struct wlr_seat_pointer_button *pointer_button = &pointer_state->buttons[i]; + if (pointer_button->button == button) { + if (--pointer_button->n_pressed > 0) { + return 0; + } + *pointer_button = pointer_state->buttons[--pointer_state->button_count]; + found = true; + break; + } + } + if (!found) { + return 0; + } } - struct wlr_seat_pointer_grab *grab = pointer_state->grab; uint32_t serial = grab->interface->button(grab, time, button, state);