From c57a142b3bfa40e67fea294b5030c14e8e9cbe39 Mon Sep 17 00:00:00 2001 From: YsLtr Date: Wed, 25 Mar 2026 10:47:43 +0800 Subject: [PATCH 1/5] Fix Linux desktop title bar theming --- v2rayN/v2rayN.Desktop/Views/MainWindow.axaml | 76 ++++++++++++++++- .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 83 +++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index 8d9a5f85..dd4d96cb 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -8,6 +8,7 @@ xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:view="using:v2rayN.Desktop.Views" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" + x:Name="mainWindow" Title="v2rayN" Width="1200" Height="800" @@ -17,11 +18,84 @@ ShowInTaskbar="True" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> + + + + + - + + + + + + + + + + + + + + + + + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 996e7c83..97612f0c 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -10,6 +10,7 @@ public partial class MainWindow : WindowBase { private static Config _config; private readonly WindowNotificationManager? _manager; + private IDisposable? _linuxWindowStateSubscription; private CheckUpdateView? _checkUpdateView; private BackupAndRestoreView? _backupAndRestoreView; private bool _blCloseByUser = false; @@ -162,6 +163,7 @@ public partial class MainWindow : WindowBase else { Title = $"{Utils.GetVersion()}"; + ConfigureLinuxTitleBar(); } menuAddServerViaScan.IsVisible = false; @@ -388,6 +390,81 @@ public partial class MainWindow : WindowBase await AppManager.Instance.AppExitAsync(true); } + private void ConfigureLinuxTitleBar() + { + if (!Utils.IsLinux()) + { + return; + } + + linuxTitleBar.IsVisible = true; + SystemDecorations = SystemDecorations.BorderOnly; + btnLinuxMaximizeRestore.IsVisible = CanResize; + + _linuxWindowStateSubscription = this + .GetObservable(WindowStateProperty) + .Subscribe(_ => UpdateLinuxTitleBarWindowState()); + UpdateLinuxTitleBarWindowState(); + } + + private void UpdateLinuxTitleBarWindowState() + { + txtLinuxMaximizeRestore.Text = WindowState == WindowState.Maximized ? "❐" : "□"; + } + + private void LinuxTitleBar_PointerPressed(object? sender, PointerPressedEventArgs e) + { + if (!Utils.IsLinux() || e.GetCurrentPoint(this).Properties.IsLeftButtonPressed == false) + { + return; + } + + BeginMoveDrag(e); + } + + private void LinuxTitleBar_DoubleTapped(object? sender, TappedEventArgs e) + { + if (!Utils.IsLinux() || !CanResize) + { + return; + } + + ToggleLinuxWindowState(); + } + + private void BtnLinuxMinimize_Click(object? sender, RoutedEventArgs e) + { + WindowState = WindowState.Minimized; + } + + private void BtnLinuxMaximizeRestore_Click(object? sender, RoutedEventArgs e) + { + ToggleLinuxWindowState(); + } + + private void BtnLinuxClose_Click(object? sender, RoutedEventArgs e) + { + HideToTray(); + } + + private void ToggleLinuxWindowState() + { + WindowState = WindowState == WindowState.Maximized + ? WindowState.Normal + : WindowState.Maximized; + } + + private void HideToTray() + { + foreach (var ownedWindow in OwnedWindows) + { + ownedWindow.Close(); + } + + Hide(); + AppManager.Instance.ShowInTaskbar = false; + } + private void Shutdown(bool obj) { if (obj is bool b && _blCloseByUser == false) @@ -450,6 +527,12 @@ public partial class MainWindow : WindowBase RestoreUI(); } + protected override void OnClosed(EventArgs e) + { + _linuxWindowStateSubscription?.Dispose(); + base.OnClosed(e); + } + private void RestoreUI() { if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0) From 0be24016359c8d8df3d3b0b0ae8f3624bf7371fc Mon Sep 17 00:00:00 2001 From: YsLtr Date: Wed, 25 Mar 2026 10:53:33 +0800 Subject: [PATCH 2/5] Handle Linux window close requests via tray hide --- v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 97612f0c..932973ca 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -282,7 +282,14 @@ public partial class MainWindow : WindowBase { case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing: e.Cancel = true; - ShowHideWindow(false); + if (Utils.IsLinux()) + { + HideToTray(); + } + else + { + ShowHideWindow(false); + } break; case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown: From 07903628f1e6a8df81e3a636a63c11f74e429fe2 Mon Sep 17 00:00:00 2001 From: YsLtr Date: Wed, 25 Mar 2026 10:59:27 +0800 Subject: [PATCH 3/5] Avoid Linux minimize hangs and remove async warning --- v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs | 2 +- v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 6e7e183c..65dd938e 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -156,7 +156,7 @@ public class ProfilesViewModel : MyReactiveObject { await MoveServer(EMove.Bottom); }, canEditRemove); - MoveToGroupCmd = ReactiveCommand.CreateFromTask(async sub => + MoveToGroupCmd = ReactiveCommand.Create(sub => { SelectedMoveToGroup = sub; }); diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index 932973ca..b4759bb1 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -441,7 +441,7 @@ public partial class MainWindow : WindowBase private void BtnLinuxMinimize_Click(object? sender, RoutedEventArgs e) { - WindowState = WindowState.Minimized; + HideToTray(); } private void BtnLinuxMaximizeRestore_Click(object? sender, RoutedEventArgs e) @@ -510,7 +510,7 @@ public partial class MainWindow : WindowBase { if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false) { - WindowState = WindowState.Minimized; + HideToTray(); return; } From 10fc87ca1296b209554db5ee7db700bb9250437a Mon Sep 17 00:00:00 2001 From: YsLtr Date: Wed, 25 Mar 2026 15:23:57 +0800 Subject: [PATCH 4/5] Keep only close button in Linux title bar --- v2rayN/v2rayN.Desktop/Views/MainWindow.axaml | 16 ------- .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 45 ------------------- 2 files changed, 61 deletions(-) diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index dd4d96cb..24505c6c 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -52,7 +52,6 @@ - - + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml b/v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml index 0c9d89a4..b7517329 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml @@ -13,7 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml index 4dc378b4..f7712dc9 100644 --- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml @@ -14,7 +14,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml index 3335785b..fda5aac2 100644 --- a/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml @@ -14,7 +14,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/FullConfigTemplateWindow.axaml b/v2rayN/v2rayN.Desktop/Views/FullConfigTemplateWindow.axaml index 1a2b482c..ddd4b614 100644 --- a/v2rayN/v2rayN.Desktop/Views/FullConfigTemplateWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/FullConfigTemplateWindow.axaml @@ -14,7 +14,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml index 8eb3b473..ae67bc8f 100644 --- a/v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml @@ -13,7 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index 24505c6c..74af4d43 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -18,26 +18,6 @@ ShowInTaskbar="True" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - - - - - + Background="Transparent" /> diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index ba73b8d6..9ab5ee3d 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -162,7 +162,6 @@ public partial class MainWindow : WindowBase else { Title = $"{Utils.GetVersion()}"; - ConfigureLinuxTitleBar(); } menuAddServerViaScan.IsVisible = false; @@ -396,28 +395,7 @@ public partial class MainWindow : WindowBase await AppManager.Instance.AppExitAsync(true); } - private void ConfigureLinuxTitleBar() - { - if (!Utils.IsLinux()) - { - return; - } - - linuxTitleBar.IsVisible = true; - SystemDecorations = SystemDecorations.BorderOnly; - } - - private void LinuxTitleBar_PointerPressed(object? sender, PointerPressedEventArgs e) - { - if (!Utils.IsLinux() || e.GetCurrentPoint(this).Properties.IsLeftButtonPressed == false) - { - return; - } - - BeginMoveDrag(e); - } - - private void BtnLinuxClose_Click(object? sender, RoutedEventArgs e) + protected override void HandleLinuxTitleBarClose() { HideToTray(); } diff --git a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml index 7d80088a..0507c52c 100644 --- a/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml @@ -13,7 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml index 2dd44b54..a467a12c 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml @@ -12,8 +12,37 @@ x:DataType="vms:ProfilesSelectViewModel" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml b/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml index 30f74a14..b62ad64d 100644 --- a/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml @@ -13,7 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml index a770b3ed..e75fef56 100644 --- a/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml @@ -13,7 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + @@ -253,5 +283,6 @@ - + + diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml index a9155f7d..a39f6767 100644 --- a/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml @@ -13,8 +13,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - - + + + + + + + + + + + + + + @@ -138,5 +167,6 @@ - + + diff --git a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml index 79216921..b9089de4 100644 --- a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml @@ -12,7 +12,37 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + + + + + + + + + + + + + - + + diff --git a/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml b/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml index 04870d4a..4b63fa2b 100644 --- a/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml @@ -14,12 +14,43 @@ ShowInTaskbar="False" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - - + + + + + + + + + + + + + + + @@ -75,6 +106,7 @@ Header="{x:Static resx:ResUI.LvSort}" /> - - + + +