Add initial session / systemd integration

This commit is contained in:
Ivan Molodetskikh 2023-08-27 07:37:36 +04:00
parent 99484afe52
commit d268cfcf9f
7 changed files with 82 additions and 0 deletions

7
Cargo.lock generated
View File

@ -813,6 +813,7 @@ dependencies = [
"clap",
"keyframe",
"profiling",
"sd-notify",
"smithay",
"smithay-drm-extras",
"tracing",
@ -1186,6 +1187,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "sd-notify"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32"
[[package]]
name = "sharded-slab"
version = "0.1.4"

View File

@ -12,6 +12,7 @@ bitflags = "2.3.3"
clap = { version = "4.3.21", features = ["derive"] }
keyframe = { version = "1.1.1", default-features = false }
profiling = "1.0.9"
sd-notify = "0.4.1"
smithay-drm-extras = { version = "0.1.0", path = "../smithay/smithay-drm-extras" }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }

30
resources/niri-session Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
# Make sure there's no already running session.
if systemctl --user -q is-active niri.service; then
echo 'A niri session is already running.'
exit 1
fi
# Reset failed state of all user units.
systemctl --user reset-failed
# Set the current desktop for xdg-desktop-portal.
export XDG_CURRENT_DESKTOP=niri
# Ensure the session type is set to Wayland for xdg-autostart apps.
export XDG_SESSION_TYPE=wayland
# Import the login manager environment.
systemctl --user import-environment
# DBus activation environment is independent from systemd. While most of
# dbus-activated services are already using `SystemdService` directive, some
# still don't and thus we should set the dbus environment with a separate
# command.
if hash dbus-update-activation-environment 2>/dev/null; then
dbus-update-activation-environment --all
fi
# Start niri and wait for it to terminate.
exec systemctl --user --wait start niri.service

6
resources/niri.desktop Normal file
View File

@ -0,0 +1,6 @@
[Desktop Entry]
Name=Niri
Comment=A scrollable-tiling Wayland compositor
Exec=niri-session
Type=Application
DesktopNames=niri

9
resources/niri.service Normal file
View File

@ -0,0 +1,9 @@
[Unit]
Description=A scrollable-tiling Wayland compositor
BindsTo=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target
[Service]
Type=notify
ExecStart=/usr/bin/niri

View File

@ -19,6 +19,7 @@ use std::ffi::OsString;
use backend::Backend;
use clap::Parser;
use niri::Niri;
use sd_notify::NotifyState;
use smithay::reexports::calloop::EventLoop;
use smithay::reexports::wayland_server::{Display, DisplayHandle};
use tracing_subscriber::EnvFilter;
@ -121,4 +122,9 @@ fn main() {
}
})
.unwrap();
// Tell systemd we're stopping.
if let Err(err) = sd_notify::notify(false, &[NotifyState::Stopping]) {
warn!("error notifying systemd: {err:?}");
}
}

View File

@ -1,8 +1,10 @@
use std::collections::HashMap;
use std::os::unix::io::AsRawFd;
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use sd_notify::NotifyState;
use smithay::backend::renderer::element::surface::{
render_elements_from_surface_tree, WaylandSurfaceRenderElement,
};
@ -149,6 +151,27 @@ impl Niri {
socket_name.to_string_lossy()
);
if std::env::var_os("NOTIFY_SOCKET").is_some() {
// We're starting as a systemd service. Export our variables and tell systemd we're
// ready.
let rv = Command::new("/bin/sh")
.args([
"-c",
"systemctl --user import-environment WAYLAND_DISPLAY && \
hash dbus-update-activation-environment 2>/dev/null && \
dbus-update-activation-environment WAYLAND_DISPLAY",
])
.spawn();
if let Err(err) = rv {
warn!("error spawning shell to import environment into systemd: {err:?}");
}
// Notify systemd we're ready.
if let Err(err) = sd_notify::notify(false, &[NotifyState::Ready]) {
warn!("error notifying systemd: {err:?}");
};
}
let display_source = Generic::new(
display.backend().poll_fd().as_raw_fd(),
Interest::READ,