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.
This commit is contained in:
Kovid Goyal
2024-04-04 21:49:32 +05:30
parent bdfa57039c
commit 1bffe89b5d
17 changed files with 85 additions and 46 deletions

View File

@@ -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 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 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 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`) - 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`) - 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] 0.33.1 [2024-03-21]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -1141,3 +1141,5 @@ void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval,
} }
} }
} }
void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { }

View File

@@ -1012,13 +1012,11 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)viewDidChangeEffectiveAppearance - (void)viewDidChangeEffectiveAppearance
{ {
static int appearance = 0; static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE;
if (_glfw.callbacks.system_color_theme_change) { GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme();
int new_appearance = glfwGetCurrentSystemColorTheme(); if (new_appearance != appearance) {
if (new_appearance != appearance) { appearance = new_appearance;
appearance = new_appearance; _glfwInputColorScheme(appearance);
_glfw.callbacks.system_color_theme_change(appearance);
}
} }
} }
@@ -3143,7 +3141,7 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us
[window->ns.object makeFirstResponder:window->ns.view]; [window->ns.object makeFirstResponder:window->ns.view];
}} }}
GLFWAPI int glfwGetCurrentSystemColorTheme(void) { GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) {
int theme_type = 0; int theme_type = 0;
NSAppearance *changedAppearance = NSApp.effectiveAppearance; NSAppearance *changedAppearance = NSApp.effectiveAppearance;
NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];

10
glfw/glfw3.h vendored
View File

@@ -540,6 +540,12 @@ typedef enum GLFWMouseButton {
} 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 /*! @defgroup joysticks Joysticks
* @brief Joystick IDs. * @brief Joystick IDs.
* *
@@ -1426,7 +1432,7 @@ typedef void (* GLFWapplicationclosefun)(int);
* *
* @ingroup window * @ingroup window
*/ */
typedef void (* GLFWsystemcolorthemechangefun)(int); typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme);
/*! @brief The function pointer type for window content refresh callbacks. /*! @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 GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback);
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun callback); GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun callback);
GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun callback); GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun callback);
GLFWAPI int glfwGetCurrentSystemColorTheme(void); GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void);
/*! @brief Sets the refresh callback for the specified window. /*! @brief Sets the refresh callback for the specified window.
* *

3
glfw/init.c vendored
View File

@@ -34,7 +34,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
// The global variables below comprise all mutable global data in GLFW // The global variables below comprise all mutable global data in GLFW
@@ -382,7 +381,7 @@ GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationc
return cbfun; return cbfun;
} }
GLFWAPI GLFWapplicationclosefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun cbfun) GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun cbfun)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.system_color_theme_change, cbfun); _GLFW_SWAP_POINTERS(_glfw.callbacks.system_color_theme_change, cbfun);

4
glfw/input.c vendored
View File

@@ -448,6 +448,10 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
js->hats[hat] = 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 ////// ////// GLFW internal API //////

2
glfw/internal.h vendored
View File

@@ -804,6 +804,8 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered); void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz); 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 _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value); void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);

View File

@@ -20,10 +20,10 @@
static char theme_name[128] = {0}; static char theme_name[128] = {0};
static int theme_size = -1; static int theme_size = -1;
static uint32_t appearance = 0; static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE;
static bool cursor_theme_changed = false; static bool cursor_theme_changed = false;
int GLFWColorScheme
glfw_current_system_color_theme(void) { glfw_current_system_color_theme(void) {
return appearance; return appearance;
} }
@@ -39,8 +39,10 @@ static void
process_fdo_setting(const char *key, DBusMessageIter *value) { process_fdo_setting(const char *key, DBusMessageIter *value) {
if (strcmp(key, FDO_APPEARANCE_KEY) == 0) { if (strcmp(key, FDO_APPEARANCE_KEY) == 0) {
if (dbus_message_iter_get_arg_type(value) == DBUS_TYPE_UINT32) { if (dbus_message_iter_get_arg_type(value) == DBUS_TYPE_UINT32) {
dbus_message_iter_get_basic(value, &appearance); uint32_t val;
if (appearance > 2) appearance = 0; 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 > 2) val = 0;
if (val != appearance) { if (val != appearance) {
appearance = val; appearance = val;
if (_glfw.callbacks.system_color_theme_change) { _glfwInputColorScheme(appearance);
_glfw.callbacks.system_color_theme_change(appearance);
}
} }
} }
break; break;

View File

@@ -12,4 +12,4 @@
void glfw_initialize_desktop_settings(void); void glfw_initialize_desktop_settings(void);
void glfw_current_cursor_theme(const char **theme, int *size); void glfw_current_cursor_theme(const char **theme, int *size);
int glfw_current_system_color_theme(void); GLFWColorScheme glfw_current_system_color_theme(void);

View File

@@ -22,8 +22,6 @@
#define B(x) ((x) & 0xff) #define B(x) ((x) & 0xff)
#define SWAP(x, y) do { __typeof__(x) SWAP = x; x = y; y = SWAP; } while (0) #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; typedef float kernel_type;
static void static void
@@ -166,18 +164,19 @@ create_shadow_tile(_GLFWwindow *window) {
static void static void
render_title_bar(_GLFWwindow *window, bool to_front_buffer) { render_title_bar(_GLFWwindow *window, bool to_front_buffer) {
const bool is_focused = window->id == _glfw.focusedWindowId; const bool is_focused = window->id == _glfw.focusedWindowId;
uint32_t bg_color = is_focused ? active_bg_color : passive_bg_color; uint32_t light_fg = is_focused ? 0xff444444 : 0xff888888, light_bg = is_focused ? 0xffdddad6 : 0xffeeeeee;
uint32_t fg_color = is_focused ? 0xff444444 : 0xff888888; uint32_t dark_fg = is_focused ? 0xffffffff : 0xffcccccc, dark_bg = is_focused ? 0xff303030 : 0xff242424;
if (decs.use_custom_titlebar_color) { 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); bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff);
double red = ((bg_color >> 16) & 0xFF) / 255.0; double red = ((bg_color >> 16) & 0xFF) / 255.0;
double green = ((bg_color >> 8) & 0xFF) / 255.0; double green = ((bg_color >> 8) & 0xFF) / 255.0;
double blue = (bg_color & 0xFF) / 255.0; double blue = (bg_color & 0xFF) / 255.0;
double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue; double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
if (luma < 0.5) { if (luma < 0.5) fg_color = dark_fg;
fg_color = is_focused ? 0xffeeeeee : 0xff888888; 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; uint8_t *output = to_front_buffer ? decs.top.buffer.data.front : decs.top.buffer.data.back;
// render shadow part // render shadow part
@@ -456,9 +455,7 @@ set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) {
void void
set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color) { set_titlebar_color(_GLFWwindow *window, uint32_t color, bool use_system_color) {
bool use_custom_color = !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.use_custom_titlebar_color = use_custom_color; decs.titlebar_color = color;
decs.titlebar_color = color;
}
change_csd_title(window); change_csd_title(window);
} }

3
glfw/wl_init.c vendored
View File

@@ -28,6 +28,7 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include "internal.h" #include "internal.h"
#include "wl_client_side_decorations.h"
#include "backend_utils.h" #include "backend_utils.h"
#include "linux_desktop_settings.h" #include "linux_desktop_settings.h"
#include "../kitty/monotonic.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(); return glfw_current_system_color_theme();
} }

11
glfw/wl_window.c vendored
View File

@@ -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[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); 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;
}
}

6
glfw/x11_init.c vendored
View File

@@ -614,10 +614,12 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot)
////// GLFW platform API ////// ////// GLFW platform API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetCurrentSystemColorTheme(void) { GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) {
return 0; return GLFW_COLOR_SCHEME_NO_PREFERENCE;
} }
void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { }
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
XInitThreads(); XInitThreads();

View File

@@ -23,6 +23,7 @@ from typing import (
Iterable, Iterable,
Iterator, Iterator,
List, List,
Literal,
Optional, Optional,
Sequence, Sequence,
Set, Set,
@@ -2934,7 +2935,7 @@ class Boss:
def sanitize_url_for_dispay_to_user(self, url: str) -> str: def sanitize_url_for_dispay_to_user(self, url: str) -> str:
return sanitize_url_for_dispay_to_user(url) 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) log_error('system color theme changed:', appearance)
@ac('win', ''' @ac('win', '''

10
kitty/glfw-wrapper.h generated
View File

@@ -278,6 +278,12 @@ typedef enum GLFWMouseButton {
} 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 /*! @defgroup joysticks Joysticks
* @brief Joystick IDs. * @brief Joystick IDs.
* *
@@ -1164,7 +1170,7 @@ typedef void (* GLFWapplicationclosefun)(int);
* *
* @ingroup window * @ingroup window
*/ */
typedef void (* GLFWsystemcolorthemechangefun)(int); typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme);
/*! @brief The function pointer type for window content refresh callbacks. /*! @brief The function pointer type for window content refresh callbacks.
@@ -1997,7 +2003,7 @@ typedef GLFWsystemcolorthemechangefun (*glfwSetSystemColorThemeChangeCallback_fu
GFW_EXTERN glfwSetSystemColorThemeChangeCallback_func glfwSetSystemColorThemeChangeCallback_impl; GFW_EXTERN glfwSetSystemColorThemeChangeCallback_func glfwSetSystemColorThemeChangeCallback_impl;
#define glfwSetSystemColorThemeChangeCallback glfwSetSystemColorThemeChangeCallback_impl #define glfwSetSystemColorThemeChangeCallback glfwSetSystemColorThemeChangeCallback_impl
typedef int (*glfwGetCurrentSystemColorTheme_func)(void); typedef GLFWColorScheme (*glfwGetCurrentSystemColorTheme_func)(void);
GFW_EXTERN glfwGetCurrentSystemColorTheme_func glfwGetCurrentSystemColorTheme_impl; GFW_EXTERN glfwGetCurrentSystemColorTheme_func glfwGetCurrentSystemColorTheme_impl;
#define glfwGetCurrentSystemColorTheme glfwGetCurrentSystemColorTheme_impl #define glfwGetCurrentSystemColorTheme glfwGetCurrentSystemColorTheme_impl

View File

@@ -62,8 +62,15 @@ get_platform_dependent_config_values(void *glfw_window) {
} }
static void static void
on_system_color_scheme_change(int appearance) { on_system_color_scheme_change(GLFWColorScheme appearance) {
call_boss(on_system_color_scheme_change, "i", 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 static void
@@ -945,7 +952,7 @@ init_window_chrome_state(WindowChromeState *s, color_type active_window_bg, bool
#define SET_TCOL(val) \ #define SET_TCOL(val) \
s->use_system_color = false; \ s->use_system_color = false; \
switch (val & 0xff) { \ 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; \ case 1: s->color = active_window_bg; break; \
default: s->color = val >> 8; 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_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_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_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) */ /* start glfw functional keys (auto generated by gen-key-constants.py do not edit) */
ADDC(GLFW_FKEY_ESCAPE); ADDC(GLFW_FKEY_ESCAPE);

View File

@@ -3275,8 +3275,8 @@ agr('os', 'OS specific tweaks')
opt('wayland_titlebar_color', 'system', option_type='titlebar_color', ctype='uint', long_text=''' 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 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 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 the default system colors, a value of :code:`background` means to use the
background color of the currently active window and finally you can use an background color of the currently active kitty window and finally you can use an
arbitrary color, such as :code:`#12af59` or :code:`red`. arbitrary color, such as :code:`#12af59` or :code:`red`.
''' '''
) )