From 34359885ab8749d93a842efbbfe3eb0a6ce0cfa5 Mon Sep 17 00:00:00 2001 From: JieXu Date: Tue, 9 Jun 2026 17:00:51 +0800 Subject: [PATCH] Update AppBuilderExtension.cs (#9514) * Update AppBuilderExtension.cs * Update MainWindow.axaml.cs * Update MacAppUtils.cs * Update App.axaml.cs * Add regions for MacOS activation and app events --------- Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --- v2rayN/v2rayN.Desktop/App.axaml.cs | 68 ++++++++++++++++--- .../Common/AppBuilderExtension.cs | 6 +- v2rayN/v2rayN.Desktop/Common/MacAppUtils.cs | 8 +++ .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 2 +- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/v2rayN/v2rayN.Desktop/App.axaml.cs b/v2rayN/v2rayN.Desktop/App.axaml.cs index bfa7e14a..92f9398c 100644 --- a/v2rayN/v2rayN.Desktop/App.axaml.cs +++ b/v2rayN/v2rayN.Desktop/App.axaml.cs @@ -23,8 +23,8 @@ public partial class App : Application DataContext = StatusBarViewModel.Instance; } - desktop.Exit += OnExit; - desktop.MainWindow = new MainWindow(); + var mainWindow = new MainWindow(); + desktop.MainWindow = mainWindow; if (OperatingSystem.IsMacOS()) { @@ -35,6 +35,8 @@ public partial class App : Application base.OnFrameworkInitializationCompleted(); } + #region MacOS Activation + private void OnMacOSActivated(object? sender, ActivatedEventArgs args) { if (args.Kind != ActivationKind.Reopen) @@ -42,17 +44,69 @@ public partial class App : Application return; } + if ((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow is not MainWindow mainWindow) + { + return; + } + + var isMiniaturized = MacAppUtils.IsWindowMiniaturized(mainWindow); + Dispatcher.UIThread.Post(() => { + if (isMiniaturized) + { + RestoreMacOSAccessoryPolicyAfterMiniaturize(mainWindow); + mainWindow.ShowHideWindow(true); + return; + } + if (!AppManager.Instance.Config.UiItem.MacOSShowInDock) { MacAppUtils.SetActivationPolicyAccessory(); } - - ((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow as MainWindow)?.ShowHideWindow(true); + + mainWindow.ShowHideWindow(true); }); } + private static void RestoreMacOSAccessoryPolicyAfterMiniaturize(MainWindow mainWindow) + { + if (AppManager.Instance.Config.UiItem.MacOSShowInDock) + { + return; + } + + mainWindow + .GetObservable(Window.WindowStateProperty) + .Skip(1) + .Where(state => state != WindowState.Minimized) + .Take(1) + .ObserveOn(RxSchedulers.MainThreadScheduler) + .Subscribe(_ => QueueMacOSAccessoryPolicyRestore(mainWindow)); + } + + private static void QueueMacOSAccessoryPolicyRestore(MainWindow mainWindow) + { + // AppKit may keep isMiniaturized set until the Dock restore animation finishes. + DispatcherTimer.RunOnce(() => RestoreMacOSAccessoryPolicy(mainWindow), TimeSpan.FromMilliseconds(300)); + } + + private static void RestoreMacOSAccessoryPolicy(MainWindow mainWindow) + { + if (AppManager.Instance.Config.UiItem.MacOSShowInDock || MacAppUtils.IsWindowMiniaturized(mainWindow)) + { + return; + } + + MacAppUtils.SetActivationPolicyAccessory(); + mainWindow.Activate(); + mainWindow.Focus(); + } + + #endregion MacOS Activation + + #region App Event + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { if (e.ExceptionObject != null) @@ -66,10 +120,6 @@ public partial class App : Application Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception); } - private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e) - { - } - private async void MenuAddServerViaClipboardClick(object? sender, EventArgs e) { try @@ -91,4 +141,6 @@ public partial class App : Application await AppManager.Instance.AppExitAsync(false); AppManager.Instance.Shutdown(true); } + + #endregion App Event } diff --git a/v2rayN/v2rayN.Desktop/Common/AppBuilderExtension.cs b/v2rayN/v2rayN.Desktop/Common/AppBuilderExtension.cs index 6bfd9e01..a510a9fc 100644 --- a/v2rayN/v2rayN.Desktop/Common/AppBuilderExtension.cs +++ b/v2rayN/v2rayN.Desktop/Common/AppBuilderExtension.cs @@ -18,18 +18,18 @@ public static class AppBuilderExtension if (OperatingSystem.IsWindows()) { - AddFontFallback(fallbacks, "Segoe UI Symbol"); AddFontFallback(fallbacks, "Segoe UI Emoji"); + AddFontFallback(fallbacks, "Segoe UI Symbol"); } else if (OperatingSystem.IsMacOS()) { - AddFontFallback(fallbacks, "Apple Symbols"); AddFontFallback(fallbacks, "Apple Color Emoji"); + AddFontFallback(fallbacks, "Apple Symbols"); } else if (OperatingSystem.IsLinux()) { - AddFontFallback(fallbacks, "Noto Sans Symbols"); AddFontFallback(fallbacks, "Noto Color Emoji"); + AddFontFallback(fallbacks, "Noto Sans Symbols"); } return appBuilder.With(new FontManagerOptions diff --git a/v2rayN/v2rayN.Desktop/Common/MacAppUtils.cs b/v2rayN/v2rayN.Desktop/Common/MacAppUtils.cs index b38f7507..3273feaf 100644 --- a/v2rayN/v2rayN.Desktop/Common/MacAppUtils.cs +++ b/v2rayN/v2rayN.Desktop/Common/MacAppUtils.cs @@ -13,6 +13,10 @@ internal static class MacAppUtils sel_registerName("setActivationPolicy:"), ActivationPolicyAccessory); + public static bool IsWindowMiniaturized(Window window) + => window.TryGetPlatformHandle() is IMacOSTopLevelPlatformHandle { NSWindow: not 0 } handle + && objc_msgSend_bool(handle.NSWindow, sel_registerName("isMiniaturized")); + [DllImport(LibObjC)] private static extern nint objc_getClass(string name); @@ -22,6 +26,10 @@ internal static class MacAppUtils [DllImport(LibObjC, EntryPoint = "objc_msgSend")] private static extern nint objc_msgSend(nint receiver, nint selector); + [DllImport(LibObjC, EntryPoint = "objc_msgSend")] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool objc_msgSend_bool(nint receiver, nint selector); + [DllImport(LibObjC, EntryPoint = "objc_msgSend")] private static extern void objc_msgSend(nint receiver, nint selector, nint argument); } diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 56457590..15c47b05 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -413,7 +413,7 @@ public partial class MainWindow : WindowBase public void ShowHideWindow(bool? blShow) { var bl = blShow ?? - (Utils.IsLinux() + (Utils.IsLinux() || Utils.IsMacOS() ? (!AppManager.Instance.ShowInTaskbar ^ (WindowState == WindowState.Minimized)) : !AppManager.Instance.ShowInTaskbar); if (bl)