Ariver
2026-06-14 d5cf4d94edbe72d53fb417bf32105c2258bce924
C1.source/Sources/Aligner/QuickSwitchRootView.swift
@@ -226,6 +226,7 @@
        let labelLayer: CATextLayer
        let countLayer: CATextLayer
        let appLayer: CATextLayer
        let splitAppLayers: [CATextLayer]
        let windowBlocks: [CALayer]
        let fullscreenMarkerLayer: CALayer?
    }
@@ -1344,6 +1345,15 @@
            }
            recordMouseCommand("click-card:\(appGroupIndex):\(windowIndex)")
            if let card = waterfallCard(appGroupIndex: appGroupIndex, windowIndex: windowIndex) {
                clickWindowCard(card)
            }
        case "click-card-id" where parts.count == 2:
            guard let windowID = UInt32(parts[1]) else {
                recordMouseCommand("invalid:\(command)")
                return
            }
            recordMouseCommand("click-card-id:\(windowID)")
            if let card = waterfallCard(windowID: windowID) {
                clickWindowCard(card)
            }
        case "hover-card-close" where parts.count == 3:
@@ -2540,6 +2550,15 @@
                    color: space.type == .fullscreen ? .labelColor : .secondaryLabelColor,
                    alignment: space.type == .fullscreen ? .center : .left
                )
                let splitAppLayers = splitViewAppNames(for: space).map { name in
                    makeTextLayer(
                        string: name,
                        fontSize: 12,
                        weight: .medium,
                        color: .labelColor,
                        alignment: .center
                    )
                }
                let windowBlocks = space.type == .fullscreen
                    ? []
                    : makeWindowBlocks(count: min(space.windowCount, 5), space: space)
@@ -2550,6 +2569,9 @@
                container.addSublayer(appLayer)
                if let fullscreenMarkerLayer {
                    container.addSublayer(fullscreenMarkerLayer)
                }
                for splitAppLayer in splitAppLayers {
                    container.addSublayer(splitAppLayer)
                }
                for block in windowBlocks {
                    container.addSublayer(block)
@@ -2562,6 +2584,7 @@
                    labelLayer: labelLayer,
                    countLayer: countLayer,
                    appLayer: appLayer,
                    splitAppLayers: splitAppLayers,
                    windowBlocks: windowBlocks,
                    fullscreenMarkerLayer: fullscreenMarkerLayer
                )
@@ -2848,10 +2871,10 @@
        let isActive = isHovered || isFocused || isLocked
        let isAssociated = (isAppAssociated || isWindowAssociated) && !isActive
        segment.containerLayer.borderWidth = isLocked
            ? 6
            : (hasWindows || isCurrent || isActive || isAssociated) ? 1.5 : 1
        segment.containerLayer.borderColor = (isActive
        segment.containerLayer.borderWidth = (hasWindows || isCurrent || isActive || isAssociated) ? 1.5 : 1
        segment.containerLayer.borderColor = (isLocked
            ? NSColor.white.withAlphaComponent(0.86)
            : isActive
            ? spaceLaneOccupiedColor.withAlphaComponent(isLocked ? 0.92 : 0.62)
            : isAssociated
                ? spaceLaneOccupiedColor.withAlphaComponent(0.50)
@@ -2861,7 +2884,12 @@
                    ? NSColor.labelColor.withAlphaComponent(0.34)
                : NSColor.separatorColor.withAlphaComponent(0.34)
        ).cgColor
        if !hasWindows {
        if isLocked {
            applySpaceLaneSolidFill(
                to: segment.containerLayer,
                color: spaceLaneLockedFillColor
            )
        } else if !hasWindows {
            applySpaceLaneSolidFill(to: segment.containerLayer, color: .clear)
        } else if isActive {
            applySpaceLaneSolidFill(
@@ -2896,7 +2924,7 @@
        segment.containerLayer.transform = (isActive || isAssociated)
            ? CATransform3DMakeScale(isActive ? 1.03 : 1.015, isActive ? 1.03 : 1.015, 1)
            : CATransform3DIdentity
        segment.containerLayer.shadowPath = hasWindows
        segment.containerLayer.shadowPath = (hasWindows || isLocked)
            ? CGPath(
                roundedRect: segment.containerLayer.bounds,
                cornerWidth: segment.containerLayer.cornerRadius,
@@ -2904,6 +2932,37 @@
                transform: nil
            )
            : nil
        applySpaceLaneContentVisualState(segment, isLocked: isLocked)
    }
    private func applySpaceLaneContentVisualState(_ segment: SpaceLaneSegmentLayers, isLocked: Bool) {
        let primaryTextColor: NSColor = isLocked ? .white : .labelColor
        let secondaryTextColor: NSColor = isLocked
            ? .white
            : .secondaryLabelColor
        segment.labelLayer.foregroundColor = primaryTextColor.cgColor
        segment.countLayer.foregroundColor = (isLocked ? NSColor.white : .secondaryLabelColor).cgColor
        segment.appLayer.foregroundColor = (segment.space.type == .fullscreen
            ? primaryTextColor
            : secondaryTextColor
        ).cgColor
        for splitAppLayer in segment.splitAppLayers {
            splitAppLayer.foregroundColor = primaryTextColor.cgColor
        }
        for block in segment.windowBlocks {
            block.backgroundColor = (isLocked
                ? NSColor.white
                : spaceLaneOccupiedColor.withAlphaComponent(segment.space.isCurrent ? 0.72 : 0.58)
            ).cgColor
        }
        (segment.fullscreenMarkerLayer as? CAShapeLayer)?.strokeColor = (isLocked
            ? NSColor.white
            : NSColor.secondaryLabelColor.withAlphaComponent(segment.space.isCurrent ? 0.42 : 0.28)
        ).cgColor
    }
    private func shouldScrollSpaceLane(for event: NSEvent) -> Bool {
@@ -3035,23 +3094,61 @@
            .first(where: { $0.item.windowIndex == windowIndex })
    }
    private func waterfallCard(windowID: UInt32) -> WaterfallCardLayers? {
        waterfallColumns
            .lazy
            .flatMap(\.cards)
            .first(where: { $0.item.window.id == windowID })
    }
    private func layoutSpaceLaneSegmentContents(_ segment: SpaceLaneSegmentLayers) {
        let bounds = segment.containerLayer.bounds
        let splitAppNames = splitViewAppNames(for: segment.space)
        let isSplitView = splitAppNames.count >= 2
        segment.labelLayer.frame = CGRect(x: 10, y: bounds.height - 29, width: max(1, bounds.width - 48), height: 20)
        segment.countLayer.frame = CGRect(x: bounds.width - 34, y: bounds.height - 29, width: 24, height: 20)
        segment.countLayer.string = isSplitView ? "" : "\(segment.space.windowCount)"
        segment.countLayer.isHidden = isSplitView
        if segment.space.type == .fullscreen {
            let markerFrame = fullscreenMarkerFrame(in: bounds)
            segment.appLayer.frame = CGRect(
                x: 8,
                y: markerFrame.midY - 8.5,
                width: max(1, bounds.width - 16),
                height: 17
            )
            segment.appLayer.isHidden = isSplitView
            if isSplitView {
                let labelY = markerFrame.midY - 8.5
                let halfWidth = markerFrame.width / 2
                for (index, splitAppLayer) in segment.splitAppLayers.enumerated() {
                    let x = markerFrame.minX + CGFloat(index) * halfWidth
                    splitAppLayer.isHidden = false
                    splitAppLayer.frame = CGRect(
                        x: x + 4,
                        y: labelY,
                        width: max(1, halfWidth - 8),
                        height: 17
                    )
                }
            } else {
                segment.appLayer.frame = CGRect(
                    x: 8,
                    y: markerFrame.midY - 8.5,
                    width: max(1, bounds.width - 16),
                    height: 17
                )
                for splitAppLayer in segment.splitAppLayers {
                    splitAppLayer.isHidden = true
                }
            }
        } else {
            segment.appLayer.isHidden = false
            segment.appLayer.frame = CGRect(x: 10, y: 9, width: max(1, bounds.width - 20), height: 17)
            for splitAppLayer in segment.splitAppLayers {
                splitAppLayer.isHidden = true
            }
        }
        if let fullscreenMarkerLayer = segment.fullscreenMarkerLayer {
            layoutFullscreenMarkerLayer(fullscreenMarkerLayer, in: bounds)
            layoutFullscreenMarkerLayer(
                fullscreenMarkerLayer,
                in: bounds,
                isSplitView: isSplitView
            )
        }
        let blockGap: CGFloat = 5
@@ -3241,6 +3338,14 @@
                .cards
                .compactMap(\.item.primarySpaceID) ?? []
        )
    }
    private var appIconHoverLinkedAppGroupIndex: Int? {
        if let debugHoveredAppGroupIndex {
            return debugHoveredAppGroupIndex
        }
        guard case .app(let appGroupIndex) = hoverTarget else { return nil }
        return appGroupIndex
    }
    private var appHoverAssociatedSpaceLabels: [String] {
@@ -3670,10 +3775,13 @@
        let bounds = card.containerLayer.bounds
        let isSelected = card.item.window.id == effectiveSelection?.windowID
        let isHovered = card.item.window.id == hoveredWindowID
        let isAppLinked = isHorizontalMasonryMode
            && card.item.appGroupIndex == appIconHoverLinkedAppGroupIndex
        applyWaterfallCardVisualState(
            card,
            selected: shouldShowSelectedVisual(isSelected: isSelected, isHovered: isHovered),
            hovered: isHovered
            hovered: isHovered,
            appLinked: isAppLinked
        )
        let outerInset: CGFloat = 0
@@ -3736,12 +3844,19 @@
        )
    }
    private func applyWaterfallCardVisualState(_ card: WaterfallCardLayers, selected: Bool, hovered: Bool) {
    private func applyWaterfallCardVisualState(
        _ card: WaterfallCardLayers,
        selected: Bool,
        hovered: Bool,
        appLinked: Bool
    ) {
        let isSpaceFocused = isWaterfallCardSpaceFocused(card)
        card.containerLayer.backgroundColor = (selected
            ? NSColor.windowBackgroundColor.withAlphaComponent(0.94)
            : hovered
                ? accentTintedWindowBackground(fraction: 0.09, alpha: 0.95)
                : appLinked
                    ? accentTintedWindowBackground(fraction: 0.08, alpha: 0.93)
                : isSpaceFocused
                    ? accentTintedWindowBackground(fraction: 0.10, alpha: 0.94)
                : NSColor.windowBackgroundColor.withAlphaComponent(0.82)
@@ -3750,27 +3865,31 @@
            ? NSColor.controlAccentColor.withAlphaComponent(0.52)
            : hovered
                ? NSColor.controlAccentColor.withAlphaComponent(0.44)
                : appLinked
                    ? NSColor.controlAccentColor.withAlphaComponent(0.38)
                : isSpaceFocused
                    ? NSColor.controlAccentColor.withAlphaComponent(0.42)
                : NSColor.separatorColor.withAlphaComponent(0.28)
        ).cgColor
        card.containerLayer.borderWidth = (selected || hovered || isSpaceFocused) ? 1.5 : 1
        card.containerLayer.borderWidth = (selected || hovered || appLinked || isSpaceFocused) ? 1.5 : 1
        card.containerLayer.shadowColor = NSColor.black.cgColor
        card.containerLayer.shadowOpacity = selected ? 0.24 : hovered ? 0.14 : isSpaceFocused ? 0.20 : 0
        card.containerLayer.shadowRadius = selected ? 22 : hovered ? 17 : isSpaceFocused ? 24 : 0
        card.containerLayer.shadowOpacity = selected ? 0.24 : hovered ? 0.14 : appLinked ? 0.16 : isSpaceFocused ? 0.20 : 0
        card.containerLayer.shadowRadius = selected ? 22 : hovered ? 17 : appLinked ? 18 : isSpaceFocused ? 24 : 0
        card.containerLayer.shadowOffset = selected
            ? CGSize(width: 0, height: -6)
            : hovered
                ? CGSize(width: 0, height: -2.5)
                : appLinked
                    ? CGSize(width: 0, height: -3)
                : isSpaceFocused
                    ? CGSize(width: 0, height: -5)
                    : .zero
        card.containerLayer.zPosition = selected ? 20 : hovered ? 10 : isSpaceFocused ? 8 : 0
        card.containerLayer.zPosition = selected ? 20 : hovered ? 12 : appLinked ? 10 : isSpaceFocused ? 8 : 0
        let focusedScale: CGFloat = selected ? 1.015 : isSpaceFocused ? 1.012 : 1.008
        card.containerLayer.transform = (selected || hovered || isSpaceFocused)
            ? CATransform3DMakeScale(focusedScale, focusedScale, 1)
            : CATransform3DIdentity
        card.containerLayer.shadowPath = (selected || hovered || isSpaceFocused)
        card.containerLayer.shadowPath = (selected || hovered || appLinked || isSpaceFocused)
            ? CGPath(
                roundedRect: card.containerLayer.bounds,
                cornerWidth: card.containerLayer.cornerRadius,
@@ -3778,7 +3897,9 @@
                transform: nil
            )
            : nil
        card.titleBarLayer.backgroundColor = NSColor.clear.cgColor
        card.titleBarLayer.backgroundColor = appLinked
            ? spaceLaneOccupiedColor.withAlphaComponent(0.18).cgColor
            : NSColor.clear.cgColor
        card.titleBarLayer.borderColor = NSColor.clear.cgColor
        card.titleBarLayer.borderWidth = 0
        card.shineLayer.opacity = selected ? 1 : 0
@@ -4395,6 +4516,14 @@
        return NSColor(calibratedRed: 0, green: 122 / 255, blue: 1, alpha: 1)
    }
    private var spaceLaneLockedFillColor: NSColor {
        if effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua {
            return NSColor(calibratedRed: 58 / 255, green: 148 / 255, blue: 1, alpha: 0.86)
        }
        return NSColor(calibratedRed: 90 / 255, green: 171 / 255, blue: 1, alpha: 0.82)
    }
    private func spaceLaneIdleOccupiedGradientColors() -> [NSColor] {
        if effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua {
            let blue = NSColor(calibratedRed: 36 / 255, green: 54 / 255, blue: 72 / 255, alpha: 1)
@@ -4630,13 +4759,38 @@
        return identifiers.joined(separator: " ")
    }
    private func layoutFullscreenMarkerLayer(_ layer: CALayer, in segmentBounds: CGRect) {
    private func splitViewAppNames(for space: QuickSwitchSpaceViewModel) -> [String] {
        guard space.type == .fullscreen else { return [] }
        let names = space.splitViewAppNames
            .prefix(2)
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
            .filter { !$0.isEmpty }
        guard names.count >= 2 else { return [] }
        return names
    }
    private func layoutFullscreenMarkerLayer(
        _ layer: CALayer,
        in segmentBounds: CGRect,
        isSplitView: Bool = false
    ) {
        let markerFrame = fullscreenMarkerFrame(in: segmentBounds)
        layer.frame = markerFrame
        guard let shapeLayer = layer as? CAShapeLayer else { return }
        let bounds = shapeLayer.bounds
        if isSplitView {
            let path = CGMutablePath()
            path.move(to: CGPoint(x: bounds.midX, y: bounds.minY))
            path.addLine(to: CGPoint(x: bounds.midX, y: bounds.maxY))
            shapeLayer.path = path
            shapeLayer.lineCap = .butt
            return
        }
        let cornerLength = min(12, max(7, min(bounds.width, bounds.height) * 0.28))
        let path = CGMutablePath()
@@ -4657,6 +4811,7 @@
        path.addLine(to: CGPoint(x: 0, y: bounds.maxY - cornerLength))
        shapeLayer.path = path
        shapeLayer.lineCap = .round
    }
    private func fullscreenMarkerFrame(in segmentBounds: CGRect) -> CGRect {
@@ -4871,6 +5026,7 @@
                "shadowRadius": Double(card.containerLayer.shadowRadius),
                "thumbnailFrame": dictionary(from: card.thumbnailLayer.frame),
                "titleBarFrame": dictionary(from: card.titleBarLayer.frame),
                "titleBarBackgroundColor": colorDictionary(from: card.titleBarLayer.backgroundColor),
                "titleBarBorderWidth": Double(card.titleBarLayer.borderWidth),
                "titleFrame": dictionary(from: card.titleLayer.frame),
                "metaFrame": dictionary(from: card.metaLayer.frame),
@@ -4978,6 +5134,8 @@
        var states: [String] = []
        let isSelected = card.item.window.id == effectiveSelection?.windowID
        let isHovered = card.item.window.id == hoveredWindowID
        let isAppLinked = isHorizontalMasonryMode
            && card.item.appGroupIndex == appIconHoverLinkedAppGroupIndex
        if shouldShowSelectedVisual(isSelected: isSelected, isHovered: isHovered) {
            states.append("selected")
        } else if isSelected {
@@ -4985,6 +5143,9 @@
        }
        if isHovered {
            states.append("hover")
        }
        if isAppLinked {
            states.append("appLinked")
        }
        if isWaterfallCardSpaceFocused(card) {
            states.append("spaceFocused")
@@ -5045,6 +5206,8 @@
                let fullscreenMarkerCenterRatio = fullscreenMarkerFrame.map {
                    Double($0.midY / max(1, segment.containerLayer.bounds.height))
                }
                let splitAppNames = splitViewAppNames(for: space)
                let splitAppLabelFrames = segment.splitAppLayers.map { dictionary(from: $0.frame) }
                return [
                    "displayUUID": display.displayUUID,
                    "displayLabel": display.displayLabel,
@@ -5053,12 +5216,32 @@
                    "type": spaceTypeName(space.type),
                    "visualStates": visualStates(for: space),
                    "fullscreenMarkerVisible": segment.fullscreenMarkerLayer != nil,
                    "fullscreenMarkerKind": segment.fullscreenMarkerLayer == nil ? "none" : "cornerBracket",
                    "fullscreenMarkerKind": fullscreenMarkerKind(
                        markerLayer: segment.fullscreenMarkerLayer,
                        splitAppNames: splitAppNames
                    ),
                    "fullscreenMarkerPathStyle": fullscreenMarkerPathStyle(
                        markerLayer: segment.fullscreenMarkerLayer,
                        splitAppNames: splitAppNames
                    ),
                    "fullscreenMarkerFrame": fullscreenMarkerFrame.map { dictionary(from: $0) } ?? NSNull(),
                    "fullscreenMarkerCenterRatio": fullscreenMarkerCenterRatio ?? NSNull(),
                    "splitViewAppNames": splitAppNames,
                    "splitViewLabelFrames": splitAppLabelFrames,
                    "splitViewLabelColors": segment.splitAppLayers.map {
                        colorDictionary(from: $0.foregroundColor)
                    },
                    "windowBlockCount": segment.windowBlocks.count,
                    "windowBlockColors": segment.windowBlocks.map { colorDictionary(from: $0.backgroundColor) },
                    "windowBlockFrames": segment.windowBlocks.map { dictionary(from: $0.frame) },
                    "labelColor": colorDictionary(from: segment.labelLayer.foregroundColor),
                    "countText": string(from: segment.countLayer.string),
                    "countVisible": !segment.countLayer.isHidden && segment.countLayer.opacity > 0,
                    "countColor": colorDictionary(from: segment.countLayer.foregroundColor),
                    "appColor": colorDictionary(from: segment.appLayer.foregroundColor),
                    "fullscreenMarkerStrokeColor": colorDictionary(
                        from: (segment.fullscreenMarkerLayer as? CAShapeLayer)?.strokeColor
                    ),
                    "backgroundKind": spaceLaneFillKind(for: segment.containerLayer),
                    "backgroundColor": colorDictionary(from: segment.containerLayer.backgroundColor),
                    "gradientColors": gradientColorDictionaries(from: segment.containerLayer),
@@ -5093,6 +5276,16 @@
        }
    }
    private func fullscreenMarkerKind(markerLayer: CALayer?, splitAppNames: [String]) -> String {
        guard markerLayer != nil else { return "none" }
        return splitAppNames.count >= 2 ? "splitViewPair" : "cornerBracket"
    }
    private func fullscreenMarkerPathStyle(markerLayer: CALayer?, splitAppNames: [String]) -> String {
        guard markerLayer != nil else { return "none" }
        return splitAppNames.count >= 2 ? "centerDividerOnly" : "cornerBracket"
    }
    private func visualStates(for space: QuickSwitchSpaceViewModel) -> [String] {
        var states: [String] = []
        if space.isCurrent {
@@ -5115,6 +5308,9 @@
        }
        if space.type == .fullscreen {
            states.append("fullscreen")
        }
        if splitViewAppNames(for: space).count >= 2 {
            states.append("splitView")
        }
        return states
    }
@@ -5141,6 +5337,16 @@
        ]
    }
    private func string(from textLayerValue: Any?) -> String {
        if let string = textLayerValue as? String {
            return string
        }
        if let attributedString = textLayerValue as? NSAttributedString {
            return attributedString.string
        }
        return ""
    }
    private func colorDictionary(from color: CGColor?) -> [String: Double] {
        guard let color,
              let nsColor = NSColor(cgColor: color)?.usingColorSpace(.deviceRGB)