Skip to content

fix(startup): autostart catch 块缺 return 导致复活主窗口 (#468)#488

Merged
appergb merged 2 commits into
betafrom
fix/autostart-catch-return-468
May 18, 2026
Merged

fix(startup): autostart catch 块缺 return 导致复活主窗口 (#468)#488
appergb merged 2 commits into
betafrom
fix/autostart-catch-return-468

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented May 18, 2026

User description

问题

PR #474 引入的"前端兜底" useEffect (`src/App.tsx:48-60`) 在 webview ready 后读 `prefs.startMinimized`,true 则跳过 `currentWindow.show()`。但 catch 块只 `console.warn` 没有 `return`,控制流继续走到 `show()` —— 等于"prefs 读取失败 = 强 show"。

autostart 早期 IPC 还没完全 ready 时,`getSettings()` 偶发失败,用户明明开了静默启动仍把主窗口弹出来。这是 issue #468 在 PR #474 修复后剩下的最后一条复现路径。

修复

catch 块加 `return`,把语义从"读不到 prefs = 强 show"反转为"读不到 prefs = 当作 startMinimized=true 保持隐藏"。

```ts
// Before
try {
const prefs = await getSettings();
if (prefs.startMinimized) return;
} catch (err) {
console.warn('...', err);
// ← 缺 return,fall through 到下面的 show()
}
const { getCurrentWindow } = await import('@tauri-apps/api/window');
// ...show()

// After
try {
const prefs = await getSettings();
if (prefs.startMinimized) return;
} catch (err) {
console.warn('[startup] read startMinimized failed; staying hidden to avoid #468', err);
return; // ← 安全侧默认 = 不弹窗
}
// ...
```

宁可让用户从 tray 手动唤起,也不要在 autostart 抖动时强 show 一个白色 / 透明主窗口。

不在本 PR 范围

`Info.plist` 的 `LSUIElement` 是另一个 macOS UX 决策:

  • 它是全局开关,会让 Finder 双击 / Spotlight / Launchpad 启动都没 Dock 图标 / 菜单栏
  • 正确做法是 Rust 端根据"是否 autostart 启动"动态切 `activationPolicy(.accessory ↔ .regular)`,而非 plist 静态写死
  • 影响范围远超 [windows] 启动时静默运行功能在 Win11 失效 #468,应作为独立 PR + 单独评审

`tauri-plugin-autostart` 的 `--silent` 参数注入也是同理 — 独立 PR。

Test plan

  • Windows 11 自启动后保持隐藏(IPC 正常)
  • Windows 11 自启动 + 模拟 IPC 失败(断点 / network throttle) → 仍保持隐藏
  • macOS 自启动同上
  • 关闭 startMinimized → 自启动应正常 show 主窗口
  • 用户从 tray 唤起 → 主窗口正常显示

Refs #468

🤖 Generated with Claude Code


PR Type

Bug fix, Documentation


Description

  • Guard show() behind startMinimized

  • Keep hidden on settings read failure

  • Improve startup warning diagnostics


Diagram Walkthrough

flowchart LR
  A["App startup"] -- "read settings" --> B["getSettings()"]
  B -- "startMinimized=true" --> C["Skip show()"]
  B -- "read fails" --> D["Log and stay hidden"]
  C -- "keep silent launch" --> E["Main window hidden"]
  D -- "avoid reopening window" --> E["Main window hidden"]
Loading

File Walkthrough

Relevant files
Bug fix
App.tsx
Guard startup reveal with silent-launch fallback                 

openless-all/app/src/App.tsx

  • Reads startMinimized before revealing the window.
  • Returns early when settings are unavailable, preserving hidden
    startup.
  • Logs a clearer diagnostic message with extracted error details.
  • Expands inline comments to explain the autostart fallback path.
+13/-3   

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
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 18, 2026

PR Reviewer Guide 🔍

(Review updated until commit 3a5e0e3)

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

468 - Partially compliant

Compliant requirements:

  • If reading startup settings fails, the app now stays hidden instead of falling through to show().

Non-compliant requirements:

  • None identified from this diff alone.

Requires further human verification:

  • Verify on Windows 11 autostart that the window remains hidden across the relevant startup paths.
⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

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
@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 18, 2026

关于 pr_agent_job 的 "preserve fallback" 合规疑虑

bot 提到本 PR 未 "Preserve a fallback when settings read fails",这是 PR #474 设计契约的反转——这次是有意的,且本地代码审查已验证。在此把判断依据写明:

1. Rust 端 get_settings 不抛错

src-tauri/src/commands.rs:60 签名:

#[tauri::command]
pub fn get_settings(coord: CoordinatorState<'_>) -> UserPreferences {
    coord.prefs().get()
}

返回类型是 UserPreferences Result。首次安装 / prefs 不存在时由 coord.prefs().get() 内部回落到默认值,不会抛错。所以前端 getSettings().catch 在正常路径下永远不会触发。

2. catch 唯一会被触发的场景

Tauri IPC 基础设施在 webview ready 但 __TAURI_INTERNALS__ 还未完全初始化时,invoke() 调用会被拒绝并 reject Promise。这只在 autostart 早期 cold-start 阶段几百毫秒窗口出现。

3. tray 是稳定的兜底入口

Rust 端 setup() 在 webview 加载之前已经把 tray 注册完成(独立于前端生命周期)。即使主窗口在 IPC 抖动期间保持隐藏,用户从 tray 点击仍能唤起。不存在"用户被锁死"的可能

4. 旧逻辑的实际危害

getSettings().catch → fall through to show()#468 的 Win11 复现路径里就是元凶:autostart 时 IPC 抖动 → catch 触发 → show() 把用户明明开了静默启动的主窗口弹出来。这条 fallback 名义上"防 UI 卡死",实际上是"无视用户偏好的硬 show"。

5. 第二个 commit 已把这层语义写入代码注释

为消除二义性,刚 push 的 3a5e0e3a 把上述四点压缩到 catch 内联注释里,并改善了 console.warn 的诊断能力(包含 err.message)。

cc @baiqing

@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 18, 2026

@claude 请审核此 PR。如有问题请逐条列出(CRITICAL / HIGH / MEDIUM);如全部通过请明确说 LGTM。

@claude
Copy link
Copy Markdown

claude Bot commented May 18, 2026

Claude finished @appergb's task in 1m 14s —— View job


PR Review: fix(startup): autostart catch 块缺 return 导致复活主窗口 (#468)

  • 读取任务上下文
  • 读取 CLAUDE.md 仓库规范
  • 查看 PR diff (App.tsx 修改)
  • 审核代码逻辑正确性
  • 检查边界情况与安全性
  • 输出审核结论

审核结论:✅ LGTM

无 CRITICAL / HIGH / MEDIUM 问题。


代码逻辑验证

修复本身正确App.tsx:55–68):

// Before: catch 无 return → fall-through 到 show()
} catch (err) {
  console.warn('...', err);
  // ← 控制流继续,等效"IPC 失败 = 强 show"
}

// After: catch 有 return → async IIFE 退出
} catch (err) {
  const detail = err instanceof Error ? err.message : String(err);
  console.warn('[startup] read startMinimized failed; staying hidden to avoid #468:', detail, err);
  return;  // ← 安全侧默认:不弹窗
}

