Ariver
2026-06-19 6f2856fa70722dad7f7c69a3addaa05ea9fd6e94
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import Foundation
 
public struct QuickSwitchWindowItem: Equatable, Sendable {
    public let window: AlignerWindow
    public let primarySpaceID: UInt64?
 
    public init(window: AlignerWindow, primarySpaceID: UInt64?) {
        self.window = window
        self.primarySpaceID = primarySpaceID
    }
}
 
public struct QuickSwitchAppGroup: Equatable, Sendable {
    public let app: AlignerApp
    public let windows: [QuickSwitchWindowItem]
 
    public init(app: AlignerApp, windows: [QuickSwitchWindowItem]) {
        self.app = app
        self.windows = windows
    }
}
 
public struct QuickSwitchSnapshot: Equatable, Sendable {
    public let displays: [AlignerDisplay]
    public let appGroups: [QuickSwitchAppGroup]
 
    public init(displays: [AlignerDisplay], appGroups: [QuickSwitchAppGroup]) {
        self.displays = displays
        self.appGroups = appGroups
    }
}
 
public enum QuickSwitchSnapshotBuilder {
    public static func snapshot(
        displays: [AlignerDisplay],
        windows: [AlignerWindow]
    ) -> QuickSwitchSnapshot {
        let displayOrder = spaceOrder(from: displays)
        let candidateWindows = windows.filter(WindowDisplayPolicy.shouldDisplay)
        let groupedWindows = Dictionary(grouping: candidateWindows) {
            AppIdentity(app: $0.app)
        }
 
        let appGroups = groupedWindows.values.compactMap { windows -> QuickSwitchAppGroup? in
            guard let firstWindow = windows.first else { return nil }
            let sortedWindows = windows
                .sorted { lhs, rhs in
                    compareWindows(lhs, rhs, displayOrder: displayOrder)
                }
                .map { window in
                    QuickSwitchWindowItem(
                        window: window,
                        primarySpaceID: primarySpaceID(for: window, displayOrder: displayOrder)
                    )
                }
 
            return QuickSwitchAppGroup(app: firstWindow.app, windows: sortedWindows)
        }
        .sorted { lhs, rhs in
            compareApps(lhs.app, rhs.app)
        }
 
        return QuickSwitchSnapshot(displays: displays, appGroups: appGroups)
    }
 
    private static func spaceOrder(from displays: [AlignerDisplay]) -> [UInt64: Int] {
        var order: [UInt64: Int] = [:]
        var nextIndex = 0
 
        for display in displays.sorted(by: { $0.uuid.localizedStandardCompare($1.uuid) == .orderedAscending }) {
            for space in display.spaces.sorted(by: { $0.index < $1.index }) {
                order[space.id] = nextIndex
                nextIndex += 1
            }
        }
 
        return order
    }
 
    private static func compareApps(_ lhs: AlignerApp, _ rhs: AlignerApp) -> Bool {
        let nameOrder = lhs.name.localizedCaseInsensitiveCompare(rhs.name)
        if nameOrder != .orderedSame {
            return nameOrder == .orderedAscending
        }
 
        let bundleOrder = normalized(lhs.bundleIdentifier)
            .localizedCaseInsensitiveCompare(normalized(rhs.bundleIdentifier))
        if bundleOrder != .orderedSame {
            return bundleOrder == .orderedAscending
        }
 
        let pathOrder = normalized(lhs.executablePath)
            .localizedCaseInsensitiveCompare(normalized(rhs.executablePath))
        if pathOrder != .orderedSame {
            return pathOrder == .orderedAscending
        }
 
        return (lhs.processIdentifier ?? Int32.max) < (rhs.processIdentifier ?? Int32.max)
    }
 
    private static func compareWindows(
        _ lhs: AlignerWindow,
        _ rhs: AlignerWindow,
        displayOrder: [UInt64: Int]
    ) -> Bool {
        let lhsSpaceOrder = primarySpaceOrder(for: lhs, displayOrder: displayOrder)
        let rhsSpaceOrder = primarySpaceOrder(for: rhs, displayOrder: displayOrder)
        if lhsSpaceOrder != rhsSpaceOrder {
            return lhsSpaceOrder < rhsSpaceOrder
        }
 
        let titleOrder = lhs.title.localizedCaseInsensitiveCompare(rhs.title)
        if titleOrder != .orderedSame {
            return titleOrder == .orderedAscending
        }
 
        return lhs.id < rhs.id
    }
 
    private static func primarySpaceID(
        for window: AlignerWindow,
        displayOrder: [UInt64: Int]
    ) -> UInt64? {
        window.spaceIDs.min { lhs, rhs in
            (displayOrder[lhs] ?? Int.max) < (displayOrder[rhs] ?? Int.max)
        }
    }
 
    private static func primarySpaceOrder(
        for window: AlignerWindow,
        displayOrder: [UInt64: Int]
    ) -> Int {
        guard let primarySpaceID = primarySpaceID(for: window, displayOrder: displayOrder) else {
            return Int.max
        }
 
        return displayOrder[primarySpaceID] ?? Int.max
    }
 
    private static func normalized(_ value: String?) -> String {
        guard let value, !value.isEmpty else { return "\u{10FFFF}" }
        return value
    }
}
 
private struct AppIdentity: Hashable {
    let bundleIdentifier: String?
    let executablePath: String?
    let processIdentifier: Int32?
    let fallbackName: String
 
    init(app: AlignerApp) {
        self.bundleIdentifier = app.bundleIdentifier.isEmpty ? nil : app.bundleIdentifier
        self.executablePath = app.executablePath?.isEmpty == false ? app.executablePath : nil
        self.processIdentifier = app.processIdentifier
        self.fallbackName = app.name
    }
}