diff --git a/.changes/panic-dispatcher-getter-main-thread.md b/.changes/panic-dispatcher-getter-main-thread.md new file mode 100644 index 000000000..157e6ee5d --- /dev/null +++ b/.changes/panic-dispatcher-getter-main-thread.md @@ -0,0 +1,7 @@ +--- +"tauri": patch +"tauri-runtime": patch +"tauri-runtime-wry": patch +--- + +Panic when a dispatcher getter method (`Window`, `GlobalShortcutHandle`, `ClipboardManager` and `MenuHandle` APIs) is called on the main thread. diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index d41646f1c..6ca5a62b8 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -112,10 +112,11 @@ pub type WindowMenuEventListeners = Arc>>; macro_rules! dispatcher_getter { ($self: ident, $message: expr) => {{ - if current_thread().id() == $self.context.main_thread_id - && !$self.context.is_event_loop_running.load(Ordering::Relaxed) - { - panic!("This API cannot be called when the event loop is not running"); + if current_thread().id() == $self.context.main_thread_id { + panic!("This API cannot be called on the main thread. Try using `std::thread::spawn` or `tauri::async_runtime::spawn`."); + } + if !$self.context.is_event_loop_running.load(Ordering::Relaxed) { + panic!("This API cannot be called when the event loop is not running. Try using `std::thread::spawn` or `tauri::async_runtime::spawn`."); } let (tx, rx) = channel(); $self @@ -129,10 +130,11 @@ macro_rules! dispatcher_getter { macro_rules! getter { ($self: ident, $rx: expr, $message: expr) => {{ - if current_thread().id() == $self.context.main_thread_id - && !$self.context.is_event_loop_running.load(Ordering::Relaxed) - { - panic!("This API cannot be called when the event loop is not running"); + if current_thread().id() == $self.context.main_thread_id { + panic!("This API cannot be called on the main thread. Try using `std::thread::spawn` or `tauri::async_runtime::spawn`."); + } + if !$self.context.is_event_loop_running.load(Ordering::Relaxed) { + panic!("This API cannot be called when the event loop is not running. Try using `std::thread::spawn` or `tauri::async_runtime::spawn`."); } $self .context diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs index 80a8a833b..7803f6a25 100644 --- a/core/tauri-runtime/src/lib.rs +++ b/core/tauri-runtime/src/lib.rs @@ -258,16 +258,20 @@ pub trait GlobalShortcutManager: Debug { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn is_registered(&self, accelerator: &str) -> crate::Result; /// Register a global shortcut of `accelerator`. /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn register( &mut self, accelerator: &str, @@ -278,16 +282,20 @@ pub trait GlobalShortcutManager: Debug { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn unregister_all(&mut self) -> crate::Result<()>; /// Unregister the provided `accelerator`. /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn unregister(&mut self, accelerator: &str) -> crate::Result<()>; } @@ -297,16 +305,19 @@ pub trait ClipboardManager: Debug { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. - + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn write_text>(&mut self, text: T) -> Result<()>; /// Read the content in the clipboard as plain text. /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the `tauri::Builder#setup` closure. - /// You can spawn a task to use the API using the `tauri::async_runtime` to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the `tauri::Builder#setup` closure. + /// - Panics when called on the main thread, usually on the `tauri::App#run`closure. + /// + /// You can spawn a task to use the API using `tauri::async_runtime::spawn` or [`std::thread::spawn`] to prevent the panic. fn read_text(&self) -> Result>; } diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 90fb29bf1..3a7b8aa65 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -313,8 +313,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn scale_factor(&self) -> crate::Result { self.window.dispatcher.scale_factor().map_err(Into::into) } @@ -323,8 +325,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn inner_position(&self) -> crate::Result> { self.window.dispatcher.inner_position().map_err(Into::into) } @@ -333,8 +337,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn outer_position(&self) -> crate::Result> { self.window.dispatcher.outer_position().map_err(Into::into) } @@ -345,8 +351,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn inner_size(&self) -> crate::Result> { self.window.dispatcher.inner_size().map_err(Into::into) } @@ -357,8 +365,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn outer_size(&self) -> crate::Result> { self.window.dispatcher.outer_size().map_err(Into::into) } @@ -367,8 +377,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_fullscreen(&self) -> crate::Result { self.window.dispatcher.is_fullscreen().map_err(Into::into) } @@ -377,8 +389,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_maximized(&self) -> crate::Result { self.window.dispatcher.is_maximized().map_err(Into::into) } @@ -387,8 +401,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_decorated(&self) -> crate::Result { self.window.dispatcher.is_decorated().map_err(Into::into) } @@ -397,8 +413,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_resizable(&self) -> crate::Result { self.window.dispatcher.is_resizable().map_err(Into::into) } @@ -407,8 +425,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_visible(&self) -> crate::Result { self.window.dispatcher.is_visible().map_err(Into::into) } @@ -423,8 +443,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn current_monitor(&self) -> crate::Result> { self .window @@ -444,8 +466,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn primary_monitor(&self) -> crate::Result> { self .window @@ -463,8 +487,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn available_monitors(&self) -> crate::Result> { self .window @@ -478,8 +504,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. #[cfg(target_os = "macos")] pub fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void> { self.window.dispatcher.ns_window().map_err(Into::into) @@ -488,8 +516,10 @@ impl Window { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. #[cfg(windows)] pub fn hwnd(&self) -> crate::Result<*mut std::ffi::c_void> { self diff --git a/core/tauri/src/window/menu.rs b/core/tauri/src/window/menu.rs index 1c776feec..bd3561575 100644 --- a/core/tauri/src/window/menu.rs +++ b/core/tauri/src/window/menu.rs @@ -86,8 +86,10 @@ impl MenuHandle { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn is_visible(&self) -> crate::Result { self.dispatcher.is_menu_visible().map_err(Into::into) } @@ -96,8 +98,10 @@ impl MenuHandle { /// /// # Panics /// - /// Panics if the app is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. - /// You can spawn a task to use the API using the [`async_runtime`](crate::async_runtime) to prevent the panic. + /// - Panics if the event loop is not running yet, usually when called on the [`setup`](crate::Builder#method.setup) closure. + /// - Panics when called on the main thread, usually on the [`run`](crate::App#method.run) closure. + /// + /// You can spawn a task to use the API using [`crate::async_runtime::spawn`] or [`std::thread::spawn`] to prevent the panic. pub fn toggle(&self) -> crate::Result<()> { if self.is_visible()? { self.hide()