Recently I started using the Sway window manager, with
occasional fallback to XFCE. Having both
mako and
xfce4-notifyd installed causes a
conflict over the org.freedesktop.Notifications
D-Bus service name (see Red
Hat Bug 484945). This post describes the
workaround I am currently using, until dynamic activation
directories or another
solution is implemented.
Background
The Desktop Notifications
Specification
defines a protocol that applications can use to generate popups to notify the
user of events. It requires a notification server to implement the
org.freedesktop.Notifications
service on the D-Bus session bus. The D-Bus
Specification
defines service activation based on information in service description files.
This mechanism is used by both xfce4-notifyd and mako use to start on demand.
However, this poses a problem. From Message Bus Starting Services
(Activation):
On the well-known session bus, if two .service files in the same directory offer the same service name, the result is undefined. Distributors should avoid this situation, for instance by naming session services’ .service files according to their service name.
On my system, the result is that xfce4-notifyd is always started, which provides a poor experience on Sway.
A Daemon Workaround
If all notification services are daemons (i.e. they only exit at the end of
the user session), an easy workaround is to avoid D-Bus Activation altogether
by starting whichever daemon is desired at the beginning of the user session.
This can be done from systemd units, Desktop
Autostart, or
traditional startup scripts (e.g. .xsessionrc
). My understanding is that
both GNOME and KDE notification services have moved to this approach.
Unfortunately, this approach forfeits the benefits of D-Bus activation, such as deferring the costs of running the notification service until/unless required and avoiding delay and contention at the start of the user session. It also doesn’t work for notification services like mako which exit after displaying a notification.
An Autostart Workaround
The next paragraph in the D-Bus Specification hints at a potential workaround:
If two .service files in different directories offer the same service name, the one in the higher-priority directory is used: for instance, on the system bus, .service files in /usr/local/share/dbus-1/system-services take precedence over those in /usr/share/dbus-1/system-services.
The service directories are defined by the dbus-daemon
configuration, as
described in
dbus-daemon(1), with
the standard session directories:
$XDG_RUNTIME_DIR/dbus-1/services
-
$XDG_DATA_HOME/dbus-1/services
(default~/.local/share
) -
$XDG_DATA_DIRS/dbus-1/services
for each directory in$XDG_DATA_DIRS
(default/usr/local/share:/usr/share
) -
${datadir}/dbus-1/services
compiled-in default (default/usr/share
)
This behavior can be used to implement a workaround by placing a service
definition file in $XDG_DATA_HOME/dbus-1/services
for a service which
activates the appropriate notification service for the current desktop
environment.
systemd Activation
The D-Bus Specification also defines systemd
Activation
for starting a service via systemd instead of executing a binary. Although
the specification does not describe the details, systemd activation in
bus/activation.c
is reasonably easy to follow: Send an ActivationRequest
signal to
org.freedesktop.systemd1.Activator
at path /org/freedesktop/DBus
on the
session bus with a string argument containing the service name to activate.
Implementation
To implement the workaround, create a service definition file named
~/.local/share/dbus-1/services/org.freedesktop.Notifications.service
with
the following content:
[D-BUS Service]
Name=org.freedesktop.Notifications
Exec=/home/username/.local/lib/notify-dispatch
Create an executable script named ~/.local/lib/notify-dispatch
which runs
the preferred notification service based on the environment:
#!/bin/sh
if [ "$XDG_SESSION_DESKTOP" = sway ]; then
exec /usr/bin/mako "$@"
fi
if [ "$XDG_SESSION_DESKTOP" = xfce ]; then
exec dbus-send --session \
--dest=org.freedesktop.systemd1 \
/org/freedesktop/DBus \
org.freedesktop.systemd1.Activator.ActivationRequest \
string:xfce4-notifyd.service
fi
echo "Error: No notification service for $XDG_SESSION_DESKTOP in $0." >&2
exit 1
Then log out and back in (or killall -HUP dbus-daemon
) to apply the changes.
To test, send a desktop notification (e.g. notify-send Test
).
Addendum: Environment Variables
The notify-dispatch
script inherits its environment from the D-Bus
activation environment. For $XDG_SESSION_DESKTOP
to be set,
dbus-update-activation-environment
must be called (with --all
or XDG_SESSION_DESKTOP=...
explicitly) after
the session bus is started, before a notification is sent. On Debian, this is
done by the Xsession script
/etc/X11/Xsession.d/95dbus_update-activation-env
(from the
dbus-x11
package). (Note:
Although, as its name implies, Xsession is a component of the X Window System,
some display managers also run Xsession when starting Wayland sessions.
LightDM is one example.)