SDL: video: Fix window manager initiated fullscreen window moves

From 8d25c2d2609494ea4ce4018b8b964a706ab40b28 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Sat, 20 Jan 2024 13:18:23 -0500
Subject: [PATCH] video: Fix window manager initiated fullscreen window moves

Distinguish between and handle fullscreen window moves initiated by the window manager vs the application to avoid cases where the window snaps back to the original display when moved due to the use of old coordinates.
---
 src/video/SDL_sysvideo.h |  1 +
 src/video/SDL_video.c    | 13 ++++++++++---
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 8e5e766900d5..7df06da787ad 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -86,6 +86,7 @@ struct SDL_Window
     SDL_Surface *surface;
     SDL_bool surface_valid;
 
+    SDL_bool is_repositioning; /* Set during an SDL_SetWindowPosition() call. */
     SDL_bool is_hiding;
     SDL_bool restore_on_show; /* Child was hidden recursively by the parent, restore when shown. */
     SDL_bool is_destroying;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index dc36afab2c75..0f5f59f6e440 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -1402,14 +1402,19 @@ SDL_VideoDisplay *SDL_GetVideoDisplayForFullscreenWindow(SDL_Window *window)
     }
 
     /* The floating position is used here as a very common pattern is
-     * SDL_SetWindowPosition() followed by SDL_SetWindowFullscreen to make the
+     * SDL_SetWindowPosition() followed by SDL_SetWindowFullscreen() to make the
      * window fullscreen desktop on a specific display. If the backend doesn't
      * support changing the window position, or the compositor hasn't yet actually
-     * moved the window, the actual position won't be updated at the time of the
+     * moved the window, the current position won't be updated at the time of the
      * fullscreen call.
      */
     if (!displayID) {
-        displayID = GetDisplayForRect(window->floating.x, window->floating.y, window->w, window->h);
+        if (window->flags & SDL_WINDOW_FULLSCREEN && !window->is_repositioning) {
+            /* This was a window manager initiated move, use the current position. */
+            displayID = GetDisplayForRect(window->x, window->y, window->w, window->h);
+        } else {
+            displayID = GetDisplayForRect(window->floating.x, window->floating.y, window->w, window->h);
+        }
     }
     if (!displayID) {
         /* Use the primary display for a window if we can't find it anywhere else */
@@ -2500,7 +2505,9 @@ int SDL_SetWindowPosition(SDL_Window *window, int x, int y)
     window->undefined_y = SDL_FALSE;
 
     if (_this->SetWindowPosition) {
+        window->is_repositioning = SDL_TRUE;
         const int ret = _this->SetWindowPosition(_this, window);
+        window->is_repositioning = SDL_FALSE;
         if (!ret) {
             SDL_SyncIfRequired(window);
         }