Added SDL_GetSystemTheme() to return whether the system is using a dark or light color theme, and SDL_EVENT_SYSTEM_THEME_CHANGED is sent when this changes

Fixes https://github.com/libsdl-org/SDL/issues/5334
Fixes https://github.com/libsdl-org/SDL/issues/6958
Closes https://github.com/libsdl-org/SDL/pull/6440
main
Sam Lantinga 2023-03-07 00:01:34 -08:00
parent fb0c3197e0
commit 8994878767
27 changed files with 243 additions and 21 deletions

View File

@ -12,6 +12,9 @@ General:
* The preprocessor symbol __IPHONEOS__ has been renamed __IOS__
* SDL_stdinc.h no longer includes stdio.h, stdlib.h, etc., it only provides the SDL C runtime functionality
* SDL_intrin.h now includes the intrinsics headers that were in SDL_cpuinfo.h
* Added SDL_GetSystemTheme() to return whether the system is using a dark or light color theme, and SDL_EVENT_SYSTEM_THEME_CHANGED is sent when this changes
* Added SDL_GetDisplays() to return a list of connected displays
* Added SDL_GetPrimaryDisplay() to get the instance ID of the primary display
* Added SDL_CreateSurface() and SDL_CreateSurfaceFrom() which replace SDL_CreateRGBSurface*(), and can also be used to create YUV surfaces
* Added SDL_GetJoysticks(), SDL_GetJoystickInstanceName(), SDL_GetJoystickInstancePath(), SDL_GetJoystickInstancePlayerIndex(), SDL_GetJoystickInstanceGUID(), SDL_GetJoystickInstanceVendor(), SDL_GetJoystickInstanceProduct(), SDL_GetJoystickInstanceProductVersion(), and SDL_GetJoystickInstanceType() to directly query the list of available joysticks
* Added SDL_GetGamepads(), SDL_GetGamepadInstanceName(), SDL_GetGamepadInstancePath(), SDL_GetGamepadInstancePlayerIndex(), SDL_GetGamepadInstanceGUID(), SDL_GetGamepadInstanceVendor(), SDL_GetGamepadInstanceProduct(), SDL_GetGamepadInstanceProductVersion(), and SDL_GetGamepadInstanceType() to directly query the list of available gamepads

View File

@ -412,6 +412,15 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
} catch(Exception ignored) {
}
switch (getContext().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_NO:
SDLActivity.onNativeDarkModeChanged(false);
break;
case Configuration.UI_MODE_NIGHT_YES:
SDLActivity.onNativeDarkModeChanged(true);
break;
}
setContentView(mLayout);
setWindowStyle(false);
@ -577,6 +586,15 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
mCurrentLocale = newConfig.locale;
SDLActivity.onNativeLocaleChanged();
}
switch (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) {
case Configuration.UI_MODE_NIGHT_NO:
SDLActivity.onNativeDarkModeChanged(false);
break;
case Configuration.UI_MODE_NIGHT_YES:
SDLActivity.onNativeDarkModeChanged(true);
break;
}
}
@Override
@ -931,6 +949,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
public static native void nativeAddTouch(int touchId, String name);
public static native void nativePermissionResult(int requestCode, boolean result);
public static native void onNativeLocaleChanged();
public static native void onNativeDarkModeChanged(boolean enabled);
/**
* This method is called by SDL using JNI.

View File

@ -87,6 +87,8 @@ typedef enum
SDL_EVENT_LOCALE_CHANGED, /**< The user's locale preferences have changed. */
SDL_EVENT_SYSTEM_THEME_CHANGED, /**< The system theme changed */
/* Display events */
/* 0x150 was SDL_DISPLAYEVENT, reserve the number for sdl2-compat */
SDL_EVENT_DISPLAY_ORIENTATION = 0x151, /**< Display orientation has changed to data1 */

View File

