diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index f0df3985f..e73bf0a17 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -952,7 +952,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)viewDidChangeEffectiveAppearance { static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE; - GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme(); + GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme(true); if (new_appearance != appearance) { appearance = new_appearance; _glfwInputColorScheme(appearance, false); @@ -3091,7 +3091,8 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us [window->ns.object makeFirstResponder:window->ns.view]; }} -GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) { + (void)query_if_unintialized; int theme_type = 0; NSAppearance *changedAppearance = NSApp.effectiveAppearance; NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; diff --git a/glfw/dbus_glfw.c b/glfw/dbus_glfw.c index 7313bcc85..328fad359 100644 --- a/glfw/dbus_glfw.c +++ b/glfw/dbus_glfw.c @@ -234,12 +234,21 @@ method_reply_received(DBusPendingCall *pending, void *user_data) { } bool -call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data) { +call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data, bool block) { bool retval = false; #define REPORT(errs) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: node=%s path=%s interface=%s method=%s, with error: %s", dbus_message_get_destination(msg), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), errs) if (callback) { DBusPendingCall *pending = NULL; - if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) { + if (block) { + DBusError error; dbus_error_init(&error); + RAII_MSG(reply, dbus_connection_send_with_reply_and_block(session_bus, msg, timeout, &error)); + if (dbus_error_is_set(&error)) { + callback(reply, error.message, user_data); + return false; + } else if (reply) { + callback(reply, NULL, user_data); + } else return false; + } else if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) { MethodResponse *res = malloc(sizeof(MethodResponse)); if (!res) return false; res->callback = callback; @@ -261,7 +270,7 @@ call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_p } static bool -call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void *user_data, va_list ap) { +call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void *user_data, bool blocking, va_list ap) { if (!conn || !path) return false; RAII_MSG(msg, dbus_message_new_method_call(node, path, interface, method)); if (!msg) return false; @@ -269,7 +278,7 @@ call_method(DBusConnection *conn, const char *node, const char *path, const char int firstarg = va_arg(ap, int); if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) { - retval = call_method_with_msg(conn, msg, timeout, callback, user_data); + retval = call_method_with_msg(conn, msg, timeout, callback, user_data, blocking); } else { _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s could not add arguments", method, node, interface); } @@ -282,7 +291,17 @@ glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const c bool retval; va_list ap; va_start(ap, user_data); - retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, ap); + retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, false, ap); + va_end(ap); + return retval; +} + +bool +glfw_dbus_call_blocking_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void* user_data, ...) { + bool retval; + va_list ap; + va_start(ap, user_data); + retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, true, ap); va_end(ap); return retval; } @@ -292,7 +311,7 @@ glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const cha bool retval; va_list ap; va_start(ap, method); - retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, ap); + retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, false, ap); va_end(ap); return retval; } diff --git a/glfw/dbus_glfw.h b/glfw/dbus_glfw.h index a491778a6..58eff276e 100644 --- a/glfw/dbus_glfw.h +++ b/glfw/dbus_glfw.h @@ -45,11 +45,13 @@ void glfw_dbus_terminate(_GLFWDBUSData *dbus); DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg, const char* name, bool register_on_bus); void glfw_dbus_close_connection(DBusConnection *conn); bool -call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data); +call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data, bool block); bool glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...); bool glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout_ms, dbus_pending_callback callback, void *user_data, ...); +bool +glfw_dbus_call_blocking_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void* user_data, ...); void glfw_dbus_dispatch(DBusConnection *); void glfw_dbus_session_bus_dispatch(void); bool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...); diff --git a/glfw/glfw3.h b/glfw/glfw3.h index f4c30218c..446032b6e 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -3982,7 +3982,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 GLFWColorScheme glfwGetCurrentSystemColorTheme(void); +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized); /*! @brief Sets the refresh callback for the specified window. * diff --git a/glfw/linux_desktop_settings.c b/glfw/linux_desktop_settings.c index bfa6bbe8c..de52f40df 100644 --- a/glfw/linux_desktop_settings.c +++ b/glfw/linux_desktop_settings.c @@ -22,12 +22,7 @@ static const char* supported_namespaces[2] = {FDO_DESKTOP_NAMESPACE, GNOME_DESKT static char theme_name[128] = {0}; static int theme_size = -1; static GLFWColorScheme appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE; -static bool cursor_theme_changed = false; - -GLFWColorScheme -glfw_current_system_color_theme(void) { - return appearance; -} +static bool cursor_theme_changed = false, appearance_initialized = false; #define HANDLER(name) static void name(DBusMessage *msg, const char* errmsg, void *data) { \ (void)data; \ @@ -36,6 +31,34 @@ glfw_current_system_color_theme(void) { return; \ } + +HANDLER(get_color_scheme) + uint32_t val; + DBusMessageIter iter, variant_iter; + if (!dbus_message_iter_init(msg, &iter)) return; + dbus_message_iter_recurse(&iter, &variant_iter); + int type = dbus_message_iter_get_arg_type(&variant_iter); + if (type != DBUS_TYPE_UINT32) { + _glfwInputError(GLFW_PLATFORM_ERROR, "ReadOne for color-scheme did not return a uint32"); return; + } + dbus_message_iter_get_basic(&variant_iter, &val); + if (val < 3) appearance = val; +} + +GLFWColorScheme +glfw_current_system_color_theme(bool query_if_unintialized) { + if (!appearance_initialized && query_if_unintialized) { + appearance_initialized = true; + DBusConnection *session_bus = glfw_dbus_session_bus(); + if (session_bus) { + const char *namespace = FDO_DESKTOP_NAMESPACE, *key = FDO_APPEARANCE_KEY; + glfw_dbus_call_blocking_method(session_bus, DESKTOP_SERVICE, DESKTOP_PATH, DESKTOP_INTERFACE, "ReadOne", DBUS_TIMEOUT_USE_DEFAULT, + get_color_scheme, NULL, DBUS_TYPE_STRING, &namespace, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID); + } + } + return appearance; +} + static void process_fdo_setting(const char *key, DBusMessageIter *value) { if (strcmp(key, FDO_APPEARANCE_KEY) == 0) { @@ -43,8 +66,13 @@ process_fdo_setting(const char *key, DBusMessageIter *value) { uint32_t val; dbus_message_iter_get_basic(value, &val); if (val > 2) val = 0; - appearance = val; - _glfwInputColorScheme(appearance, true); + if (!appearance_initialized) { + appearance_initialized = true; + if (val != appearance) { + appearance = val; + _glfwInputColorScheme(appearance, true); + } + } } } } @@ -131,7 +159,7 @@ read_desktop_settings(DBusConnection *session_bus) { if (!dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &supported_namespaces[i])) return false; } if (!dbus_message_iter_close_container(&iter, &array_iter)) { return false; } - return call_method_with_msg(session_bus, msg, DBUS_TIMEOUT_USE_DEFAULT, process_desktop_settings, NULL); + return call_method_with_msg(session_bus, msg, DBUS_TIMEOUT_USE_DEFAULT, process_desktop_settings, NULL, false); } void @@ -166,6 +194,7 @@ on_color_scheme_change(DBusMessage *message) { if (val > 2) val = 0; if (val != appearance) { appearance = val; + appearance_initialized = true; _glfwInputColorScheme(appearance, false); } } diff --git a/glfw/linux_desktop_settings.h b/glfw/linux_desktop_settings.h index de260ec29..de8cb8a8f 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); -GLFWColorScheme glfw_current_system_color_theme(void); +GLFWColorScheme glfw_current_system_color_theme(bool); diff --git a/glfw/linux_notify.c b/glfw/linux_notify.c index 617058473..f0ef298f6 100644 --- a/glfw/linux_notify.c +++ b/glfw/linux_notify.c @@ -184,7 +184,7 @@ glfw_dbus_send_user_notification(const GLFWDBUSNotificationData *n, GLFWDBusnoti APPEND(args, DBUS_TYPE_INT32, n->timeout) #undef check_call #undef APPEND - if (!call_method_with_msg(session_bus, msg, 5000, notification_created, data)) return 0; + if (!call_method_with_msg(session_bus, msg, 5000, notification_created, data, false)) return 0; notification_id_type ans = data->next_id; data = NULL; return ans; diff --git a/glfw/wl_client_side_decorations.c b/glfw/wl_client_side_decorations.c index bef02b2b6..6690c5b4d 100644 --- a/glfw/wl_client_side_decorations.c +++ b/glfw/wl_client_side_decorations.c @@ -332,7 +332,7 @@ render_title_bar(_GLFWwindow *window, bool to_front_buffer) { const uint32_t dark_fg = is_focused ? 0xffffffff : 0xffcccccc, dark_bg = is_focused ? 0xff303030 : 0xff242424; static const uint32_t hover_dark_bg = 0xff444444, hover_light_bg = 0xffbbbbbb; uint32_t bg_color = light_bg, fg_color = light_fg, hover_bg = hover_light_bg; - GLFWColorScheme appearance = glfwGetCurrentSystemColorTheme(); + GLFWColorScheme appearance = glfwGetCurrentSystemColorTheme(false); bool is_dark = false; if (decs.use_custom_titlebar_color || appearance == GLFW_COLOR_SCHEME_NO_PREFERENCE) { bg_color = 0xff000000 | (decs.titlebar_color & 0xffffff); diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 56df744c7..4a0202aa4 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -636,8 +636,8 @@ static const struct wl_registry_listener registryListener = { }; -GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { - return glfw_current_system_color_theme(); +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) { + return glfw_current_system_color_theme(query_if_unintialized); } static pid_t diff --git a/glfw/x11_init.c b/glfw/x11_init.c index cbf47c598..219ef61ab 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -615,8 +615,8 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) { - return GLFW_COLOR_SCHEME_NO_PREFERENCE; +GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) { + return glfw_current_system_color_theme(query_if_unintialized); } void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { } diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index fb8b261f7..acb4cb126 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -1711,6 +1711,7 @@ def opengl_version_string() -> str: ... def systemd_move_pid_into_new_scope(pid: int, scope_name: str, description: str) -> str: ... def play_desktop_sound_async(name: str, event_id: str = 'test sound', is_path: bool = False, theme_name: str = '') -> str: ... def cocoa_play_system_sound_by_id_async(sound_id: int) -> None: ... +def glfw_get_system_color_theme(query_if_unintialized: bool = True) -> Literal['light', 'dark', 'no_preference']: ... class MousePosition(TypedDict): cell_x: int diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 94bc7ef28..dfc38b6a8 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -2010,7 +2010,7 @@ typedef GLFWsystemcolorthemechangefun (*glfwSetSystemColorThemeChangeCallback_fu GFW_EXTERN glfwSetSystemColorThemeChangeCallback_func glfwSetSystemColorThemeChangeCallback_impl; #define glfwSetSystemColorThemeChangeCallback glfwSetSystemColorThemeChangeCallback_impl -typedef GLFWColorScheme (*glfwGetCurrentSystemColorTheme_func)(void); +typedef GLFWColorScheme (*glfwGetCurrentSystemColorTheme_func)(bool); GFW_EXTERN glfwGetCurrentSystemColorTheme_func glfwGetCurrentSystemColorTheme_impl; #define glfwGetCurrentSystemColorTheme glfwGetCurrentSystemColorTheme_impl diff --git a/kitty/glfw.c b/kitty/glfw.c index 21ead3f1a..01911e630 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -46,14 +46,20 @@ get_platform_dependent_config_values(void *glfw_window) { } } -static void -on_system_color_scheme_change(GLFWColorScheme appearance, bool is_initial_value) { +static const char* +appearance_name(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; } + return which; +} + +static void +on_system_color_scheme_change(GLFWColorScheme appearance, bool is_initial_value) { + const char *which = appearance_name(appearance); debug("system color-scheme changed to: %s is_initial_value: %d\n", which, is_initial_value); call_boss(on_system_color_scheme_change, "sO", which, is_initial_value ? Py_True : Py_False); } @@ -1519,6 +1525,17 @@ glfw_get_physical_dpi(PYNOARG) { return get_physical_dpi(m); } +static PyObject* +glfw_get_system_color_theme(PyObject UNUSED *self, PyObject *args) { + int query_if_unintialized = 1; + if (!PyArg_ParseTuple(args, "|p", &query_if_unintialized)) return NULL; + if (!glfwGetCurrentSystemColorTheme) { + PyErr_SetString(PyExc_RuntimeError, "must initialize GFLW before calling this function"); return NULL; + } + const char *which = appearance_name(glfwGetCurrentSystemColorTheme(query_if_unintialized)); + return PyUnicode_FromString(which); +} + static PyObject* glfw_get_key_name(PyObject UNUSED *self, PyObject *args) { int key, native_key; @@ -2306,6 +2323,7 @@ static PyMethodDef module_methods[] = { {"glfw_terminate", (PyCFunction)glfw_terminate, METH_NOARGS, ""}, {"glfw_get_physical_dpi", (PyCFunction)glfw_get_physical_dpi, METH_NOARGS, ""}, {"glfw_get_key_name", (PyCFunction)glfw_get_key_name, METH_VARARGS, ""}, + {"glfw_get_system_color_theme", (PyCFunction)glfw_get_system_color_theme, METH_VARARGS, ""}, {"glfw_primary_monitor_size", (PyCFunction)primary_monitor_size, METH_NOARGS, ""}, {"glfw_primary_monitor_content_scale", (PyCFunction)primary_monitor_content_scale, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} /* Sentinel */