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