From 599b4ef2546f6b1147035e6465cebb789705818b Mon Sep 17 00:00:00 2001 From: Frank Praznik 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 4802303cca..641ff9b272 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 b07d7dc0fb..a5d17c0f30 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 ddc3ddd6d9..3a21a1c258 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;