edit | blame | history | raw

Taglauncher WindowServer 会诊

用户目标

  • 作为代码审核员,基于管理员诊断说明会诊 TagLauncher 是否是 2026-07-01 大规模系统卡顿 / WindowServer watchdog 的重要原因之一。
  • 按用户要求拉两位架构师和两位代码审核员共同做只读审查。
  • 输出是否仍存在重大隐患,以及后续最小验证 / 缓解方向。

当前起点

  • 项目:/Users/ar/Projects/Taglauncher
  • 源码根目录:/Users/ar/Projects/Taglauncher/src
  • 诊断说明:/Users/ar/Documents/技术实验室/TagLauncher-WindowServer-CursorUIViewService-诊断说明-2026-07-01.md
  • 开工时分支:codex/pro-custom-hotkeys-8.2.0
  • 开工时 HEAD:4c6f31c Remove non-source materials from source worktree
  • 开工时工作区状态:已有大量未提交改动,按用户 / 其他任务既有改动处理,本轮不回滚、不改源码。
  • 最终核对时 HEAD 已由外部流程推进到 0ae3a93 Prepare TagLauncher 8.3.1 candidate,并带 tag v8.3.1-build20260701.2302;这不是本轮会诊创建的 commit。

核心事实 / 变更快照

  • 诊断中的故障包:TagLauncher 8.3.0 (20260701.2029)
  • 本机 /Applications/TagLauncher.app 当前读到:8.3.0 (20260701.2234)
  • 当前源码 src/Apptag/Info.plist 读到:8.3.1 (20260701.2302)
  • 最终核对时 src/Apptag/ContentView.swiftsrc/Apptag/ApptagApp.swiftsrc/Scripts/tag_editor_mouse_event_qa.sh 对当前 HEAD 已无 diff,说明相关修复已经进入 0ae3a93
  • 20260701.2029 是本地验收 DMG,不是正式冻结包;会话记录已明确其未冻结 commit / tag。
  • 20260701 晚些时候已有一轮“编辑标签卡死”修复记录:26.0701-Taglauncher.发布修复-编辑标签崩溃和额度刷新.md
  • 该修复已把 TextFieldContainer.mouseDownDismissibleHostingView.mouseDown 中“把同一 NSEvent 手动转发给 NSTextField.mouseDown / TextFieldContainer.mouseDown”改为 focus-only 路径,并新增 tag_editor_mouse_event_qa.sh 防回归。

已完成事项

  • 读取并遵守项目入口规则、CODE_GOVERNANCE.mdCODEGRAPH.md、全局 code / debugging / QA / delivery / session memory 规则。
  • 读取管理员诊断说明并提取核心链路:TagLauncher CPU resource / hang -> CursorUIViewService on-behalf-of TagLauncher -> WindowServer CPU resource/watchdog。
  • 派出 4 个只读子代理:
  • 架构师 A:窗口 / 事件系统。
  • 架构师 B:文本输入 / 焦点 / IME。
  • 审核员 C:事件转发 / mouseDown / monitor。
  • 审核员 D:窗口 / 渲染 / 资源风险。
  • 主线程复核关键源码:ApptagApp.swiftOverlayWindowController.swiftQuickSearch.swiftContentView.swiftAppGridCollectionView.swiftTagNavigationView.swiftAppGridSupport.swiftPreferencesView.swiftAppDragCoordinator.swift

关键结论

  1. 20260701.2029 故障包很可能命中过“同一鼠标事件被手动转发到 NSTextField.mouseDown”的问题。
  • 证据:当前 diff 显示旧代码曾调用 container.mouseDown(with: event) / tf.mouseDown(with: event) / textField.mouseDown(with: event),而当前工作区已修成 focusTextField() / makeFirstResponder + selectText
  • 诊断栈中的 NSControl/NSView mouseDownforwardMethodNSTextInputContextIMKInputSession 与这个问题高度吻合。
  • 这部分在 20260701.2234 后已有静态 QA 防回归。
  1. 不能把所有 WindowServer 问题完全定责给 TagLauncher。
  • 系统是 macOS 27 beta / build 26A5368g,TextInputUI、SCIM、WindowServer 自身也可能有系统侧放大。
  • 但诊断里的 On Behalf Of 链路足以把 TagLauncher 列为重点触发入口 / 放大因素。
  1. 当前代码仍存在需要立即处理或强验证的重大隐患,尤其是 Quick Search + 中文输入法 / IME 候选窗路径。
  • 当前 QuickSearchNativeTextField 和 delegate command path 没有 marked-text guard。
  • Quick Search 打开期间 global mouse monitor 可能把 IME 候选窗点击当作外部点击并关闭文本客户端。
  • Quick Search 每次更新可能重复 NSApp.activate / makeKeyAndOrderFront / orderFrontRegardless,并排 4 次 delayed focus。
  1. 仍存在多个窗口/事件架构风险。
  • TagNavigationView.mouseDown 里有阻塞式 while + window?.nextEvent(... inMode: .eventTracking),缺失窗口失活 / mouseUp 丢失 / monitor 吞事件时的硬退出条件。
  • AppGridCollectionHostView / Usage Tips 的 hitTest 会触发状态变更、first responder、hover 刷新,hitTest 不再是纯命中测试。
  • Usage Tips local mouse monitor 对非 overlay 窗口事件用 NSEvent.mouseLocation 映射,可能吞掉同 App 其它窗口事件。
  • overlay 是 .nonactivatingPanel 但允许 key/main,同时 AppDelegate 多处切 activation policy、activate、orderFront。
  1. 当前发布判断:20260701.223420260701.2029 明显更安全,但在 macOS 27 + 简体中文输入法环境下仍不应视为彻底安全。建议进入阻塞修复 / 诊断增强,而不是直接发布。

主要隐患清单

  • P0:Quick Search 抢 IME 候选键。
  • 路径:src/Apptag/QuickSearch.swiftdoCommandByQuickSearchNativeTextField.keyDown
  • 问题:Up / Down / Return / Escape 在 marked text 状态下应优先交给 IME。
  • P0:IME 候选窗鼠标点击可能被 Quick Search global mouse monitor 当作外部点击关闭。

  • 路径:src/Apptag/ApptagApp.swiftinstallQuickSearchExternalMouseMonitorsrc/Apptag/ContentView.swiftcloseQuickSearch
  • 问题:候选窗属于 TextInputUI/CursorUIViewService,点击候选时撤掉文本客户端很危险。
  • P1:Quick Search 输入期间重复抢焦点 / 重排窗口。

  • 路径:QuickSearchPanelPresentationView.updateNSViewCoordinator.applyQuickSearchTextField.requestFocuspromoteOverlayToForegroundInput
  • 问题:每次 query/result update 都可能触发窗口置前、first responder 切换、输入上下文 activate。
  • P1:DismissibleHostingView.mouseDown 仍在顶层同步切文本 first responder。

  • 路径:src/Apptag/ApptagApp.swift
  • 问题:虽已停止同事件转发,但已编辑 / marked text 状态下外层截获仍可能破坏原生光标、候选坐标和 input context。
  • P1:TagNavigationView.mouseDown 阻塞式事件循环。

  • 路径:src/Apptag/TagNavigationView.swift
  • 问题:mouseUp 丢失、窗口隐藏、App resign active 或事件被 monitor 吞掉时,主线程可能困在 mouseDown 栈。
  • P1:Usage Tips 的 hitTest / local monitor 有副作用和误吞风险。

  • 路径:src/Apptag/AppGridCollectionView.swift
  • 问题:hitTest 触发 hover/first responder/刷新;非本窗口事件按屏幕坐标映射后可能被吞。
  • P1:App note 泡泡使用 SwiftUI TextField + 非激活 overlay + 主动提升焦点。

  • 路径:src/Apptag/AppGridSupport.swiftsrc/Apptag/ContentView.swiftsrc/Apptag/ApptagApp.swift
  • 问题:中文 composition 期间 binding 截断、焦点提升和透明全屏 panel 组合风险高。
  • P2:Quick Search 点击启动缺少 de-dupe guard。

  • 路径:src/Apptag/QuickSearch.swiftsrc/Apptag/ContentView.swift
  • 问题:双击 / 抖动点击可能在 panel 关闭前多次 launch。
  • P2:拖拽碎纸预览使用无限 CA 动画,依赖正常结束路径清理。

  • 路径:src/Apptag/AppDragCoordinator.swift
  • 问题:窗口隐藏、App 失活或事件取消时需证明动画和 layer 一定清理。

QA / 验证结论

本轮只做只读 / 静态检查,不做源码修改,不构建。

已执行并通过:

cd /Users/ar/Projects/Taglauncher/src
bash Scripts/tag_editor_mouse_event_qa.sh
bash Scripts/quick_search_launch_contract_qa.sh

结果:

PASS Tag editor mouse event QA: text-field clicks focus without recursive mouseDown forwarding
PASS quick search launch contract

已执行:

cd /Users/ar/Projects/Taglauncher
git diff --check -- src/Apptag/ContentView.swift src/Apptag/ApptagApp.swift src/Apptag/QuickSearch.swift src/Apptag/OverlayWindowController.swift src/Apptag/AppGridCollectionView.swift src/Scripts/tag_editor_mouse_event_qa.sh

结果:无输出,表示相关 diff 无 whitespace 错误。

不作为有效证据:

cd /Users/ar/Projects/Taglauncher/src
bash Scripts/window_logic_qa.sh

该脚本会操作 Dock、defaults、LaunchAgent 和 GUI,不适合本轮只读会诊;已中断,退出码 130。脚本含 trap cleanup EXIT,后续检查 TagLauncher 仍在运行、TAGLAUNCHER_QA_PRO_STATE 为空。

可复用命令 / Runbook

用途:复查 20260701 WindowServer / CursorUIViewService 会诊中的静态门禁和版本基线。

前置条件:

  • 项目路径:/Users/ar/Projects/Taglauncher
  • 源码目录:/Users/ar/Projects/Taglauncher/src
  • 本轮命令不替代真实 GUI/IME 复现;WindowServer/IME 问题必须在 macOS 27 + 简体中文输入法环境单独验证。

静态 QA:

cd /Users/ar/Projects/Taglauncher/src
bash Scripts/tag_editor_mouse_event_qa.sh
bash Scripts/quick_search_launch_contract_qa.sh

版本基线核对:

defaults read /Applications/TagLauncher.app/Contents/Info CFBundleShortVersionString
defaults read /Applications/TagLauncher.app/Contents/Info CFBundleVersion
plutil -p /Users/ar/Projects/Taglauncher/src/Apptag/Info.plist

源码风险定位:

cd /Users/ar/Projects/Taglauncher
rg -n "mouseDown|mouseDragged|mouseUp|sendEvent|hitTest|NSTextInputContext|inputContext|firstResponder|makeFirstResponder|addLocalMonitor|addGlobalMonitor|orderFrontRegardless|makeKeyAndOrderFront|NSVisualEffectView|reloadData" src/Apptag --glob '*.swift'

建议新增的真实复现步骤:

  1. macOS 27.0 / 简体中文输入法下打开 Quick Search。
  2. 输入拼音使候选窗可见。
  3. 分别按 Up / Down / Return / Escape,确认候选窗优先处理而不是 Quick Search 抢键。
  4. 用鼠标点击候选词,确认 Quick Search 不因 global mouse monitor 关闭。
  5. 连续输入 20 个中文字符,记录 makeFirstResponderorderFrontinputContext activate 次数和 WindowServer / CursorUIViewService CPU。
  6. 长按 TagNavigation 并在拖拽中切换 App / Esc / 隐藏 overlay,确认 mouseDown 事件循环有退出。

搜索关键词:WindowServerCursorUIViewService20260701.202920260701.2234Quick Search IMEmarkedTextmouseDown forwardMethodtag_editor_mouse_event_qaUsage Tips hitTestTagNavigation nextEvent

未决问题

  • 未直接读取原始 sysdiagnose .diag 文件;本轮基于管理员整理的诊断说明和项目源码审查。
  • 未做真实中文 IME GUI 复现;这是下一轮必须补的反馈环。
  • 开工时工作区脏状态很大;最终核对时大部分源码改动已进入 0ae3a93,仍有 6 个历史 Release 文档文件处于 modified 状态。后续修复前必须先明确是否基于 0ae3a93 / v8.3.1-build20260701.2302 继续。
  • window_logic_qa.sh 是 GUI/系统状态脚本,不适合只读会诊;后续若要跑,需按 QA 场景安排并确保用户知道会操作本机 GUI/Dock。

后续建议

  1. 先修 Quick Search marked text / IME 候选窗两项 P0,并补静态 + 真实中文输入法 QA。
  2. 给 Quick Search focus/orderFront、overlay activation、input context、mouseDown event number 增加临时 signpost/counter,建立可复现反馈环。
  3. DismissibleHostingView.mouseDown 对文本控件的外层截获收窄:已编辑或 marked text 时放行原生事件。
  4. TagNavigationView.mouseDown 改成非阻塞状态机,或至少加失活 / 超时 / mouseUp 丢失保护。
  5. 清理 Usage Tips hitTest 副作用和 local monitor 对非 overlay 事件的误吞风险。
  6. 在 P0/P1 处理并复现通过前,不建议把当前版本作为 macOS 27 + 中文输入法环境的安全发布候选。