From d698ed2f7529d48b21bcc8f3f6ca2c683ad95af0 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 20 Feb 2023 17:10:26 +1000 Subject: [PATCH] ei: remove some indirection from device events Now that we only have one nice hook as entry point for those events, let's move (and harden) the code there. --- src/libei-device.c | 406 ++++++++++++++++++--------------------------- src/libei-device.h | 41 ----- 2 files changed, 162 insertions(+), 285 deletions(-) diff --git a/src/libei-device.c b/src/libei-device.c index a33f2bd..8de8c4f 100644 --- a/src/libei-device.c +++ b/src/libei-device.c @@ -125,6 +125,19 @@ ei_device_get_context(struct ei_device *device) return ei_seat_get_context(ei_device_get_seat(device)); } +static inline bool +ei_device_in_region(struct ei_device *device, double x, double y) +{ + struct ei_region *r; + + list_for_each(r, &device->regions, link) { + if (ei_region_contains(r, x, y)) + return true; + } + + return false; +} + static struct brei_result * handle_msg_destroy(struct ei_device *device) { @@ -261,7 +274,6 @@ handle_msg_paused(struct ei_device *device) } \ } while(0) - static struct brei_result * handle_msg_start_emulating(struct ei_device *device, uint32_t sequence) { @@ -308,14 +320,39 @@ handle_msg_stop_emulating(struct ei_device *device) return NULL; } +static struct brei_result * +maybe_error_on_device_state(struct ei_device *device, const char *event_type) +{ + switch (device->state) { + case EI_DEVICE_STATE_EMULATING: + return NULL; + case EI_DEVICE_STATE_REMOVED_FROM_CLIENT: + /* we removed the device but server sent us an event - most + * likely a race condition, so let's ignore it */ + return NULL; + case EI_DEVICE_STATE_NEW: + case EI_DEVICE_STATE_PAUSED: + case EI_DEVICE_STATE_RESUMED: + case EI_DEVICE_STATE_REMOVED_FROM_SERVER: + case EI_DEVICE_STATE_DEAD: + break; + } + + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Invalid device state %ud for a %s event", device->state, event_type); +} + static struct brei_result * handle_msg_frame(struct ei_device *device, uint32_t time, uint32_t micros) { DISCONNECT_IF_SENDER_CONTEXT(device); - ei_queue_frame_event(device, ms2us(time) + micros); + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_frame_event(device, ms2us(time) + micros); + return NULL; + } - return NULL; + return maybe_error_on_device_state(device, "frame"); } static struct brei_result * @@ -385,7 +422,17 @@ handle_msg_pointer_rel(struct ei_pointer *pointer, float x, float y) DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_pointer_rel(device, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer rel event for non-pointer device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_pointer_rel_event(device, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer rel"); } static struct brei_result * @@ -395,7 +442,21 @@ handle_msg_pointer_abs(struct ei_pointer *pointer, float x, float y) DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_pointer_abs(device, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer abs event for non-pointer device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + if (!ei_device_in_region(device, x, y)) + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_VALUE, + "abs position outside regions"); + + ei_queue_pointer_abs_event(device, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer abs"); } static struct brei_result * @@ -406,7 +467,19 @@ handle_msg_pointer_button(struct ei_pointer *pointer, DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_pointer_button(device, button, !!state)); + + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) && + !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer button event for non-pointer device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_pointer_button_event(device, button, !!state); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer button"); } static struct brei_result * @@ -416,7 +489,18 @@ handle_msg_pointer_scroll(struct ei_pointer *pointer, float x, float y) DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_pointer_scroll(device, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) && + !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer scroll event for non-pointer device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_pointer_scroll_event(device, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer scroll"); } static struct brei_result * @@ -427,7 +511,18 @@ handle_msg_pointer_scroll_discrete(struct ei_pointer *pointer, DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_pointer_scroll_discrete(device, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) && + !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer scroll discrete event for non-pointer device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_pointer_scroll_discrete_event(device, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer scroll discrete"); } static struct brei_result * @@ -438,12 +533,21 @@ handle_msg_pointer_scroll_stop(struct ei_pointer *pointer, DISCONNECT_IF_SENDER_CONTEXT(device); - if (is_cancel) - return brei_result_new_from_neg_errno(ei_device_event_pointer_scroll_cancel(device, !!x, !!y)); - else - return brei_result_new_from_neg_errno(ei_device_event_pointer_scroll_stop(device, !!x, !!y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) && + !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Pointer scroll stop event for non-pointer device"); + } - return brei_result_new_from_neg_errno(-EINVAL); + if (device->state == EI_DEVICE_STATE_EMULATING) { + if (is_cancel) + ei_queue_pointer_scroll_cancel_event(device, !!x, !!y); + else + ei_queue_pointer_scroll_stop_event(device, !!x, !!y); + return NULL; + } + + return maybe_error_on_device_state(device, "pointer scroll discrete"); } static struct brei_result * @@ -488,19 +592,28 @@ handle_msg_keyboard_key(struct ei_keyboard *keyboard, uint32_t key, uint32_t sta DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_keyboard_key(device, key, !!state)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Key event for non-keyboard device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_keyboard_key_event(device, key, !!state); + return NULL; + } + + return maybe_error_on_device_state(device, "key"); } static struct brei_result * handle_msg_keyboard_modifiers(struct ei_keyboard *keyboard, uint32_t depressed, uint32_t locked, uint32_t latched, uint32_t group) { - struct ei *ei = ei_keyboard_get_context(keyboard); struct ei_device *device = ei_keyboard_get_device(keyboard); if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) { - log_bug(ei,"Modifier event for non-keyboard"); - return brei_result_new_from_neg_errno(-EPROTO); + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Modifier event for non-keyboard device"); } struct ei_xkb_modifiers mods = { @@ -546,7 +659,17 @@ handle_msg_touch_down(struct ei_touchscreen *touchscreen, DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_touch_down(device, touchid, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Touch down event for non-touch device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_touch_down_event(device, touchid, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "touch down"); } static struct brei_result * @@ -557,7 +680,17 @@ handle_msg_touch_motion(struct ei_touchscreen *touchscreen, DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_touch_motion(device, touchid, x, y)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Touch motion event for non-touch device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_touch_motion_event(device, touchid, x, y); + return NULL; + } + + return maybe_error_on_device_state(device, "touch motion"); } static struct brei_result * @@ -567,7 +700,16 @@ handle_msg_touch_up(struct ei_touchscreen *touchscreen, uint32_t touchid) DISCONNECT_IF_SENDER_CONTEXT(device); - return brei_result_new_from_neg_errno(ei_device_event_touch_up(device, touchid)); + if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { + return brei_result_new(EI_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Touch up event for non-touch device"); + } + + if (device->state == EI_DEVICE_STATE_EMULATING) { + ei_queue_touch_up_event(device, touchid); + return NULL; + } + return maybe_error_on_device_state(device, "touch up"); } static struct brei_result * @@ -1065,19 +1207,6 @@ ei_device_pointer_motion(struct ei_device *device, ei_send_pointer_rel(device, x, y); } -static inline bool -ei_device_in_region(struct ei_device *device, double x, double y) -{ - struct ei_region *r; - - list_for_each(r, &device->regions, link) { - if (ei_region_contains(r, x, y)) - return true; - } - - return false; -} - _public_ void ei_device_pointer_motion_absolute(struct ei_device *device, double x, double y) @@ -1461,214 +1590,3 @@ ei_device_frame(struct ei_device *device, uint64_t time) ei_disconnect(ei_device_get_context(device)); return; } - -int -ei_device_event_frame(struct ei_device *device, uint64_t time) -{ - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_frame_event(device, time); - - return 0; -} - -int -ei_device_event_pointer_rel(struct ei_device *device, double x, double y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_rel_event(device, x, y); - - return 0; -} - -int -ei_device_event_pointer_abs(struct ei_device *device, - double x, double y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not an absolute pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - if (!ei_device_in_region(device, x, y)) - return -EINVAL; - - ei_queue_pointer_abs_event(device, x, y); - - return 0; -} - -int -ei_device_event_pointer_button(struct ei_device *device, - uint32_t button, bool is_press) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_button_event(device, button, is_press); - - return 0; -} - -int -ei_device_event_pointer_scroll(struct ei_device *device, - double x, double y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) && - !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a (absolute) pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_scroll_event(device, x, y); - - return 0; -} - -int -ei_device_event_pointer_scroll_discrete(struct ei_device *device, - int32_t x, int32_t y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) && - !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a (absolute) pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_scroll_discrete_event(device, x, y); - - return 0; -} - -int -ei_device_event_pointer_scroll_stop(struct ei_device *device, bool x, bool y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) && - !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a (absolute) pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_scroll_stop_event(device, x, y); - - return 0; -} - -int -ei_device_event_pointer_scroll_cancel(struct ei_device *device, bool x, bool y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) && - !ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a (absolute) pointer", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_pointer_scroll_cancel_event(device, x, y); - - return 0; -} - -int -ei_device_event_keyboard_key(struct ei_device *device, - uint32_t key, bool is_press) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a keyboard", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_keyboard_key_event(device, key, is_press); - - return 0; -} - -int -ei_device_event_touch_down(struct ei_device *device, uint32_t touchid, double x, double y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a touch device", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_touch_down_event(device, touchid, x, y); - - return 0; -} - -int -ei_device_event_touch_motion(struct ei_device *device, uint32_t touchid, double x, double y) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a touch device", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_touch_motion_event(device, touchid, x, y); - - return 0; -} - -int -ei_device_event_touch_up(struct ei_device *device, uint32_t touchid) -{ - if (!ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)) { - log_bug_client(ei_device_get_context(device), - "%s: device is not a touch device", __func__); - return -EINVAL; - } - - if (device->state != EI_DEVICE_STATE_EMULATING) - return -EINVAL; - - ei_queue_touch_up_event(device, touchid); - - return 0; -} - diff --git a/src/libei-device.h b/src/libei-device.h index a9a684c..9d7424c 100644 --- a/src/libei-device.h +++ b/src/libei-device.h @@ -133,53 +133,12 @@ ei_device_done(struct ei_device *device); void ei_device_removed_by_server(struct ei_device *device); -int -ei_device_event_frame(struct ei_device *device, uint64_t time); - void ei_device_event_start_emulating(struct ei_device *device, uint32_t sequence); void ei_device_event_stop_emulating(struct ei_device *device); -int -ei_device_event_pointer_rel(struct ei_device *device, - double x, double y); - -int -ei_device_event_pointer_abs(struct ei_device *device, - double x, double y); - -int -ei_device_event_pointer_button(struct ei_device *device, - uint32_t button, bool is_press); - -int -ei_device_event_pointer_scroll(struct ei_device *device, - double x, double y); -int -ei_device_event_pointer_scroll_stop(struct ei_device *device, bool x, bool y); - -int -ei_device_event_pointer_scroll_cancel(struct ei_device *device, bool x, bool y); - -int -ei_device_event_pointer_scroll_discrete(struct ei_device *device, - int32_t x, int32_t y); - -int -ei_device_event_keyboard_key(struct ei_device *device, - uint32_t key, bool is_press); - -int -ei_device_event_touch_down(struct ei_device *device, uint32_t tid, - double x, double y); -int -ei_device_event_touch_motion(struct ei_device *device, uint32_t tid, - double x, double y); -int -ei_device_event_touch_up(struct ei_device *device, uint32_t tid); - void ei_device_added(struct ei_device *device);