import AppKit import Foundation @main @MainActor struct CompactWindowChecks { struct Failure: Error, CustomStringConvertible { let description: String } static func require(_ condition: @autoclosure () -> Bool, _ message: String) throws { if !condition() { throw Failure(description: "FAIL: \(message)") } } static func close(_ actual: CGFloat, _ expected: CGFloat) -> Bool { abs(actual - expected) < 0.001 } static func sameFrame(_ actual: NSRect, _ expected: NSRect) -> Bool { close(actual.minX, expected.minX) && close(actual.minY, expected.minY) && close(actual.width, expected.width) && close(actual.height, expected.height) } static func geometry() throws { let screen = NSRect(x: 100, y: 200, width: 1_000, height: 700) func snap(_ x: CGFloat, _ y: CGFloat, to expectedX: CGFloat, _ expectedY: CGFloat) throws { let frame = NSRect(x: x, y: y, width: 320, height: 180) let expected = NSRect(x: expectedX, y: expectedY, width: 320, height: 180) try require(sameFrame(CompactWindowController.snappedFrame(frame, visibleFrame: screen), expected), "snap (\(x), \(y)) to (\(expectedX), \(expectedY)), preserving size") } // Inset edges: x = 116 / 764, y = 216 / 704. Each axis acts independently. try snap(130, 460, to: 116, 460) try snap(750, 460, to: 764, 460) try snap(440, 230, to: 440, 216) try snap(440, 690, to: 440, 704) try snap(130, 230, to: 116, 216) try snap(750, 230, to: 764, 216) try snap(130, 690, to: 116, 704) try snap(750, 690, to: 764, 704) try snap(140, 460, to: 116, 460) try snap(740, 460, to: 764, 460) try snap(440, 240, to: 440, 216) try snap(440, 680, to: 440, 704) try snap(92, 460, to: 116, 460) try snap(788, 460, to: 764, 460) try snap(141, 460, to: 141, 460) try snap(739, 460, to: 739, 460) try snap(440, 241, to: 440, 241) try snap(440, 679, to: 440, 679) try snap(440, 192, to: 440, 216) try snap(440, 728, to: 440, 704) try snap(91, 460, to: 91, 460) try snap(789, 460, to: 789, 460) try snap(440, 191, to: 440, 191) try snap(440, 729, to: 440, 729) try snap(440, 460, to: 440, 460) let negativeScreen = NSRect(x: -1_440, y: -900, width: 1_440, height: 900) let negativeFrame = NSRect(x: -1_410, y: -870, width: 320, height: 180) try require(sameFrame(CompactWindowController.snappedFrame(negativeFrame, visibleFrame: negativeScreen), NSRect(x: -1_424, y: -884, width: 320, height: 180)), "negative-origin screen uses its own inset edges") let narrowScreen = NSRect(x: 0, y: 0, width: 100, height: 200) try require(sameFrame(CompactWindowController.snappedFrame( NSRect(x: 35, y: 80, width: 40, height: 20), visibleFrame: narrowScreen), NSRect(x: 44, y: 80, width: 40, height: 20)), "overlapping magnetic zones choose the closest edge, not first edge") let usableScreen = NSRect(x: -1_200, y: 50, width: 1_200, height: 800) let landscape = CompactWindowController.initialFrame(aspect: 16.0 / 9.0, visibleFrame: usableScreen) try require(sameFrame(landscape, NSRect(x: -336, y: 66, width: 320, height: 180)), "16:9 enters at bottom right with 320pt width and 16pt inset") let portrait = CompactWindowController.initialFrame(aspect: 9.0 / 16.0, visibleFrame: usableScreen) try require(sameFrame(portrait, NSRect(x: -336, y: 66, width: 320, height: 5_120.0 / 9.0)), "portrait preserves exact aspect when it fits") for aspect in [16.0 / 9.0, 9.0 / 16.0, 100.0, 0.01] { let frame = CompactWindowController.initialFrame(aspect: aspect, visibleFrame: usableScreen) try require(frame.origin.x.isFinite && frame.origin.y.isFinite && frame.width.isFinite && frame.height.isFinite, "initial geometry is finite for aspect \(aspect)") try require(frame.width >= 160 && frame.height >= 90, "extreme aspect \(aspect) never defeats minimum size") try require(frame.minX >= usableScreen.minX + 16 && frame.minY >= usableScreen.minY + 16 && frame.maxX <= usableScreen.maxX - 16 && frame.maxY <= usableScreen.maxY - 16, "aspect \(aspect) stays inside inset usable screen") try require(close(frame.maxX, usableScreen.maxX - 16) && close(frame.minY, usableScreen.minY + 16), "aspect \(aspect) stays anchored bottom right") } let smallScreen = NSRect(x: 0, y: 0, width: 300, height: 400) let bounded = CompactWindowController.initialFrame(aspect: 16.0 / 9.0, visibleFrame: smallScreen) try require(sameFrame(bounded, NSRect(x: 16, y: 16, width: 268, height: 150.75)), "target width shrinks to usable bounds without distorting ordinary aspect") } static func windowBehavior(defaults: UserDefaults) throws { _ = NSApplication.shared guard let screen = NSScreen.main else { throw Failure(description: "FAIL: native window checks require a macOS GUI session with a screen") } // Creating a window does not display it: never orderFront, makeKey, or enter native fullscreen. let window = NSWindow(contentRect: NSRect(x: -10_000, y: -10_000, width: 640, height: 360), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false) window.isReleasedWhenClosed = false defer { window.close() } guard let content = window.contentView else { throw Failure(description: "FAIL: missing content view") } let sentinel = NSView(frame: NSRect(x: 5, y: 7, width: 12, height: 14)) content.addSubview(sentinel) let sentinelFrame = sentinel.frame window.minSize = NSSize(width: 300, height: 180) window.contentMinSize = NSSize(width: 220, height: 120) window.aspectRatio = NSSize(width: 4, height: 3) window.collectionBehavior = [.managed, .fullScreenPrimary] window.level = .normal window.hidesOnDeactivate = true window.isMovableByWindowBackground = false let originalFrame = window.frame let originalMinSize = window.minSize let originalContentMinSize = window.contentMinSize let originalAspect = window.aspectRatio let originalStyle = window.styleMask let originalTitleVisibility = window.titleVisibility let originalTransparentTitlebar = window.titlebarAppearsTransparent let originalCollection = window.collectionBehavior let originalLevel = window.level let originalHides = window.hidesOnDeactivate let originalDrag = window.isMovableByWindowBackground let identity = ObjectIdentifier(window) let controller = CompactWindowController(defaults: defaults) defer { controller.restore(resumeFullScreen: false) } controller.attach(window) try require(!controller.isCompact && !controller.isTransitioning, "attached window starts ordinary") try require(controller.snappingEnabled, "fresh isolated preferences default snapping on") func preservedContent() throws { try require(ObjectIdentifier(window) == identity && sentinel.window === window, "compact mode keeps the actual rendering window") try require(window.contentView === content && sentinel.superview === content && content.subviews.count == 1 && sameFrame(sentinel.frame, sentinelFrame), "compact mode preserves content and attached sentinel without reparenting") try require(!window.isVisible, "checks never display a window") } func restored() throws { try require(!controller.isCompact && !controller.isTransitioning, "restore finishes in ordinary mode") try require(sameFrame(window.frame, originalFrame), "restore recovers original normal geometry") try require(window.minSize == originalMinSize && window.contentMinSize == originalContentMinSize && window.aspectRatio == originalAspect, "restore recovers aspect and both minima") try require(window.styleMask == originalStyle && window.collectionBehavior == originalCollection && window.level == originalLevel, "restore recovers style, Spaces policy, and level") try require(window.titleVisibility == originalTitleVisibility && window.titlebarAppearsTransparent == originalTransparentTitlebar, "restore recovers original native chrome") try require(window.hidesOnDeactivate == originalHides && window.isMovableByWindowBackground == originalDrag, "restore recovers deactivate and background drag behavior") try preservedContent() } controller.toggle(aspect: 16.0 / 9.0) try require(controller.isCompact && !controller.isTransitioning, "windowed toggle enters compact synchronously") try require(window.level == .floating && !window.hidesOnDeactivate, "compact floats and remains visible on deactivate") try require(window.collectionBehavior.contains([.canJoinAllSpaces, .canJoinAllApplications, .fullScreenAuxiliary]), "compact can join Spaces, other-app fullscreen, and Stage Manager") try require(window.collectionBehavior.intersection([.primary, .auxiliary, .fullScreenPrimary, .fullScreenNone]).isEmpty, "compact removes incompatible primary and auxiliary policies") try require(window.contentMinSize == NSSize(width: 160, height: 90), "compact uses 160x90 content minimum") try require(window.isMovableByWindowBackground, "compact allows background dragging") try require(window.canBecomeKey, "compact window still accepts keyboard playback controls") try preservedContent() let visible = (window.screen ?? screen).visibleFrame try require(close(window.frame.maxX, visible.maxX - 16) && close(window.frame.minY, visible.minY + 16) && close(window.frame.width / window.frame.height, 16.0 / 9.0), "actual compact window enters at inset bottom right with playback aspect") let nearEdge = NSRect(x: visible.minX + 26, y: visible.minY + 27, width: window.frame.width, height: window.frame.height) window.setFrame(nearEdge, display: false) try require(sameFrame(window.frame, nearEdge), "native move installs unsnapped drag position") controller.snapAfterDrag() try require(close(window.frame.minX, visible.minX + 16) && close(window.frame.minY, visible.minY + 16) && window.frame.size == nearEdge.size, "enabled preference snaps the actual moved window") controller.snappingEnabled = false let second = CompactWindowController(defaults: defaults) try require(!second.snappingEnabled, "disabled preference persists across controller instances") window.setFrame(nearEdge, display: false) controller.snapAfterDrag() try require(sameFrame(window.frame, nearEdge), "disabled preference leaves an actual moved window untouched") second.snappingEnabled = true let third = CompactWindowController(defaults: defaults) try require(third.snappingEnabled, "re-enabled preference persists across controller instances") controller.snappingEnabled = true let resized = NSRect(x: nearEdge.minX, y: nearEdge.minY, width: 240, height: 135) window.setFrame(resized, display: false) controller.updateAspect(16.0 / 9.0) try require(sameFrame(window.frame, resized), "repeated aspect updates preserve a user's compact resize and placement") controller.updateAspect(4.0 / 3.0) try require(controller.isCompact && !controller.isTransitioning, "aspect update retains compact mode") try require(close(window.frame.width / window.frame.height, 4.0 / 3.0), "actual compact window follows changed playback aspect") try preservedContent() controller.toggle(aspect: 4.0 / 3.0) try restored() controller.toggle(aspect: 16.0 / 9.0) controller.restore(resumeFullScreen: false) try restored() controller.restore(resumeFullScreen: false) try restored() // Replay AppKit's failure lifecycle without creating a visible fullscreen Space. NotificationCenter.default.post(name: NSWindow.willEnterFullScreenNotification, object: window) controller.toggle(aspect: 16.0 / 9.0) try require(controller.isTransitioning && !controller.isCompact, "compact entry waits for an in-flight native fullscreen transition") window.delegate?.windowDidFailToEnterFullScreen?(window) try restored() } static func main() throws { let suite = "terebi.compact-window-checks.\(UUID().uuidString)" guard let defaults = UserDefaults(suiteName: suite) else { throw Failure(description: "FAIL: cannot create isolated preference suite") } defer { defaults.removePersistentDomain(forName: suite) } try geometry() try windowBehavior(defaults: defaults) print("Compact window checks passed") } }