Fix window position restore on relaunch (#2129)
* test: cover accessible window frame restore * fix: preserve accessible window frame on relaunch
This commit is contained in:
parent
da70f3fa47
commit
0ea16b12c2
2 changed files with 69 additions and 0 deletions
|
|
@ -3066,6 +3066,15 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
|
|||
minHeight: CGFloat
|
||||
) -> CGRect {
|
||||
if targetDisplay.visibleFrame.intersects(frame) {
|
||||
// Preserve the user's exact frame when enough of the top of the window
|
||||
// remains reachable on-screen; only clamp when the saved frame would
|
||||
// reopen with an inaccessible titlebar/top strip.
|
||||
if shouldPreserveAccessibleFrame(
|
||||
frame: frame,
|
||||
targetDisplay: targetDisplay
|
||||
) {
|
||||
return frame
|
||||
}
|
||||
return clampFrame(
|
||||
frame,
|
||||
within: targetDisplay.visibleFrame,
|
||||
|
|
@ -3092,6 +3101,38 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
|
|||
)
|
||||
}
|
||||
|
||||
private nonisolated static func shouldPreserveAccessibleFrame(
|
||||
frame: CGRect,
|
||||
targetDisplay: SessionDisplayGeometry,
|
||||
minimumVisibleTopStripWidth: CGFloat = 120,
|
||||
topStripHeight: CGFloat = 64,
|
||||
minimumVisibleTopStripHeight: CGFloat = 24
|
||||
) -> Bool {
|
||||
let standardizedFrame = frame.standardized
|
||||
guard standardizedFrame.width.isFinite,
|
||||
standardizedFrame.height.isFinite,
|
||||
standardizedFrame.width > 0,
|
||||
standardizedFrame.height > 0,
|
||||
standardizedFrame.intersects(targetDisplay.frame) else {
|
||||
return false
|
||||
}
|
||||
|
||||
let stripHeight = min(topStripHeight, standardizedFrame.height)
|
||||
let topStrip = CGRect(
|
||||
x: standardizedFrame.minX,
|
||||
y: standardizedFrame.maxY - stripHeight,
|
||||
width: standardizedFrame.width,
|
||||
height: stripHeight
|
||||
)
|
||||
let visibleTopStrip = topStrip.intersection(targetDisplay.visibleFrame)
|
||||
guard !visibleTopStrip.isNull else { return false }
|
||||
|
||||
let requiredWidth = min(minimumVisibleTopStripWidth, standardizedFrame.width)
|
||||
let requiredHeight = min(minimumVisibleTopStripHeight, stripHeight)
|
||||
return visibleTopStrip.width >= requiredWidth
|
||||
&& visibleTopStrip.height >= requiredHeight
|
||||
}
|
||||
|
||||
private nonisolated static func display(
|
||||
for snapshot: SessionDisplaySnapshot?,
|
||||
in displays: [SessionDisplayGeometry]
|
||||
|
|
|
|||
|
|
@ -693,6 +693,34 @@ final class SessionPersistenceTests: XCTestCase {
|
|||
XCTAssertEqual(restored.height, 1_410, accuracy: 0.001)
|
||||
}
|
||||
|
||||
func testResolvedWindowFramePreservesExactGeometryWhenDisplayChangesButWindowRemainsAccessible() {
|
||||
let savedFrame = SessionRectSnapshot(x: 1_100, y: -20, width: 1_280, height: 1_000)
|
||||
let savedDisplay = SessionDisplaySnapshot(
|
||||
displayID: 2,
|
||||
frame: SessionRectSnapshot(x: 0, y: 0, width: 2_560, height: 1_440),
|
||||
visibleFrame: SessionRectSnapshot(x: 0, y: 0, width: 2_560, height: 1_410)
|
||||
)
|
||||
let adjustedDisplay = AppDelegate.SessionDisplayGeometry(
|
||||
displayID: 2,
|
||||
frame: CGRect(x: 0, y: 0, width: 2_560, height: 1_440),
|
||||
visibleFrame: CGRect(x: 0, y: 40, width: 2_560, height: 1_360)
|
||||
)
|
||||
|
||||
let restored = AppDelegate.resolvedWindowFrame(
|
||||
from: savedFrame,
|
||||
display: savedDisplay,
|
||||
availableDisplays: [adjustedDisplay],
|
||||
fallbackDisplay: adjustedDisplay
|
||||
)
|
||||
|
||||
XCTAssertNotNil(restored)
|
||||
guard let restored else { return }
|
||||
XCTAssertEqual(restored.minX, 1_100, accuracy: 0.001)
|
||||
XCTAssertEqual(restored.minY, -20, accuracy: 0.001)
|
||||
XCTAssertEqual(restored.width, 1_280, accuracy: 0.001)
|
||||
XCTAssertEqual(restored.height, 1_000, accuracy: 0.001)
|
||||
}
|
||||
|
||||
func testResolvedWindowFrameClampsWhenDisplayGeometryChangesEvenWithSameDisplayID() {
|
||||
let savedFrame = SessionRectSnapshot(x: 1_303, y: -90, width: 1_280, height: 1_410)
|
||||
let savedDisplay = SessionDisplaySnapshot(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue