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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 62a2557..08c1866 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 8e3fc99..720608b 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 e017747..0608f0f 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);