From 1bffe89b5dca89a1a311d6898eadb7d9bd79031c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 4 Apr 2024 21:49:32 +0530 Subject: [PATCH] Wayland GNOME: titlebar color now follows system theme When GNOME system theme is default, the color matches the background color. When it is dark it is dark. --- docs/changelog.rst | 6 ++++-- glfw/cocoa_init.m | 2 ++ glfw/cocoa_window.m | 14 ++++++-------- glfw/glfw3.h | 10 ++++++++-- glfw/init.c | 3 +-- glfw/input.c | 4 ++++ glfw/internal.h | 2 ++ glfw/linux_desktop_settings.c | 14 +++++++------- glfw/linux_desktop_settings.h | 2 +- glfw/wl_client_side_decorations.c | 23 ++++++++++------------- glfw/wl_init.c | 3 ++- glfw/wl_window.c | 11 +++++++++++ glfw/x11_init.c | 6 ++++-- kitty/boss.py | 3 ++- kitty/glfw-wrapper.h | 10 ++++++++-- kitty/glfw.c | 14 +++++++++++--- kitty/options/definition.py | 4 ++-- 17 files changed, 85 insertions(+), 46 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f8d04b7e2..67ae96ae6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -59,10 +59,10 @@ Detailed list of changes - Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor -- Wayland: Support preferred integer scales - - Wayland KDE: Support :opt:`background_blur` +- Wayland GNOME: The window titlebar color now follows the system light/dark color scheme preference, see :opt:`wayland_titlebar_color` + - Wayland KDE: Fix mouse cursor hiding not working in Plasma 6 (:iss:`7265`) - Wayland IME: Fix a bug with handling synthetic keypresses generated by ZMK keyboard + fcitx (:pull:`7283`) @@ -83,6 +83,8 @@ Detailed list of changes - Linux: Fix for a regression in 0.32.0 that caused some CJK fonts to not render glyphs (:iss:`7263`) +- Wayland: Support preferred integer scales + 0.33.1 [2024-03-21] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/cocoa_init.m b/glfw/cocoa_init.m index dc626ae5f..284c57d49 100644 --- a/glfw/cocoa_init.m +++ b/glfw/cocoa_init.m @@ -1141,3 +1141,5 @@ void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval, } } } + +void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { } diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 79a274764..02112ba09 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1012,13 +1012,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)viewDidChangeEffectiveAppearance { - static int appearance = 0; - if (_glfw.callbacks.system_color_theme_change) { - int new_appearance = glfwGetCurrentSystemColorTheme(); - if (new_appearance != appearance) { - appearance = new_appearance; - _glfw.callbacks.system_color_theme_change(appearance); - } + static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE; + GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme(); + if (new_appearance != appearance) { + appearance = new_appearance; + _glfwInputColorScheme(appearance); } } @@ -3143,7 +3141,7 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us [window->ns.object makeFirstResponder:window->ns.view]; }} -GLFWAPI int glfwGetCurrentSystemColorTheme(void) { +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { int theme_type = 0; NSAppearance *changedAppearance = NSApp.effectiveAppearance; NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 312665645..4c5b8da42 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -540,6 +540,12 @@ typedef enum GLFWMouseButton { } GLFWMouseButton; /*! @} */ +typedef enum GLFWColorScheme { + GLFW_COLOR_SCHEME_NO_PREFERENCE = 0, + GLFW_COLOR_SCHEME_DARK = 1, + GLFW_COLOR_SCHEME_LIGHT = 2 +} GLFWColorScheme; + /*! @defgroup joysticks Joysticks * @brief Joystick IDs. * @@ -1426,7 +1432,7 @@ typedef void (* GLFWapplicationclosefun)(int); * * @ingroup window */ -typedef void (* GLFWsystemcolorthemechangefun)(int); +typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme); /*! @brief The function pointer type for window content refresh callbacks. @@ -3969,7 +3975,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback); GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun callback); GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun callback); -GLFWAPI int glfwGetCurrentSystemColorTheme(void); +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void); /*! @brief Sets the refresh callback for the specified window. * diff --git a/glfw/init.c b/glfw/init.c index c3faaaf11..8d09106a1 100644 --- a/glfw/init.c +++ b/glfw/init.c @@ -34,7 +34,6 @@ #include #include #include -#include // The global variables below comprise all mutable global data in GLFW @@ -382,7 +381,7 @@ GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationc return cbfun; } -GLFWAPI GLFWapplicationclosefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun cbfun) +GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_SWAP_POINTERS(_glfw.callbacks.system_color_theme_change, cbfun); diff --git a/glfw/input.c b/glfw/input.c index 4cde4608f..9671c1061 100644 --- a/glfw/input.c +++ b/glfw/input.c @@ -448,6 +448,10 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) js->hats[hat] = value; } +void _glfwInputColorScheme(GLFWColorScheme value) { + _glfwPlatformInputColorScheme(value); + if (_glfw.callbacks.system_color_theme_change) _glfw.callbacks.system_color_theme_change(value); +} ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// diff --git a/glfw/internal.h b/glfw/internal.h index 7af6ec000..381251df9 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -804,6 +804,8 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorEnter(_GLFWwindow* window, bool entered); int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz); +void _glfwInputColorScheme(GLFWColorScheme); +void _glfwPlatformInputColorScheme(GLFWColorScheme); void _glfwInputJoystick(_GLFWjoystick* js, int event); void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); diff --git a/glfw/linux_desktop_settings.c b/glfw/linux_desktop_settings.c index d68700b03..b089ff2b1 100644 --- a/glfw/linux_desktop_settings.c +++ b/glfw/linux_desktop_settings.c @@ -20,10 +20,10 @@ static char theme_name[128] = {0}; static int theme_size = -1; -static uint32_t appearance = 0; +static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE; static bool cursor_theme_changed = false; -int +GLFWColorScheme glfw_current_system_color_theme(void) { return appearance; } @@ -39,8 +39,10 @@ static void process_fdo_setting(const char *key, DBusMessageIter *value) { if (strcmp(key, FDO_APPEARANCE_KEY) == 0) { if (dbus_message_iter_get_arg_type(value) == DBUS_TYPE_UINT32) { - dbus_message_iter_get_basic(value, &appearance); - if (appearance > 2) appearance = 0; + uint32_t val; + dbus_message_iter_get_basic(value, &val); + if (val > 2) val = 0; + appearance = val; } } } @@ -159,9 +161,7 @@ on_color_scheme_change(DBusMessage *message) { if (val > 2) val = 0; if (val != appearance) { appearance = val; - if (_glfw.callbacks.system_color_theme_change) { - _glfw.callbacks.system_color_theme_change(appearance); - } + _glfwInputColorScheme(appearance); } } break; diff --git a/glfw/linux_desktop_settings.h b/glfw/linux_desktop_settings.h index 105100a67..de260ec29 100644 --- a/glfw/linux_desktop_settings.h +++ b/glfw/linux_desktop_settings.h @@ -12,4 +12,4 @@ void glfw_initialize_desktop_settings(void); void glfw_current_cursor_theme(const char **theme, int *size); -int glfw_current_system_color_theme(void); +GLFWColorScheme glfw_current_system_color_theme(void); diff --git a/glfw/wl_client_side_decorations.c b/glfw/wl_client_side_decorations.c index afb6e0b1a..ed5f018ba 100644 --- a/glfw/wl_client_side_decorations.c +++ b/glfw/wl_client_side_decorations.c @@ -22,8 +22,6 @@ #define B(x) ((x) & 0xff) #define SWAP(x, y) do { __typeof__(x) SWAP = x; x = y; y = SWAP; } while (0) -static const uint32_t passive_bg_color = 0xffeeeeee; -static const uint32_t active_bg_color = 0xffdddad6; typedef float kernel_type; static void @@ -166,18 +164,19 @@ create_shadow_tile(_GLFWwindow *window) { static void render_title_bar(_GLFWwindow *window, bool to_front_buffer) { const bool is_focused = window->id == _glfw.focusedWindowId; - uint32_t bg_color = is_focused ? active_bg_color : passive_bg_color; - uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888; - if (decs.use_custom_titlebar_color) { + uint32_t light_fg = is_focused ? 0xff444444 : 0xff888888, light_bg = is_focused ? 0xffdddad6 : 0xffeeeeee; + uint32_t dark_fg = is_focused ? 0xffffffff : 0xffcccccc, dark_bg = is_focused ? 0xff303030 : 0xff242424; + uint32_t bg_color = light_bg, fg_color = light_fg; + GLFWColorScheme appearance = glfwGetCurrentSystemColorTheme(); + if (decs.use_custom_titlebar_color || appearance == GLFW_COLOR_SCHEME_NO_PREFERENCE) { bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff); double red = ((bg_color >> 16) & 0xFF) / 255.0; double green = ((bg_color >> 8) & 0xFF) / 255.0; double blue = (bg_color & 0xFF) / 255.0; double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue; - if (luma < 0.5) { - fg_color = is_focused ? 0xffeeeeee : 0xff888888; - } - } + if (luma < 0.5) fg_color = dark_fg; + if (!decs.use_custom_titlebar_color) bg_color = luma < 0.5 ? dark_bg : light_bg; + } else if (appearance == GLFW_COLOR_SCHEME_DARK) { bg_color = dark_bg; fg_color = dark_fg; } uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back; // render shadow part @@ -456,9 +455,7 @@ set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) { void set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color) { bool use_custom_color = !use_system_color; - if (use_custom_color != decs.use_custom_titlebar_color || color != decs.titlebar_color) { - decs.use_custom_titlebar_color = use_custom_color; - decs.titlebar_color = color; - } + decs.use_custom_titlebar_color = use_custom_color; + decs.titlebar_color = color; change_csd_title(window); } diff --git a/glfw/wl_init.c b/glfw/wl_init.c index f54759505..aeccddf2d 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -28,6 +28,7 @@ #define _GNU_SOURCE #include "internal.h" +#include "wl_client_side_decorations.h" #include "backend_utils.h" #include "linux_desktop_settings.h" #include "../kitty/monotonic.h" @@ -781,7 +782,7 @@ static const struct wl_registry_listener registryListener = { }; -GLFWAPI int glfwGetCurrentSystemColorTheme(void) { +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { return glfw_current_system_color_theme(); } diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 3f547f659..d4a7dccea 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -2691,3 +2691,14 @@ GLFWAPI void glfwWaylandSetupLayerShellForNextWindow(GLFWLayerShellConfig c) { if (layer_shell_config_for_next_window.output_name && !layer_shell_config_for_next_window.output_name[0]) layer_shell_config_for_next_window.output_name = NULL; if (layer_shell_config_for_next_window.output_name) layer_shell_config_for_next_window.output_name = strdup(layer_shell_config_for_next_window.output_name); } + +void +_glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { + _GLFWwindow* window = _glfw.windowListHead; + while (window) { + change_csd_title(window); + commit_window_surface_if_safe(window); + + window = window->next; + } +} diff --git a/glfw/x11_init.c b/glfw/x11_init.c index fdec2a4ec..f290051ee 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -614,10 +614,12 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWAPI int glfwGetCurrentSystemColorTheme(void) { - return 0; +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { + return GLFW_COLOR_SCHEME_NO_PREFERENCE; } +void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { } + int _glfwPlatformInit(void) { XInitThreads(); diff --git a/kitty/boss.py b/kitty/boss.py index bb588ceac..5957cb23c 100644 --- a/kitty/boss.py +++ b/kitty/boss.py @@ -23,6 +23,7 @@ from typing import ( Iterable, Iterator, List, + Literal, Optional, Sequence, Set, @@ -2934,7 +2935,7 @@ class Boss: def sanitize_url_for_dispay_to_user(self, url: str) -> str: return sanitize_url_for_dispay_to_user(url) - def on_system_color_scheme_change(self, appearance: int) -> None: + def on_system_color_scheme_change(self, appearance: Literal['light', 'dark', 'no_preference']) -> None: log_error('system color theme changed:', appearance) @ac('win', ''' diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index eac44c312..3058d282e 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -278,6 +278,12 @@ typedef enum GLFWMouseButton { } GLFWMouseButton; /*! @} */ +typedef enum GLFWColorScheme { + GLFW_COLOR_SCHEME_NO_PREFERENCE = 0, + GLFW_COLOR_SCHEME_DARK = 1, + GLFW_COLOR_SCHEME_LIGHT = 2 +} GLFWColorScheme; + /*! @defgroup joysticks Joysticks * @brief Joystick IDs. * @@ -1164,7 +1170,7 @@ typedef void (* GLFWapplicationclosefun)(int); * * @ingroup window */ -typedef void (* GLFWsystemcolorthemechangefun)(int); +typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme); /*! @brief The function pointer type for window content refresh callbacks. @@ -1997,7 +2003,7 @@ typedef GLFWsystemcolorthemechangefun (*glfwSetSystemColorThemeChangeCallback_fu GFW_EXTERN glfwSetSystemColorThemeChangeCallback_func glfwSetSystemColorThemeChangeCallback_impl; #define glfwSetSystemColorThemeChangeCallback glfwSetSystemColorThemeChangeCallback_impl -typedef int (*glfwGetCurrentSystemColorTheme_func)(void); +typedef GLFWColorScheme (*glfwGetCurrentSystemColorTheme_func)(void); GFW_EXTERN glfwGetCurrentSystemColorTheme_func glfwGetCurrentSystemColorTheme_impl; #define glfwGetCurrentSystemColorTheme glfwGetCurrentSystemColorTheme_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 405715aab..34c53fd40 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -62,8 +62,15 @@ get_platform_dependent_config_values(void *glfw_window) { } static void -on_system_color_scheme_change(int appearance) { - call_boss(on_system_color_scheme_change, "i", appearance); +on_system_color_scheme_change(GLFWColorScheme appearance) { + const char *which = NULL; + switch (appearance) { + case GLFW_COLOR_SCHEME_NO_PREFERENCE: which = "no_preference"; break; + case GLFW_COLOR_SCHEME_DARK: which = "dark"; break; + case GLFW_COLOR_SCHEME_LIGHT: which = "light"; break; + } + debug("system color-scheme changed to: %s\n", which); + call_boss(on_system_color_scheme_change, "s", which); } static void @@ -945,7 +952,7 @@ init_window_chrome_state(WindowChromeState *s, color_type active_window_bg, bool #define SET_TCOL(val) \ s->use_system_color = false; \ switch (val & 0xff) { \ - case 0: s->use_system_color = true; break; \ + case 0: s->use_system_color = true; s->color = active_window_bg; break; \ case 1: s->color = active_window_bg; break; \ default: s->color = val >> 8; break; \ } @@ -2265,6 +2272,7 @@ init_glfw(PyObject *m) { ADDC(GLFW_LAYER_SHELL_NONE); ADDC(GLFW_LAYER_SHELL_PANEL); ADDC(GLFW_LAYER_SHELL_BACKGROUND); ADDC(GLFW_FOCUS_NOT_ALLOWED); ADDC(GLFW_FOCUS_EXCLUSIVE); ADDC(GLFW_FOCUS_ON_DEMAND); ADDC(GLFW_EDGE_TOP); ADDC(GLFW_EDGE_BOTTOM); ADDC(GLFW_EDGE_LEFT); ADDC(GLFW_EDGE_RIGHT); + ADDC(GLFW_COLOR_SCHEME_NO_PREFERENCE); ADDC(GLFW_COLOR_SCHEME_DARK); ADDC(GLFW_COLOR_SCHEME_LIGHT); /* start glfw functional keys (auto generated by gen-key-constants.py do not edit) */ ADDC(GLFW_FKEY_ESCAPE); diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 1cb57083a..29d03f548 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -3275,8 +3275,8 @@ agr('os', 'OS specific tweaks') opt('wayland_titlebar_color', 'system', option_type='titlebar_color', ctype='uint', long_text=''' The color of the kitty window's titlebar on Wayland systems with client side window decorations such as GNOME. A value of :code:`system` means to use -the default system color, a value of :code:`background` means to use the -background color of the currently active window and finally you can use an +the default system colors, a value of :code:`background` means to use the +background color of the currently active kitty window and finally you can use an arbitrary color, such as :code:`#12af59` or :code:`red`. ''' )