fix(macos): restore native window lifecycle (#30)

Install the native macOS application menu for Command-M, handle Dock reopen events only when no window is visible, and preserve early secondary-launch restores until the main window exists. Refs #30.
This commit is contained in:
NimBold
2026-07-22 18:34:56 +03:30
parent 17eb8e5d39
commit d3e5e8c208
+45 -11
View File
@@ -2948,6 +2948,11 @@ pub struct AppState {
pub queue_manager: Arc<queue::QueueManager>, pub queue_manager: Arc<queue::QueueManager>,
} }
#[derive(Default)]
struct MainWindowRestoreState {
requested: AtomicBool,
}
const KEYCHAIN_CONSENT_REQUIRED_ERROR: &str = const KEYCHAIN_CONSENT_REQUIRED_ERROR: &str =
"Credential-store access requires explicit user consent"; "Credential-store access requires explicit user consent";
const KEYCHAIN_GRANT_IN_PROGRESS_ERROR: &str = const KEYCHAIN_GRANT_IN_PROGRESS_ERROR: &str =
@@ -3139,10 +3144,24 @@ fn parse_firelink_deep_link(deep_link: &url::Url) -> FirelinkDeepLink {
} }
fn restore_main_window(app_handle: &tauri::AppHandle) { fn restore_main_window(app_handle: &tauri::AppHandle) {
if let Some(window) = app_handle.get_webview_window("main") { let Some(window) = app_handle.get_webview_window("main") else {
let _ = window.unminimize(); if let Some(state) = app_handle.try_state::<MainWindowRestoreState>() {
let _ = window.show(); state.requested.store(true, Ordering::Release);
let _ = window.set_focus(); }
return;
};
let _ = window.unminimize();
let _ = window.show();
let _ = window.set_focus();
}
fn restore_pending_main_window(app_handle: &tauri::AppHandle) {
if app_handle
.try_state::<MainWindowRestoreState>()
.is_some_and(|state| state.requested.swap(false, Ordering::AcqRel))
{
restore_main_window(app_handle);
} }
} }
@@ -8583,12 +8602,9 @@ pub fn run() {
let aria2_port_clone = Arc::clone(&aria2_port); let aria2_port_clone = Arc::clone(&aria2_port);
let aria2_secret = uuid::Uuid::new_v4().to_string(); let aria2_secret = uuid::Uuid::new_v4().to_string();
tauri::Builder::default() tauri::Builder::default()
.manage(MainWindowRestoreState::default())
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
if let Some(window) = app.get_webview_window("main") { restore_main_window(app);
let _ = window.unminimize();
window.show().unwrap();
window.set_focus().unwrap();
}
})) }))
.plugin(tauri_plugin_deep_link::init()) .plugin(tauri_plugin_deep_link::init())
.manage(Aria2DaemonGuard::new()) .manage(Aria2DaemonGuard::new())
@@ -8627,6 +8643,13 @@ pub fn run() {
log::info!("=========================="); log::info!("==========================");
build_main_tray(app.handle()) build_main_tray(app.handle())
.map_err(|error| format!("failed to create tray menu: {error}"))?; .map_err(|error| format!("failed to create tray menu: {error}"))?;
#[cfg(target_os = "macos")]
{
let app_menu = tauri::menu::Menu::default(app.handle())
.map_err(|error| format!("failed to create application menu: {error}"))?;
app.set_menu(app_menu)
.map_err(|error| format!("failed to install application menu: {error}"))?;
}
let database = crate::db::init(&storage_layout) let database = crate::db::init(&storage_layout)
.map_err(|error| format!("failed to initialize persistence: {error}"))?; .map_err(|error| format!("failed to initialize persistence: {error}"))?;
@@ -8718,6 +8741,7 @@ pub fn run() {
main_window_builder main_window_builder
.build() .build()
.map_err(|error| format!("failed to create main window: {error}"))?; .map_err(|error| format!("failed to create main window: {error}"))?;
restore_pending_main_window(app.handle());
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
if let Some(window) = app.get_webview_window("main") { if let Some(window) = app.get_webview_window("main") {
@@ -9257,11 +9281,21 @@ pub fn run() {
]) ])
.build(tauri::generate_context!()) .build(tauri::generate_context!())
.expect("error while building tauri application") .expect("error while building tauri application")
.run(|app_handle, event| { .run(|app_handle, event| match event {
if let tauri::RunEvent::ExitRequested { .. } = event { #[cfg(target_os = "macos")]
tauri::RunEvent::Reopen {
has_visible_windows,
..
} => {
if !has_visible_windows {
restore_main_window(app_handle);
}
}
tauri::RunEvent::ExitRequested { .. } => {
let state = app_handle.state::<AppState>(); let state = app_handle.state::<AppState>();
let _ = state.extension_server_shutdown.send(true); let _ = state.extension_server_shutdown.send(true);
} }
_ => {}
}); });
} }
mod db; mod db;