Fix glfwSetSystemThemeCallback and its Cocoa implementation

This commit is contained in:
ws909 2023-01-26 02:22:57 +01:00
parent ae437d3eaa
commit b091cc0c80
6 changed files with 118 additions and 48 deletions

View File

@ -175,6 +175,50 @@ static void createMenuBar(void)
[NSApp performSelector:setAppleMenuSelector withObject:appMenu];
}
void nsAppearanceToGLFWTheme(NSAppearance* appearance, GLFWtheme* theme)
{
NSAppearanceName name = appearance.name;
if (name == NSAppearanceNameAqua)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
}
else if (name == NSAppearanceNameDarkAqua)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
}
else if (name == NSAppearanceNameVibrantLight)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_VIBRANT;
}
else if (name == NSAppearanceNameVibrantDark)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_VIBRANT;
}
if (name == NSAppearanceNameAccessibilityHighContrastAqua)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastDarkAqua)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastVibrantLight)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_VIBRANT | GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastVibrantDark)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_VIBRANT | GLFW_THEME_FLAG_HIGH_CONTRAST;
}
}
// Create key code translation tables
//
static void createKeyTables(void)
@ -393,6 +437,41 @@ static GLFWbool initializeTIS(void)
- (void)doNothing:(id)object
{
}
/*
- (void)themeChanged:(NSNotification*)notification
{
_glfwInputSystemTheme(NULL);
}
- (void)accentColorChanged
{
_glfwInputSystemTheme(NULL);
}*/
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// This class is never subclassed, so it's safe to ignore the context parameter
GLFWtheme theme = { 0, 0 };
nsAppearanceToGLFWTheme(NSApp.effectiveAppearance, &theme);
NSColor* color = [[NSColor controlAccentColor] colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
theme.flags |= GLFW_THEME_FLAG_HAS_COLOR;
theme.color[0] = color.redComponent * 255;
theme.color[1] = color.greenComponent * 255;
theme.color[2] = color.blueComponent * 255;
theme.color[3] = color.alphaComponent * 255;
_glfwInputSystemTheme(&theme);
/*if ([keyPath isEqualToString:@"controlAccentColor"]) {
[self accentColorChanged];
}*/
}
@end // GLFWHelper
@ -641,6 +720,24 @@ int _glfwInitCocoa(void)
return GLFW_FALSE;
_glfwPollMonitorsCocoa();
/*
[[NSNotificationCenter defaultCenter]
addObserver:_glfw.ns.helper
selector:@selector(themeChanged:)
name:@"AppleInterfaceThemeChangedNotification"
object:nil];
[NSColor addObserver:_glfw.ns.helper
forKeyPath:@"controlAccentColor"
options:0
context:nil];
*/
[NSApp addObserver:_glfw.ns.helper
forKeyPath:@"effectiveAppearance"
options:0
context:nil];
if (![[NSRunningApplication currentApplication] isFinishedLaunching])
[NSApp run];

View File

@ -39,8 +39,10 @@
#import <Cocoa/Cocoa.h>
#else
typedef void* id;
typedef void NSAppearance;
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or deprecated.
// We use the newer names in code and replace them with the older names if
@ -291,6 +293,8 @@ void _glfwRestoreVideoModeCocoa(_GLFWmonitor* monitor);
float _glfwTransformYCocoa(float y);
void nsAppearanceToGLFWTheme(NSAppearance* appearance, GLFWtheme* theme);
void* _glfwLoadLocalVulkanLoaderCocoa(void);
GLFWbool _glfwInitNSGL(void);

View File

@ -1930,58 +1930,16 @@ void _glfwSetThemeCocoa(_GLFWwindow* window, GLFWtheme* theme)
GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window)
{
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); // TODO: remove
// TODO: must use KVO to observe NSApplication NSAppearance for theme callback.
GLFWtheme* theme = &window->theme;
NSAppearanceName name = [window->ns.object appearance].name;
theme->baseTheme = 0;
theme->flags = 0;
if (name == NSAppearanceNameAqua)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
}
else if (name == NSAppearanceNameDarkAqua)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
}
else if (name == NSAppearanceNameVibrantLight)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_VIBRANT;
}
else if (name == NSAppearanceNameVibrantDark)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_VIBRANT;
}
if (name == NSAppearanceNameAccessibilityHighContrastAqua)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastDarkAqua)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastVibrantLight)
{
theme->baseTheme = GLFW_BASE_THEME_LIGHT;
theme->flags |= GLFW_THEME_FLAG_VIBRANT | GLFW_THEME_FLAG_HIGH_CONTRAST;
}
else if (name == NSAppearanceNameAccessibilityHighContrastVibrantDark)
{
theme->baseTheme = GLFW_BASE_THEME_DARK;
theme->flags |= GLFW_THEME_FLAG_VIBRANT | GLFW_THEME_FLAG_HIGH_CONTRAST;
}
nsAppearanceToGLFWTheme([window->ns.object appearance], theme);
// 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.
// TODO: must use KVO to observe the controlAccentColor for the theme callback.
NSColor* color = [[NSColor controlAccentColor] colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
// TODO: Cannot use the accent color directly, for window themes, because the accent color is never overridden.
theme->flags |= GLFW_THEME_FLAG_HAS_COLOR;
theme->color[0] = color.redComponent * 255;

View File

@ -554,8 +554,9 @@ GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
//return _glfw.platform.setSystemThemeCallback(callback);
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL);
return NULL; // TODO: implement
//return _glfw.platform.setSystemThemeCallback(callback
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWthemefun, _glfw.callbacks.theme, callback);
return callback;
}

View File

@ -477,6 +477,13 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
js->hats[hat] = value;
}
void _glfwInputSystemTheme(GLFWtheme* theme)
{
assert(theme != NULL);
if (_glfw.callbacks.theme)
_glfw.callbacks.theme(theme);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////

View File

@ -868,6 +868,7 @@ struct _GLFWlibrary
struct {
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;
GLFWthemefun theme;
} callbacks;
// These are defined in platform.h
@ -934,6 +935,8 @@ void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
void _glfwInputSystemTheme(GLFWtheme* theme);
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);