close
Skip to content

kavau/atrium

Repository files navigation

atrium

A lightweight Wayland display manager for Linux with first-class multiseat support. Discovers seats via logind, launches a greeter on each seat inside a kiosk compositor, and hands off to a user-selected Wayland session.

Why atrium?

The Linux kernel and the low-level system stack (udev device tagging, logind seat management) are fully capable of multiseat operation. Wayland compositors are seat-agnostic by design: they simply claim whatever display and input devices logind assigns to their seat. The missing piece has always been the display manager. Historically, display managers have treated multiseat as an afterthought. Most implementations are brittle, poorly tested on real hardware, and often impossible to get working reliably.

atrium aims to fill this gap. It is a display manager that puts multiseat first: discover every seat, run a greeter on each one, authenticate the user, and start the session, with correct seat lifecycle management throughout. The project targets a modern, minimal setup: systemd/logind for session management, PAM for authentication, and Wayland as the primary target. No historical baggage.

Status

post-v0.3.0 — fully functional but still in early development.

atrium runs well as a daily-driver display manager. The core workflow (seat discovery, PAM authentication, session management, etc.) is fully operational. That said, atrium has been tested on a limited range of hardware and distributions; expect rough edges in certain cases. See Known Limitations below.

See doc/architecture.md for a detailed design overview.

For instructions how to configure your hardware for multiseat, see doc/multiseat-setup.md.

What's new since the v0.3 release

  • Support for greeter background images — set background-image in /etc/atrium-greeter.conf to an image path, or to a directory to pick a random image on each greeter launch.
  • Greeter themes — set theme in /etc/atrium-greeter.conf to a theme .css file in order to override built-in colors and styles. A handful of themes are shipped with atrium and installed in /usr/local/share/atrium/themes.

What's new since v0.2

  • Runtime config files/etc/atrium.conf and /etc/atrium-greeter.conf replace the compile-time src/config.h used in v0.2.0.
  • Session discovery — atrium reads /usr/share/wayland-sessions/ and /usr/local/share/wayland-sessions/ at greeter launch. The compositor= and desktop= settings are now optional overrides.
  • Session picker — the greeter shows a dropdown of discovered sessions. Hidden when only one session is installed or a compositor= override is set.
  • Wallet/keyring auto-unlock — KWallet and GNOME Keyring are unlocked automatically at login if the relevant PAM module packages are installed. See Wallet and keyring auto-unlock.

Supported Distros

