SDL: win32: Restore the base size of a window when leaving fullscreen

From 6449339ae353de91440a05305222c56ed328602c Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 20 Jan 2025 14:04:33 -0500
Subject: [PATCH] win32: Restore the base size of a window when leaving
 fullscreen

Always restore the base floating size of a window before possibly entering the maximized state, as base size can be lost during the fullscreen transition, resulting in the window de-maximizing to the wrong size.
---
 src/video/windows/SDL_windowsevents.c | 28 ++++++++++++++-------------
 src/video/windows/SDL_windowswindow.c | 17 +++++++++-------
 src/video/windows/SDL_windowswindow.h |  1 +
 3 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 459f43dfa5202..3ef492ec5679b 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1633,23 +1633,25 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
             break;
         }
 
-        if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
-            ClientToScreen(hwnd, (LPPOINT) &rect);
-            ClientToScreen(hwnd, (LPPOINT) &rect + 1);
+        if (!data->disable_move_size_events) {
+            if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
+                ClientToScreen(hwnd, (LPPOINT) &rect);
+                ClientToScreen(hwnd, (LPPOINT) &rect + 1);
 
-            x = rect.left;
-            y = rect.top;
+                x = rect.left;
+                y = rect.top;
 
-            SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
-            SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
-        }
+                SDL_GlobalToRelativeForWindow(data->window, x, y, &x, &y);
+                SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MOVED, x, y);
+            }
 
-        // Moving the window from one display to another can change the size of the window (in the handling of SDL_EVENT_WINDOW_MOVED), so we need to re-query the bounds
-        if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
-            w = rect.right;
-            h = rect.bottom;
+            // Moving the window from one display to another can change the size of the window (in the handling of SDL_EVENT_WINDOW_MOVED), so we need to re-query the bounds
+            if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
+                w = rect.right;
+                h = rect.bottom;
 
-            SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, w, h);
+                SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, w, h);
+            }
         }
 
         WIN_UpdateClipCursor(data->window);
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index b3d2d69f23b9f..6ca0bfde57bc6 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -1377,28 +1377,31 @@ SDL_FullscreenResult WIN_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window
            https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
         */
         if (data->windowed_mode_was_maximized && !data->in_window_deactivation) {
-            style |= WS_MAXIMIZE;
             enterMaximized = true;
+            data->disable_move_size_events = true;
         }
 
         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
         WIN_AdjustWindowRectWithStyle(window, style, styleEx, menu,
                                       &x, &y,
                                       &w, &h,
-                                      data->windowed_mode_was_maximized ? SDL_WINDOWRECT_WINDOWED : SDL_WINDOWRECT_FLOATING);
+                                      SDL_WINDOWRECT_FLOATING);
         data->windowed_mode_was_maximized = false;
     }
+
+    /* Always reset the window to the base floating size before possibly re-applying the maximized state,
+     * otherwise, the base floating size can seemingly be lost in some cases.
+     */
     SetWindowLong(hwnd, GWL_STYLE, style);
     data->expected_resize = true;
+    SetWindowPos(hwnd, top, x, y, w, h, data->copybits_flag | SWP_NOACTIVATE);
+    data->expected_resize = false;
+    data->disable_move_size_events = false;
 
-    if (!enterMaximized) {
-        SetWindowPos(hwnd, top, x, y, w, h, data->copybits_flag | SWP_NOACTIVATE);
-    } else {
+    if (enterMaximized) {
         WIN_MaximizeWindow(_this, window);
     }
 
-    data->expected_resize = false;
-
 #ifdef HIGHDPI_DEBUG
     SDL_Log("WIN_SetWindowFullscreen: %d finished. Set window to %d,%d, %dx%d", (int)fullscreen, x, y, w, h);
 #endif
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 467c5b893fffa..1430dee572b08 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -82,6 +82,7 @@ struct SDL_WindowData
     bool windowed_mode_was_maximized;
     bool in_window_deactivation;
     bool force_resizable;
+    bool disable_move_size_events;
     RECT initial_size_rect;
     RECT cursor_clipped_rect; // last successfully committed clipping rect for this window
     RECT cursor_ctrlock_rect; // this is Windows-specific, but probably does not need to be per-window