From 3898bb482deb06dc999a57e25fed8f11ef2aa627 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sun, 2 Apr 2023 10:18:28 +0000 Subject: [PATCH] seat: Let client manage its own resources This makes seat_client resources inert when seats and/or input devices are destroyed, rather than destroying the resources. When the client calls e.g. wl_keyboard_release(), it's not expecting the keyboard global to be already destroyed, so this results in an error such as this: wl_display@1: error 0: invalid object 22 --- types/data_device/wlr_data_device.c | 1 + types/seat/wlr_seat.c | 68 ++++++++++++++++------------- types/seat/wlr_seat_keyboard.c | 3 +- types/seat/wlr_seat_pointer.c | 3 +- types/seat/wlr_seat_touch.c | 3 +- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index 7e6747905..428f7906b 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -99,6 +99,7 @@ static const struct wl_data_device_interface data_device_impl = { static void data_device_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); } diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index f1bda82e0..0b536d594 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -18,6 +18,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) { + return; + } if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_POINTER)) { wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY, "wl_seat.get_pointer called when no pointer capability has existed"); @@ -32,6 +35,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) { + return; + } if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY, "wl_seat.get_keyboard called when no keyboard capability has existed"); @@ -46,6 +52,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) { + return; + } if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_TOUCH)) { wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY, "wl_seat.get_touch called when no touch capability has existed"); @@ -56,16 +65,7 @@ static void seat_handle_get_touch(struct wl_client *client, seat_client_create_touch(seat_client, version, id); } -static void seat_client_handle_resource_destroy( - struct wl_resource *seat_resource) { - struct wlr_seat_client *client = - wlr_seat_client_from_resource(seat_resource); - - wl_list_remove(wl_resource_get_link(seat_resource)); - if (!wl_list_empty(&client->resources)) { - return; - } - +static void seat_client_destroy(struct wlr_seat_client *client) { wl_signal_emit_mutable(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { @@ -81,27 +81,47 @@ static void seat_client_handle_resource_destroy( struct wl_resource *resource, *tmp; wl_resource_for_each_safe(resource, tmp, &client->pointers) { - wl_resource_destroy(resource); + seat_client_destroy_pointer(resource); } wl_resource_for_each_safe(resource, tmp, &client->keyboards) { - wl_resource_destroy(resource); + seat_client_destroy_keyboard(resource); } wl_resource_for_each_safe(resource, tmp, &client->touches) { - wl_resource_destroy(resource); + seat_client_destroy_touch(resource); } wl_resource_for_each_safe(resource, tmp, &client->data_devices) { // Make the data device inert + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); + wl_resource_set_user_data(resource, NULL); + } + wl_resource_for_each_safe(resource, tmp, &client->resources) { + // Make the seat resource inert + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); wl_resource_set_user_data(resource, NULL); - - struct wl_list *link = wl_resource_get_link(resource); - wl_list_remove(link); - wl_list_init(link); } wl_list_remove(&client->link); free(client); } +static void seat_client_handle_resource_destroy( + struct wl_resource *seat_resource) { + struct wlr_seat_client *client = + wlr_seat_client_from_resource(seat_resource); + if (!client) { + return; + } + + wl_list_remove(wl_resource_get_link(seat_resource)); + if (!wl_list_empty(&client->resources)) { + return; + } + + seat_client_destroy(client); +} + static void seat_handle_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -207,19 +227,7 @@ void wlr_seat_destroy(struct wlr_seat *seat) { struct wlr_seat_client *client, *tmp; wl_list_for_each_safe(client, tmp, &seat->clients, link) { - struct wl_resource *resource, *next; - /* wl_resource_for_each_safe isn't safe to use here, because the last - * wl_resource_destroy will also destroy the head we cannot do the last - * 'next' update that usually is harmless here. - * Work around this by breaking one step ahead - */ - wl_resource_for_each_safe(resource, next, &client->resources) { - // will destroy other resources as well - wl_resource_destroy(resource); - if (wl_resource_get_link(next) == &client->resources) { - break; - } - } + seat_client_destroy(client); } wlr_global_destroy_safe(seat->global); diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 51456f8b3..874e43eac 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -59,7 +59,6 @@ static struct wlr_seat_client *seat_client_from_keyboard_resource( } static void keyboard_handle_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); seat_client_destroy_keyboard(resource); } @@ -445,5 +444,7 @@ void seat_client_destroy_keyboard(struct wl_resource *resource) { if (seat_client == NULL) { return; } + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); wl_resource_set_user_data(resource, NULL); } diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index ffa706bd6..cc4fd4413 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -114,7 +114,6 @@ static const struct wl_pointer_interface pointer_impl = { }; static void pointer_handle_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); seat_client_destroy_pointer(resource); } @@ -538,6 +537,8 @@ void seat_client_destroy_pointer(struct wl_resource *resource) { if (seat_client == NULL) { return; } + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); wl_resource_set_user_data(resource, NULL); } diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index 9b533c07b..a298cf28c 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -66,7 +66,6 @@ static const struct wl_touch_interface touch_impl = { }; static void touch_handle_resource_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); seat_client_destroy_touch(resource); } @@ -449,6 +448,8 @@ void seat_client_destroy_touch(struct wl_resource *resource) { if (seat_client == NULL) { return; } + wl_list_remove(wl_resource_get_link(resource)); + wl_list_init(wl_resource_get_link(resource)); wl_resource_set_user_data(resource, NULL); }