SDL: win32: Use the size in the WINDOWPOS data while handling popup windows in the WM_WINDOWPOSCHANGED message

From 4f0a056b953800154ccbf8368f3877687fa29150 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Tue, 31 Dec 2024 13:00:40 -0500
Subject: [PATCH] win32: Use the size in the WINDOWPOS data while handling
 popup windows in the WM_WINDOWPOSCHANGED message

GetClientRect() returns old, incorrect size data for popup windows when called while processing the WM_WINDOWPOSCHANGED message, so use the WINDOWPOS data instead.

Popups can't be maximized or fullscreen, so no need to worry about a move event resizing them.
---
 src/video/windows/SDL_windowsevents.c | 19 +++++++++++++++----
 src/video/windows/SDL_windowswindow.c |  6 +++++-
 src/video/windows/SDL_windowswindow.h |  2 ++
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 73f3c627e46ad..ae50f2536c9f4 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -1506,12 +1506,23 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
             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;
+        // GetClientRect() returns the old size for popup windows for some reason.
+        if (!SDL_WINDOW_IS_POPUP(data->window)) {
+            // 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);
+            }
+        } else {
+            // Cache the data, as a resize event will call GetWindowSizeInPixels().
+            w = data->last_popup_width = windowpos->cx;
+            h = data->last_popup_height = windowpos->cy;
 
+            data->use_last_popup_size = true;
             SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESIZED, w, h);
+            data->use_last_popup_size = false;
         }
 
         WIN_UpdateClipCursor(data->window);
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index a5d17c0f3008a..2a315f7b36d5e 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -1053,7 +1053,11 @@ void WIN_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *
     HWND hwnd = data->hwnd;
     RECT rect;
 
-    if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
+    // GetClientRect() returns the wrong size for popup windows if called while handling WM_WINDOWPOSCHANGED.
+    if (data->use_last_popup_size) {
+        *w = data->last_popup_width;
+        *h = data->last_popup_height;
+    } else if (GetClientRect(hwnd, &rect) && !WIN_IsRectEmpty(&rect)) {
         *w = rect.right;
         *h = rect.bottom;
     } else if (window->last_pixel_w && window->last_pixel_h) {
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 3a21a1c258726..07877fa554aac 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -82,6 +82,8 @@ struct SDL_WindowData
     bool windowed_mode_was_maximized;
     bool in_window_deactivation;
     bool force_resizable;
+    bool use_last_popup_size;
+    int last_popup_width, last_popup_height;
     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
     UINT windowed_mode_corner_rounding;