Distro Status
CachyOS / Arch Linux Tested
Debian / Ubuntu Tested
Fedora Tested; SELinux handled via xdm_t workaround (issue #86)

Other systemd-based distros should work — the only distro-specific piece is the PAM stack. Use whichever of the three provided configs most closely matches your distro's PAM layout, or adapt one as needed.


Building and Installation

atrium runs as a systemd service (as root) and must be the only display manager active on the system.

Tip

main receives only tested changes and is generally stable for day-to-day use. However, for production deployments, tagged releases are recommended. The latest release is at github.com/kavau/atrium/releases/latest.

1. Install dependencies

  • libsystemd: logind session management
  • libudev: seat and device hotplug events
  • libpam: user authentication
  • gtk4: greeter UI
  • cage: Wayland compositor hosting the greeter
  • meson, ninja: build system

On Debian/Ubuntu:

sudo apt install libsystemd-dev libudev-dev libpam0g-dev libgtk-4-dev cage meson ninja-build

On CachyOS/Arch (libsystemd and libudev are both provided by the systemd package):

sudo pacman -S systemd pam gtk4 cage meson ninja

On Fedora (systemd-devel covers both libsystemd and libudev; gcc is not installed by default on a minimal Fedora system):

sudo dnf install gcc systemd-devel pam-devel gtk4-devel cage meson ninja-build policycoreutils-python-utils checkpolicy

2. Build and install

meson setup build -Ddist=<your-distro>   # arch, debian, fedora
ninja -C build
sudo ninja -C build install

The -Ddist option (required) selects the target distribution. It controls the PAM stack installed and the greeter binary location:

  • arch: PAM stack for Arch/CachyOS; greeter at /usr/lib/atrium/atrium-greeter
  • debian: PAM stack for Debian/Ubuntu; greeter at /usr/libexec/atrium-greeter
  • fedora: PAM stack for Fedora; greeter at /usr/libexec/atrium-greeter

This installs:

/usr/local/bin/atrium -- the daemon
/usr/local/lib/atrium/atrium-greeter (Arch) or
    /usr/local/libexec/atrium-greeter (others) -- the GTK4 greeter
/usr/lib/systemd/system/atrium.service -- the systemd unit file
/usr/lib/sysusers.d/atrium.conf -- sysusers.d snippet for `atriumdm` user
/etc/pam.d/atrium -- the PAM configuration
/etc/atrium.conf -- daemon configuration
/etc/atrium-greeter.conf -- greeter UI configuration
/usr/local/share/atrium/themes/*.css -- greeter themes

The install process also creates the atriumdm system user via systemd-sysusers (if it doesn't already exist), which runs the greeter process as an unprivileged account.

On Fedora, the install also runs SELinux setup: labels the atrium binary as xdm_exec_t and installs the atrium-local policy module, which grants xdm_t the permissions needed to run udevadm settle. See issue #86 for the long-term plan to replace the xdm_t workaround with a dedicated domain.

3. Configure

Most users can skip this step. The defaults work for a standard single-seat or multiseat setup with automatic session discovery.

atrium reads two runtime config files under /etc, both installed by the previous step:

  • /etc/atrium.conf — daemon settings: greeter command, ignored seats, passwordless users, and optional compositor override.
  • /etc/atrium-greeter.conf — greeter UI settings: idle blanking timeout, theming etc.

Each config file is heavily commented; consult them for the full set of available keys and their meaning. Missing config files or keys fall back to compiled-in defaults.

Greeter background and themes

Set background-image in /etc/atrium-greeter.conf to an image path, or to a directory to pick a random image on each launch. JPEG, PNG, WebP, and several other formats are supported.

Set theme to a CSS file to change the color scheme and widget styling. Several themes ship with atrium and are installed under /usr/local/share/atrium/themes/, or you can write your own.

Session discovery and compositor override

By default, atrium reads session .desktop files from /usr/share/wayland-sessions/ and /usr/local/share/wayland-sessions/ at greeter launch and presents them in a dropdown.

Note: Session memory is currently per-seat, not per-user. If multiple users share a seat, the preselected session reflects whichever user logged in last, not the user's own last choice.

To bypass discovery and always launch a specific compositor, set compositor= and desktop= in /etc/atrium.conf. When set, the session dropdown is hidden and the specified command is used for every login on every seat.

X11 sessions (/usr/share/xsessions/) are not supported.

Wallet and keyring auto-unlock

atrium's PAM configuration already includes optional entries for KWallet and GNOME Keyring. If the corresponding packages are installed, the wallet or keyring is automatically unlocked at login using the login password.

Desktop Package (Arch) Package (Debian/Ubuntu)
KDE (KWallet) kwallet-pam libpam-kwallet5
GNOME / COSMIC (GNOME Keyring) gnome-keyring libpam-gnome-keyring

Note: Passwordless users currently bypass PAM entirely and will not benefit from automatic wallet unlock.

4. Enable and start

Note

Multiseat users: seat assignment must be configured with loginctl attach before starting atrium. Without this step, only a single seat (seat0) exists, and additional GPUs and input devices will not be recognised as independent seats. See doc/multiseat-setup.md for a step-by-step guide.

First, note which display manager is currently active so you can restore it if needed:

readlink /etc/systemd/system/display-manager.service
# e.g. /usr/lib/systemd/system/gdm.service  -->  re-enable with: systemctl enable gdm

Then disable it and enable atrium:

sudo systemctl disable gdm   # substitute your current display manager
sudo systemctl enable atrium

Then reboot. atrium will start on boot and launch a greeter on every seat.

Uninstall

To fully remove atrium, switch to another display manager first (so the next boot still has a graphical login) and then run the provided script. Do this from a TTY (Ctrl+Alt+F2) to avoid killing your current desktop session when the atrium service stops.

sudo systemctl disable atrium    # free the display-manager alias
sudo systemctl enable gdm        # substitute your previous display manager
sudo ./tools/uninstall.sh        # stop the service, remove files, delete the atriumdm user

The script expects the Meson build directory to be build/; pass a different path as the second argument if yours lives elsewhere.

If the script reports that it could not remove the atriumdm user (lingering processes can briefly hold it open after the service stops), simply run it again after a short time. The second run will clean up the user once those processes have exited.


If Things Go Wrong

If atrium fails to start or you can't log in, switch back to your previous display manager from a TTY (Ctrl+Alt+F2, log in as root or with sudo):

sudo systemctl disable atrium
sudo systemctl enable gdm   # substitute your previous display manager
sudo reboot

To reset all seat assignments and return to a single-seat configuration:

sudo loginctl flush-devices

To check what went wrong, inspect the journal:

sudo journalctl -u atrium -b    # logs from the current boot
sudo journalctl -u atrium -b-1  # logs from the previous boot

Note: compositor failures are not visible in the atrium unit log. When CreateSession is called, logind moves the compositor child into its own cgroup scope, so any subsequent output from that child is attributed to that scope rather than to atrium.service. If the greeter restarts immediately after login, query by time window or by PID instead:

journalctl -b --no-pager --since="HH:MM:SS" --until="HH:MM:SS"
journalctl -b --no-pager _PID=<pid shown in atrium log>

Known Limitations

Hotplug is only partially supported

Seats added after startup and monitors connected after boot may not be reliably detected. atrium reacts to some runtime events (a new logind seat or a DRM connector change) but detection can fail, e.g. if a GPU enters a deep idle state that prevents hotplug interrupts from being delivered. Tracked in #28.

Mixed-GPU setups are untested

Running two GPU vendor drivers simultaneously (e.g. AMD + NVIDIA, or Intel + NVIDIA) is generally considered unsupported territory on Linux, and can result in driver instabilities and configuration headaches. So far atrium has only been tested on all-AMD multiseat machines.

Cross-seat keyboard input leakage to text VTs

The Linux kernel routes keystrokes to whichever VT (Virtual Terminal) is foreground system-wide, ignoring udev seat tagging. On a multiseat machine, keystrokes typed on seat1's keyboard can land on a text login (e.g. agetty) on seat0 if that VT is in the foreground at the time. This is universal Linux multiseat behavior, not atrium-specific. Recommended mitigation: mask getty@tty1 and autovt@tty[2-6] on managed seats, removing the leak destination. Tracked in #72.

PAM authentication limited to a single password prompt

The greeter collects a username and a single password and sends both to the daemon in one shot, rather than driving PAM's conversation function interactively. As a result, any PAM stack that emits more than one prompt (e.g. multi-factor, hardware tokens, fingerprint, etc.) will misbehave or hang. Tracked in #93.

Passwordless users bypass PAM

Users listed under passwordless-user in /etc/atrium.conf skip pam_authenticate entirely and proceed directly to session creation. There is no PAM account/session check for these users. PAM modules that capture the password during authentication are skipped as well, which means wallet/keyring auto-unlock will not work for passwordless users. Tracked in #30.

Fedora: SELinux uses an xdm_t workaround

ninja install handles SELinux automatically: the atrium binary is labelled xdm_exec_t so it runs in GDM's xdm_t domain, and the atrium-local policy module is installed to grant xdm_t the permissions atrium needs (running udevadm settle, connecting to the udev socket).

If new AVCs appear after a Fedora policy update, re-running ninja install will rebuild and reinstall the module. A dedicated SELinux policy module with its own atrium_t domain is tracked in #86.


FAQ

The greeter immediately comes back after login

The user session failed to start. To see what went wrong, look up the PID from the atrium log and query the logs for it:

sudo journalctl -u atrium -b | grep "compositor started"
# note the pid=NNNN value, then:
sudo journalctl -b _PID=NNNN

Common causes:

  • The compositor binary (see the Exec= line in the session's .desktop file) is missing or not in $PATH.
  • A compositor-specific config file has a syntax error (e.g. sway prints these and exits immediately).
  • The compositor could not acquire DRM master (e.g. another compositor is running). Check for Permission denied or EACCES in the log.

Login succeeds but I get a black screen

The compositor is running but nothing is displayed. This is compositor- or desktop-environment-specific and atrium has no control over it. Check the compositor log with the _PID= technique above for errors or warnings.

Common causes:

  • The Exec= line in the .desktop file is missing a required setup wrapper. For example, KDE Plasma needs /usr/lib/plasma-dbus-run-session-if-needed prepended to startplasma-wayland. Check the .desktop file under /usr/share/wayland-sessions/ shipped with your distro and make sure your Exec= matches it exactly.

My desktop environment or compositor doesn't appear in the greeter's session list

atrium reads .desktop files from /usr/share/wayland-sessions/ and /usr/local/share/wayland-sessions/ at greeter launch. If a session is missing from the list, check for these common causes:

  • No .desktop file exists in either directory (note that atrium does not scan /usr/share/xsessions/ or /usr/local/share/xsessions/).
  • The .desktop file contains Hidden=true or NoDisplay=true — atrium skips those entries.
  • The TryExec= binary was not found on $PATH — atrium skips the entry when the binary is absent.

To add a custom session, create a .desktop file in /usr/local/share/wayland-sessions/:

[Desktop Entry]
Name=My Session
Exec=/usr/local/bin/my-compositor
TryExec=/usr/local/bin/my-compositor
Type=Application

GNOME: "Screen Lock disabled / Screen Locking requires the GNOME display manager"

This is due to the deep integration between GDM and the GNOME Shell, which depends on the org.gnome.DisplayManager service as the PAM credential broker when the user unlocks the screen. If it is not present (i.e. GDM is not running), GNOME Shell disables its built-in lock screen and shows this warning. No display manager other than GDM implements this interface, so this warning appears with LightDM, SDDM, greetd, and atrium alike.

Workaround: use a standalone screen locker such as swaylock or hyprlock, triggered by swayidle or a systemd user service listening for logind's lock/idle signals. Tracked in #91.

Multiseat: my computer goes to sleep unexpectedly

Many desktop environments are pre-configured to put the computer to sleep after a period of inactivity. In a single-seat setup this is fine, but in a multiseat setup each seat manages its own idle state independently: if a seat is unused, the desktop environment may trigger a system-wide sleep even if another seat is still actively in use. To the active seat this appears as a sudden, unexplained sleep.

Fix: disable the automatic sleep timeout in your desktop environment's power settings. In GNOME, this is under Settings → Power → Automatic Suspend. In KDE Plasma, it is under System Settings → Power Management → Suspend Session.


Development

Remote deploy

Since restarting the atrium daemon kills the active user session, it is often convenient to test atrium on a machine other than the development machine. The tools/deploy.sh script syncs the source tree to a remote machine, builds there, and optionally installs and restarts the service (/tmp/atrium can be any temp directory):

# Build only
./tools/deploy.sh user@host:/tmp/atrium

# Build, install, and restart
./tools/deploy.sh user@host:/tmp/atrium -r

Community

Reporting Issues

Bug reports and feature requests are welcome. Please open an issue on GitHub and include:

  • A description of the problem or request.
  • Relevant journal output (sudo journalctl -u atrium -b).
  • Your distro, kernel version, and hardware configuration (especially for multiseat-related issues).

About

A Wayland display manager for Linux with first-class multiseat support.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors