From a3c699eee51e7915b97a260e08a8f998c9fb2816 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 2 Mar 2020 17:17:28 +0100 Subject: [PATCH] backend/wayland: fix seat caps handling Previously, each time a wl_seat.capabilities event was received the Wayland backend created new input devices. It now only does so the first time. Input devices are now destroyed when the cap is removed. Closes: https://github.com/swaywm/sway/issues/5055 --- backend/wayland/seat.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d59bd6d8..edb690b8 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -289,8 +289,9 @@ static struct wlr_wl_input_device *get_wl_input_device_from_input_device( static void input_device_destroy(struct wlr_input_device *wlr_dev) { struct wlr_wl_input_device *dev = get_wl_input_device_from_input_device(wlr_dev); - if (dev->resource) { - wl_proxy_destroy(dev->resource); + if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) { + wl_keyboard_release(dev->backend->keyboard); + dev->backend->keyboard = NULL; } wl_list_remove(&dev->wlr_input_device.link); free(dev); @@ -535,6 +536,7 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp &relative_pointer_listener, dev); } + wl_pointer_add_listener(wl_pointer, &pointer_listener, backend); wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); } @@ -556,7 +558,6 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend * wlr_keyboard_init(wlr_dev->keyboard, NULL); wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); - dev->resource = wl_keyboard; wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev); } @@ -565,7 +566,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, struct wlr_wl_backend *backend = data; assert(backend->seat == wl_seat); - if ((caps & WL_SEAT_CAPABILITY_POINTER)) { + if ((caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer == NULL) { wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat); struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat); @@ -575,10 +576,22 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wl_list_for_each(output, &backend->outputs, link) { create_wl_pointer(wl_pointer, output); } + } + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer != NULL) { + wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat); + + struct wlr_input_device *device, *tmp; + wl_list_for_each_safe(device, tmp, &backend->devices, link) { + if (device->type == WLR_INPUT_DEVICE_POINTER) { + wlr_input_device_destroy(device); + } + } - wl_pointer_add_listener(wl_pointer, &pointer_listener, backend); + wl_pointer_release(backend->pointer); + backend->pointer = NULL; } - if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) { wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat); struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat); @@ -588,6 +601,17 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, create_wl_keyboard(wl_keyboard, backend); } } + if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard != NULL) { + wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat); + + struct wlr_input_device *device, *tmp; + wl_list_for_each_safe(device, tmp, &backend->devices, link) { + if (device->type == WLR_INPUT_DEVICE_KEYBOARD) { + wlr_input_device_destroy(device); + } + } + assert(backend->keyboard == NULL); // free'ed by input_device_destroy + } } static void seat_handle_name(void *data, struct wl_seat *wl_seat,