fix(client/windows): 任务栏图标 + 关闭窗口不再断连接

- 关闭窗口断连接:onExitRequested 原先无条件 _teardownVpn 再退出;Windows 点 X
  会触发该回调拆隧道,而 window_manager 的 preventClose 又把窗口仅隐藏到托盘
  → 出现「一关就断网、进程还在」。改为 Windows 下点 X/Alt+F4 取消退出+隐藏,
  保持隧道;真正退出只走托盘「退出」(onBeforeQuit 标记 _isQuitting 再拆隧道)。
  macOS Cmd+Q 仍正常拆隧道退出。
- 任务栏图标没换:仅靠 WNDCLASS.hIcon(LoadIcon 单尺寸)任务栏可能拿不到正确
  尺寸。窗口创建后用 LoadImage 按系统 SM_CXICON/SM_CXSMICON 各取一份,
  WM_SETICON 显式设 ICON_BIG(任务栏/Alt-Tab)+ ICON_SMALL(标题栏)。
- 版本 1.0.1 → 1.0.2。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-22 17:53:34 +08:00
parent 94993b21b4
commit 5ea4e1ae03
4 changed files with 37 additions and 4 deletions
+16 -2
View File
@@ -46,17 +46,31 @@ class PangolinApp extends ConsumerStatefulWidget {
class _PangolinAppState extends ConsumerState<PangolinApp> {
AppLifecycleListener? _lifecycle;
// 是否正在「真退出」(托盘「退出」菜单触发)。区分:点关闭只隐藏到托盘、保持隧道。
bool _isQuitting = false;
@override
void initState() {
super.initState();
if (isDesktop) {
// 真退出(Cmd+Q / 托盘退出)前先停内核拆隧道,避免 sing-box 孤儿 + TUN 残留。
// 关闭 / 退出请求的处理:
// - Windows:点 X / Alt+F4 会触发 onExitRequested,但桌面端要常驻托盘、隧道不断
// → 取消退出并隐藏到托盘。真正退出只走托盘「退出」菜单(见 onBeforeQuit)。
// (否则会出现:连接被拆、窗口却只是隐藏,即「关掉就断网但进程还在」。)
// - macOS:Cmd+Q 等真退出 → 先停内核拆隧道再退出(红叉关闭走 onWindowClose 隐藏)。
_lifecycle = AppLifecycleListener(onExitRequested: () async {
if (Platform.isWindows && !_isQuitting) {
await windowManager.hide();
return ui.AppExitResponse.cancel;
}
await _teardownVpn();
return ui.AppExitResponse.exit;
});
TrayService.instance.onBeforeQuit = _teardownVpn;
// 托盘「退出」前置钩子:标记真退出 + 停内核拆隧道(避免 sing-box 孤儿 + TUN 残留)。
TrayService.instance.onBeforeQuit = () async {
_isQuitting = true;
await _teardownVpn();
};
}
}