Sway as a --user service with a little loop wait for WAYLAND_DISPLAY

Hi,

I spend few hours trying to figure this out without being lame and using large sleep.

The problem is basically this:

  1. You start sway service and that executed the sway binary,
  2. You have to set Environment="XDG_SESSION_ID=1" without it Sway will bail and exits
  3. All other graphical services (redshift, waybar, …etc) that starts after sway.service fails because the wayland display is not yet initialized.

It’s not a bug, it’s like this by design “ddevault” and “emersion” even warn people from not launching sway as a systemd --user service because of that fact it forks and never calls sd_ready or whatever.

SOLUTION:

Simple script I made as a post start command
ExecStartPost=%h/.config/systemd/user/sway-wait-for-wayland-display.sh

the content of the sway-wait-for-wayland-display.sh I put that next to the service fail.
It basically ask systemd what the user’s environment is which is not tied to the running context.

#!/bin/sh
i=1

while [ "$i" -ne 100 ]
do
	systemctl --user show-environment | grep WAYLAND_DISPLAY > /dev/null
	
	# Return status of grep is 0 when found 1 if not found
	status=$?

	# Break loop to skip sleep if found on first try
	if [ $status -eq 0 ]; then
		echo Display has been found.
		break
	fi

        sleep 0.1s
	# Increment
	i=$((i + 1))
done

If you are just thinking now "Why the frik he didn’t just poll printenv ?
Jokes on you, once you start runnning service the environment is passed to it and is being static.

You can look at my dotfiles, I made them little bit more complex by splitting them into sway-session-pre target and sway session target similarly as graphical session target.

https://git.sr.ht/~freed00m/dotfiles/tree/master/.config/systemd/user

Else, what do you thing? Is it worth mentioning it upstream? I think this is nice cherry on top of what they have in git repo wiki.