naftuli.wtf An urban mystic, pining for conifers in a jungle of concrete and steel.

Integrating systemctl --user and your Graphical Session

For those of us nerds who have been running Linux on the desktop for years now, the addition of systemd in recent releases has opened up some interesting user service management solutions. While not often discussed, systemctl --user is a per-user systemd service management system which sports most if not all of the features of the parent PID 1 systemd.

One issue I ran into on elementary 0.4 Loki (Ubuntu 16.04) was that the environment of systemctl --user was pretty barren:

naftuli@laststand:~$ systemctl --user show-environment
HOME=/home/naftuli
LANG=en_US.UTF-8
LOGNAME=naftuli
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
USER=naftuli
XDG_RUNTIME_DIR=/run/user/1000

This constitutes the bare minimum of what a user service might need. However, for starting user services on the desktop, this environment doesn’t have a reference back to the DISPLAY or anything else about the desktop session.

I found a workaround for this limitation by defining a script called by the desktop session on login and a user target called user-graphical-login.target which other services can depend on.

My script simply imports the current environment and starts the user-graphical-login.target, allowing other units to start:

#!/usr/bin/env bash

systemctl --user import-environment
systemctl --user start user-graphical-login.target

Drop this wherever you’d like, and then add it as a startup script in your distribution’s startup applications:

Screenshot

Next, let’s define our target at ~/.config/systemd/user/user-graphical-login.target:

[Unit]
Description=User Graphical Login
Requires=default.target
After=default.target

Log out, log back in, and then check that the target has been started:

naftuli@laststand:~$ systemctl --user status user-graphical-login.target
● user-graphical-login.target - User Graphical Login
   Loaded: loaded (/home/naftuli/.config/systemd/user/user-graphical-login.target; static; vendor preset: enabled)
   Active: active since Wed 2017-12-27 11:54:16 PST; 1 day 3h ago

Dec 27 11:54:16 laststand systemd[1938]: Reached target User Graphical Login.
Dec 27 11:54:27 laststand systemd[1938]: Reached target User Graphical Login.

If we now dump the environment from systemd --user, we should now see a ton of environment variables:

DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-4CdgBoOWOy,guid=54269270bb9eccd9b83e0e1f5a43fa10
DEFAULTS_PATH=/usr/share/gconf/pantheon.default.path
DESKTOP_SESSION=pantheon
DISPLAY=:0
EDITOR=vim
GDMSESSION=pantheon
GDM_LANG=en_US
GIO_LAUNCHED_DESKTOP_FILE=/usr/share/applications/org.pantheon.terminal.desktop
GIO_LAUNCHED_DESKTOP_FILE_PID=3930
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
GPG_TTY=/dev/pts/4
GSETTINGS_SCHEMA_DIR=/home/naftuli/data
GTK_CSD=1
GTK_MODULES=pantheon-filechooser-module:gail:atk-bridge
HOME=/home/naftuli
LANG=en_US.UTF-8
LANGUAGE=en_US
LESSCLOSE=/usr/bin/lesspipe %s %s
LESSOPEN=| /usr/bin/lesspipe %s
LOGNAME=naftuli
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
MANDATORY_PATH=/usr/share/gconf/pantheon.mandatory.path
PANTHEON_TERMINAL_ID=0
PATH=/home/naftuli/bin:/home/naftuli/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
POWERLINE_COMMAND=powerline
PROMPT_COMMAND=__bp_precmd_invoke_cmd; dbus-send --type=method_call --session --dest=org.pantheon.terminal /org/pantheon/terminal org.pantheon.terminal.ProcessFinished string:$PANTHEON_TERMINAL_ID string:"$(history 1 | cut -c 8-)" >/dev/null 2>&1;  __bp_interactive_mode;
PWD=/home/naftuli
QT_ACCESSIBILITY=1
QT_IM_MODULE=ibus
QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
QT_STYLE_OVERRIDE=gtk
SESSION_MANAGER=local/laststand:@/tmp/.ICE-unix/2023,unix/laststand:/tmp/.ICE-unix/2023
SHELL=/bin/bash
SHLVL=2
SSH_AGENT_PID=2095
SSH_AUTH_SOCK=/home/naftuli/.gnupg/S.gpg-agent.ssh
TERM=screen-256color
TMUX=/tmp/tmux-1000/default,1956,1
TMUX_PANE=%1
USER=naftuli
VTE_VERSION=4205
XAUTHORITY=/home/naftuli/.Xauthority
XDG_CONFIG_DIRS=/etc/xdg/xdg-pantheon:/etc/xdg
XDG_CURRENT_DESKTOP=Pantheon
XDG_DATA_DIRS=/usr/share/pantheon:/usr/local/share/:/usr/share/
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/naftuli
XDG_MENU_PREFIX=gnome-
XDG_RUNTIME_DIR=/run/user/1000
XDG_SEAT=seat0
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0
XDG_SESSION_DESKTOP=pantheon
XDG_SESSION_ID=c2
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0
XDG_SESSION_TYPE=x11
XDG_VTNR=7
XMODIFIERS=@im=ibus
_=/bin/systemctl

Now, your user services can start graphical applications and interact with the session.