Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: Expose new Tao APIs #3840

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/set-activation-policy-at-runtime.md
@@ -0,0 +1,7 @@
---
"tauri": patch
---

MacOS: Added `Window.set_activation_policy_at_runtime` method, which allows
betamos marked this conversation as resolved.
Show resolved Hide resolved
dynamically changing the activation policy (previously only possible at
application-build time).
7 changes: 7 additions & 0 deletions .changes/show-hide-application.md
@@ -0,0 +1,7 @@
---
"tauri": patch
---

MacOS: Added `Window.show_application` and `Window.hide_application` method,
betamos marked this conversation as resolved.
Show resolved Hide resolved
which shows or hides the entire app. The `Window.show` and `Window.hide`
methods are unaffected by this change.
64 changes: 58 additions & 6 deletions core/tauri-runtime-wry/src/lib.rs
Expand Up @@ -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")]
Expand Down Expand Up @@ -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<NativeImage> for NativeImageWrapper {
fn from(image: NativeImage) -> NativeImageWrapper {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -1388,6 +1407,36 @@ impl<T: UserEvent> Dispatch<T> for WryDispatcher<T> {
)
}

#[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
Expand Down Expand Up @@ -1885,12 +1934,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
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<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> RunIteration {
Expand Down Expand Up @@ -2107,6 +2151,14 @@ fn handle_user_message<T: UserEvent>(
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),
Expand Down
16 changes: 16 additions & 0 deletions core/tauri-runtime/src/lib.rs
Expand Up @@ -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.
Expand Down Expand Up @@ -528,6 +529,21 @@ pub trait Dispatch<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'static
/// Hides the window.
fn hide(&self) -> Result<()>;

/// Shows the application on MacOS (independent of current window).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some more explanations would be helpful here, what does hiding the app mean in detail? Does it affect the dock icon? Does it affect Mission Control? Or the app quick switcher?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to, but the only way to know would be experimental. Apple is deliberately vague about this, probably because things like dock and mission control are subject to changes across MacOS versions. Being more detailed than Apple's own docs won't be much help. Here's an example of what we call show_application:

https://developer.apple.com/documentation/appkit/nsapplication/1428761-unhide?language=objc

betamos marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_os = "macos")]
fn show_application(&self) -> crate::Result<()>;

/// Hides the application on MacOS (independent of current window).
betamos marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_os = "macos")]
fn hide_application(&self) -> crate::Result<()>;

/// Sets the activation policy at runtime on MacOS (independent of current window).
betamos marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(target_os = "macos")]
fn set_activation_policy_at_runtime(
&self,
activation_policy: ActivationPolicy,
) -> crate::Result<()>;

/// Closes the window.
fn close(&self) -> Result<()>;

Expand Down
15 changes: 15 additions & 0 deletions core/tauri/src/test/mock_runtime.rs
Expand Up @@ -427,6 +427,21 @@ impl<T: UserEvent> Dispatch<T> 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(())
}
Expand Down
36 changes: 36 additions & 0 deletions core/tauri/src/window.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -1058,6 +1061,39 @@ impl<R: Runtime> Window<R> {
self.window.dispatcher.hide().map_err(Into::into)
}

/// Shows the application on MacOS (independent of current window).
betamos marked this conversation as resolved.
Show resolved Hide resolved
#[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).
betamos marked this conversation as resolved.
Show resolved Hide resolved
#[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).
betamos marked this conversation as resolved.
Show resolved Hide resolved
#[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
///
Expand Down