macos: unify confirm close in our terminal controllers
parent
d1dce1e372
commit
b84b715ddb
|
|
@ -194,6 +194,40 @@ class BaseTerminalController: NSWindowController,
|
||||||
savedFrame = .init(window: window.frame, screen: screen.visibleFrame)
|
savedFrame = .init(window: window.frame, screen: screen.visibleFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func confirmClose(
|
||||||
|
messageText: String,
|
||||||
|
informativeText: String,
|
||||||
|
completion: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
// If we already have an alert, we need to wait for that one.
|
||||||
|
guard alert == nil else { return }
|
||||||
|
|
||||||
|
// If there is no window to attach the modal then we assume success
|
||||||
|
// since we'll never be able to show the modal.
|
||||||
|
guard let window else {
|
||||||
|
completion()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we need confirmation by any, show one confirmation for all windows
|
||||||
|
// in the tab group.
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = messageText
|
||||||
|
alert.informativeText = informativeText
|
||||||
|
alert.addButton(withTitle: "Close")
|
||||||
|
alert.addButton(withTitle: "Cancel")
|
||||||
|
alert.alertStyle = .warning
|
||||||
|
alert.beginSheetModal(for: window) { response in
|
||||||
|
self.alert = nil
|
||||||
|
if response == .alertFirstButtonReturn {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store our alert so we only ever show one.
|
||||||
|
self.alert = alert
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Notifications
|
// MARK: Notifications
|
||||||
|
|
||||||
@objc private func didChangeScreenParametersNotification(_ notification: Notification) {
|
@objc private func didChangeScreenParametersNotification(_ notification: Notification) {
|
||||||
|
|
@ -287,37 +321,19 @@ class BaseTerminalController: NSWindowController,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't have a window to attach our modal to, we also exit immediately.
|
|
||||||
// This should NOT happen.
|
|
||||||
guard let window = target.window else {
|
|
||||||
surfaceTree2 = surfaceTree2.remove(node)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirm close. We use an NSAlert instead of a SwiftUI confirmationDialog
|
// Confirm close. We use an NSAlert instead of a SwiftUI confirmationDialog
|
||||||
// due to SwiftUI bugs (see Ghostty #560). To repeat from #560, the bug is that
|
// due to SwiftUI bugs (see Ghostty #560). To repeat from #560, the bug is that
|
||||||
// confirmationDialog allows the user to Cmd-W close the alert, but when doing
|
// confirmationDialog allows the user to Cmd-W close the alert, but when doing
|
||||||
// so SwiftUI does not update any of the bindings to note that window is no longer
|
// so SwiftUI does not update any of the bindings to note that window is no longer
|
||||||
// being shown, and provides no callback to detect this.
|
// being shown, and provides no callback to detect this.
|
||||||
let alert = NSAlert()
|
confirmClose(
|
||||||
alert.messageText = "Close Terminal?"
|
messageText: "Close Terminal?",
|
||||||
alert.informativeText = "The terminal still has a running process. If you close the " +
|
informativeText: "The terminal still has a running process. If you close the terminal the process will be killed."
|
||||||
"terminal the process will be killed."
|
) { [weak self] in
|
||||||
alert.addButton(withTitle: "Close the Terminal")
|
if let self {
|
||||||
alert.addButton(withTitle: "Cancel")
|
self.surfaceTree2 = self.surfaceTree2.remove(node)
|
||||||
alert.alertStyle = .warning
|
|
||||||
alert.beginSheetModal(for: window, completionHandler: { [weak self] response in
|
|
||||||
switch (response) {
|
|
||||||
case .alertFirstButtonReturn:
|
|
||||||
alert.window.orderOut(nil)
|
|
||||||
if let self {
|
|
||||||
self.surfaceTree2 = self.surfaceTree2.remove(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func ghosttyDidNewSplit(_ notification: Notification) {
|
@objc private func ghosttyDidNewSplit(_ notification: Notification) {
|
||||||
|
|
@ -624,26 +640,12 @@ class BaseTerminalController: NSWindowController,
|
||||||
if (!node.needsConfirmQuit()) { return true }
|
if (!node.needsConfirmQuit()) { return true }
|
||||||
|
|
||||||
// We require confirmation, so show an alert as long as we aren't already.
|
// We require confirmation, so show an alert as long as we aren't already.
|
||||||
let alert = NSAlert()
|
confirmClose(
|
||||||
alert.messageText = "Close Terminal?"
|
messageText: "Close Terminal?",
|
||||||
alert.informativeText = "The terminal still has a running process. If you close the " +
|
informativeText: "The terminal still has a running process. If you close the terminal the process will be killed."
|
||||||
"terminal the process will be killed."
|
) {
|
||||||
alert.addButton(withTitle: "Close the Terminal")
|
window.close()
|
||||||
alert.addButton(withTitle: "Cancel")
|
}
|
||||||
alert.alertStyle = .warning
|
|
||||||
alert.beginSheetModal(for: window, completionHandler: { response in
|
|
||||||
self.alert = nil
|
|
||||||
switch (response) {
|
|
||||||
case .alertFirstButtonReturn:
|
|
||||||
alert.window.orderOut(nil)
|
|
||||||
window.close()
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.alert = alert
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -587,27 +587,6 @@ class TerminalController: BaseTerminalController {
|
||||||
ghostty.newTab(surface: surface)
|
ghostty.newTab(surface: surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func confirmClose(
|
|
||||||
window: NSWindow,
|
|
||||||
messageText: String,
|
|
||||||
informativeText: String,
|
|
||||||
completion: @escaping () -> Void
|
|
||||||
) {
|
|
||||||
// If we need confirmation by any, show one confirmation for all windows
|
|
||||||
// in the tab group.
|
|
||||||
let alert = NSAlert()
|
|
||||||
alert.messageText = messageText
|
|
||||||
alert.informativeText = informativeText
|
|
||||||
alert.addButton(withTitle: "Close")
|
|
||||||
alert.addButton(withTitle: "Cancel")
|
|
||||||
alert.alertStyle = .warning
|
|
||||||
alert.beginSheetModal(for: window) { response in
|
|
||||||
if response == .alertFirstButtonReturn {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func closeTab(_ sender: Any?) {
|
@IBAction func closeTab(_ sender: Any?) {
|
||||||
guard let window = window else { return }
|
guard let window = window else { return }
|
||||||
guard window.tabGroup != nil else {
|
guard window.tabGroup != nil else {
|
||||||
|
|
@ -618,7 +597,6 @@ class TerminalController: BaseTerminalController {
|
||||||
|
|
||||||
if surfaceTree?.needsConfirmQuit() ?? false {
|
if surfaceTree?.needsConfirmQuit() ?? false {
|
||||||
confirmClose(
|
confirmClose(
|
||||||
window: window,
|
|
||||||
messageText: "Close Tab?",
|
messageText: "Close Tab?",
|
||||||
informativeText: "The terminal still has a running process. If you close the tab the process will be killed."
|
informativeText: "The terminal still has a running process. If you close the tab the process will be killed."
|
||||||
) {
|
) {
|
||||||
|
|
@ -664,7 +642,6 @@ class TerminalController: BaseTerminalController {
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmClose(
|
confirmClose(
|
||||||
window: window,
|
|
||||||
messageText: "Close Window?",
|
messageText: "Close Window?",
|
||||||
informativeText: "All terminal sessions in this window will be terminated."
|
informativeText: "All terminal sessions in this window will be terminated."
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue