Merge worktree-windows-icon-tray-fix: Windows 桌面/托盘/任务栏图标 + 关窗不断连接
- 关窗(X/Alt+F4)隐藏到托盘并保持隧道,真退出只走托盘菜单(Platform.isWindows 隔离) - 窗口标题设「穿山甲」(无 VPN 字眼) - Windows 托盘改用 .ico(Win32 只认 ico,PNG 空白),mac/Linux 仍 PNG - 更新 app_icon.ico / tray_icon.ico / Runner.rc / installer Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+18
-2
@@ -31,6 +31,8 @@ Future<void> main() async {
|
||||
await windowManager.setMinimumSize(const Size(720, 560));
|
||||
await windowManager.setSize(const Size(920, 640));
|
||||
await windowManager.center();
|
||||
// 窗口标题用中文品牌名(不带 "VPN" 字眼);英文环境下原生标题为 "Pangolin"。
|
||||
await windowManager.setTitle('穿山甲');
|
||||
}
|
||||
runApp(const ProviderScope(child: PangolinApp()));
|
||||
}
|
||||
@@ -44,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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,11 @@ class TrayService with TrayListener, WindowListener {
|
||||
windowManager.addListener(this);
|
||||
|
||||
trayManager.addListener(this);
|
||||
await trayManager.setIcon('assets/tray_icon.png');
|
||||
// Windows 托盘走 Win32 Shell_NotifyIcon,只认 .ico(传 PNG 会显示空白);
|
||||
// macOS/Linux 用 PNG。
|
||||
await trayManager.setIcon(
|
||||
Platform.isWindows ? 'assets/tray_icon.ico' : 'assets/tray_icon.png',
|
||||
);
|
||||
await trayManager.setToolTip('穿山甲 Pangolin');
|
||||
await trayManager.setContextMenu(Menu(items: [
|
||||
MenuItem(key: 'show', label: '显示主界面'),
|
||||
|
||||
Reference in New Issue
Block a user