From 777929a8fe603574474f6e1c9c0a35c08af1a2d9 Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Fri, 28 Aug 2026 19:32:27 +0200 Subject: [PATCH] macOS: review windows when closing multiple tabs --- macos/Sources/App/AppDelegate.swift | 10 +--- .../Terminal/TerminalController.swift | 55 ++++++++++++++++--- .../Extensions/NSAlert+Extension.swift | 19 +++++++ 3 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 macos/Sources/Helpers/Extensions/NSAlert+Extension.swift diff --git a/macos/Sources/App/AppDelegate.swift b/macos/Sources/App/AppDelegate.swift index 91d6f15c1..30ac31a68 100644 --- a/macos/Sources/App/AppDelegate.swift +++ b/macos/Sources/App/AppDelegate.swift @@ -1346,13 +1346,9 @@ extension AppDelegate { return .terminateLater } else { - let alert = NSAlert() - alert.messageText = "You have \(controllersNeedConfirmation.count) windows with running processes. Do you want to review these windows before quitting?" - alert.informativeText = "If you don't review your windows, any running processes will be terminated" - alert.addButton(withTitle: "Review Windows...") - alert.addButton(withTitle: "Terminate Processes") - alert.addButton(withTitle: "Cancel") - alert.alertStyle = .warning + let alert = NSAlert.reviewWindowsAlert( + messageText: "You have \(controllersNeedConfirmation.count) windows with running processes. Do you want to review these windows before quitting?" + ) switch alert.runModal() { case .alertFirstButtonReturn: diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index 32c5db855..5e556afea 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -1386,21 +1386,58 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr // if we're closing the window. If we don't have a tabgroup for any // reason we check ourselves. let windows: [NSWindow] = window.tabGroup?.windows ?? [window] - guard let confirmController = windows + let confirmControllers = windows .compactMap({ $0.windowController as? TerminalController }) - .first(where: { $0.surfaceTree.contains(where: { $0.needsConfirmQuit }) }) + .filter({ $0.surfaceTree.contains(where: { $0.needsConfirmQuit }) }) + guard + !confirmControllers.isEmpty else { closeWindowImmediately() return } + if confirmControllers.count == 1 { + // We call confirmClose on the proper controller so the alert is + // attached to the window that needs confirmation. + confirmControllers[0].confirmClose( + messageText: "Close Window?", + informativeText: "All terminal sessions in this window will be terminated.", + ) { + self.closeWindowImmediately() + } + return + } - // We call confirmClose on the proper controller so the alert is - // attached to the window that needs confirmation. - confirmController.confirmClose( - messageText: "Close Window?", - informativeText: "All terminal sessions in this window will be terminated.", - ) { - self.closeWindowImmediately() + Task { + let alert = NSAlert.reviewWindowsAlert( + messageText: "You have \(confirmControllers.count) windows with running processes. Do you want to review these windows before closing?", + terminateNowButtonTitle: "Close" + ) + switch await alert.beginSheetModal(for: window) { + case .alertFirstButtonReturn: + await reviewWindows(confirmControllers, window: window) + case .alertSecondButtonReturn: + closeWindowImmediately() + default: + break + } + } + } + + private func reviewWindows(_ controllers: [TerminalController], window: NSWindow) async { + for controller in controllers { + let response = await controller.confirmCloseAsync( + messageText: "Close Window?", + informativeText: "All terminal sessions in this window will be terminated.", + ) + + if [.OK, .alertFirstButtonReturn].contains(response) { + // Close this tab + controller.closeTabImmediately() + continue + } else { + // Cancel the review + return + } } } diff --git a/macos/Sources/Helpers/Extensions/NSAlert+Extension.swift b/macos/Sources/Helpers/Extensions/NSAlert+Extension.swift new file mode 100644 index 000000000..edf755af4 --- /dev/null +++ b/macos/Sources/Helpers/Extensions/NSAlert+Extension.swift @@ -0,0 +1,19 @@ +import AppKit + +extension NSAlert { + static func reviewWindowsAlert( + messageText: String, + informativeText: String = "If you don't review your windows, any running processes will be terminated", + terminateNowButtonTitle: String = "Terminate Processes" + ) -> NSAlert { + let alert = NSAlert() + alert.messageText = messageText + alert.informativeText = informativeText + alert.addButton(withTitle: "Review Windows...") + alert.addButton(withTitle: terminateNowButtonTitle) + alert.addButton(withTitle: "Cancel") + alert.alertStyle = .warning + + return alert + } +}