From 90e8e6e10520148dd8d641f9bee3f5fc479f4300 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 14 Mar 2021 15:23:42 -0700 Subject: [PATCH] toast: hook up action/event handling on Windows refs: #489 --- Cargo.lock | 93 +++++++++++-------- wezterm-toast-notification/Cargo.toml | 6 +- wezterm-toast-notification/build.rs | 8 ++ wezterm-toast-notification/src/lib.rs | 4 +- wezterm-toast-notification/src/windows.rs | 108 +++++++++++++++++++--- 5 files changed, 167 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80b0f573a..7f2e0fcac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3664,27 +3664,6 @@ dependencies = [ "syn", ] -[[package]] -name = "strum" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "svg_fmt" version = "0.4.1" @@ -4520,7 +4499,7 @@ dependencies = [ "wezterm-toast-notification", "winapi 0.3.9", "window", - "windows", + "windows 0.3.1", ] [[package]] @@ -4619,7 +4598,8 @@ dependencies = [ "objc", "open", "serde", - "winrt-notification", + "windows 0.4.0", + "xml-rs", "zbus", "zvariant", ] @@ -4731,11 +4711,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "426842497696b65fbfc575691d94ef65befb248ed1a8c4361e293c724e7ebe61" dependencies = [ "const-sha1", - "windows_gen", - "windows_macros", + "windows_gen 0.3.1", + "windows_macros 0.3.1", "windows_winmd", ] +[[package]] +name = "windows" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "015de964f21e0b20b9744ebc6f3a3e4dfdd1788f133a4aeec09c035748f88a21" +dependencies = [ + "const-sha1", + "windows_gen 0.4.0", + "windows_macros 0.4.0", +] + [[package]] name = "windows_gen" version = "0.3.1" @@ -4746,10 +4737,23 @@ dependencies = [ "quote", "squote", "syn", - "windows_gen_macros", + "windows_gen_macros 0.3.1", "windows_winmd", ] +[[package]] +name = "windows_gen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70028758c92f5ed61ce12ab8e7482dce152418bac41dbefe794511b9fb673022" +dependencies = [ + "proc-macro2", + "quote", + "squote", + "syn", + "windows_gen_macros 0.4.0", +] + [[package]] name = "windows_gen_macros" version = "0.3.1" @@ -4761,6 +4765,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows_gen_macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a4e4aa3c108fc3112bb797662b14958d088d3b989f2560d89335775c566c88d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows_macros" version = "0.3.1" @@ -4771,10 +4786,23 @@ dependencies = [ "quote", "squote", "syn", - "windows_gen", + "windows_gen 0.3.1", "windows_winmd", ] +[[package]] +name = "windows_macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e5b872245607ec18bf35eaa7a6146831c07449c0b724afd7403d732c6da856" +dependencies = [ + "proc-macro2", + "quote", + "squote", + "syn", + "windows_gen 0.4.0", +] + [[package]] name = "windows_winmd" version = "0.3.1" @@ -4813,17 +4841,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "winrt-notification" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c285268f30382d46eac2c5a8068fa9bbf90b07a3b57196e171aea0cefbb7540" -dependencies = [ - "strum", - "windows", - "xml-rs", -] - [[package]] name = "wio" version = "0.2.2" diff --git a/wezterm-toast-notification/Cargo.toml b/wezterm-toast-notification/Cargo.toml index f42c06362..1466f7da7 100644 --- a/wezterm-toast-notification/Cargo.toml +++ b/wezterm-toast-notification/Cargo.toml @@ -22,4 +22,8 @@ core-foundation = "0.7" objc = "0.2" [target.'cfg(windows)'.dependencies] -winrt-notification = "0.3" +windows = "0.4" +xml-rs = "0.8" + +[target.'cfg(windows)'.build-dependencies] +windows = "0.4" diff --git a/wezterm-toast-notification/build.rs b/wezterm-toast-notification/build.rs index 5ecc6da67..a93316813 100644 --- a/wezterm-toast-notification/build.rs +++ b/wezterm-toast-notification/build.rs @@ -2,4 +2,12 @@ fn main() { if cfg!(target_os = "macos") { println!("cargo:rustc-link-lib=framework=UserNotifications"); } + #[cfg(windows)] + { + windows::build!( + windows::data::xml::dom::XmlDocument, + windows::foundation::*, + windows::ui::notifications::*, + ); + } } diff --git a/wezterm-toast-notification/src/lib.rs b/wezterm-toast-notification/src/lib.rs index 1586868c3..663c85c87 100644 --- a/wezterm-toast-notification/src/lib.rs +++ b/wezterm-toast-notification/src/lib.rs @@ -2,12 +2,12 @@ mod dbus; mod macos; mod windows; +#[cfg(windows)] +use crate::windows as backend; #[cfg(all(not(target_os = "macos"), not(windows), not(target_os = "freebsd")))] use dbus as backend; #[cfg(target_os = "macos")] use macos as backend; -#[cfg(windows)] -use windows as backend; mod nop { #[allow(dead_code)] diff --git a/wezterm-toast-notification/src/windows.rs b/wezterm-toast-notification/src/windows.rs index a02483f63..312518a39 100644 --- a/wezterm-toast-notification/src/windows.rs +++ b/wezterm-toast-notification/src/windows.rs @@ -1,28 +1,114 @@ #![cfg(windows)] -use winrt_notification::{Duration, Toast}; + +use xml::escape::escape_str_pcdata; + +#[allow(dead_code)] +mod bindings { + ::windows::include_bindings!(); +} + +use bindings::{ + windows::data::xml::dom::XmlDocument, windows::foundation::*, windows::ui::notifications::*, +}; +use windows::{Error as WinError, Interface, Object}; + +fn unwrap_arg(a: &Option) -> Result<&T, WinError> { + match a { + Some(t) => Ok(t), + None => Err(WinError::new( + ::windows::ErrorCode::E_POINTER, + "option is none", + )), + } +} + +fn show_notif_impl( + title: String, + message: String, + url: Option, +) -> Result<(), Box> { + let xml = XmlDocument::new()?; + + let url_actions = if url.is_some() { + r#" + + + + "# + } else { + "" + }; + + xml.load_xml(format!( + r#" + + + {} + {} + + + {} + "#, + escape_str_pcdata(&title), + escape_str_pcdata(&message), + url_actions + ))?; + + let notif = ToastNotification::create_toast_notification(xml)?; + + notif.activated(TypedEventHandler::new( + move |_: &Option, result: &Option| { + // let myself = unwrap_arg(myself)?; + let result = unwrap_arg(result)?.cast::()?; + + let args = result.arguments()?; + + if args == "show" { + if let Some(url) = url.as_ref() { + let _ = open::that(url); + } + } + + Ok(()) + }, + ))?; + + /* + notif.dismissed(TypedEventHandler::new(|sender, result| { + log::info!("dismissed {:?}", result); + Ok(()) + }))?; + + notif.failed(TypedEventHandler::new(|sender, result| { + log::warn!("toasts are disabled {:?}", result); + Ok(()) + }))?; + */ + + let notifier = + ToastNotificationManager::create_toast_notifier_with_id("org.wezfurlong.wezterm")?; + + notifier.show(¬if)?; + + Ok(()) +} pub fn show_notif( title: &str, message: &str, url: Option<&str>, ) -> Result<(), Box> { - if url.is_some() { - return Ok(()); - } - let title = title.to_owned(); let message = message.to_owned(); + let url = url.map(|s| s.to_string()); // We need to be in a different thread from the caller // in case we get called in the guts of a windows message // loop dispatch and are unable to pump messages std::thread::spawn(move || { - Toast::new("org.wezfurlong.wezterm") - .title(&title) - .text1(&message) - .duration(Duration::Long) - .show() - .ok(); + if let Err(err) = show_notif_impl(title, message, url) { + log::error!("Failed to show toast notification: {:#}", err); + } }); Ok(())