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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions libexec/i3-session-start

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.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

# This script tries to start i3 via the i3-session systemd unit if it is loaded
# and systemd is running, otherwise falls back to execing i3 directly.

# Check if the i3-session systemd unit is loaded.
UNIT_LOAD_STATE=$(systemctl show i3-session.service -P LoadState)
if [[ $? != 0 || "${UNIT_LOAD_STATE}" != "loaded" ]]; then
# The unit is not loaded, or systemctl failed, so just start i3 normally.
exec i3
fi

# Start the i3 systemd session.
systemctl start --user --wait i3-session.service
35 changes: 33 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ endif
cdata.set('HAVE_STRNDUP', cc.has_function('strndup'))
cdata.set('HAVE_MKDIRP', cc.has_function('mkdirp'))

# Used in share/xsessions/i3.desktop.in to find i3-session-start.
cdata.set('LIBEXECDIR', join_paths(get_option('prefix'), get_option('libexecdir')))

# Instead of generating config.h directly, make vcs_tag generate it so that
# @VCS_TAG@ is replaced.
config_h_in = configure_file(
Expand Down Expand Up @@ -325,6 +328,8 @@ pangocairo_dep = dependency('pangocairo', method: 'pkg-config')
glib_dep = dependency('glib-2.0', method: 'pkg-config')
gobject_dep = dependency('gobject-2.0', method: 'pkg-config')

systemd_dep = dependency('systemd', required: false)

ev_dep = cc.find_library('ev')

inc = include_directories('include')
Expand Down Expand Up @@ -597,12 +602,38 @@ install_subdir(
install_dir: join_paths(get_option('sysconfdir'), 'i3'),
)

configure_file(
input: 'share/xsessions/i3.desktop.in',
output: 'i3.desktop',
configuration: cdata,
install: true,
install_dir: join_paths(get_option('datadir'), 'xsessions'),
)

install_data(
'share/applications/i3.desktop',
'share/xsessions/i3-with-shmlog.desktop',
rename: [
'applications/i3.desktop',
'xsessions/i3-with-shmlog.desktop',
],
install_dir: get_option('datadir'),
)

install_subdir(
'share/',
'libexec/',
strip_directory: true,
install_dir: get_option('datadir'),
install_dir: get_option('libexecdir'),
)

if systemd_dep.found()
install_subdir(
'systemd/',
strip_directory: true,
install_dir: systemd_dep.get_pkgconfig_variable('systemduserunitdir'),
)
endif

install_headers(
'include/i3/ipc.h',
subdir: 'i3',
Expand Down
4 changes: 2 additions & 2 deletions share/xsessions/i3.desktop → share/xsessions/i3.desktop.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[Desktop Entry]
Name=i3
Comment=improved dynamic tiling window manager
Exec=i3
TryExec=i3
Exec=@LIBEXECDIR@/i3-session-start
TryExec=@LIBEXECDIR@/i3-session-start
Type=Application
X-LightDM-DesktopName=i3
DesktopNames=i3
Expand Down
11 changes: 11 additions & 0 deletions systemd/i3-session.service

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.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Unit]
Description=i3 Session

Requires=graphical-session-pre.target
After=graphical-session-pre.target
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.

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?

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.