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:

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.