From 12867f4fc023c55b9c675eae339873c6bcfa8557 Mon Sep 17 00:00:00 2001 From: Ramez Ragaa Date: Wed, 22 Jan 2025 18:55:52 +0200 Subject: [PATCH 1/4] feat(linux): implement an ISystemThemeHelper based on the Settings portal --- .../LinuxSystemThemeHelper.cs | 109 ++++++++++++++++++ .../X11ApplicationHost.cs | 3 + 2 files changed, 112 insertions(+) create mode 100644 src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs diff --git a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs new file mode 100644 index 000000000000..2301a191f586 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs @@ -0,0 +1,109 @@ +using System; +using System.Threading.Tasks; +using Tmds.DBus.Protocol; +using Uno.Foundation.Logging; +using Uno.Helpers.Theming; +using Uno.UI.Dispatching; +using Uno.WinUI.Runtime.Skia.X11.DBus; + +namespace Uno.WinUI.Runtime.Skia.X11; + +// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html + +internal class LinuxSystemThemeHelper : ISystemThemeHelperExtension +{ + private const string Service = "org.freedesktop.portal.Desktop"; + private const string ObjectPath = "/org/freedesktop/portal/desktop"; + + public event EventHandler? SystemThemeChanged; + + private SystemTheme _currentTheme = SystemTheme.Light; + private SystemTheme CurrentTheme + { + get => _currentTheme; + set + { + if (NativeDispatcher.Main.HasThreadAccess) + { + if (_currentTheme != value) + { + _currentTheme = value; + SystemThemeChanged?.Invoke(this, EventArgs.Empty); + } + } + else + { + NativeDispatcher.Main.Enqueue(() => CurrentTheme = value); + } + } + } + + public SystemTheme GetSystemTheme() => CurrentTheme; + + public static LinuxSystemThemeHelper Instance { get; } = new(); + + private LinuxSystemThemeHelper() + { + _ = Init().ConfigureAwait(false); + } + + public async Task Init() + { + try + { + var sessionsAddressBus = Address.Session; + if (sessionsAddressBus is null) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"Can not determine DBus session bus address"); + } + return; + } + + var connection = new Connection(sessionsAddressBus); + await connection.ConnectAsync(); + + var desktopService = new DesktopService(connection, Service); + var settings = desktopService.CreateSettings(ObjectPath); + + var version = await settings.GetVersionAsync(); + if (version != 2) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"File pickers are only implemented for version 2 of the Settings portal, but version {version} was found"); + } + return; + } + + var result = await settings.ReadOneAsync("org.freedesktop.appearance", "color-scheme"); + CurrentTheme = result.GetUInt32() == 1 ? SystemTheme.Dark : SystemTheme.Light; + + // ignoring IDisposable return value here since we're watching for the lifetime of the app + await settings.WatchSettingChangedAsync((exception, tuple) => + { + if (exception is not null) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"{nameof(settings.WatchSettingChangedAsync)} threw an exception", exception); + } + return; + } + + if (tuple is { Namespace: "org.freedesktop.appearance", Key: "color-scheme" }) + { + CurrentTheme = tuple.Value.GetUInt32() == 1 ? SystemTheme.Dark : SystemTheme.Light; + } + }); + } + catch (Exception e) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"DBus Settings error, see https://aka.platform.uno/x11-dbus-troubleshoot for troubleshooting information.", e); + } + } + } +} diff --git a/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs b/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs index a7a878784d02..0ee0933cb619 100644 --- a/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs +++ b/src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs @@ -17,6 +17,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices.Marshalling; using Microsoft.UI.Xaml.Controls; +using Uno.Helpers.Theming; namespace Uno.WinUI.Runtime.Skia.X11; @@ -68,6 +69,8 @@ static X11ApplicationHost() ApiExtensibility.Register(typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), o => new X11DragDropExtension(o)); ApiExtensibility.Register(typeof(Uno.Graphics.INativeOpenGLWrapper), xamlRoot => new X11NativeOpenGLWrapper(xamlRoot)); + + ApiExtensibility.Register(typeof(ISystemThemeHelperExtension), xamlRoot => LinuxSystemThemeHelper.Instance); } public X11ApplicationHost(Func appBuilder, int renderFrameRate = 60) From 03df24f6bb2670320fdb328de4cb183ada490255 Mon Sep 17 00:00:00 2001 From: Ramez Ragaa <66218781+ramezgerges@users.noreply.github.com> Date: Thu, 23 Jan 2025 00:47:27 +0200 Subject: [PATCH 2/4] chore: reword log message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérôme Laban --- src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs index 2301a191f586..2ca27ac84196 100644 --- a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs +++ b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs @@ -56,7 +56,7 @@ public async Task Init() { if (this.Log().IsEnabled(LogLevel.Error)) { - this.Log().Error($"Can not determine DBus session bus address"); + this.Log().Error($"Unable to observe the system theme. (Unable to determine the DBus session bus address)"); } return; } From 2a56222993170ea2231c6fda1f34dca6795aaa1c Mon Sep 17 00:00:00 2001 From: Ramez Ragaa <66218781+ramezgerges@users.noreply.github.com> Date: Thu, 23 Jan 2025 00:48:02 +0200 Subject: [PATCH 3/4] chore: reword log message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jérôme Laban --- src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs index 2ca27ac84196..e7d25237b00c 100644 --- a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs +++ b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs @@ -102,7 +102,7 @@ await settings.WatchSettingChangedAsync((exception, tuple) => { if (this.Log().IsEnabled(LogLevel.Error)) { - this.Log().Error($"DBus Settings error, see https://aka.platform.uno/x11-dbus-troubleshoot for troubleshooting information.", e); + this.Log().Error($"Unable to observe the system theme. (DBus Settings error, see https://aka.platform.uno/x11-dbus-troubleshoot for troubleshooting information)", e); } } } From f7f8103d3c5ce5b47ca0a0402a32b104bd609909 Mon Sep 17 00:00:00 2001 From: Ramez Ragaa Date: Thu, 23 Jan 2025 00:49:45 +0200 Subject: [PATCH 4/4] chore: reword log message --- src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs index e7d25237b00c..76324bce05cd 100644 --- a/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs +++ b/src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs @@ -72,7 +72,7 @@ public async Task Init() { if (this.Log().IsEnabled(LogLevel.Error)) { - this.Log().Error($"File pickers are only implemented for version 2 of the Settings portal, but version {version} was found"); + this.Log().Error($"System theme detection is only implemented for version 2 of the Settings portal, but version {version} was found"); } return; }