Since early 2022, darkman supports exposing the dark mode / light mode
preference via the appropriate xdg-desktop-portal
API. While this works quite
well, it’s been a constant source of questions, since setting it up and actually
understanding how it works is far from trivial.
The xdg-desktop-portal
is a kitchen-sink service1, which
implements dozens of unrelated functionalities mashed together. Some of these
features are implemented directly in the portal, while others are delegated to
portal implementations.
One of the features implemented by the xdg-desktop-portal
is the settings
interface. This interface exposes settings to local user applications. Amongst
a few other values, it exposes a color-scheme
preference, which can be either
dark mode, light mode, or “no preference”.
However, the xdg-desktop-portal
itself isn’t the source of this information;
it queries portal implementations for the correct value. Which portal
implementation it uses requires careful configuration, and this is the main
source of confusion.
There are several ways to configure which portal implementation is used.
Configuration files can exist in system-wide locations, or user-specific
locations. I’ll only cover user-specific locations here; if you need to
configure something system-wide for multiple users, consult man 5 portals.conf
for additional details.
Depending on the filename given to the configuration file, it will apply only to
specific desktop environments (e.g.: kde-portals.conf
would only apply on KDE)
or apply to any environment (e.g.: portals.conf
will be used by default on any
desktop environment unless a desktop-specific configuration is found)
I prefer using portals.conf
, since my user account always runs sway and I
don’t need per-DE functionality for it. If you use your same user account with
different compositors or DEs, you’ll need to take the other approach.
A single configuration file
The most straightforward location for a user configuration is
~/.config/xdg-desktop-portal/portals.conf
, which overrides other directories.
To use darkman
as a source for settings (which results in its dark / light
mode value being exposed), the following configuration would suffice:
[preferred]
org.freedesktop.impl.portal.Settings=darkman
In my case, I also configure the xdg-desktop-portal
to use xdp-wlr
for
screen casting (this in turn is used by Firefox). My real configuration file
currently looks like this:
[preferred]
org.freedesktop.impl.portal.ScreenCast=wlr
org.freedesktop.impl.portal.Settings=darkman
If you are using a distribution with a pre-configured desktop environment, when you create a configuration file it will completely override the system-wide configuration. You may need to copy-paste any lines from the system-wide configuration file into your own to retain existing integrations.
Per-DE configuration files
I mentioned before that it is possible to create per-DE configuration files.
For example, if you need to support both sway and KDE, you’ll need two configuration files2:
~/.config/xdg-desktop-portal/sway-portals.conf
~/.config/xdg-desktop-portal/kde-portals.conf
Creating the files alone isn’t enough: the xdg-desktop-portal
needs to know
which desktop you are currently running. This is configured via the
XDG_CURRENT_DESKTOP
environment variable, which must be set for the
xdg-desktop-portal
process itself. If you are using a service manager, you
need to inject this variable into the environment that it creates for services.
If you are starting the service manually, you can just export it with the usual
mechanisms.
For the above two example, this variable should be defined as
XDG_CURRENT_DESKTOP=sway
or XDG_CURRENT_DESKTOP=kde
respectively.
Darkman and XDG_CURRENT_DESKTOP
Darkman doesn’t care about the value of XDG_CURRENT_DESKTOP
. It will expose
its portal implementation bus in org.freedesktop.impl.portal.desktop.darkman
.
When the xdg-desktop-portal
is configured with
org.freedesktop.impl.portal.Settings=darkman
, it will query darkman’s bus for
settings.
Darkman will only respond to queries for the color-scheme
preference.
Start-up order
The XDG_CURRENT_DESKTOP
variable needs to be defined in the execution
environment of xdg-desktop-portal
. If it starts during early session
initialisation, ensure that the ordering is as expected.
The xdg-desktop-portal
will try to communicate with configured portal
implementations (e.g.: darkman) as soon as it starts.
When dbus-daemon
is configured to auto-start services (this is the default),
then it will start darkman immediately.
If you are using a service manager to start these service, you should consider
darkman a dependency of xdg-desktop-portal
. In this case, darkman must start
and be ready before the xdg-desktop-portal
starts.
I find the general design of the xdg-desktop-portal quite poor. It’s the far opposite of “do one thing and do it well”; it does dozens of things in highly opinionated ways, and is quite coupled with several other systems. ↩︎
Keep in mind that other locations are searched if these do not exist. Again, see
man 5 portals.conf
for full details. ↩︎