SDL: wayland: Use the implicit grab serial for setting the clipboard/primary selection data

From d28e9960cec4d2b3f1b9863911ebedf1395292f7 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Thu, 6 Jul 2023 12:43:24 -0400
Subject: [PATCH] wayland: Use the implicit grab serial for setting the
 clipboard/primary selection data

Use the implicit grab serial, which includes keyboard key, mouse button, touch, and tablet tool events, for setting the clipboard and primary selection data, as these are all considered valid originating event serials.
---
 src/video/wayland/SDL_waylandevents.c   | 41 +++++++++----------------
 src/video/wayland/SDL_waylandevents_c.h | 19 +++++++-----
 src/video/wayland/SDL_waylandwindow.c   |  3 +-
 3 files changed, 28 insertions(+), 35 deletions(-)

diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 0cbc0076d9f3..87b3c05863f9 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -675,12 +675,9 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_
         }
 
         if (state) {
-            input->button_press_serial = serial;
+            Wayland_UpdateImplicitGrabSerial(input, serial);
         }
 
-        Wayland_data_device_set_serial(input->data_device, serial);
-        Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
-
         SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, 0,
                             state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
     }
@@ -926,7 +923,7 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
     }
 
     touch_add(id, fx, fy, surface);
-    input->touch_down_serial = serial;
+    Wayland_UpdateImplicitGrabSerial(input, serial);
     window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
 
     if (window_data) {
@@ -1486,7 +1483,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
     SDL_bool handled_by_ime = SDL_FALSE;
     const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time);
 
-    input->key_serial = serial;
+    Wayland_UpdateImplicitGrabSerial(input, serial);
 
     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
         has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime);
@@ -1509,9 +1506,6 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
         SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetKeyboardTimestamp(input, time), state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode);
     }
 
-    Wayland_data_device_set_serial(input->data_device, serial);
-    Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
-
     if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
         if (has_text && !(SDL_GetModState() & SDL_KMOD_CTRL)) {
             if (!handled_by_ime) {
@@ -2397,7 +2391,7 @@ static void tablet_tool_handle_down(void *data, struct zwp_tablet_tool_v2 *tool,
     struct SDL_WaylandTabletInput *input = data;
     SDL_WindowData *window = input->tool_focus;
     input->is_down = SDL_TRUE;
-    input->press_serial = serial;
+    Wayland_UpdateImplicitGrabSerial(input->sdlWaylandInput, serial);
     if (window == NULL) {
         /* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
          * that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
@@ -2458,14 +2452,14 @@ static void tablet_tool_handle_tilt(void *data, struct zwp_tablet_tool_v2 *tool,
 
 static void tablet_tool_handle_button(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial, uint32_t button, uint32_t state)
 {
-    struct SDL_WaylandTabletInput *input = data;
+    struct SDL_WaylandTabletInput *input = (struct SDL_WaylandTabletInput*)data;
 
     if (input->is_down) {
         tablet_tool_handle_up(data, tool);
         input->is_down = SDL_TRUE;
     }
 
-    input->press_serial = serial;
+    Wayland_UpdateImplicitGrabSerial(input->sdlWaylandInput, serial);
 
     switch (button) {
     /* see %{_includedir}/linux/input-event-codes.h */
@@ -2613,7 +2607,8 @@ void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_Wayland
 
     input->tablet = tablet_input;
 
-    tablet_input->seat = (struct SDL_WaylandTabletSeat *)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2 *)tablet_manager, input->seat);
+    tablet_input->sdlWaylandInput = input;
+    tablet_input->seat = zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2 *)tablet_manager, input->seat);
 
     tablet_input->tablets = tablet_object_list_new_node(NULL);
     tablet_input->tools = tablet_object_list_new_node(NULL);
@@ -2629,7 +2624,7 @@ void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input)
     tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy));
     tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy));
 
