diff --git a/src/comp.rs b/src/comp.rs index 8457d08..31ef79a 100644 --- a/src/comp.rs +++ b/src/comp.rs @@ -99,6 +99,7 @@ pub fn run_compositor( process_manager: &ProcessManager, exec: String, args: Vec, + env: Vec<(String, String)>, _token: CancellationToken, env_tx: oneshot::Sender>, session_dbus_tx: mpsc::Sender, @@ -119,6 +120,7 @@ pub fn run_compositor( OwnedFd::from(std_stream) }; mark_as_not_cloexec(&comp).expect("Failed to mark fd as not cloexec"); + Ok(tokio::spawn(async move { // Create a new process handler for cosmic-comp, with our compositor socket's // file descriptor as the `COSMIC_SESSION_SOCK` environment variable. @@ -127,7 +129,10 @@ pub fn run_compositor( Process::new() .with_executable(exec) .with_args(args) - .with_env([("COSMIC_SESSION_SOCK", comp.as_raw_fd().to_string())]) + .with_env(env.into_iter().chain([( + "COSMIC_SESSION_SOCK".to_string(), + comp.as_raw_fd().to_string(), + )])) .with_on_exit(move |pman, _, err_code, _will_restart| { let session_dbus_tx = session_dbus_tx.clone(); async move { diff --git a/src/main.rs b/src/main.rs index 20b8651..989eb44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,9 +24,9 @@ use std::path::PathBuf; #[cfg(feature = "autostart")] use std::process::{Command, Stdio}; use std::sync::Arc; -use systemd::is_systemd_used; #[cfg(feature = "systemd")] -use systemd::{get_systemd_env, spawn_scope}; +use systemd::spawn_scope; +use systemd::{get_systemd_env, is_systemd_used}; use tokio::signal::unix::{SignalKind, signal}; use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::{Mutex, oneshot}; @@ -143,10 +143,12 @@ async fn start( .await; let token = CancellationToken::new(); let (env_tx, env_rx) = oneshot::channel(); + let systemd_env = get_systemd_env().await; let compositor_handle = comp::run_compositor( &process_manager, executable.clone(), args, + systemd_env.clone(), token.child_token(), env_tx, session_tx, @@ -163,8 +165,12 @@ async fn start( env_vars ); - // now that cosmic-comp is ready, set XDG_SESSION_TYPE=wayland for new processes - env_vars.push(("XDG_SESSION_TYPE".to_string(), "wayland".to_string())); + // now that cosmic-comp is ready, extend the env vars with the systemd_env and set XDG_SESSION_TYPE=wayland for new processes + env_vars.extend( + systemd_env + .into_iter() + .chain([("XDG_SESSION_TYPE".to_string(), "wayland".to_string())]), + ); systemd::set_systemd_environment("XDG_SESSION_TYPE", "wayland").await; // expose the session version @@ -176,32 +182,6 @@ async fn start( #[cfg(feature = "systemd")] let _inhibit_fd = if *is_systemd_used() { - match get_systemd_env().await { - Ok(env) => { - for systemd_env in env { - // Only update the envvar if unset - if std::env::var_os(&systemd_env.key).is_none() { - // Blacklist of envvars that we shouldn't touch (taken from KDE) - if (!systemd_env.key.starts_with("XDG_") - || systemd_env.key == "XDG_DATA_DIRS" - || systemd_env.key == "XDG_CONFIG_DIRS") - && systemd_env.key != "DISPLAY" - && systemd_env.key != "XAUTHORITY" - && systemd_env.key != "WAYLAND_DISPLAY" - && systemd_env.key != "WAYLAND_SOCKET" - && systemd_env.key != "_" - && systemd_env.key != "SHELL" - && systemd_env.key != "SHLVL" - { - env_vars.push((systemd_env.key, systemd_env.value)); - } - } - } - } - Err(err) => { - warn!("Failed to sync systemd environment {}.", err); - } - }; #[cfg(feature = "logind")] match zbus::Connection::system().await { Ok(connection) => match logind_zbus::manager::ManagerProxy::new(&connection).await { diff --git a/src/systemd.rs b/src/systemd.rs index cbf64d5..1bad338 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -4,24 +4,10 @@ use std::path::Path; use std::process::{Command, Stdio}; use std::sync::OnceLock; +#[cfg(feature = "systemd")] use zbus::Connection; use zbus::zvariant::{Array, OwnedValue}; -#[derive(Debug)] -pub struct EnvVar { - pub key: String, - pub value: String, -} - -impl From<(&str, &str)> for EnvVar { - fn from(val: (&str, &str)) -> Self { - EnvVar { - key: val.0.to_owned(), - value: val.1.to_owned(), - } - } -} - #[cfg(feature = "systemd")] use zbus_systemd::systemd1::ManagerProxy as SystemdManagerProxy; @@ -54,18 +40,47 @@ pub fn is_systemd_used() -> &'static bool { } #[cfg(feature = "systemd")] -pub async fn get_systemd_env() -> Result, zbus::Error> { +async fn load_systemd_env() -> zbus::Result> { let connection = Connection::session().await?; let systemd_manager = SystemdManagerProxy::new(&connection).await?; - let systemd_env = systemd_manager.environment().await?; + systemd_manager.environment().await +} - let mut out: Vec = Vec::new(); - for i in systemd_env { - if let Some(b) = i.split_once("=") { - out.push(b.into()); - } +/// 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() + // Blocklist of envvars that we shouldn't touch (taken from KDE) + && (!key.starts_with("XDG_") + || key == "XDG_DATA_DIRS" + || key == "XDG_CONFIG_DIRS") + && key != "DISPLAY" + && key != "XAUTHORITY" + && key != "WAYLAND_DISPLAY" + && key != "WAYLAND_SOCKET" + && 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() + } + }; } - Ok(out) + Vec::new() } #[cfg(feature = "systemd")]