Browse Source

win32: Fix maximizing borderless windows

Even if a borderless window doesn't have resizable borders set, the WS_MAXIMIZEBOX property needs to be set on the window, or maximizing it will make it fullscreen and cover the taskbar, instead of only filling the usable desktop space, as is usually expected from a maximized window. This style property needs to be retained until the window is no longer maximized, even if the resize flag is toggled off, or restoring from minimized can fail.
Frank Praznik 3 months ago
parent
commit
599b4ef254

+ 7 - 2
src/video/windows/SDL_windowsevents.c

@@ -1473,8 +1473,13 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
                 SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
             }
             SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_MAXIMIZED, 0, 0);
+            data->force_resizable = true;
         } else if (data->window->flags & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MINIMIZED)) {
             SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
+
+            // If resizable was forced on for the maximized window, clear the style flags now.
+            data->force_resizable = false;
+            WIN_SetWindowResizable(SDL_GetVideoDevice(), data->window, !!(data->window->flags & SDL_WINDOW_RESIZABLE));
         }
 
         if (windowpos->flags & SWP_HIDEWINDOW) {
@@ -1873,14 +1878,14 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
             NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
             WINDOWPLACEMENT placement;
             if (GetWindowPlacement(hwnd, &placement) && placement.showCmd == SW_MAXIMIZE) {
-                // Maximized borderless windows should use the full monitor size
+                // Maximized borderless windows should use the monitor work area.
                 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
                 if (hMonitor) {
                     MONITORINFO info;
                     SDL_zero(info);
                     info.cbSize = sizeof(info);
                     if (GetMonitorInfo(hMonitor, &info)) {
-                        params->rgrc[0] = info.rcMonitor;
+                        params->rgrc[0] = info.rcWork;
                     }
                 }
             } else if (!(window_flags & SDL_WINDOW_RESIZABLE)) {

+ 10 - 1
src/video/windows/SDL_windowswindow.c

@@ -180,13 +180,22 @@ static DWORD GetWindowStyle(SDL_Window *window)
             style |= STYLE_NORMAL;
         }
 
-        if (window->flags & SDL_WINDOW_RESIZABLE) {
+        /* The WS_MAXIMIZEBOX style flag needs to be retained for as long as the window is maximized,
+         * or restoration from minimized can fail, and leaving maximized can result in an odd size.
+         */
+        if ((window->flags & SDL_WINDOW_RESIZABLE) || (window->internal && window->internal->force_resizable)) {
             /* You can have a borderless resizable window, but Windows doesn't always draw it correctly,
                see https://bugzilla.libsdl.org/show_bug.cgi?id=4466
              */
             if (!(window->flags & SDL_WINDOW_BORDERLESS) ||
                 SDL_GetHintBoolean("SDL_BORDERLESS_RESIZABLE_STYLE", false)) {
                 style |= STYLE_RESIZABLE;
+            } else if (window->flags & SDL_WINDOW_BORDERLESS) {
+                /* Even if the resizable style hint isn't set, WS_MAXIMIZEBOX is still needed, or
+                 * maximizing the window will make it fullscreen and cover the taskbar, instead
+                 * of entering a normal maximized state that fills the usable desktop area.
+                 */
+                style |= WS_MAXIMIZEBOX;
             }
         }
 

+ 1 - 0
src/video/windows/SDL_windowswindow.h

@@ -81,6 +81,7 @@ struct SDL_WindowData
     bool skip_update_clipcursor;
     bool windowed_mode_was_maximized;
     bool in_window_deactivation;
+    bool force_resizable;
     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;