UWSM(1) General Commands Manual UWSM(1)

UWSM - Universal Wayland Session Manager.

uwsm [-h] {subcommand} [options ...]

Launches arbitrary wayland compositor via a set of systemd user units to provide graphical user session with environment management, XDG autostart support, clean shutdown. Provides helpers for launching applications as scopes or services.

select Select default compositor Entry.
start Start compositor and graphical session.
finalize Send compositor-set variables and unit startup notification to systemd user manager.
stop Stop graphical session and compositor.
app Application unit launcher (with Desktop Entry support).
check Perform state checks (for scripting and info).
aux Technical functions for use inside units.

See corresponding SUBCOMMANDS subsections below for further info.

Help for each subcommand is accessible by running "uwsm {subcommand} -h".

In XDG config hierarchy:

uwsm/env
uwsm/env-${compositor} Environment (shell) to be sourced for the graphical session. Sourced from directories of increasing priority, in each directory common file is sourced first, then suffixed files in the order of items listed in XDG_CURRENT_SESSION var (lowercased).
uwsm/default-id Stores Desktop Entry ID of default compositor.

Fallback is also extended into the system part of XDG data hierarchy, this can be used for distro level defaults.

UWSM_USE_SESSION_SLICE (true|false)
Put compositor unit in session.slice
UWSM_FINALIZE_VARNAMES (whitespace-separated names of env vars)
Additional variables for "uwsm finalize"
UWSM_WAIT_VARNAMES (whitespace-separated names of env vars)
Variables to wait for in activation environemnt before proceeding to graphical session (in addition to WAYLAND_DISPLAY)
UWSM_WAIT_VARNAMES_SETTLETIME (float value)
Seconds to pause after all expected vars found in activation environment
UWSM_APP_UNIT_TYPE (service|scope)
Default unit type for launching apps
DEBUG Dump debug info to stderr

uwsm can be launched by using conditional exec in shell profile to replace login shell (see Shell Profile Integration section).

Alternatively "uwsm start ..." command can be put into wayland session's Desktop Entry to be launched by a display manager (see Use Inside Desktop Entry section).

uwsm can run arbitrary compositor command line or a Desktop Entry by ID (specifying Action ID is also supported).

Desktop Entry can also be selected via a whiptail menu (see select subcommand section).

See start subcommand section for command syntax.

A set of runtime units bound to standard user session targets is generated:

wayland-session-pre@.target (bound to graphical-session-pre.target)
wayland-wm-env@.service (environment preloader service)
wayland-session@.target (bound to graphical-session.target)
wayland-wm@.service (service for the selected compositor)
  • wayland-session-xdg-autostart@.target (bound to xdg-desktop-autostart.target)
  • wayland-session-shutdown.target (conflicts with targets above for shutdown)
  • wayland-session-bindpid@.service (PID-tracking session killswitch)
  • wayland-session-waitenv.service (delays graphical session until vars appear)

Compositor ID (Desktop Entry ID or executable name) becomes the specifier for all templated units.

At the stage of graphical-session-pre.target, the environment is sourced from the shell profile and from uwsm environment files. The delta is exported to the systemd and D-Bus activation environments by the environment preloader service and is marked for cleanup at shutdown stage. Preloader shell context for convenience has IN_UWSM_ENV_PRELOADER var set to true.

At the stage of graphical-session.target (before it) the main compositor unit wayland-wm@${ID}.service and wayland-session-waitenv.service are started.

Compositor should at least put WAYLAND_DISPLAY variable to systemd activation environment. This will trigger uwsm's automatic finalization logic. Without WAYLAND_DISPLAY in activation environment startup will timeout in 10 seconds.

Manual finalization is possible by running "uwsm finalize" (see finalize subcommand section), also in combination with tweaking UWSM_WAIT_VARNAMES and UWSM_WAIT_VARNAMES_SETTLETIME vars (see Environment vars section).

Successful activation of compositor unit and existence of WAYLAND_DISPLAY in activation environment will allow graphical-session.target to be declared reached.

Finally, xdg-desktop-autostart.target is activated.

It is highly recommended to configure the compositor or app launcher to launch apps as scopes or services in special user session slices (app.slice, background.slice, session.slice). uwsm provides custom nested slices for apps to live in and be terminated on session end:

  • app-graphical.slice
  • background-graphical.slice
  • session-graphical.slice

A helper app subcommand is provided to handle all the systemd-run invocations for you (see app subcommand section).

If app launching is configured as recommended, uwsm can be set to launch the compositor in session.slice (as recommended by systemd.special(7)) by adding "-S" to start subcommand, or adding this to the environment in which "uwsm start" is launched:

UWSM_USE_SESSION_SLICE=true

Can be initiated by either:

  • running uwsm stop
  • stopping wayland-wm@*.service
  • starting wayland-session-shutdown.target

Systemd stops all user units in reverse, as it usually does. During deactivation of graphical-session-pre.target, the environment preloader service cleans activation environments by unsetting all variables that were marked for removal during startup and finalization stages.

Do not use compositor's native exit mechanism or kill its process directly.

Selects default wayland session compositor Desktop Entry.

uwsm select

Invokes a whiptail menu to select default session among Desktop Entries in wayland-sessions XDG data hierarchy. Writes to ${XDG_CONFIG_HOME}/uwsm/default-id. Nothing else is done. Returns 1 if selection is cancelled. Can be used for scripting launch condition in shell profile.

Performs tests, returns 0 on success, 1 on failure.

is-active:

uwsm check is-active [-h] [-v] [compositor]
-v show additional info
compositor check for specific compositor

Checks if unit of specific compositor or graphical-session*.target in general is in active or activating state.

may-start:

uwsm check may-start [-h] [-g [S]] [-v|-q] [N ...]
-g S wait S seconds for graphical.target in queue (default: 60; 0 or less disables check).
-v show all failed tests
-q be quiet
N ... allowed VT numbers (default: 1)

Checks whether it is OK to launch a wayland session via the following conditions:

  • Running from login shell
  • System is at graphical.target
  • User graphical-session*.target units are not yet active
  • Foreground VT is among allowed (default: 1)

Generates units for given compositor command line or Desktop Entry and starts them.

uwsm start [-h] [-D name[:name...]] [-a|-e] [-N Name] [-C Comment] [-S|-A] [-o] [-n] -- compositor [args ...]
-F Hardcode mode, always write command line to unit drop-ins and use full paths.
-D name[:name...] Names to fill XDG_CURRENT_DESKTOP with (:-separated). Existing var content is a starting point if no active session is running.
-a Append desktop names set by -D to other sources (default).
-e Use desktop names set by -D exclusively, discard other sources.
-N Name Fancy name for compositor (filled from Desktop Entry by default).
-C Comment Fancy description for compositor (filled from Desktop Entry by default).
-S Launch compositor in session.slice.
-A Launch compositor in app.slice.
-o Only generate units, but do not start.
-n Do not write or start anything.

The first argument of the compositor command line acts as an ID and should be either one of:

  • Executable name
  • Desktop Entry ID (optionally with ":"-delimited action ID)
  • Special value:
  • select - invoke menu to select compositor.
  • default - run previously selected compositor (or select if no selection was saved).

If given as path, hardcode mode will be used implicitly.

Always use "--" to disambiguate dashed arguments intended for compositor itself.

After units are (re)generated, wayland-session-bindpid@${PID}.service is started, to track the PID of invoking uwsm, then uwsm process replaces itself with systemctl execution that starts wayland-wm@${ID}.service and waits for it to finish.

In order to complete the startup sequence, the compositor has to put WAYLAND_DISPLAY into the systemd activation environment. This can be done explicitly by making compositor run "uwsm finalize" command (see the next subsection).

For running by a compositor on startup.

uwsm finalize [-h] [VAR_NAME ...]

Exports WAYLAND_DISPLAY, DISPLAY and any defined vars mentioned by names in arguments or in UWSM_FINALIZE_VARNAMES variable (whitespace-separated). Then sends startup notification for the unit to systemd user manager.

This is required if compositor itself does not put WAYLAND_DISPLAY to systemd activation environment, otherwise wayland-session@.service unit or a dedicated wayland-session-waitenv.service unit will terminate due to startup timeout.

UWSM_FINALIZE_VARNAMES variable can be prefilled by plugins.

Direct assignment as VAR_NAME=value is also possible, but recommended only for creating flags for UWSM_WAIT_VARNAMES mechanism.

Stops compositor and optionally removes generated units.

uwsm stop [-h] [-r [compositor] [-n]
-r [compositor] Also remove units (all or only compositor-specific).
-n Dry run, do not stop or remove anything.

Application-to-unit launcher with Desktop Entry support.

uwsm app [-h] [-s {a,b,s,custom.slice}] [-t {scope,service}] [-a app_name] [-u unit_name] [-d unit_description] [-S ] [-T] -- application[args ...]
-s {a,b,s,custom.slice} Slice selector (default: a):
a - app-graphical.slice
b - background-graphical.slice
s - session-graphical.slice
any slice by full name
-t {scope,service} Type of unit to launch (default: scope, can be preset by UWSM_APP_UNIT_TYPE env var).
-a app_name Override app name (a substring in unit name).
-u unit_name Override the whole autogenerated unit name.
-d unit_description Unit Description.
-S {out,err,both} Silence stdout, stderr, or both.
-T Launch app in a terminal. Allows command to be empty to just launch a terminal.

Application can be provided as a command with optional arguments, or a Desktop Entry ID, optionally suffixed with ":"-delimited Action ID. If Destop Entry is being launched, arguments should be compatible with it.

Always use "--" to disambiguate dashed arguments intended for application itself.

For use in systemd user services. Can only be called by systemd user manager.

prepare-env Prepares environment (for use in ExecStart in wayland-wm-env@.service bound to wayland-session-pre@.target).
cleanup-env Cleans up environment (for use ExecStop in in wayland-wm-env@.service bound to wayland-session-pre@.target).
exec Executes a command with arguments or a desktop entry (for use in Exec in wayland-wm@.service bound to wayland-session@.target).
app-daemon Daemon for faster app argument generation, used by uwsm-app client.

Provided as wayland-wm-app-daemon.service to be started on-demand.

Daemon receives app arguments from ${XDG_RUNTIME_DIR}/uwsm-app-daemon-in pipe. Resulting arguments are formatted as shell code and written to ${XDG_RUNTIME_DIR}/uwsm-app-daemon-out pipe.

Arguments are expected to be \0-delimited, leading \0 are stripped. One command is received per write+close.

The first argument determines the behavior:

  • app the rest is processed the same as in "uwsm app"
  • ping just "pong" is returnedn
  • stop daemon is stoppedn

Single commands are prepended with exec, iterated commands are assembled with trailing & each, followed by wait.

The purpose of all this is to skip all the expensive Python startup and import routines that slow things down every time "uwsm app" is called. Instead the daemon does it once and then listens for requests, while a simple shell script may dump arguments to one pipe and run the code received from another via eval, which is much faster.

The simplest script is:

#!/bin/sh
printf '0%s' app "$@" > "${XDG_RUNTIME_DIR}/uwsm-app-daemon-in"
IFS='' read -r cmd < "${XDG_RUNTIME_DIR}/uwsm-app-daemon-out"
eval "$cmd"

Provided uwsm-app client script is a bit smarter: it can start the daemon, applies timeouts, and supports newlines in returned args.

To launch uwsm automatically on login, add one of constructs below (or similar) to shell profile.

This asks to select a compositor (or refuse and continue with login shell) when logged in on VT 1:

if uwsm may-start && uwsm select; then
	exec systemd-cat -t uwsm_start uwsm start default
fi

This just starts a specific compositor depending on foreground VT:

if uwsm may-start 1; then
	exec systemd-cat -t uwsm_start uwsm start sway.desktop
elif uwsm may-start 2; then
	exec systemd-cat -t uwsm_start uwsm start labwc.desktop
fi

Using "uwsm check may-start" as a condition is essential, not only to prevent accidental startup attempts where they are not expected, but also since startup involves sourcing shell profile, which might lead to nasty loops.

See check subcommand section for info on may-start checker.

exec allows uwsm to replace login shell in order to properly bind to user session and handle session termination.

"systemd-cat -t uwsm_start" (optional) executes the command given to it (uwsm) with its stdout and stderr connected to the systemd journal, tagged with identifier "uwsm_start". See systemd-cat(1) for more options.

To launch uwsm from a display/login manager, "uwsm start" can be used inside Desktop Entries. Example /usr/local/share/wayland-sessions/my-compositor.desktop:

[Desktop Entry]
Name=My compositor (with UWSM)
Comment=My cool compositor
Exec=uwsm start -N "My compositor" -D mycompositor -C "My cool compositor" mywm
DesktopNames=mycompositor
Type=Application

Things to keep in mind:

  • For consistency, command line arguments should mirror the keys of the entry
  • Command in Exec= should start with "uwsm start"
  • It should not point to itself (as a combination of Desktop Entry ID and Action ID)
  • It should not point to a Desktop Entry ID and Action ID that also uses `uwsm`

Potentially such entries may be found and used by uwsm itself, i.e. in shell profile integration situation, or when launched manually. Following the principles above ensures uwsm will properly recognize itself and parse requested arguments inside the entry without any side effects.

uwsm-plugins(3), systemd-run(1), systemd-cat(1), systemd.special(7)

2025-01-30