This is an experiment in creating a versatile tool for launching any standalone Wayland WM with environment management and systemd integration.
WIP. Use at your onw risk.
- WM-specific behavior is handled by plugins
- currently supported: sway, wayfire, labwc
- Two (and a half) modes of operation:
- Starting a service
- Running from shell (with two choices of scopes)
- Maximum use of systemd units and dependencies for startup, operation, and shutdown
- Systemd units are treated with hierarchy and universality in mind:
- use specifiers
- named from common to specific:
wayland-${category}@${wm}.${unit_type}
- allow for high-level
name-.d
drop-ins
- Idempotently (well, best-effort-idempotently) handle environment:
- On startup environment is prepared by:
- sourcing shell profile
- sourcing common
wayland-session-env
files (from $XDG_CONFIG_DIRS, $XDG_CONFIG_HOME) - sourcing
${wm}/env
files (from $XDG_CONFIG_DIRS, $XDG_CONFIG_HOME)
- Difference between inital state and prepared environment is exported into systemd user manager
- Special variables are imported back from systemd user manager at various stages of startup (in shell mode)
- On shutdown variables that were exported are unset from systemd user manager
- Lists of variables for export import-back and cleanup are determined algorithmically by:
- comparing environment before and after preparation procedures
- boolean operations with predefined lists (tweakable by plugins)
- On startup environment is prepared by:
- Better control of XDG autostart apps:
- Propagate Stop from xdg-desktop-autostart.target via a drop-in
- Try best to shutdown session cleanly via more dependencies between units
- Written in POSIX shell (a smidgen of masochism went into this code)
Put wayland-session
script somewhere in $PATH
.
Put wayland-session-plugins
dir somewhere in /lib:/usr/lib:/usr/local/lib:${HOME}/.local/lib
Ensure your WM does this sequentially upon startup:
- exports
WAYLAND_DISPLAY
to systemd user manager - runs
systemd-notify --ready
after that
Example snippet for sway:
exec dbus-update-activation-environment --systemd \
SWAYSOCK \
DISPLAY \
I3SOCK \
WAYLAND_DISPLAY \
XCURSOR_SIZE \
XCURSOR_THEME \
&& systemctl --user import-environment \
SWAYSOCK \
DISPLAY \
I3SOCK \
WAYLAND_DISPLAY \
XCURSOR_SIZE \
XCURSOR_THEME \
&& systemd-notify --ready
Start with wayland-session ${wm} sd-start
Stop with either wayland-session ${wm} sd-stop
or systemctl --user stop "wayland-wm@*.service"
(At least for now) Units are generated by the script (and plugins).
Run wayland-session ${wm} unitgen
to populate ${XDG_RUNTIME_DIR}
with them.
After that: systemctl --user start wayland-wm@${wm}.service
to start WM.
Add --wait
to hold terminal until session ends.
exec
it from login shell to bind to login session:
exec systemctl --user start --wait wayland-wm@${wm}.service
Then to stop: systemctl --user stop "wayland-wm@*.service"
(no need to specify WM here).
If start command was run with exec
, (i.e. from login shell on a tty or via .profile
),
this stop command also doubles as a logout command.
wayland-session
is smart enough to find login session associated with current TTY
and export (and later cleanup) $XDG_SESSION_ID
, $XDG_VTNR
to user manager environment.
Even though when started as a service it does not have those vars at immediate disposal.
(I really do not know it this is a good idea, but since there can be only one graphical session
per user with systemd, seems like such).
This example starts sway wayland session automatically upon login on tty1 if system is in graphical.target
Short snippet for ~/.profile
:
if [ "${0}" != "${0#-}" -a "$XDG_VTNR" = "1" ]
then
exec wayland-session sway sd-start
fi
Extended snippet for ~/.profile
:
WM=sway
if [ "${0}" != "${0#-}" -a "$XDG_VTNR" = "1" ] \
&& systemctl is-active -q graphical.target \
&& ! systemctl --user is-active -q wayland-wm@*.service
then
wayland-session ${WM} unitgen
echo Starting ${WM} WM
exec systemctl --user start --wait wayland-wm@${WM}.service
fi
Pros:
- Everything happens automagcally, maximum usage of systemd features
Cons:
- Pro#1 can be a con depending on your philosophy. I honestly understand both sides of this.
- (Probably counts as such) WM and its descendants are not a part of login session.
If recommended way of starting graphical session is to exec
systemctl --user start --wait ...
then this command will be the sole occupant of login session apart from/bin/login
.
In this mode WM is launched directly from the script, and the script manages startup, targets, and eventual cleanup.
wayland-session $wm shell-start
to start WM, In this mode WM is put into
diretly-descendant scope with logging to jouranl
(unit: wayland-wm-${WM}.scope
, log identifier: wayland-wm-${WM}
)
wayland-session $wm shell-intstart
also reexec the script itself with
logging to journald (log identifier: wayland-session-${WM}
)
To stop wm either run wayland-sesion $wm shell-stop
or just kill already running script instance.
Pros:
- (probably counts as such) WM and its descendants are a direct part of login session.
Cons:
- This mode is kinda semi-abandoned ATM.
Plugins provide WM support and associated functions. See wayland-session-plugins/*.sh.in
for examples.
- more plugins
- invent a better way to stop xdg-desktop-portal-gtk.service on WM stop
- maybe drop shell mode altogether
Inspired by and adapted some techniques from: