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
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
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 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]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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 @@ - (void)mouseEntered:(NSEvent *)event
- (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]];

10
glfw/glfw3.h vendored
View file

@ -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.
*

3
glfw/init.c vendored
View file

@ -34,7 +34,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
// 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);

4
glfw/input.c vendored
View file

@ -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 //////

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 _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);

View file

@ -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;

View file

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

View file

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

3
glfw/wl_init.c vendored
View file

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

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 = 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 //////
//////////////////////////////////////////////////////////////////////////
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();

View file

@ -23,6 +23,7 @@
Iterable,
Iterator,
List,
Literal,
Optional,
Sequence,
Set,
@ -2934,7 +2935,7 @@ def discard_event(self) -> None:
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', '''

10
kitty/glfw-wrapper.h generated
View file

@ -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

View file

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

View file

@ -3275,8 +3275,8 @@
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`.
'''
)