Ariver
2026-06-04 7a4f911c64b552081d957e826f32d90b2b11c858
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import AppKit
import CoreGraphics
import AlignerCore
 
@MainActor
final class WindowCoordinator: OverlaySessionDelegate {
    private let session: OverlaySession
    private let overlayWindowController: OverlayWindowController
    private let screenProvider: () -> [NSScreen]
    private let mouseLocationProvider: () -> NSPoint
    private let screenSpaceStateProvider: any OverlayScreenSpaceStateProviding
    private var currentContext: OverlayContext?
 
    init(
        overlayWindowController: OverlayWindowController,
        screenProvider: @escaping () -> [NSScreen] = { NSScreen.screens },
        mouseLocationProvider: @escaping () -> NSPoint = { NSEvent.mouseLocation },
        screenSpaceStateProvider: any OverlayScreenSpaceStateProviding = SkyLightOverlayScreenSpaceStateProvider()
    ) {
        self.session = OverlaySession()
        self.overlayWindowController = overlayWindowController
        self.screenProvider = screenProvider
        self.mouseLocationProvider = mouseLocationProvider
        self.screenSpaceStateProvider = screenSpaceStateProvider
        self.session.delegate = self
    }
 
    convenience init(
        contentView: NSView? = nil,
        title: String = "Aligner Quick Switch Overlay",
        debugOverlayWidth: CGFloat? = nil
    ) {
        let host = QuickSwitchOverlayHost(
            title: title,
            contentView: contentView,
            debugOverlayWidth: debugOverlayWidth
        )
        self.init(overlayWindowController: OverlayWindowController(host: host))
    }
 
    var isQuickSwitchVisible: Bool {
        session.state != .idle && overlayWindowController.isVisible
    }
 
    var currentLevel: CGWindowLevel {
        overlayWindowController.currentLevel
    }
 
    func toggleQuickSwitch() {
        if isQuickSwitchVisible {
            closeQuickSwitch(reason: .userClosed)
        } else {
            openQuickSwitch()
        }
    }
 
    func openQuickSwitch() {
        let placement = OverlayPlacementPolicy.placement(
            forMouseLocation: mouseLocationProvider(),
            screens: screenRecords()
        )
        let context = placement.overlayContext
 
        currentContext = context
        session.openQuickSwitch(context: context)
        overlayWindowController.show(context: context)
    }
 
    func closeQuickSwitch(reason: DismissReason) {
        session.dismiss(reason: reason)
    }
 
    func promoteForTextInput() {
        let allowAppActivation = currentContext?.spacePolicy.avoidSpaceSwitch != true
        overlayWindowController.promoteForTextInput(allowAppActivation: allowAppActivation)
    }
 
    func sessionDidChangeState(_ state: SessionState) {}
 
    func sessionShouldDismiss(reason: DismissReason) {
        overlayWindowController.hide(reason: reason)
        currentContext = nil
    }
 
    func sessionDidTimeout() {}
 
    private func screenRecords() -> [OverlayScreenRecord] {
        screenProvider().compactMap { screen in
            guard let displayUUID = Self.displayUUID(for: screen) else { return nil }
            return OverlayScreenRecord(
                displayUUID: displayUUID,
                frame: screen.frame,
                visibleFrame: screen.visibleFrame,
                spaceState: screenSpaceStateProvider.state(forDisplayUUID: displayUUID)
            )
        }
    }
 
    private static func displayUUID(for screen: NSScreen) -> String? {
        guard
            let number = screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? NSNumber,
            let unmanagedUUID = CGDisplayCreateUUIDFromDisplayID(CGDirectDisplayID(number.uint32Value))
        else {
            return nil
        }
 
        let uuid = unmanagedUUID.takeRetainedValue()
        return CFUUIDCreateString(nil, uuid) as String?
    }
}