修:窗口失去前台后不再每 500 毫秒整窗重绘(光标闪烁) 用户问「打开之后总是定期占用 2-3% CPU,有什么自动执行的代码么」。查下来 **没有失控的自动任务**:全仓只有一处常驻周期代码(scheduler 每 30 秒一条 due_tasks 查询,微秒级)与两处 5 分钟空闲卸载(记忆 / OCR 工作线程)。 真正在烧的是光标闪烁。gpui-base 的 BlinkCursor 每 500 毫秒翻转一次并 cx.notify(),而 GPUI 的 Window::mark_view_dirty 会把这条视图链的**所有 祖先**都标脏(gpui-pre-0.3.4/src/window.rs:2102),引擎又不复用未变子树的 预排结果,于是每一次翻转都是一次整窗重绘。上游那句注释写的是 「Blink the cursor when the window is active, pause when it's not.」,但只 实现了前半句:激活观察里没有 else 分支,on_focus 也无条件启动闪烁。而光标 只在窗口是前台时才画(InputState::show_cursor 里的 is_window_active()), 所以后台里这些重绘一张有效的像素都画不出来。 实测(隔离库 + 改名副本 + 帧探针 + typeperf,窗口全程不是前台): 无输入框有焦点 0 帧/秒;聊天输入框有焦点 2 帧/秒、2.44% 单核(主线程 2.30%); 空会话 1.22%;审计页 + 侧栏搜索框 4 帧/秒、2.24%。每次重绘 4.4–11.5 ms (空会话 4.4 / 38 条消息 11.5 / 审计页 9.8)——这就是「后台挂着不动却一直 占 2-3%」的来源。 改法(本地副本 vendor/gpui-base,第二处补丁;注释随上游用英文): 1. blink_cursor::suspend():把 epoch 推进一格(在途定时器回来时自己放弃)、 清掉 paused、保持光标可见,**不通知、不排下一次**; 2. 窗口激活观察补上「失去激活」分支(调 suspend()); 3. on_focus 只在窗口是前台时才启动闪烁(后台里收到焦点不再点火)。 验证:按同一条生产路径驱动(投递 WM_ACTIVATE(WA_INACTIVE),与用户切走窗口 时 Windows 发的是同一条消息——gpui 收到后更新 window.active 并回调激活 观察者):主线程 2.29% → 0.20%(进程 2.85% → 0.40%),投回 WA_ACTIVE 后 2.80%(光标照常闪,行为不变)。门禁:vendor_patch.rs 新增第二条检查 (the_vendored_blink_patch_is_still_applied)+ 副本自带用例 a_suspended_cursor_stops_toggling(挂起后不许再翻转;去掉补丁必红)。 文档:VENDORED.md 补「补丁二」的理由、实测表、门禁与退出条件; REQUIREMENTS.md §2.11 一行;docs/09 新增 E5/E6,把剩下的每帧成本 (状态栏每帧 3 次 fs::metadata、对话流按全部块建元素)与界面线程上 std:🧵:sleep 轮询的四处记下来。 门禁:cargo test --workspace、clippy --all-targets -D warnings、convention、 docs、vendor_patch 全绿。 |