@ -43,6 +43,16 @@ extern "C" {
typedef Uint32 SDL_DisplayID;
typedef Uint32 SDL_WindowID;
/**
* \brief System theme
*/
typedef enum
{
SDL_SYSTEM_THEME_UNKNOWN, /**< Unknown system theme */
SDL_SYSTEM_THEME_LIGHT, /**< Light colored system theme */
SDL_SYSTEM_THEME_DARK, /**< Dark colored system theme */
} SDL_SystemTheme;
/**
* \brief The structure that defines a display mode
*
@ -65,6 +75,18 @@ typedef struct
void *driverdata; /**< driver-specific data, initialize to 0 */
} SDL_DisplayMode;
/**
* \brief Display orientation
*/
typedef enum
{
SDL_ORIENTATION_UNKNOWN, /**< The display orientation can't be determined */
SDL_ORIENTATION_LANDSCAPE, /**< The display is in landscape mode, with the right side up, relative to portrait mode */
SDL_ORIENTATION_LANDSCAPE_FLIPPED, /**< The display is in landscape mode, with the left side up, relative to portrait mode */
SDL_ORIENTATION_PORTRAIT, /**< The display is in portrait mode */
SDL_ORIENTATION_PORTRAIT_FLIPPED /**< The display is in portrait mode, upside down */
} SDL_DisplayOrientation;
/**
* \brief The type used to identify a window
*
@ -151,18 +173,6 @@ typedef enum
#define SDL_WINDOWPOS_ISCENTERED(X) \
(((X)&0xFFFF0000) == SDL_WINDOWPOS_CENTERED_MASK)
/**
* \brief Display orientation
*/
typedef enum
{
SDL_ORIENTATION_UNKNOWN, /**< The display orientation can't be determined */
SDL_ORIENTATION_LANDSCAPE, /**< The display is in landscape mode, with the right side up, relative to portrait mode */
SDL_ORIENTATION_LANDSCAPE_FLIPPED, /**< The display is in landscape mode, with the left side up, relative to portrait mode */
SDL_ORIENTATION_PORTRAIT, /**< The display is in portrait mode */
SDL_ORIENTATION_PORTRAIT_FLIPPED /**< The display is in portrait mode, upside down */
} SDL_DisplayOrientation;
/**
* \brief Window flash operation
*/
@ -297,6 +307,15 @@ extern DECLSPEC const char *SDLCALL SDL_GetVideoDriver(int index);
*/
extern DECLSPEC const char *SDLCALL SDL_GetCurrentVideoDriver(void);
/**
* Get the current system theme
*
* \returns the current system theme, light, dark, or unknown
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC SDL_SystemTheme SDLCALL SDL_GetSystemTheme(void);
/**
* Get a list of currently connected displays.
*

View File

@ -124,6 +124,9 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeLowMemory)(
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeLocaleChanged)(
JNIEnv *env, jclass cls);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDarkModeChanged)(
JNIEnv *env, jclass cls, jboolean enabled);
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
JNIEnv *env, jclass cls);
@ -183,6 +186,7 @@ static JNINativeMethod SDLActivity_tab[] = {
{ "onNativeClipboardChanged", "()V", SDL_JAVA_INTERFACE(onNativeClipboardChanged) },
{ "nativeLowMemory", "()V", SDL_JAVA_INTERFACE(nativeLowMemory) },
{ "onNativeLocaleChanged", "()V", SDL_JAVA_INTERFACE(onNativeLocaleChanged) },
{ "onNativeDarkModeChanged", "(Z)V", SDL_JAVA_INTERFACE(onNativeDarkModeChanged) },
{ "nativeSendQuit", "()V", SDL_JAVA_INTERFACE(nativeSendQuit) },
{ "nativeQuit", "()V", SDL_JAVA_INTERFACE(nativeQuit) },
{ "nativePause", "()V", SDL_JAVA_INTERFACE(nativePause) },
@ -1199,6 +1203,13 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeLocaleChanged)(
SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED);
}
/* Dark mode */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDarkModeChanged)(
JNIEnv *env, jclass cls, jboolean enabled)
{
Android_SetDarkMode(enabled);
}
/* Send Quit event to "SDLThread" thread */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSendQuit)(
JNIEnv *env, jclass cls)

View File

