From 3d8d37306e39db5c8eb41fafd95a13112d573f62 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 11 Jun 2026 22:24:39 +0800
Subject: [PATCH] Center filtered Waterfall columns
---
C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 230 insertions(+), 5 deletions(-)
diff --git a/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift b/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
index 2dcabd3..e583820 100644
--- a/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
+++ b/C1.source/Tests/AlignerCoreTests/AlignerCoreTests.swift
@@ -212,12 +212,25 @@
let record = makeWindowRecord(
title: "Closed Document.md",
hasAXBacking: false,
- isOnscreen: false,
- spaceIDs: [5]
+ isOnscreen: false
)
XCTAssertFalse(WindowEnumerationPolicy.shouldInclude(record))
XCTAssertNil(WindowEnumerationPolicy.window(from: record))
+ }
+
+ func testWindowEnumerationPolicyKeepsCGOnlyOffscreenWindowsWithKnownSpaceIDs() {
+ let record = makeWindowRecord(
+ title: "Other Space Document.md",
+ hasAXBacking: false,
+ isOnscreen: false,
+ spaceIDs: [5]
+ )
+
+ let window = WindowEnumerationPolicy.window(from: record)
+
+ XCTAssertEqual(window?.title, "Other Space Document.md")
+ XCTAssertEqual(window?.spaceIDs, [5])
}
func testWindowEnumerationPolicyKeepsAXBackedOffscreenWindows() {
@@ -283,13 +296,13 @@
XCTAssertNil(WindowEnumerationPolicy.window(from: tinyRecord))
}
- func testWindowEnumerationPolicyKeepsShottrCGOnlyAnnotationWindow() {
+ func testWindowEnumerationPolicyExcludesClosedShottrCGPlaceholderButKeepsVisibleWindow() {
let shottrApp = AlignerApp(
bundleIdentifier: "cc.ffitch.shottr",
name: "Shottr",
category: .generic
)
- let annotationRecord = WindowEnumerationRecord(
+ let closedPlaceholderRecord = WindowEnumerationRecord(
id: 78,
app: shottrApp,
activationPolicy: .accessory,
@@ -298,6 +311,16 @@
subrole: .standard,
hasAXBacking: false,
isOnscreen: false
+ )
+ let visibleRecord = WindowEnumerationRecord(
+ id: 79,
+ app: shottrApp,
+ activationPolicy: .accessory,
+ title: "Shottr",
+ size: CGSize(width: 1710, height: 997),
+ subrole: .standard,
+ hasAXBacking: false,
+ isOnscreen: true
)
let utilityRecord = WindowEnumerationRecord(
id: 102,
@@ -310,7 +333,8 @@
isOnscreen: false
)
- XCTAssertEqual(WindowEnumerationPolicy.window(from: annotationRecord)?.title, "Shottr")
+ XCTAssertNil(WindowEnumerationPolicy.window(from: closedPlaceholderRecord))
+ XCTAssertEqual(WindowEnumerationPolicy.window(from: visibleRecord)?.title, "Shottr")
XCTAssertNil(WindowEnumerationPolicy.window(from: utilityRecord))
}
@@ -1150,6 +1174,50 @@
XCTAssertEqual(snapshot.appGroups.single?.windows.map(\.primarySpaceID), [10, 11, 12, 12, nil])
}
+ func testWindowSpaceMappingFillsUnresolvedWindowsFromSpaceInverseMap() {
+ let mapping = WindowSpaceMappingPolicy.mergedSpaceIDsByWindowID(
+ requestedWindowIDs: [10, 20, 30],
+ directSpaceIDsByWindowID: [10: [100]],
+ windowIDsBySpaceID: [
+ 100: [10, 20],
+ 101: [30]
+ ],
+ orderedSpaceIDs: [100, 101]
+ )
+
+ XCTAssertEqual(mapping[10], [100])
+ XCTAssertEqual(mapping[20], [100])
+ XCTAssertEqual(mapping[30], [101])
+ }
+
+ func testWindowSpaceMappingDoesNotOverwriteDirectSpaceAssignments() {
+ let mapping = WindowSpaceMappingPolicy.mergedSpaceIDsByWindowID(
+ requestedWindowIDs: [10],
+ directSpaceIDsByWindowID: [10: [101]],
+ windowIDsBySpaceID: [
+ 100: [10]
+ ],
+ orderedSpaceIDs: [100, 101]
+ )
+
+ XCTAssertEqual(mapping[10], [101])
+ }
+
+ func testWindowSpaceMappingLeavesAmbiguousNoSpaceWindowsUnassigned() {
+ let mapping = WindowSpaceMappingPolicy.mergedSpaceIDsByWindowID(
+ requestedWindowIDs: [10, 20],
+ directSpaceIDsByWindowID: [:],
+ windowIDsBySpaceID: [
+ 100: [10, 99]
+ ],
+ orderedSpaceIDs: [100]
+ )
+
+ XCTAssertEqual(mapping[10], [100])
+ XCTAssertNil(mapping[20])
+ XCTAssertNil(mapping[99])
+ }
+
func testQuickSwitchSnapshotKeepsMinimizedAndFullscreenWindows() {
let app = makeApp()
let snapshot = QuickSwitchSnapshotBuilder.snapshot(
@@ -1211,6 +1279,163 @@
XCTAssertEqual(viewModel.waterfallColumns.flatMap { $0.windows.map(\.primarySpaceLabel) }, ["01", "02"])
}
+ func testQuickSwitchSpaceFilterProjectsAppShelfAndWaterfallWithoutChangingSpaceLane() {
+ let alpha = AlignerApp(bundleIdentifier: "com.example.Alpha", name: "Alpha", category: .generic)
+ let beta = AlignerApp(bundleIdentifier: "com.example.Beta", name: "Beta", category: .generic)
+ let snapshot = QuickSwitchSnapshotBuilder.snapshot(
+ displays: [makeDisplay(spaceIDs: [10, 11])],
+ windows: [
+ AlignerWindow(id: 1, app: alpha, title: "A1", spaceIDs: [10]),
+ AlignerWindow(id: 2, app: alpha, title: "A2", spaceIDs: [11]),
+ AlignerWindow(id: 3, app: beta, title: "B1", spaceIDs: [11]),
+ AlignerWindow(id: 4, app: beta, title: "No Space")
+ ]
+ )
+ let viewModel = QuickSwitchViewModelBuilder.viewModel(from: snapshot)
+
+ let filtered = QuickSwitchSpaceFilterPolicy.projectedViewModel(
+ from: viewModel,
+ lockedSpaceID: 11
+ )
+
+ XCTAssertEqual(filtered.lockedSpaceID, 11)
+ XCTAssertEqual(filtered.displays.flatMap { $0.spaces.map(\.id) }, [10, 11])
+ XCTAssertEqual(filtered.displays.flatMap { $0.spaces.map(\.windowCount) }, [1, 2])
+ XCTAssertEqual(filtered.appShelf.map(\.app.name), ["Alpha", "Beta"])
+ XCTAssertEqual(filtered.appShelf.map(\.windowCount), [1, 1])
+ XCTAssertEqual(filtered.appShelf.flatMap(\.primarySpaceIDs), [11, 11])
+ XCTAssertEqual(filtered.waterfallColumns.flatMap { $0.windows.map(\.window.id) }, [2, 3])
+ XCTAssertEqual(filtered.waterfallColumns.flatMap { $0.windows.map(\.windowIndex) }, [0, 0])
+ XCTAssertEqual(filtered.waterfallColumns.flatMap { $0.windows.map(\.globalIndex) }, [0, 1])
+ XCTAssertEqual(filtered.initialSelection, QuickSwitchSelection(appGroupIndex: 0, windowIndex: 0, windowID: 2))
+ }
+
+ func testQuickSwitchSpaceFilterKeyboardNavigationStaysInsideFilteredCollection() {
+ let alpha = AlignerApp(bundleIdentifier: "com.example.Alpha", name: "Alpha", category: .generic)
+ let beta = AlignerApp(bundleIdentifier: "com.example.Beta", name: "Beta", category: .generic)
+ let snapshot = QuickSwitchSnapshotBuilder.snapshot(
+ displays: [makeDisplay(spaceIDs: [10, 11])],
+ windows: [
+ AlignerWindow(id: 1, app: alpha, title: "Alpha A1", spaceIDs: [10]),
+ AlignerWindow(id: 2, app: alpha, title: "Alpha A2", spaceIDs: [11]),
+ AlignerWindow(id: 3, app: beta, title: "Beta A2", spaceIDs: [11]),
+ AlignerWindow(id: 4, app: beta, title: "Beta No Space")
+ ]
+ )
+ let viewModel = QuickSwitchViewModelBuilder.viewModel(from: snapshot)
+ let filtered = QuickSwitchSpaceFilterPolicy.projectedViewModel(
+ from: viewModel,
+ lockedSpaceID: 11
+ )
+ let filteredSnapshot = QuickSwitchSnapshot(
+ displays: snapshot.displays,
+ appGroups: filtered.waterfallColumns.map { column in
+ QuickSwitchAppGroup(
+ app: column.app,
+ windows: column.windows.map {
+ QuickSwitchWindowItem(window: $0.window, primarySpaceID: $0.primarySpaceID)
+ }
+ )
+ }
+ )
+
+ XCTAssertEqual(filtered.initialSelection, QuickSwitchSelection(appGroupIndex: 0, windowIndex: 0, windowID: 2))
+ XCTAssertEqual(
+ QuickSwitchFocusPolicy.nextSelection(
+ from: filtered.initialSelection!,
+ in: filteredSnapshot,
+ direction: .right
+ ),
+ QuickSwitchSelection(appGroupIndex: 1, windowIndex: 0, windowID: 3)
+ )
+ XCTAssertEqual(
+ QuickSwitchFocusPolicy.nextSelection(
+ from: QuickSwitchSelection(appGroupIndex: 1, windowIndex: 0, windowID: 3),
+ in: filteredSnapshot,
+ direction: .right
+ ),
+ QuickSwitchSelection(appGroupIndex: 1, windowIndex: 0, windowID: 3)
+ )
+ XCTAssertFalse(filteredSnapshot.appGroups.flatMap(\.windows).contains { $0.window.id == 1 || $0.window.id == 4 })
+ }
+
+ func testQuickSwitchSpaceFilterCanLockEmptySpaceWithoutChangingSpaceLane() {
+ let app = AlignerApp(bundleIdentifier: "com.example.Alpha", name: "Alpha", category: .generic)
+ let snapshot = QuickSwitchSnapshotBuilder.snapshot(
+ displays: [makeDisplay(spaceIDs: [10, 11])],
+ windows: [
+ AlignerWindow(id: 1, app: app, title: "A1", spaceIDs: [10])
+ ]
+ )
+ let viewModel = QuickSwitchViewModelBuilder.viewModel(from: snapshot)
+
+ let filtered = QuickSwitchSpaceFilterPolicy.projectedViewModel(
+ from: viewModel,
+ lockedSpaceID: 11
+ )
+
+ XCTAssertEqual(filtered.lockedSpaceID, 11)
+ XCTAssertEqual(filtered.displays.flatMap { $0.spaces.map(\.id) }, [10, 11])
+ XCTAssertTrue(filtered.appShelf.isEmpty)
+ XCTAssertTrue(filtered.waterfallColumns.isEmpty)
+ XCTAssertNil(filtered.initialSelection)
+ }
+
+ func testQuickSwitchSpaceFilterRestoresPreferredSelectionWhenUnlocking() {
+ let app = AlignerApp(bundleIdentifier: "com.example.Alpha", name: "Alpha", category: .generic)
+ let snapshot = QuickSwitchSnapshotBuilder.snapshot(
+ displays: [makeDisplay(spaceIDs: [10, 11])],
+ windows: [
+ AlignerWindow(id: 1, app: app, title: "A1", spaceIDs: [10]),
+ AlignerWindow(id: 2, app: app, title: "A2", spaceIDs: [11])
+ ]
+ )
+ let viewModel = QuickSwitchViewModelBuilder.viewModel(from: snapshot)
+ let preferred = QuickSwitchSelection(appGroupIndex: 0, windowIndex: 1, windowID: 2)
+
+ let unlocked = QuickSwitchSpaceFilterPolicy.projectedViewModel(
+ from: viewModel,
+ lockedSpaceID: nil,
+ preferredSelection: preferred
+ )
+
+ XCTAssertNil(unlocked.lockedSpaceID)
+ XCTAssertEqual(unlocked.initialSelection, preferred)
+ }
+
+ func testQuickSwitchSpaceFilterDetectsOnlySingleFullscreenWindowSpacesAsDirectActivation() {
+ let alpha = AlignerApp(bundleIdentifier: "com.example.Alpha", name: "Alpha", category: .generic)
+ let beta = AlignerApp(bundleIdentifier: "com.example.Beta", name: "Beta", category: .generic)
+ let displayUUID = "display-a"
+ let snapshot = QuickSwitchSnapshotBuilder.snapshot(
+ displays: [
+ AlignerDisplay(
+ uuid: displayUUID,
+ physical: true,
+ spaces: [
+ AlignerSpace(id: 10, type: .user, displayUUID: displayUUID, index: 1),
+ AlignerSpace(id: 11, type: .fullscreen, displayUUID: displayUUID, index: 2),
+ AlignerSpace(id: 12, type: .fullscreen, displayUUID: displayUUID, index: 3)
+ ]
+ )
+ ],
+ windows: [
+ AlignerWindow(id: 1, app: alpha, title: "Normal", spaceIDs: [10]),
+ AlignerWindow(id: 2, app: alpha, title: "Fullscreen", isFullscreen: true, spaceIDs: [11]),
+ AlignerWindow(id: 3, app: beta, title: "Split A", isFullscreen: true, spaceIDs: [12]),
+ AlignerWindow(id: 4, app: beta, title: "Split B", isFullscreen: true, spaceIDs: [12])
+ ]
+ )
+ let viewModel = QuickSwitchViewModelBuilder.viewModel(from: snapshot)
+
+ XCTAssertEqual(
+ QuickSwitchSpaceFilterPolicy.singleFullscreenSelection(inSpaceID: 11, viewModel: viewModel),
+ QuickSwitchSelection(appGroupIndex: 0, windowIndex: 1, windowID: 2)
+ )
+ XCTAssertNil(QuickSwitchSpaceFilterPolicy.singleFullscreenSelection(inSpaceID: 10, viewModel: viewModel))
+ XCTAssertNil(QuickSwitchSpaceFilterPolicy.singleFullscreenSelection(inSpaceID: 12, viewModel: viewModel))
+ }
+
func testQuickSwitchFocusPolicySelectsFirstStableWindowInitially() {
let app = makeApp()
let snapshot = QuickSwitchSnapshotBuilder.snapshot(
--
Gitblit v1.9.3