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]; [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 // Create key code translation tables
// //
static void createKeyTables(void) static void createKeyTables(void)
@ -393,6 +437,41 @@ static GLFWbool initializeTIS(void)
- (void)doNothing:(id)object - (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 @end // GLFWHelper
@ -641,6 +720,24 @@ int _glfwInitCocoa(void)
return GLFW_FALSE; return GLFW_FALSE;
_glfwPollMonitorsCocoa(); _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]) if (![[NSRunningApplication currentApplication] isFinishedLaunching])
[NSApp run]; [NSApp run];

View File

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

View File

@ -1930,58 +1930,16 @@ void _glfwSetThemeCocoa(_GLFWwindow* window, GLFWtheme* theme)
GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window) 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; GLFWtheme* theme = &window->theme;
NSAppearanceName name = [window->ns.object appearance].name;
theme->baseTheme = 0; theme->baseTheme = 0;
theme->flags = 0; theme->flags = 0;
if (name == NSAppearanceNameAqua) nsAppearanceToGLFWTheme([window->ns.object appearance], theme);
{
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;
}
// 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: 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]; 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->flags |= GLFW_THEME_FLAG_HAS_COLOR;
theme->color[0] = color.redComponent * 255; theme->color[0] = color.redComponent * 255;

View File

@ -554,8 +554,9 @@ GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
//return _glfw.platform.setSystemThemeCallback(callback); //return _glfw.platform.setSystemThemeCallback(callback
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return NULL; // TODO: implement _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; js->hats[hat] = value;
} }
void _glfwInputSystemTheme(GLFWtheme* theme)
{
assert(theme != NULL);
if (_glfw.callbacks.theme)
_glfw.callbacks.theme(theme);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////

View File

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