Skip to content

Commit 0ea16b1

Browse files
authored
Fix window position restore on relaunch (#2129)
* test: cover accessible window frame restore * fix: preserve accessible window frame on relaunch
1 parent da70f3f commit 0ea16b1

2 files changed

Lines changed: 69 additions & 0 deletions

File tree

Sources/AppDelegate.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,6 +3066,15 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
30663066
minHeight: CGFloat
30673067
) -> CGRect {
30683068
if targetDisplay.visibleFrame.intersects(frame) {
3069+
// Preserve the user's exact frame when enough of the top of the window
3070+
// remains reachable on-screen; only clamp when the saved frame would
3071+
// reopen with an inaccessible titlebar/top strip.
3072+
if shouldPreserveAccessibleFrame(
3073+
frame: frame,
3074+
targetDisplay: targetDisplay
3075+
) {
3076+
return frame
3077+
}
30693078
return clampFrame(
30703079
frame,
30713080
within: targetDisplay.visibleFrame,
@@ -3092,6 +3101,38 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
30923101
)
30933102
}
30943103

3104+
private nonisolated static func shouldPreserveAccessibleFrame(
3105+
frame: CGRect,
3106+
targetDisplay: SessionDisplayGeometry,
3107+
minimumVisibleTopStripWidth: CGFloat = 120,
3108+
topStripHeight: CGFloat = 64,
3109+
minimumVisibleTopStripHeight: CGFloat = 24
3110+
) -> Bool {
3111+
let standardizedFrame = frame.standardized
3112+
guard standardizedFrame.width.isFinite,
3113+
standardizedFrame.height.isFinite,
3114+
standardizedFrame.width > 0,
3115+
standardizedFrame.height > 0,
3116+
standardizedFrame.intersects(targetDisplay.frame) else {
3117+
return false
3118+
}
3119+
3120+
let stripHeight = min(topStripHeight, standardizedFrame.height)
3121+
let topStrip = CGRect(
3122+
x: standardizedFrame.minX,
3123+
y: standardizedFrame.maxY - stripHeight,
3124+
width: standardizedFrame.width,
3125+
height: stripHeight
3126+
)
3127+
let visibleTopStrip = topStrip.intersection(targetDisplay.visibleFrame)
3128+
guard !visibleTopStrip.isNull else { return false }
3129+
3130+
let requiredWidth = min(minimumVisibleTopStripWidth, standardizedFrame.width)
3131+
let requiredHeight = min(minimumVisibleTopStripHeight, stripHeight)
3132+
return visibleTopStrip.width >= requiredWidth
3133+
&& visibleTopStrip.height >= requiredHeight
3134+
}
3135+
30953136
private nonisolated static func display(
30963137
for snapshot: SessionDisplaySnapshot?,
30973138
in displays: [SessionDisplayGeometry]

cmuxTests/SessionPersistenceTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,34 @@ final class SessionPersistenceTests: XCTestCase {
693693
XCTAssertEqual(restored.height, 1_410, accuracy: 0.001)
694694
}
695695

696+
func testResolvedWindowFramePreservesExactGeometryWhenDisplayChangesButWindowRemainsAccessible() {
697+
let savedFrame = SessionRectSnapshot(x: 1_100, y: -20, width: 1_280, height: 1_000)
698+
let savedDisplay = SessionDisplaySnapshot(
699+
displayID: 2,
700+
frame: SessionRectSnapshot(x: 0, y: 0, width: 2_560, height: 1_440),
701+
visibleFrame: SessionRectSnapshot(x: 0, y: 0, width: 2_560, height: 1_410)
702+
)
703+
let adjustedDisplay = AppDelegate.SessionDisplayGeometry(
704+
displayID: 2,
705+
frame: CGRect(x: 0, y: 0, width: 2_560, height: 1_440),
706+
visibleFrame: CGRect(x: 0, y: 40, width: 2_560, height: 1_360)
707+
)
708+
709+
let restored = AppDelegate.resolvedWindowFrame(
710+
from: savedFrame,
711+
display: savedDisplay,
712+
availableDisplays: [adjustedDisplay],
713+
fallbackDisplay: adjustedDisplay
714+
)
715+
716+
XCTAssertNotNil(restored)
717+
guard let restored else { return }
718+
XCTAssertEqual(restored.minX, 1_100, accuracy: 0.001)
719+
XCTAssertEqual(restored.minY, -20, accuracy: 0.001)
720+
XCTAssertEqual(restored.width, 1_280, accuracy: 0.001)
721+
XCTAssertEqual(restored.height, 1_000, accuracy: 0.001)
722+
}
723+
696724
func testResolvedWindowFrameClampsWhenDisplayGeometryChangesEvenWithSameDisplayID() {
697725
let savedFrame = SessionRectSnapshot(x: 1_303, y: -90, width: 1_280, height: 1_410)
698726
let savedDisplay = SessionDisplaySnapshot(

0 commit comments

Comments
 (0)