Ariver
2026-08-14 86f0b4bd20cdec86dfb5bdb7978d1f6ff4af111a
C1.source/Sources/Aligner/QuickSwitchSessionController.swift
@@ -19,6 +19,8 @@
    private let windowCloseService: any WindowCloseServiceProtocol
    private let systemCriticalWindowDetector: any SystemCriticalWindowDetecting
    private let disableScreenshotRefresh: Bool
    private var waterfallViewMode: QuickSwitchWaterfallViewMode
    private var theme: ThemePreference
    private var closeConfirmationRequired: Bool
    private let onCloseConfirmationDisabled: (() -> Void)?
    private let debugOverlayWidth: CGFloat?
@@ -55,6 +57,7 @@
    private var lastActivationWindowID: UInt32?
    private var lastActivationResult: WindowActivationResult?
    private var lastActivationError: String?
    private var lastActivationDurationMilliseconds: Double?
    private var lastSpaceActivationSpaceID: UInt64?
    private var lastSpaceActivationDidRequestFocus: Bool?
    private var lastSpaceActivationDisplayIdentifier: String?
@@ -68,6 +71,7 @@
    private var lastCloseError: String?
    private var pendingCloseVerification: PendingCloseVerification?
    private var suppressedCloseTargets: [SuppressedCloseTarget] = []
    private var suppressedActivationWindowIDs = Set<UInt32>()
    private var lastDismissReason: DismissReason?
    private var lastSystemCriticalAction: String?
    private var lastSystemCriticalMonitorSource: String?
@@ -85,6 +89,8 @@
    private var lifecycleResidualOverlayWindows = 0
    private var lifecycleResidualVisibleOverlayWindows = 0
    var onSnapshotUpdated: (() -> Void)?
    var onToggleWaterfallViewMode: (() -> Void)?
    var onToggleTheme: (() -> Void)?
    private struct PendingCloseVerification {
        let request: QuickSwitchCloseRequest
@@ -120,6 +126,8 @@
        ),
        systemCriticalWindowDetector: any SystemCriticalWindowDetecting = CGWindowSystemCriticalWindowDetector(),
        disableScreenshotRefresh: Bool = false,
        waterfallViewMode: QuickSwitchWaterfallViewMode = .verticalColumns,
        theme: ThemePreference = .light,
        closeConfirmationRequired: Bool = true,
        onCloseConfirmationDisabled: (() -> Void)? = nil,
        debugHoveredAppGroupIndex: Int? = nil,
@@ -135,6 +143,8 @@
        self.windowCloseService = windowCloseService
        self.systemCriticalWindowDetector = systemCriticalWindowDetector
        self.disableScreenshotRefresh = disableScreenshotRefresh
        self.waterfallViewMode = waterfallViewMode
        self.theme = theme
        self.closeConfirmationRequired = closeConfirmationRequired
        self.onCloseConfirmationDisabled = onCloseConfirmationDisabled
        self.debugOverlayWidth = debugOverlayWidth
@@ -165,6 +175,7 @@
        lastActivationWindowID = nil
        lastActivationResult = nil
        lastActivationError = nil
        lastActivationDurationMilliseconds = nil
        lastSpaceActivationSpaceID = nil
        lastSpaceActivationDidRequestFocus = nil
        lastSpaceActivationDisplayIdentifier = nil
@@ -178,6 +189,7 @@
        lastCloseError = nil
        pendingCloseVerification = nil
        suppressedCloseTargets = []
        suppressedActivationWindowIDs = []
        cancelPendingLockedSpaceUnlock()
        lockedSpaceFilterID = nil
        selectionBeforeSpaceFilter = nil
