From 9ba7cd3b47fb91eaaa8d0c3df8b7286a89be1756 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sun, 28 Jun 2026 21:19:30 +0800
Subject: [PATCH] Freeze 0.1.12 local QA baseline

---
 C1.source/Sources/Aligner/AlignerApplicationDelegate.swift |  327 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 306 insertions(+), 21 deletions(-)

diff --git a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
index ad68641..9904f96 100644
--- a/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
+++ b/C1.source/Sources/Aligner/AlignerApplicationDelegate.swift
@@ -14,16 +14,19 @@
     private let round1SnapshotDumpOptions = Round1SnapshotDumpOptions.parse(arguments: ProcessInfo.processInfo.arguments)
     private let round1ScreenshotProbeOptions = Round1ScreenshotProbeOptions.parse(arguments: ProcessInfo.processInfo.arguments)
     private let round1QuickSwitchOptions = Round1QuickSwitchLaunchOptions.parse(arguments: ProcessInfo.processInfo.arguments)
+    private let round015EntitlementOptions = Round015EntitlementLaunchOptions.parse(arguments: ProcessInfo.processInfo.arguments)
     private var permissionWindowController: PermissionsWindowController?
     private var debugOverlayController: Round0DebugOverlayController?
     private var round1PerformancePoCController: Round1PerformancePoCController?
     private var round1TriggerProbe: CGEventTapTriggerProbe?
     private var quickSwitchSessionController: QuickSwitchSessionController?
     private var quickSwitchTriggerService: CGEventTapTriggerService?
+    private var settingsWindowController: SettingsWindowController?
     private var isRunningQuickSwitchLifecycle = false
+    private var lastQuickSwitchOpenRequestSource: String?
     private var statusItem: NSStatusItem?
-    private var verticalWaterfallViewModeMenuItem: NSMenuItem?
-    private var horizontalWaterfallViewModeMenuItem: NSMenuItem?
+    private var verticalWaterfallViewModeMenuItems: [NSMenuItem] = []
+    private var horizontalWaterfallViewModeMenuItems: [NSMenuItem] = []
 
     func applicationDidFinishLaunching(_ notification: Notification) {
         let bundlePathSummary = DevelopmentDiagnostics.pathSummary(Bundle.main.bundlePath)
@@ -47,6 +50,7 @@
             return
         }
 
+        configureMainMenu()
         configureStatusItem()
         if !launchOptions.skipPermissions {
             showPermissionsIfNeeded()
@@ -85,7 +89,8 @@
             "hasVisibleWindows": flag,
             "activationPolicy": sender.activationPolicy().rawValue
         ])
