diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 76aac5b2..1551b2b4 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1932,53 +1932,66 @@ GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window) { _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED, NULL); // TODO: remove - GLFWtheme theme; + // 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; + theme->baseTheme = GLFW_BASE_THEME_LIGHT; } else if (name == NSAppearanceNameDarkAqua) { - theme.baseTheme = GLFW_BASE_THEME_DARK; + theme->baseTheme = GLFW_BASE_THEME_DARK; } else if (name == NSAppearanceNameVibrantLight) { - theme.baseTheme = GLFW_BASE_THEME_LIGHT; - theme.flags |= GLFW_THEME_FLAG_VIBRANT; + 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; + 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; + 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; + 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; + 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; + theme->baseTheme = GLFW_BASE_THEME_DARK; + theme->flags |= GLFW_THEME_FLAG_VIBRANT | GLFW_THEME_FLAG_HIGH_CONTRAST; } - //return theme; - return NULL; // TODO: implement + // 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]; + + 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; + + return theme; } - EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) diff --git a/src/internal.h b/src/internal.h index 5bb135e1..1024e193 100644 --- a/src/internal.h +++ b/src/internal.h @@ -570,6 +570,8 @@ struct _GLFWwindow GLFWcharmodsfun charmods; GLFWdropfun drop; } callbacks; + + GLFWtheme theme; // This is defined in platform.h GLFW_PLATFORM_WINDOW_STATE diff --git a/tests/theming.c b/tests/theming.c index 695876ff..c74425c8 100644 --- a/tests/theming.c +++ b/tests/theming.c @@ -50,6 +50,33 @@ static int cur_theme_color = 0; static GLFWtheme theme; +static void print_theme(GLFWtheme* theme, const char* title) +{ + int n = 0; + + printf("%s: {\n", title); + printf(" Base: %s\n", theme->baseTheme == GLFW_BASE_THEME_LIGHT ? "light" : "dark"); + printf(" Flags: ["); + if (theme->flags & GLFW_THEME_FLAG_HAS_COLOR) + { + printf(n++ > 0 ? ", %s" : "%s", "HAS_COLOR"); + } + if (theme->flags & GLFW_THEME_FLAG_VIBRANT) + { + printf(n++ > 0 ? ", %s" : "%s", "VIBRANT"); + } + if (theme->flags & GLFW_THEME_FLAG_HIGH_CONTRAST) + { + printf(n++ > 0 ? ", %s" : "%s", "HIGH_CONTRAST"); + } + printf("]\n"); + if (theme->flags & GLFW_THEME_FLAG_HAS_COLOR) + { + printf(" Color: [%i, %i, %i, %i]\n", theme->color[0], theme->color[1], theme->color[2], theme->color[3]); + } + printf("}\n"); +} + static void set_theme(GLFWwindow* window, int theme_color) { memcpy(theme.color, theme_colors[theme_color], 4); @@ -110,9 +137,17 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, cur_theme_color = (cur_theme_color + 1) % 6; set_theme(window, cur_theme_color); break; + case GLFW_KEY_P: + print_theme(glfwGetTheme(window), "Window theme"); + break; } } +static void theme_callback(GLFWtheme* theme) +{ + print_theme(theme, "System theme changed to"); +} + int main(int argc, char** argv) { GLFWwindow* window; @@ -144,6 +179,8 @@ int main(int argc, char** argv) theme.color[2] = 0; theme.color[3] = 0; set_theme(window, cur_theme_color); + + glfwSetSystemThemeCallback(theme_callback); while (!glfwWindowShouldClose(window)) {