fix(coordinator): read show_capsule pref inside main-thread closure
Addresses pr_agent "Stale State" review on PR #389. show_capsule was read on the audio callback thread and snapshotted into the run_on_main_thread closure. If the user toggled the preference between the audio-thread emit and the main-thread closure firing (one or two frames later), the queued window show/hide could apply the old preference and briefly flash the wrong UI state. Move that read inside the closure so the latest user pref always wins. Why visible / translation stay snapshotted: they're the payload of THIS specific capsule:state event — the whole point is to tell the JS frontend "this is the state at the moment emit_capsule was called". Re-reading them inside the closure would mean the OS-level window state and the JS-side payload disagree (the closure lands one frame later than the emit_to that already shipped). No behavior change in the steady state; eliminates a 16–33 ms stale- pref window when the user changes show_capsule mid-dictation.
This commit is contained in:
1 parent
faf02ad47e
commit
84ee3d96d5
1 file changed
+8
-1
@@ -3666,19 +3666,26 @@ fn emit_capsule(
|
||||
translation,
|
||||
};
|
||||
|
||||
let show_capsule = inner.prefs.get().show_capsule;
|
||||
// visible / translation 是「这一帧 capsule:state event 的 payload」内容 ——
|
||||
// 必须在 call-site(即音频线程触发 emit_capsule 时)就算定,否则 main thread
|
||||
// 闭包里读到的将是「下一帧」的 state,跟实际下发给 JS 的 payload 不一致。
|
||||
let visible = !matches!(state, CapsuleState::Idle);
|
||||
|
||||
// emit_capsule 会被 cpal process_callback(音频回调线程)调用 ~30 Hz —— 在该
|
||||
// 线程上调用 NSWindow / HWND API 会撞 macOS dispatch_assert_queue_fail SIGTRAP
|
||||
// 或者 Win32 SendMessage 死锁。把 window.show/hide + 位置调整 marshal 到主线程;
|
||||
// app.emit_to 走 Tauri 内部事件总线,本身线程安全,保留同步调用。详见 audit 3.2.2。
|
||||
//
|
||||
// show_capsule(用户偏好)在主线程执行时再读 —— 用户可以在录音过程中改设置,
|
||||
// 闭包入队到真正跑之间窗口上限是一两帧(~16-33ms),用最新值消除 stale-pref
|
||||
// 闪烁。pr_agent 关注点 — 见 audit follow-up。
|
||||
let inner_for_main = Arc::clone(inner);
|
||||
let app_for_main = app.clone();
|
||||
let _ = app.run_on_main_thread(move || {
|
||||
let Some(window) = app_for_main.get_webview_window("capsule") else {
|
||||
return;
|
||||
};
|
||||
let show_capsule = inner_for_main.prefs.get().show_capsule;
|
||||
// 三平台统一:Done / Cancelled / Error 状态保留 ~1.5s toast
|
||||
// (schedule_capsule_idle 之后会回 Idle 隐藏)。
|
||||
// Windows 上 linger 的真实问题(截图选中 / 死区 / 拖拽卡顿)由 #140 加的
|
||||
|
||||
Reference in new issue
Block a user