From 41943b9a00e46840ccfb74c3f348392e9479b74e Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 27 Mar 2023 10:05:29 -0700 Subject: [PATCH] macos: quit if we have no visible windows --- macos/Sources/GhosttyApp.swift | 9 +++++++++ macos/Sources/SettingsView.swift | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/macos/Sources/GhosttyApp.swift b/macos/Sources/GhosttyApp.swift index 5a34f5df6..e1f1406fe 100644 --- a/macos/Sources/GhosttyApp.swift +++ b/macos/Sources/GhosttyApp.swift @@ -120,6 +120,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { } func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { + let windows = NSApplication.shared.windows + if (windows.isEmpty) { return .terminateNow } + + // This probably isn't fully safe. The isEmpty check above is aspirational, it doesn't + // quit work with SwiftUI because windows are retained on close. So instead we check + // if there are any that are visible. I'm guessing this breaks under certain scenarios. + if (windows.allSatisfy { !$0.isVisible }) { return .terminateNow } + + // We have some visible window, and all our windows will watch the confirmQuit. confirmQuit = true return .terminateLater } diff --git a/macos/Sources/SettingsView.swift b/macos/Sources/SettingsView.swift index e419f9dfe..379233d55 100644 --- a/macos/Sources/SettingsView.swift +++ b/macos/Sources/SettingsView.swift @@ -1,6 +1,9 @@ import SwiftUI struct SettingsView: View { + // We need access to our app delegate to know if we're quitting or not. + @EnvironmentObject private var appDelegate: AppDelegate + var body: some View { HStack { Image("AppIconImage") @@ -18,6 +21,10 @@ struct SettingsView: View { } .padding() .frame(minWidth: 500, maxWidth: 500, minHeight: 156, maxHeight: 156) + .onChange(of: appDelegate.confirmQuit) { value in + guard value else { return } + NSApplication.shared.reply(toApplicationShouldTerminate: true) + } } }