-    zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2 *)input->tablet->seat);
+    zwp_tablet_seat_v2_destroy(input->tablet->seat);
 
     SDL_free(input->tablet);
     input->tablet = NULL;
@@ -3084,21 +3079,13 @@ int Wayland_input_ungrab_keyboard(SDL_Window *window)
     return 0;
 }
 
-Uint32 Wayland_GetLastImplicitGrabSerial(struct SDL_WaylandInput *input)
+void Wayland_UpdateImplicitGrabSerial(struct SDL_WaylandInput *input, Uint32 serial)
 {
-    Uint32 serial = input->key_serial;
-
-    if (serial < input->button_press_serial) {
-        serial = input->button_press_serial;
-    }
-    if (serial < input->touch_down_serial) {
-        serial = input->touch_down_serial;
-    }
-    if (input->tablet && serial < input->tablet->press_serial) {
-        serial = input->tablet->press_serial;
+    if (serial > input->last_implicit_grab_serial) {
+        input->last_implicit_grab_serial = serial;
+        Wayland_data_device_set_serial(input->data_device, serial);
+        Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
     }
-
-    return serial;
 }
 
 #endif /* SDL_VIDEO_DRIVER_WAYLAND */
diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h
index 4c36ab8bff75..0a5189324b90 100644
--- a/src/video/wayland/SDL_waylandevents_c.h
+++ b/src/video/wayland/SDL_waylandevents_c.h
@@ -48,7 +48,8 @@ struct SDL_WaylandTabletObjectListNode
 
 struct SDL_WaylandTabletInput
 {
-    struct SDL_WaylandTabletSeat *seat;
+    struct SDL_WaylandInput *sdlWaylandInput;
+    struct zwp_tablet_seat_v2 *seat;
 
     struct SDL_WaylandTabletObjectListNode *tablets;
     struct SDL_WaylandTabletObjectListNode *tools;
@@ -56,7 +57,6 @@ struct SDL_WaylandTabletInput
 
     SDL_WindowData *tool_focus;
     uint32_t tool_prox_serial;
-    uint32_t press_serial;
 
     /* Last motion location */
     wl_fixed_t sx_w;
@@ -113,10 +113,8 @@ struct SDL_WaylandInput
 
     uint32_t buttons_pressed;
 
-    /* Implicit grab serial events */
-    Uint32 key_serial;
-    Uint32 button_press_serial;
-    Uint32 touch_down_serial;
+    /* The serial of the last implicit grab event for window activation and selection data. */
+    Uint32 last_implicit_grab_serial;
 
     struct
     {
@@ -204,6 +202,13 @@ extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
 
 extern void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input);
 
-extern Uint32 Wayland_GetLastImplicitGrabSerial(struct SDL_WaylandInput *input);
+/* The implicit grab serial needs to be updated on:
+ * - Keyboard key down/up
+ * - Mouse button down
+ * - Touch event down
+ * - Tablet tool down
+ * - Tablet tool button down/up
+ */
+extern void Wayland_UpdateImplicitGrabSerial(struct SDL_WaylandInput *input, Uint32 serial);
 
 #endif /* SDL_waylandevents_h_ */
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index 4193dbce8d31..dbbf68c30b2e 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -1252,6 +1252,7 @@ static void handle_preferred_fractional_scale(void *data, struct wp_fractional_s
 {
     const float factor = scale / 120.; /* 120 is a magic number defined in the spec as a common denominator */
     Wayland_HandlePreferredScaleChanged(data, factor);
+    SDL_Log("Scale reported");
 }
 
 static const struct wp_fractional_scale_v1_listener fractional_scale_listener = {
@@ -1734,7 +1735,7 @@ void Wayland_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window)
      */
     if (input) {
         seat = input->seat;
-        serial = Wayland_GetLastImplicitGrabSerial(input);
+        serial = input->last_implicit_grab_serial;
     }
 
     Wayland_activate_window(_this->driverdata,