From e7922d7b4f7c25349fd63a0170403425461cd67b Mon Sep 17 00:00:00 2001 From: ws909 <37029098+ws909@users.noreply.github.com> Date: Wed, 25 Jan 2023 19:46:16 +0100 Subject: [PATCH] Add GLFW theming functions Cocoa implementations are broken. Other platforms have no stubs, and therefore can't be compiled for. --- include/GLFW/glfw3.h | 31 ++++++++++++++ src/cocoa_init.m | 14 ++++++ src/cocoa_platform.h | 4 ++ src/cocoa_window.m | 100 +++++++++++++++++++++++++++++++++++++++++++ src/init.c | 14 ++++++ src/internal.h | 3 ++ src/window.c | 18 ++++++++ 7 files changed, 184 insertions(+) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index d4b40dd4..8129d2fa 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -5845,6 +5845,37 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); +typedef struct GLFWtheme +{ + int baseTheme; // light/dark + int flags; + unsigned char color[4]; +} GLFWtheme; + +#define GLFW_BASE_THEME_DEFAULT 0 +#define GLFW_BASE_THEME_LIGHT 1 +#define GLFW_BASE_THEME_DARK 2 + +#define GLFW_THEME_FLAG_HAS_COLOR 1 +#define GLFW_THEME_FLAG_HIGH_CONTRAST 2 +#define GLFW_THEME_FLAG_VIBRANT 4 + +typedef void (* GLFWthemefun)(GLFWtheme* theme); + +/*! @brief Notifies the application when the system default theme changes. + * + */ +GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback); + +/*! @brief Sets the theme for a window. + * + * @param[in] window The window to set the theme for. + * @param[in] theme The theme to set. Pass `NULL` to set it to the system default. + */ +GLFWAPI void glfwSetTheme(GLFWwindow* handle, GLFWtheme* theme); +GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle); +GLFWAPI GLFWtheme* glfwGetSystemDefaultTheme(); + /*! @brief Returns the GLFW time. * * This function returns the current GLFW time, in seconds. Unless the time diff --git a/src/cocoa_init.m b/src/cocoa_init.m index b3831df1..64c99b7c 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -496,8 +496,11 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) const _GLFWplatform cocoa = { GLFW_PLATFORM_COCOA, + // Init _glfwInitCocoa, _glfwTerminateCocoa, + _glfwGetSystemDefaultThemeCocoa, + // Input _glfwGetCursorPosCocoa, _glfwSetCursorPosCocoa, _glfwSetCursorModeCocoa, @@ -516,6 +519,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) _glfwPollJoystickCocoa, _glfwGetMappingNameCocoa, _glfwUpdateGamepadGUIDCocoa, + // Monitor _glfwFreeMonitorCocoa, _glfwGetMonitorPosCocoa, _glfwGetMonitorContentScaleCocoa, @@ -524,6 +528,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) _glfwGetVideoModeCocoa, _glfwGetGammaRampCocoa, _glfwSetGammaRampCocoa, + // Window _glfwCreateWindowCocoa, _glfwDestroyWindowCocoa, _glfwSetWindowTitleCocoa, @@ -557,13 +562,17 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform) _glfwSetWindowFloatingCocoa, _glfwSetWindowOpacityCocoa, _glfwSetWindowMousePassthroughCocoa, + _glfwGetThemeCocoa, + _glfwSetThemeCocoa, _glfwPollEventsCocoa, _glfwWaitEventsCocoa, _glfwWaitEventsTimeoutCocoa, _glfwPostEmptyEventCocoa, + // EGL _glfwGetEGLPlatformCocoa, _glfwGetEGLNativeDisplayCocoa, _glfwGetEGLNativeWindowCocoa, + // Vulkan _glfwGetRequiredInstanceExtensionsCocoa, _glfwGetPhysicalDevicePresentationSupportCocoa, _glfwCreateWindowSurfaceCocoa, @@ -693,5 +702,10 @@ void _glfwTerminateCocoa(void) } // autoreleasepool } +GLFWtheme* _glfwGetSystemDefaultThemeCocoa(void) +{ + return NULL; +} + #endif // _GLFW_COCOA diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 9f7d191d..3535615d 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -300,3 +300,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextNSGL(_GLFWwindow* window); + +GLFWtheme* _glfwGetSystemDefaultThemeCocoa(void); +void _glfwSetThemeCocoa(_GLFWwindow* window, GLFWtheme* theme); +GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window); diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6f8aa978..8391884a 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1876,6 +1876,106 @@ const char* _glfwGetClipboardStringCocoa(void) } // autoreleasepool } +void _glfwSetThemeCocoa(_GLFWwindow* window, GLFWtheme* theme) +{ + if (!theme || theme->baseTheme == GLFW_BASE_THEME_DEFAULT) + { + [window->ns.object setAppearance:nil]; + return; + } + + NSAppearanceName name; + + if (theme->baseTheme == GLFW_BASE_THEME_LIGHT) + { + if ((theme->flags & GLFW_THEME_FLAG_VIBRANT) && (theme->flags & GLFW_THEME_FLAG_HIGH_CONTRAST)) + { + name = NSAppearanceNameAccessibilityHighContrastVibrantLight; + } + else if (theme->flags & GLFW_THEME_FLAG_VIBRANT) { + name = NSAppearanceNameVibrantLight; + } + else if (theme->flags & GLFW_THEME_FLAG_HIGH_CONTRAST) + { + name = NSAppearanceNameAccessibilityHighContrastAqua; + } + else + { + name = NSAppearanceNameAqua; + } + } + else + { + if ((theme->flags & GLFW_THEME_FLAG_VIBRANT) && (theme->flags & GLFW_THEME_FLAG_HIGH_CONTRAST)) + { + name = NSAppearanceNameAccessibilityHighContrastVibrantDark; + } + else if (theme->flags & GLFW_THEME_FLAG_VIBRANT) { + name = NSAppearanceNameVibrantDark; + } + else if (theme->flags & GLFW_THEME_FLAG_HIGH_CONTRAST) + { + name = NSAppearanceNameAccessibilityHighContrastDarkAqua; + } + else + { + name = NSAppearanceNameDarkAqua; + } + } + + NSAppearance* appearance = [NSAppearance appearanceNamed:name]; + [window->ns.object setAppearance:appearance]; +} + +GLFWtheme* _glfwGetThemeCocoa(_GLFWwindow* window) +{ + GLFWtheme theme; + NSAppearanceName name = [window->ns.object 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; + } + + //return theme; + return NULL; +} + + EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) diff --git a/src/init.c b/src/init.c index d07a492e..890af4aa 100644 --- a/src/init.c +++ b/src/init.c @@ -543,3 +543,17 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun) return cbfun; } +GLFWAPI GLFWtheme* glfwGetSystemDefaultTheme() +{ + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.platform.getSystemDefaultTheme(); +} + +GLFWAPI GLFWthemefun glfwSetSystemThemeCallback(GLFWthemefun callback) +{ + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + //return _glfw.platform.setSystemThemeCallback(callback); + return NULL; +} diff --git a/src/internal.h b/src/internal.h index 781c8cdc..5bb135e1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -673,6 +673,7 @@ struct _GLFWplatform // init GLFWbool (*init)(void); void (*terminate)(void); + GLFWtheme* (*getSystemDefaultTheme)(void); // input void (*getCursorPos)(_GLFWwindow*,double*,double*); void (*setCursorPos)(_GLFWwindow*,double,double); @@ -735,6 +736,8 @@ struct _GLFWplatform void (*setWindowFloating)(_GLFWwindow*,GLFWbool); void (*setWindowOpacity)(_GLFWwindow*,float); void (*setWindowMousePassthrough)(_GLFWwindow*,GLFWbool); + GLFWtheme* (*getTheme)(_GLFWwindow*); + void (*setTheme)(_GLFWwindow*,GLFWtheme*); void (*pollEvents)(void); void (*waitEvents)(void); void (*waitEventsTimeout)(double); diff --git a/src/window.c b/src/window.c index 1c8519ff..e380d3fb 100644 --- a/src/window.c +++ b/src/window.c @@ -1153,3 +1153,21 @@ GLFWAPI void glfwPostEmptyEvent(void) _glfw.platform.postEmptyEvent(); } +GLFWAPI void glfwSetTheme(GLFWwindow* handle, GLFWtheme* theme) +{ + + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT(); + _glfw.platform.setTheme(window, theme); +} + +GLFWAPI GLFWtheme* glfwGetTheme(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return _glfw.platform.getTheme(window); +}