From 71acd11e8d5349672da8b1b6bb254e9a25ff4e51 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Wed, 10 Jun 2026 11:59:13 +0800
Subject: [PATCH] Fix Space Lane tile visuals

---
 C1.source/Sources/Aligner/QuickSwitchRootView.swift |  110 ++++++++++++++++++++++++++++++------
 C1.source/Resources/Aligner-Info.plist              |    4 
 C3.tools/round1-three-zone-linkage-fixture-qa.sh    |   41 +++++++++++++
 3 files changed, 131 insertions(+), 24 deletions(-)

diff --git a/C1.source/Resources/Aligner-Info.plist b/C1.source/Resources/Aligner-Info.plist
index 1a78fa3..1254b21 100644
--- a/C1.source/Resources/Aligner-Info.plist
+++ b/C1.source/Resources/Aligner-Info.plist
@@ -17,9 +17,9 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-    <string>0.0.49</string>
+    <string>0.0.50</string>
 	<key>CFBundleVersion</key>
-    <string>20260609.2143</string>
+    <string>20260610.1156</string>
 	<key>LSMinimumSystemVersion</key>
 	<string>26.0</string>
 	<key>NSHighResolutionCapable</key>
diff --git a/C1.source/Sources/Aligner/QuickSwitchRootView.swift b/C1.source/Sources/Aligner/QuickSwitchRootView.swift
index 0b41426..f3e63f2 100644
--- a/C1.source/Sources/Aligner/QuickSwitchRootView.swift
+++ b/C1.source/Sources/Aligner/QuickSwitchRootView.swift
@@ -1835,12 +1835,14 @@
             groupContainer.shadowOffset = .zero
 
             let segments = display.spaces.map { space in
-                let container = CALayer()
+                let container = CAGradientLayer()
                 container.name = space.label
                 container.cornerRadius = 10
                 container.borderWidth = 1
                 container.borderColor = NSColor.separatorColor.withAlphaComponent(0.34).cgColor
-                container.backgroundColor = spaceColor(for: space).cgColor
+                container.backgroundColor = NSColor.clear.cgColor
+                container.startPoint = CGPoint(x: 0.5, y: 1.0)
+                container.endPoint = CGPoint(x: 0.5, y: 0.0)
                 container.shadowColor = NSColor.black.cgColor
 
                 let labelLayer = makeTextLayer(
@@ -2148,12 +2150,24 @@
                     ? NSColor.labelColor.withAlphaComponent(0.34)
                 : NSColor.separatorColor.withAlphaComponent(0.34)
         ).cgColor
-        segment.containerLayer.backgroundColor = (isActive
-            ? accentTintedWindowBackground(fraction: 0.10, alpha: 0.94)
-            : isAssociated
-                ? accentTintedWindowBackground(fraction: 0.07, alpha: 0.90)
-                : spaceColor(for: segment.space)
-        ).cgColor
+        if isActive {
+            applySpaceLaneSolidFill(
+                to: segment.containerLayer,
+                color: accentTintedWindowBackground(fraction: 0.10, alpha: 0.94)
+            )
+        } else if isAssociated {
+            applySpaceLaneSolidFill(
+                to: segment.containerLayer,
+                color: accentTintedWindowBackground(fraction: 0.07, alpha: 0.90)
+            )
+        } else if hasWindows {
+            applySpaceLaneGradientFill(
+                to: segment.containerLayer,
+                colors: spaceLaneIdleOccupiedGradientColors()
+            )
+        } else {
+            applySpaceLaneSolidFill(to: segment.containerLayer, color: .clear)
+        }
         segment.containerLayer.shadowOpacity = isActive ? 0.26 : isAssociated ? 0.18 : isCurrent ? 0.14 : 0
         segment.containerLayer.shadowRadius = isActive ? 24 : isAssociated ? 18 : isCurrent ? 12 : 0
         segment.containerLayer.shadowOffset = CGSize(
@@ -3440,20 +3454,43 @@
         return states.joined(separator: " / ")
     }
 
-    private func spaceColor(for space: QuickSwitchSpaceViewModel) -> NSColor {
-        if space.windowCount > 0 {
-            return NSColor.controlBackgroundColor.withAlphaComponent(0.36)
-        }
-
-        return NSColor.clear
-    }
-
     private var spaceLaneOccupiedColor: NSColor {
         if effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua {
             return NSColor(calibratedRed: 10 / 255, green: 132 / 255, blue: 1, alpha: 1)
         }
 
         return NSColor(calibratedRed: 0, green: 122 / 255, blue: 1, alpha: 1)
+    }
+
+    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)
+            let surface = NSColor.windowBackgroundColor.withAlphaComponent(1)
+            return [blue, surface]
+        }
+
+        return [
+            NSColor(calibratedRed: 232 / 255, green: 246 / 255, blue: 1, alpha: 1),
+            NSColor.white
+        ]
+    }
+
+    private func applySpaceLaneGradientFill(to layer: CALayer, colors: [NSColor]) {
+        if let gradientLayer = layer as? CAGradientLayer {
+            gradientLayer.colors = colors.map(\.cgColor)
+            gradientLayer.locations = [0, 1]
+            gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
+            gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
+        }
+        layer.backgroundColor = NSColor.clear.cgColor
+    }
+
+    private func applySpaceLaneSolidFill(to layer: CALayer, color: NSColor) {
+        if let gradientLayer = layer as? CAGradientLayer {
+            gradientLayer.colors = nil
+            gradientLayer.locations = nil
+        }
+        layer.backgroundColor = color.cgColor
     }
 
     private func makeFullscreenMarkerLayer(for space: QuickSwitchSpaceViewModel) -> CALayer? {
@@ -3675,11 +3712,18 @@
     }
 
     private func fullscreenMarkerFrame(in segmentBounds: CGRect) -> CGRect {
-        CGRect(
+        let topReserved: CGFloat = 32
+        let bottomReserved: CGFloat = 16
+        let availableHeight = max(20, segmentBounds.height - topReserved - bottomReserved)
+        let markerHeight = min(30, max(20, availableHeight))
+        let markerCenterY = bottomReserved + availableHeight * 0.5
+        let markerY = max(8, min(segmentBounds.height - topReserved - markerHeight, markerCenterY - markerHeight * 0.5))
+
+        return CGRect(
             x: 10,
-            y: 30,
+            y: markerY,
             width: max(1, segmentBounds.width - 20),
-            height: max(1, segmentBounds.height - 58)
+            height: markerHeight
         )
     }
 
@@ -4049,6 +4093,10 @@
                     dx: (group?.containerLayer.frame.minX ?? 0) + spaceLaneContentLayer.frame.minX,
                     dy: group?.containerLayer.frame.minY ?? 0
                 )
+                let fullscreenMarkerFrame = segment.fullscreenMarkerLayer?.frame
+                let fullscreenMarkerCenterRatio = fullscreenMarkerFrame.map {
+                    Double($0.midY / max(1, segment.containerLayer.bounds.height))
+                }
                 return [
                     "displayUUID": display.displayUUID,
                     "displayLabel": display.displayLabel,
@@ -4058,11 +4106,14 @@
                     "visualStates": visualStates(for: space),
                     "fullscreenMarkerVisible": segment.fullscreenMarkerLayer != nil,
                     "fullscreenMarkerKind": segment.fullscreenMarkerLayer == nil ? "none" : "cornerBracket",
-                    "fullscreenMarkerFrame": segment.fullscreenMarkerLayer.map { dictionary(from: $0.frame) } ?? NSNull(),
+                    "fullscreenMarkerFrame": fullscreenMarkerFrame.map { dictionary(from: $0) } ?? NSNull(),
+                    "fullscreenMarkerCenterRatio": fullscreenMarkerCenterRatio ?? NSNull(),
                     "windowBlockCount": segment.windowBlocks.count,
                     "windowBlockColors": segment.windowBlocks.map { colorDictionary(from: $0.backgroundColor) },
                     "windowBlockFrames": segment.windowBlocks.map { dictionary(from: $0.frame) },
+                    "backgroundKind": spaceLaneFillKind(for: segment.containerLayer),
                     "backgroundColor": colorDictionary(from: segment.containerLayer.backgroundColor),
+                    "gradientColors": gradientColorDictionaries(from: segment.containerLayer),
                     "borderColor": colorDictionary(from: segment.containerLayer.borderColor),
                     "borderWidth": Double(segment.containerLayer.borderWidth),
                     "shadowOpacity": Double(segment.containerLayer.shadowOpacity),
@@ -4153,4 +4204,23 @@
             "alpha": Double(nsColor.alphaComponent)
         ]
     }
+
+    private func gradientColorDictionaries(from layer: CALayer) -> [[String: Double]] {
+        guard let gradientLayer = layer as? CAGradientLayer else { return [] }
+        return (gradientLayer.colors ?? []).map { color in
+            let cgColor = color as! CGColor
+            return colorDictionary(from: cgColor)
+        }
+    }
+
+    private func spaceLaneFillKind(for layer: CALayer) -> String {
+        if !gradientColorDictionaries(from: layer).isEmpty {
+            return "gradient"
+        }
+        let background = colorDictionary(from: layer.backgroundColor)
+        if background["alpha", default: 0] <= 0.01 {
+            return "clear"
+        }
+        return "solid"
+    }
 }
diff --git a/C3.tools/round1-three-zone-linkage-fixture-qa.sh b/C3.tools/round1-three-zone-linkage-fixture-qa.sh
index 3510d7f..84b821a 100755
--- a/C3.tools/round1-three-zone-linkage-fixture-qa.sh
+++ b/C3.tools/round1-three-zone-linkage-fixture-qa.sh
@@ -531,6 +531,23 @@
         and inner.get("y", 0) + inner.get("height", 0) <= outer.get("y", 0) + outer.get("height", 0) + tolerance
     )
 
+def is_light_blue(color):
+    return (
+        color.get("alpha", 0) >= 0.98
+        and color.get("blue", 0) >= 0.98
+        and color.get("green", 0) >= 0.90
+        and color.get("red", 0) >= 0.80
+        and color.get("blue", 0) > color.get("red", 0) + 0.04
+    )
+
+def is_white(color):
+    return (
+        color.get("alpha", 0) >= 0.98
+        and color.get("red", 0) >= 0.98
+        and color.get("green", 0) >= 0.98
+        and color.get("blue", 0) >= 0.98
+    )
+
 root = report.get("rootView", {})
 groups = root.get("spaceLaneDisplayGroups", [])
 segments = root.get("spaceLaneSegments", [])
@@ -606,14 +623,34 @@
 ]
 require(idle_empty_segments, "multi-display visual fixture must include at least one idle empty Space")
 require(
-    all(segment.get("backgroundColor", {}).get("alpha", 1) <= 0.01 for segment in idle_empty_segments),
+    all(segment.get("backgroundKind") == "clear" for segment in idle_empty_segments),
     "idle empty Spaces must not keep a dirty gray fill"
 )
+idle_occupied_segments = [
+    segment for segment in segments
+    if segment.get("windowCount", 0) > 0
+    and segment.get("isFocused") is not True
+    and segment.get("isCurrent") is not True
+    and segment.get("isAppAssociated") is not True
+    and segment.get("isWindowAssociated") is not True
+]
+require(idle_occupied_segments, "multi-display visual fixture must include an idle occupied Space")
+for segment in idle_occupied_segments:
+    gradient_colors = segment.get("gradientColors", [])
+    require(segment.get("backgroundKind") == "gradient", "idle occupied Spaces must use blue-white gradient fill")
+    require(len(gradient_colors) == 2, "idle occupied Space gradient must expose two color stops")
+    require(is_light_blue(gradient_colors[0]), "idle occupied Space gradient must start with pure light blue")
+    require(is_white(gradient_colors[1]), "idle occupied Space gradient must end with pure white")
 fullscreen_segments = [segment for segment in segments if segment.get("type") == "fullscreen"]
 require(fullscreen_segments, "multi-display visual fixture must include a fullscreen Space")
 for segment in fullscreen_segments:
     marker_frame = segment.get("fullscreenMarkerFrame", {})
-    require(marker_frame.get("y") == 30, "fullscreen Space marker must keep the previous vertical style")
+    app_frame = segment.get("appFrame", {})
+    marker_center_ratio = segment.get("fullscreenMarkerCenterRatio", 0)
+    marker_mid_y = marker_frame.get("y", 0) + marker_frame.get("height", 0) / 2
+    app_mid_y = app_frame.get("y", 0) + app_frame.get("height", 0) / 2
+    require(0.36 <= marker_center_ratio <= 0.44, "fullscreen Space marker must use adaptive vertical centering")
+    require(abs(marker_mid_y - app_mid_y) <= 2, "fullscreen App label must remain centered in the marker")
 
 print(json.dumps({
     "displayGroups": [

--
Gitblit v1.9.3