feat(core): panic when a dispatcher getter is used on the main thread (#2455)

This commit is contained in:
Lucas Fernandes Nogueira 2021-08-16 17:28:15 -03:00 committed by GitHub
parent c76f4b7d39
commit 50ffdc06fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 55 deletions

View File

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

View File

@ -112,10 +112,11 @@ pub type WindowMenuEventListeners = Arc<Mutex<HashMap<Uuid, MenuEventHandler>>>;
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

View File

@ -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<bool>;
/// 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<F: Fn() + Send + 'static>(
&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<T: Into<String>>(&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<Option<String>>;
}

View File

@ -313,8 +313,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<f64> {
self.window.dispatcher.scale_factor().map_err(Into::into)
}
@ -323,8 +325,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<PhysicalPosition<i32>> {
self.window.dispatcher.inner_position().map_err(Into::into)
}
@ -333,8 +337,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<PhysicalPosition<i32>> {
self.window.dispatcher.outer_position().map_err(Into::into)
}
@ -345,8 +351,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<PhysicalSize<u32>> {
self.window.dispatcher.inner_size().map_err(Into::into)
}
@ -357,8 +365,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<PhysicalSize<u32>> {
self.window.dispatcher.outer_size().map_err(Into::into)
}
@ -367,8 +377,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<bool> {
self.window.dispatcher.is_fullscreen().map_err(Into::into)
}
@ -377,8 +389,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<bool> {
self.window.dispatcher.is_maximized().map_err(Into::into)
}
@ -387,8 +401,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<bool> {
self.window.dispatcher.is_decorated().map_err(Into::into)
}
@ -397,8 +413,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<bool> {
self.window.dispatcher.is_resizable().map_err(Into::into)
}
@ -407,8 +425,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<bool> {
self.window.dispatcher.is_visible().map_err(Into::into)
}
@ -423,8 +443,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<Option<Monitor>> {
self
.window
@ -444,8 +466,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<Option<Monitor>> {
self
.window
@ -463,8 +487,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<Vec<Monitor>> {
self
.window
@ -478,8 +504,10 @@ impl<R: Runtime> Window<R> {
///
/// # 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<R: Runtime> Window<R> {
///
/// # 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

View File

@ -86,8 +86,10 @@ impl<R: Runtime> MenuHandle<R> {
///
/// # 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<bool> {
self.dispatcher.is_menu_visible().map_err(Into::into)
}
@ -96,8 +98,10 @@ impl<R: Runtime> MenuHandle<R> {
///
/// # 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()