SDL: video: Disable mouse warp on fullscreen transitions for Wayland and XWayland

From b1e01b971b9d5967168539e2ce65e80e98d93a97 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sat, 18 May 2024 09:42:32 -0400
Subject: [PATCH] video: Disable mouse warp on fullscreen transitions for
 Wayland and XWayland

At best, it simply doesn't work, and if it does, it frequently warps the pointer to the wrong position as the window animates in/out of fullscreen mode.

It can also inadvertently trigger the relative warp mode emulation mode on Wayland if a fullscreen transition occurs while the client has the pointer hidden.
---
 src/video/SDL_sysvideo.h             |  3 ++-
 src/video/SDL_video.c                | 11 +++++++++--
 src/video/wayland/SDL_waylandvideo.c |  3 ++-
 src/video/x11/SDL_x11video.c         |  3 ++-
 4 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 7cf30ade20778..eb0f57c15bca4 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -158,7 +158,8 @@ typedef enum
     VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT = 0x02,
     VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS = 0x04,
     VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY = 0x08,
-    VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES = 0x10
+    VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES = 0x10,
+    VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS = 0x20
 } DeviceCaps;
 
 struct SDL_VideoDevice
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index bfe79182a18db..bd8f079b4e32b 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -190,6 +190,11 @@ static SDL_bool SDL_SendsDisplayChanges(SDL_VideoDevice *_this)
     return !!(_this->device_caps & VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES);
 }
 
+static SDL_bool SDL_DisableMouseWarpOnFullscreenTransitions(SDL_VideoDevice *_this)
+{
+    return !!(_this->device_caps & VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS);
+}
+
 /* Hint to treat all window ops as synchronous */
 static SDL_bool syncHint;
 
@@ -1822,7 +1827,9 @@ int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen, SDL_bool c
             }
 
             /* Restore the cursor position */
-            SDL_RestoreMousePosition(window);
+            if (!SDL_DisableMouseWarpOnFullscreenTransitions(_this)) {
+                SDL_RestoreMousePosition(window);
+            }
         }
     } else {
         SDL_bool resized = SDL_FALSE;
@@ -1866,7 +1873,7 @@ int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen, SDL_bool c
             }
 
             /* Restore the cursor position if we've exited fullscreen on a display */
-            if (display) {
+            if (display && !SDL_DisableMouseWarpOnFullscreenTransitions(_this)) {
                 SDL_RestoreMousePosition(window);
             }
         }
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 5e94d4f44ab82..5f50c79a90e58 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -523,7 +523,8 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
     device->device_caps = VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |
                           VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT |
                           VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS |
-                          VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES;
+                          VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES |
+                          VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS;
 
     return device;
 }
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 64ffb763fc037..952c501d97e74 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -292,7 +292,8 @@ static SDL_VideoDevice *X11_CreateDevice(void)
 
     data->is_xwayland = X11_IsXWayland(x11_display);
     if (data->is_xwayland) {
-        device->device_caps |= VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED;
+        device->device_caps |= VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |
+                               VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS;
     }
 
     return device;