Skip to content

Commit

Permalink
feat(macOS): Add application show and hide methods (#3689)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
probablykasper and lucasfernog committed Oct 3, 2022
1 parent 7c0fa1f commit 39bf895
Show file tree
Hide file tree
Showing 20 changed files with 394 additions and 46 deletions.
5 changes: 5 additions & 0 deletions .changes/mac-app-hide-allowlist.md
@@ -0,0 +1,5 @@
---
"tauri-utils": minor
---

Added the `app` allowlist module.
5 changes: 5 additions & 0 deletions .changes/mac-app-hide-api.md
@@ -0,0 +1,5 @@
---
"api": minor
---

Added `show` and `hide` methods on the `app` module.
6 changes: 6 additions & 0 deletions .changes/mac-app-hide-runtime.md
@@ -0,0 +1,6 @@
---
"tauri-runtime-wry": minor
"tauri-runtime": minor
---

Added `Runtime::show()`, `RuntimeHandle::show()`, `Runtime::hide()`, `RuntimeHandle::hide()` for hiding/showing the entire application on macOS.
5 changes: 5 additions & 0 deletions .changes/mac-app-hide.md
@@ -0,0 +1,5 @@
---
"tauri": minor
---

Add `App::show()`, `AppHandle::show()`, `App::hide()` and `AppHandle::hide()` for hiding/showing the entire application on macOS.
46 changes: 46 additions & 0 deletions core/tauri-runtime-wry/src/lib.rs
Expand Up @@ -29,6 +29,8 @@ 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(target_os = "macos")]
use wry::application::platform::macos::WindowBuilderExtMacOS;
#[cfg(target_os = "linux")]
use wry::application::platform::unix::{WindowBuilderExtUnix, WindowExtUnix};
Expand Down Expand Up @@ -1021,6 +1023,13 @@ unsafe impl Send for GtkWindow {}
pub struct RawWindowHandle(pub raw_window_handle::RawWindowHandle);
unsafe impl Send for RawWindowHandle {}

#[cfg(target_os = "macos")]
#[derive(Debug, Clone)]
pub enum ApplicationMessage {
Show,
Hide,
}

pub enum WindowMessage {
#[cfg(desktop)]
WithWebview(Box<dyn FnOnce(Webview) + Send>),
Expand Down Expand Up @@ -1126,6 +1135,8 @@ pub type CreateWebviewClosure<T> = Box<

pub enum Message<T: 'static> {
Task(Box<dyn FnOnce() + Send>),
#[cfg(target_os = "macos")]
Application(ApplicationMessage),
Window(WebviewId, WindowMessage),
Webview(WebviewId, WebviewMessage),
#[cfg(all(desktop, feature = "system-tray"))]
Expand Down Expand Up @@ -1786,6 +1797,22 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
fn raw_display_handle(&self) -> RawDisplayHandle {
self.context.main_thread.window_target.raw_display_handle()
}

#[cfg(target_os = "macos")]
fn show(&self) -> tauri_runtime::Result<()> {
send_user_message(
&self.context,
Message::Application(ApplicationMessage::Show),
)
}

#[cfg(target_os = "macos")]
fn hide(&self) -> tauri_runtime::Result<()> {
send_user_message(
&self.context,
Message::Application(ApplicationMessage::Hide),
)
}
}

impl<T: UserEvent> Wry<T> {
Expand Down Expand Up @@ -1995,6 +2022,16 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
});
}

#[cfg(target_os = "macos")]
fn show(&self) {
self.event_loop.show_application();
}

#[cfg(target_os = "macos")]
fn hide(&self) {
self.event_loop.hide_application();
}

#[cfg(desktop)]
fn run_iteration<F: FnMut(RunEvent<T>) + 'static>(&mut self, mut callback: F) -> RunIteration {
use wry::application::platform::run_return::EventLoopExtRunReturn;
Expand Down Expand Up @@ -2185,6 +2222,15 @@ fn handle_user_message<T: UserEvent>(
} = context;
match message {
Message::Task(task) => task(),
#[cfg(target_os = "macos")]
Message::Application(application_message) => match application_message {
ApplicationMessage::Show => {
event_loop.show_application();
}
ApplicationMessage::Hide => {
event_loop.hide_application();
}
},
Message::Window(id, window_message) => {
if let WindowMessage::UpdateMenuItem(item_id, update) = window_message {
if let Some(menu_items) = windows.borrow_mut().get_mut(&id).map(|w| &mut w.menu_items) {
Expand Down
20 changes: 20 additions & 0 deletions core/tauri-runtime/src/lib.rs
Expand Up @@ -352,6 +352,16 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
) -> Result<<Self::Runtime as Runtime<T>>::TrayHandler>;

fn raw_display_handle(&self) -> RawDisplayHandle;

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn show(&self) -> Result<()>;

/// Hides the application.
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self) -> Result<()>;
}

/// A global shortcut manager.
Expand Down Expand Up @@ -441,6 +451,16 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn show(&self);

/// Hides the application.
#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self);

/// Runs the one step of the webview runtime event loop and returns control flow to the caller.
#[cfg(desktop)]
fn run_iteration<F: Fn(RunEvent<T>) + 'static>(&mut self, callback: F) -> RunIteration;
Expand Down
44 changes: 44 additions & 0 deletions core/tauri-utils/src/config.rs
Expand Up @@ -2009,6 +2009,46 @@ impl Allowlist for ClipboardAllowlistConfig {
}
}

/// Allowlist for the app APIs.
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct AppAllowlistConfig {
/// Use this flag to enable all app APIs.
#[serde(default)]
pub all: bool,
/// Enables the app's `show` API.
#[serde(default)]
pub show: bool,
/// Enables the app's `hide` API.
#[serde(default)]
pub hide: bool,
}

impl Allowlist for AppAllowlistConfig {
fn all_features() -> Vec<&'static str> {
let allowlist = Self {
all: false,
show: true,
hide: true,
};
let mut features = allowlist.to_features();
features.push("app-all");
features
}

fn to_features(&self) -> Vec<&'static str> {
if self.all {
vec!["app-all"]
} else {
let mut features = Vec::new();
check_feature!(self, features, show, "app-show");
check_feature!(self, features, hide, "app-hide");
features
}
}
}

/// Allowlist configuration.
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
Expand Down Expand Up @@ -2053,6 +2093,9 @@ pub struct AllowlistConfig {
/// Clipboard APIs allowlist.
#[serde(default)]
pub clipboard: ClipboardAllowlistConfig,
/// App APIs allowlist.
#[serde(default)]
pub app: AppAllowlistConfig,
}

impl Allowlist for AllowlistConfig {
Expand All @@ -2070,6 +2113,7 @@ impl Allowlist for AllowlistConfig {
features.extend(ProtocolAllowlistConfig::all_features());
features.extend(ProcessAllowlistConfig::all_features());
features.extend(ClipboardAllowlistConfig::all_features());
features.extend(AppAllowlistConfig::all_features());
features
}

Expand Down
6 changes: 5 additions & 1 deletion core/tauri/Cargo.toml
Expand Up @@ -176,7 +176,8 @@ api-all = [
"process-all",
"protocol-all",
"shell-all",
"window-all"
"window-all",
"app-all"
]
clipboard-all = [ "clipboard-write-text", "clipboard-read-text" ]
clipboard-read-text = [ "clipboard" ]
Expand Down Expand Up @@ -283,6 +284,9 @@ window-set-cursor-position = [ ]
window-set-ignore-cursor-events = [ ]
window-start-dragging = [ ]
window-print = [ ]
app-all = [ "app-show", "app-hide" ]
app-show = [ ]
app-hide = [ ]
config-json5 = [ "tauri-macros/config-json5" ]
config-toml = [ "tauri-macros/config-toml" ]
icon-ico = [ "infer", "ico" ]
Expand Down
2 changes: 2 additions & 0 deletions core/tauri/build.rs
Expand Up @@ -131,6 +131,8 @@ fn main() {

alias_module("clipboard", &["write-text", "read-text"], api_all);

alias_module("app", &["show", "hide"], api_all);

let checked_features_out_path =
Path::new(&std::env::var("OUT_DIR").unwrap()).join("checked_features");
std::fs::write(
Expand Down
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.js

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions core/tauri/src/app.rs
Expand Up @@ -734,6 +734,28 @@ macro_rules! shared_app_impl {
manager: self.manager.clone(),
}
}

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
pub fn show(&self) -> crate::Result<()> {
match self.runtime() {
RuntimeOrDispatch::Runtime(r) => r.show(),
RuntimeOrDispatch::RuntimeHandle(h) => h.show()?,
_ => unreachable!(),
}
Ok(())
}

/// Hides the application.
#[cfg(target_os = "macos")]
pub fn hide(&self) -> crate::Result<()> {
match self.runtime() {
RuntimeOrDispatch::Runtime(r) => r.hide(),
RuntimeOrDispatch::RuntimeHandle(h) => h.hide()?,
_ => unreachable!(),
}
Ok(())
}
}
};
}
Expand Down
24 changes: 23 additions & 1 deletion core/tauri/src/endpoints/app.rs
Expand Up @@ -5,7 +5,7 @@
use super::InvokeContext;
use crate::Runtime;
use serde::Deserialize;
use tauri_macros::{command_enum, CommandModule};
use tauri_macros::{command_enum, module_command_handler, CommandModule};

/// The API descriptor.
#[command_enum]
Expand All @@ -19,6 +19,12 @@ pub enum Cmd {
GetAppName,
/// Get Tauri Version
GetTauriVersion,
/// Shows the application on macOS.
#[cmd(app_show, "app > show")]
Show,
/// Hides the application on macOS.
#[cmd(app_hide, "app > hide")]
Hide,
}

impl Cmd {
Expand All @@ -33,4 +39,20 @@ impl Cmd {
fn get_tauri_version<R: Runtime>(_context: InvokeContext<R>) -> super::Result<&'static str> {
Ok(env!("CARGO_PKG_VERSION"))
}

#[module_command_handler(app_show)]
#[allow(unused_variables)]
fn show<R: Runtime>(context: InvokeContext<R>) -> super::Result<()> {
#[cfg(target_os = "macos")]
context.window.app_handle.show()?;
Ok(())
}

#[module_command_handler(app_hide)]
#[allow(unused_variables)]
fn hide<R: Runtime>(context: InvokeContext<R>) -> super::Result<()> {
#[cfg(target_os = "macos")]
context.window.app_handle.hide()?;
Ok(())
}
}
6 changes: 6 additions & 0 deletions core/tauri/src/lib.rs
Expand Up @@ -148,6 +148,12 @@
//! - **window-set-ignore-cursor-events**: Enables the [`setIgnoreCursorEvents` API](https://tauri.app/en/docs/api/js/classes/window.WebviewWindow#setignorecursorevents).
//! - **window-start-dragging**: Enables the [`startDragging` API](https://tauri.app/en/docs/api/js/classes/window.WebviewWindow#startdragging).
//! - **window-print**: Enables the [`print` API](https://tauri.app/en/docs/api/js/classes/window.WebviewWindow#print).
//!
//! ### App allowlist
//!
//! - **app-all**: Enables all [App APIs](https://tauri.app/en/docs/api/js/modules/app).
//! - **app-show**: Enables the [`show` API](https://tauri.app/en/docs/api/js/modules/app#show).
//! - **app-hide**: Enables the [`hide` API](https://tauri.app/en/docs/api/js/modules/app#hide).

#![warn(missing_docs, rust_2018_idioms)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
Expand Down
20 changes: 20 additions & 0 deletions core/tauri/src/test/mock_runtime.rs
Expand Up @@ -94,6 +94,18 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
unimplemented!()
}

/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
fn show(&self) -> Result<()> {
Ok(())
}

/// Hides the application.
#[cfg(target_os = "macos")]
fn hide(&self) -> Result<()> {
Ok(())
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -670,6 +682,14 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: tauri_runtime::ActivationPolicy) {}

#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn show(&self) {}

#[cfg(target_os = "macos")]
#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))]
fn hide(&self) {}

#[cfg(any(
target_os = "macos",
windows,
Expand Down
2 changes: 1 addition & 1 deletion examples/api/dist/assets/index.css

Large diffs are not rendered by default.

0 comments on commit 39bf895

Please sign in to comment.