From 621de17cad02346f256a50f285ed746c83e3c1f1 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 24 Jul 2024 18:40:18 -0700 Subject: [PATCH] Call systemd `StartTransientUnit` what starting app This is needed for things like `xdg-desktop-portal` to get the app ID from a pid, in unsandboxed apps. https://systemd.io/DESKTOP_ENVIRONMENTS documents this, and this sets things similarly to how Gnome does. Which should be good for now. Making `spawn_desktop_exec` an `async` function is reasonable given it is called in `async` functions in `cosmic-app-list`/`cosmic-launcher`/`cosmic-applibrary`. --- Cargo.toml | 4 +++- src/desktop.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a917aa8..0cb519a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,9 @@ desktop = [ "dep:freedesktop-desktop-entry", "dep:mime", "dep:shlex", + "dep:tokio", "dep:textdistance", + "dep:zbus", ] # Enables keycode serialization serde-keycode = ["iced_core/serde"] @@ -96,7 +98,7 @@ tokio = { version = "1.24.2", optional = true } tracing = "0.1" unicode-segmentation = "1.6" url = "2.4.0" -zbus = { version = "4.2.1", default-features = false, optional = true } +zbus = { version = "4.2.1", default-features = false, features = ["tokio"], optional = true } [target.'cfg(unix)'.dependencies] freedesktop-icons = "0.2.5" diff --git a/src/desktop.rs b/src/desktop.rs index cb3fc846..a4aaf5c0 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -7,6 +7,7 @@ use std::{ ffi::OsStr, path::{Path, PathBuf}, }; +use zbus::zvariant; #[derive(Debug, Clone, PartialEq, Eq)] pub enum IconSource { @@ -306,7 +307,7 @@ impl DesktopEntryData { } } -pub fn spawn_desktop_exec(exec: S, env_vars: I) +pub async fn spawn_desktop_exec(exec: S, env_vars: I, app_id: Option<&str>) where S: AsRef, I: IntoIterator, @@ -314,11 +315,14 @@ where V: AsRef, { let mut exec = shlex::Shlex::new(exec.as_ref()); - let mut cmd = match exec.next() { - Some(cmd) if !cmd.contains('=') => std::process::Command::new(cmd), + + let executable = match exec.next() { + Some(executable) if !executable.contains('=') => executable, _ => return, }; + let mut cmd = std::process::Command::new(&executable); + for arg in exec { // TODO handle "%" args here if necessary? if !arg.starts_with('%') { @@ -328,5 +332,53 @@ where cmd.envs(env_vars); - crate::process::spawn(cmd); + // https://systemd.io/DESKTOP_ENVIRONMENTS + // + // Similar to what Gnome sets, for now. + if let Ok(Some(pid)) = tokio::task::spawn_blocking(|| crate::process::spawn(cmd)).await { + if let Ok(session) = zbus::Connection::session().await { + if let Ok(systemd_manager) = SystemdMangerProxy::new(&session).await { + let _ = systemd_manager + .start_transient_unit( + &format!("app-cosmic-{}-{}.scope", app_id.unwrap_or(&executable), pid), + "fail", + &[ + ( + "Description".to_string(), + zvariant::Value::from("Application launched by COSMIC") + .try_to_owned() + .unwrap(), + ), + ( + "PIDs".to_string(), + zvariant::Value::from(vec![pid]).try_to_owned().unwrap(), + ), + ( + "CollectMode".to_string(), + zvariant::Value::from("inactive-or-failed") + .try_to_owned() + .unwrap(), + ), + ], + &[], + ) + .await; + } + } + } +} + +#[zbus::proxy( + interface = "org.freedesktop.systemd1.Manager", + default_service = "org.freedesktop.systemd1", + default_path = "/org/freedesktop/systemd1" +)] +trait SystemdManger { + async fn start_transient_unit( + &self, + name: &str, + mode: &str, + properties: &[(String, zvariant::OwnedValue)], + aux: &[(String, Vec<(String, zvariant::OwnedValue)>)], + ) -> zbus::Result; }