diff --git a/.changes/set-activation-policy-at-runtime.md b/.changes/set-activation-policy-at-runtime.md new file mode 100644 index 000000000000..9c33ae9ee960 --- /dev/null +++ b/.changes/set-activation-policy-at-runtime.md @@ -0,0 +1,7 @@ +--- +"tauri": patch +--- + +macOS: Added `Window.set_activation_policy_at_runtime` method, which allows +dynamically changing the activation policy (previously only possible at +application-build time). diff --git a/.changes/show-hide-application.md b/.changes/show-hide-application.md new file mode 100644 index 000000000000..fa856e47a787 --- /dev/null +++ b/.changes/show-hide-application.md @@ -0,0 +1,7 @@ +--- +"tauri": patch +--- + +macOS: Added `Window.show_application` and `Window.hide_application` method, +which shows or hides the entire app. The `Window.show` and `Window.hide` +methods are unaffected by this change. \ No newline at end of file diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 5512330d926b..d3dae10bd48b 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -28,6 +28,9 @@ use tauri_runtime::{SystemTray, SystemTrayEvent}; use webview2_com::FocusChangedEventHandler; #[cfg(windows)] use windows::Win32::{Foundation::HWND, System::WinRT::EventRegistrationToken}; + +#[cfg(target_os = "macos")] +use wry::application::platform::macos::EventLoopWindowTargetExtMacOS; #[cfg(all(feature = "system-tray", target_os = "macos"))] use wry::application::platform::macos::{SystemTrayBuilderExtMacOS, SystemTrayExtMacOS}; #[cfg(target_os = "linux")] @@ -388,6 +391,16 @@ impl std::fmt::Debug for NativeImageWrapper { } } +#[cfg(target_os = "macos")] +fn to_wry_activation_policy(act_pol: ActivationPolicy) -> WryActivationPolicy { + match act_pol { + ActivationPolicy::Regular => WryActivationPolicy::Regular, + ActivationPolicy::Accessory => WryActivationPolicy::Accessory, + ActivationPolicy::Prohibited => WryActivationPolicy::Prohibited, + _ => unimplemented!(), + } +} + #[cfg(target_os = "macos")] impl From for NativeImageWrapper { fn from(image: NativeImage) -> NativeImageWrapper { @@ -1037,6 +1050,12 @@ pub enum WindowMessage { HideMenu, Show, Hide, + #[cfg(target_os = "macos")] + ShowApplication, + #[cfg(target_os = "macos")] + HideApplication, + #[cfg(target_os = "macos")] + SetActivationPolicy(ActivationPolicy), Close, SetDecorations(bool), SetAlwaysOnTop(bool), @@ -1388,6 +1407,36 @@ impl Dispatch for WryDispatcher { ) } + #[cfg(target_os = "macos")] + fn show_application(&self) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::ShowApplication), + ) + } + + #[cfg(target_os = "macos")] + fn hide_application(&self) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::HideApplication), + ) + } + + #[cfg(target_os = "macos")] + fn set_activation_policy_at_runtime( + &self, + activation_policy: ActivationPolicy, + ) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetActivationPolicy(activation_policy), + ), + ) + } + fn close(&self) -> Result<()> { // NOTE: close cannot use the `send_user_message` function because it accesses the event loop callback self @@ -1885,12 +1934,7 @@ impl Runtime for Wry { fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) { self .event_loop - .set_activation_policy(match activation_policy { - ActivationPolicy::Regular => WryActivationPolicy::Regular, - ActivationPolicy::Accessory => WryActivationPolicy::Accessory, - ActivationPolicy::Prohibited => WryActivationPolicy::Prohibited, - _ => unimplemented!(), - }); + .set_activation_policy(to_wry_activation_policy(activation_policy)); } fn run_iteration) + 'static>(&mut self, mut callback: F) -> RunIteration { @@ -2107,6 +2151,14 @@ fn handle_user_message( WindowMessage::HideMenu => window.hide_menu(), WindowMessage::Show => window.set_visible(true), WindowMessage::Hide => window.set_visible(false), + #[cfg(target_os = "macos")] + WindowMessage::ShowApplication => event_loop.show_application(), + #[cfg(target_os = "macos")] + WindowMessage::HideApplication => event_loop.hide_application(), + #[cfg(target_os = "macos")] + WindowMessage::SetActivationPolicy(act_pol) => { + event_loop.set_activation_policy_at_runtime(to_wry_activation_policy(act_pol)) + } WindowMessage::Close => panic!("cannot handle `WindowMessage::Close` on the main thread"), WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations), WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top), diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs index 26cd65da1a7d..17c9819987a9 100644 --- a/core/tauri-runtime/src/lib.rs +++ b/core/tauri-runtime/src/lib.rs @@ -261,6 +261,7 @@ pub struct RunIteration { /// Application's activation policy. Corresponds to NSApplicationActivationPolicy. #[cfg(target_os = "macos")] #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] +#[derive(Debug, Clone)] #[non_exhaustive] pub enum ActivationPolicy { /// Corresponds to NSApplicationActivationPolicyRegular. @@ -528,6 +529,21 @@ pub trait Dispatch: Debug + Clone + Send + Sync + Sized + 'static /// Hides the window. fn hide(&self) -> Result<()>; + /// Shows the application on macOS (independent of current window). + #[cfg(target_os = "macos")] + fn show_application(&self) -> crate::Result<()>; + + /// Hides the application on macOS (independent of current window). + #[cfg(target_os = "macos")] + fn hide_application(&self) -> crate::Result<()>; + + /// Sets the activation policy at runtime on macOS (independent of current window). + #[cfg(target_os = "macos")] + fn set_activation_policy_at_runtime( + &self, + activation_policy: ActivationPolicy, + ) -> crate::Result<()>; + /// Closes the window. fn close(&self) -> Result<()>; diff --git a/core/tauri/src/test/mock_runtime.rs b/core/tauri/src/test/mock_runtime.rs index 2ab8a2217a78..05b031d71d47 100644 --- a/core/tauri/src/test/mock_runtime.rs +++ b/core/tauri/src/test/mock_runtime.rs @@ -427,6 +427,21 @@ impl Dispatch for MockDispatcher { Ok(()) } + #[cfg(target_os = "macos")] + fn show_application(&self) -> Result<()> { + Ok(()) + } + + #[cfg(target_os = "macos")] + fn hide_application(&self) -> Result<()> { + Ok(()) + } + + #[cfg(target_os = "macos")] + fn set_activation_policy_at_runtime(&self, _: tauri_runtime::ActivationPolicy) -> Result<()> { + Ok(()) + } + fn close(&self) -> Result<()> { Ok(()) } diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 3427e15b3ae0..517e723b21c0 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -32,6 +32,9 @@ use crate::{ PageLoadPayload, Runtime, WindowEvent, }; +#[cfg(target_os = "macos")] +use crate::runtime::ActivationPolicy; + use serde::Serialize; #[cfg(windows)] use windows::Win32::Foundation::HWND; @@ -1058,6 +1061,39 @@ impl Window { self.window.dispatcher.hide().map_err(Into::into) } + /// Shows the application on macOS (independent of current window). + #[cfg(target_os = "macos")] + pub fn show_application(&self) -> crate::Result<()> { + self + .window + .dispatcher + .show_application() + .map_err(Into::into) + } + + /// Hides the application on macOS (independent of current window). + #[cfg(target_os = "macos")] + pub fn hide_application(&self) -> crate::Result<()> { + self + .window + .dispatcher + .hide_application() + .map_err(Into::into) + } + + /// Sets the activation policy at runtime on macOS (independent of current window). + #[cfg(target_os = "macos")] + pub fn set_activation_policy_at_runtime( + &self, + activation_policy: ActivationPolicy, + ) -> crate::Result<()> { + self + .window + .dispatcher + .set_activation_policy_at_runtime(activation_policy) + .map_err(Into::into) + } + /// Closes this window. /// # Panics ///