wonfen:Clash Verge Rev 托盘菜单项编号溢出导致 Windows 托盘菜单点击全部失效
在 Clash Verge Rev「Windows 版右击系统托盘的“退出”命令无效」(issue #8159)讨论中,维护者 wonfen 表示已在 Windows 上复现并定位:托盘菜单底层的 muda 库在 Windows 上给每个菜单项分配只增不减的内部编号,但点击时只按低 16 位(最大 65535)匹配;CVR 每次刷新托盘菜单(切换模式、节点、订阅、进出轻量模式等)都会整体重建菜单,开启托盘代理组显示时一次重建会产生几百到几千个菜单项,累计超过约 6.4 万个后新菜单项编号超出范围,点击后找不到对应项、事件被直接丢弃——右键菜单仍能弹出但点了没有反应,日志也没有记录。「退出」在每次重建中创建得最晚,往往最先失效,之后其他托盘菜单项也会一起失效,只有重启应用才能恢复;设置页的「退出」不经过托盘菜单,所以一直正常。这与轻量模式、主窗口是否打开无关,也不限于 Windows 10:在 Windows 11 上用当前开发版通过托盘交替切换出站模式约 230 次后即可稳定复现,订阅节点越多、操作越频繁出现越早。临时规避:出现后重启 CVR;将设置中的「托盘代理组显示模式」改为「禁用」可大幅推迟问题出现。修复方案(回收已释放的菜单项编号,使其保持在有效范围内)已在本地验证,后续会提交到上游并跟进到 CVR。他同时回应了 #8164:判断「频繁重建后托盘点击全部失效」是对的,但成因不是跨线程创建菜单(Tauri 本身已在主线程创建和销毁菜单对象),跳过重复重建只能推迟、无法避免编号溢出,因此不会采用该方案。
作者原文@wonfen感谢反馈,这个问题已在 Windows 上复现并定位。
原因
托盘菜单底层的 muda 库在 Windows 上给每个菜单项分配一个只增不减的内部编号,但点击时只按低 16 位(最大 65535)去匹配菜单项。CVR 每次刷新托盘菜单(切换模式、节点、订阅,进出轻量模式等)都会整体重建菜单;开启托盘代理组显示时,一次重建会产生几百到几千个菜单项。应用持续运行、累计创建的菜单项超过约 6.4 万个后,新菜单项的编号超出范围,点击后找不到对应项,事件被直接丢弃:右键菜单能正常弹出,但点了没有任何反应,日志里也没有记录。「退出」在每次重建中创建得最晚,往往最先失效,之后其他托盘菜单项也会一起失效,只有重启应用才能恢复。设置页的「退出」不经过托盘菜单,所以一直正常。这与轻量模式、主窗口是否打开无关,也不限于 Windows 10:在 Windows 11 上用当前开发版,通过托盘交替切换出站模式约 230 次(每次重建 117~440 个菜单项)后即可稳定复现。订阅节点越多、操作越频繁,出现得越早,所以刚启动时不容易复现。
临时规避
- 出现后重启 CVR 即可恢复;
- 将设置中的「托盘代理组显示模式」改为「禁用」,可以大幅推迟问题出现。
修复
修复方案(回收已释放的菜单项编号,使其保持在有效范围内)已在本地验证:累计创建超过 6.4 万个菜单项后,托盘「退出」和其他菜单项仍然正常。后续会提交到上游并跟进到 CVR。@DCxDESIGN 方便的话请确认一下:出现问题时,托盘菜单里的其他项(如「打开窗口」、切换出站模式)是否也同时没有反应?
关于 #8164:感谢 @dai123x 的分析,「频繁重建后托盘点击全部失效」的判断是对的,但成因不是跨线程创建菜单(Tauri 本身已在主线程创建和销毁菜单对象),跳过重复重建也只能推迟、无法避免编号溢出,所以不会采用这个方案。