Skip to content

Commit

Permalink
Merge pull request #19295 from ramezgerges/x11_dark_mode
Browse files Browse the repository at this point in the history
feat(linux): implement an ISystemThemeHelper based on the Settings portal
  • Loading branch information
ramezgerges authored Jan 23, 2025
2 parents f09c944 + f7f8103 commit e455335
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
109 changes: 109 additions & 0 deletions src/Uno.UI.Runtime.Skia.X11/LinuxSystemThemeHelper.cs
Original file line number Diff line number Diff line change
@@ -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($"Unable to observe the system theme. (Unable to determine the 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($"System theme detection is 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($"Unable to observe the system theme. (DBus Settings error, see https://aka.platform.uno/x11-dbus-troubleshoot for troubleshooting information)", e);
}
}
}
}
3 changes: 3 additions & 0 deletions src/Uno.UI.Runtime.Skia.X11/X11ApplicationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -68,6 +69,8 @@ static X11ApplicationHost()
ApiExtensibility.Register<DragDropManager>(typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), o => new X11DragDropExtension(o));

ApiExtensibility.Register<XamlRoot>(typeof(Uno.Graphics.INativeOpenGLWrapper), xamlRoot => new X11NativeOpenGLWrapper(xamlRoot));

ApiExtensibility.Register(typeof(ISystemThemeHelperExtension), xamlRoot => LinuxSystemThemeHelper.Instance);
}

public X11ApplicationHost(Func<Application> appBuilder, int renderFrameRate = 60)
Expand Down

0 comments on commit e455335

Please sign in to comment.