From 7510245af92c801162cf469cf313d8ebe6cfa298 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Thu, 8 Apr 2021 14:08:35 -0400 Subject: [PATCH] wayland: Create the data_device only after both device_manager and input exist. There is no guarantee on what order the Wayland interfaces will come in, but the callbacks were assuming that wl_data_device_manager would could before wl_seat. This would cause certain desktops to not have any data_device to work with, meaning certain features like the clipboard would silently no-op. --- src/video/wayland/SDL_waylandevents.c | 55 ++++++++++++++++--------- src/video/wayland/SDL_waylandevents_c.h | 2 + src/video/wayland/SDL_waylandvideo.c | 2 +- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 62a2557ec..08c1866ab 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1087,11 +1087,45 @@ static const struct wl_data_device_listener data_device_listener = { data_device_handle_selection }; +static void +Wayland_create_data_device(SDL_VideoData *d) +{ + SDL_WaylandDataDevice *data_device = NULL; + + data_device = SDL_calloc(1, sizeof *data_device); + if (data_device == NULL) { + return; + } + + data_device->data_device = wl_data_device_manager_get_data_device( + d->data_device_manager, d->input->seat + ); + data_device->video_data = d; + + if (data_device->data_device == NULL) { + SDL_free(data_device); + } else { + wl_data_device_set_user_data(data_device->data_device, data_device); + wl_data_device_add_listener(data_device->data_device, + &data_device_listener, data_device); + d->input->data_device = data_device; + } +} + +void +Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version) +{ + d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, SDL_min(3, version)); + + if (d->input != NULL) { + Wayland_create_data_device(d); + } +} + void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) { struct SDL_WaylandInput *input; - SDL_WaylandDataDevice *data_device = NULL; input = SDL_calloc(1, sizeof *input); if (input == NULL) @@ -1104,24 +1138,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) d->input = input; if (d->data_device_manager != NULL) { - data_device = SDL_calloc(1, sizeof *data_device); - if (data_device == NULL) { - return; - } - - data_device->data_device = wl_data_device_manager_get_data_device( - d->data_device_manager, input->seat - ); - data_device->video_data = d; - - if (data_device->data_device == NULL) { - SDL_free(data_device); - } else { - wl_data_device_set_user_data(data_device->data_device, data_device); - wl_data_device_add_listener(data_device->data_device, - &data_device_listener, data_device); - input->data_device = data_device; - } + Wayland_create_data_device(d); } wl_seat_add_listener(input->seat, &seat_listener, input); diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 8e3fc998a..720608b12 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -80,6 +80,8 @@ struct SDL_WaylandInput { extern void Wayland_PumpEvents(_THIS); +extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version); + extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version); extern void Wayland_display_destroy_input(SDL_VideoData *d); diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index e017747a4..0608f0fd6 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -423,7 +423,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) { d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1); } else if (strcmp(interface, "wl_data_device_manager") == 0) { - d->data_device_manager = wl_registry_bind(d->registry, id, &wl_data_device_manager_interface, SDL_min(3, version)); + Wayland_add_data_device_manager(d, id, version); } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);