Skip to content

fix(windows): 静默启动 #468 最后一公里 - 前端兜底#474

Merged
appergb merged 5 commits into
betafrom
fix/silent-startup-frontend-show
May 18, 2026
Merged

fix(windows): 静默启动 #468 最后一公里 - 前端兜底#474
appergb merged 5 commits into
betafrom
fix/silent-startup-frontend-show

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented May 18, 2026

User description

closes #468 — 详见 PR description (Rust 端 #471 修了 setup + single-instance 后,前端 App.tsx 仍无条件 IPC show 把窗口拉出来;现在 show 前读 startMinimized 兜底)


PR Type

Bug fix


Description

  • Respect startMinimized before showing

  • Preserve fallback when settings read fails

  • Stop frontend relaunch from reopening


Diagram Walkthrough

flowchart LR
  A["App startup"] -- "read settings" --> B["getSettings()"]
  B -- "startMinimized=true" --> C["Skip show()"]
  B -- "read fails" --> D["Fallback to show window"]
  C -- "preserve silent launch" --> E["Main window stays hidden"]
  D -- "keep existing behavior" --> E
Loading

File Walkthrough

Relevant files
Bug fix
App.tsx
Guard startup show by settings                                                     

openless-all/app/src/App.tsx

  • Imports getSettings for startup prefs
  • Checks startMinimized before window show
  • Skips relaunch window reveal when minimized
  • Keeps legacy show fallback on read errors
+21/-8   

