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;