Allow building the tray subsystem without the video subsystem

Fixes https://github.com/libsdl-org/SDL/issues/13235
This commit is contained in:
Sam Lantinga
2025-08-27 07:34:18 -07:00
parent 943d0f67ba
commit da6e9bbf7c
18 changed files with 219 additions and 263 deletions

View File

@@ -253,6 +253,7 @@ define_sdl_subsystem(Hidapi)
define_sdl_subsystem(Power)
define_sdl_subsystem(Sensor)
define_sdl_subsystem(Dialog)
define_sdl_subsystem(Tray)
cmake_dependent_option(SDL_FRAMEWORK "Build SDL libraries as Apple Framework" OFF "APPLE" OFF)
if(SDL_FRAMEWORK)
@@ -410,6 +411,7 @@ if (NGAGE)
set(SDL_DUMMYVIDEO OFF)
set(SDL_OFFSCREEN OFF)
set(SDL_RENDER_GPU OFF)
set(SDL_TRAY OFF)
set(SDL_VIRTUAL_JOYSTICK OFF)
endif()
@@ -1752,7 +1754,9 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
CheckVivante()
CheckVulkan()
CheckQNXScreen()
endif()
if(SDL_TRAY)
sdl_glob_sources(
"${SDL3_SOURCE_DIR}/src/tray/unix/*.c"
"${SDL3_SOURCE_DIR}/src/tray/unix/*.h"
@@ -2330,7 +2334,9 @@ elseif(WINDOWS)
set(HAVE_RENDER_VULKAN TRUE)
endif()
endif()
endif()
if(SDL_TRAY)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/windows/*.c")
set(HAVE_SDL_TRAY TRUE)
endif()
@@ -2646,11 +2652,11 @@ elseif(APPLE)
endif()
endif()
endif()
endif()
if(MACOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/cocoa/*.m")
set(HAVE_SDL_TRAY TRUE)
endif()
if(SDL_TRAY AND MACOS)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/tray/cocoa/*.m")
set(HAVE_SDL_TRAY TRUE)
endif()
# Minimum version for $<LINK_LIBRARY:feature,library-list>

View File

@@ -889,7 +889,6 @@
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />

View File

@@ -191,7 +191,6 @@
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />

View File

@@ -744,7 +744,6 @@
<ClCompile Include="..\..\src\video\SDL_video_unsupported.c" />
<ClCompile Include="..\..\src\video\SDL_vulkan_utils.c" />
<ClCompile Include="..\..\src\video\SDL_yuv.c" />
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
<ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
@@ -775,4 +774,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -1356,9 +1356,6 @@
<ClCompile Include="..\..\src\video\dummy\SDL_nullvideo.c">
<Filter>video\dummy</Filter>
</ClCompile>
<ClCompile Include="..\..\src\video\windows\SDL_surface_utils.c">
<Filter>video\windows</Filter>
</ClCompile>
<ClCompile Include="..\..\src\video\windows\SDL_windowsclipboard.c">
<Filter>video\windows</Filter>
</ClCompile>
@@ -1618,4 +1615,4 @@
<ItemGroup>
<ResourceCompile Include="..\..\src\core\windows\version.rc" />
</ItemGroup>
</Project>
</Project>

View File

@@ -540,6 +540,9 @@
/* Enable dialog subsystem */
#cmakedefine SDL_DIALOG_DUMMY 1
/* Enable tray subsystem */
#cmakedefine SDL_TRAY_DUMMY 1
/* Enable assembly routines */
#cmakedefine SDL_ALTIVEC_BLITTERS 1

View File

@@ -208,6 +208,9 @@
#define SDL_CAMERA_DRIVER_ANDROID 1
#endif /* SDL_CAMERA_DISABLED */
/* Enable tray subsystem */
#define SDL_TRAY_DUMMY 1
/* Enable nl_langinfo and high-res file times on version 26 and higher. */
#if __ANDROID_API__ >= 26
#define HAVE_NL_LANGINFO 1

View File

@@ -223,4 +223,7 @@
/* Enable dialog subsystem */
#define SDL_DIALOG_DUMMY 1
/* Enable tray subsystem */
#define SDL_TRAY_DUMMY 1
#endif /* SDL_build_config_ios_h_ */

View File

@@ -98,4 +98,7 @@ typedef unsigned int uintptr_t;
/* Enable dialog subsystem */
#define SDL_DIALOG_DUMMY 1
/* Enable tray subsystem */
#define SDL_TRAY_DUMMY 1
#endif /* SDL_build_config_minimal_h_ */

View File

@@ -220,4 +220,7 @@
/* Enable dialog subsystem */
#define SDL_DIALOG_DUMMY 1
/* Enable tray subsystem */
#define SDL_TRAY_DUMMY 1
#endif /* SDL_build_config_wingdk_h_ */

View File

@@ -24,6 +24,8 @@
#include "SDL_windows.h"
#include "../../video/SDL_surface_c.h"
#include <objbase.h> // for CoInitialize/CoUninitialize (Win32 only)
#ifdef HAVE_ROAPI_H
#include <roapi.h> // For RoInitialize/RoUninitialize (Win32 only)
@@ -53,6 +55,44 @@ typedef enum RO_INIT_TYPE
#define WC_ERR_INVALID_CHARS 0x00000080
#endif
// Dark mode support
typedef enum {
UXTHEME_APPMODE_DEFAULT,
UXTHEME_APPMODE_ALLOW_DARK,
UXTHEME_APPMODE_FORCE_DARK,
UXTHEME_APPMODE_FORCE_LIGHT,
UXTHEME_APPMODE_MAX
} UxthemePreferredAppMode;
typedef enum {
WCA_UNDEFINED = 0,
WCA_USEDARKMODECOLORS = 26,
WCA_LAST = 27
} WINDOWCOMPOSITIONATTRIB;
typedef struct {
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;
typedef struct {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
} NT_OSVERSIONINFOW;
typedef bool (WINAPI *ShouldAppsUseDarkMode_t)(void);
typedef void (WINAPI *AllowDarkModeForWindow_t)(HWND, bool);
typedef void (WINAPI *AllowDarkModeForApp_t)(bool);
typedef void (WINAPI *RefreshImmersiveColorPolicyState_t)(void);
typedef UxthemePreferredAppMode (WINAPI *SetPreferredAppMode_t)(UxthemePreferredAppMode);
typedef BOOL (WINAPI *SetWindowCompositionAttribute_t)(HWND, const WINDOWCOMPOSITIONATTRIBDATA *);
typedef void (NTAPI *RtlGetVersion_t)(NT_OSVERSIONINFOW *);
// Fake window to help with DirectInput events.
HWND SDL_HelperWindow = NULL;
static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
@@ -408,6 +448,148 @@ bool WIN_WindowRectValid(const RECT *rect)
return (rect->right > 0);
}
void WIN_UpdateDarkModeForHWND(HWND hwnd)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
HMODULE ntdll = LoadLibrary(TEXT("ntdll.dll"));
if (!ntdll) {
return;
}
// There is no function to get Windows build number, so let's get it here via RtlGetVersion
RtlGetVersion_t RtlGetVersionFunc = (RtlGetVersion_t)GetProcAddress(ntdll, "RtlGetVersion");
NT_OSVERSIONINFOW os_info;
os_info.dwOSVersionInfoSize = sizeof(NT_OSVERSIONINFOW);
os_info.dwBuildNumber = 0;
if (RtlGetVersionFunc) {
RtlGetVersionFunc(&os_info);
}
FreeLibrary(ntdll);
os_info.dwBuildNumber &= ~0xF0000000;
if (os_info.dwBuildNumber < 17763) {
// Too old to support dark mode
return;
}
HMODULE uxtheme = LoadLibrary(TEXT("uxtheme.dll"));
if (!uxtheme) {
return;
}
RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyStateFunc = (RefreshImmersiveColorPolicyState_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(104));
ShouldAppsUseDarkMode_t ShouldAppsUseDarkModeFunc = (ShouldAppsUseDarkMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(132));
AllowDarkModeForWindow_t AllowDarkModeForWindowFunc = (AllowDarkModeForWindow_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(133));
if (os_info.dwBuildNumber < 18362) {
AllowDarkModeForApp_t AllowDarkModeForAppFunc = (AllowDarkModeForApp_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (AllowDarkModeForAppFunc) {
AllowDarkModeForAppFunc(true);
}
} else {
SetPreferredAppMode_t SetPreferredAppModeFunc = (SetPreferredAppMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (SetPreferredAppModeFunc) {
SetPreferredAppModeFunc(UXTHEME_APPMODE_ALLOW_DARK);
}
}
if (RefreshImmersiveColorPolicyStateFunc) {
RefreshImmersiveColorPolicyStateFunc();
}
if (AllowDarkModeForWindowFunc) {
AllowDarkModeForWindowFunc(hwnd, true);
}
BOOL value;
// Check dark mode using ShouldAppsUseDarkMode, but use SDL_GetSystemTheme as a fallback
if (ShouldAppsUseDarkModeFunc) {
value = ShouldAppsUseDarkModeFunc() ? TRUE : FALSE;
} else {
value = (SDL_GetSystemTheme() == SDL_SYSTEM_THEME_DARK) ? TRUE : FALSE;
}
FreeLibrary(uxtheme);
if (os_info.dwBuildNumber < 18362) {
SetProp(hwnd, TEXT("UseImmersiveDarkModeColors"), SDL_reinterpret_cast(HANDLE, SDL_static_cast(INT_PTR, value)));
} else {
HMODULE user32 = GetModuleHandle(TEXT("user32.dll"));
if (user32) {
SetWindowCompositionAttribute_t SetWindowCompositionAttributeFunc = (SetWindowCompositionAttribute_t)GetProcAddress(user32, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttributeFunc) {
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &value, sizeof(value) };
SetWindowCompositionAttributeFunc(hwnd, &data);
}
}
}
#endif
}
HICON WIN_CreateIconFromSurface(SDL_Surface *surface)
{
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
SDL_Surface *s = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
if (!s) {
return NULL;
}
/* The dimensions will be needed after s is freed */
const int width = s->w;
const int height = s->h;
BITMAPINFO bmpInfo;
SDL_zero(bmpInfo);
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = width;
bmpInfo.bmiHeader.biHeight = -height; /* Top-down bitmap */
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(NULL);
void *pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(hdc, &bmpInfo, DIB_RGB_COLORS, &pBits, NULL, 0);
if (!hBitmap) {
ReleaseDC(NULL, hdc);
SDL_DestroySurface(s);
return NULL;
}
SDL_memcpy(pBits, s->pixels, width * height * 4);
SDL_DestroySurface(s);
HBITMAP hMask = CreateBitmap(width, height, 1, 1, NULL);
if (!hMask) {
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
return NULL;
}
HDC hdcMem = CreateCompatibleDC(hdc);
HGDIOBJ oldBitmap = SelectObject(hdcMem, hMask);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
BYTE* pixel = (BYTE*)pBits + (y * width + x) * 4;
BYTE alpha = pixel[3];
COLORREF maskColor = (alpha == 0) ? RGB(0, 0, 0) : RGB(255, 255, 255);
SetPixel(hdcMem, x, y, maskColor);
}
}
ICONINFO iconInfo;
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = hMask;
iconInfo.hbmColor = hBitmap;
HICON hIcon = CreateIconIndirect(&iconInfo);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
DeleteObject(hMask);
ReleaseDC(NULL, hdc);
return hIcon;
#else
return NULL;
#endif
}
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
/* *INDENT-OFF* */ // clang-format off
static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };

