Merge pull request #2 from floppyhammer/add-win32-theming

Add win32 theming base
This commit is contained in:
Andreas 2023-02-22 22:57:17 +01:00 committed by GitHub
commit 85a6eb0625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 125 additions and 8 deletions

View File

@ -151,6 +151,8 @@ static GLFWbool loadLibraries(void)
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
_glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor) _glfw.win32.dwmapi.GetColorizationColor = (PFN_DwmGetColorizationColor)
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor"); _glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmGetColorizationColor");
_glfw.win32.dwmapi.SetWindowAttribute = (PFN_DwmSetWindowAttribute)
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmSetWindowAttribute");
} }
_glfw.win32.shcore.instance = _glfwPlatformLoadModule("shcore.dll"); _glfw.win32.shcore.instance = _glfwPlatformLoadModule("shcore.dll");
@ -169,6 +171,18 @@ static GLFWbool loadLibraries(void)
_glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); _glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
} }
_glfw.win32.uxtheme.instance = _glfwPlatformLoadModule("uxtheme.dll");
if (_glfw.win32.uxtheme.instance)
{
_glfw.win32.uxtheme.ShouldAppsUseDarkMode = (ShouldAppsUseDarkModePtr)_glfwPlatformGetModuleSymbol(_glfw.win32.uxtheme.instance, MAKEINTRESOURCEA(132));
_glfw.win32.uxtheme.GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)_glfwPlatformGetModuleSymbol(_glfw.win32.uxtheme.instance, MAKEINTRESOURCEA(95));
_glfw.win32.uxtheme.GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)_glfwPlatformGetModuleSymbol(_glfw.win32.uxtheme.instance, MAKEINTRESOURCEA(96));
_glfw.win32.uxtheme.GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)_glfwPlatformGetModuleSymbol(_glfw.win32.uxtheme.instance, MAKEINTRESOURCEA(98));
_glfw.win32.uxtheme.uxThemeAvailable = _glfw.win32.uxtheme.ShouldAppsUseDarkMode && _glfw.win32.uxtheme.GetImmersiveColorFromColorSetEx && _glfw.win32.uxtheme.GetImmersiveColorTypeFromName && _glfw.win32.uxtheme.GetImmersiveUserColorSetPreference;
_glfw.win32.uxtheme.darkTitleAvailable = _glfwIsWindows10BuildOrGreaterWin32(22000);
}
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -193,6 +207,9 @@ static void freeLibraries(void)
if (_glfw.win32.ntdll.instance) if (_glfw.win32.ntdll.instance)
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance); _glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
if (_glfw.win32.uxtheme.instance)
_glfwPlatformFreeModule(_glfw.win32.uxtheme.instance);
} }
// Create key code translation tables // Create key code translation tables
@ -739,9 +756,18 @@ void _glfwTerminateWin32(void)
_GLFWtheme* _glfwGetSystemDefaultThemeWin32(void) _GLFWtheme* _glfwGetSystemDefaultThemeWin32(void)
{ {
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); _GLFWtheme* theme = &_glfw.theme;
return NULL; // TODO: implement
theme->variation = GLFW_THEME_LIGHT;
theme->flags = 0;
if (_glfw.win32.uxtheme.uxThemeAvailable && _glfw.win32.uxtheme.darkTitleAvailable) {
if (_glfw.win32.uxtheme.ShouldAppsUseDarkMode() & 0x1) {
theme->variation = GLFW_THEME_DARK;
}
}
return theme;
} }
#endif // _GLFW_WIN32 #endif // _GLFW_WIN32

View File

@ -301,10 +301,13 @@ typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID); typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID);
typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*); typedef HRESULT (WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*);
typedef HRESULT (WINAPI * PFN_DwmGetColorizationColor)(DWORD*,BOOL*); typedef HRESULT (WINAPI * PFN_DwmGetColorizationColor)(DWORD*,BOOL*);
typedef HRESULT (WINAPI * PFN_DwmSetWindowAttribute)(HWND,DWORD,LPCVOID,DWORD);
#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
#define DwmFlush _glfw.win32.dwmapi.Flush #define DwmFlush _glfw.win32.dwmapi.Flush
#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow #define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow
#define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor #define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor
#define DwmSetWindowAttribute _glfw.win32.dwmapi.SetWindowAttribute
// shcore.dll function pointer typedefs // shcore.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
@ -366,6 +369,11 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(
#define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl; #define GLFW_WGL_CONTEXT_STATE _GLFWcontextWGL wgl;
#define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl; #define GLFW_WGL_LIBRARY_CONTEXT_STATE _GLFWlibraryWGL wgl;
typedef BOOL (WINAPI * ShouldAppsUseDarkModePtr)();
typedef DWORD (WINAPI * GetImmersiveColorFromColorSetExPtr)(UINT,UINT,BOOL,UINT);
typedef int (WINAPI * GetImmersiveColorTypeFromNamePtr)(const WCHAR*);
typedef int (WINAPI * GetImmersiveUserColorSetPreferencePtr)(BOOL,BOOL);
// WGL-specific per-context data // WGL-specific per-context data
// //
@ -487,6 +495,7 @@ typedef struct _GLFWlibraryWin32
PFN_DwmFlush Flush; PFN_DwmFlush Flush;
PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow;
PFN_DwmGetColorizationColor GetColorizationColor; PFN_DwmGetColorizationColor GetColorizationColor;
PFN_DwmSetWindowAttribute SetWindowAttribute;
} dwmapi; } dwmapi;
struct { struct {
@ -499,6 +508,16 @@ typedef struct _GLFWlibraryWin32
HINSTANCE instance; HINSTANCE instance;
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
} ntdll; } ntdll;
struct {
HINSTANCE instance;
GLFWbool uxThemeAvailable;
GLFWbool darkTitleAvailable;
ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName;
GetImmersiveUserColorSetPreferencePtr GetImmersiveUserColorSetPreference;
} uxtheme;
} _GLFWlibraryWin32; } _GLFWlibraryWin32;
// Win32-specific per-monitor data // Win32-specific per-monitor data