@@ -209,6 +221,12 @@
        view.onBackgroundClick = { [weak self] in
            self?.handleBackgroundClick() ?? false
        }
        view.onToggleWaterfallViewMode = { [weak self] in
            self?.onToggleWaterfallViewMode?()
        }
        view.onToggleTheme = { [weak self] in
            self?.onToggleTheme?()
        }
        view.setSuppressEventInput(!debugMouseSequence.isEmpty || !debugKeySequence.isEmpty)
        view.onRequestClose = { [weak self] request in
            self?.requestClose(request)
@@ -219,6 +237,8 @@
            self.onCloseConfirmationDisabled?()
        }
        view.setCloseConfirmationRequired(closeConfirmationRequired)
        view.setWaterfallViewMode(waterfallViewMode)
        view.setTheme(theme)
        view.apply(viewModel: nil)
        view.beginPerformanceFirstFrameMeasurement()
        coordinator.openQuickSwitch()
@@ -272,7 +292,58 @@
    func retriggerFromShortcut() {
        DevelopmentDiagnostics.log("quickSwitch.session.retriggerFromShortcut")
        show()
        guard isVisible else {
            show()
            return
        }
        guard currentViewModel != nil else {
            DevelopmentDiagnostics.log("quickSwitch.session.retriggerFromShortcut.noSnapshot", [
                "action": "fallbackShow"
            ])
            show()
            return
        }
        let didCycle = view.hoverNextAppGroupIndex()
        DevelopmentDiagnostics.log("quickSwitch.session.retriggerFromShortcut.hoverApp", [
            "didCycle": didCycle
        ])
        if !didCycle {
            show()
        }
    }
    func setWaterfallViewMode(_ mode: QuickSwitchWaterfallViewMode) {
        guard waterfallViewMode != mode else { return }
        waterfallViewMode = mode
        DevelopmentDiagnostics.log("quickSwitch.session.waterfallViewModeChanged", [
            "mode": mode.rawValue,
            "visible": isVisible,
            "hasViewModel": currentViewModel != nil
        ])
        view.setWaterfallViewMode(mode)
        if isVisible, let currentViewModel {
            view.applyProjected(viewModel: currentViewModel)
        }
        onSnapshotUpdated?()
    }
    func setTheme(_ theme: ThemePreference) {
        guard self.theme != theme else { return }
        self.theme = theme
        DevelopmentDiagnostics.log("quickSwitch.session.themeChanged", [
            "theme": theme.rawValue,
            "visible": isVisible,
            "hasViewModel": currentViewModel != nil
        ])
        view.setTheme(theme)
        onSnapshotUpdated?()
    }
    func reportDictionary() -> [String: Any] {
@@ -309,6 +380,7 @@
            "lastActivationWindowID": lastActivationWindowID ?? NSNull(),
            "lastActivationResult": lastActivationResult.map(Self.activationResultString) ?? NSNull(),
            "lastActivationError": lastActivationError ?? NSNull(),
            "lastActivationDurationMilliseconds": lastActivationDurationMilliseconds ?? NSNull(),
            "lastSpaceActivationSpaceID": lastSpaceActivationSpaceID ?? NSNull(),
            "lastSpaceActivationDidRequestFocus": lastSpaceActivationDidRequestFocus ?? NSNull(),
            "lastSpaceActivationDisplayIdentifier": lastSpaceActivationDisplayIdentifier ?? NSNull(),
@@ -321,6 +393,8 @@
            "lastCloseResult": lastCloseResult.map(Self.closeResultString) ?? NSNull(),
            "lastCloseError": lastCloseError ?? NSNull(),
            "suppressedCloseTargetCount": suppressedCloseTargets.count,
            "suppressedActivationWindowCount": suppressedActivationWindowIDs.count,
            "suppressedActivationWindowIDs": Array(suppressedActivationWindowIDs).sorted(),
            "lastDismissReason": lastDismissReason.map(Self.dismissReasonString) ?? NSNull(),
            "overlayLevel": Int(coordinator.currentLevel),
            "overlayMainMenuLevel": Int(CGWindowLevelForKey(.mainMenuWindow)),
@@ -349,6 +423,40 @@
                        && lifecycleResidualVisibleOverlayWindows == 0
                ),
            "rootView": view.reportDictionary()
        ]
    }
    func performanceDiagnosticSummary() -> [String: Any] {
        let applications = currentSnapshot?.appGroups.map { group in
            [
                "name": group.app.name,
                "bundleIdentifier": group.app.bundleIdentifier,
                "processIdentifier": group.app.processIdentifier ?? NSNull(),
                "windowCount": group.windows.count,
                "minimizedWindowCount": group.windows.filter { $0.window.isMinimized }.count,
                "fullscreenWindowCount": group.windows.filter { $0.window.isFullscreen }.count
            ] as [String: Any]
        } ?? []
        return [
            "snapshotLoaded": currentSnapshot != nil,
            "snapshotError": lastSnapshotError ?? NSNull(),
            "quickSwitchVisible": isVisible,
            "displayCount": currentSnapshot?.displays.count ?? 0,
            "spaceCount": currentSnapshot?.displays.flatMap(\.spaces).count ?? 0,
            "applicationCount": applications.count,
            "windowCount": currentSnapshot?.appGroups.flatMap(\.windows).count ?? 0,
            "applications": applications,
            "timingsMilliseconds": [
                "overlayOpen": overlayOpenElapsedMilliseconds ?? NSNull(),
                "snapshotStart": snapshotStartElapsedMilliseconds ?? NSNull(),
                "snapshot": snapshotDurationMilliseconds ?? NSNull(),
                "lastActivation": lastActivationDurationMilliseconds ?? NSNull()
            ] as [String: Any],
            "snapshotRanOnMainThread": snapshotRanOnMainThread ?? NSNull(),
            "lastActivationResult": lastActivationResult.map(Self.activationResultString) ?? NSNull(),
            "lastActivationError": lastActivationError ?? NSNull(),
            "lastDismissReason": lastDismissReason.map(Self.dismissReasonString) ?? NSNull()
        ]
    }