View File

@@ -157,7 +157,11 @@ extern void WIN_RECTToRect(const RECT *winrect, SDL_Rect *sdlrect);
extern void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect);
// Returns false if a window client rect is not valid
bool WIN_WindowRectValid(const RECT *rect);
extern bool WIN_WindowRectValid(const RECT *rect);
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
extern HICON WIN_CreateIconFromSurface(SDL_Surface *surface);
extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);

View File

@@ -21,7 +21,7 @@
#include "SDL_internal.h"
#ifndef SDL_PLATFORM_MACOS
#ifdef SDL_TRAY_DUMMY
#include "../SDL_tray_utils.h"
@@ -140,4 +140,4 @@ void SDL_DestroyTray(SDL_Tray *tray)
{
}
#endif // !SDL_PLATFORM_MACOS
#endif // SDL_TRAY_DUMMY

View File

@@ -23,13 +23,10 @@
#include "../SDL_tray_utils.h"
#include "../../core/windows/SDL_windows.h"
#include "../../video/windows/SDL_windowswindow.h"
#include <windowsx.h>
#include <shellapi.h>
#include "../../video/windows/SDL_surface_utils.h"
#ifndef NOTIFYICON_VERSION_4
#define NOTIFYICON_VERSION_4 4
#endif
@@ -115,7 +112,7 @@ LRESULT CALLBACK TrayWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPar
case WM_TRAYICON:
if (LOWORD(lParam) == WM_CONTEXTMENU || LOWORD(lParam) == WM_LBUTTONUP) {
SetForegroundWindow(hwnd);
if (tray->menu) {
TrackPopupMenu(tray->menu->hMenu, TPM_BOTTOMALIGN | TPM_RIGHTALIGN, GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam), 0, hwnd, NULL);
}
@@ -247,7 +244,7 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
SDL_free(tooltipw);
if (icon) {
tray->nid.hIcon = CreateIconFromSurface(icon);
tray->nid.hIcon = WIN_CreateIconFromSurface(icon);
if (!tray->nid.hIcon) {
tray->nid.hIcon = load_default_icon();
@@ -280,7 +277,7 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
}
if (icon) {
tray->nid.hIcon = CreateIconFromSurface(icon);
tray->nid.hIcon = WIN_CreateIconFromSurface(icon);
if (!tray->nid.hIcon) {
tray->nid.hIcon = load_default_icon();

View File

@@ -1,97 +0,0 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_surface_utils.h"
#include "../SDL_surface_c.h"
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
HICON CreateIconFromSurface(SDL_Surface *surface)
{
SDL_Surface *s = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
if (!s) {
return NULL;
}
/* The dimensions will be needed after s is freed */
const int width = s->w;
const int height = s->h;
BITMAPINFO bmpInfo;
SDL_zero(bmpInfo);
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = width;
bmpInfo.bmiHeader.biHeight = -height; /* Top-down bitmap */
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
HDC hdc = GetDC(NULL);
void *pBits = NULL;
HBITMAP hBitmap = CreateDIBSection(hdc, &bmpInfo, DIB_RGB_COLORS, &pBits, NULL, 0);
if (!hBitmap) {
ReleaseDC(NULL, hdc);
SDL_DestroySurface(s);
return NULL;
}
SDL_memcpy(pBits, s->pixels, width * height * 4);
SDL_DestroySurface(s);
HBITMAP hMask = CreateBitmap(width, height, 1, 1, NULL);
if (!hMask) {
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
return NULL;
}
HDC hdcMem = CreateCompatibleDC(hdc);
HGDIOBJ oldBitmap = SelectObject(hdcMem, hMask);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
BYTE* pixel = (BYTE*)pBits + (y * width + x) * 4;
BYTE alpha = pixel[3];
COLORREF maskColor = (alpha == 0) ? RGB(0, 0, 0) : RGB(255, 255, 255);
SetPixel(hdcMem, x, y, maskColor);
}
}
ICONINFO iconInfo;
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = hMask;
iconInfo.hbmColor = hBitmap;
HICON hIcon = CreateIconIndirect(&iconInfo);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
DeleteObject(hMask);
ReleaseDC(NULL, hdc);
return hIcon;
}
#endif

View File

@@ -1,38 +0,0 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_surface_utils_h_
#define SDL_surface_utils_h_
#include "../../core/windows/SDL_windows.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HICON CreateIconFromSurface(SDL_Surface *surface);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -43,44 +43,6 @@
#include <shobjidl.h>
#endif
// Dark mode support
typedef enum {
UXTHEME_APPMODE_DEFAULT,
UXTHEME_APPMODE_ALLOW_DARK,
UXTHEME_APPMODE_FORCE_DARK,
UXTHEME_APPMODE_FORCE_LIGHT,
UXTHEME_APPMODE_MAX
} UxthemePreferredAppMode;
typedef enum {
WCA_UNDEFINED = 0,
WCA_USEDARKMODECOLORS = 26,
WCA_LAST = 27
} WINDOWCOMPOSITIONATTRIB;
typedef struct {
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;
typedef struct {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
} NT_OSVERSIONINFOW;
typedef bool (WINAPI *ShouldAppsUseDarkMode_t)(void);
typedef void (WINAPI *AllowDarkModeForWindow_t)(HWND, bool);
typedef void (WINAPI *AllowDarkModeForApp_t)(bool);
typedef void (WINAPI *RefreshImmersiveColorPolicyState_t)(void);
typedef UxthemePreferredAppMode (WINAPI *SetPreferredAppMode_t)(UxthemePreferredAppMode);
typedef BOOL (WINAPI *SetWindowCompositionAttribute_t)(HWND, const WINDOWCOMPOSITIONATTRIBDATA *);
typedef void (NTAPI *RtlGetVersion_t)(NT_OSVERSIONINFOW *);
// Windows CE compatibility
#ifndef SWP_NOCOPYBITS
#define SWP_NOCOPYBITS 0
@@ -2298,74 +2260,6 @@ bool WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool foc
}
#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
void WIN_UpdateDarkModeForHWND(HWND hwnd)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
HMODULE ntdll = LoadLibrary(TEXT("ntdll.dll"));
if (!ntdll) {
return;
}
// There is no function to get Windows build number, so let's get it here via RtlGetVersion
RtlGetVersion_t RtlGetVersionFunc = (RtlGetVersion_t)GetProcAddress(ntdll, "RtlGetVersion");
NT_OSVERSIONINFOW os_info;
os_info.dwOSVersionInfoSize = sizeof(NT_OSVERSIONINFOW);
os_info.dwBuildNumber = 0;
if (RtlGetVersionFunc) {
RtlGetVersionFunc(&os_info);
}
FreeLibrary(ntdll);
os_info.dwBuildNumber &= ~0xF0000000;
if (os_info.dwBuildNumber < 17763) {
// Too old to support dark mode
return;
}
HMODULE uxtheme = LoadLibrary(TEXT("uxtheme.dll"));
if (!uxtheme) {
return;
}
RefreshImmersiveColorPolicyState_t RefreshImmersiveColorPolicyStateFunc = (RefreshImmersiveColorPolicyState_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(104));
ShouldAppsUseDarkMode_t ShouldAppsUseDarkModeFunc = (ShouldAppsUseDarkMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(132));
AllowDarkModeForWindow_t AllowDarkModeForWindowFunc = (AllowDarkModeForWindow_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(133));
if (os_info.dwBuildNumber < 18362) {
AllowDarkModeForApp_t AllowDarkModeForAppFunc = (AllowDarkModeForApp_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (AllowDarkModeForAppFunc) {
AllowDarkModeForAppFunc(true);
}
} else {
SetPreferredAppMode_t SetPreferredAppModeFunc = (SetPreferredAppMode_t)GetProcAddress(uxtheme, MAKEINTRESOURCEA(135));
if (SetPreferredAppModeFunc) {
SetPreferredAppModeFunc(UXTHEME_APPMODE_ALLOW_DARK);
}
}
if (RefreshImmersiveColorPolicyStateFunc) {
RefreshImmersiveColorPolicyStateFunc();
}
if (AllowDarkModeForWindowFunc) {
AllowDarkModeForWindowFunc(hwnd, true);
}
BOOL value;
// Check dark mode using ShouldAppsUseDarkMode, but use SDL_GetSystemTheme as a fallback
if (ShouldAppsUseDarkModeFunc) {
value = ShouldAppsUseDarkModeFunc() ? TRUE : FALSE;
} else {
value = (SDL_GetSystemTheme() == SDL_SYSTEM_THEME_DARK) ? TRUE : FALSE;
}
FreeLibrary(uxtheme);
if (os_info.dwBuildNumber < 18362) {
SetProp(hwnd, TEXT("UseImmersiveDarkModeColors"), SDL_reinterpret_cast(HANDLE, SDL_static_cast(INT_PTR, value)));
} else {
HMODULE user32 = GetModuleHandle(TEXT("user32.dll"));
if (user32) {
SetWindowCompositionAttribute_t SetWindowCompositionAttributeFunc = (SetWindowCompositionAttribute_t)GetProcAddress(user32, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttributeFunc) {
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &value, sizeof(value) };
SetWindowCompositionAttributeFunc(hwnd, &data);
}
}
}
#endif
}
bool WIN_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent)
{
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)

View File

@@ -136,7 +136,6 @@ extern bool WIN_SetWindowHitTest(SDL_Window *window, bool enabled);
extern void WIN_AcceptDragAndDrop(SDL_Window *window, bool accept);
extern bool WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
extern bool WIN_ApplyWindowProgress(SDL_VideoDevice *_this, SDL_Window *window);
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
extern bool WIN_SetWindowPositionInternal(SDL_Window *window, UINT flags, SDL_WindowRect rect_type);
extern void WIN_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
extern bool WIN_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);