Skip to content

fix(capsule): 入场帧强制重注册 Space 贴附——胶囊不再被 macOS 26 钉死在单个桌面 - #875

Merged
appergb merged 1 commit into
Open-Less:betafrom
bigsongeth:fix/capsule-space-reassert
Aug 2, 2026
Merged

fix(capsule): 入场帧强制重注册 Space 贴附——胶囊不再被 macOS 26 钉死在单个桌面#875
appergb merged 1 commit into
Open-Less:betafrom
bigsongeth:fix/capsule-space-reassert

Conversation

@bigsongeth

@bigsongeth bigsongeth commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

User description

症状

用户报告「微信里不弹录音胶囊、Claude 里又有」。实测按**桌面(Space)**分而不按 App 分:胶囊被钉死在某一个桌面,用户在其它桌面听写时,麦克风开着却没有任何 UI 指示(最长观测到 78 秒无提示录音)。

取证(2026-07-31,macOS 26 / Darwin 25.5)

  • 坏状态下,会话期间后端以 ~30Hz 调 orderFrontRegardless,CGWindowList 显示窗口位置/level 全对,但 onscreen=0 贯穿全程;
  • CGSCopySpacesForWindows:坏状态胶囊 spaces=[3](应为 [3,5]);重启 App 恢复;
  • 体外复现:用 CGSRemoveWindowsFromSpaces 对同款设置的测试窗口人工制造相同坏状态(值仍 273、注册残缺),然后跑遍救法:
救法 结果
重写同值 273 + orderFront(现行为,30Hz 在干的事) ❌ 无效
纯 hide + show ❌ 无效
隐藏时翻转 0→273 再显示 ❌ 无效
同一 tick 连写 0、273 ❌ 无效(被合并)
可见状态下 CanJoinAllSpaces 位 0→1 转变 ✅ 完整恢复
跨显示器移动 ✅ 恢复(与野外「外接屏意外自愈」观察一致)

结论:macOS 26 上贴附注册只在「窗口可见时 CanJoinAllSpaces 位发生真实转变」时刷新;AppKit 同值写入是 no-op——这就是坏状态一旦出现便不可恢复(除重启)的机制。剥离的野生触发点未定位(拔/插显示器、新建桌面均实测良性),但修复不依赖触发点。

修法

  • 入场帧(隐藏→可见)先以 272(去 CanJoinAllSpaces 位,保留 Stationary|FullScreenAuxiliary)上屏,30ms 后下一个主线程 tick 写回 273,强制重注册;
  • 30Hz level 帧不参与(避免 WindowServer 反复重排);
  • 写前读当前值,漂移打 warn 留证据;
  • glow 窗口同款写法一并加固。

验证

  • 修复配方在体外实验中对人工制造的坏状态 100% 恢复(含紧凑 async 时序版本);
  • cargo check 通过(仅存量 warning);
  • 跨进程无法对真胶囊人工制造坏状态(系统限制),端到端复发场景待野外验证——修复为幂等低风险操作,正常状态下执行无副作用;复发时日志的 drift warn 可直接指认。

🤖 Generated with Claude Code


PR Type

Bug fix


Description

  • Fix macOS 26 Space pinning of capsule window

  • Reassert Spaces registration on entry frame

  • Flip CanJoinAllSpaces only while window visible

  • Mirror fix in glow window and log drift


Diagram Walkthrough

flowchart LR
  Entry["Capsule enter visible"] --> Low["setCollectionBehavior 272"]
  Low --> Show["orderFrontRegardless"]
  Show --> Wait["30ms later"]
  Wait --> Full["setCollectionBehavior 273"]
  Full --> Register["WindowServer re-registers Spaces attachment"]
Loading

File Walkthrough

Relevant files
Bug fix
coordinator.rs
Plumb reassert-spaces flag through capsule show path         

openless-all/app/src-tauri/src/coordinator.rs

  • Adds reassert_spaces parameter to show_capsule_window_for_recording
  • Passes the flag through to the macOS no-activate show path
  • Enables reassertion only when entering a visible capsule frame
+2/-1     
capsule_focus.rs
Reassert macOS Spaces attachment via visible bit flip       

openless-all/app/src-tauri/src/coordinator/capsule_focus.rs

  • Defines constants for CanJoinAllSpaces, Stationary, and
    FullScreenAuxiliary
  • On reassert, sets 272 (without CanJoinAllSpaces) before
    orderFrontRegardless
  • Writes 273 back after 30ms to trigger WindowServer re-registration
  • Logs collectionBehavior drift and updates non-macOS signatures
+59/-7   
lib.rs
Apply Spaces reassert sequence to glow window                       

openless-all/app/src-tauri/src/lib.rs

  • Applies the same 272-then-273 reassert sequence to the glow window
  • Sets 272 before orderFrontRegardless, then schedules the 273 write
  • Clones the app handle for async main-thread reassert callback
+24/-2   

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit bd63cbe)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

实测(2026-07-31):macOS 26 会在运行中把胶囊窗口从「全 Space 贴附」剥离,
之后它表现为普通受管窗口:只在某一个桌面可见,其它桌面上听写全程无任何
UI 指示(后端 30Hz orderFrontRegardless 全部无效,窗口 onscreen=0,最长观测
到 78 秒无提示录音)。用户侧症状即「微信里不弹胶囊、Claude 里又有」——
实际按桌面分,不按 App 分。

CGS 取证 + 体外复现(CGSRemoveWindowsFromSpaces 人工制造同款坏状态)跑遍
四种救法,结论:
  · 重写同值 273:无效(AppKit 同值写入是 no-op,这正是坏状态救不回的原因)
  · 隐藏时翻转 0→273 再显示:无效(隐藏期间的值变化不触发重注册)
  · 同一 tick 连写 0、273:无效(被合并)
  · 窗口可见时发生 CanJoinAllSpaces 位 0→1 的转变:有效,完整恢复贴附
  · 跨显示器移动:有效(与野外观察到的「外接屏上意外自愈」一致)

修法:入场帧(隐藏→可见)先以 272(保留 Stationary|FullScreenAuxiliary,仅去
CanJoinAllSpaces 位)上屏,30ms 后的下一个主线程 tick 写回 273——可见状态下
的位翻转强制 WindowServer 重新注册贴附。30Hz level 帧不参与。写前读当前值,
发现漂移打 warn 留证据。glow 窗口同款写法一并加固。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit bd63cbe

@bigsongeth bigsongeth closed this Jul 31, 2026
@bigsongeth
bigsongeth deleted the fix/capsule-space-reassert branch July 31, 2026 15:53
@bigsongeth
bigsongeth restored the fix/capsule-space-reassert branch July 31, 2026 15:54
@bigsongeth bigsongeth reopened this Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit bd63cbe

@appergb appergb left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已审查 macOS Space 重注册逻辑:延迟恢复仅在隐藏→显示入场帧及 Less Computer glow 展示时触发,不会随音量帧重复创建线程;回调重新在主线程获取窗口并恢复既定 behavior。四平台 CI 通过,并已在最新 beta 上与 #874/#876 联合验证:819 个 Rust 测试、26 个前端/契约测试及生产构建通过。

@appergb
appergb merged commit f0ffa8a into Open-Less:beta Aug 2, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants