SDL: Wayland: Fix mouse pointer hiding on Plasma Wayland

From 8c5b7af2d2f317c42c5437aa4b4dc7c3f5a06057 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Thu, 25 Feb 2021 19:30:47 -0600
Subject: [PATCH] Wayland: Fix mouse pointer hiding on Plasma Wayland

Unlike Mutter and Sway, KWin actually checks the serial passed in
wl_pointer_set_cursor(). The serial provided is supposed to be the
serial of the pointer enter event, but We were always passing 0.
This caused KWin to drop our requests to hide the cursor.

Thanks to the KDE folks for spotting this in my debug logs.

Fixes #3576
---
 src/video/wayland/SDL_waylandevents.c   | 50 +------------------------
 src/video/wayland/SDL_waylandevents_c.h | 50 ++++++++++++++++++++++++-
 src/video/wayland/SDL_waylandmouse.c    |  7 +++-
 3 files changed, 55 insertions(+), 52 deletions(-)

diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 0cb1f674b..5e17e12ff 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -61,55 +61,6 @@
 /* Weston uses a ratio of 10 units per scroll tick */
 #define WAYLAND_WHEEL_AXIS_UNIT 10
 
-typedef struct {
-    // repeat_rate in range of [1, 1000]
-    int32_t repeat_rate;
-    int32_t repeat_delay;
-    SDL_bool is_initialized;
-
-    SDL_bool is_key_down;
-    uint32_t next_repeat_ms;
-    uint32_t scancode;
-    char text[8];
-} SDL_WaylandKeyboardRepeat;
-
-struct SDL_WaylandInput {
-    SDL_VideoData *display;
-    struct wl_seat *seat;
-    struct wl_pointer *pointer;
-    struct wl_touch *touch;
-    struct wl_keyboard *keyboard;
-    SDL_WaylandDataDevice *data_device;
-    struct zwp_relative_pointer_v1 *relative_pointer;
-    struct zwp_confined_pointer_v1 *confined_pointer;
-    SDL_Window *confined_pointer_window;
-    SDL_WindowData *pointer_focus;
-    SDL_WindowData *keyboard_focus;
-
-    /* Last motion location */
-    wl_fixed_t sx_w;
-    wl_fixed_t sy_w;
-
-    double dx_frac;
-    double dy_frac;
-
-    struct {
-        struct xkb_keymap *keymap;
-        struct xkb_state *state;
-    } xkb;
-
-    /* information about axis events on current frame */
-    struct {
-        SDL_bool is_x_discrete;
-        float x;
-
-        SDL_bool is_y_discrete;
-        float y;
-    } pointer_curr_axis_info;
-
-    SDL_WaylandKeyboardRepeat keyboard_repeat;
-};
-
 struct SDL_WaylandTouchPoint {
     SDL_TouchID id;
     float x;
@@ -324,6 +275,7 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
 
     if (window) {
         input->pointer_focus = window;
+        input->pointer_enter_serial = serial;
         SDL_SetMouseFocus(window->sdlwindow);
         /* In the case of e.g. a pointer confine warp, we may receive an enter
          * event with no following motion event, but with the new coordinates
diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h
index 74ea24c5f..8e3fc998a 100644
--- a/src/video/wayland/SDL_waylandevents_c.h
+++ b/src/video/wayland/SDL_waylandevents_c.h
@@ -28,7 +28,55 @@
 #include "SDL_waylandwindow.h"
 #include "SDL_waylanddatamanager.h"
 
-struct SDL_WaylandInput;
+typedef struct {
+    // repeat_rate in range of [1, 1000]
+    int32_t repeat_rate;
+    int32_t repeat_delay;
+    SDL_bool is_initialized;
+
+    SDL_bool is_key_down;
+    uint32_t next_repeat_ms;
+    uint32_t scancode;
+    char text[8];
+} SDL_WaylandKeyboardRepeat;
+
+struct SDL_WaylandInput {
+    SDL_VideoData *display;
+    struct wl_seat *seat;
+    struct wl_pointer *pointer;
+    struct wl_touch *touch;
+    struct wl_keyboard *keyboard;
+    SDL_WaylandDataDevice *data_device;
+    struct zwp_relative_pointer_v1 *relative_pointer;
+    struct zwp_confined_pointer_v1 *confined_pointer;
+    SDL_Window *confined_pointer_window;
+    SDL_WindowData *pointer_focus;
+    SDL_WindowData *keyboard_focus;
+    uint32_t pointer_enter_serial;
+
+    /* Last motion location */
+    wl_fixed_t sx_w;
+    wl_fixed_t sy_w;
+
+    double dx_frac;
+    double dy_frac;
+
+    struct {
+        struct xkb_keymap *keymap;
+        struct xkb_state *state;
+    } xkb;
+
+    /* information about axis events on current frame */
+    struct {
+        SDL_bool is_x_discrete;
+        float x;
+
+        SDL_bool is_y_discrete;
+        float y;
+    } pointer_curr_axis_info;
+
+    SDL_WaylandKeyboardRepeat keyboard_repeat;
+};
 
 extern void Wayland_PumpEvents(_THIS);
 
diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c
index ef259b9ba..bf0ede081 100644
--- a/src/video/wayland/SDL_waylandmouse.c
+++ b/src/video/wayland/SDL_waylandmouse.c
@@ -318,6 +318,7 @@ Wayland_ShowCursor(SDL_Cursor *cursor)
 {
     SDL_VideoDevice *vd = SDL_GetVideoDevice();
     SDL_VideoData *d = vd->driverdata;
+    struct SDL_WaylandInput *input = d->input;
 
     struct wl_pointer *pointer = d->pointer;
 
@@ -328,7 +329,8 @@ Wayland_ShowCursor(SDL_Cursor *cursor)
     {
         Wayland_CursorData *data = cursor->driverdata;
 
-        wl_pointer_set_cursor (pointer, 0,
+        wl_pointer_set_cursor (pointer,
+                               input->pointer_enter_serial,
                                data->surface,
                                data->hot_x,
                                data->hot_y);
@@ -338,7 +340,8 @@ Wayland_ShowCursor(SDL_Cursor *cursor)
     }
     else
     {
-        wl_pointer_set_cursor (pointer, 0,
+        wl_pointer_set_cursor (pointer,
+                               input->pointer_enter_serial,
                                NULL,
                                0,
                                0);