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
This commit is contained in:
Simon Ser 2020-03-02 17:17:28 +01:00
parent 348f52b5fc
commit a3c699eee5
1 changed files with 31 additions and 7 deletions

View File

@ -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) { static void input_device_destroy(struct wlr_input_device *wlr_dev) {
struct wlr_wl_input_device *dev = struct wlr_wl_input_device *dev =
get_wl_input_device_from_input_device(wlr_dev); get_wl_input_device_from_input_device(wlr_dev);
if (dev->resource) { if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) {
wl_proxy_destroy(dev->resource); wl_keyboard_release(dev->backend->keyboard);
dev->backend->keyboard = NULL;
} }
wl_list_remove(&dev->wlr_input_device.link); wl_list_remove(&dev->wlr_input_device.link);
free(dev); free(dev);
@ -535,6 +536,7 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
&relative_pointer_listener, dev); &relative_pointer_listener, dev);
} }
wl_pointer_add_listener(wl_pointer, &pointer_listener, backend);
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); 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); wlr_keyboard_init(wlr_dev->keyboard, NULL);
wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, wlr_dev); 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); 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; struct wlr_wl_backend *backend = data;
assert(backend->seat == wl_seat); 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); wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat);
struct wl_pointer *wl_pointer = wl_seat_get_pointer(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) { wl_list_for_each(output, &backend->outputs, link) {
create_wl_pointer(wl_pointer, output); create_wl_pointer(wl_pointer, output);
} }
wl_pointer_add_listener(wl_pointer, &pointer_listener, backend);
} }
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { 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_release(backend->pointer);
backend->pointer = NULL;
}
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) {
wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat); wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat);
struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(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); 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, static void seat_handle_name(void *data, struct wl_seat *wl_seat,