mirror of
https://github.com/glfw/glfw.git
synced 2024-11-14 10:34:34 +00:00
Merge branch 'dev-theming' into theming
This commit is contained in:
commit
14eea06345
@ -33,6 +33,7 @@ video tutorials.
|
||||
- David Carlier
|
||||
- Arturo Castro
|
||||
- Chi-kwan Chan
|
||||
- Haoyun Chen
|
||||
- TheChocolateOre
|
||||
- Ali Chraghi
|
||||
- Joseph Chua
|
||||
|
@ -5879,9 +5879,12 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string);
|
||||
*/
|
||||
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
|
||||
|
||||
// TODO: consider requiring GLFW to be initialized for these GLFWTheme functions to work. That way, implementations can add extra data to the themes, and process them in a platform-specific way.
|
||||
|
||||
GLFWAPI GLFWtheme* glfwCreateTheme(void);
|
||||
GLFWAPI void glfwDestroyTheme(GLFWtheme* theme);
|
||||
GLFWAPI void glfwCopyTheme(const GLFWtheme* source, GLFWtheme* target);
|
||||
GLFWAPI int glfwThemeEqual(const GLFWtheme* first, const GLFWtheme* second);
|
||||
|
||||
GLFWAPI int glfwThemeGetVariation(const GLFWtheme* theme);
|
||||
GLFWAPI void glfwThemeSetVariation(GLFWtheme* theme, int value);
|
||||
@ -5889,10 +5892,12 @@ GLFWAPI void glfwThemeSetVariation(GLFWtheme* theme, int value);
|
||||
GLFWAPI int glfwThemeGetAttribute(const GLFWtheme* theme, int attribute);
|
||||
GLFWAPI void glfwThemeSetAttribute(GLFWtheme* theme, int attribute, int value);
|
||||
|
||||
// If the return value of glfwGetAttribute(specifier) is GLFW_FALSE, the return values of this function are undefined.
|
||||
GLFWAPI void glfwThemeGetColor(const GLFWtheme* theme,
|
||||
int specifier,
|
||||
float* red, float* green, float* blue, float* alpha);
|
||||
|
||||
// Must execute glfwThemeSetAttribute(specifier, GLFW_TRUE) for this to have an effect.
|
||||
GLFWAPI void glfwThemeSetColor(GLFWtheme* theme,
|
||||
int specifier,
|
||||
float red, float green, float blue, float alpha);
|
||||
@ -5934,11 +5939,19 @@ GLFWAPI void glfwThemeSetColor(GLFWtheme* theme,
|
||||
|
||||
/*! @brief Theme attribute.
|
||||
*
|
||||
* Specifies that a theme is vibrant.
|
||||
* Specifies that a theme requests reduced transparency.
|
||||
*
|
||||
* @ingroup theme
|
||||
*/
|
||||
#define GLFW_THEME_ATTRIBUTE_VIBRANT 2
|
||||
#define GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY 2
|
||||
|
||||
/*! @brief Theme attribute.
|
||||
*
|
||||
* Specifies that a theme requests reduced motion.
|
||||
*
|
||||
* @ingroup theme
|
||||
*/
|
||||
#define GLFW_THEME_ATTRIBUTE_REDUCE_MOTION 4
|
||||
|
||||
/*! @brief Theme color attribute.
|
||||
*
|
||||
@ -5949,7 +5962,7 @@ GLFWAPI void glfwThemeSetColor(GLFWtheme* theme,
|
||||
*
|
||||
* @ingroup theme
|
||||
*/
|
||||
#define GLFW_THEME_COLOR_MAIN 4
|
||||
#define GLFW_THEME_COLOR_MAIN 8
|
||||
|
||||
/*! @brief Sets the system theme callback.
|
||||
*
|
||||
@ -6005,8 +6018,24 @@ GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback);
|
||||
GLFWAPI void glfwSetTheme(GLFWwindow* handle, const GLFWtheme* theme);
|
||||
|
||||
/*! @brief Returns the currently active system theme.
|
||||
*
|
||||
* Executing this yields no changes to a window's theme settings:
|
||||
* @code
|
||||
* glfwSetTheme(window, glfwGetTheme(window, GLFW_FALSE))
|
||||
* @endcode
|
||||
*
|
||||
* Executing this sets a window's theme to the current system theme, and disables
|
||||
* automatic changes to the window's theme for when the system changes its theme.
|
||||
* @code
|
||||
* glfwSetTheme(window, glfwGetTheme(window, GLFW_TRUE))
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* @param[in] window The [window](@ref window) to retrieve the current theme for.
|
||||
* @param[in] inlineDefaults Specifies whether or not GLFW should replace unspecified
|
||||
* theme attributes with the currently active system ones. If `GLFW_TRUE`, the returned
|
||||
* theme describes the active style of the window. If `GLFW_FALSE`, the returned theme
|
||||
* describes the window's theme settings.
|
||||
*
|
||||
* @return A mutable [theme](@ref theme) object, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
@ -6027,7 +6056,7 @@ GLFWAPI void glfwSetTheme(GLFWwindow* handle, const GLFWtheme* theme);
|
||||
*
|
||||
* @ingroup theme
|
||||
*/
|
||||
GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle);
|
||||
GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle, int inlineDefaults);
|
||||
|
||||
/*! @brief Returns the currently active system theme.
|
||||
*
|
||||
@ -6051,7 +6080,7 @@ GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle);
|
||||
*
|
||||
* @ingroup theme
|
||||
*/
|
||||
GLFWAPI GLFWtheme* glfwGetSystemDefaultTheme();
|
||||
GLFWAPI const GLFWtheme* glfwGetSystemDefaultTheme();
|
||||
|
||||
/*! @brief Returns the GLFW time.
|
||||
*
|
||||
|
@ -175,7 +175,7 @@ static void createMenuBar(void)
|
||||
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
|
||||
}
|
||||
|
||||
void nsAppearanceToGLFWTheme(NSAppearance* appearance, _GLFWtheme* theme)
|
||||
void _glfwNSAppearanceToTheme(NSAppearance* appearance, _GLFWtheme* theme)
|
||||
{
|
||||
NSAppearanceName name;
|
||||
|
||||
@ -188,10 +188,9 @@ void nsAppearanceToGLFWTheme(NSAppearance* appearance, _GLFWtheme* theme)
|
||||
NSAppearanceNameVibrantDark,
|
||||
NSAppearanceNameAccessibilityHighContrastAqua,
|
||||
NSAppearanceNameAccessibilityHighContrastDarkAqua,
|
||||
NSAppearanceNameAccessibilityHighContrastVibrantLight,
|
||||
NSAppearanceNameAccessibilityHighContrastVibrantDark
|
||||
]];
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
name = appearance.name;
|
||||
}
|
||||
|
||||
@ -205,13 +204,11 @@ void nsAppearanceToGLFWTheme(NSAppearance* appearance, _GLFWtheme* theme)
|
||||
if ([name isEqualToString:NSAppearanceNameVibrantLight])
|
||||
{
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_VIBRANT;
|
||||
return;
|
||||
}
|
||||
if ([name isEqualToString:NSAppearanceNameVibrantDark])
|
||||
{
|
||||
theme->variation = GLFW_THEME_DARK;
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_VIBRANT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -235,24 +232,12 @@ void nsAppearanceToGLFWTheme(NSAppearance* appearance, _GLFWtheme* theme)
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST;
|
||||
return;
|
||||
}
|
||||
if ([name isEqualToString:NSAppearanceNameAccessibilityHighContrastVibrantLight])
|
||||
{
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_VIBRANT | GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST;
|
||||
return;
|
||||
}
|
||||
if ([name isEqualToString:NSAppearanceNameAccessibilityHighContrastVibrantDark])
|
||||
{
|
||||
theme->variation = GLFW_THEME_DARK;
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_VIBRANT | GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
}
|
||||
|
||||
static void getSystemTheme(_GLFWtheme* theme)
|
||||
void _glfwGetSystemThemeCocoa(_GLFWtheme* theme)
|
||||
{
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
theme->flags = 0;
|
||||
@ -262,7 +247,7 @@ static void getSystemTheme(_GLFWtheme* theme)
|
||||
// effectiveAppearance is actually not the system appearance, but the application appearance.
|
||||
// As long as NSApplication.appearance is never set, using the effective appearance is fine
|
||||
// to get and observe the system appearance.
|
||||
nsAppearanceToGLFWTheme(NSApp.effectiveAppearance, theme);
|
||||
_glfwNSAppearanceToTheme(NSApp.effectiveAppearance, theme);
|
||||
|
||||
NSColor* color = [[NSColor controlAccentColor] colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
|
||||
|
||||
@ -272,6 +257,35 @@ static void getSystemTheme(_GLFWtheme* theme)
|
||||
theme->color[2] = color.blueComponent;
|
||||
theme->color[3] = color.alphaComponent;
|
||||
}
|
||||
|
||||
// TODO: return the standard blue accent color if running in 10.13 or earlier.
|
||||
|
||||
// TODO: optimize by reading multiple values at once.
|
||||
|
||||
const CFStringRef applicationID = CFSTR("com.apple.universalaccess");
|
||||
|
||||
Boolean keyIsValid = false;
|
||||
Boolean highContrast = CFPreferencesGetAppBooleanValue(CFSTR("increaseContrast"),
|
||||
applicationID,
|
||||
&keyIsValid);
|
||||
|
||||
if (keyIsValid && highContrast)
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST;
|
||||
|
||||
keyIsValid = false;
|
||||
Boolean reduceTransparency = CFPreferencesGetAppBooleanValue(CFSTR("reduceTransparency"),
|
||||
applicationID,
|
||||
&keyIsValid);
|
||||
if (keyIsValid && reduceTransparency)
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY;
|
||||
|
||||
keyIsValid = false;
|
||||
Boolean reduceMotion = CFPreferencesGetAppBooleanValue(CFSTR("reduceMotion"),
|
||||
applicationID,
|
||||
&keyIsValid);
|
||||
|
||||
if (keyIsValid && reduceMotion)
|
||||
theme->flags |= GLFW_THEME_ATTRIBUTE_REDUCE_MOTION;
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
@ -511,11 +525,16 @@ static GLFWbool initializeTIS(void)
|
||||
{
|
||||
// This class is never subclassed, so it's safe to ignore the context parameter
|
||||
|
||||
// TODO: FIXME: this method is invoked twice when the high contrast setting is edited in the preferences.
|
||||
|
||||
_GLFWtheme theme;
|
||||
getSystemTheme(&theme);
|
||||
_glfwGetSystemThemeCocoa(&theme);
|
||||
|
||||
// The observer for the effective appearance is invoked more often than the appearance name itself changes.
|
||||
// For instance, it's invoked when various accesibility settings are changed in the system preferences.
|
||||
// Not all of these properties are included in the GLFW themes, so those updates must be filtered out.
|
||||
if (glfwThemeEqual((GLFWtheme*) &theme, (GLFWtheme*) &_glfw.theme))
|
||||
return;
|
||||
|
||||
memcpy(&_glfw.theme, &theme, sizeof(_GLFWtheme));
|
||||
_glfwInputSystemTheme(&theme);
|
||||
|
||||
/*if ([keyPath isEqualToString:@"controlAccentColor"]) {
|
||||
@ -786,6 +805,9 @@ int _glfwInitCocoa(void)
|
||||
context:nil];
|
||||
*/
|
||||
|
||||
_glfwInitDefaultTheme(&_glfw.theme);
|
||||
|
||||
// TODO: add observer for properties other than effectiveAppearance, for observing prior to 10.14. I assume the accesibility options were available then.
|
||||
if (@available(macOS 10.14, *))
|
||||
{
|
||||
[NSApp addObserver:_glfw.ns.helper
|
||||
@ -857,7 +879,7 @@ void _glfwTerminateCocoa(void)
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeCocoa(void)
|
||||
{
|
||||
_GLFWtheme* theme = &_glfw.theme;
|
||||
getSystemTheme(theme);
|
||||
_glfwGetSystemThemeCocoa(theme);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
@ -297,7 +297,8 @@ void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor);
|
||||
|
||||
float _glfwTransformYCocoa(float y);
|
||||
|
||||
void nsAppearanceToGLFWTheme(NSAppearance* appearance, _GLFWtheme* theme);
|
||||
void _glfwNSAppearanceToTheme(NSAppearance* appearance, _GLFWtheme* theme);
|
||||
void _glfwGetSystemThemeCocoa(_GLFWtheme* theme);
|
||||
|
||||
void* _glfwLoadLocalVulkanLoaderCocoa(void);
|
||||
|
||||
@ -308,7 +309,6 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
void _glfwDestroyContextNSGL(_GLFWwindow* window);
|
||||
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeCocoa(void);
|
||||
void _glfwSetThemeCocoa(_GLFWwindow* window, _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window);
|
||||
void _glfwSetThemeCocoa(_GLFWwindow* window, const _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window, int inlineDefaults);
|
||||
|
@ -1876,59 +1876,90 @@ const char* _glfwGetClipboardStringCocoa(void)
|
||||
} // autoreleasepool
|
||||
}
|
||||
|
||||
void _glfwSetThemeCocoa(_GLFWwindow* window, _GLFWtheme* theme)
|
||||
// TODO: move
|
||||
static void replaceTheme(_GLFWwindow* window, _GLFWtheme* currentTheme, const _GLFWtheme* newTheme)
|
||||
{
|
||||
if (!theme || theme->variation == GLFW_THEME_DEFAULT)
|
||||
const int dissimilarFlags = currentTheme->flags ^ newTheme->flags;
|
||||
|
||||
if (currentTheme->variation != newTheme->variation
|
||||
|| (dissimilarFlags & GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY))
|
||||
{
|
||||
[(NSWindow*)window->ns.object setAppearance:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
if (@available(macOS 10.10, *)) {} else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: support color
|
||||
// TODO: fix vibrancy
|
||||
|
||||
// As per the Cocoa documentation, passing the high contrast names to
|
||||
// appearanceNamed: will result in nil, so these can not be used.
|
||||
NSAppearanceName name;
|
||||
|
||||
if (theme->variation == GLFW_THEME_LIGHT)
|
||||
{
|
||||
if (theme->flags & GLFW_THEME_ATTRIBUTE_VIBRANT)
|
||||
if (newTheme->variation == GLFW_THEME_DEFAULT)
|
||||
{
|
||||
name = NSAppearanceNameVibrantLight;
|
||||
[(NSWindow*)window->ns.object setAppearance:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
name = NSAppearanceNameAqua;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (theme->flags & GLFW_THEME_ATTRIBUTE_VIBRANT)
|
||||
{
|
||||
name = NSAppearanceNameVibrantDark;
|
||||
}
|
||||
else if (@available(macOS 10.14, *))
|
||||
{
|
||||
name = NSAppearanceNameDarkAqua;
|
||||
} else
|
||||
{
|
||||
name = NSAppearanceNameAqua;
|
||||
}
|
||||
}
|
||||
if (@available(macOS 10.10, *))
|
||||
{
|
||||
// TODO: support color
|
||||
// TODO: fix vibrancy
|
||||
|
||||
NSAppearance* appearance = [NSAppearance appearanceNamed:name];
|
||||
[(NSWindow*)window->ns.object setAppearance:appearance];
|
||||
// As per the Cocoa documentation, passing the high contrast names to
|
||||
// appearanceNamed: will result in nil, so these can not be used.
|
||||
NSAppearanceName name;
|
||||
|
||||
if (newTheme->variation == GLFW_THEME_LIGHT)
|
||||
{
|
||||
if (newTheme->flags & GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY)
|
||||
name = NSAppearanceNameVibrantLight;
|
||||
else
|
||||
name = NSAppearanceNameAqua;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newTheme->flags & GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY)
|
||||
{
|
||||
name = NSAppearanceNameVibrantDark;
|
||||
}
|
||||
else if (@available(macOS 10.14, *))
|
||||
{
|
||||
name = NSAppearanceNameDarkAqua;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = NSAppearanceNameAqua;
|
||||
}
|
||||
}
|
||||
|
||||
NSAppearance* appearance = [NSAppearance appearanceNamed:name];
|
||||
[(NSWindow*)window->ns.object setAppearance:appearance];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window)
|
||||
void _glfwSetThemeCocoa(_GLFWwindow* window, const _GLFWtheme* theme)
|
||||
{
|
||||
_GLFWtheme* theme = &window->theme;
|
||||
_GLFWtheme* currentTheme = &window->theme.internal;
|
||||
_GLFWtheme newTheme;
|
||||
|
||||
if (!theme)
|
||||
_glfwInitDefaultTheme(&newTheme);
|
||||
else
|
||||
memcpy(&newTheme, theme, sizeof(_GLFWtheme));
|
||||
|
||||
replaceTheme(window, currentTheme, &newTheme);
|
||||
|
||||
memcpy(currentTheme, &newTheme, sizeof(_GLFWtheme));
|
||||
|
||||
// Not available for setting in Cocoa.
|
||||
currentTheme->flags &= ~(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_MOTION|
|
||||
GLFW_THEME_COLOR_MAIN);
|
||||
|
||||
// TODO: NSColor controlAccentColor is not settable. Is there any reason in overriding a similar value? Does it apply to menu item highlights? If yes, then it must be overridden.
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window, int inlineDefaults)
|
||||
{
|
||||
_GLFWtheme* theme = &window->theme.external;
|
||||
memcpy(theme, &window->theme.internal, sizeof(_GLFWtheme));
|
||||
|
||||
// FIXME: fix not overriding specified properties.
|
||||
if (!inlineDefaults)
|
||||
return theme;
|
||||
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
theme->flags = 0;
|
||||
@ -1940,21 +1971,21 @@ _GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window)
|
||||
if (appearance == NULL)
|
||||
appearance = [NSApp effectiveAppearance];
|
||||
|
||||
nsAppearanceToGLFWTheme(appearance, theme);
|
||||
_glfwNSAppearanceToTheme(appearance, theme);
|
||||
}
|
||||
|
||||
if (@available(macOS 10.14, *)) {
|
||||
// TODO: this is not settable. Is there any reason in overriding a similar value? Does it apply to menu item highlights? If yes, then it must be overridden.
|
||||
NSColor* color = [[NSColor controlAccentColor] colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
|
||||
// TODO: Cannot use the accent color directly, for window themes, because the accent color is never overridden.
|
||||
_GLFWtheme systemTheme;
|
||||
|
||||
theme->flags |= GLFW_THEME_COLOR_MAIN;
|
||||
theme->color[0] = color.redComponent;
|
||||
theme->color[1] = color.greenComponent;
|
||||
theme->color[2] = color.blueComponent;
|
||||
theme->color[3] = color.alphaComponent;
|
||||
_glfwGetSystemThemeCocoa(&systemTheme);
|
||||
|
||||
if ((theme->flags & GLFW_THEME_COLOR_MAIN) == 0)
|
||||
{
|
||||
assert(systemTheme.flags & GLFW_THEME_COLOR_MAIN);
|
||||
memcpy(&theme->color, &systemTheme.color, sizeof(float) * 4);
|
||||
}
|
||||
|
||||
theme->flags |= systemTheme.flags;
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
|
@ -543,7 +543,7 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun)
|
||||
return cbfun;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWtheme* glfwGetSystemDefaultTheme()
|
||||
GLFWAPI const GLFWtheme* glfwGetSystemDefaultTheme()
|
||||
{
|
||||
_GLFWtheme* theme;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
@ -551,7 +551,7 @@ GLFWAPI GLFWtheme* glfwGetSystemDefaultTheme()
|
||||
theme = _glfw.platform.getSystemDefaultTheme();
|
||||
assert(theme->variation != GLFW_THEME_DEFAULT);
|
||||
|
||||
return (GLFWtheme*) theme;
|
||||
return (const GLFWtheme*) theme;
|
||||
}
|
||||
|
||||
GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback)
|
||||
|
@ -586,8 +586,13 @@ struct _GLFWwindow
|
||||
GLFWdropfun drop;
|
||||
} callbacks;
|
||||
|
||||
// Clients can mutate this theme data at any time
|
||||
_GLFWtheme theme;
|
||||
struct {
|
||||
// Clients can mutate this theme data at any time
|
||||
_GLFWtheme external;
|
||||
|
||||
// The window's user-specified theme settings.
|
||||
_GLFWtheme internal; // TODO: init to defaults on window creation. TODO: set in glfwSetTheme
|
||||
} theme;
|
||||
|
||||
// This is defined in platform.h
|
||||
GLFW_PLATFORM_WINDOW_STATE
|
||||
@ -754,8 +759,8 @@ struct _GLFWplatform
|
||||
void (*setWindowFloating)(_GLFWwindow*,GLFWbool);
|
||||
void (*setWindowOpacity)(_GLFWwindow*,float);
|
||||
void (*setWindowMousePassthrough)(_GLFWwindow*,GLFWbool);
|
||||
_GLFWtheme* (*getTheme)(_GLFWwindow*);
|
||||
void (*setTheme)(_GLFWwindow*,_GLFWtheme*);
|
||||
_GLFWtheme* (*getTheme)(_GLFWwindow*,int);
|
||||
void (*setTheme)(_GLFWwindow*,const _GLFWtheme*);
|
||||
// Events
|
||||
void (*pollEvents)(void);
|
||||
void (*waitEvents)(void);
|
||||
@ -888,7 +893,6 @@ struct _GLFWlibrary
|
||||
GLFWthemefun theme;
|
||||
} callbacks;
|
||||
|
||||
// Clients can mutate this theme data at any time
|
||||
_GLFWtheme theme;
|
||||
|
||||
// These are defined in platform.h
|
||||
@ -1035,3 +1039,4 @@ void* _glfw_calloc(size_t count, size_t size);
|
||||
void* _glfw_realloc(void* pointer, size_t size);
|
||||
void _glfw_free(void* pointer);
|
||||
|
||||
void _glfwInitDefaultTheme(_GLFWtheme* theme);
|
||||
|
@ -142,5 +142,10 @@ void _glfwTerminateNull(void)
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeNull(void)
|
||||
{
|
||||
return NULL; // TODO: should probably return a colorless GLFWtheme with baseTheme set to GLFW_THEME_LIGHT
|
||||
_glfwInitDefaultTheme(&_glfw.theme);
|
||||
|
||||
// DEFAULT is not a valid return value.
|
||||
_glfw.theme.variation = GLFW_THEME_LIGHT;
|
||||
|
||||
return &_glfw.theme;
|
||||
}
|
||||
|
@ -148,5 +148,5 @@ VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, _GLFWwindow* window,
|
||||
void _glfwPollMonitorsNull(void);
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeNull(void);
|
||||
void _glfwSetThemeNull(_GLFWwindow* window, _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeNull(_GLFWwindow* window);
|
||||
void _glfwSetThemeNull(_GLFWwindow* window, const _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeNull(_GLFWwindow* window, int inlineDefaults);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
|
||||
{
|
||||
@ -551,13 +552,16 @@ const char* _glfwGetClipboardStringNull(void)
|
||||
return _glfw.null.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwSetThemeNull(_GLFWwindow* window, _GLFWtheme* theme)
|
||||
void _glfwSetThemeNull(_GLFWwindow* window, const _GLFWtheme* theme)
|
||||
{
|
||||
memcpy(&window->theme.internal, theme, sizeof(_GLFWtheme));
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeNull(_GLFWwindow* window)
|
||||
_GLFWtheme* _glfwGetThemeNull(_GLFWwindow* window, int inlineDefaults)
|
||||
{
|
||||
return NULL; // TODO: see to-do in _glfwGetSystemDefaultThemeNull
|
||||
memcpy(&window->theme.external, &window->theme.internal, sizeof(_GLFWtheme));
|
||||
|
||||
return &window->theme.external;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformNull(EGLint** attribs)
|
||||
|
56
src/theme.c
56
src/theme.c
@ -31,12 +31,25 @@
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static GLFWbool attributesAreValid(int attributes)
|
||||
{
|
||||
return (attributes & ~(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_MOTION |
|
||||
GLFW_THEME_COLOR_MAIN)) == 0;
|
||||
}
|
||||
|
||||
void _glfwInitDefaultTheme(_GLFWtheme* theme)
|
||||
{
|
||||
theme->variation = GLFW_THEME_DEFAULT;
|
||||
theme->flags = 0;
|
||||
}
|
||||
|
||||
|
||||
GLFWAPI GLFWtheme* glfwCreateTheme(void)
|
||||
{
|
||||
_GLFWtheme* theme = _glfw_calloc(1, sizeof(_GLFWtheme));
|
||||
|
||||
theme->variation = GLFW_THEME_DEFAULT;
|
||||
theme->flags = 0;
|
||||
_glfwInitDefaultTheme(theme);
|
||||
|
||||
return (GLFWtheme*) theme;
|
||||
}
|
||||
@ -51,6 +64,23 @@ GLFWAPI void glfwCopyTheme(const GLFWtheme* source, GLFWtheme* target)
|
||||
memcpy(target, source, sizeof(_GLFWtheme));
|
||||
}
|
||||
|
||||
GLFWAPI int glfwThemeEqual(const GLFWtheme* first, const GLFWtheme* second)
|
||||
{
|
||||
_GLFWtheme* _first = (_GLFWtheme*) first;
|
||||
_GLFWtheme* _second = (_GLFWtheme*) second;
|
||||
|
||||
if (_first->variation != _second->variation)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (_first->flags != _second->flags)
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (_first->flags & GLFW_THEME_COLOR_MAIN)
|
||||
return memcmp(&_first->color, &_second->color, sizeof(float) * 4);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
GLFWAPI int glfwThemeGetVariation(const GLFWtheme* theme)
|
||||
{
|
||||
assert(theme != NULL);
|
||||
@ -68,22 +98,18 @@ GLFWAPI void glfwThemeSetVariation(GLFWtheme* theme, int value)
|
||||
GLFWAPI int glfwThemeGetAttribute(const GLFWtheme* theme, int attribute)
|
||||
{
|
||||
assert(theme != NULL);
|
||||
assert((attribute & ~(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST |
|
||||
GLFW_THEME_ATTRIBUTE_VIBRANT |
|
||||
GLFW_THEME_COLOR_MAIN)) == 0);
|
||||
assert(attributesAreValid(attribute));
|
||||
|
||||
return ((_GLFWtheme*) theme)->flags & attribute ? GLFW_TRUE : GLFW_FALSE;
|
||||
}
|
||||
|
||||
GLFWAPI void glfwThemeSetAttribute(GLFWtheme* theme, int attribute, int value)
|
||||
{
|
||||
_GLFWtheme* _theme = (_GLFWtheme*) theme;
|
||||
|
||||
assert(theme != NULL);
|
||||
assert(value == GLFW_TRUE || value == GLFW_FALSE);
|
||||
assert((attribute & ~(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST |
|
||||
GLFW_THEME_ATTRIBUTE_VIBRANT |
|
||||
GLFW_THEME_COLOR_MAIN)) == 0);
|
||||
|
||||
_GLFWtheme* _theme = (_GLFWtheme*) theme;
|
||||
assert(attributesAreValid(attribute));
|
||||
|
||||
if (value == GLFW_TRUE)
|
||||
_theme->flags |= attribute;
|
||||
@ -93,12 +119,12 @@ GLFWAPI void glfwThemeSetAttribute(GLFWtheme* theme, int attribute, int value)
|
||||
|
||||
GLFWAPI void glfwThemeGetColor(const GLFWtheme* theme, int specifier, float* red, float* green, float* blue, float* alpha)
|
||||
{
|
||||
const float* color = ((_GLFWtheme*) theme)->color;
|
||||
|
||||
assert(theme != NULL);
|
||||
assert(specifier == GLFW_THEME_COLOR_MAIN);
|
||||
assert(red != NULL && green != NULL && blue != NULL && alpha != NULL);
|
||||
|
||||
const float* color = ((_GLFWtheme*) theme)->color;
|
||||
|
||||
*red = color[0];
|
||||
*green = color[1];
|
||||
*blue = color[2];
|
||||
@ -107,11 +133,11 @@ GLFWAPI void glfwThemeGetColor(const GLFWtheme* theme, int specifier, float* red
|
||||
|
||||
GLFWAPI void glfwThemeSetColor(GLFWtheme* theme, int specifier, float red, float green, float blue, float alpha)
|
||||
{
|
||||
float* color = ((_GLFWtheme*) theme)->color;
|
||||
|
||||
assert(theme != NULL);
|
||||
assert(specifier == GLFW_THEME_COLOR_MAIN);
|
||||
|
||||
float* color = ((_GLFWtheme*) theme)->color;
|
||||
|
||||
color[0] = red;
|
||||
color[1] = green;
|
||||
color[2] = blue;
|
||||
|
@ -151,6 +151,8 @@ static GLFWbool loadLibraries(void)
|
||||
_glfwPlatformGetModuleSymbol(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
|
||||
_glfw.win32.dwmapi.GetColorizationColor = (PFN_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");
|
||||
@ -169,6 +171,18 @@ static GLFWbool loadLibraries(void)
|
||||
_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;
|
||||
}
|
||||
|
||||
@ -193,6 +207,9 @@ static void freeLibraries(void)
|
||||
|
||||
if (_glfw.win32.ntdll.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
|
||||
|
||||
if (_glfw.win32.uxtheme.instance)
|
||||
_glfwPlatformFreeModule(_glfw.win32.uxtheme.instance);
|
||||
}
|
||||
|
||||
// Create key code translation tables
|
||||
@ -739,9 +756,18 @@ void _glfwTerminateWin32(void)
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeWin32(void)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
return NULL; // TODO: implement
|
||||
_GLFWtheme* theme = &_glfw.theme;
|
||||
|
||||
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
|
||||
|
||||
|
@ -299,12 +299,15 @@ typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
|
||||
// dwmapi.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
|
||||
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_DwmSetWindowAttribute)(HWND,DWORD,LPCVOID,DWORD);
|
||||
|
||||
#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
|
||||
#define DwmFlush _glfw.win32.dwmapi.Flush
|
||||
#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow
|
||||
#define DwmGetColorizationColor _glfw.win32.dwmapi.GetColorizationColor
|
||||
#define DwmSetWindowAttribute _glfw.win32.dwmapi.SetWindowAttribute
|
||||
|
||||
// shcore.dll function pointer typedefs
|
||||
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_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
|
||||
//
|
||||
@ -487,6 +495,7 @@ typedef struct _GLFWlibraryWin32
|
||||
PFN_DwmFlush Flush;
|
||||
PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow;
|
||||
PFN_DwmGetColorizationColor GetColorizationColor;
|
||||
PFN_DwmSetWindowAttribute SetWindowAttribute;
|
||||
} dwmapi;
|
||||
|
||||
struct {
|
||||
@ -499,6 +508,16 @@ typedef struct _GLFWlibraryWin32
|
||||
HINSTANCE instance;
|
||||
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
|
||||
} ntdll;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
GLFWbool uxThemeAvailable;
|
||||
GLFWbool darkTitleAvailable;
|
||||
ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
|
||||
GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
|
||||
GetImmersiveColorTypeFromNamePtr GetImmersiveColorTypeFromName;
|
||||
GetImmersiveUserColorSetPreferencePtr GetImmersiveUserColorSetPreference;
|
||||
} uxtheme;
|
||||
} _GLFWlibraryWin32;
|
||||
|
||||
// Win32-specific per-monitor data
|
||||
@ -623,5 +642,5 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
|
||||
const _GLFWfbconfig* fbconfig);
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeWin32(void);
|
||||
void _glfwSetThemeWin32(_GLFWwindow* window, _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window);
|
||||
void _glfwSetThemeWin32(_GLFWwindow* window, const _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window, int inlineDefaults);
|
||||
|
@ -37,6 +37,47 @@
|
||||
#include <windowsx.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 int getAccentColor(float color[4])
|
||||
{
|
||||
if (!_glfw.win32.uxtheme.uxThemeAvailable)
|
||||
return GLFW_FALSE;
|
||||
|
||||
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] = (float) (0xFF & rgba);
|
||||
color[1] = (float) ((0xFF00 & rgba) >> 8);
|
||||
color[2] = (float) ((0xFF0000 & rgba) >> 16);
|
||||
color[3] = (float) ((0xFF000000 & rgba) >> 24);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Returns the window style for the specified window
|
||||
//
|
||||
static DWORD getWindowStyle(const _GLFWwindow* window)
|
||||
@ -1146,6 +1187,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_THEMECHANGED:
|
||||
case WM_SETTINGCHANGE: {
|
||||
if (window->theme.internal.variation == GLFW_THEME_DEFAULT) {
|
||||
applySystemTheme(window->win32.handle);
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_GETDPISCALEDSIZE:
|
||||
{
|
||||
if (window->win32.scaleToMonitor)
|
||||
@ -1436,6 +1484,9 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
_glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height);
|
||||
|
||||
// Use the system default when creating a window
|
||||
applySystemTheme(window->win32.handle);
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
@ -2373,15 +2424,66 @@ const char* _glfwGetClipboardStringWin32(void)
|
||||
return _glfw.win32.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwSetThemeWin32(_GLFWwindow* window, _GLFWtheme* theme)
|
||||
void _glfwSetThemeWin32(_GLFWwindow* window, const _GLFWtheme* theme)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
_GLFWtheme* currentTheme = &window->theme.internal;
|
||||
_GLFWtheme newTheme;
|
||||
|
||||
if (!theme)
|
||||
_glfwInitDefaultTheme(&newTheme);
|
||||
else
|
||||
memcpy(&newTheme, theme, sizeof(_GLFWtheme));
|
||||
|
||||
if (newTheme.variation == GLFW_THEME_DEFAULT)
|
||||
{
|
||||
applySystemTheme(window->win32.handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLFWbool darkMode = newTheme.variation == GLFW_THEME_DARK;
|
||||
|
||||
DwmSetWindowAttribute(window->win32.handle,
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||
&darkMode,
|
||||
sizeof(darkMode));
|
||||
}
|
||||
|
||||
// TODO: set accent color
|
||||
|
||||
memcpy(currentTheme, &newTheme, sizeof(_GLFWtheme));
|
||||
|
||||
// Not available for setting in Win32.
|
||||
currentTheme->flags &= ~(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY |
|
||||
GLFW_THEME_ATTRIBUTE_REDUCE_MOTION|
|
||||
GLFW_THEME_COLOR_MAIN);
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window)
|
||||
_GLFWtheme* _glfwGetThemeWin32(_GLFWwindow* window, int inlineDefaults)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
return NULL; // TODO: implement
|
||||
_GLFWtheme* theme = &window->theme.external;
|
||||
memcpy(theme, &window->theme.internal, sizeof(_GLFWtheme));
|
||||
|
||||
if (!inlineDefaults)
|
||||
return theme;
|
||||
|
||||
if (theme->variation == GLFW_THEME_DEFAULT)
|
||||
{
|
||||
theme->variation = GLFW_THEME_LIGHT;
|
||||
|
||||
if (_glfw.win32.uxtheme.uxThemeAvailable && _glfw.win32.uxtheme.darkTitleAvailable)
|
||||
theme->variation = GLFW_THEME_DARK;
|
||||
}
|
||||
|
||||
if ((theme->flags & GLFW_THEME_COLOR_MAIN) == 0)
|
||||
{
|
||||
if (getAccentColor(theme->color))
|
||||
theme->flags |= GLFW_THEME_COLOR_MAIN;
|
||||
else
|
||||
memset(&theme->color, 0, sizeof(float) * 4);
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs)
|
||||
@ -2512,4 +2614,3 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
|
||||
}
|
||||
|
||||
#endif // _GLFW_WIN32
|
||||
|
||||
|
@ -245,6 +245,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
|
||||
window->numer = GLFW_DONT_CARE;
|
||||
window->denom = GLFW_DONT_CARE;
|
||||
|
||||
_glfwInitDefaultTheme(&window->theme.internal);
|
||||
|
||||
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
|
||||
{
|
||||
glfwDestroyWindow((GLFWwindow*) window);
|
||||
@ -1163,11 +1165,11 @@ GLFWAPI void glfwSetTheme(GLFWwindow* handle, const GLFWtheme* theme)
|
||||
_glfw.platform.setTheme(window, (_GLFWtheme*) theme);
|
||||
}
|
||||
|
||||
GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle)
|
||||
GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle, int inlineDefaults)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
return (GLFWtheme*) _glfw.platform.getTheme(window);
|
||||
return (GLFWtheme*) _glfw.platform.getTheme(window, inlineDefaults);
|
||||
}
|
||||
|
@ -520,5 +520,5 @@ void _glfwAddSeatListenerWayland(struct wl_seat* seat);
|
||||
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeWayland(void);
|
||||
void _glfwSetThemeWayland(_GLFWwindow* window, _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeWayland(_GLFWwindow* window);
|
||||
void _glfwSetThemeWayland(_GLFWwindow* window, const _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeWayland(_GLFWwindow* window, int inlineDefaults);
|
||||
|
@ -2775,12 +2775,13 @@ const char* _glfwGetClipboardStringWayland(void)
|
||||
return _glfw.wl.clipboardString;
|
||||
}
|
||||
|
||||
void _glfwSetThemeWayland(_GLFWwindow* window, _GLFWtheme* theme)
|
||||
void _glfwSetThemeWayland(_GLFWwindow* window, const _GLFWtheme* theme)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeWayland(_GLFWwindow* window)
|
||||
_GLFWtheme* _glfwGetThemeWayland(_GLFWwindow* window, int inlineDefaults)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
return NULL; // TODO: implement
|
||||
|
@ -1003,5 +1003,5 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
|
||||
Visual** visual, int* depth);
|
||||
|
||||
_GLFWtheme* _glfwGetSystemDefaultThemeX11(void);
|
||||
void _glfwSetThemeX11(_GLFWwindow* window, _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeX11(_GLFWwindow* window);
|
||||
void _glfwSetThemeX11(_GLFWwindow* window, const _GLFWtheme* theme);
|
||||
_GLFWtheme* _glfwGetThemeX11(_GLFWwindow* window, int inlineDefaults);
|
||||
|
@ -3082,12 +3082,13 @@ const char* _glfwGetClipboardStringX11(void)
|
||||
return getSelectionString(_glfw.x11.CLIPBOARD);
|
||||
}
|
||||
|
||||
void _glfwSetThemeX11(_GLFWwindow* window, _GLFWtheme* theme)
|
||||
void _glfwSetThemeX11(_GLFWwindow* window, const _GLFWtheme* theme)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
_GLFWtheme* _glfwGetThemeX11(_GLFWwindow* window)
|
||||
_GLFWtheme* _glfwGetThemeX11(_GLFWwindow* window, int inlineDefaults)
|
||||
{
|
||||
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
|
||||
return NULL; // TODO: implement
|
||||
|
@ -50,26 +50,29 @@ static int cur_theme_color = 0;
|
||||
|
||||
static GLFWtheme* theme;
|
||||
|
||||
static void print_theme(GLFWtheme* theme, const char* title)
|
||||
static void print_theme(const GLFWtheme* theme, const char* title)
|
||||
{
|
||||
int n = 0;
|
||||
int variation = glfwThemeGetVariation(theme);
|
||||
|
||||
printf("%s: {\n", title);
|
||||
printf(" Variation: %s\n", glfwThemeGetVariation(theme) == GLFW_THEME_LIGHT ? "light" : "dark");
|
||||
printf(" Variation: %s\n", variation == GLFW_THEME_DEFAULT ? "default" : variation == GLFW_THEME_LIGHT ? "light" : "dark");
|
||||
printf(" Attributes: [");
|
||||
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_COLOR_MAIN))
|
||||
{
|
||||
printf(n++ > 0 ? ", %s" : "%s", "COLOR_MAIN");
|
||||
}
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_ATTRIBUTE_VIBRANT))
|
||||
{
|
||||
printf(n++ > 0 ? ", %s" : "%s", "VIBRANT");
|
||||
}
|
||||
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST))
|
||||
{
|
||||
printf(n++ > 0 ? ", %s" : "%s", "HIGH_CONTRAST");
|
||||
}
|
||||
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY))
|
||||
printf(n++ > 0 ? ", %s" : "%s", "REDUCE_TRANSPARENCY");
|
||||
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_ATTRIBUTE_REDUCE_MOTION))
|
||||
printf(n++ > 0 ? ", %s" : "%s", "REDUCE_MOTION");
|
||||
|
||||
printf("]\n");
|
||||
|
||||
if (glfwThemeGetAttribute(theme, GLFW_THEME_COLOR_MAIN))
|
||||
{
|
||||
float r, g, b, a;
|
||||
@ -90,7 +93,7 @@ static void set_theme(GLFWwindow* window, int theme_color)
|
||||
theme_colors[theme_color][3]
|
||||
);
|
||||
|
||||
if (theme_color == 6)
|
||||
if (theme_color == 5)
|
||||
glfwThemeSetAttribute(theme, GLFW_THEME_COLOR_MAIN, GLFW_FALSE);
|
||||
else
|
||||
glfwThemeSetAttribute(theme, GLFW_THEME_COLOR_MAIN, GLFW_TRUE);
|
||||
@ -113,6 +116,11 @@ static void set_theme(GLFWwindow* window, int theme_color)
|
||||
glfwSetTheme(window, theme);
|
||||
}
|
||||
|
||||
static void flip_attribute(int attribute)
|
||||
{
|
||||
glfwThemeSetAttribute(theme, attribute, !glfwThemeGetAttribute(theme, attribute));
|
||||
}
|
||||
|
||||
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
if (action != GLFW_PRESS)
|
||||
@ -120,31 +128,59 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
switch (key)
|
||||
{
|
||||
// No theme specified
|
||||
case GLFW_KEY_0:
|
||||
glfwSetWindowTitle(window, "Default theme (NULL)");
|
||||
glfwSetTheme(window, NULL);
|
||||
break;
|
||||
// Theme with default variation
|
||||
case GLFW_KEY_1:
|
||||
glfwThemeSetVariation(theme, GLFW_THEME_DEFAULT);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Theme with light variation
|
||||
case GLFW_KEY_2:
|
||||
glfwThemeSetVariation(theme, GLFW_THEME_LIGHT);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Theme with dark variation
|
||||
case GLFW_KEY_3:
|
||||
glfwThemeSetVariation(theme, GLFW_THEME_DARK);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
break;
|
||||
// Traverse colors
|
||||
case GLFW_KEY_SPACE:
|
||||
cur_theme_color = (cur_theme_color + 1) % 6;
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Inspect
|
||||
case GLFW_KEY_I:
|
||||
print_theme(theme, "Constructed theme");
|
||||
break;
|
||||
// Print
|
||||
case GLFW_KEY_P:
|
||||
print_theme(glfwGetTheme(window), "Window theme");
|
||||
print_theme(glfwGetTheme(window, GLFW_FALSE), "Specified window theme");
|
||||
print_theme(glfwGetTheme(window, GLFW_TRUE), "Active window theme");
|
||||
printf("\n");
|
||||
break;
|
||||
// High contrast
|
||||
case GLFW_KEY_H:
|
||||
flip_attribute(GLFW_THEME_ATTRIBUTE_HIGH_CONTRAST);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Transparency
|
||||
case GLFW_KEY_T:
|
||||
flip_attribute(GLFW_THEME_ATTRIBUTE_REDUCE_TRANSPARENCY);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Motion
|
||||
case GLFW_KEY_M:
|
||||
flip_attribute(GLFW_THEME_ATTRIBUTE_REDUCE_MOTION);
|
||||
set_theme(window, cur_theme_color);
|
||||
break;
|
||||
// Exit
|
||||
case GLFW_KEY_ESCAPE:
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -175,6 +211,10 @@ int main(int argc, char** argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
print_theme(glfwGetTheme(window, GLFW_FALSE), "Initial specified window theme");
|
||||
print_theme(glfwGetTheme(window, GLFW_TRUE), "Initial active window theme");
|
||||
printf("\n");
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
gladLoadGL(glfwGetProcAddress);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user