macos: quick terminal stores the last closed size by screen

Fixes #8713

This stores the last closed state of the quick terminal by screen
pointer. We use a weak mapping so if a screen is unplugged we'll clear
the memory. We will not remember the size if you unplug and replug in a
monitor.
This commit is contained in:
Mitchell Hashimoto
2025-09-19 12:44:32 -07:00
parent 3ce1239460
commit 4d761c96e5

View File

@@ -21,13 +21,13 @@ class QuickTerminalController: BaseTerminalController {
// The active space when the quick terminal was last shown. // The active space when the quick terminal was last shown.
private var previousActiveSpace: CGSSpace? = nil private var previousActiveSpace: CGSSpace? = nil
/// The window frame saved when the quick terminal's surface tree becomes empty. /// The saved state when the quick terminal's surface tree becomes empty.
/// ///
/// This preserves the user's window size and position when all terminal surfaces /// This preserves the user's window size and position when all terminal surfaces
/// are closed (e.g., via the `exit` command). When a new surface is created, /// are closed (e.g., via the `exit` command). When a new surface is created,
/// the window will be restored to this frame, preventing SwiftUI from resetting /// the window will be restored to this frame, preventing SwiftUI from resetting
/// the window to its default minimum size. /// the window to its default minimum size.
private var lastClosedFrame: NSRect? = nil private var lastClosedFrames: NSMapTable<NSScreen, LastClosedState>
/// Non-nil if we have hidden dock state. /// Non-nil if we have hidden dock state.
private var hiddenDock: HiddenDock? = nil private var hiddenDock: HiddenDock? = nil
@@ -46,6 +46,10 @@ class QuickTerminalController: BaseTerminalController {
self.position = position self.position = position
self.derivedConfig = DerivedConfig(ghostty.config) self.derivedConfig = DerivedConfig(ghostty.config)
// This is a weak to strong mapping, so that our keys being NSScreens
// can remove themselves when they disappear.
self.lastClosedFrames = .weakToStrongObjects()
// Important detail here: we initialize with an empty surface tree so // Important detail here: we initialize with an empty surface tree so
// that we don't start a terminal process. This gets started when the // that we don't start a terminal process. This gets started when the
// first terminal is shown in `animateIn`. // first terminal is shown in `animateIn`.
@@ -360,8 +364,9 @@ class QuickTerminalController: BaseTerminalController {
guard let screen = derivedConfig.quickTerminalScreen.screen else { return } guard let screen = derivedConfig.quickTerminalScreen.screen else { return }
// Grab our last closed frame to use, and clear our state since we're animating in. // Grab our last closed frame to use, and clear our state since we're animating in.
let lastClosedFrame = self.lastClosedFrame // We only use the last closed frame if we're opening on the same screen.
self.lastClosedFrame = nil let lastClosedFrame: NSRect? = lastClosedFrames.object(forKey: screen)?.frame
lastClosedFrames.removeObject(forKey: screen)
// Move our window off screen to the initial animation position. // Move our window off screen to the initial animation position.
position.setInitial( position.setInitial(
@@ -491,8 +496,8 @@ class QuickTerminalController: BaseTerminalController {
// the user's preferred window size and position for when the quick // the user's preferred window size and position for when the quick
// terminal is reactivated with a new surface. Without this, SwiftUI // terminal is reactivated with a new surface. Without this, SwiftUI
// would reset the window to its minimum content size. // would reset the window to its minimum content size.
if window.frame.width > 0 && window.frame.height > 0 { if window.frame.width > 0 && window.frame.height > 0, let screen = window.screen {
lastClosedFrame = window.frame lastClosedFrames.setObject(.init(frame: window.frame), forKey: screen)
} }
// If we hid the dock then we unhide it. // If we hid the dock then we unhide it.
@@ -715,6 +720,14 @@ class QuickTerminalController: BaseTerminalController {
hidden = false hidden = false
} }
} }
private class LastClosedState {
let frame: NSRect
init(frame: NSRect) {
self.frame = frame
}
}
} }
extension Notification.Name { extension Notification.Name {