From 599b4ef2546f6b1147035e6465cebb789705818b Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Fri, 27 Dec 2024 12:02:33 -0500
Subject: [PATCH] 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.
---
src/video/windows/SDL_windowsevents.c | 9 +++++++--
src/video/windows/SDL_windowswindow.c | 11 ++++++++++-
src/video/windows/SDL_windowswindow.h | 1 +
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 4802303ccae4f..641ff9b272940 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/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)) {
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index b07d7dc0fb63f..a5d17c0f3008a 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/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;
}
}
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index ddc3ddd6d9797..3a21a1c258726 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/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;