diff --git a/Sources/Fluid/AppDelegate.swift b/Sources/Fluid/AppDelegate.swift index 82e9bf45..c890f0db 100644 --- a/Sources/Fluid/AppDelegate.swift +++ b/Sources/Fluid/AppDelegate.swift @@ -18,6 +18,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele private var shouldSuppressNextReopenActivation = false private var wasLaunchedAsLoginItem = false private var hasDeferredMLXUpgradeOffer = false + private weak var mainWindowHiddenByAppHide: NSWindow? + private var shouldSuppressMainWindowLaunchReveal = false func applicationDidFinishLaunching(_ notification: Notification) { // Bring up file logging + crash handlers immediately during launch. @@ -128,16 +130,55 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele return true } + self.mainWindowHiddenByAppHide = nil + self.shouldSuppressMainWindowLaunchReveal = false + // Ensure dock-icon reopen always foregrounds FluidVoice. sender.activate(ignoringOtherApps: true) return !self.bringMainWindowToFrontIfPresent() } + func applicationWillHide(_ notification: Notification) { + // A system-hidden login launch is not a user request to suppress its configured reveal. + if self.wasLaunchedAsLoginItem, + !self.didRevealMainWindowOnLaunch, + !NSApp.isActive + { + return + } + + // A nonactivating recording panel can make AppKit unhide the process. Remember + // the visible main window so the panel does not restore it along with itself. + self.shouldSuppressMainWindowLaunchReveal = true + self.mainWindowHiddenByAppHide = NSApp.windows.first { + self.isMainWindow($0) && $0.isVisible && !$0.isMiniaturized + } + if self.mainWindowHiddenByAppHide != nil { + self.didRevealMainWindowOnLaunch = true + } + } + + func applicationDidHide(_ notification: Notification) { + self.mainWindowHiddenByAppHide?.orderOut(nil) + } + func applicationDidBecomeActive(_ notification: Notification) { - guard self.hasDeferredMLXUpgradeOffer else { return } - self.hasDeferredMLXUpgradeOffer = false - self.scheduleMLXUpgradeOffer() + self.shouldSuppressMainWindowLaunchReveal = false + + if let mainWindow = self.mainWindowHiddenByAppHide { + self.mainWindowHiddenByAppHide = nil + if mainWindow.alphaValue <= 0.01 { + mainWindow.alphaValue = 1 + } + mainWindow.orderFrontRegardless() + mainWindow.makeKeyAndOrderFront(nil) + } + + if self.hasDeferredMLXUpgradeOffer { + self.hasDeferredMLXUpgradeOffer = false + self.scheduleMLXUpgradeOffer() + } } func userNotificationCenter( @@ -200,7 +241,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele guard let self else { return } guard self.didRevealMainWindowOnLaunch == false else { return } - if revealWindow { + let shouldRevealWindow = revealWindow && !self.shouldSuppressMainWindowLaunchReveal + if shouldRevealWindow { NSApp.unhide(nil) NSApp.activate(ignoringOtherApps: true) @@ -209,13 +251,18 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele return } } else if self.bootMainWindowHiddenIfPresent() { + if self.shouldSuppressMainWindowLaunchReveal, + self.mainWindowHiddenByAppHide == nil + { + self.mainWindowHiddenByAppHide = NSApp.windows.first(where: self.isMainWindow) + } self.didRevealMainWindowOnLaunch = true return } DebugLogger.shared.debug("Main window not ready during launch reveal retry", source: "AppDelegate") if delay >= 0.6 { - self.requestMainWindowReopenIfNeeded(activate: revealWindow) + self.requestMainWindowReopenIfNeeded(activate: shouldRevealWindow) } } }