Browse Source

fix(core): macos #5122 app.runtime panic in app.set_activation_policy (#8713)

* fix #5122 app.runtime panic in set_activation_policy

* allow setting the policy at runtime

* add change file

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
Jingyu 1 year ago
parent
commit
95da1a2747

+ 7 - 0
.changes/fix-set-activation-policy.md

@@ -0,0 +1,7 @@
+---
+"tauri": patch:bug
+"tauri-runtime": patch:bug
+"tauri-runtime-wry": patch:bug
+---
+
+Fix calling `set_activation_policy` when the event loop is running.

+ 26 - 9
core/tauri-runtime-wry/src/lib.rs

@@ -26,9 +26,7 @@ use tauri_runtime::{
 };
 
 #[cfg(target_os = "macos")]
-use tao::platform::macos::EventLoopWindowTargetExtMacOS;
-#[cfg(target_os = "macos")]
-use tao::platform::macos::WindowBuilderExtMacOS;
+use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS};
 #[cfg(target_os = "linux")]
 use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
 #[cfg(windows)]
@@ -431,6 +429,16 @@ pub fn map_theme(theme: &TaoTheme) -> Theme {
   }
 }
 
+#[cfg(target_os = "macos")]
+fn tao_activation_policy(activation_policy: ActivationPolicy) -> TaoActivationPolicy {
+  match activation_policy {
+    ActivationPolicy::Regular => TaoActivationPolicy::Regular,
+    ActivationPolicy::Accessory => TaoActivationPolicy::Accessory,
+    ActivationPolicy::Prohibited => TaoActivationPolicy::Prohibited,
+    _ => unimplemented!(),
+  }
+}
+
 impl<'a> From<&TaoWindowEvent<'a>> for WindowEventWrapper {
   fn from(event: &TaoWindowEvent<'a>) -> Self {
     let event = match event {
@@ -1201,6 +1209,8 @@ pub type CreateWebviewClosure = Box<dyn FnOnce(&Window) -> Result<WebviewWrapper
 
 pub enum Message<T: 'static> {
   Task(Box<dyn FnOnce() + Send>),
+  #[cfg(target_os = "macos")]
+  SetActivationPolicy(ActivationPolicy),
   RequestExit(i32),
   #[cfg(target_os = "macos")]
   Application(ApplicationMessage),
@@ -1995,6 +2005,14 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
     EventProxy(self.context.proxy.clone())
   }
 
+  #[cfg(target_os = "macos")]
+  fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()> {
+    send_user_message(
+      &self.context,
+      Message::SetActivationPolicy(activation_policy),
+    )
+  }
+
   fn request_exit(&self, code: i32) -> Result<()> {
     // NOTE: request_exit cannot use the `send_user_message` function because it accesses the event loop callback
     self
@@ -2296,12 +2314,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 => TaoActivationPolicy::Regular,
-        ActivationPolicy::Accessory => TaoActivationPolicy::Accessory,
-        ActivationPolicy::Prohibited => TaoActivationPolicy::Prohibited,
-        _ => unimplemented!(),
-      });
+      .set_activation_policy(tao_activation_policy(activation_policy));
   }
 
   #[cfg(target_os = "macos")]
@@ -2446,6 +2459,10 @@ fn handle_user_message<T: UserEvent>(
   } = context;
   match message {
     Message::Task(task) => task(),
+    #[cfg(target_os = "macos")]
+    Message::SetActivationPolicy(activation_policy) => {
+      event_loop.set_activation_policy_at_runtime(tao_activation_policy(activation_policy))
+    }
     Message::RequestExit(_code) => panic!("cannot handle RequestExit on the main thread"),
     #[cfg(target_os = "macos")]
     Message::Application(application_message) => match application_message {

+ 6 - 1
core/tauri-runtime/src/lib.rs

@@ -208,6 +208,11 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
   /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop.
   fn create_proxy(&self) -> <Self::Runtime as Runtime<T>>::EventLoopProxy;
 
+  /// Sets the activation policy for the application.
+  #[cfg(target_os = "macos")]
+  #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
+  fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()>;
+
   /// Requests an exit of the event loop.
   fn request_exit(&self, code: i32) -> Result<()>;
 
@@ -313,7 +318,7 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
   fn primary_monitor(&self) -> Option<Monitor>;
   fn available_monitors(&self) -> Vec<Monitor>;
 
-  /// Sets the activation policy for the application. It is set to `NSApplicationActivationPolicyRegular` by default.
+  /// Sets the activation policy for the application.
   #[cfg(target_os = "macos")]
   #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
   fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);

+ 8 - 5
core/tauri/src/app.rs

@@ -876,11 +876,14 @@ impl<R: Runtime> App<R> {
   #[cfg(target_os = "macos")]
   #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
   pub fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
-    self
-      .runtime
-      .as_mut()
-      .unwrap()
-      .set_activation_policy(activation_policy);
+    if let Some(runtime) = self.runtime.as_mut() {
+      runtime.set_activation_policy(activation_policy);
+    } else {
+      let _ = self
+        .app_handle()
+        .runtime_handle
+        .set_activation_policy(activation_policy);
+    }
   }
 
   /// Change the device event filter mode.

+ 9 - 0
core/tauri/src/test/mock_runtime.rs

@@ -120,6 +120,15 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
     EventProxy {}
   }
 
+  #[cfg(target_os = "macos")]
+  #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
+  fn set_activation_policy(
+    &self,
+    activation_policy: tauri_runtime::ActivationPolicy,
+  ) -> Result<()> {
+    Ok(())
+  }
+
   fn request_exit(&self, code: i32) -> Result<()> {
     unimplemented!()
   }