Skip to content

Commit ba9590a

Browse files
authored
feat!: add Listener and Emitter traits (#9640)
* feat!: add `Listener` and `Emitter` traits * keep only trait implementation * change file * fix doctests * fix build
1 parent 1a88fc1 commit ba9590a

14 files changed

Lines changed: 859 additions & 506 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"tauri": "patch:breaking"
3+
---
4+
5+
Added `Emitter` and `Listener` traits that defines what an emitter or a listener can do, this however comes with a few breaking changes:
6+
- Removed `Manager::listen_any`, use `Listener::listen_any` instead.
7+
- Removed `Manager::once_any`, use `Listener::once_any` instead.
8+
- Removed `Manager::unlisten`, use `Listener::unlisten` instead.
9+
- Removed `Manager::emit`, use `Emitter::emit` instead.
10+
- Removed `Manager::emit_to`, use `Emitter::emit_to` instead.
11+
- Removed `Manager::emit_filter`, use `Emitter::emit_filter` instead.
12+
- Removed `App/AppHandle::listen`, `WebviewWindow::listen`, `Window::listen` and `Webview::listen`, use `Listener::listen` instead.
13+
- Removed `App/AppHandle::once`, `WebviewWindow::once`, `Window::once` and `Webview::once`, use `Listener::once` instead.
14+
- Removed `App/AppHandle::unlisten`, `WebviewWindow::unlisten`, `Window::unlisten` and `Webview::unlisten`, use `Listener::unlisten` instead.
15+

core/tauri/src/app.rs

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use crate::{
2222
utils::config::Config,
2323
utils::Env,
2424
webview::PageLoadPayload,
25-
Context, DeviceEventFilter, EventLoopMessage, Manager, Monitor, Runtime, Scopes, StateManager,
26-
Theme, Webview, WebviewWindowBuilder, Window,
25+
Context, DeviceEventFilter, Emitter, EventLoopMessage, Listener, Manager, Monitor, Result,
26+
Runtime, Scopes, StateManager, Theme, Webview, WebviewWindowBuilder, Window,
2727
};
2828

2929
#[cfg(desktop)]
@@ -42,6 +42,7 @@ use tauri_runtime::{
4242
};
4343
use tauri_utils::PackageInfo;
4444

45+
use serde::Serialize;
4546
use std::{
4647
borrow::Cow,
4748
collections::HashMap,
@@ -66,7 +67,7 @@ pub(crate) type GlobalWebviewEventListener<R> =
6667
Box<dyn Fn(&Webview<R>, &WebviewEvent) + Send + Sync>;
6768
/// A closure that is run when the Tauri application is setting up.
6869
pub type SetupHook<R> =
69-
Box<dyn FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send>;
70+
Box<dyn FnOnce(&mut App<R>) -> std::result::Result<(), Box<dyn std::error::Error>> + Send>;
7071
/// A closure that is run every time a page starts or finishes loading.
7172
pub type OnPageLoad<R> = dyn Fn(&Webview<R>, &PageLoadPayload<'_>) + Send + Sync + 'static;
7273

@@ -328,7 +329,7 @@ impl<R: Runtime> Clone for AppHandle<R> {
328329

329330
impl<'de, R: Runtime> CommandArg<'de, R> for AppHandle<R> {
330331
/// Grabs the [`Window`] from the [`CommandItem`] and returns the associated [`AppHandle`]. This will never fail.
331-
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
332+
fn from_command(command: CommandItem<'de, R>) -> std::result::Result<Self, InvokeError> {
332333
Ok(command.message.webview().window().app_handle)
333334
}
334335
}
@@ -820,14 +821,13 @@ macro_rules! shared_app_impl {
820821
}
821822
}
822823

823-
/// Event system APIs.
824-
impl<R: Runtime> $app {
824+
impl<R: Runtime> Listener<R> for $app {
825825
/// Listen to an event on this app.
826826
///
827827
/// # Examples
828828
///
829829
/// ```
830-
/// use tauri::Manager;
830+
/// use tauri::Listener;
831831
///
832832
/// tauri::Builder::default()
833833
/// .setup(|app| {
@@ -838,19 +838,29 @@ macro_rules! shared_app_impl {
838838
/// Ok(())
839839
/// });
840840
/// ```
841-
pub fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
841+
fn listen<F>(&self, event: impl Into<String>, handler: F) -> EventId
842842
where
843843
F: Fn(Event) + Send + 'static,
844844
{
845845
self.manager.listen(event.into(), EventTarget::App, handler)
846846
}
847847

848+
/// Listen to an event on this app only once.
849+
///
850+
/// See [`Self::listen`] for more information.
851+
fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
852+
where
853+
F: FnOnce(Event) + Send + 'static,
854+
{
855+
self.manager.once(event.into(), EventTarget::App, handler)
856+
}
857+
848858
/// Unlisten to an event on this app.
849859
///
850860
/// # Examples
851861
///
852862
/// ```
853-
/// use tauri::Manager;
863+
/// use tauri::Listener;
854864
///
855865
/// tauri::Builder::default()
856866
/// .setup(|app| {
@@ -864,18 +874,82 @@ macro_rules! shared_app_impl {
864874
/// Ok(())
865875
/// });
866876
/// ```
867-
pub fn unlisten(&self, id: EventId) {
877+
fn unlisten(&self, id: EventId) {
868878
self.manager.unlisten(id)
869879
}
880+
}
870881

871-
/// Listen to an event on this app only once.
882+
impl<R: Runtime> Emitter<R> for $app {
883+
/// Emits an event to all [targets](EventTarget).
872884
///
873-
/// See [`Self::listen`] for more information.
874-
pub fn once<F>(&self, event: impl Into<String>, handler: F) -> EventId
885+
/// # Examples
886+
/// ```
887+
/// use tauri::Emitter;
888+
///
889+
/// #[tauri::command]
890+
/// fn synchronize(app: tauri::AppHandle) {
891+
/// // emits the synchronized event to all webviews
892+
/// app.emit("synchronized", ());
893+
/// }
894+
/// ```
895+
fn emit<S: Serialize + Clone>(&self, event: &str, payload: S) -> Result<()> {
896+
self.manager.emit(event, payload)
897+
}
898+
899+
/// Emits an event to all [targets](EventTarget) matching the given target.
900+
///
901+
/// # Examples
902+
/// ```
903+
/// use tauri::{Emitter, EventTarget};
904+
///
905+
/// #[tauri::command]
906+
/// fn download(app: tauri::AppHandle) {
907+
/// for i in 1..100 {
908+
/// std::thread::sleep(std::time::Duration::from_millis(150));
909+
/// // emit a download progress event to all listeners
910+
/// app.emit_to(EventTarget::any(), "download-progress", i);
911+
/// // emit an event to listeners that used App::listen or AppHandle::listen
912+
/// app.emit_to(EventTarget::app(), "download-progress", i);
913+
/// // emit an event to any webview/window/webviewWindow matching the given label
914+
/// app.emit_to("updater", "download-progress", i); // similar to using EventTarget::labeled
915+
/// app.emit_to(EventTarget::labeled("updater"), "download-progress", i);
916+
/// // emit an event to listeners that used WebviewWindow::listen
917+
/// app.emit_to(EventTarget::webview_window("updater"), "download-progress", i);
918+
/// }
919+
/// }
920+
/// ```
921+
fn emit_to<I, S>(&self, target: I, event: &str, payload: S) -> Result<()>
875922
where
876-
F: FnOnce(Event) + Send + 'static,
923+
I: Into<EventTarget>,
924+
S: Serialize + Clone,
877925
{
878-
self.manager.once(event.into(), EventTarget::App, handler)
926+
self.manager.emit_to(target, event, payload)
927+
}
928+
929+
/// Emits an event to all [targets](EventTarget) based on the given filter.
930+
///
931+
/// # Examples
932+
/// ```
933+
/// use tauri::{Emitter, EventTarget};
934+
///
935+
/// #[tauri::command]
936+
/// fn download(app: tauri::AppHandle) {
937+
/// for i in 1..100 {
938+
/// std::thread::sleep(std::time::Duration::from_millis(150));
939+
/// // emit a download progress event to the updater window
940+
/// app.emit_filter("download-progress", i, |t| match t {
941+
/// EventTarget::WebviewWindow { label } => label == "main",
942+
/// _ => false,
943+
/// });
944+
/// }
945+
/// }
946+
/// ```
947+
fn emit_filter<S, F>(&self, event: &str, payload: S, filter: F) -> Result<()>
948+
where
949+
S: Serialize + Clone,
950+
F: Fn(&EventTarget) -> bool,
951+
{
952+
self.manager.emit_filter(event, payload, filter)
879953
}
880954
}
881955
};
@@ -1239,7 +1313,7 @@ tauri::Builder::default()
12391313
#[must_use]
12401314
pub fn setup<F>(mut self, setup: F) -> Self
12411315
where
1242-
F: FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send + 'static,
1316+
F: FnOnce(&mut App<R>) -> std::result::Result<(), Box<dyn std::error::Error>> + Send + 'static,
12431317
{
12441318
self.setup = Box::new(setup);
12451319
self

core/tauri/src/event/plugin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use serde_json::Value as JsonValue;
99
use tauri_runtime::window::is_label_valid;
1010

1111
use crate::plugin::{Builder, TauriPlugin};
12-
use crate::{command, ipc::CallbackFn, EventId, Manager, Result, Runtime};
13-
use crate::{AppHandle, Webview};
12+
use crate::{command, ipc::CallbackFn, EventId, Result, Runtime};
13+
use crate::{AppHandle, Emitter, Webview};
1414

1515
use super::{is_event_name_valid, EventTarget};
1616

0 commit comments

Comments
 (0)