fix(ui): Shutdown terminates the app even with secondary windows open

ShutdownWorkerAndCloseApp only closed MainWindow via CloseWindow, relying
on ShutdownMode.OnMainWindowClose to bring the process down. That mode
backs off if any window cancels its own Closing event, and
MissionControlWindow always does (it hides instead of closing) - so the
process never actually exited while Mission Control, Cheat Sheets, or the
diff viewer were still open. Call IClassicDesktopStyleApplicationLifetime
.Shutdown() directly, which force-closes every window regardless of
per-window cancellation.
This commit is contained in:
Mika Kuns
2026-09-16 15:43:36 +02:00
committed by mika kuns
parent 7ecb1fa0b5
commit 103eb9a687
2 changed files with 10 additions and 10 deletions
@@ -1,3 +1,5 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading; using Avalonia.Threading;
using System; using System;
using System.Threading; using System.Threading;
@@ -686,10 +688,6 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
} }
} }
// Set by MainWindow: force-closes the window without re-triggering its own close
// confirmation (the shutdown dialog above already confirmed).
public Action? CloseWindow { get; set; }
// Test seam: overrides the real kill-worker + close-window body. // Test seam: overrides the real kill-worker + close-window body.
internal Action? ShutdownOperation { get; set; } internal Action? ShutdownOperation { get; set; }
@@ -706,7 +704,14 @@ public sealed partial class IslandsShellViewModel : ViewModelBase, IDisposable
{ {
var exe = _workerLocator.Find(); var exe = _workerLocator.Find();
if (exe is not null) KillMatchingWorkerProcesses(exe); if (exe is not null) KillMatchingWorkerProcesses(exe);
CloseWindow?.Invoke();
// Closing just the MainWindow relies on ShutdownMode.OnMainWindowClose, which asks
// every open window to close and backs off if any of them cancels — and
// MissionControlWindow always cancels its own close (it hides instead, see
// MissionControlWindow.OnClosing), so the process never actually exited. Shutdown()
// force-closes every window, ignoring that cancellation.
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.Shutdown();
} }
private bool _updatingClaudeCli; private bool _updatingClaudeCli;
@@ -80,11 +80,6 @@ public partial class MainWindow : Window
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
Activate(); Activate();
}; };
vm.CloseWindow = () =>
{
_forceClose = true;
Close();
};
if (vm.Tasks is not null) if (vm.Tasks is not null)
vm.Tasks.IsWindowVisible = WindowState != WindowState.Minimized; vm.Tasks.IsWindowVisible = WindowState != WindowState.Minimized;
} }