fix: bring windows to front and into Cmd-Tab while open

Accessory apps never appear in the Cmd-Tab switcher and macOS does not
activate them when they open windows — the log window opened behind
other apps (settings only worked via a manual activate call).

presentWindow(of:) now switches the activation policy to .regular
while a BrewBar window is open, giving a Dock icon and a Cmd-Tab entry;
a willClose observer drops back to .accessory once the last window is
gone. Used by both showLogs and showSettings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
maxsoch 2026-07-07 05:58:23 +02:00
parent 25e4476317
commit 59683ee8a9

View file

@ -48,6 +48,13 @@ class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_: Notification) {
Settings.registerDefaults()
NotificationCenter.default.addObserver(
self,
selector: #selector(windowWillClose(_:)),
name: NSWindow.willCloseNotification,
object: nil
)
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
statusItem.button?.imagePosition = .imageLeft // icon stays visible next to the count
setMenuBarIcon("brewbar-uptodate")
@ -117,10 +124,31 @@ class AppDelegate: NSObject, NSApplicationDelegate {
settingsWindow = SettingsWindowController(appDelegate: self)
}
settingsWindow?.syncUI()
settingsWindow?.showWindow(nil)
// accessory app: without activation the window can open behind others
presentWindow(of: settingsWindow)
}
// MARK: - Window presentation
/// Accessory apps never appear in Cmd-Tab and their windows can open
/// behind other apps. While one of our windows is open we temporarily
/// become a regular app (Dock icon + Cmd-Tab entry); windowWillClose
/// drops back to accessory once the last window is gone.
func presentWindow(of controller: NSWindowController?) {
NSApp.setActivationPolicy(.regular)
controller?.showWindow(nil)
NSApp.activate(ignoringOtherApps: true)
settingsWindow?.window?.makeKeyAndOrderFront(nil)
controller?.window?.makeKeyAndOrderFront(nil)
}
@objc func windowWillClose(_: Notification) {
// async so the closing window's isVisible has flipped to false
DispatchQueue.main.async {
let ourWindows = [self.logWindow?.window, self.settingsWindow?.window]
let stillOpen = ourWindows.compactMap { $0 }.contains { $0.isVisible }
if !stillOpen {
NSApp.setActivationPolicy(.accessory)
}
}
}
func resolveBrewPath() -> String {
@ -433,7 +461,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if logWindow == nil {
logWindow = LogWindowController()
}
logWindow?.showWindow(nil)
logWindow?.update(text: logBuffer)
presentWindow(of: logWindow)
}
}