hide app icon in macos dock without real windows
This commit is contained in:
@@ -47,7 +47,11 @@ pub fn run() {
|
||||
)
|
||||
.expect("Failed to export TypeScript bindings");
|
||||
|
||||
tauri::Builder::default()
|
||||
let builder = tauri::Builder::default();
|
||||
#[cfg(target_os = "macos")]
|
||||
let builder = builder.plugin(ui::activation_policy::ActivationPolicy::default());
|
||||
|
||||
builder
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_autostart::init(
|
||||
tauri_plugin_autostart::MacosLauncher::LaunchAgent,
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use tauri::{AppHandle, Manager, RunEvent, Window, WindowEvent, Wry, plugin::Plugin};
|
||||
|
||||
/// Normal windows live from opening until dismissal. Minimized windows still count.
|
||||
#[derive(Default)]
|
||||
pub struct ActivationPolicy {
|
||||
windows: HashSet<String>,
|
||||
applied_regular: Option<bool>,
|
||||
}
|
||||
|
||||
impl ActivationPolicy {
|
||||
fn record_window(&mut self, label: &str, created: bool) {
|
||||
if matches!(label, "scene" | "splashscreen") {
|
||||
return;
|
||||
}
|
||||
if created {
|
||||
self.windows.insert(label.to_owned());
|
||||
} else {
|
||||
self.windows.remove(label);
|
||||
}
|
||||
}
|
||||
|
||||
fn reconcile(&mut self, app: &AppHandle) -> tauri::Result<()> {
|
||||
let regular = !self.windows.is_empty();
|
||||
if self.applied_regular != Some(regular) {
|
||||
app.set_activation_policy(if regular {
|
||||
tauri::ActivationPolicy::Regular
|
||||
} else {
|
||||
tauri::ActivationPolicy::Accessory
|
||||
})?;
|
||||
self.applied_regular = Some(regular);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin<Wry> for ActivationPolicy {
|
||||
fn name(&self) -> &'static str {
|
||||
"activation-policy"
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
app: &AppHandle,
|
||||
_config: serde_json::Value,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.reconcile(app)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn window_created(&mut self, window: Window) {
|
||||
self.record_window(window.label(), true);
|
||||
if let Err(error) = self.reconcile(window.app_handle()) {
|
||||
eprintln!("failed to update macOS activation policy: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
fn on_event(&mut self, app: &AppHandle, event: &RunEvent) {
|
||||
if let RunEvent::WindowEvent {
|
||||
label,
|
||||
event: WindowEvent::Destroyed,
|
||||
..
|
||||
} = event
|
||||
{
|
||||
self.record_window(label, false);
|
||||
if let Err(error) = self.reconcile(app) {
|
||||
eprintln!("failed to update macOS activation policy: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ActivationPolicy;
|
||||
|
||||
#[test]
|
||||
fn decoration_windows_do_not_keep_the_app_in_the_dock() {
|
||||
let mut policy = ActivationPolicy::default();
|
||||
policy.record_window("scene", true);
|
||||
policy.record_window("splashscreen", true);
|
||||
policy.record_window("onboarding", true);
|
||||
policy.record_window("splashscreen", false);
|
||||
assert_eq!(policy.windows.len(), 1);
|
||||
policy.record_window("onboarding", false);
|
||||
assert!(policy.windows.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn action_windows_keep_the_app_in_the_dock_after_the_panel_closes() {
|
||||
let mut policy = ActivationPolicy::default();
|
||||
policy.record_window("control-panel", true);
|
||||
policy.record_window("control-panel", true);
|
||||
policy.record_window("control-panel-action-add-friend", true);
|
||||
policy.record_window("control-panel", false);
|
||||
policy.record_window("control-panel", false);
|
||||
assert_eq!(policy.windows.len(), 1);
|
||||
policy.record_window("control-panel-action-add-friend", false);
|
||||
assert!(policy.windows.is_empty());
|
||||
policy.record_window("control-panel", true);
|
||||
assert_eq!(policy.windows.len(), 1);
|
||||
}
|
||||
}
|
||||
@@ -3,40 +3,25 @@ use tauri::{AppHandle, Manager, WebviewUrl};
|
||||
const WINDOW_LABEL: &str = "control-panel";
|
||||
const ACTION_WINDOW_PREFIX: &str = "control-panel-action-";
|
||||
|
||||
pub fn init(handle: &AppHandle) {
|
||||
if let Some(window) = handle.get_webview_window(WINDOW_LABEL) {
|
||||
window.hide().unwrap();
|
||||
return;
|
||||
};
|
||||
|
||||
let builder = tauri::WebviewWindowBuilder::new(
|
||||
handle,
|
||||
WINDOW_LABEL,
|
||||
WebviewUrl::App("/control-panel".into()),
|
||||
)
|
||||
.title("Friendolls")
|
||||
.inner_size(400.0, 600.0)
|
||||
.min_inner_size(400.0, 600.0)
|
||||
.resizable(false)
|
||||
.maximizable(false)
|
||||
.center()
|
||||
.visible(false);
|
||||
|
||||
let window = builder.build().unwrap();
|
||||
window.hide().unwrap();
|
||||
let window_c = window.clone();
|
||||
window.on_window_event(move |event: &tauri::WindowEvent| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
window_c.hide().unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn show(handle: &AppHandle) -> Result<(), String> {
|
||||
let window = handle
|
||||
.get_webview_window(WINDOW_LABEL)
|
||||
.ok_or_else(|| "Control panel window was not created during startup.".to_string())?;
|
||||
let window = if let Some(window) = handle.get_webview_window(WINDOW_LABEL) {
|
||||
window
|
||||
} else {
|
||||
tauri::WebviewWindowBuilder::new(
|
||||
handle,
|
||||
WINDOW_LABEL,
|
||||
WebviewUrl::App("/control-panel".into()),
|
||||
)
|
||||
.title("Friendolls")
|
||||
.inner_size(400.0, 600.0)
|
||||
.min_inner_size(400.0, 600.0)
|
||||
.resizable(false)
|
||||
.maximizable(false)
|
||||
.transparent(true)
|
||||
.center()
|
||||
.build()
|
||||
.map_err(|error| error.to_string())?
|
||||
};
|
||||
|
||||
window.unminimize().map_err(|error| error.to_string())?;
|
||||
window.show().map_err(|error| error.to_string())?;
|
||||
@@ -84,6 +69,7 @@ pub async fn open_action_window(
|
||||
.resizable(false)
|
||||
.minimizable(false)
|
||||
.maximizable(false)
|
||||
.transparent(true)
|
||||
.skip_taskbar(true)
|
||||
.center()
|
||||
.build()
|
||||
|
||||
@@ -18,14 +18,8 @@ pub fn init(handle: &AppHandle) {
|
||||
.title("Friendolls Debug")
|
||||
.inner_size(800.0, 600.0)
|
||||
.min_inner_size(500.0, 400.0)
|
||||
.transparent(true)
|
||||
.visible(true);
|
||||
|
||||
let window = builder.build().unwrap();
|
||||
let window_c = window.clone();
|
||||
window.on_window_event(move |event: &tauri::WindowEvent| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
window_c.hide().unwrap();
|
||||
}
|
||||
});
|
||||
builder.build().unwrap();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use tauri::AppHandle;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub mod activation_policy;
|
||||
pub mod control_panel;
|
||||
#[cfg(debug_assertions)]
|
||||
mod debug;
|
||||
@@ -12,7 +14,6 @@ pub fn init(app_handle: &AppHandle) {
|
||||
// #[cfg(debug_assertions)]
|
||||
// debug::init(app_handle);
|
||||
scene::init(app_handle);
|
||||
control_panel::init(app_handle);
|
||||
tray::init(app_handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ async fn show(handle: &AppHandle, accessibility_only: bool) -> Result<(), String
|
||||
))
|
||||
.inner_size(680.0, 520.0)
|
||||
.min_inner_size(680.0, 520.0)
|
||||
.transparent(true)
|
||||
.resizable(false)
|
||||
.maximizable(false)
|
||||
.center()
|
||||
|
||||
@@ -68,21 +68,21 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
async function hideWindow() {
|
||||
async function closeWindow() {
|
||||
try {
|
||||
await getCurrentWindow().hide();
|
||||
await getCurrentWindow().close();
|
||||
} catch (error) {
|
||||
console.error("failed to hide control panel", error);
|
||||
console.error("failed to close control panel", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function confirm() {
|
||||
if (await applyAll()) await hideWindow();
|
||||
if (await applyAll()) await closeWindow();
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
tabs.forEach((tab) => actions[tab.id]?.reset());
|
||||
void hideWindow();
|
||||
void closeWindow();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user