diff --git a/Cargo.toml b/Cargo.toml index 3031a67..22c764f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,6 @@ logind-zbus = { version = "5.3.2", optional = true } [features] systemd = ["dep:zbus_systemd", "dep:tracing-journald"] -logind = ["systemd", "logind-zbus"] -default = ["logind"] +logind = ["dep:logind-zbus"] +default = ["logind", "systemd"] autostart = ["dep:shell-words", "dep:dirs", "dep:freedesktop-desktop-entry"] diff --git a/src/main.rs b/src/main.rs index 989eb44..a081118 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod comp; mod notifications; mod process; mod service; +#[cfg(feature = "systemd")] mod systemd; use color_eyre::Result; @@ -15,18 +16,13 @@ use launch_pad::ProcessManager; use launch_pad::process::Process; use service::SessionRequest; use std::borrow::Cow; -#[cfg(feature = "autostart")] -use std::collections::HashSet; use std::env; use std::os::fd::AsRawFd; -#[cfg(feature = "autostart")] -use std::path::PathBuf; -#[cfg(feature = "autostart")] -use std::process::{Command, Stdio}; use std::sync::Arc; +#[cfg(any(feature = "autostart", feature = "systemd"))] +use std::{path::Path, sync::OnceLock}; #[cfg(feature = "systemd")] -use systemd::spawn_scope; -use systemd::{get_systemd_env, is_systemd_used}; +use systemd::{get_systemd_env, spawn_scope}; use tokio::signal::unix::{SignalKind, signal}; use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::{Mutex, oneshot}; @@ -36,14 +32,20 @@ use tracing::Instrument; use tracing::metadata::LevelFilter; use tracing_subscriber::prelude::*; use tracing_subscriber::{EnvFilter, fmt}; +#[cfg(feature = "autostart")] +use { + std::collections::HashSet, + std::path::PathBuf, + std::process::{Command, Stdio}, +}; use crate::notifications::{ DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD, notifications_process, }; #[cfg(feature = "autostart")] -const AUTOSTART_DIR: &'static str = "autostart"; +const AUTOSTART_DIR: &str = "autostart"; #[cfg(feature = "autostart")] -const ENVIRONMENT_NAME: &'static str = "COSMIC"; +const ENVIRONMENT_NAME: &str = "COSMIC"; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { @@ -143,7 +145,15 @@ async fn start( .await; let token = CancellationToken::new(); let (env_tx, env_rx) = oneshot::channel(); - let systemd_env = get_systemd_env().await; + + #[cfg(feature = "systemd")] + let systemd_env = if *is_systemd_used() { + get_systemd_env().await + } else { + Vec::new() + }; + #[cfg(not(feature = "systemd"))] + let systemd_env = Vec::new(); let compositor_handle = comp::run_compositor( &process_manager, executable.clone(), @@ -165,12 +175,13 @@ async fn start( env_vars ); - // now that cosmic-comp is ready, extend the env vars with the systemd_env and set XDG_SESSION_TYPE=wayland for new processes + // now that cosmic-comp is ready, set XDG_SESSION_TYPE=wayland for new processes env_vars.extend( systemd_env .into_iter() .chain([("XDG_SESSION_TYPE".to_string(), "wayland".to_string())]), ); + #[cfg(feature = "systemd")] systemd::set_systemd_environment("XDG_SESSION_TYPE", "wayland").await; // expose the session version @@ -178,42 +189,36 @@ async fn start( "COSMIC_VERSION".to_string(), env!("CARGO_PKG_VERSION").to_string(), )); + #[cfg(feature = "systemd")] systemd::set_systemd_environment("COSMIC_VERSION", env!("CARGO_PKG_VERSION")).await; - #[cfg(feature = "systemd")] - let _inhibit_fd = if *is_systemd_used() { - #[cfg(feature = "logind")] - match zbus::Connection::system().await { - Ok(connection) => match logind_zbus::manager::ManagerProxy::new(&connection).await { - Ok(proxy) => match proxy - .inhibit( - logind_zbus::manager::InhibitType::HandlePowerKey, - "Cosmic Session", - "Show confirmation dialog.", - "block", - ) - .await - { - Ok(fd) => Some(fd), - Err(err) => { - error!("Failed to inhibit power key {err:?}"); - None - } - }, + #[cfg(feature = "logind")] + let _inhibit_fd = match zbus::Connection::system().await { + Ok(connection) => match logind_zbus::manager::ManagerProxy::new(&connection).await { + Ok(proxy) => match proxy + .inhibit( + logind_zbus::manager::InhibitType::HandlePowerKey, + "Cosmic Session", + "Show confirmation dialog.", + "block", + ) + .await + { + Ok(fd) => Some(fd), Err(err) => { - error!("Failed to connect to logind manager {err:?}"); + error!("Failed to inhibit power key {err:?}"); None } }, Err(err) => { - error!("Failed to connect to system dbus {err:?}"); + error!("Failed to connect to logind manager {err:?}"); None } + }, + Err(err) => { + error!("Failed to connect to system dbus {err:?}"); + None } - #[cfg(not(feature = "logind"))] - None - } else { - None }; let stdout_span = info_span!(parent: None, "cosmic-settings-daemon"); @@ -254,8 +259,10 @@ async fn start( // - cosmic-comp is ready // - we've set any related variables // - cosmic-settings-daemon is ready + #[cfg(feature = "systemd")] systemd::start_systemd_target().await; // Always stop the target when the process exits or panics. + #[cfg(feature = "systemd")] scopeguard::defer! { systemd::stop_systemd_target(); } @@ -388,17 +395,17 @@ async fn start( } // skip if we have an OnlyShowIn entry that doesn't include COSMIC - if let Some(only_show_in) = entry.only_show_in() { - if !only_show_in.contains(&ENVIRONMENT_NAME) { - continue; - } + if let Some(only_show_in) = entry.only_show_in() + && !only_show_in.contains(&ENVIRONMENT_NAME) + { + continue; } // ... OR we have a NotShowIn entry that includes COSMIC - if let Some(not_show_in) = entry.not_show_in() { - if not_show_in.contains(&ENVIRONMENT_NAME) { - continue; - } + if let Some(not_show_in) = entry.not_show_in() + && not_show_in.contains(&ENVIRONMENT_NAME) + { + continue; } info!( @@ -417,7 +424,7 @@ async fn start( .collect::>(); // escape them - let escaped_args = shell_words::split(&*filtered_args.join(" ")); + let escaped_args = shell_words::split(&filtered_args.join(" ")); if let Ok(args) = escaped_args { info!("trying to start {} {}", program_name, args.join(" ")); @@ -556,3 +563,11 @@ async fn start_component( error!("failed to start {}: {}", cmd, err); } } + +/// Determine if systemd is used as the init system. This should work on all +/// linux distributions. +#[cfg(any(feature = "autostart", feature = "systemd"))] +fn is_systemd_used() -> &'static bool { + static IS_SYSTEMD_USED: OnceLock = OnceLock::new(); + IS_SYSTEMD_USED.get_or_init(|| Path::new("/run/systemd/system").exists()) +} diff --git a/src/systemd.rs b/src/systemd.rs index 1bad338..77c03e9 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -1,14 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only -use std::path::Path; use std::process::{Command, Stdio}; -use std::sync::OnceLock; -#[cfg(feature = "systemd")] use zbus::Connection; use zbus::zvariant::{Array, OwnedValue}; - -#[cfg(feature = "systemd")] use zbus_systemd::systemd1::ManagerProxy as SystemdManagerProxy; pub async fn set_systemd_environment(key: &str, value: &str) { @@ -32,14 +27,6 @@ pub fn stop_systemd_target() { ) } -/// Determine if systemd is used as the init system. This should work on all -/// linux distributions. -pub fn is_systemd_used() -> &'static bool { - static IS_SYSTEMD_USED: OnceLock = OnceLock::new(); - IS_SYSTEMD_USED.get_or_init(|| Path::new("/run/systemd/system").exists()) -} - -#[cfg(feature = "systemd")] async fn load_systemd_env() -> zbus::Result> { let connection = Connection::session().await?; let systemd_manager = SystemdManagerProxy::new(&connection).await?; @@ -47,18 +34,15 @@ async fn load_systemd_env() -> zbus::Result> { } /// Get the systemd user manager environment variables. -/// Is Empty if systemd isn't used. pub async fn get_systemd_env() -> Vec<(String, String)> { - #[cfg(feature = "systemd")] - if *is_systemd_used() { - return match load_systemd_env().await { - Ok(env) => { - env.iter() - // split into key value pairs - .filter_map(|var| var.split_once("=")) - .filter(|&(key, _value)| { - // Only update the envvar if unset - std::env::var_os(key).is_none() + match load_systemd_env().await { + Ok(env) => { + env.iter() + // split into key value pairs + .filter_map(|var| var.split_once("=")) + .filter(|&(key, _value)| { + // Only update the envvar if unset + std::env::var_os(key).is_none() // Blocklist of envvars that we shouldn't touch (taken from KDE) && (!key.starts_with("XDG_") || key == "XDG_DATA_DIRS" @@ -70,20 +54,17 @@ pub async fn get_systemd_env() -> Vec<(String, String)> { && key != "_" && key != "SHELL" && key != "SHLVL" - }) - .map(|(key, value)| (key.to_owned(), value.to_owned())) - .collect() - } - Err(err) => { - warn!("Failed to sync systemd environment {}.", err); - Vec::new() - } - }; + }) + .map(|(key, value)| (key.to_owned(), value.to_owned())) + .collect() + } + Err(err) => { + warn!("Failed to sync systemd environment {}.", err); + Vec::new() + } } - Vec::new() } -#[cfg(feature = "systemd")] /// Spawn a systemd scope unit with the given name and PIDs. pub async fn spawn_scope(mut command: String, pids: Vec) -> Result<(), zbus::Error> { let connection = Connection::session().await?;