-        return true
+        openQuickSwitchFromDockReopen(hasVisibleWindows: flag)
+        return false
     }
 
     private func configureStatusItem() {
@@ -96,8 +101,9 @@
         let menu = NSMenu()
         menu.delegate = self
         menu.addItem(menuItem(title: "About Aligner...", action: #selector(showAbout), keyEquivalent: ""))
+        menu.addItem(menuItem(title: "Settings...", action: #selector(showSettingsFromMenu), keyEquivalent: ""))
         menu.addItem(.separator())
-        menu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ","))
+        menu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ""))
         menu.addItem(.separator())
         menu.addItem(menuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
         menu.addItem(menuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
@@ -114,8 +120,70 @@
         DevelopmentDiagnostics.log("app.statusItem.configure.end", [
             "hasButton": item.button != nil,
             "hasAboutItem": true,
-            "hasWaterfallViewModeItems": verticalWaterfallViewModeMenuItem != nil
-                && horizontalWaterfallViewModeMenuItem != nil
+            "hasSettingsItem": true,
+            "hasWaterfallViewModeItems": !verticalWaterfallViewModeMenuItems.isEmpty
+                && !horizontalWaterfallViewModeMenuItems.isEmpty
+        ])
+    }
+
+    private func configureMainMenu() {
+        DevelopmentDiagnostics.log("app.mainMenu.configure.start")
+
+        let mainMenu = NSMenu(title: "Main Menu")
+        let appMenuItem = NSMenuItem(title: "Aligner", action: nil, keyEquivalent: "")
+        let appMenu = NSMenu(title: "Aligner")
+        appMenu.delegate = self
+        appMenuItem.submenu = appMenu
+        appMenu.addItem(menuItem(title: "About Aligner...", action: #selector(showAbout), keyEquivalent: ""))
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Settings...", action: #selector(showSettingsFromMenu), keyEquivalent: ","))
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Check Permissions...", action: #selector(showPermissions), keyEquivalent: ""))
+        appMenu.addItem(menuItem(title: "Show Quick Switch", action: #selector(showQuickSwitchFromMenu), keyEquivalent: ""))
+        appMenu.addItem(menuItem(title: "Hide Quick Switch", action: #selector(hideQuickSwitchFromMenu), keyEquivalent: ""))
+        appMenu.addItem(quickSwitchViewModeMenuItem())
+        appMenu.addItem(.separator())
+        appMenu.addItem(menuItem(title: "Quit Aligner", action: #selector(quit), keyEquivalent: "q"))
+        mainMenu.addItem(appMenuItem)
+
+        let editMenuItem = NSMenuItem(title: "Edit", action: nil, keyEquivalent: "")
+        let editMenu = NSMenu(title: "Edit")
+        editMenuItem.submenu = editMenu
+        editMenu.addItem(responderMenuItem(title: "Undo", action: Selector(("undo:")), keyEquivalent: "z"))
+        editMenu.addItem(responderMenuItem(title: "Redo", action: Selector(("redo:")), keyEquivalent: "Z"))
+        editMenu.addItem(.separator())
+        editMenu.addItem(responderMenuItem(title: "Cut", action: #selector(NSText.cut(_:)), keyEquivalent: "x"))
+        editMenu.addItem(responderMenuItem(title: "Copy", action: #selector(NSText.copy(_:)), keyEquivalent: "c"))
+        editMenu.addItem(responderMenuItem(title: "Paste", action: #selector(NSText.paste(_:)), keyEquivalent: "v"))
+        editMenu.addItem(responderMenuItem(title: "Select All", action: #selector(NSText.selectAll(_:)), keyEquivalent: "a"))
+        mainMenu.addItem(editMenuItem)
+
+        let viewMenuItem = NSMenuItem(title: "View", action: nil, keyEquivalent: "")
+        let viewMenu = NSMenu(title: "View")
+        viewMenu.delegate = self
+        viewMenuItem.submenu = viewMenu
+        viewMenu.addItem(quickSwitchViewModeMenuItem())
+        mainMenu.addItem(viewMenuItem)
+
+        let windowMenuItem = NSMenuItem(title: "Window", action: nil, keyEquivalent: "")
+        let windowMenu = NSMenu(title: "Window")
+        windowMenuItem.submenu = windowMenu
+        windowMenu.addItem(responderMenuItem(title: "Minimize", action: #selector(NSWindow.performMiniaturize(_:)), keyEquivalent: "m"))
+        windowMenu.addItem(responderMenuItem(title: "Zoom", action: #selector(NSWindow.performZoom(_:)), keyEquivalent: ""))
+        windowMenu.addItem(.separator())
+        windowMenu.addItem(responderMenuItem(title: "Bring All to Front", action: #selector(NSApplication.arrangeInFront(_:)), keyEquivalent: ""))
+        mainMenu.addItem(windowMenuItem)
+        NSApp.windowsMenu = windowMenu
+
+        let helpMenuItem = NSMenuItem(title: "Help", action: nil, keyEquivalent: "")
+        helpMenuItem.submenu = NSMenu(title: "Help")
+        mainMenu.addItem(helpMenuItem)
+
+        NSApp.mainMenu = mainMenu
+        updateWaterfallViewModeMenuState()
+        DevelopmentDiagnostics.log("app.mainMenu.configure.end", [
+            "hasSettingsItem": appMenu.item(withTitle: "Settings...") != nil,
+            "hasQuickSwitchViewSubmenu": appMenu.item(withTitle: "Quick Switch View")?.submenu != nil
         ])
     }
 
@@ -127,6 +195,10 @@
         let item = NSMenuItem(title: title, action: action, keyEquivalent: keyEquivalent)
         item.target = self
         return item
+    }
+
+    private func responderMenuItem(title: String, action: Selector?, keyEquivalent: String) -> NSMenuItem {
+        NSMenuItem(title: title, action: action, keyEquivalent: keyEquivalent)
     }
 
     private func quickSwitchViewModeMenuItem() -> NSMenuItem {
@@ -144,8 +216,8 @@
         submenu.addItem(verticalItem)
         submenu.addItem(horizontalItem)
 
-        verticalWaterfallViewModeMenuItem = verticalItem
-        horizontalWaterfallViewModeMenuItem = horizontalItem
+        verticalWaterfallViewModeMenuItems.append(verticalItem)
+        horizontalWaterfallViewModeMenuItems.append(horizontalItem)
 
         let rootItem = NSMenuItem(title: "Quick Switch View", action: nil, keyEquivalent: "")
         rootItem.submenu = submenu
@@ -154,8 +226,12 @@
 
     private func updateWaterfallViewModeMenuState() {
         let mode = quickSwitchWaterfallViewMode()
-        verticalWaterfallViewModeMenuItem?.state = mode == .verticalColumns ? .on : .off
-        horizontalWaterfallViewModeMenuItem?.state = mode == .horizontalMasonry ? .on : .off
+        for item in verticalWaterfallViewModeMenuItems {
+            item.state = mode == .verticalColumns ? .on : .off
+        }
+        for item in horizontalWaterfallViewModeMenuItems {
+            item.state = mode == .horizontalMasonry ? .on : .off
+        }
     }
 
     private func showPermissionsIfNeeded() {
@@ -368,10 +444,13 @@
     }
 
     private func showQuickSwitchIfRequested() {
-        guard round1QuickSwitchOptions.openQuickSwitch || round1QuickSwitchOptions.lifecycleCycles != nil else { return }
+        guard round1QuickSwitchOptions.openQuickSwitch
+                || round1QuickSwitchOptions.lifecycleCycles != nil
+                || round1QuickSwitchOptions.simulateDockReopenAfter != nil else { return }
         DevelopmentDiagnostics.log("app.quickSwitch.launchOptionRequested", [
             "openQuickSwitch": round1QuickSwitchOptions.openQuickSwitch,
-            "lifecycleCycles": round1QuickSwitchOptions.lifecycleCycles
+            "lifecycleCycles": round1QuickSwitchOptions.lifecycleCycles,
+            "simulateDockReopenAfter": round1QuickSwitchOptions.simulateDockReopenAfter
         ])
 
         if let lifecycleCycles = round1QuickSwitchOptions.lifecycleCycles {
@@ -379,9 +458,23 @@
             return
         }
 
-        openQuickSwitchFromTrigger()
-        writeQuickSwitchReportIfNeeded()
+        if let simulateDockReopenAfter = round1QuickSwitchOptions.simulateDockReopenAfter {
+            DispatchQueue.main.asyncAfter(deadline: .now() + simulateDockReopenAfter) { [weak self] in
+                guard let self else { return }
+                let hasVisibleWindows = NSApp.windows.contains { $0.isVisible }
+                self.openQuickSwitchFromDockReopen(hasVisibleWindows: hasVisibleWindows)
+                self.writeQuickSwitchReportIfNeeded()
+                self.scheduleQuickSwitchAutoHideAndQuitIfNeeded()
+            }
+            return
+        }
 
+        openQuickSwitchFromTrigger(source: "launchOption")
+        writeQuickSwitchReportIfNeeded()
+        scheduleQuickSwitchAutoHideAndQuitIfNeeded()
+    }
+
+    private func scheduleQuickSwitchAutoHideAndQuitIfNeeded() {
         if let autoHideAfter = round1QuickSwitchOptions.autoHideAfter {
             DispatchQueue.main.asyncAfter(deadline: .now() + autoHideAfter) { [weak self] in
                 self?.hideQuickSwitchSession(reason: .timeout)
@@ -408,6 +501,7 @@
                 windowCloseService: quickSwitchWindowCloseService(),
                 disableScreenshotRefresh: round1QuickSwitchOptions.disableScreenshotRefresh,
                 waterfallViewMode: quickSwitchWaterfallViewMode(),
+                theme: quickSwitchThemePreference(),
                 closeConfirmationRequired: quickSwitchConfirmBeforeClose,
                 onCloseConfirmationDisabled: { [weak self] in
                     self?.setQuickSwitchConfirmBeforeClose(false)
@@ -420,6 +514,12 @@
             )
             controller.onSnapshotUpdated = { [weak self] in
                 self?.writeQuickSwitchReportIfNeeded()
+            }
+            controller.onToggleWaterfallViewMode = { [weak self] in
+                self?.toggleQuickSwitchWaterfallViewModeFromQuickSwitch()
+            }
+            controller.onToggleTheme = { [weak self] in
+                self?.toggleQuickSwitchThemeFromQuickSwitch()
             }
             quickSwitchSessionController = controller
         }
@@ -453,9 +553,19 @@
         }
     }
 
-    private func openQuickSwitchFromTrigger() {
+    private func openQuickSwitchFromDockReopen(hasVisibleWindows: Bool) {
+        DevelopmentDiagnostics.log("app.quickSwitch.openFromDockReopen", [
+            "hasVisibleWindows": hasVisibleWindows,
+            "alreadyVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+        openQuickSwitchFromTrigger(source: "dockReopen")
+    }
+
+    private func openQuickSwitchFromTrigger(source: String = "trigger") {
+        lastQuickSwitchOpenRequestSource = source
         let accessibility = accessibilityStatus()
         DevelopmentDiagnostics.log("app.quickSwitch.openFromTrigger", [
+            "source": source,
             "accessibility": permissionStatusString(accessibility),
             "screenRecording": permissionStatusString(screenRecordingStatus()),
             "alreadyVisible": quickSwitchSessionController?.isVisible ?? false
@@ -484,6 +594,7 @@
                 windowCloseService: quickSwitchWindowCloseService(),
                 disableScreenshotRefresh: round1QuickSwitchOptions.disableScreenshotRefresh,
                 waterfallViewMode: quickSwitchWaterfallViewMode(),
+                theme: quickSwitchThemePreference(),
                 closeConfirmationRequired: quickSwitchConfirmBeforeClose,
                 onCloseConfirmationDisabled: { [weak self] in
                     self?.setQuickSwitchConfirmBeforeClose(false)
@@ -496,6 +607,12 @@
             )
             controller.onSnapshotUpdated = { [weak self] in
                 self?.writeQuickSwitchReportIfNeeded()
+            }
+            controller.onToggleWaterfallViewMode = { [weak self] in
+                self?.toggleQuickSwitchWaterfallViewModeFromQuickSwitch()
+            }
+            controller.onToggleTheme = { [weak self] in
+                self?.toggleQuickSwitchThemeFromQuickSwitch()
             }
             quickSwitchSessionController = controller
         }
@@ -528,9 +645,15 @@
         let versionBuild = appVersionBuild()
         report["preferenceWaterfallViewMode"] = preferenceStore.read().quickSwitchWaterfallViewMode.rawValue
         report["resolvedWaterfallViewMode"] = quickSwitchWaterfallViewMode().rawValue
+        report["preferenceTheme"] = preferenceStore.read().theme.rawValue
+        report["resolvedQuickSwitchTheme"] = quickSwitchThemePreference().rawValue
+        report["lastQuickSwitchOpenRequestSource"] = lastQuickSwitchOpenRequestSource
+        report["authorization"] = round015EntitlementOptions.authorizationReportDictionary()
         report["aboutVersion"] = versionBuild.version
         report["aboutBuild"] = versionBuild.build
         report["statusMenu"] = statusMenuReportDictionary()
+        report["mainMenu"] = mainMenuReportDictionary()
+        report["settingsWindow"] = settingsWindowReportDictionary()
 
         do {
             let data = try JSONSerialization.data(withJSONObject: report, options: [.prettyPrinted, .sortedKeys])
@@ -581,6 +704,14 @@
             return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .spaceFilter)
         }
 
+        if round1QuickSwitchOptions.fixtureSplitView {
+            return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .splitView)
+        }
+
+        if round1QuickSwitchOptions.fixtureMultiPageIdentity {
+            return FixtureQuickSwitchSnapshotLoader(appCount: 1, mode: .multiPageIdentity)
+        }
+
         if let fixtureAppCount = round1QuickSwitchOptions.fixtureAppCount {
             return FixtureQuickSwitchSnapshotLoader(
                 appCount: fixtureAppCount,
@@ -603,12 +734,21 @@
             return DebugWindowActivationService()
         }
 
-        return CGWindowAXWindowService(spaceIDsByWindowIDProvider: { _ in [:] })
+        let context = quickSwitchWindowSpaceContext()
+        return CGWindowAXWindowService(
+            spaceIDsByWindowIDProvider: context.spaceIDsByWindowIDProvider,
+            fullscreenSpaceIDs: context.fullscreenSpaceIDs
+        )
     }
 
     private func quickSwitchWaterfallViewMode() -> QuickSwitchWaterfallViewMode {
         round1QuickSwitchOptions.waterfallViewMode
             ?? preferenceStore.read().quickSwitchWaterfallViewMode
+    }
+
+    private func quickSwitchThemePreference() -> ThemePreference {
+        let theme = preferenceStore.read().theme
+        return theme == .dark ? .dark : .light
     }
 
     private func quickSwitchSpaceActivationService() -> any SpaceActivationServiceProtocol {
@@ -624,7 +764,39 @@
             return DebugWindowCloseService()
         }
 
-        return CGWindowAXWindowService(spaceIDsByWindowIDProvider: { _ in [:] })
+        let context = quickSwitchWindowSpaceContext()
+        return CGWindowAXWindowService(
+            spaceIDsByWindowIDProvider: context.spaceIDsByWindowIDProvider,
+            fullscreenSpaceIDs: context.fullscreenSpaceIDs
+        )
+    }
+
+    private func quickSwitchWindowSpaceContext() -> (
+        spaceIDsByWindowIDProvider: ([UInt32]) -> [UInt32: [UInt64]],
+        fullscreenSpaceIDs: Set<UInt64>
+    ) {
+        do {
+            let spaceEnumerator = try SkyLightSpaceEnumerator()
+            let displays = try spaceEnumerator.displays()
+            let fullscreenSpaceIDs = Set(
+                displays
+                    .flatMap(\.spaces)
+                    .filter { $0.type == .fullscreen }
+                    .map(\.id)
+            )
+            return (
+                spaceIDsByWindowIDProvider: spaceEnumerator.spaceIDsByWindowID(windowIDs:),
+                fullscreenSpaceIDs: fullscreenSpaceIDs
+            )
+        } catch {
+            DevelopmentDiagnostics.log("app.quickSwitch.windowSpaceContextUnavailable", [
+                "error": DevelopmentDiagnostics.errorSummaryString(error)
+            ])
+            return (
+                spaceIDsByWindowIDProvider: { _ in [:] },
+                fullscreenSpaceIDs: []
+            )
+        }
     }
 
     private var quickSwitchConfirmBeforeClose: Bool {
@@ -652,11 +824,56 @@
         preferenceStore.write(updatedPreferences)
         quickSwitchSessionController?.setWaterfallViewMode(mode)
         updateWaterfallViewModeMenuState()
+        settingsWindowController?.refreshWaterfallViewMode()
         writeQuickSwitchReportIfNeeded()
         DevelopmentDiagnostics.log("app.quickSwitch.waterfallViewModePreferenceChanged", [
             "mode": mode.rawValue,
             "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
         ])
+    }
+
+    private func toggleQuickSwitchWaterfallViewModeFromQuickSwitch() {
+        let currentMode = quickSwitchWaterfallViewMode()
+        let nextMode: QuickSwitchWaterfallViewMode = currentMode == .horizontalMasonry
+            ? .verticalColumns
+            : .horizontalMasonry
+        DevelopmentDiagnostics.log("app.quickSwitch.waterfallViewModeToggle", [
+            "currentMode": currentMode.rawValue,
+            "nextMode": nextMode.rawValue,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+        setQuickSwitchWaterfallViewMode(nextMode)
+    }
+
+    private func setQuickSwitchThemePreference(_ theme: ThemePreference) {
+        let normalizedTheme: ThemePreference = theme == .dark ? .dark : .light
+        let preferences = preferenceStore.read()
+        let updatedPreferences = AlignerPreferences(
+            showMinimizedWindows: preferences.showMinimizedWindows,
+            showFullscreenWindows: preferences.showFullscreenWindows,
+            quickSwitchWaterfallViewMode: preferences.quickSwitchWaterfallViewMode,
+            theme: normalizedTheme,
+            language: preferences.language,
+            spaceDisplayStrategy: preferences.spaceDisplayStrategy
+        )
+        preferenceStore.write(updatedPreferences)
+        quickSwitchSessionController?.setTheme(normalizedTheme)
+        writeQuickSwitchReportIfNeeded()
+        DevelopmentDiagnostics.log("app.quickSwitch.themePreferenceChanged", [
+            "theme": normalizedTheme.rawValue,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+    }
+
+    private func toggleQuickSwitchThemeFromQuickSwitch() {
+        let currentTheme = quickSwitchThemePreference()
+        let nextTheme: ThemePreference = currentTheme == .dark ? .light : .dark
+        DevelopmentDiagnostics.log("app.quickSwitch.themeToggle", [
+            "currentTheme": currentTheme.rawValue,
+            "nextTheme": nextTheme.rawValue,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false
+        ])
+        setQuickSwitchThemePreference(nextTheme)
     }
 
     private func appVersionBuild() -> (version: String, build: String) {
@@ -668,13 +885,44 @@
 
     private func statusMenuReportDictionary() -> [String: Any] {
         updateWaterfallViewModeMenuState()
+        let verticalItem = verticalWaterfallViewModeMenuItems.first
+        let horizontalItem = horizontalWaterfallViewModeMenuItems.first
         return [
             "hasAboutItem": statusItem?.menu?.item(withTitle: "About Aligner...") != nil,
+            "hasSettingsItem": statusItem?.menu?.item(withTitle: "Settings...") != nil,
             "hasQuickSwitchViewSubmenu": statusItem?.menu?.item(withTitle: "Quick Switch View")?.submenu != nil,
-            "hasVerticalColumnsItem": verticalWaterfallViewModeMenuItem != nil,
-            "hasHorizontalWaterfallItem": horizontalWaterfallViewModeMenuItem != nil,
-            "verticalColumnsState": verticalWaterfallViewModeMenuItem?.state == .on ? "on" : "off",
-            "horizontalWaterfallState": horizontalWaterfallViewModeMenuItem?.state == .on ? "on" : "off"
+            "hasVerticalColumnsItem": verticalItem != nil,
+            "hasHorizontalWaterfallItem": horizontalItem != nil,
+            "verticalColumnsState": verticalItem?.state == .on ? "on" : "off",
+            "horizontalWaterfallState": horizontalItem?.state == .on ? "on" : "off"
+        ]
+    }
+
+    private func mainMenuReportDictionary() -> [String: Any] {
+        updateWaterfallViewModeMenuState()
+        let appMenu = NSApp.mainMenu?.items.first?.submenu
+        let viewMenu = NSApp.mainMenu?.item(withTitle: "View")?.submenu
+        return [
+            "hasMenu": NSApp.mainMenu != nil,
+            "hasAppMenu": appMenu != nil,
+            "hasAboutItem": appMenu?.item(withTitle: "About Aligner...") != nil,
+            "hasSettingsItem": appMenu?.item(withTitle: "Settings...") != nil,
+            "settingsKeyEquivalent": appMenu?.item(withTitle: "Settings...")?.keyEquivalent ?? "",
+            "hasQuickSwitchViewSubmenuInAppMenu": appMenu?.item(withTitle: "Quick Switch View")?.submenu != nil,
+            "hasQuickSwitchViewSubmenuInViewMenu": viewMenu?.item(withTitle: "Quick Switch View")?.submenu != nil
+        ]
+    }
+
+    private func settingsWindowReportDictionary() -> [String: Any] {
+        settingsWindowController?.reportDictionary() ?? [
+            "exists": false,
+            "visible": false,
+            "title": "",
+            "selectedTabLabel": "",
+            "selectedTabIdentifier": "",
+            "waterfallViewMode": quickSwitchWaterfallViewMode().rawValue,
+            "hasViewTab": false,
+            "usesSwiftUI": false
         ]
     }
 
@@ -696,6 +944,43 @@
         alert.runModal()
     }
 
+    @objc private func showSettingsFromMenu() {
+        openSettingsWindow(source: "menu")
+    }
+
+    private func showSettingsFromQuickSwitch() {
+        openSettingsWindow(source: "quickSwitch")
+    }
+
+    private func openSettingsWindow(source: String) {
+        DevelopmentDiagnostics.log("app.settings.show", [
+            "source": source,
+            "quickSwitchVisible": quickSwitchSessionController?.isVisible ?? false,
+            "mode": quickSwitchWaterfallViewMode().rawValue
+        ])
+        hideQuickSwitchSession(reason: .userClosed)
+        NSApp.setActivationPolicy(.regular)
+
+        if settingsWindowController == nil {
+            settingsWindowController = SettingsWindowController(
+                modeProvider: { [weak self] in
+                    self?.quickSwitchWaterfallViewMode() ?? .verticalColumns
+                },
+                onWaterfallViewModeChanged: { [weak self] mode in
+                    self?.setQuickSwitchWaterfallViewMode(mode)
+                }
+            )
+        }
+
+        settingsWindowController?.showWindow(nil)
+        NSApp.activate(ignoringOtherApps: true)
+        writeQuickSwitchReportIfNeeded()
+        DevelopmentDiagnostics.log("app.settings.windowShown", [
+            "windowVisible": settingsWindowController?.window?.isVisible ?? false,
+            "activationPolicy": NSApp.activationPolicy().rawValue
+        ])
+    }
+
     @objc private func useVerticalWaterfallViewMode() {
         setQuickSwitchWaterfallViewMode(.verticalColumns)
     }

--
Gitblit v1.9.3