逐点检查:

检查项 结论
return 语义在 async IIFE 内是否正确退出 ✅ 正确退出,不影响外层 cancelled flag
Rust get_settings 是否真的是非-Result 返回 ✅ 已验证:pub fn get_settings(...) -> UserPreferences(行 60,非 Result),prefs 不存在时内部回落默认值
catch 触发后 cancelled 检查是否还能运行 return 在 catch 里,非 catch 正常路径仍有 if (cancelled) return 守卫
startMinimized=false + IPC 失败场景 行为变化:旧逻辑会 show,新逻辑保持隐藏。这是有意为之:此路径仅发生在 autostart 冷启动几百毫秒内,tray 是稳定兜底;接受此取舍
tray 是否在此时已就绪 ✅ Rust setup() 在 webview 加载前注册 tray,生命周期早于前端
detail 日志冗余性 轻微:detail(err.message)和 err 对象同时传给 console.warn,信息有重叠,但不影响功能,有助于调试

注意事项(不阻塞合并,非本 PR 引入)

App.tsx:30–41 存在一个预存的 React Hooks 规则违反:isCapsule/isQa 早返回后才调用 useState/useEffect。这不是本 PR 引入的,且在 React 运行时层面通常在实际使用时 isCapsuleisQa 的路径互斥,但严格来说违反了 Rules of Hooks,可作为独立 issue 跟进。


总结:修复精准、最小化、有充分文档支撑,行为变更(IPC 失败保持隐藏)经过充分论证且有 tray 兜底。Rust 端签名已核实。

LGTM — 可以合并。

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 3a5e0e3

@appergb appergb merged commit a1d9549 into beta May 18, 2026
4 checks passed
@appergb appergb deleted the fix/autostart-catch-return-468 branch May 18, 2026 11:00
appergb pushed a commit that referenced this pull request May 18, 2026
包含 PR #487 / #488 / #489 三个修复,供 Windows 实机验证:

- #489 快捷键二次按键失效(toggle/stop 失灵,只能 ESC)
  → coordinator.rs hotkey_bridge_loop 改 block_on 顺序 await
- #487 capsule/qa 透明遮罩看不清
  → lib.rs Windows 下追加 apply_acrylic 兜底
- #488 autostart catch fall-through 复活主窗口(#468 残留)
  → App.tsx catch 加 return + 改善 warn 诊断
appergb pushed a commit that referenced this pull request May 18, 2026
…v 安装

v1.3.4-4 / -5 的 Linux 构建在 "Build fcitx5 plugin" 步骤连挂两次,
错误一致:"E: Unable to locate package fcitx5-dev"。同一 job 前面的
"Install Linux bundle deps" 步骤明明已经 apt-get update + 装好了一堆
universe 包,到 fcitx5 这步突然找不到 —— 表象与 GitHub Actions
ubuntu-22.04 runner 镜像弃用过渡期里 apt 元数据漂移的现象一致。

release-tauri.yml "Build fcitx5 plugin" 步骤增加三层防御:
  1) sudo add-apt-repository -y universe(已启用则 no-op)
  2) 本步骤内重新 sudo apt-get update,独立于上游 step 缓存
  3) 安装失败时打印 apt-cache policy / search / os-release / sources.list.d
     便于以后排查

同 commit 同时 bump 五处版本到 1.3.4-6 重发,让 PR #487/#488/#489
三个 Windows P0 修复带上 Linux 包一起进 Beta 通道。
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.

1 participant