@ -838,6 +838,7 @@ SDL3_0.0.0 {
SDL_SetRenderScale;
SDL_GetRenderScale;
SDL_GetRenderWindowSize;
SDL_GetSystemTheme;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -865,3 +865,4 @@
#define SDL_SetRenderScale SDL_SetRenderScale_REAL
#define SDL_GetRenderScale SDL_GetRenderScale_REAL
#define SDL_GetRenderWindowSize SDL_GetRenderWindowSize_REAL
#define SDL_GetSystemTheme SDL_GetSystemTheme_REAL

View File

@ -910,3 +910,4 @@ SDL_DYNAPI_PROC(int,SDL_ConvertEventToRenderCoordinates,(SDL_Renderer *a, SDL_Ev
SDL_DYNAPI_PROC(int,SDL_SetRenderScale,(SDL_Renderer *a, float b, float c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetRenderScale,(SDL_Renderer *a, float *b, float *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetRenderWindowSize,(SDL_Renderer *a, int *b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_SystemTheme,SDL_GetSystemTheme,(void),(),return)

View File

@ -204,6 +204,8 @@ static void SDL_LogEvent(const SDL_Event *event)
break;
SDL_EVENT_CASE(SDL_EVENT_LOCALE_CHANGED)
break;
SDL_EVENT_CASE(SDL_EVENT_SYSTEM_THEME_CHANGED)
break;
SDL_EVENT_CASE(SDL_EVENT_KEYMAP_CHANGED)
break;
SDL_EVENT_CASE(SDL_EVENT_CLIPBOARD_UPDATE)
@ -1346,6 +1348,11 @@ int SDL_SendLocaleChangedEvent(void)
return SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED);
}
int SDL_SendSystemThemeChangedEvent(void)
{
return SDL_SendAppEvent(SDL_EVENT_SYSTEM_THEME_CHANGED);
}
int SDL_InitEvents(void)
{
#if !SDL_JOYSTICK_DISABLED

View File

@ -44,6 +44,7 @@ extern int SDL_SendAppEvent(SDL_EventType eventType);
extern int SDL_SendSysWMEvent(SDL_SysWMmsg *message);
extern int SDL_SendKeymapChangedEvent(void);
extern int SDL_SendLocaleChangedEvent(void);
extern int SDL_SendSystemThemeChangedEvent(void);
extern int SDL_SendQuit(void);

View File

@ -1438,6 +1438,21 @@ SDLTest_CommonInit(SDLTest_CommonState *state)
return SDL_TRUE;
}
static const char *SystemThemeName(void)
{
switch (SDL_GetSystemTheme()) {
#define CASE(X) \
case SDL_SYSTEM_THEME_##X: \
return #X
CASE(UNKNOWN);
CASE(LIGHT);
CASE(DARK);
#undef CASE
default:
return "???";
}
}
static const char *DisplayOrientationName(int orientation)
{
switch (orientation) {
@ -1505,6 +1520,9 @@ static const char *GamepadButtonName(const SDL_GamepadButton button)
static void SDLTest_PrintEvent(SDL_Event *event)
{
switch (event->type) {
case SDL_EVENT_SYSTEM_THEME_CHANGED:
SDL_Log("SDL EVENT: System theme changed to %s\n", SystemThemeName());
break;
case SDL_EVENT_DISPLAY_CONNECTED:
SDL_Log("SDL EVENT: Display %" SDL_PRIu32 " connected",
event->display.displayID);

View File

@ -354,6 +354,7 @@ struct SDL_VideoDevice
char *primary_selection_text;
SDL_bool setting_display_mode;
Uint32 quirk_flags;
SDL_SystemTheme system_theme;
/* * * */
/* Data used by the GL drivers */
@ -476,6 +477,7 @@ extern VideoBootStrap NGAGE_bootstrap;
extern SDL_bool SDL_OnVideoThread(void);
extern SDL_VideoDevice *SDL_GetVideoDevice(void);
extern SDL_bool SDL_IsVideoContextExternal(void);
extern void SDL_SetSystemTheme(SDL_SystemTheme theme);
extern SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode);
extern SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event);
extern void SDL_DelVideoDisplay(SDL_DisplayID display, SDL_bool send_event);

View File

@ -576,14 +576,31 @@ SDL_VideoDevice *SDL_GetVideoDevice(void)
return _this;
}
SDL_bool SDL_OnVideoThread(void)
{
return (_this && SDL_ThreadID() == _this->thread) ? SDL_TRUE : SDL_FALSE;
}
SDL_bool SDL_IsVideoContextExternal(void)
{
return SDL_GetHintBoolean(SDL_HINT_VIDEO_EXTERNAL_CONTEXT, SDL_FALSE);
}
SDL_bool SDL_OnVideoThread(void)
void SDL_SetSystemTheme(SDL_SystemTheme theme)
{
return (_this && SDL_ThreadID() == _this->thread) ? SDL_TRUE : SDL_FALSE;
if (_this && theme != _this->system_theme) {
_this->system_theme = theme;
SDL_SendSystemThemeChangedEvent();
}
}
SDL_SystemTheme SDL_GetSystemTheme(void)
{
if (_this) {
return _this->system_theme;
} else {
return SDL_SYSTEM_THEME_UNKNOWN;
}
}
static void SDL_FinalizeDisplayMode(SDL_DisplayMode *mode)

View File

@ -65,6 +65,7 @@ static float Android_ScreenRate = 0.0f;
SDL_sem *Android_PauseSem = NULL;
SDL_sem *Android_ResumeSem = NULL;
SDL_mutex *Android_ActivityMutex = NULL;
static SDL_SystemTheme Android_SystemTheme;
static int Android_SuspendScreenSaver(_THIS)
{
@ -98,6 +99,7 @@ static SDL_VideoDevice *Android_CreateDevice(void)
}
device->driverdata = data;
device->system_theme = Android_SystemTheme;
/* Set the function pointers */
device->VideoInit = Android_VideoInit;
@ -284,4 +286,19 @@ void Android_SendResize(SDL_Window *window)
}
}
void Android_SetDarkMode(SDL_bool enabled)
{
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (enabled) {
Android_SystemTheme = SDL_SYSTEM_THEME_DARK;
} else {
Android_SystemTheme = SDL_SYSTEM_THEME_LIGHT;
}
if (device) {
SDL_SetSystemTheme(Android_SystemTheme);
}
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -29,6 +29,7 @@
extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate);
extern void Android_SetFormat(int format_wanted, int format_got);
extern void Android_SendResize(SDL_Window *window);
extern void Android_SetDarkMode(SDL_bool enabled);
/* Private display data */

View File

@ -129,6 +129,10 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
- (id)init;
- (void)localeDidChange:(NSNotification *)notification;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context;
@end
@implementation SDLAppDelegate : NSObject
@ -154,6 +158,11 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
selector:@selector(localeDidChange:)
name:NSCurrentLocaleDidChangeNotification
object:nil];
[NSApp addObserver:self
forKeyPath:@"effectiveAppearance"
options:NSKeyValueObservingOptionInitial
context:nil];
}
return self;
@ -166,6 +175,7 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
/* Remove our URL event handler only if we set it */
if ([NSApp delegate] == self) {
@ -262,11 +272,19 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
}
}
- (void)localeDidChange:(NSNotification *)notification;
- (void)localeDidChange:(NSNotification *)notification
{
SDL_SendLocaleChangedEvent();
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
context:(void *)context
{
SDL_SetSystemTheme(Cocoa_GetSystemTheme());
}
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);