@@ -501,9 +609,11 @@
        lastCommitSource = source
        lastActivationWindowID = selection.windowID
        lastActivationError = nil
        lastActivationDurationMilliseconds = nil
        guard let window = window(for: selection, in: viewModel ?? currentViewModel) else {
            lastActivationResult = .windowNotFound
            suppressActivationWindowID(selection.windowID, reason: "selectionMissing")
            DevelopmentDiagnostics.log("quickSwitch.activation.commit.windowNotFound", [
                "source": source.rawValue,
                "appGroupIndex": selection.appGroupIndex,
@@ -520,8 +630,10 @@
        ])
        hide(reason: .userClosed)
        let activationStartedAt = CACurrentMediaTime()
        do {
            lastActivationResult = try windowActivationService.activate(window: window)
            lastActivationDurationMilliseconds = (CACurrentMediaTime() - activationStartedAt) * 1_000
            DevelopmentDiagnostics.log("quickSwitch.activation.commit.result", [
                "source": source.rawValue,
                "windowID": window.id,
@@ -530,9 +642,11 @@
                "titleHash": DevelopmentDiagnostics.stableFingerprint(window.title),
                "titleLength": window.title.count,
                "titleIsEmpty": window.title.isEmpty,
                "result": lastActivationResult.map(Self.activationResultString)
                "result": lastActivationResult.map(Self.activationResultString),
                "durationMilliseconds": lastActivationDurationMilliseconds
            ])
        } catch {
            lastActivationDurationMilliseconds = (CACurrentMediaTime() - activationStartedAt) * 1_000
            let errorSummary = DevelopmentDiagnostics.errorSummaryString(error)
            lastActivationResult = .failed(errorSummary)
            lastActivationError = errorSummary
@@ -542,10 +656,15 @@
                "appName": window.app.name,
                "titleHash": DevelopmentDiagnostics.stableFingerprint(window.title),
                "titleLength": window.title.count,
                "titleIsEmpty": window.title.isEmpty
                "titleIsEmpty": window.title.isEmpty,
                "durationMilliseconds": lastActivationDurationMilliseconds
            ]
            DevelopmentDiagnostics.errorSummaryFields(error).forEach { fields[$0.key] = $0.value }
            DevelopmentDiagnostics.log("quickSwitch.activation.commit.error", fields)
        }
        if shouldSuppressAfterActivationResult(lastActivationResult) {
            suppressActivationWindowID(window.id, reason: lastActivationResult.map(Self.activationResultString) ?? "unknown")
        }
        if shouldCloseAfterActivation(lastActivationResult) {
@@ -562,7 +681,7 @@
    private func handleSpaceLaneClick(_ spaceID: UInt64, clickCount: Int) {
        if clickCount >= 2 {
            if pendingLockedSpaceUnlockSpaceID == spaceID {
            if pendingLockedSpaceUnlockSpaceID == spaceID || lockedSpaceFilterID == spaceID {
                cancelPendingLockedSpaceUnlock()
                activateLockedSpace(spaceID)
            } else {
@@ -819,12 +938,12 @@
                "result": Self.closeResultString(result)
            ])
            if result == .requested {
                suppressCloseTarget(request)
                DevelopmentDiagnostics.log("quickSwitch.close.request.refreshAfterClose", [
                    "targetKind": request.kindDescription,
                    "appGroupIndex": request.appGroupIndex,
                    "appName": request.appName,
                    "windowID": request.windowID
                    "windowID": request.windowID,
                    "optimisticRemove": false
                ])
                pendingCloseVerification = PendingCloseVerification(
                    request: request,
@@ -894,18 +1013,37 @@
        ])
    }
    private func suppressActivationWindowID(_ windowID: UInt32, reason: String) {
        guard windowID != 0 else { return }
        suppressedActivationWindowIDs.insert(windowID)
        guard let sourceViewModel else { return }
        let visibleViewModel = projectedViewModel(from: sourceViewModel, preferredSelection: view.effectiveSelectionForProjection())
        self.currentViewModel = visibleViewModel
        view.applyProjected(viewModel: visibleViewModel)
        DevelopmentDiagnostics.log("quickSwitch.activation.suppressWindow", [
            "windowID": windowID,
            "reason": reason,
            "remainingWindowCount": visibleViewModel.windowCount,
            "suppressedActivationWindowCount": suppressedActivationWindowIDs.count
        ])
    }
    private func viewModel(
        _ viewModel: QuickSwitchViewModel,
        excluding suppressedTargets: [SuppressedCloseTarget]
        excluding suppressedTargets: [SuppressedCloseTarget],
        suppressedActivationWindowIDs: Set<UInt32> = []
    ) -> QuickSwitchViewModel {
        guard !suppressedTargets.isEmpty else { return viewModel }
        guard !suppressedTargets.isEmpty || !suppressedActivationWindowIDs.isEmpty else { return viewModel }
        var nextGlobalIndex = 0
        let columns = viewModel.waterfallColumns.compactMap { column -> QuickSwitchWaterfallColumnViewModel? in
            let windows = column.windows.filter { card in
                !suppressedTargets.contains { target in
                let isActivationSuppressed = suppressedActivationWindowIDs.contains(card.window.id)
                let isCloseSuppressed = suppressedTargets.contains { target in
                    suppressedTarget(target, matches: card)
                }
                return !isActivationSuppressed && !isCloseSuppressed
            }
            guard !windows.isEmpty else { return nil }
@@ -954,7 +1092,11 @@
        from sourceViewModel: QuickSwitchViewModel,
        preferredSelection: QuickSwitchSelection? = nil
    ) -> QuickSwitchViewModel {
        let closeProjectedViewModel = viewModel(sourceViewModel, excluding: suppressedCloseTargets)
        let closeProjectedViewModel = viewModel(
            sourceViewModel,
            excluding: suppressedCloseTargets,
            suppressedActivationWindowIDs: suppressedActivationWindowIDs
        )
        return QuickSwitchSpaceFilterPolicy.projectedViewModel(
            from: closeProjectedViewModel,
            lockedSpaceID: lockedSpaceFilterID,
@@ -1011,9 +1153,18 @@
    private func shouldCloseAfterActivation(_ result: WindowActivationResult?) -> Bool {
        switch result {
        case .activated, .restored, .appActivatedOnly:
        case .activated, .restored:
            return true
        case .windowNotFound, .unsupported, .activationFailed, .failed, nil:
        case .appActivatedOnly, .windowNotFound, .unsupported, .activationFailed, .failed, nil:
            return false
        }
    }
    private func shouldSuppressAfterActivationResult(_ result: WindowActivationResult?) -> Bool {
        switch result {
        case .windowNotFound, .unsupported, .activationFailed, .failed:
            return true
        case .activated, .restored, .appActivatedOnly, nil:
            return false
        }
    }
@@ -1453,6 +1604,8 @@
    let fixtureCandidateFiltering: Bool
    let fixtureActivation: Bool
    let fixtureSpaceFilter: Bool
    let fixtureSplitView: Bool
    let fixtureMultiPageIdentity: Bool
    let debugHoveredAppGroupIndex: Int?
    let debugOverlayWidth: CGFloat?
    let debugKeySequence: [String]
@@ -1461,9 +1614,11 @@
    let debugWindowActivation: Bool
    let debugWindowClose: Bool
    let disableScreenshotRefresh: Bool
    let waterfallViewMode: QuickSwitchWaterfallViewMode?
    let lifecycleCycles: Int?
    let lifecycleInterval: TimeInterval
    let lifecycleVisibleDuration: TimeInterval
    let simulateDockReopenAfter: TimeInterval?
    static func parse(arguments: [String]) -> Round1QuickSwitchLaunchOptions {
        Round1QuickSwitchLaunchOptions(
@@ -1480,6 +1635,8 @@
            fixtureCandidateFiltering: arguments.contains("--round01-fixture-candidate-filtering"),
            fixtureActivation: arguments.contains("--round01-fixture-window-activation"),
            fixtureSpaceFilter: arguments.contains("--round01-fixture-space-filter"),
            fixtureSplitView: arguments.contains("--round01-fixture-split-view"),
            fixtureMultiPageIdentity: arguments.contains("--round01-fixture-multi-page-identity"),
            debugHoveredAppGroupIndex: intValue(for: "--round01-debug-hover-app-index", in: arguments),
            debugOverlayWidth: cgFloatValue(for: "--round01-debug-overlay-width", in: arguments),
            debugKeySequence: stringListValue(for: "--round01-debug-key-sequence", in: arguments),
@@ -1488,9 +1645,11 @@
            debugWindowActivation: arguments.contains("--round01-debug-window-activation"),
            debugWindowClose: arguments.contains("--round01-debug-window-close"),
            disableScreenshotRefresh: arguments.contains("--round01-disable-screenshot-refresh"),
            waterfallViewMode: waterfallViewModeValue(for: "--round01-waterfall-view-mode", in: arguments),
            lifecycleCycles: intValue(for: "--round01-quick-switch-lifecycle-cycles", in: arguments),
            lifecycleInterval: timeInterval(for: "--round01-quick-switch-lifecycle-interval", in: arguments) ?? 0.02,
            lifecycleVisibleDuration: timeInterval(for: "--round01-quick-switch-lifecycle-visible-duration", in: arguments) ?? 0.16
            lifecycleVisibleDuration: timeInterval(for: "--round01-quick-switch-lifecycle-visible-duration", in: arguments) ?? 0.16,
            simulateDockReopenAfter: timeInterval(for: "--round01-simulate-dock-reopen-after", in: arguments)
        )
    }
@@ -1512,6 +1671,22 @@
        return String(argument.dropFirst(prefix.count))
    }
    private static func waterfallViewModeValue(
        for key: String,
        in arguments: [String]
    ) -> QuickSwitchWaterfallViewMode? {
        guard let value = stringValue(for: key, in: arguments) else { return nil }
        switch value {
        case "vertical", "vertical-columns", "verticalColumns":
            return .verticalColumns
        case "horizontal", "horizontal-masonry", "horizontalMasonry":
            return .horizontalMasonry
        default:
            return nil
        }
    }
    private static func intValue(for key: String, in arguments: [String]) -> Int? {
        stringValue(for: key, in: arguments).flatMap(Int.init)
    }