From ab6266f745bfff989ff4c20040e9695d5dea6479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=98=BF=E7=8F=8F?= <32321958+iAJue@users.noreply.github.com> Date: Sat, 6 Jun 2026 22:27:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DWindows=E9=80=80?= =?UTF-8?q?=E5=87=BA=E6=89=98=E7=9B=98=E5=9B=BE=E6=A0=87=E6=AE=8B=E7=95=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#3797)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e1901a532..c96b752e5 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1460,6 +1460,11 @@ pub fn run() { tauri::async_runtime::spawn(async move { save_window_state_before_exit(&app_handle); cleanup_before_exit(&app_handle).await; + // 先于 std::process::exit 显式移除托盘图标。 + // 进程直接退出时 Tauri 运行时不走正常 Drop 流程, + // 不会向 Windows Shell 发送 NIM_DELETE,导致已退出的进程 + // 注册的图标仍残留在系统托盘(鼠标悬停 Shell 才会重绘发现进程已死)。 + remove_tray_icon_before_exit(&app_handle); log::info!("清理完成,退出应用"); // 短暂等待确保所有 I/O 操作(如数据库写入)刷新到磁盘 @@ -1607,6 +1612,26 @@ pub async fn cleanup_before_exit(app_handle: &tauri::AppHandle) { } } +/// 主动从系统托盘移除托盘图标。 +/// +/// `std::process::exit` 会绕过 Tauri 运行时,触发不了 `TrayIcon::drop()`, +/// 也就不会向 Windows Shell 发 `NIM_DELETE`。结果是进程退出后托盘里 +/// 仍保留一个死图标的缓存占位(Shell 不会主动重绘,需要鼠标悬停才刷新)。 +/// +/// 通过 `set_visible(false)` 走 `WM_USER_HIDE_TRAYICON` 消息路径, +/// 触发 tray-icon 内部的 `remove_tray_icon` → `Shell_NotifyIconW(NIM_DELETE)`, +/// 在进程结束前干净地把图标摘掉。其它平台 `set_visible(false)` 也是 +/// 正常的隐藏/移除语义,作为跨平台兜底也安全。 +fn remove_tray_icon_before_exit(app_handle: &tauri::AppHandle) { + if let Some(tray) = app_handle.tray_by_id(tray::TRAY_ID) { + if let Err(e) = tray.set_visible(false) { + log::warn!("退出时移除托盘图标失败: {e}"); + } else { + log::info!("已显式从系统托盘移除图标"); + } + } +} + // ============================================================ // 启动时恢复代理状态 // ============================================================