From 06a13203ddb9c085b1e514b09b424c19f058fd8d Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Sat, 15 Jun 2019 11:08:53 -0700 Subject: [PATCH] Use a set to track pointer button state. In addition to `button_count`, we keep track of the current buttons pressed just as in `wlr_keyboard`. Add `set_add` and `set_remove` to assist with this. These functions can only be used with values greater than 0 (such as the button/key masks for keyboards and pointers). Partially addresses: - https://github.com/swaywm/wlroots/issues/1716 - https://github.com/swaywm/wlroots/issues/1593 --- include/util/array.h | 15 +++++++++++++++ include/wlr/types/wlr_seat.h | 5 ++++- types/seat/wlr_seat_pointer.c | 33 ++++++++++++++++++++------------- types/wlr_keyboard.c | 21 ++++++--------------- util/array.c | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 75 insertions(+), 31 deletions(-) diff --git a/include/util/array.h b/include/util/array.h index 1c046e1d..32bc059f 100644 --- a/include/util/array.h +++ b/include/util/array.h @@ -3,7 +3,22 @@ #include #include +#include size_t push_zeroes_to_end(uint32_t arr[], size_t n); +/** + * Add `target` to `values` if it doesn't exist + * "set"s should only be modified with set_* functions + * Values MUST be greater than 0 + */ +bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target); + +/** + * Remove `target` from `values` if it exists + * "set"s should only be modified with set_* functions + * Values MUST be greater than 0 + */ +bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target); + #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 0724136b..bfd3625d 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -131,6 +131,8 @@ struct wlr_seat_pointer_grab { void *data; }; +#define WLR_POINTER_BUTTONS_CAP 16 + struct wlr_seat_pointer_state { struct wlr_seat *seat; struct wlr_seat_client *focused_client; @@ -140,7 +142,8 @@ struct wlr_seat_pointer_state { struct wlr_seat_pointer_grab *grab; struct wlr_seat_pointer_grab *default_grab; - uint32_t button_count; + uint32_t 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 e1182fd2..e2034c78 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -8,6 +8,7 @@ #include #include "types/wlr_seat.h" #include "util/signal.h" +#include "util/array.h" static void default_pointer_enter(struct wlr_seat_pointer_grab *grab, struct wlr_surface *surface, double sx, double sy) { @@ -339,26 +340,32 @@ void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t button, enum wlr_button_state state) { clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event); + + struct wlr_seat_pointer_state* pointer_state = &wlr_seat->pointer_state; + if (state == WLR_BUTTON_PRESSED) { - if (wlr_seat->pointer_state.button_count == 0) { - wlr_seat->pointer_state.grab_button = button; - wlr_seat->pointer_state.grab_time = time; + if (pointer_state->button_count == 0) { + pointer_state->grab_button = button; + pointer_state->grab_time = time; } - wlr_seat->pointer_state.button_count++; + set_add(pointer_state->buttons, &pointer_state->button_count, + WLR_POINTER_BUTTONS_CAP, button); } else { - if (wlr_seat->pointer_state.button_count == 0) { - wlr_log(WLR_ERROR, "Corrupted seat button count"); - } else { - wlr_seat->pointer_state.button_count--; - } + set_remove(pointer_state->buttons, &pointer_state->button_count, + WLR_POINTER_BUTTONS_CAP, button); } - struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; + + struct wlr_seat_pointer_grab *grab = pointer_state->grab; uint32_t serial = grab->interface->button(grab, time, button, state); - if (serial && wlr_seat->pointer_state.button_count == 1 && + wlr_log(WLR_DEBUG, "button_count=%zu grab_serial=%"PRIu32" serial=%"PRIu32"", + pointer_state->button_count, + pointer_state->grab_serial, serial); + + if (serial && pointer_state->button_count == 1 && state == WLR_BUTTON_PRESSED) { - wlr_seat->pointer_state.grab_serial = serial; + pointer_state->grab_serial = serial; } return serial; @@ -413,7 +420,7 @@ bool wlr_seat_validate_pointer_grab_serial(struct wlr_seat *seat, if (seat->pointer_state.button_count != 1 || seat->pointer_state.grab_serial != serial) { wlr_log(WLR_DEBUG, "Pointer grab serial validation failed: " - "button_count=%"PRIu32" grab_serial=%"PRIu32" (got %"PRIu32")", + "button_count=%zu grab_serial=%"PRIu32" (got %"PRIu32")", seat->pointer_state.button_count, seat->pointer_state.grab_serial, serial); return false; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index 89c7ca50..cffa3ec6 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -57,22 +57,13 @@ static bool keyboard_modifier_update(struct wlr_keyboard *keyboard) { static void keyboard_key_update(struct wlr_keyboard *keyboard, struct wlr_event_keyboard_key *event) { - bool found = false; - size_t i = 0; - for (; i < keyboard->num_keycodes; ++i) { - if (keyboard->keycodes[i] == event->keycode) { - found = true; - break; - } - } - - if (event->state == WLR_KEY_PRESSED && !found && - keyboard->num_keycodes < WLR_KEYBOARD_KEYS_CAP) { - keyboard->keycodes[keyboard->num_keycodes++] = event->keycode; + if (event->state == WLR_KEY_PRESSED) { + set_add(keyboard->keycodes, &keyboard->num_keycodes, + WLR_KEYBOARD_KEYS_CAP, event->keycode); } - if (event->state == WLR_KEY_RELEASED && found) { - keyboard->keycodes[i] = 0; - keyboard->num_keycodes = push_zeroes_to_end(keyboard->keycodes, WLR_KEYBOARD_KEYS_CAP); + if (event->state == WLR_KEY_RELEASED) { + set_remove(keyboard->keycodes, &keyboard->num_keycodes, + WLR_KEYBOARD_KEYS_CAP, event->keycode); } assert(keyboard->num_keycodes <= WLR_KEYBOARD_KEYS_CAP); diff --git a/util/array.c b/util/array.c index 9ee39d33..7095870d 100644 --- a/util/array.c +++ b/util/array.c @@ -1,5 +1,5 @@ -#include -#include +#include "util/array.h" +#include // https://www.geeksforgeeks.org/move-zeroes-end-array/ size_t push_zeroes_to_end(uint32_t arr[], size_t n) { @@ -19,3 +19,31 @@ size_t push_zeroes_to_end(uint32_t arr[], size_t n) { return ret; } + +bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target) { + if (*len == cap) { + return false; + } + assert(target > 0); + for (uint32_t i = 0; i < *len; ++i) { + if (values[i] == target) { + return false; + } + } + values[(*len)++] = target; + return false; +} + +bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target) { + for (uint32_t i = 0; i < *len; ++i) { + if (values[i] == target) { + // Set to 0 and swap with the end element so that + // zeroes exist only after all the values. + size_t last_elem_pos = --(*len); + values[i] = values[last_elem_pos]; + values[last_elem_pos] = 0; + return true; + } + } + return false; +}