feat: add set_dock_visibility method (#13185)

* feat: add `set_dock_visibility` method

Signed-off-by: The1111mp <The1111mp@outlook.com>

* add api

* retain focus

* fmt

* make SetDockVisibility message conditional (macos only)

* lint

---------

Signed-off-by: The1111mp <The1111mp@outlook.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
The1111mp
2025-04-12 02:13:07 +08:00
committed by GitHub
parent 7b14531f24
commit dd4f13ce4b
13 changed files with 168 additions and 4 deletions

View File

@@ -0,0 +1,7 @@
---
tauri: patch:feat
tauri-runtime: patch:feat
tauri-runtime-wry: patch:feat
---
MacOS: Add `set_dock_visibility` method to support setting the visibility of the application in the dock.

View File

@@ -0,0 +1,6 @@
---
"@tauri-apps/api": minor:feat
---
Added `app.setDockVisibility` for macOS.

View File

@@ -1363,6 +1363,8 @@ pub enum Message<T: 'static> {
Task(Box<dyn FnOnce() + Send>),
#[cfg(target_os = "macos")]
SetActivationPolicy(ActivationPolicy),
#[cfg(target_os = "macos")]
SetDockVisibility(bool),
RequestExit(i32),
Application(ApplicationMessage),
Window(WindowId, WindowMessage),
@@ -2435,6 +2437,11 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
)
}
#[cfg(target_os = "macos")]
fn set_dock_visibility(&self, visible: bool) -> Result<()> {
send_user_message(&self.context, Message::SetDockVisibility(visible))
}
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
@@ -2844,6 +2851,11 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.set_activation_policy(tao_activation_policy(activation_policy));
}
#[cfg(target_os = "macos")]
fn set_dock_visibility(&mut self, visible: bool) {
self.event_loop.set_dock_visibility(visible);
}
#[cfg(target_os = "macos")]
fn show(&self) {
self.event_loop.show_application();
@@ -3018,6 +3030,8 @@ fn handle_user_message<T: UserEvent>(
Message::SetActivationPolicy(activation_policy) => {
event_loop.set_activation_policy_at_runtime(tao_activation_policy(activation_policy))
}
#[cfg(target_os = "macos")]
Message::SetDockVisibility(visible) => event_loop.set_dock_visibility(visible),
Message::RequestExit(_code) => panic!("cannot handle RequestExit on the main thread"),
Message::Application(application_message) => match application_message {
#[cfg(target_os = "macos")]

View File

@@ -288,6 +288,12 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()>;
/// Sets the dock visibility for the application.
///
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_dock_visibility(&self, visible: bool) -> Result<()>;
/// Requests an exit of the event loop.
fn request_exit(&self, code: i32) -> Result<()>;
@@ -431,6 +437,12 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy);
/// Sets the dock visibility for the application.
///
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_dock_visibility(&mut self, visible: bool);
/// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]

View File

@@ -159,6 +159,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("remove_data_store", false),
("default_window_icon", false),
("set_app_theme", false),
("set_dock_visibility", false),
],
),
(

View File

@@ -229,6 +229,32 @@ Denies the set_app_theme command without any pre-configured scope.
<tr>
<td>
`core:app:allow-set-dock-visibility`
</td>
<td>
Enables the set_dock_visibility command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:app:deny-set-dock-visibility`
</td>
<td>
Denies the set_dock_visibility command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`core:app:allow-tauri-version`
</td>

File diff suppressed because one or more lines are too long

View File

@@ -601,6 +601,26 @@ impl<R: Runtime> AppHandle<R> {
.set_activation_policy(activation_policy)
.map_err(Into::into)
}
/// Sets the dock visibility for the application.
///
/// # Examples
/// ```,no_run
/// tauri::Builder::default()
/// .setup(move |app| {
/// #[cfg(target_os = "macos")]
/// app.handle().set_dock_visibility(false);
/// Ok(())
/// });
/// ```
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
pub fn set_dock_visibility(&self, visible: bool) -> crate::Result<()> {
self
.runtime_handle
.set_dock_visibility(visible)
.map_err(Into::into)
}
}
impl<R: Runtime> Manager<R> for AppHandle<R> {
@@ -1130,6 +1150,27 @@ impl<R: Runtime> App<R> {
}
}
/// Sets the dock visibility for the application.
///
/// # Examples
/// ```,no_run
/// tauri::Builder::default()
/// .setup(move |app| {
/// #[cfg(target_os = "macos")]
/// app.set_dock_visibility(false);
/// Ok(())
/// });
/// ```
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
pub fn set_dock_visibility(&mut self, visible: bool) {
if let Some(runtime) = self.runtime.as_mut() {
runtime.set_dock_visibility(visible);
} else {
let _ = self.app_handle().set_dock_visibility(visible);
}
}
/// Change the device event filter mode.
///
/// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`]

View File

@@ -83,6 +83,33 @@ pub async fn set_app_theme<R: Runtime>(app: AppHandle<R>, theme: Option<Theme>)
app.set_theme(theme);
}
#[command(root = "crate")]
pub async fn set_dock_visibility<R: Runtime>(
app: AppHandle<R>,
visible: bool,
) -> crate::Result<()> {
#[cfg(target_os = "macos")]
{
let mut focused_window = None;
for window in app.manager.windows().into_values() {
if window.is_focused().unwrap_or_default() {
focused_window.replace(window);
break;
}
}
app.set_dock_visibility(visible)?;
// retain focus
if let Some(focused_window) = focused_window {
let _ = focused_window.set_focus();
}
}
#[cfg(not(target_os = "macos"))]
let (_app, _visible) = (app, visible);
Ok(())
}
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("app")
.invoke_handler(crate::generate_handler![
@@ -97,6 +124,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
remove_data_store,
default_window_icon,
set_app_theme,
set_dock_visibility,
])
.build()
}

View File

@@ -134,6 +134,12 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
Ok(())
}
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_dock_visibility(&self, visible: bool) -> Result<()> {
Ok(())
}
fn request_exit(&self, code: i32) -> Result<()> {
unimplemented!()
}
@@ -1209,6 +1215,10 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_activation_policy(&mut self, activation_policy: tauri_runtime::ActivationPolicy) {}
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn set_dock_visibility(&mut self, visible: bool) {}
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
fn show(&self) {}

View File

@@ -24,6 +24,7 @@
"core:app:allow-app-hide",
"core:app:allow-app-show",
"core:app:allow-set-app-theme",
"core:app:allow-set-dock-visibility",
"core:window:allow-set-theme",
"core:window:allow-center",
"core:window:allow-request-user-attention",

View File

@@ -1,9 +1,10 @@
<script>
import { show, hide, setTheme } from '@tauri-apps/api/app'
import { show, hide, setTheme, setDockVisibility } from '@tauri-apps/api/app'
export let onMessage
/** @type {import('@tauri-apps/api/window').Theme | 'auto'} */
let theme = 'auto'
let dockVisible = true
function showApp() {
hideApp()
@@ -37,6 +38,11 @@
}
setTheme(theme === 'auto' ? null : theme)
}
async function toggleDockVisibility() {
await setDockVisibility(!dockVisible)
dockVisible = !dockVisible
}
</script>
<div>
@@ -47,5 +53,6 @@
on:click={showApp}>Show</button
>
<button class="btn" id="hide" on:click={hideApp}>Hide</button>
<button class="btn" id="hide" on:click={switchTheme}>Switch Theme ({theme})</button>
<button class="btn" id="switch-theme" on:click={switchTheme}>Switch Theme ({theme})</button>
<button class="btn" id="toggle-dock-visibility" on:click={toggleDockVisibility}>Toggle dock visibility</button>
</div>

View File

@@ -196,6 +196,16 @@ async function setTheme(theme?: Theme | null): Promise<void> {
return invoke('plugin:app|set_app_theme', { theme })
}
/**
* Sets the dock visibility for the application on macOS.
*
* @param visible whether the dock should be visible or not
* @since 2.5.0
*/
async function setDockVisibility(visible: boolean): Promise<void> {
return invoke('plugin:app|set_dock_visibility', { visible })
}
export {
getName,
getVersion,
@@ -206,5 +216,6 @@ export {
defaultWindowIcon,
setTheme,
fetchDataStoreIdentifiers,
removeDataStore
removeDataStore,
setDockVisibility
}