View File

@ -108,6 +108,7 @@ DECLARE_ALERT_STYLE(Critical);
@end
/* Utility functions */
extern SDL_SystemTheme Cocoa_GetSystemTheme(void);
extern NSImage *Cocoa_CreateImage(SDL_Surface *surface);
/* Fix build with the 10.11 SDK */

View File

@ -75,6 +75,7 @@ static SDL_VideoDevice *Cocoa_CreateDevice(void)
}
device->driverdata = (SDL_VideoData *)CFBridgingRetain(data);
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = Cocoa_GetSystemTheme();
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
@ -220,6 +221,18 @@ void Cocoa_VideoQuit(_THIS)
}
}
/* This function assumes that it's called from within an autorelease pool */
SDL_SystemTheme Cocoa_GetSystemTheme(void)
{
NSAppearance* appearance = [[NSApplication sharedApplication] effectiveAppearance];
if ([appearance.name containsString: @"Dark"]) {
return SDL_SYSTEM_THEME_DARK;
} else {
return SDL_SYSTEM_THEME_LIGHT;
}
}
/* This function assumes that it's called from within an autorelease pool */
NSImage *Cocoa_CreateImage(SDL_Surface *surface)
{

View File

@ -43,4 +43,6 @@ void UIKit_ForceUpdateHomeIndicator(void);
SDL_bool UIKit_IsSystemVersionAtLeast(double version);
SDL_SystemTheme UIKit_GetSystemTheme(void);
#endif /* SDL_uikitvideo_h_ */

View File

@ -74,6 +74,7 @@ static SDL_VideoDevice *UIKit_CreateDevice(void)
}
device->driverdata = (SDL_VideoData *)CFBridgingRetain(data);
device->system_theme = UIKit_GetSystemTheme();
/* Set the function pointers */
device->VideoInit = UIKit_VideoInit;
@ -175,14 +176,27 @@ int UIKit_SuspendScreenSaver(_THIS)
return 0;
}
SDL_bool
UIKit_IsSystemVersionAtLeast(double version)
SDL_bool UIKit_IsSystemVersionAtLeast(double version)
{
return [[UIDevice currentDevice].systemVersion doubleValue] >= version;
}
CGRect
UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
SDL_SystemTheme UIKit_GetSystemTheme(void)
{
if (@available(iOS 12.0, tvOS 10.0, *)) {
switch ([UIScreen mainScreen].traitCollection.userInterfaceStyle) {
case UIUserInterfaceStyleDark:
return SDL_SYSTEM_THEME_DARK;
case UIUserInterfaceStyleLight:
return SDL_SYSTEM_THEME_LIGHT;
default:
break;
}
}
return SDL_SYSTEM_THEME_UNKNOWN;
}
CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen)
{
SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->driverdata;
CGRect frame = screen.bounds;

View File

@ -45,6 +45,8 @@
- (instancetype)initWithSDLWindow:(SDL_Window *)_window;
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;
- (void)setAnimationCallback:(int)interval
callback:(void (*)(void *))callback
callbackParam:(void *)callbackParam;

View File

@ -136,6 +136,11 @@ static void SDLCALL SDL_HideHomeIndicatorHintChanged(void *userdata, const char
#endif
}
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
SDL_SetSystemTheme(UIKit_GetSystemTheme());
}
- (void)setAnimationCallback:(int)interval
callback:(void (*)(void *))callback
callbackParam:(void *)callbackParam

