-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SDL3] Win32 darkmode doesn't apply for title bar's context menu #11535
Milestone
Comments
I noticed the same with all other Windows 10 apps as well. Probably not an SDL thing. |
BTW, here is C++ code I used for my SDL2 game: #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <app.hpp>
#include "SDL_syswm.h"
#ifdef _MSC_VER
#pragma comment(lib, "ntdll.lib")
#endif
#ifndef NTAPI
#define NTAPI __stdcall
#endif
#ifndef NTSYSAPI
#define NTSYSAPI declspec(dllimport)
#endif
#define LOAD_FUNC_ORD(func_name, func_ord) do { \
win_dark.func_name = reinterpret_cast<func_name##_t>(GetProcAddress(win_dark.uxtheme_handle, MAKEINTRESOURCEA(func_ord))); \
if (win_dark.func_name == NULL) { \
app->show_error("failed to load uxtheme.dll func " #func_name); \
FreeLibrary(win_dark.uxtheme_handle); \
return true; \
} \
} while (0)
typedef LONG WIN_NTDLL_NTSTATUS;
typedef struct {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
USHORT wServicePackMajor;
USHORT wServicePackMinor;
USHORT wSuiteMask;
UCHAR wProductType;
UCHAR wReserved;
} WIN_NTDLL_OSVERSIONINFOEXW;
typedef enum {
WIN_APPMODE_DEFAULT,
WIN_APPMODE_ALLOW_DARK,
WIN_APPMODE_FORCE_DARK,
WIN_APPMODE_FORCE_LIGHT,
WIN_APPMODE_MAX
} WinPreferredAppMode;
enum WINDOWCOMPOSITIONATTRIB {
WCA_UNDEFINED = 0,
WCA_NCRENDERING_ENABLED = 1,
WCA_NCRENDERING_POLICY = 2,
WCA_TRANSITIONS_FORCEDISABLED = 3,
WCA_ALLOW_NCPAINT = 4,
WCA_CAPTION_BUTTON_BOUNDS = 5,
WCA_NONCLIENT_RTL_LAYOUT = 6,
WCA_FORCE_ICONIC_REPRESENTATION = 7,
WCA_EXTENDED_FRAME_BOUNDS = 8,
WCA_HAS_ICONIC_BITMAP = 9,
WCA_THEME_ATTRIBUTES = 10,
WCA_NCRENDERING_EXILED = 11,
WCA_NCADORNMENTINFO = 12,
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
WCA_VIDEO_OVERLAY_ACTIVE = 14,
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
WCA_DISALLOW_PEEK = 16,
WCA_CLOAK = 17,
WCA_CLOAKED = 18,
WCA_ACCENT_POLICY = 19,
WCA_FREEZE_REPRESENTATION = 20,
WCA_EVER_UNCLOAKED = 21,
WCA_VISUAL_OWNER = 22,
WCA_HOLOGRAPHIC = 23,
WCA_EXCLUDED_FROM_DDA = 24,
WCA_PASSIVEUPDATEMODE = 25,
WCA_USEDARKMODECOLORS = 26,
WCA_LAST = 27
};
typedef struct {
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;
typedef bool (WINAPI *ShouldAppsUseDarkMode_t)(void);
typedef void (WINAPI *AllowDarkModeForWindow_t)(HWND, bool);
typedef void (WINAPI *AllowDarkModeForApp_t)(bool);
typedef void (WINAPI *FlushMenuThemes_t)(void);
typedef void (WINAPI *RefreshImmersiveColorPolicyState_t)(void);
typedef bool (WINAPI *IsDarkModeAllowedForWindow_t)(HWND);
typedef bool (WINAPI *ShouldSystemUseDarkMode_t)(void);
typedef WinPreferredAppMode (WINAPI *SetPreferredAppMode_t)(WinPreferredAppMode);
typedef bool (WINAPI *IsDarkModeAllowedForApp_t)(void);
typedef BOOL (WINAPI *SetWindowCompositionAttribute_t)(HWND, const WINDOWCOMPOSITIONATTRIBDATA*);
typedef struct {
HMODULE uxtheme_handle;
HMODULE user32_handle;
ShouldAppsUseDarkMode_t ShouldAppsUseDarkMode;
AllowDarkModeForWindow_t AllowDarkModeForWindow;
AllowDarkModeForApp_t AllowDarkModeForApp;
FlushMenuThemes_t FlushMenuThemes;
RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyState;
IsDarkModeAllowedForWindow_t IsDarkModeAllowedForWindow;
ShouldSystemUseDarkMode_t ShouldSystemUseDarkMode;
SetPreferredAppMode_t SetPreferredAppMode;
IsDarkModeAllowedForApp_t IsDarkModeAllowedForApp;
SetWindowCompositionAttribute_t SetWindowCompositionAttribute;
DWORD build_num;
} win_dark_type;
static win_dark_type win_dark;
// Ugly import from ntdll
extern "C" NTSYSAPI WIN_NTDLL_NTSTATUS NTAPI RtlGetVersion(WIN_NTDLL_OSVERSIONINFOEXW* ver_info);
bool app_fix_win32_theme(App* app) {
win_dark.uxtheme_handle = NULL;
win_dark.user32_handle = NULL;
WIN_NTDLL_OSVERSIONINFOEXW os_ver;
os_ver.dwOSVersionInfoSize = sizeof(WIN_NTDLL_OSVERSIONINFOEXW);
RtlGetVersion(&os_ver);
win_dark.build_num = os_ver.dwBuildNumber;
win_dark.build_num &= ~0xF0000000;
if (win_dark.build_num < 17763)
return false; // windows is too old
win_dark.uxtheme_handle = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_SEARCH_SYSTEM32);
if (win_dark.uxtheme_handle == NULL) {
app->show_error("failed to load uxtheme.dll");
return true;
};
win_dark.user32_handle = LoadLibraryExW(L"user32.dll", NULL, LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_SEARCH_SYSTEM32);
if (win_dark.user32_handle == NULL) {
FreeLibrary(win_dark.uxtheme_handle);
app->show_error("failed to load user32.dll");
return true;
};
win_dark.SetWindowCompositionAttribute = (SetWindowCompositionAttribute_t)GetProcAddress(win_dark.user32_handle, "SetWindowCompositionAttribute");
LOAD_FUNC_ORD(ShouldAppsUseDarkMode, 132);
LOAD_FUNC_ORD(AllowDarkModeForWindow, 133);
if (win_dark.build_num < 18362) {
win_dark.SetPreferredAppMode = NULL;
LOAD_FUNC_ORD(AllowDarkModeForApp, 135);
}
else {
win_dark.AllowDarkModeForApp = NULL;
LOAD_FUNC_ORD(SetPreferredAppMode, 135);
}
LOAD_FUNC_ORD(FlushMenuThemes, 136);
LOAD_FUNC_ORD(RefreshImmersiveColorPolicyState, 104);
LOAD_FUNC_ORD(IsDarkModeAllowedForWindow, 137);
if (win_dark.build_num >= 18290)
LOAD_FUNC_ORD(ShouldSystemUseDarkMode, 138);
else
win_dark.ShouldSystemUseDarkMode = NULL;
if (win_dark.build_num >= 18334)
LOAD_FUNC_ORD(IsDarkModeAllowedForApp, 139);
else
win_dark.IsDarkModeAllowedForApp = NULL;
// Get HWND
SDL_SysWMinfo wm_info;
SDL_VERSION(&wm_info.version);
HWND hwnd = NULL;
if (SDL_GetWindowWMInfo(app->w, &wm_info) == SDL_TRUE)
hwnd = wm_info.info.win.window;
else {
FreeLibrary(win_dark.user32_handle);
FreeLibrary(win_dark.uxtheme_handle);
app->show_error("Failed to get window HWND");
return true;
}
// Let's begin our magic
if (win_dark.AllowDarkModeForApp != NULL)
win_dark.AllowDarkModeForApp(true);
if (win_dark.SetPreferredAppMode != NULL)
win_dark.SetPreferredAppMode(WIN_APPMODE_ALLOW_DARK);
win_dark.RefreshImmersiveColorPolicyState();
win_dark.AllowDarkModeForWindow(hwnd, true);
bool enable_dark = win_dark.ShouldAppsUseDarkMode();
BOOL win_dark = enable_dark ? TRUE : FALSE;
if (win_dark.build_num < 18362)
SetPropW(hwnd, L"UseImmersiveDarkModeColors", reinterpret_cast<HANDLE>(static_cast<INT_PTR>(win_dark)));
else if (win_dark.SetWindowCompositionAttribute != NULL) {
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &win_dark, sizeof(win_dark) };
win_dark.SetWindowCompositionAttribute(hwnd, &data);
}
FreeLibrary(win_dark.user32_handle);
FreeLibrary(win_dark.uxtheme_handle);
return false;
}
#endif
|
Feel free to submit a PR to fix this. I'm bumping it out of the 3.2.0 milestone so we can focus on shipping blockers. |
the title bar context menu is one of many that is not dark mode implemented in the shell, and must be handled explicitly by the application developer. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just a small visual bug:

The text was updated successfully, but these errors were encountered: