diff --git a/src-tauri/src/commands/windows.rs b/src-tauri/src/commands/windows.rs index db841545f2..1adfe1b529 100644 --- a/src-tauri/src/commands/windows.rs +++ b/src-tauri/src/commands/windows.rs @@ -886,12 +886,13 @@ pub async fn open_import_sessions_window( /// focus alone then left the app with nothing on screen once settings was /// closed too. /// -/// Single source of truth for the sequence: the tray (`show_main_window`), the -/// dock / single-instance activation (`workspace_windows::activate_workspace`) -/// and the auxiliary-window owner restores must not drift apart again. `unminimize` is inert when the window isn't minimized -/// (macOS returns early; Windows first syncs the flag from `IsIconic`, so the -/// diff it applies is empty), and `show` preserves the maximized flag — a -/// tray-hidden maximized workspace comes back maximized. +/// Single source of truth for the sequence: the tray (`show_main_window`), +/// Dock / second-launch activation (`workspace_windows::activate_workspace`) +/// and the auxiliary-window owner restores must not drift apart again. +/// `unminimize` is inert when the window isn't minimized (macOS returns early; +/// Windows first syncs the flag from `IsIconic`, so the diff it applies is +/// empty), and `show` preserves the maximized flag — a tray-hidden maximized +/// workspace comes back maximized. pub(crate) fn show_and_focus_window(app: &AppHandle, label: &str) { let Some(window) = app.get_webview_window(label) else { return; diff --git a/src-tauri/src/commands/workspace_windows.rs b/src-tauri/src/commands/workspace_windows.rs index fd20f6bbc4..4484f94540 100644 --- a/src-tauri/src/commands/workspace_windows.rs +++ b/src-tauri/src/commands/workspace_windows.rs @@ -701,6 +701,52 @@ mod tests { } } + #[test] + fn activation_prefers_the_most_recent_existing_workspace() { + let mut state = SessionState::default(); + state.mark_open(LOCAL); + state.mark_open(remote(1)); + state.mark_open(remote(2)); + assert_eq!(state.activation_target(|_| true), Some(remote(2))); + assert_eq!( + state.activation_target(|window| window != remote(2)), + Some(remote(1)) + ); + state.mark_open(LOCAL); + assert_eq!(state.activation_target(|_| true), Some(LOCAL)); + } + + #[test] + fn activation_does_not_reopen_a_closed_local_workspace() { + let mut state = SessionState::default(); + state.mark_open(LOCAL); + state.mark_open(remote(1)); + state.mark_closed(LOCAL); + // main still physically exists, hidden to tray; it must stay hidden. + assert_eq!(state.activation_target(|_| true), Some(remote(1))); + state.mark_closed(remote(1)); + assert_eq!(state.activation_target(|_| true), Some(LOCAL)); + } + + #[test] + fn activation_waits_for_a_remote_only_restore() { + // As `begin_restore` leaves it: the remembered front is still pending. + let mut state = SessionState { + pending: vec![remote(1)], + restoring: true, + restore_front: Some(remote(1)), + ..SessionState::default() + }; + assert_eq!(state.activation_target(|window| window == LOCAL), None); + state.mark_open(remote(1)); + assert_eq!(state.activation_target(|_| true), Some(remote(1))); + assert_eq!(state.snapshot(), vec![remote(1)]); + // Still restoring, but nothing is left pending to wait for: with the + // restored window closed again, local is the only workspace left. + state.mark_closed(remote(1)); + assert_eq!(state.activation_target(|_| true), Some(LOCAL)); + } + #[test] fn stored_list_round_trips() { let windows = [remote(4), LOCAL, remote(2)]; diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 759cdf4b25..c1a2c27d1f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1375,7 +1375,9 @@ mod tauri_app { // `list_open_folder_details` / `list_opened_tabs` inside it. It // starts hidden only when it was hidden to the tray at quit and // other workspace windows are coming back in its place; the - // tray and explicit local-workspace actions still bring it up. + // tray, a `codeg://` link and the other explicit local-workspace + // actions still bring it up, and so do the Dock and a second + // launch once no other workspace is open or on its way back. if app.get_webview_window("main").is_none() { let url = tauri::WebviewUrl::App(workspace_path.into()); let builder = tauri::WebviewWindowBuilder::new(app, "main", url) @@ -2199,8 +2201,10 @@ mod tauri_app { tauri::RunEvent::ExitRequested { .. } | tauri::RunEvent::Exit => shut_down(app), #[cfg(target_os = "macos")] tauri::RunEvent::Reopen { .. } => { - // Auxiliary windows do not determine which workspace is - // active. Restore the last local/remote workspace instead. + // Every Dock click, whatever `has_visible_windows` says: + // it is true whenever an auxiliary window (pet, settings, + // commit…) is up, even with every workspace hidden or + // minimized. Raise the last-used local/remote workspace. workspace_windows::activate_workspace(app); } _ => {}