View File

@ -1723,6 +1723,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
break;
case WM_SETTINGCHANGE:
if (wParam == 0 && lParam != 0 && SDL_wcscmp((wchar_t *)lParam, L"ImmersiveColorSet") == 0) {
SDL_SetSystemTheme(WIN_GetSystemTheme());
WIN_UpdateDarkModeForHWND(hwnd);
}
if (wParam == SPI_SETMOUSE || wParam == SPI_SETMOUSESPEED) {
WIN_UpdateMouseSystemScale();
}

View File

@ -116,6 +116,7 @@ static SDL_VideoDevice *WIN_CreateDevice(void)
}
device->driverdata = data;
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = WIN_GetSystemTheme();
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
data->userDLL = SDL_LoadObject("USER32.DLL");
@ -675,8 +676,26 @@ SDL_bool SDL_DXGIGetOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *
#endif
}
SDL_bool
WIN_IsPerMonitorV2DPIAware(_THIS)
SDL_SystemTheme WIN_GetSystemTheme(void)
{
DWORD type;
DWORD value;
DWORD count = sizeof(value);
LSTATUS status;
/* Technically this isn't the system theme, but it's the preference for applications */
status = RegGetValue(HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
TEXT("AppsUseLightTheme"),
RRF_RT_REG_DWORD, &type, &value, &count);
if (status == ERROR_SUCCESS && type == REG_DWORD && value == 0) {
return SDL_SYSTEM_THEME_DARK;
} else {
return SDL_SYSTEM_THEME_LIGHT;
}
}
SDL_bool WIN_IsPerMonitorV2DPIAware(_THIS)
{
#if !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
SDL_VideoData *data = _this->driverdata;

View File

@ -466,6 +466,7 @@ extern SDL_bool g_WindowFrameUsableWhileCursorHidden;
typedef struct IDirect3D9 IDirect3D9;
extern SDL_bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface);
extern SDL_SystemTheme WIN_GetSystemTheme(void);
extern SDL_bool WIN_IsPerMonitorV2DPIAware(_THIS);
#endif /* SDL_windowsvideo_h_ */

View File

@ -40,6 +40,12 @@
#include <SDL3/SDL_syswm.h>
/* 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);
/* Windows CE compatibility */
#ifndef SWP_NOCOPYBITS
#define SWP_NOCOPYBITS 0
@ -511,6 +517,8 @@ int WIN_CreateWindow(_THIS, SDL_Window *window)
return WIN_SetError("Couldn't create window");
}
WIN_UpdateDarkModeForHWND(hwnd);
WIN_PumpEvents(_this);
if (SetupWindowData(_this, window, hwnd, parent, SDL_TRUE) < 0) {
@ -1459,4 +1467,18 @@ int WIN_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation)
}
#endif /*!defined(__XBOXONE__) && !defined(__XBOXSERIES__)*/
void WIN_UpdateDarkModeForHWND(HWND hwnd)
{
void *handle = SDL_LoadObject("dwmapi.dll");
if (handle) {
DwmSetWindowAttribute_t DwmSetWindowAttributeFunc = (DwmSetWindowAttribute_t)SDL_LoadFunction(handle, "DwmSetWindowAttribute");
if (DwmSetWindowAttributeFunc) {
/* FIXME: Do we need to traverse children? */
BOOL value = (SDL_GetSystemTheme() == SDL_SYSTEM_THEME_DARK) ? TRUE : FALSE;
DwmSetWindowAttributeFunc(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
SDL_UnloadObject(handle);
}
}
#endif /* SDL_VIDEO_DRIVER_WINDOWS */

View File

@ -110,6 +110,7 @@ extern void WIN_ClientPointFromSDL(const SDL_Window *window, int *x, int *y);
extern void WIN_ClientPointFromSDLFloat(const SDL_Window *window, float x, float y, LONG *xOut, LONG *yOut);
extern void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int WIN_FlashWindow(_THIS, SDL_Window *window, SDL_FlashOperation operation);
extern void WIN_UpdateDarkModeForHWND(HWND hwnd);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus