mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
macos: Cmd-Q without any window focus works
Previously, this would crash. Once the crash was fixed, it would hang because we would only show confirmation if the terminal window had focus. This introduces some medium complexity logic to work around this: 1. If we are the key window, then show the confirmation dialog. Done. 2. Otherwise, if any other window is a terminal window and is key, they're going to take it so we do nothing. 3. Otherwise, if we are the first terminal window in the application windows list, we show it even if we're not focused.
This commit is contained in:
@ -48,8 +48,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
if (windows.allSatisfy { !$0.isVisible }) { return .terminateNow }
|
if (windows.allSatisfy { !$0.isVisible }) { return .terminateNow }
|
||||||
|
|
||||||
// If the user is shutting down, restarting, or logging out, we don't confirm quit.
|
// If the user is shutting down, restarting, or logging out, we don't confirm quit.
|
||||||
if let event = NSAppleEventManager.shared().currentAppleEvent {
|
why: if let event = NSAppleEventManager.shared().currentAppleEvent {
|
||||||
if let why = event.attributeDescriptor(forKeyword: AEKeyword("why?")!) {
|
// If all Ghostty windows are in the background (i.e. you Cmd-Q from the Cmd-Tab
|
||||||
|
// view), then this is null. I don't know why (pun intended) but we have to
|
||||||
|
// guard against it.
|
||||||
|
guard let keyword = AEKeyword("why?") else { break why }
|
||||||
|
|
||||||
|
if let why = event.attributeDescriptor(forKeyword: keyword) {
|
||||||
switch (why.typeCodeValue) {
|
switch (why.typeCodeValue) {
|
||||||
case kAEShutDown:
|
case kAEShutDown:
|
||||||
fallthrough
|
fallthrough
|
||||||
|
@ -24,6 +24,28 @@ struct PrimaryView: View {
|
|||||||
@FocusedValue(\.ghosttySurfaceView) private var focusedSurface
|
@FocusedValue(\.ghosttySurfaceView) private var focusedSurface
|
||||||
@FocusedValue(\.ghosttySurfaceTitle) private var surfaceTitle
|
@FocusedValue(\.ghosttySurfaceTitle) private var surfaceTitle
|
||||||
|
|
||||||
|
// This is true if this view should be the one to show the quit confirmation.
|
||||||
|
var ownsQuitConfirmation: Bool {
|
||||||
|
// We need to have a window to show a confirmation.
|
||||||
|
guard let window = self.window else { return false }
|
||||||
|
|
||||||
|
// If we are the key window then definitely yes.
|
||||||
|
if (window.isKeyWindow) { return true }
|
||||||
|
|
||||||
|
// If there is some other PrimaryWindow that is key, let it handle it.
|
||||||
|
let windows = NSApplication.shared.windows
|
||||||
|
if (windows.contains {
|
||||||
|
guard let primary = $0 as? PrimaryWindow else { return false }
|
||||||
|
return primary.isKeyWindow
|
||||||
|
}) { return false }
|
||||||
|
|
||||||
|
// We aren't the key window but also there is no key PrimaryWindow.
|
||||||
|
// If we are the FIRST PrimaryWindow in the windows array, then
|
||||||
|
// we take the job.
|
||||||
|
guard let firstWindow = (windows.first { $0 is PrimaryWindow }) else { return false }
|
||||||
|
return window == firstWindow
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
switch ghostty.readiness {
|
switch ghostty.readiness {
|
||||||
case .loading:
|
case .loading:
|
||||||
@ -44,7 +66,7 @@ struct PrimaryView: View {
|
|||||||
let toggleFullscreen = center.publisher(for: Ghostty.Notification.ghosttyToggleFullscreen)
|
let toggleFullscreen = center.publisher(for: Ghostty.Notification.ghosttyToggleFullscreen)
|
||||||
|
|
||||||
let confirmQuitting = Binding<Bool>(get: {
|
let confirmQuitting = Binding<Bool>(get: {
|
||||||
self.appDelegate.confirmQuit && (self.window?.isKeyWindow ?? false)
|
self.appDelegate.confirmQuit && self.ownsQuitConfirmation
|
||||||
}, set: {
|
}, set: {
|
||||||
self.appDelegate.confirmQuit = $0
|
self.appDelegate.confirmQuit = $0
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user