1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-22 12:51:31 +03:00

toast: hook up action/event handling on Windows

refs: #489
This commit is contained in:
Wez Furlong 2021-03-14 15:23:42 -07:00
parent 46227a741f
commit 90e8e6e105
5 changed files with 167 additions and 52 deletions

93
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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::*,
);
}
}

View File

@ -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)]

View File

@ -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<T>(a: &Option<T>) -> 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<String>,
) -> Result<(), Box<dyn std::error::Error>> {
let xml = XmlDocument::new()?;
let url_actions = if url.is_some() {
r#"
<actions>
<action content="Show" arguments="show" />
</actions>
"#
} else {
""
};
xml.load_xml(format!(
r#"<toast duration="long">
<visual>
<binding template="ToastGeneric">
<text>{}</text>
<text>{}</text>
</binding>
</visual>
{}
</toast>"#,
escape_str_pcdata(&title),
escape_str_pcdata(&message),
url_actions
))?;
let notif = ToastNotification::create_toast_notification(xml)?;
notif.activated(TypedEventHandler::new(
move |_: &Option<ToastNotification>, result: &Option<Object>| {
// let myself = unwrap_arg(myself)?;
let result = unwrap_arg(result)?.cast::<ToastActivatedEventArgs>()?;
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(&notif)?;
Ok(())
}
pub fn show_notif(
title: &str,
message: &str,
url: Option<&str>,
) -> Result<(), Box<dyn std::error::Error>> {
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(())