macOS: fix window position for the very first window

pull/11421/head
Lukas 2026-03-12 13:43:57 +01:00
parent c399812036
commit 4f849a1512
No known key found for this signature in database
GPG Key ID: 1944A0A77B561220
3 changed files with 39 additions and 22 deletions

View File

@ -1061,22 +1061,6 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
}
}
// Set the initial window position. This must happen after the window
// is fully set up (content view, toolbar, default size) so that
// decorations added by subclass awakeFromNib (e.g. toolbar for tabs
// style) don't change the frame after the position is restored.
if let terminalWindow = window as? TerminalWindow {
terminalWindow.setInitialWindowPosition(
x: derivedConfig.windowPositionX,
y: derivedConfig.windowPositionY,
)
}
LastWindowPosition.shared.restore(
window,
origin: derivedConfig.windowPositionX == nil && derivedConfig.windowPositionY == nil,
size: defaultSize == nil,
)
// Store our initial frame so we can know our default later. This MUST
// be after the defaultSize call above so that we don't re-apply our frame.
@ -1110,6 +1094,34 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
syncAppearance(.init(config))
}
/// Setup correct window frame before showing the window
override func showWindow(_ sender: Any?) {
guard let terminalWindow = window as? TerminalWindow else { return }
// Set the initial window position. This must happen after the window
// is fully set up (content view, toolbar, default size) so that
// decorations added by subclass awakeFromNib (e.g. toolbar for tabs
// style) don't change the frame after the position is restored.
let originChanged = terminalWindow.setInitialWindowPosition(
x: derivedConfig.windowPositionX,
y: derivedConfig.windowPositionY,
)
let restored = LastWindowPosition.shared.restore(
terminalWindow,
origin: !originChanged,
size: defaultSize == nil,
)
// If nothing is changed for the frame,
// we should center the window
if !originChanged, !restored {
// This doesn't work in `windowDidLoad` somehow
terminalWindow.center()
}
super.showWindow(sender)
}
// Shows the "+" button in the tab bar, responds to that click.
override func newWindowForTab(_ sender: Any?) {
// Trigger the ghostty core event logic for a new tab.

View File

@ -536,17 +536,15 @@ class TerminalWindow: NSWindow {
terminalController?.updateColorSchemeForSurfaceTree()
}
func setInitialWindowPosition(x: Int16?, y: Int16?) {
func setInitialWindowPosition(x: Int16?, y: Int16?) -> Bool {
// If we don't have an X/Y then we try to use the previously saved window pos.
guard let x = x, let y = y else {
center()
return
return false
}
// Prefer the screen our window is being placed on otherwise our primary screen.
guard let screen = screen ?? NSScreen.screens.first else {
center()
return
return false
}
// Convert top-left coordinates to bottom-left origin using our utility extension
@ -562,6 +560,7 @@ class TerminalWindow: NSWindow {
safeOrigin.y = min(max(safeOrigin.y, vf.minY), vf.maxY - frame.height)
setFrameOrigin(safeOrigin)
return true
}
private func hideWindowButtons() {

View File

@ -50,7 +50,13 @@ class LastWindowPosition {
newFrame.size.height = min(values[3], visibleFrame.height)
}
if restoreOrigin, !visibleFrame.contains(newFrame.origin) {
// If the new frame is not constrained to the visible screen,
// we need to shift it a little bit before AppKit does this for us,
// so that we can save the correct size beforehand.
// This fixes restoration while running UI tests,
// where config is modified without switching apps,
// which will not trigger `windowDidBecomeMain`.
if restoreOrigin, !visibleFrame.contains(newFrame) {
newFrame.origin.x = max(visibleFrame.minX, min(visibleFrame.maxX - newFrame.width, newFrame.origin.x))
newFrame.origin.y = max(visibleFrame.minY, min(visibleFrame.maxY - newFrame.height, newFrame.origin.y))
}