import Foundation public struct LauncherAlignment: Sendable { public let targetFrame: CGRect public let snappedOrigin: CGPoint public init(windowFrame: CGRect, visibleFrame: CGRect) { // Whole-point origins keep the guides aligned with AppKit's window positioning. targetFrame = CGRect( x: (visibleFrame.midX - windowFrame.width / 2).rounded(.down), y: (visibleFrame.maxY - visibleFrame.height / 5 - windowFrame.height).rounded(.down), width: windowFrame.width, height: windowFrame.height ) snappedOrigin = CGPoint( x: abs(windowFrame.minX - targetFrame.minX) <= 12 ? targetFrame.minX : windowFrame.minX, y: abs(windowFrame.maxY - targetFrame.maxY) <= 12 ? targetFrame.minY : windowFrame.minY ) } public static func restoredFrame(savedCenter: CGPoint?, windowSize: CGSize, visibleFrame: CGRect) -> CGRect { if let savedCenter, savedCenter.x.isFinite, savedCenter.y.isFinite { let saved = CGRect(x: savedCenter.x - windowSize.width / 2, y: savedCenter.y - windowSize.height / 2, width: windowSize.width, height: windowSize.height) if visibleFrame.contains(saved) { return saved } } var frame = LauncherAlignment( windowFrame: CGRect(origin: .zero, size: windowSize), visibleFrame: visibleFrame ).targetFrame frame.origin.x = max(visibleFrame.minX, min(frame.minX, visibleFrame.maxX - frame.width)) frame.origin.y = max(visibleFrame.minY, min(frame.minY, visibleFrame.maxY - frame.height)) return frame } }