Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start i3 with a systemd service, if systemd is running and the service is loaded. #5591

Open
wants to merge 1 commit into
base: next
Choose a base branch
from

Conversation

davidsansome
Copy link

The systemd service activates graphical-session.target which in turn may activate other useful services such as the ssh-agent.

Fixes #5186

is loaded.

The systemd service activates `graphical-session.target` which in turn
may activate other useful services such as the ssh-agent.

[Service]
Type=exec
ExecStart=i3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Units usually use absolute paths for exec.
Should it be @bindir@/i3?


[Service]
Type=exec
ExecStart=i3
Copy link

@Thaodan Thaodan Oct 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ExecStart=i3
ExecStart=i3
ExecReload=/usr/bin/i3-msg restart

In case the user want's to reload or restart i3.
I'm referencing restart instead of reload here since systemd's restart doesn't allow
the user to specific it's on command for restarts, there is only the option to define
a reload, start or stop command.

Copy link

@faivirol faivirol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR, replacing autostart scripts with services becomes feasible. I would add documentation about something like this:

[Unit]
Description=picom
BindsTo=i3@%i.service
After=i3@%i.service

[Service]
Environment=DISPLAY=%i
ExecStart=picom <args>

[Install]
[email protected]

Placed at $XDG_CONFIG_HOME/systemd/user/picom.service, it could then be enabled with systemctl --user enable picom@ .

Alternatively, if sticking with the current service in the PR and not implementing instances, a simpler service like this could be used:

[Unit]
Description=picom
BindsTo=i3.service
After=i3.service

[Service]
ExecStart=picom <args>

[Install]
WantedBy=i3.service

The enabling would then also be without the at sign.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If run a second time before the first is done, it will hang and wait for the same service. If not implementing support for multiple instances, a check and message for if the service is already running would at least show that the single instance limit is intended.

BindsTo=graphical-session.target
Before=graphical-session.target

[Service]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slice=session.slice should be set in this case according to systemd.special

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this might not be the best since it seems like all processes i3 spawns, including applications, then fall under the session slice.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does the service get DISPLAY and XAUTHORITY from? I can get it to work using systemctl --user import-environment DISPLAY XAUTHORITY in .xinitrc or adding ENVIRONMENT=... to the service, but I don't see how the service can work as is, although I might be missing something.

Although I don't often have two instances open, it does happen. My suggestion is to make the unit into a template and use the instance variable like Environment=DISPLAY=%i. This will support multiple instances and nonstandard DISPLAY values, making i3-session-start a drop-in replacement for running i3.

As for XAUTHORITY, asking the user to run/script systemctl --user import-environment XAUTHORITY before i3-session-start seems like a good choice since it is global for a user/systemd user instance (unlike DISPLAY), although a fallback to ~/.Xauthority would probably be enough for most. For reference, Arch already sets XAUTHORITY this way, although it is only suggested in a note that you actually include this in your user's .xinitrc.

Copy link

@kjkent kjkent Jul 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does the service get DISPLAY and XAUTHORITY from?

/etc/X11/xinit/xinitrc.d/50-systemd-user.sh should be sourced by the user's $XINITRC (default ~/.xinitrc, falling back to /etc/X11/xinit/xinitrc if neither is found), which is sourced by startx/xinit. The fallback xinitrc contains:

# ...
# start some nice programs
if [ -d /etc/X11/xinit/xinitrc.d ] ; then
 for f in /etc/X11/xinit/xinitrc.d/?*.sh ; do
  [ -x "$f" ] && . "$f"
 done
 unset f
fi

As per the Arch Wiki:

Units started by user instance of systemd do not inherit any of the environment variables set in places like .bashrc etc. There are several ways to set environment variables for them ...

There's a bit in 2.1.1 talking about DISPLAY and XAUTHORITY in particular.

I hope some of this is useful and not just stuff you already know!

Edit: I've just read that /etc/X11/xinit/xinitrc.d/50-systemd-user.sh might be an Arch-implemented file (although it contains a license specifying it as part of systemd...), so here's its contents for convenience:

#!/bin/sh
#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

systemctl --user import-environment DISPLAY XAUTHORITY

if command -v dbus-update-activation-environment >/dev/null 2>&1; then
    dbus-update-activation-environment DISPLAY XAUTHORITY
fi

@Thaodan
Copy link

Thaodan commented Dec 30, 2023 via email

@faivirol
Copy link

I think applications should be started by the session-manager not by the
window-manager.

What do you mean by this?

I don't think ***@***.*** is needed as there wouldn't be more than one
windoww-manager in the session.

After sleeping on it, this sounds more reasonable. The extra complexity is probably not justifiable for such a niche case. Using systemd --user import-environment DISPLAY would remove the need to provide it through an instance variable or hardcode it. If a user needs to run multiple instances, they can always fall back to executing the i3 binary directly.

I am curious though about how you provide DISPLAY and XAUTHORITY to the service you posted in #5186, @Thaodan. Did you use import-environment as well?

Using Install=windwmanager.servcice in i3.service and
After=windowmanager.service in picom.service would make the unit more
universal for e.g. upstreaming of the picom service file.

Yep, seems obvious in hindsight. Although graphical-session.target works as well (for BindsTo, After and WantedBy), so I think that's better than creating a new windowmanager.service standard.

@Thaodan
Copy link

Thaodan commented Dec 30, 2023 via email

@budRich
Copy link

budRich commented Jul 19, 2024

i3-session-start is a bash script ([[ $? != 0 || "${UNIT_LOAD_STATE}" != "loaded" ]]) . Use appropriate shbang: #!/usr/bin/env bash . Also as in discussion about needing environment variables, before systemctl start --user --wait i3-session.service you could do: dbus-update-activation-environment --systemd DISPLAY XAUTHORITY .

Also the service type can be changed to notify since i3 implements the feature (#4454).

[Service]
Type=notify
ExecStart=i3
ExecStopPost=/bin/systemctl --user stop --no-block graphical-session.target

I use ExecStopPost to shut down other graphical programs started by systemd gracefully when i3 stops.

In my experience (i have been starting i3 with systemd for years), there are more environment variables one probably want. PATH, without it, relative paths in the i3 config file will not be found f.i. exec --no-startup-id dex --autostart --environment i3 (from the default config) (dexplain to a new user why to init programs need to be involved to start i3...)

dbus-update-activation-environment --systemd DISPLAY XAUTHORITY in my personal setup is actually: dbus-update-activation-environment --systemd --all , which will import all environment variables to systemd. But this is not proper to do security wise.

systemctl --user import-environment DISPLAY XAUTHORITY <- this command and dbus-update-activation-environment --systemd DISPLAY XAUTHORITY are equivalent i think.

You will break lots of peoples configs if they start i3 without access to the PATH environment variable, but you will also upset lots of people for compromising security if you do import the PATH environment variable. In my opinion this whole systemd stuff is headaches that the package maintainers could customize for their distros if they wanted to. I wouldn't be surprised if a large chunk of i3 user base doesn't even have systemd..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

i3 session does not activate systemd graphical-session.target
5 participants