View File

@ -37,6 +37,46 @@
#include <windowsx.h> #include <windowsx.h>
#include <shellapi.h> #include <shellapi.h>
// Ref: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
// Apply the system default theme
//
static void applySystemTheme(HWND handle)
{
if (_glfw.win32.uxtheme.uxThemeAvailable && _glfw.win32.uxtheme.darkTitleAvailable)
{
GLFWbool value = _glfw.win32.uxtheme.ShouldAppsUseDarkMode() & 0x1;
DwmSetWindowAttribute(handle,
DWMWA_USE_IMMERSIVE_DARK_MODE,
&value,
sizeof(value));
}
}
static void getAccentColor(float color[4])
{
if (!_glfw.win32.uxtheme.uxThemeAvailable)
{
return;
}
UINT dwImmersiveColorType = _glfw.win32.uxtheme.GetImmersiveColorTypeFromName(L"ImmersiveSystemAccent");
UINT dwImmersiveColorSet = _glfw.win32.uxtheme.GetImmersiveUserColorSetPreference(FALSE, FALSE);
UINT rgba = _glfw.win32.uxtheme.GetImmersiveColorFromColorSetEx(dwImmersiveColorSet,
dwImmersiveColorType,
FALSE,
0);
color[0] = (0xFF & rgba);
color[1] = ((0xFF00 & rgba) >> 8) ;
color[2] = ((0xFF0000 & rgba) >> 16);
color[3] = ((0xFF000000 & rgba) >> 24);
}
// Returns the window style for the specified window // Returns the window style for the specified window
// //
static DWORD getWindowStyle(const _GLFWwindow* window) static DWORD getWindowStyle(const _GLFWwindow* window)
@ -1146,6 +1186,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
return 0; return 0;
} }
case WM_THEMECHANGED:
case WM_SETTINGCHANGE: {
if (window->theme.variation == GLFW_THEME_DEFAULT) {
applySystemTheme(window->win32.handle);
}
} break;
case WM_GETDPISCALEDSIZE: case WM_GETDPISCALEDSIZE:
{ {
if (window->win32.scaleToMonitor) if (window->win32.scaleToMonitor)
@ -1436,6 +1483,9 @@ static int createNativeWindow(_GLFWwindow* window,
_glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height); _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height);
// Use the system default when creating a window
applySystemTheme(window->win32.handle);
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -2375,13 +2425,36 @@ const char* _glfwGetClipboardStringWin32(void)
void _glfwSetThemeWin32(_GLFWwindow* window, _GLFWtheme* theme) void _glfwSetThemeWin32(_GLFWwindow* window, _GLFWtheme* theme)
{ {
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); if (!theme || theme->variation == GLFW_THEME_DEFAULT)
{
applySystemTheme(window->win32.handle);
return;
}
GLFWbool darkMode = theme->variation == GLFW_THEME_DARK;
DwmSetWindowAttribute(window->win32.handle,
DWMWA_USE_IMMERSIVE_DARK_MODE,
&darkMode,
sizeof(darkMode));
} }
_GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window) _GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window)
{ {
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); _GLFWtheme* theme = &window->theme;
return NULL; // TODO: implement
theme->variation = GLFW_THEME_LIGHT;
theme->flags = 0;
if (_glfw.win32.uxtheme.uxThemeAvailable && _glfw.win32.uxtheme.darkTitleAvailable)
{
theme->variation = GLFW_THEME_DARK;
}
memset(theme->color, 0, sizeof(float) * 4);
getAccentColor(theme->color);
return theme;
} }
EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs) EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs)
@ -2512,4 +2585,3 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
} }
#endif // _GLFW_WIN32 #endif // _GLFW_WIN32