From 18f6c33d72ae10766cf7c049545524ced5e3f3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Thu, 13 Mar 2025 23:18:22 +0200 Subject: [PATCH] [DisplayServer] Implement `get_accent_color` on Linux. --- doc/classes/DisplayServer.xml | 2 +- .../linuxbsd/freedesktop_portal_desktop.cpp | 63 ++++++++++++++++--- .../linuxbsd/freedesktop_portal_desktop.h | 10 ++- .../wayland/display_server_wayland.cpp | 4 ++ .../linuxbsd/wayland/display_server_wayland.h | 1 + platform/linuxbsd/x11/display_server_x11.cpp | 4 ++ platform/linuxbsd/x11/display_server_x11.h | 1 + 7 files changed, 73 insertions(+), 12 deletions(-) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 179a969faa..4df3d9c314 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -195,7 +195,7 @@ Returns OS theme accent color. Returns [code]Color(0, 0, 0, 0)[/code], if accent color is unknown. - [b]Note:[/b] This method is implemented on macOS, Windows, and Android. + [b]Note:[/b] This method is implemented on macOS, Windows, Android, and Linux (X11/Wayland). diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index dfac5e3776..85778d7347 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -53,7 +53,7 @@ #define BUS_INTERFACE_SETTINGS "org.freedesktop.portal.Settings" #define BUS_INTERFACE_FILE_CHOOSER "org.freedesktop.portal.FileChooser" -bool FreeDesktopPortalDesktop::try_parse_variant(DBusMessage *p_reply_message, int p_type, void *r_value) { +bool FreeDesktopPortalDesktop::try_parse_variant(DBusMessage *p_reply_message, ReadVariantType p_type, void *r_value) { DBusMessageIter iter[3]; dbus_message_iter_init(p_reply_message, &iter[0]); @@ -67,15 +67,44 @@ bool FreeDesktopPortalDesktop::try_parse_variant(DBusMessage *p_reply_message, i } dbus_message_iter_recurse(&iter[1], &iter[2]); - if (dbus_message_iter_get_arg_type(&iter[2]) != p_type) { - return false; + if (p_type == VAR_TYPE_COLOR) { + if (dbus_message_iter_get_arg_type(&iter[2]) != DBUS_TYPE_STRUCT) { + return false; + } + DBusMessageIter struct_iter; + dbus_message_iter_recurse(&iter[2], &struct_iter); + int idx = 0; + while (dbus_message_iter_get_arg_type(&struct_iter) == DBUS_TYPE_DOUBLE) { + double value = 0.0; + dbus_message_iter_get_basic(&struct_iter, &value); + if (value < 0.0 || value > 1.0) { + return false; + } + if (idx == 0) { + static_cast(r_value)->r = value; + } else if (idx == 1) { + static_cast(r_value)->g = value; + } else if (idx == 2) { + static_cast(r_value)->b = value; + } + idx++; + if (!dbus_message_iter_next(&struct_iter)) { + break; + } + } + if (idx != 3) { + return false; + } + } else if (p_type == VAR_TYPE_UINT32) { + if (dbus_message_iter_get_arg_type(&iter[2]) != DBUS_TYPE_UINT32) { + return false; + } + dbus_message_iter_get_basic(&iter[2], r_value); } - - dbus_message_iter_get_basic(&iter[2], r_value); return true; } -bool FreeDesktopPortalDesktop::read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value) { +bool FreeDesktopPortalDesktop::read_setting(const char *p_namespace, const char *p_key, ReadVariantType p_type, void *r_value) { if (unsupported) { return false; } @@ -127,8 +156,24 @@ uint32_t FreeDesktopPortalDesktop::get_appearance_color_scheme() { } uint32_t value = 0; - read_setting("org.freedesktop.appearance", "color-scheme", DBUS_TYPE_UINT32, &value); - return value; + if (read_setting("org.freedesktop.appearance", "color-scheme", VAR_TYPE_UINT32, &value)) { + return value; + } else { + return 0; + } +} + +Color FreeDesktopPortalDesktop::get_appearance_accent_color() { + if (unsupported) { + return Color(0, 0, 0, 0); + } + + Color value; + if (read_setting("org.freedesktop.appearance", "accent-color", VAR_TYPE_COLOR, &value)) { + return value; + } else { + return Color(0, 0, 0, 0); + } } static const char *cs_empty = ""; @@ -639,7 +684,7 @@ void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) { dbus_message_iter_get_basic(&iter, &value); String key = String::utf8(value); - if (name_space == "org.freedesktop.appearance" && key == "color-scheme") { + if (name_space == "org.freedesktop.appearance" && (key == "color-scheme" || key == "accent-color")) { callable_mp(portal, &FreeDesktopPortalDesktop::_system_theme_changed_callback).call_deferred(); } } diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h index edcc07ce79..8d42c159ef 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.h +++ b/platform/linuxbsd/freedesktop_portal_desktop.h @@ -44,9 +44,14 @@ class FreeDesktopPortalDesktop : public Object { private: bool unsupported = false; - static bool try_parse_variant(DBusMessage *p_reply_message, int p_type, void *r_value); + enum ReadVariantType { + VAR_TYPE_UINT32, // u + VAR_TYPE_COLOR, // (ddd) + }; + + static bool try_parse_variant(DBusMessage *p_reply_message, ReadVariantType p_type, void *r_value); // Read a setting from org.freekdesktop.portal.Settings - bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value); + bool read_setting(const char *p_namespace, const char *p_key, ReadVariantType p_type, void *r_value); static void append_dbus_string(DBusMessageIter *p_iter, const String &p_string); static void append_dbus_dict_options(DBusMessageIter *p_iter, const TypedArray &p_options, HashMap &r_ids); @@ -108,6 +113,7 @@ public: // 1: Prefer dark appearance. // 2: Prefer light appearance. uint32_t get_appearance_color_scheme(); + Color get_appearance_accent_color(); void set_system_theme_change_callback(const Callable &p_system_theme_changed) { system_theme_changed = p_system_theme_changed; } diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 4fed8e8096..8718463ae7 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -302,6 +302,10 @@ bool DisplayServerWayland::is_dark_mode() const { } } +Color DisplayServerWayland::get_accent_color() const { + return portal_desktop->get_appearance_accent_color(); +} + void DisplayServerWayland::set_system_theme_change_callback(const Callable &p_callable) { portal_desktop->set_system_theme_change_callback(p_callable); } diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index 22af7534ec..6b662a8991 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -184,6 +184,7 @@ public: #ifdef DBUS_ENABLED virtual bool is_dark_mode_supported() const override; virtual bool is_dark_mode() const override; + virtual Color get_accent_color() const override; virtual void set_system_theme_change_callback(const Callable &p_callable) override; virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const Callable &p_callback, WindowID p_window_id) override; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 553e4df2bd..011ec6fe60 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -398,6 +398,10 @@ bool DisplayServerX11::is_dark_mode() const { } } +Color DisplayServerX11::get_accent_color() const { + return portal_desktop->get_appearance_accent_color(); +} + void DisplayServerX11::set_system_theme_change_callback(const Callable &p_callable) { portal_desktop->set_system_theme_change_callback(p_callable); } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index ea63d22b84..244c6acbb5 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -419,6 +419,7 @@ public: #if defined(DBUS_ENABLED) virtual bool is_dark_mode_supported() const override; virtual bool is_dark_mode() const override; + virtual Color get_accent_color() const override; virtual void set_system_theme_change_callback(const Callable &p_callable) override; virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const Callable &p_callback, WindowID p_window_id) override;