From e0c2cca629e4a3f3910d5a3d5c88e257ef6bef51 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 26 Jan 2024 23:05:31 -0800
Subject: [PATCH] Fixed fullscreen windows having rounded corners and 1px
transparent borders on Windows 11.
When an app makes a fullscreen window on Windows, the window is really just resized to the monitor dimensions and positioned at 0, 0 and positioned on top of everything, including the taskbar. Added disabling rounded corners and some new DWM controlled border color (which seems to be defaulted to 1px transparent, but can be set to the theme color by users). Previous settings are restored when exiting fullscreen mode.
---
src/video/windows/SDL_windowswindow.c | 78 ++++++++++++++++++++++++++-
src/video/windows/SDL_windowswindow.h | 2 +
2 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 789411bcba13..d1e4f02b4af8 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -37,11 +37,38 @@
/* Dropfile support */
#include <shellapi.h>
-/* Dark mode support */
+/* DWM setting support */
+typedef HRESULT (WINAPI *DwmSetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
+typedef HRESULT (WINAPI *DwmGetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
+
+/* Dark mode support*/
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
-typedef HRESULT (WINAPI *DwmSetWindowAttribute_t)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute);
+
+/* Corner rounding support (Win 11+) */
+#ifndef DWMWA_WINDOW_CORNER_PREFERENCE
+#define DWMWA_WINDOW_CORNER_PREFERENCE 33
+#endif
+typedef enum {
+ DWMWCP_DEFAULT = 0,
+ DWMWCP_DONOTROUND = 1,
+ DWMWCP_ROUND = 2,
+ DWMWCP_ROUNDSMALL = 3
+} DWM_WINDOW_CORNER_PREFERENCE;
+
+/* Border Color support (Win 11+) */
+#ifndef DWMWA_BORDER_COLOR
+#define DWMWA_BORDER_COLOR 34
+#endif
+
+#ifndef DWMWA_COLOR_DEFAULT
+#define DWMWA_COLOR_DEFAULT 0xFFFFFFFF
+#endif
+
+#ifndef DWMWA_COLOR_NONE
+#define DWMWA_COLOR_NONE 0xFFFFFFFE
+#endif
/* Transparent window support */
#ifndef DWM_BB_ENABLE
@@ -347,6 +374,8 @@ static int SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, HWND hwnd
data->videodata = videodata;
data->initializing = SDL_TRUE;
data->last_displayID = window->last_displayID;
+ data->dwma_border_color = DWMWA_COLOR_DEFAULT;
+
if (SDL_GetHintBoolean("SDL_WINDOW_RETAIN_CONTENT", SDL_FALSE)) {
data->copybits_flag = 0;
} else {
@@ -1115,6 +1144,44 @@ void WIN_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window)
data->expected_resize = SDL_FALSE;
}
+static DWM_WINDOW_CORNER_PREFERENCE WIN_UpdateCornerRoundingForHWND(HWND hwnd, DWM_WINDOW_CORNER_PREFERENCE cornerPref)
+{
+ DWM_WINDOW_CORNER_PREFERENCE oldPref = DWMWCP_DEFAULT;
+
+ void *handle = SDL_LoadObject("dwmapi.dll");
+ if (handle) {
+ DwmGetWindowAttribute_t DwmGetWindowAttributeFunc = (DwmGetWindowAttribute_t)SDL_LoadFunction(handle, "DwmGetWindowAttribute");
+ DwmSetWindowAttribute_t DwmSetWindowAttributeFunc = (DwmSetWindowAttribute_t)SDL_LoadFunction(handle, "DwmSetWindowAttribute");
+ if (DwmGetWindowAttributeFunc && DwmSetWindowAttributeFunc) {
+ DwmGetWindowAttributeFunc(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &oldPref, sizeof(oldPref));
+ DwmSetWindowAttributeFunc(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
+ }
+
+ SDL_UnloadObject(handle);
+ }
+
+ return oldPref;
+}
+
+static COLORREF WIN_UpdateBorderColorForHWND(HWND hwnd, COLORREF colorRef)
+{
+ COLORREF oldPref = DWMWA_COLOR_DEFAULT;
+
+ void *handle = SDL_LoadObject("dwmapi.dll");
+ if (handle) {
+ DwmGetWindowAttribute_t DwmGetWindowAttributeFunc = (DwmGetWindowAttribute_t)SDL_LoadFunction(handle, "DwmGetWindowAttribute");
+ DwmSetWindowAttribute_t DwmSetWindowAttributeFunc = (DwmSetWindowAttribute_t)SDL_LoadFunction(handle, "DwmSetWindowAttribute");
+ if (DwmGetWindowAttributeFunc && DwmSetWindowAttributeFunc) {
+ DwmGetWindowAttributeFunc(hwnd, DWMWA_BORDER_COLOR, &oldPref, sizeof(oldPref));
+ DwmSetWindowAttributeFunc(hwnd, DWMWA_BORDER_COLOR, &colorRef, sizeof(colorRef));
+ }
+
+ SDL_UnloadObject(handle);
+ }
+
+ return oldPref;
+}
+
/**
* Reconfigures the window to fill the given display, if fullscreen is true, otherwise restores the window.
*/
@@ -1175,9 +1242,16 @@ int WIN_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_Vide
data->windowed_mode_was_maximized = SDL_TRUE;
style &= ~WS_MAXIMIZE;
}
+
+ /* Disable corner rounding & border color (Windows 11+) so the window fills the full screen */
+ data->windowed_mode_corner_rounding = WIN_UpdateCornerRoundingForHWND(hwnd, DWMWCP_DONOTROUND);
+ data->dwma_border_color = WIN_UpdateBorderColorForHWND(hwnd, DWMWA_COLOR_NONE);
} else {
BOOL menu;
+ WIN_UpdateCornerRoundingForHWND(hwnd, data->windowed_mode_corner_rounding);
+ WIN_UpdateBorderColorForHWND(hwnd, data->dwma_border_color);
+
/* Restore window-maximization state, as applicable.
Special care is taken to *not* do this if and when we're
alt-tab'ing away (to some other window; as indicated by
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index 3c887df47728..1e8fded4879b 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -67,6 +67,8 @@ struct SDL_WindowData
SDL_bool windowed_mode_was_maximized;
SDL_bool in_window_deactivation;
RECT cursor_clipped_rect;
+ UINT windowed_mode_corner_rounding;
+ COLORREF dwma_border_color;
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
RAWINPUT *rawinput;
UINT rawinput_offset;