appergb and others added 5 commits May 17, 2026 19:14
release-sync: beta → main (no tag, internal merge)
…诊断 (#471)

集中修复 4 个 Windows-only bug:

- #469 IME 切不回 — restore_profile 对称补 legacy TSF ChangeCurrentLanguage + ActivateLanguageProfile,回归点是 c3b5932 升级激活路径时漏改恢复路径。现代 ActivateProfile 失败降为 warn(legacy 已完成视觉切回)。
- #468 Win11 静默启动失效 — single-instance 回调读 start_minimized,true 时跳过 show_main_window;托盘 / CLI intent 路径不受影响。
- #466 QA 弹窗 X/ESC 关不掉 — Win 上从 SW_SHOWNOACTIVATE 切到 Tauri window.show + set_focus,让 webview 拿键盘焦点。配套 focus-dance:begin_qa_session 抓选区前临时把焦点还给用户原 app,抓完再 refocus QA;多轮场景下用 GetWindowThreadProcessId 区分本进程窗口,刷新 qa_focus_target,避免 stale HWND。
- #470 录音胶囊不显示 — 加 per-process 一次性诊断 log(CapsuleState 用 capsule_state_log_name 显式短名,不走 Debug 防字段扩展时泄露),下次能直接定位 prefs / state / Win32 哪一环失败。

pr_agent 五轮迭代到 No major issues + No security concerns;Cloud 评审建议的 begin_qa_session 双锁 TOCTOU 已合并为单 scope。三平台 build + pr_agent CI 全绿。

#470 没标 closes,是 refs—需要真机日志才能定位真因,先 ship 诊断手段。
权限页 (Settings → 快捷键 → 权限):
- Pill 组件加 whiteSpace:nowrap + flexShrink:0 → "已安装"徽章在 Win
  窄宽下不再被挤成 3 行(每个汉字一行)。
- 行内 message span 加 whiteSpace:nowrap + overflow:hidden +
  textOverflow:ellipsis + minWidth:0 → 长文本("Windows 低层键盘 hook
  已安装")超宽时省略号收尾,徽章保持完整。
- zh-CN 描述大段精简:descAcc / descNoAcc / micDesc / accDesc /
  hotkeyDesc / networkDesc / windowsImeDesc / windowsIme.* 都改短,
  减少 Win 上拥挤感(用户反馈 zh 文案过长)。

高级页 (Settings → 高级 → 本地 ASR):
- Windows 上把"本地 ASR 模型(实验性)"标题区 + 警告小字 + Qwen3 行
  整组 opacity:0.45 灰显 —— Qwen3 在 Win 是 stub 不支持,那条"实验性"
  主线在 Win 没意义;用户视觉关注点应落到下方独立的 Foundry 行(Foundry
  保持正常颜色)。Toggle 的 disabled 行为已经在原 onToggle 条件里,本次
  纯加视觉灰显。
#471 在 Rust 端 setup() / single-instance callback 都加了 start_minimized
suppression,本机日志确认 Rust 路径完全正确("[main] start_minimized=true
→ 跳过初始 show")。但用户在 Win11 1.3.4-3 上仍然「重启进桌面那一刻主
窗口就出来了」。

定位到最后一条遗漏路径在前端:App.tsx 里 mount 时一条 useEffect 无条件
通过 IPC 调 `getCurrentWindow().show()`,把 Rust 端已经 suppress 的窗口
又拉出来 —— 这条路径 Rust log 完全看不见(走的是 plugin-window 的
showWindow IPC,不经过我们的 show_main_window helper)。

那条 useEffect 当初是给 issue #163 引入的:Windows 权限探测可能死锁让
首屏卡灰,所以前端兜底 force show 一次。

修法:show 前先读 prefs.startMinimized,true 就 return。读 prefs 失败
(极少数情况)保持原 show 行为,不让 #163 的兜底语义丢失。

closes #468 (the actual one this time, Rust + JS 双端都收敛了)
@github-actions
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis ✅

468 - PR Code Verified

Compliant requirements:

  • 启动时在前端读取 startMinimized,为 true 时跳过 show()

Requires further human verification:

  • 需要在 Win11 真机上确认登录启动和手动二次启动都不会再弹出主窗口。
⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 18, 2026

@claude 请审查这个 PR。

简短说明:

  • fix(windows): 修复 #466 / #468 / #469 / #470 四个 Windows bug #471 在 Rust 端两条 show 路径都加了 start_minimized 抑制,用户日志确认 Rust 正确没问题
  • 但用户在 1.3.4-3 Win11 真机仍然「开机进桌面那一刻主窗口就出来」
  • 定位:App.tsx mount 时一条 useEffect 通过 IPC getCurrentWindow().show() 把窗口拉出来,绕过 Rust suppression,Rust log 完全看不到
  • 修法:show 前读 prefs.startMinimized,true 就 return
  • pr_agent 已一轮通过(No major issues / No security concerns),三平台 CI 全绿

主要关注点:

  1. App.tsx 改成异步 IIFE 之后 cancelled 标志处理是否正确(getSettings 之后再判 cancelled,再 dynamic import)
  2. getSettings 失败时走原 show 路径是否合理(保留 [windows] hotkey hook 永远 starting 时启动 gate 死锁,主窗口卡 "正在启动" 灰屏 #163 的「权限探测死锁→前端兜底拉首屏」语义)
  3. 跨平台:这条 useEffect 在 mac 上也跑,prefs.startMinimized 在 mac 上意味着什么、有没有副作用

辛苦。

@claude
Copy link
Copy Markdown

claude Bot commented May 18, 2026

Claude finished @appergb's task in 2m 48s —— View job


PR #474 代码审查

  • 读取变更文件和 git diff
  • 分析 cancelled 标志处理正确性
  • 分析 getSettings 失败回退路径合理性
  • 分析跨平台(macOS)副作用
  • 输出完整审查意见

总体结论

修复思路正确,针对 issue #468 的最后一公里路径(前端 IPC show 绕过 Rust 抑制)定位准确。三个关注点的详细分析如下。


关注点 1:cancelled 标志处理

结论:基本正确,有一个无害的检测空隙。

当前检测点:

requestAnimationFrame → [cancelled check] → getSettings() 
                                              ↓
                                        prefs.startMinimized=true → return ✓
                                        prefs.startMinimized=false → ⬇
                                        import('@tauri-apps/api/window')
                                              ↓
                                        [cancelled check] ← 第二次检测点
                                              ↓
                                        isVisible() → show()

问题所在:在 getSettings() resolve(startMinimized=false 路径)之后到 dynamic import 完成之前,没有 cancelled 检测。若组件恰好在这一时间窗口卸载,IIFE 会继续执行 dynamic import,再到 if (cancelled) return 才停下——也就是说 dynamic import 会被触发但 show() 不会执行。

为什么不是真正的 Bug

  1. @tauri-apps/api/window 是静态依赖,通常已被 bundler 加载,dynamic import 几乎同步完成;
  2. 即便有竞争,cancelledshow() 之前仍然会被正确检测;
  3. 该 useEffect 依赖 [gate, os],在应用生命周期内 os 永不变,gate 只从 checkingready/onboarding 单向转换,重新触发(从而产生竞争)的概率极低。

如果追求最严格的写法,可在 getSettings() 之后加一次检测:

const prefs = await getSettings();
if (cancelled) return;              // ← 可加
if (prefs.startMinimized) return;

不加也不影响正确性,看项目风格偏好。


关注点 2:getSettings 失败时走原 show 路径

结论:合理,保留了 #163 的兜底语义。

} catch (err) {
  console.warn('[startup] read startMinimized failed, falling back to show', err);
}
// 继续走 show 路径

失败时默认行为是"展示窗口"而非"静默",这是正确的 fail-safe 方向:

唯一值得商量的地方:失败时也许应读取 mockSettings 的默认值 startMinimized: false 而非直接 fallback,但效果等价,且当前写法更显式,更容易调试。


关注点 3:跨平台 —— macOS 副作用

结论:存在一个轻微的设计风险,实际影响极低,但建议后续修复。

当前问题:Settings UI 中 startMinimized toggle 没有平台限制Settings.tsx:600-604AutostartRow 也跨平台),Mac 用户可以将其打开。打开后,这条 useEffect 在 macOS 上同样会 return 而跳过 show()

macOS 的 Rust 端 setup() 不做 startMinimized 抑制(这是 Windows 专属修复),所以 macOS 在正常启动时窗口由 Rust 端 show() 打开。但若由于某种原因(边缘场景)窗口在 webview 加载时处于不可见状态,这个前端兜底 show 本是最后的保险——新代码在 startMinimized=true 时把这个保险也禁用了。

场景 旧行为 新行为
Mac + startMinimized=false(99.9% 用户) isVisible() 检测后 NOP 同左,多一次 IPC 读 prefs
Mac + startMinimized=true(极少数) 若窗口可见则 NOP,不可见则 show 直接跳过 show,窗口可能卡在不可见状态
Windows + startMinimized=true show() 被调用(Bug) 正确跳过 ✓

建议的改法:将 startMinimized 检测限定到 Windows,与现有平台分支保持一致:

if (os === 'win') {
  try {
    const prefs = await getSettings();
    if (prefs.startMinimized) return;
  } catch (err) {
    console.warn('[startup] read startMinimized failed, falling back to show', err);
  }
}

这消除了对 macOS 的任何影响,且逻辑更清晰:静默启动是 Windows autostart 特性,不适用于 macOS 的 gate 流程。

Fix this →


其他小观察

  1. 性能:现在所有平台的启动 show 路径都多了一次 get_settings IPC 调用。在正常情况下这是 <2ms,可忽略。但如果 get_settings 在特定环境下较慢(如首次启动磁盘 IO),会轻微延迟窗口显示。Windows + startMinimized=false 的用户也受影响,虽然实际观感上几乎察觉不到。

  2. 注释质量:注释写得很清楚,明确解释了为什么要做这件事(Rust log 看不到、[windows] 启动时静默运行功能在 Win11 失效 #468 最后路径、[windows] hotkey hook 永远 starting 时启动 gate 死锁,主窗口卡 "正在启动" 灰屏 #163 语义),这是好的。


是否可以合并

Windows startMinimized=true 的修复逻辑正确,CI 全绿,可以合并。

macOS 的 os === 'win' 守卫是锦上添花的防御性改进,不影响当前 99.9% 用户,可以在这个 PR 里顺手加上,也可以留到后续 cleanup。由你们决定。

@appergb appergb changed the base branch from main to beta May 18, 2026 07:29
@appergb appergb merged commit b4e806e into beta May 18, 2026
4 checks passed
appergb pushed a commit that referenced this pull request May 18, 2026
合并 PR #474 后随版本号一起出 Beta 包,供 Windows 端验证
startMinimized 兜底是否彻底关掉 #468 漏窗最后一公里。
appergb added a commit that referenced this pull request May 18, 2026
* fix(startup): autostart catch 块缺 return 导致复活主窗口 (#468)

PR #474 引入的"前端兜底"useEffect 在 webview ready 后读
prefs.startMinimized,true 则跳过 currentWindow.show()。但 catch 块只
console.warn 没有 return,控制流继续走到 show()——等于"prefs 读失败 = 强 show"。
autostart 早期 IPC 抖动时 getSettings() 偶发失败,旧逻辑让用户明明开了
静默启动仍把主窗口弹出来。

修复: catch 块加 return,安全侧默认 = 当作 startMinimized=true 保持隐藏。
宁可让用户从 tray 手动唤起,也不要在 autostart 抖动时强 show 一个白色
/ 透明主窗口。

LSUIElement 不在本 PR 范围: 那是全局 macOS UX 决策,会影响 Finder
双击 / Spotlight / Launchpad 启动场景,应单独 PR + 单独评审。
正确做法是 Rust 端动态切 activationPolicy 而非 plist 静态写死。

Refs #468

* docs(startup): clarify catch rationale + improve warn diagnostics

Both local review and PR-Agent bot flagged the "fallback when settings
read fails" semantic reversal. Re-analysis confirms the change is
correct, but the rationale needs to be explicit in the code:

- Rust `get_settings` signature is `pub fn -> UserPreferences` (not
  Result), so this catch is unreachable from a normal first-launch
  scenario (returns defaults). Only Tauri IPC infrastructure failures
  (e.g. __TAURI_INTERNALS__ not ready during autostart early-mount)
  reach this branch.
- Tray is registered by Rust setup() before webview ready, so it remains
  the universal fallback entry point — no "user locked out" risk.
- Improved console.warn to include err.message for diagnostics, since
  raw err objects serialize as [object Object] in Tauri devtools.

No behavior change; comment + log improvement only.

Refs review of #488

---------

Co-authored-by: baiqing <lbx12309@icloud.com>
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.

[windows] 启动时静默运行功能在 Win11 失效

1 participant