aboutsummaryrefslogtreecommitdiff
path: root/src/platform/linux.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/linux.rs')
-rw-r--r--src/platform/linux.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 13aa6ec8..6823cca8 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -155,6 +155,43 @@ pub fn write_clipboard(bytes: &[u8]) -> bool {
false
}
+/// Show a native desktop notification through libnotify's command-line helper.
+pub fn show_desktop_notification(title: &str, body: Option<&str>) -> std::io::Result<bool> {
+ show_desktop_notification_with_command(title, body, |program| Command::new(program))
+}
+
+fn show_desktop_notification_with_command(
+ title: &str,
+ body: Option<&str>,
+ mut command: impl FnMut(&str) -> Command,
+) -> std::io::Result<bool> {
+ if std::env::var_os("DISPLAY").is_none() && std::env::var_os("WAYLAND_DISPLAY").is_none() {
+ return Ok(false);
+ }
+
+ let mut cmd = command("notify-send");
+ cmd.arg("--").arg(title);
+ if let Some(body) = body.filter(|body| !body.is_empty()) {
+ cmd.arg(body);
+ }
+ run_notification_command(cmd)
+}
+
+fn run_notification_command(mut command: Command) -> std::io::Result<bool> {
+ let status = match command
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ {
+ Ok(status) => status,
+ Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(false),
+ Err(err) => return Err(err),
+ };
+
+ Ok(status.success())
+}
+
fn clipboard_commands() -> Vec<ClipboardCommand> {
let mut commands = Vec::new();
@@ -248,4 +285,31 @@ mod tests {
assert_eq!(commands[0].program, "xclip");
assert_eq!(commands[1].program, "xsel");
}
+
+ #[test]
+ fn desktop_notification_separates_option_like_titles() {
+ let _guard = env_lock().lock().unwrap();
+ unsafe {
+ std::env::remove_var("WAYLAND_DISPLAY");
+ std::env::set_var("DISPLAY", ":0");
+ }
+
+ let path =
+ std::env::temp_dir().join(format!("herdr-notify-send-args-{}", std::process::id()));
+ let script = "printf '%s\\n' \"$@\" > \"$HERDR_NOTIFY_ARGS\"";
+ let shown = show_desktop_notification_with_command("-danger", Some("body"), |_| {
+ let mut cmd = Command::new("sh");
+ cmd.arg("-c")
+ .arg(script)
+ .arg("notify-send")
+ .env("HERDR_NOTIFY_ARGS", &path);
+ cmd
+ })
+ .expect("notification command should run");
+
+ assert!(shown);
+ let args = std::fs::read_to_string(&path).expect("args file");
+ let _ = std::fs::remove_file(&path);
+ assert_eq!(args, "--\n-danger\nbody\n");
+ }
}