diff --git a/.changes/core-emit-js-all-targets.md b/.changes/core-emit-js-all-targets.md new file mode 100644 index 000000000..6a62a35c5 --- /dev/null +++ b/.changes/core-emit-js-all-targets.md @@ -0,0 +1,5 @@ +--- +'tauri': 'patch:bug' +--- + +Fix `emit` and `emit_to` (when used with `EventTarget::Any`) always skipping the webview listeners. diff --git a/core/tauri/src/event/listener.rs b/core/tauri/src/event/listener.rs index 034e33791..4dc23444a 100644 --- a/core/tauri/src/event/listener.rs +++ b/core/tauri/src/event/listener.rs @@ -16,12 +16,6 @@ use std::{ }, }; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -struct JsHandler { - target: EventTarget, - id: EventId, -} - /// What to do with the pending handler when resolving it? enum Pending { Unlisten(EventId), @@ -48,6 +42,18 @@ impl Handler { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct JsHandler { + target: EventTarget, + id: EventId, +} + +impl JsHandler { + fn new(target: EventTarget, id: EventId) -> Self { + Self { target, id } + } +} + type WebviewLabel = String; type EventName = String; @@ -189,23 +195,16 @@ impl Listeners { F: Fn(&EventTarget) -> bool, { let mut maybe_pending = false; + match self.inner.handlers.try_lock() { Err(_) => self.insert_pending(Pending::Emit(emit_args.clone())), Ok(lock) => { if let Some(handlers) = lock.get(&emit_args.event_name) { - let handlers: Vec<_> = match filter { - Some(filter) => handlers - .iter() - .filter(|(_, Handler { target, .. })| *target == EventTarget::Any || filter(target)) - .collect(), - None => handlers.iter().collect(), - }; - - if !handlers.is_empty() { + let handlers = handlers.iter(); + let handlers = handlers.filter(|(_, h)| match_any_or_filter(&h.target, &filter)); + for (&id, Handler { callback, .. }) in handlers { maybe_pending = true; - for (&id, Handler { callback, .. }) in handlers { - (callback)(Event::new(id, emit_args.payload.clone())) - } + (callback)(Event::new(id, emit_args.payload.clone())) } } } @@ -236,44 +235,26 @@ impl Listeners { .or_default() .entry(event.to_string()) .or_default() - .insert(JsHandler { id, target }); + .insert(JsHandler::new(target, id)); } - pub(crate) fn unlisten_js(&self, id: EventId) { - let mut listeners = self.inner.js_event_listeners.lock().unwrap(); - - let mut empty = None; - let listeners = listeners.values_mut(); - 'outer: for listeners in listeners { - for (key, handlers) in listeners.iter_mut() { - let mut found = false; - - handlers.retain(|h| { - let keep = h.id != id; - if !found { - found = !keep - } - keep - }); + pub(crate) fn unlisten_js(&self, event: &str, id: EventId) { + let mut js_listeners = self.inner.js_event_listeners.lock().unwrap(); + let js_listeners = js_listeners.values_mut(); + for js_listeners in js_listeners { + if let Some(handlers) = js_listeners.get_mut(event) { + handlers.retain(|h| h.id != id); if handlers.is_empty() { - empty.replace(key.clone()); + js_listeners.remove(event); } - - if found { - break 'outer; - } - } - - if let Some(key) = &empty { - listeners.remove(key); } } } pub(crate) fn unlisten_all_js(&self, webview_label: &str) { - let inner_listeners = self.inner.as_ref(); - let mut js_listeners = inner_listeners.js_event_listeners.lock().unwrap(); + let js_listeners = self.inner.as_ref(); + let mut js_listeners = js_listeners.js_event_listeners.lock().unwrap(); js_listeners.remove(webview_label); } @@ -282,11 +263,11 @@ impl Listeners { event: &str, filter: F, ) -> bool { - let listeners = self.inner.js_event_listeners.lock().unwrap(); - listeners.values().any(|events| { + let js_listeners = self.inner.js_event_listeners.lock().unwrap(); + js_listeners.values().any(|events| { events .get(event) - .map(|handlers| handlers.iter().any(|h| filter(&h.target))) + .map(|handlers| handlers.iter().any(|handler| filter(&handler.target))) .unwrap_or(false) }) } @@ -296,20 +277,20 @@ impl Listeners { mut webviews: I, event: &str, emit_args: &EmitArgs, - filter: Option<&F>, + filter: Option, ) -> crate::Result<()> where R: Runtime, I: Iterator>, F: Fn(&EventTarget) -> bool, { - let listeners = self.inner.js_event_listeners.lock().unwrap(); + let js_listeners = self.inner.js_event_listeners.lock().unwrap(); webviews.try_for_each(|webview| { - if let Some(handlers) = listeners.get(webview.label()).and_then(|s| s.get(event)) { + if let Some(handlers) = js_listeners.get(webview.label()).and_then(|s| s.get(event)) { + let handlers = handlers.iter(); + let handlers = handlers.filter(|handler| match_any_or_filter(&handler.target, &filter)); for JsHandler { target, .. } in handlers { - if *target == EventTarget::Any || filter.as_ref().map(|f| f(target)).unwrap_or(false) { - webview.emit_js(emit_args, target)?; - } + webview.emit_js(emit_args, target)?; } } @@ -331,11 +312,19 @@ impl Listeners { webviews, event, emit_args, - None::<&&dyn Fn(&EventTarget) -> bool>, + None::<&dyn Fn(&EventTarget) -> bool>, ) } } +#[inline(always)] +fn match_any_or_filter bool>( + target: &EventTarget, + filter: &Option, +) -> bool { + *target == EventTarget::Any || filter.as_ref().map(|f| f(target)).unwrap_or(true) +} + #[cfg(test)] mod test { use super::*; diff --git a/core/tauri/src/webview/mod.rs b/core/tauri/src/webview/mod.rs index 43b4d168f..0c740d057 100644 --- a/core/tauri/src/webview/mod.rs +++ b/core/tauri/src/webview/mod.rs @@ -1297,7 +1297,7 @@ fn main() { id, ))?; - listeners.unlisten_js(id); + listeners.unlisten_js(event, id); Ok(()) } diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock index b419ca47a..5bd10d413 100644 --- a/examples/api/src-tauri/Cargo.lock +++ b/examples/api/src-tauri/Cargo.lock @@ -172,6 +172,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "bitflags" version = "1.3.2" @@ -1769,9 +1775,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "loom" @@ -2265,7 +2271,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" dependencies = [ - "base64", + "base64 0.21.7", "indexmap 2.2.3", "line-wrap", "quick-xml", @@ -2556,7 +2562,7 @@ version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -2790,7 +2796,7 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ - "base64", + "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", @@ -3019,7 +3025,7 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bbdb58577b6301f8d17ae2561f32002a5bae056d444e0f69e611e504a276204" dependencies = [ - "base64", + "base64 0.21.7", "serde", "serde_json", ] @@ -3145,7 +3151,7 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tauri" -version = "2.0.0-beta.8" +version = "2.0.0-beta.9" dependencies = [ "anyhow", "bytes", @@ -3195,7 +3201,7 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "anyhow", "cargo_toml", @@ -3217,9 +3223,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ - "base64", + "base64 0.22.0", "brotli", "ico", "json-patch", @@ -3242,7 +3248,7 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "heck", "proc-macro2", @@ -3254,7 +3260,7 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "anyhow", "glob", @@ -3280,7 +3286,7 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "gtk", "http", @@ -3296,7 +3302,7 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "cocoa", "gtk", @@ -3318,7 +3324,7 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.0.0-beta.6" +version = "2.0.0-beta.7" dependencies = [ "aes-gcm", "brotli", @@ -4384,7 +4390,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b717040ba9771fd88eb428c6ea6b555f8e734ff8534f02c13e8f10d97f5935e" dependencies = [ - "base64", + "base64 0.21.7", "block", "cfg_aliases 0.1.1", "cocoa", diff --git a/examples/api/src/views/Communication.svelte b/examples/api/src/views/Communication.svelte index e24a86009..2b20b8796 100644 --- a/examples/api/src/views/Communication.svelte +++ b/examples/api/src/views/Communication.svelte @@ -1,13 +1,15 @@