diff --git a/README.md b/README.md index 48db795..9a1ac2f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ software. AUR package: `dfmd-git` -If some other handler takes precedence over this one, try copying the DBus +If some other handler takes precedence over this one, try copying the D-Bus service file into your user directory. Also make sure no other service is running while executing `dfmd`. @@ -31,7 +31,7 @@ cp /usr/share/dbus-1/services/sh.natty.FileManager1.service "$XDG_DATA_HOME/dbus ## Dependencies -- DBus +- D-Bus - xdg-open as the default handler ## Building @@ -42,20 +42,20 @@ cargo build --release ## Configuration -Use the DFMD_*_PROGRAM environment variables. `%ARGS%` is substituted with a -list of input files. +Use the DFMD_*_PROGRAM environment variables. Filenames are provided via stdin, +one per line. ### Default handler programs ```sh -DFMD_FOLDER_PROGRAM="echo %ARGS% | xargs -n1 xdg-open" -DFMD_ITEMS_PROGRAM="echo %ARGS% | xargs -d ' ' -r -n1 dirname | xargs -n1 xdg-open" -DFMD_PROPERTIES_PROGRAM="echo %ARGS% | xargs -n1 xdg-open" +DFMD_FOLDER_PROGRAM="xargs -r -n1 xdg-open" +DFMD_ITEMS_PROGRAM="xargs -r -n1 dirname | xargs -n1 xdg-open" +DFMD_PROPERTIES_PROGRAM="xargs -r -n1 xdg-open" ``` ## Autostart -Create a DBus service in +Create a D-Bus service in `$XDG_DATA_HOME/dbus-1/services/org.freedesktop.FileManager1.service`. (The default directory for `XDG_DATA_HOME` is `$HOME/.local/share/`) @@ -76,5 +76,5 @@ can be overridden using `env`: ``` [D-BUS Service] Name=org.freedesktop.FileManager1 -Exec=env DFMD_ITEMS_PROGRAM="echo %ARGS% | xargs -d ' ' -r -n1 dirname | xargs -n1 notify-send 'File opened'" /usr/bin/dfmd +Exec=env DFMD_ITEMS_PROGRAM="xargs -r -n1 dirname | xargs -n1 notify-send 'File opened'" /usr/bin/dfmd ``` diff --git a/src/main.rs b/src/main.rs index 54fa4f5..68dfc32 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ -use std::{env, future::pending}; +use std::{env, future::pending, process::Stdio}; -use tokio::process; +use tokio::{io::AsyncWriteExt, process}; use tracing::{error, Level}; use zbus::ConnectionBuilder; use zbus_macros::dbus_interface; @@ -14,47 +14,78 @@ struct FileManager { #[dbus_interface(name = "org.freedesktop.FileManager1")] impl FileManager { async fn show_folders(&self, ref uris: Vec, _startup_id: &str) { - process::Command::new("sh") - .args([ - "-c", - &self.show_folder_program.replace("%ARGS%", &uris.join(" ")), - ]) + let Ok(mut proc) = process::Command::new("sh") + .args(["-c", &self.show_folder_program]) + .stdin(Stdio::piped()) .spawn() .map_err(|e| { error!("Failed to run file manager: {}", e); e }) - .ok(); + else { + return; + }; + + let data = uris.join("\n"); + let Some(mut stdin) = proc.stdin.take() else { + error!("No process stdin!"); + return; + }; + tokio::spawn(async move { + if let Err(e) = stdin.write_all(data.as_bytes()).await { + error!("Write error: {}", e) + } + }); } async fn show_items(&self, uris: Vec, _startup_id: &str) { - process::Command::new("sh") - .args([ - "-c", - &self.show_items_program.replace("%ARGS%", &uris.join(" ")), - ]) + let Ok(mut proc) = process::Command::new("sh") + .args(["-c", &self.show_items_program]) + .stdin(Stdio::piped()) .spawn() .map_err(|e| { error!("Failed to run file manager: {}", e); e }) - .ok(); + else { + return; + }; + + let data = uris.join("\n"); + let Some(mut stdin) = proc.stdin.take() else { + error!("No process stdin!"); + return; + }; + tokio::spawn(async move { + if let Err(e) = stdin.write_all(data.as_bytes()).await { + error!("Write error: {}", e) + } + }); } async fn show_item_properties(&self, ref uris: Vec, _startup_id: &str) { - process::Command::new("sh") - .args([ - "-c", - &self - .show_properties_program - .replace("%ARGS%", &uris.join(" ")), - ]) + let Ok(mut proc) = process::Command::new("sh") + .args(["-c", &self.show_properties_program]) + .stdin(Stdio::piped()) .spawn() .map_err(|e| { error!("Failed to run file manager: {}", e); e }) - .ok(); + else { + return; + }; + + let data = uris.join("\n"); + let Some(mut stdin) = proc.stdin.take() else { + error!("No process stdin!"); + return; + }; + tokio::spawn(async move { + if let Err(e) = stdin.write_all(data.as_bytes()).await { + error!("Write error: {}", e) + } + }); } } @@ -64,15 +95,15 @@ async fn main() -> eyre::Result<()> { let show_folder_program = env::var("DFMD_FOLDER_PROGRAM") .ok() - .unwrap_or_else(|| r#"echo %ARGS% | xargs -n1 xdg-open"#.to_string()); + .unwrap_or_else(|| r#"xargs -r -n1 xdg-open"#.to_string()); - let show_items_program = env::var("DFMD_ITEMS_PROGRAM").ok().unwrap_or_else(|| { - r#"echo %ARGS% | xargs -d ' ' -r -n1 dirname | xargs -n1 xdg-open"#.to_string() - }); + let show_items_program = env::var("DFMD_ITEMS_PROGRAM") + .ok() + .unwrap_or_else(|| r#"xargs -r -n1 dirname | xargs -n1 xdg-open"#.to_string()); let show_properties_program = env::var("DFMD_PROPERTIES_PROGRAM") .ok() - .unwrap_or_else(|| r#"echo %ARGS% | xargs -n1 xdg-open"#.to_string()); + .unwrap_or_else(|| r#"xargs -r -n1 xdg-open"#.to_string()); let _conn = ConnectionBuilder::session()? .name("org.freedesktop.FileManager1")?