Browse Source

[DisplayServer] Implement `get_accent_color` on Linux.

Pāvels Nadtočajevs 5 months ago
parent
commit
18f6c33d72

+ 1 - 1
doc/classes/DisplayServer.xml

@@ -195,7 +195,7 @@
 			<return type="Color" />
 			<description>
 				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).
 			</description>
 		</method>
 		<method name="get_base_color" qualifiers="const">

+ 54 - 9
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<Color *>(r_value)->r = value;
+			} else if (idx == 1) {
+				static_cast<Color *>(r_value)->g = value;
+			} else if (idx == 2) {
+				static_cast<Color *>(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();
 						}
 					}

+ 8 - 2
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<Dictionary> &p_options, HashMap<String, String> &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;
 	}

+ 4 - 0
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);
 }

+ 1 - 0
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<String> &p_filters, const Callable &p_callback, WindowID p_window_id) override;

+ 4 - 0
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);
 }

+ 1 - 0
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<String> &p_filters, const Callable &p_callback, WindowID p_window_id) override;