From 5e0ef70cc085666d0939aefdf403664c5cd268e5 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 28 May 2020 00:24:50 +0200 Subject: [PATCH] seat: Create inert objects for missing capabilities We should throw a protocol error if the relevant capability has never existed when get_(pointer|keyboard|touch) is called. Otherwise, it should succeed, even if the capability is not currently present. This follows the spec, and avoids possible races with the client when capabilities are lost. Closes: https://github.com/swaywm/wlroots/issues/2227 --- include/wlr/types/wlr_seat.h | 1 + types/seat/wlr_seat.c | 19 ++++++++++--------- types/seat/wlr_seat_keyboard.c | 5 +++++ types/seat/wlr_seat_pointer.c | 5 +++++ types/seat/wlr_seat_touch.c | 4 ++++ 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 949cd419..aabed7ff 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -214,6 +214,7 @@ struct wlr_seat { char *name; uint32_t capabilities; + uint32_t accumulated_capabilities; struct timespec last_event; struct wlr_data_source *selection_source; diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index d606c6a2..33db5101 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -19,9 +19,9 @@ static void seat_handle_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); - if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { - wlr_log(WLR_ERROR, "Client sent get_pointer on seat without the " - "pointer capability"); + if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_POINTER)) { + wl_resource_post_error(seat_resource, 0, + "wl_seat.get_pointer called when no pointer capability has existed"); return; } @@ -33,9 +33,9 @@ static void seat_handle_get_keyboard(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); - if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { - wlr_log(WLR_ERROR, "Client sent get_keyboard on seat without the " - "keyboard capability"); + if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { + wl_resource_post_error(seat_resource, 0, + "wl_seat.get_keyboard called when no keyboard capability has existed"); return; } @@ -47,9 +47,9 @@ static void seat_handle_get_touch(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); - if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { - wlr_log(WLR_ERROR, "Client sent get_touch on seat without the " - "touch capability"); + if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_TOUCH)) { + wl_resource_post_error(seat_resource, 0, + "wl_seat.get_touch called when no touch capability has existed"); return; } @@ -311,6 +311,7 @@ struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, uint32_t capabilities) { wlr_seat->capabilities = capabilities; + wlr_seat->accumulated_capabilities |= capabilities; struct wlr_seat_client *client; wl_list_for_each(client, &wlr_seat->clients, link) { diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index bfd6fc43..33de2aa5 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -410,6 +410,11 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, keyboard_handle_resource_destroy); wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource)); + if ((seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) { + wl_resource_set_user_data(resource, NULL); + return; + } + struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard; if (keyboard == NULL) { return; diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 7ac21d0d..22848d81 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -410,6 +410,11 @@ void seat_client_create_pointer(struct wlr_seat_client *seat_client, &pointer_handle_resource_destroy); wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource)); + if ((seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) { + wl_resource_set_user_data(resource, NULL); + return; + } + struct wlr_seat_client *focused_client = seat_client->seat->pointer_state.focused_client; struct wlr_surface *focused_surface = diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index f0dee5da..2142a83b 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -366,6 +366,10 @@ void seat_client_create_touch(struct wlr_seat_client *seat_client, wl_resource_set_implementation(resource, &touch_impl, seat_client, &touch_handle_resource_destroy); wl_list_insert(&seat_client->touches, wl_resource_get_link(resource)); + + if ((seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0) { + wl_resource_set_user_data(resource, NULL); + } } void seat_client_destroy_touch(struct wl_resource *resource) {