macos: ensure previously key window regains key on toggle_visibility (#5692)

Fixes #5690

When we hide the app and then show it again, the previously key window
is lost. This is because we are not using unhide and are manually doing
it (and we're not using unhide for good reasons commented in the source
already).

Modify our hidden state to include what the key window was (as a weak
ref) and restore it when we show the app again.
This commit is contained in:
Mitchell Hashimoto
2025-02-11 11:23:48 -08:00
committed by GitHub

View File

@ -93,7 +93,7 @@ class AppDelegate: NSObject,
} }
/// Tracks the windows that we hid for toggleVisibility. /// Tracks the windows that we hid for toggleVisibility.
private var hiddenWindows: [Weak<NSWindow>] = [] private var hiddenState: ToggleVisibilityState? = nil
/// The observer for the app appearance. /// The observer for the app appearance.
private var appearanceObserver: NSKeyValueObservation? = nil private var appearanceObserver: NSKeyValueObservation? = nil
@ -217,8 +217,8 @@ class AppDelegate: NSObject,
} }
func applicationDidBecomeActive(_ notification: Notification) { func applicationDidBecomeActive(_ notification: Notification) {
// If we're back then clear the hidden windows // If we're back manually then clear the hidden state because macOS handles it.
self.hiddenWindows = [] self.hiddenState = nil
// First launch stuff // First launch stuff
if (!applicationHasBecomeActive) { if (!applicationHasBecomeActive) {
@ -716,14 +716,8 @@ class AppDelegate: NSObject,
guard let keyWindow = NSApp.keyWindow, guard let keyWindow = NSApp.keyWindow,
!keyWindow.styleMask.contains(.fullScreen) else { return } !keyWindow.styleMask.contains(.fullScreen) else { return }
// We need to keep track of the windows that were visible because we only // Keep track of our hidden state to restore properly
// want to bring back these windows if we remove the toggle. self.hiddenState = .init()
//
// We also ignore fullscreen windows because they don't hide anyways.
self.hiddenWindows = NSApp.windows.filter {
$0.isVisible &&
!$0.styleMask.contains(.fullScreen)
}.map { Weak($0) }
NSApp.hide(nil) NSApp.hide(nil)
return return
} }
@ -734,8 +728,8 @@ class AppDelegate: NSObject,
// Bring all windows to the front. Note: we don't use NSApp.unhide because // Bring all windows to the front. Note: we don't use NSApp.unhide because
// that will unhide ALL hidden windows. We want to only bring forward the // that will unhide ALL hidden windows. We want to only bring forward the
// ones that we hid. // ones that we hid.
self.hiddenWindows.forEach { $0.value?.orderFrontRegardless() } hiddenState?.restore()
self.hiddenWindows = [] hiddenState = nil
} }
private struct DerivedConfig { private struct DerivedConfig {
@ -755,4 +749,33 @@ class AppDelegate: NSObject,
self.quickTerminalPosition = config.quickTerminalPosition self.quickTerminalPosition = config.quickTerminalPosition
} }
} }
private struct ToggleVisibilityState {
let hiddenWindows: [Weak<NSWindow>]
let keyWindow: Weak<NSWindow>?
init() {
// We need to know the key window so that we can bring focus back to the
// right window if it was hidden.
self.keyWindow = if let keyWindow = NSApp.keyWindow {
.init(keyWindow)
} else {
nil
}
// We need to keep track of the windows that were visible because we only
// want to bring back these windows if we remove the toggle.
//
// We also ignore fullscreen windows because they don't hide anyways.
self.hiddenWindows = NSApp.windows.filter {
$0.isVisible &&
!$0.styleMask.contains(.fullScreen)
}.map { Weak($0) }
}
func restore() {
hiddenWindows.forEach { $0.value?.orderFrontRegardless() }
keyWindow?.value?.makeKey()
}
}
} }