| C1.source/Resources/Aligner-Info.plist | ●●●●● patch | view | raw | blame | history | |
| C1.source/Sources/Aligner/QuickSwitchRootView.swift | ●●●●● patch | view | raw | blame | history | |
| C3.tools/round1-three-zone-linkage-fixture-qa.sh | ●●●●● patch | view | raw | blame | history | |
| C3.tools/round1-waterfall-fixture-qa.sh | ●●●●● patch | view | raw | blame | history |
C1.source/Resources/Aligner-Info.plist
@@ -17,9 +17,9 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>0.0.48</string> <string>0.0.49</string> <key>CFBundleVersion</key> <string>20260609.2055</string> <string>20260609.2143</string> <key>LSMinimumSystemVersion</key> <string>26.0</string> <key>NSHighResolutionCapable</key> C1.source/Sources/Aligner/QuickSwitchRootView.swift
@@ -283,7 +283,7 @@ static let columnMaxWidth: CGFloat = 292 static let contentHorizontalPadding: CGFloat = 0 static let columnHorizontalPadding: CGFloat = 0 static let columnVerticalPadding: CGFloat = 12 static let columnVerticalPadding: CGFloat = 0 static let columnHeaderTextInset: CGFloat = 12 static let headerHeight: CGFloat = 34 static let cardHeight: CGFloat = 138 @@ -304,11 +304,11 @@ } private enum SpaceLaneMetrics { static let horizontalPadding: CGFloat = 12 static let groupGap: CGFloat = 30 static let groupHorizontalPadding: CGFloat = 12 static let groupVerticalPadding: CGFloat = 10 static let segmentGap: CGFloat = 10 static let horizontalPadding: CGFloat = 0 static let groupGap: CGFloat = 36 static let groupHorizontalPadding: CGFloat = 24 static let groupVerticalPadding: CGFloat = 6 static let segmentGap: CGFloat = 12 static let segmentMinWidth: CGFloat = 96 static let segmentMaxWidth: CGFloat = 150 } @@ -669,6 +669,8 @@ "glassBorderWidth": Double(glassLayer.borderWidth), "glassShadowOpacity": Double(glassLayer.shadowOpacity), "spaceLaneFrame": dictionary(from: laneLayer.frame), "spaceLaneBackgroundColor": colorDictionary(from: laneLayer.backgroundColor), "spaceLaneCornerRadius": Double(laneLayer.cornerRadius), "spaceLaneContentWidth": Double(spaceLaneContentWidth), "spaceLaneVisibleWidth": Double(laneLayer.bounds.width), "spaceLaneMaxScrollOffset": Double(spaceLaneMaxScrollOffset), @@ -1576,8 +1578,8 @@ glassLayer.shadowOpacity = 0 rootLayer.addSublayer(glassLayer) laneLayer.backgroundColor = NSColor.controlBackgroundColor.withAlphaComponent(0.68).cgColor laneLayer.cornerRadius = 16 laneLayer.backgroundColor = NSColor.clear.cgColor laneLayer.cornerRadius = 0 laneLayer.masksToBounds = true glassLayer.addSublayer(laneLayer) laneLayer.addSublayer(spaceLaneContentLayer) @@ -1822,11 +1824,11 @@ for display in currentViewModel?.displays ?? [] { let groupContainer = CALayer() groupContainer.name = display.displayLabel groupContainer.cornerRadius = 16 groupContainer.cornerRadius = 14 groupContainer.masksToBounds = false groupContainer.borderWidth = 1 groupContainer.borderColor = NSColor.separatorColor.withAlphaComponent(0.26).cgColor groupContainer.backgroundColor = NSColor.windowBackgroundColor.withAlphaComponent(0.28).cgColor groupContainer.borderWidth = 0 groupContainer.borderColor = NSColor.clear.cgColor groupContainer.backgroundColor = NSColor.windowBackgroundColor.cgColor groupContainer.shadowColor = NSColor.black.cgColor groupContainer.shadowOpacity = 0 groupContainer.shadowRadius = 0 @@ -2033,7 +2035,8 @@ private func layoutSpaceLaneSegments() { guard !spaceLaneDisplayGroups.isEmpty, !spaceLaneSegments.isEmpty else { return } let groupHeight = max(1, laneLayer.bounds.height - 16) let groupOuterVerticalInset: CGFloat = 6 let groupHeight = max(1, laneLayer.bounds.height - groupOuterVerticalInset * 2) let segmentHeight = max(1, groupHeight - SpaceLaneMetrics.groupVerticalPadding * 2) let groupGapWidth = CGFloat(max(0, spaceLaneDisplayGroups.count - 1)) * SpaceLaneMetrics.groupGap let segmentGapWidth = spaceLaneDisplayGroups.reduce(CGFloat(0)) { total, group in @@ -2076,7 +2079,7 @@ let groupWidth = groupWidths[index] group.containerLayer.frame = CGRect( x: x, y: 8, y: groupOuterVerticalInset, width: groupWidth, height: groupHeight ) @@ -2114,29 +2117,14 @@ || segment.space.id == windowHoverAssociatedSpaceID } let hasCurrentSegment = group.display.spaces.contains { $0.isCurrent } let hasWindows = group.display.spaces.contains { $0.windowCount > 0 } let background = hasActiveSegment ? accentTintedWindowBackground(fraction: 0.035, alpha: 0.62) : NSColor.windowBackgroundColor.withAlphaComponent(hasWindows ? 0.44 : 0.30) group.containerLayer.backgroundColor = background.cgColor group.containerLayer.borderColor = (hasActiveSegment ? spaceLaneOccupiedColor.withAlphaComponent(0.36) : hasCurrentSegment ? NSColor.labelColor.withAlphaComponent(0.22) : NSColor.separatorColor.withAlphaComponent(0.24) ).cgColor group.containerLayer.borderWidth = 1 group.containerLayer.shadowOpacity = hasActiveSegment ? 0.12 : 0 group.containerLayer.shadowRadius = hasActiveSegment ? 14 : 0 group.containerLayer.shadowOffset = CGSize(width: 0, height: -3) group.containerLayer.backgroundColor = NSColor.windowBackgroundColor.cgColor group.containerLayer.borderColor = NSColor.clear.cgColor group.containerLayer.borderWidth = 0 group.containerLayer.shadowOpacity = 0 group.containerLayer.shadowRadius = 0 group.containerLayer.shadowOffset = .zero group.containerLayer.zPosition = hasActiveSegment ? 8 : hasCurrentSegment ? 4 : 0 group.containerLayer.shadowPath = CGPath( roundedRect: group.containerLayer.bounds, cornerWidth: group.containerLayer.cornerRadius, cornerHeight: group.containerLayer.cornerRadius, transform: nil ) group.containerLayer.shadowPath = nil } private func applySpaceLaneVisualState(_ segment: SpaceLaneSegmentLayers) { @@ -3457,7 +3445,7 @@ return NSColor.controlBackgroundColor.withAlphaComponent(0.36) } return NSColor.labelColor.withAlphaComponent(space.isCurrent ? 0.07 : 0.05) return NSColor.clear } private var spaceLaneOccupiedColor: NSColor { @@ -3689,9 +3677,9 @@ private func fullscreenMarkerFrame(in segmentBounds: CGRect) -> CGRect { CGRect( x: 10, y: 12, y: 30, width: max(1, segmentBounds.width - 20), height: max(1, segmentBounds.height - 64) height: max(1, segmentBounds.height - 58) ) } @@ -3778,6 +3766,13 @@ let visibleFrame = column.containerLayer.frame.offsetBy(dx: waterfallContentLayer.frame.minX, dy: 0) let appGroupIndex = column.column.appGroupIndex let isHovered = appGroupIndex == effectiveHoveredAppGroupIndex let firstCardFrame = column.cards.first?.containerLayer.frame let headerToFirstCardGap = firstCardFrame.map { column.headerLayer.frame.minY - $0.maxY } let topToFirstCardGap = firstCardFrame.map { column.containerLayer.bounds.height - $0.maxY } return [ "appGroupIndex": appGroupIndex, @@ -3791,6 +3786,9 @@ "spaceFocusDirection": spaceFocusDirection(for: appGroupIndex), "frame": dictionary(from: column.containerLayer.frame), "visibleFrame": dictionary(from: visibleFrame), "headerFrame": dictionary(from: column.headerLayer.frame), "headerToFirstCardGap": headerToFirstCardGap.map(Double.init) ?? NSNull(), "topToFirstCardGap": topToFirstCardGap.map(Double.init) ?? NSNull(), "appNameFrame": dictionary(from: column.appNameLayer.frame), "appNameAlignment": column.appNameLayer.alignmentMode.rawValue, "appNameColor": colorDictionary(from: column.appNameLayer.foregroundColor), @@ -4031,6 +4029,8 @@ "shadowOpacity": Double(group.containerLayer.shadowOpacity), "shadowRadius": Double(group.containerLayer.shadowRadius), "groupGap": Double(SpaceLaneMetrics.groupGap), "groupHorizontalPadding": Double(SpaceLaneMetrics.groupHorizontalPadding), "groupVerticalPadding": Double(SpaceLaneMetrics.groupVerticalPadding), "segmentGap": Double(SpaceLaneMetrics.segmentGap) ] as [String: Any] } C3.tools/round1-three-zone-linkage-fixture-qa.sh
@@ -534,6 +534,7 @@ root = report.get("rootView", {}) groups = root.get("spaceLaneDisplayGroups", []) segments = root.get("spaceLaneSegments", []) lane_background = root.get("spaceLaneBackgroundColor", {}) require(report.get("snapshotLoaded") is True, "snapshotLoaded must be true") require(report.get("quickSwitchVisible") is True, "multi-display report must keep Quick Switch visible") @@ -544,6 +545,8 @@ require(len(segments) == 5, "Space segment reports must contain five segments") require(groups[0].get("spaceLabels") == ["A1", "A2", "A3"], "first Display group must contain A spaces") require(groups[1].get("spaceLabels") == ["B1", "B2"], "second Display group must contain B spaces") require(lane_background.get("alpha", 1) <= 0.01, "Space Lane outer background must be transparent") require(root.get("spaceLaneCornerRadius") == 0, "Space Lane outer layer must not draw a rounded white rectangle") first_group_frame = groups[0].get("visibleFrame", {}) second_group_frame = groups[1].get("visibleFrame", {}) @@ -556,9 +559,23 @@ for group in groups: group_frame = group.get("visibleFrame", {}) labels = group.get("spaceLabels", []) require(group.get("borderWidth") == 0, "Display group container must be borderless") require(group.get("shadowOpacity") == 0, "Display group container must not add a floating shadow") require(group.get("backgroundColor", {}).get("alpha", 0) >= 0.98, "Display group container must use an opaque system surface") require(group.get("groupHorizontalPadding", 0) >= 24, "Display group horizontal padding must be widened") for label in labels: require(label in segments_by_label, f"segment report must include {label}") require(contains(group_frame, segments_by_label[label].get("visibleFrame", {})), f"{label} must be inside its Display group") first_segment = segments_by_label[labels[0]].get("visibleFrame", {}) last_segment = segments_by_label[labels[-1]].get("visibleFrame", {}) require( first_segment.get("x", 0) - group_frame.get("x", 0) >= group.get("groupHorizontalPadding", 0) - 1.0, "Display group leading padding must match widened padding" ) require( right_edge(group_frame) - right_edge(last_segment) >= group.get("groupHorizontalPadding", 0) - 1.0, "Display group trailing padding must match widened padding" ) for group in groups: labels = group.get("spaceLabels", []) @@ -578,6 +595,25 @@ require(len(focused) == 1, "exactly one Space segment must be focused") require(focused[0].get("label") == "B1", "hovered multi-display Space must be B1") require("focused" in focused[0].get("visualStates", []), "focused B1 segment must expose focused visual state") idle_empty_segments = [ segment for segment in segments if segment.get("windowCount") == 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_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), "idle empty Spaces must not keep a dirty gray fill" ) 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") print(json.dumps({ "displayGroups": [ @@ -626,7 +662,7 @@ run_report "$SCROLL_REPORT" "scroll-app-shelf:99999" "scroll-app-shelf:99999" 60 1 assert_app_shelf_scroll_report "$SCROLL_REPORT" run_report "$DISPLAY_GROUP_REPORT" "hover-space:4" "hover-space:4" 6 3 report-only multi-display run_report "$DISPLAY_GROUP_REPORT" "hover-space:4" "hover-space:4" 1 1 report-only multi-display assert_display_group_report "$DISPLAY_GROUP_REPORT" swift "$SCRIPT_DIR/window-logic-qa.swift" --expect-no-quick-switch >&2 C3.tools/round1-waterfall-fixture-qa.sh
@@ -121,8 +121,12 @@ require(column.get("windowCount") == fixture_windows_per_app, "Waterfall column window count must match fixture") require(column.get("appNameAlignment") == "center", "Waterfall column app name must be center aligned") column_frame = column.get("frame", {}) header_frame = column.get("headerFrame", {}) app_name_frame = column.get("appNameFrame", {}) count_frame = column.get("countFrame", {}) header_to_first_card_gap = column.get("headerToFirstCardGap") top_to_first_card_gap = column.get("topToFirstCardGap") require(isinstance(header_frame, dict), "Waterfall column must expose headerFrame") require(isinstance(app_name_frame, dict), "Waterfall column must expose appNameFrame") require(isinstance(count_frame, dict), "Waterfall column must expose countFrame") column_width = column_frame.get("width", 0) @@ -131,6 +135,8 @@ require(app_name_frame.get("width", 0) >= column_width * 0.88, "Waterfall column app name frame must span most of the title bar") require(count_frame.get("x", 0) + count_frame.get("width", 0) <= column_width + 1.0, "Waterfall count frame must remain inside the title bar") require(count_frame.get("x", 0) >= column_width * 0.72, "Waterfall count frame must stay in the right side of the title bar") require(abs(header_to_first_card_gap) <= 1.0, "Waterfall first card must sit directly under the title bar") require(top_to_first_card_gap <= header_frame.get("height", 0) + 1.0, "Waterfall title-to-card height must remain compact") require(column.get("maxVerticalScrollOffset", 0) > 0, "Long Waterfall column must expose vertical scroll overflow") require(column.get("verticalScrollOffset") == 0, "Waterfall column should start at top")