From ec7b78bc63242beddfd6682e32286e4b33e5aa49 Mon Sep 17 00:00:00 2001 From: lincube Date: Mon, 9 Mar 2026 22:26:42 +0800 Subject: [PATCH] 0.5.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现已支持更改关键设置时提醒重启功能 --- LanMountainDesktop/App.axaml.cs | 10 +- LanMountainDesktop/Localization/en-US.json | 7 + LanMountainDesktop/Localization/zh-CN.json | 7 + .../Services/AppRestartService.cs | 17 ++ .../Services/PendingRestartStateService.cs | 54 +++++ .../Views/MainWindow.Localization.cs | 1 + .../Views/MainWindow.RestartPrompt.cs | 112 ++++++++++ .../Views/MainWindow.Settings.cs | 42 +++- LanMountainDesktop/Views/MainWindow.axaml | 200 +++++++++++------- LanMountainDesktop/Views/MainWindow.axaml.cs | 4 + .../SettingsPages/AboutSettingsPage.axaml | 1 + .../Views/SettingsWindow.Core.cs | 2 + .../Views/SettingsWindow.Localization.cs | 1 + .../Views/SettingsWindow.RestartPrompt.cs | 112 ++++++++++ .../Views/SettingsWindow.WeatherLauncher.cs | 42 +++- LanMountainDesktop/Views/SettingsWindow.axaml | 50 +++++ .../Views/SettingsWindow.axaml.cs | 2 + 17 files changed, 564 insertions(+), 100 deletions(-) create mode 100644 LanMountainDesktop/Services/PendingRestartStateService.cs create mode 100644 LanMountainDesktop/Views/MainWindow.RestartPrompt.cs create mode 100644 LanMountainDesktop/Views/SettingsWindow.RestartPrompt.cs diff --git a/LanMountainDesktop/App.axaml.cs b/LanMountainDesktop/App.axaml.cs index f00156c..521e28b 100644 --- a/LanMountainDesktop/App.axaml.cs +++ b/LanMountainDesktop/App.axaml.cs @@ -96,15 +96,7 @@ public partial class App : Application private void OnTrayRestartClick(object? sender, EventArgs e) { - if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) - { - return; - } - - if (AppRestartService.TryRestartCurrentProcess()) - { - desktop.Shutdown(); - } + AppRestartService.TryRestartApplication(); } private void DisableAvaloniaDataAnnotationValidation() diff --git a/LanMountainDesktop/Localization/en-US.json b/LanMountainDesktop/Localization/en-US.json index c1a6afc..bb54415 100644 --- a/LanMountainDesktop/Localization/en-US.json +++ b/LanMountainDesktop/Localization/en-US.json @@ -249,6 +249,13 @@ "settings.about.render_mode.current_format": "Current backend: {0}", "settings.about.render_mode.impl_format": "Runtime implementation: {0}", "settings.about.render_mode.impl_unavailable": "Runtime implementation details are unavailable.", + "settings.restart_dialog.title": "Restart required", + "settings.restart_dialog.render_mode_message": "Restart the app to switch the rendering mode from \"{0}\" to \"{1}\". Restart now?", + "settings.restart_dialog.restart": "Restart now", + "settings.restart_dialog.cancel": "Cancel", + "settings.restart_dock.title": "Restart required", + "settings.restart_dock.description": "Some changes will take effect after restarting the app.", + "settings.restart_dock.button": "Restart app", "settings.footer": "LanMountainDesktop Settings", "filepicker.title": "Select wallpaper", "filepicker.image_files": "Image files", diff --git a/LanMountainDesktop/Localization/zh-CN.json b/LanMountainDesktop/Localization/zh-CN.json index c2e96a0..eb43df9 100644 --- a/LanMountainDesktop/Localization/zh-CN.json +++ b/LanMountainDesktop/Localization/zh-CN.json @@ -249,6 +249,13 @@ "settings.about.render_mode.current_format": "当前后端:{0}", "settings.about.render_mode.impl_format": "运行时实现:{0}", "settings.about.render_mode.impl_unavailable": "当前无法获取运行时实现信息。", + "settings.restart_dialog.title": "需要重启应用", + "settings.restart_dialog.render_mode_message": "需要重启应用,才能将渲染模式从“{0}”切换到“{1}”。是否现在重启?", + "settings.restart_dialog.restart": "立即重启", + "settings.restart_dialog.cancel": "取消", + "settings.restart_dock.title": "需要重启应用", + "settings.restart_dock.description": "部分更改需要在重启应用后才会生效。", + "settings.restart_dock.button": "重启应用", "settings.footer": "LanMountainDesktop 设置", "filepicker.title": "选择壁纸", "filepicker.image_files": "图片文件", diff --git a/LanMountainDesktop/Services/AppRestartService.cs b/LanMountainDesktop/Services/AppRestartService.cs index 3ae0b01..4cdb416 100644 --- a/LanMountainDesktop/Services/AppRestartService.cs +++ b/LanMountainDesktop/Services/AppRestartService.cs @@ -3,11 +3,28 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; namespace LanMountainDesktop.Services; public static class AppRestartService { + public static bool TryRestartApplication() + { + if (!TryRestartCurrentProcess()) + { + return false; + } + + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.Shutdown(); + } + + return true; + } + public static bool TryRestartCurrentProcess() { try diff --git a/LanMountainDesktop/Services/PendingRestartStateService.cs b/LanMountainDesktop/Services/PendingRestartStateService.cs new file mode 100644 index 0000000..70a4ede --- /dev/null +++ b/LanMountainDesktop/Services/PendingRestartStateService.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace LanMountainDesktop.Services; + +public static class PendingRestartStateService +{ + public const string RenderModeReason = "RenderMode"; + + private static readonly object Gate = new(); + private static readonly HashSet PendingReasons = new(StringComparer.OrdinalIgnoreCase); + + public static event Action? StateChanged; + + public static bool HasPendingRestart + { + get + { + lock (Gate) + { + return PendingReasons.Count > 0; + } + } + } + + public static bool HasPendingReason(string reason) + { + lock (Gate) + { + return PendingReasons.Contains(reason); + } + } + + public static void SetPending(string reason, bool pending) + { + if (string.IsNullOrWhiteSpace(reason)) + { + return; + } + + var changed = false; + lock (Gate) + { + changed = pending + ? PendingReasons.Add(reason) + : PendingReasons.Remove(reason); + } + + if (changed) + { + StateChanged?.Invoke(); + } + } +} diff --git a/LanMountainDesktop/Views/MainWindow.Localization.cs b/LanMountainDesktop/Views/MainWindow.Localization.cs index 0c6572c..aeb2309 100644 --- a/LanMountainDesktop/Views/MainWindow.Localization.cs +++ b/LanMountainDesktop/Views/MainWindow.Localization.cs @@ -327,6 +327,7 @@ public partial class MainWindow SetAppRenderModeComboItemContent(AppRenderingModeHelper.Wgl, L("settings.about.render_mode.wgl", "WGL")); SetAppRenderModeComboItemContent(AppRenderingModeHelper.Vulkan, L("settings.about.render_mode.vulkan", "Vulkan")); UpdateCurrentRenderBackendStatus(); + UpdatePendingRestartDock(); if (WallpaperPlacementComboBox?.ItemCount >= 5) { diff --git a/LanMountainDesktop/Views/MainWindow.RestartPrompt.cs b/LanMountainDesktop/Views/MainWindow.RestartPrompt.cs new file mode 100644 index 0000000..4f2b4cf --- /dev/null +++ b/LanMountainDesktop/Views/MainWindow.RestartPrompt.cs @@ -0,0 +1,112 @@ +using System.Threading.Tasks; +using Avalonia.Interactivity; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using LanMountainDesktop.Services; + +namespace LanMountainDesktop.Views; + +public partial class MainWindow +{ + private bool _isRestartPromptVisible; + + private void OnPendingRestartStateChanged() + { + if (Dispatcher.UIThread.CheckAccess()) + { + UpdatePendingRestartDock(); + return; + } + + Dispatcher.UIThread.Post(UpdatePendingRestartDock); + } + + private void UpdatePendingRestartDock() + { + PendingRestartDock.IsVisible = PendingRestartStateService.HasPendingRestart; + PendingRestartDockTitleTextBlock.Text = L("settings.restart_dock.title", "Restart required"); + PendingRestartDockDescriptionTextBlock.Text = L( + "settings.restart_dock.description", + "Some changes will take effect after restarting the app."); + PendingRestartDockButtonTextBlock.Text = L("settings.restart_dock.button", "Restart app"); + } + + private async void OnPendingRestartDockButtonClick(object? sender, RoutedEventArgs e) + { + await ShowGenericRestartPromptAsync(); + } + + private Task ShowRenderModeRestartPromptAsync(string selectedMode) + { + var message = Lf( + "settings.restart_dialog.render_mode_message", + "Restart the app to switch the rendering mode from \"{0}\" to \"{1}\". Restart now?", + GetLocalizedAppRenderModeDisplayName(_runningAppRenderMode), + GetLocalizedAppRenderModeDisplayName(selectedMode)); + + return ShowRestartPromptCoreAsync(message); + } + + private Task ShowGenericRestartPromptAsync() + { + return ShowRestartPromptCoreAsync(L( + "settings.restart_dock.description", + "Some changes will take effect after restarting the app.")); + } + + private async Task ShowRestartPromptCoreAsync(string message) + { + if (_isRestartPromptVisible) + { + return; + } + + _isRestartPromptVisible = true; + + try + { + var dialog = new ContentDialog + { + Title = L("settings.restart_dialog.title", "Restart required"), + Content = message, + PrimaryButtonText = L("settings.restart_dialog.restart", "Restart now"), + CloseButtonText = L("settings.restart_dialog.cancel", "Cancel"), + DefaultButton = ContentDialogButton.Primary + }; + + var result = await dialog.ShowAsync(this); + if (result == ContentDialogResult.Primary) + { + if (!AppRestartService.TryRestartApplication()) + { + UpdatePendingRestartDock(); + } + + return; + } + + UpdatePendingRestartDock(); + } + finally + { + _isRestartPromptVisible = false; + } + } + + private string GetLocalizedAppRenderModeDisplayName(string renderMode) + { + if (renderMode == AppRenderBackendDiagnostics.Unknown) + { + return L("settings.about.render_mode.unknown", "Unknown"); + } + + return AppRenderingModeHelper.Normalize(renderMode) switch + { + AppRenderingModeHelper.Software => L("settings.about.render_mode.software", "Software"), + AppRenderingModeHelper.AngleEgl => L("settings.about.render_mode.angle_egl", "angleEgl"), + AppRenderingModeHelper.Wgl => L("settings.about.render_mode.wgl", "WGL"), + AppRenderingModeHelper.Vulkan => L("settings.about.render_mode.vulkan", "Vulkan"), + _ => L("settings.about.render_mode.default", "Default") + }; + } +} diff --git a/LanMountainDesktop/Views/MainWindow.Settings.cs b/LanMountainDesktop/Views/MainWindow.Settings.cs index 4254d6e..3e7d330 100644 --- a/LanMountainDesktop/Views/MainWindow.Settings.cs +++ b/LanMountainDesktop/Views/MainWindow.Settings.cs @@ -1225,6 +1225,10 @@ public partial class MainWindow private void InitializeAppRenderModeSetting(AppSettingsSnapshot snapshot) { _selectedAppRenderMode = AppRenderingModeHelper.Normalize(snapshot.AppRenderMode); + _runningAppRenderMode = ResolveActiveAppRenderModeForUi(_selectedAppRenderMode); + var renderModeForUi = PendingRestartStateService.HasPendingReason(PendingRestartStateService.RenderModeReason) + ? _selectedAppRenderMode + : _runningAppRenderMode; if (AppRenderModeComboBox is null) { @@ -1235,7 +1239,7 @@ public partial class MainWindow try { AppRenderModeComboBox.IsEnabled = OperatingSystem.IsWindows(); - SelectAppRenderModeInUi(_selectedAppRenderMode); + SelectAppRenderModeInUi(renderModeForUi); } finally { @@ -1250,13 +1254,27 @@ public partial class MainWindow return; } - var selectedItem = AppRenderModeComboBox.Items - .OfType() - .FirstOrDefault(item => - string.Equals(item.Tag?.ToString(), renderMode, StringComparison.OrdinalIgnoreCase)); + AppRenderModeComboBox.SelectedIndex = GetAppRenderModeComboBoxIndex(renderMode); + } - AppRenderModeComboBox.SelectedItem = selectedItem - ?? AppRenderModeComboBox.Items.OfType().FirstOrDefault(); + private static int GetAppRenderModeComboBoxIndex(string renderMode) + { + return AppRenderingModeHelper.Normalize(renderMode) switch + { + AppRenderingModeHelper.Software => 1, + AppRenderingModeHelper.AngleEgl => 2, + AppRenderingModeHelper.Wgl => 3, + AppRenderingModeHelper.Vulkan => 4, + _ => 0 + }; + } + + private static string ResolveActiveAppRenderModeForUi(string configuredRenderMode) + { + var detectedRenderMode = AppRenderBackendDiagnostics.Detect().ActualBackend; + return string.Equals(detectedRenderMode, AppRenderBackendDiagnostics.Unknown, StringComparison.Ordinal) + ? configuredRenderMode + : AppRenderingModeHelper.Normalize(detectedRenderMode); } private static WeatherLocationMode ParseWeatherLocationMode(string? value) @@ -1534,7 +1552,7 @@ public partial class MainWindow } var selectedMode = AppRenderingModeHelper.Normalize( - (AppRenderModeComboBox.SelectedItem as ComboBoxItem)?.Tag?.ToString()); + TryGetSelectedComboBoxTag(AppRenderModeComboBox)); if (string.Equals(_selectedAppRenderMode, selectedMode, StringComparison.Ordinal)) { @@ -1543,6 +1561,14 @@ public partial class MainWindow _selectedAppRenderMode = selectedMode; PersistSettings(); + var requiresRestart = !string.Equals(_runningAppRenderMode, selectedMode, StringComparison.Ordinal); + PendingRestartStateService.SetPending(PendingRestartStateService.RenderModeReason, requiresRestart); + UpdatePendingRestartDock(); + + if (requiresRestart) + { + _ = ShowRenderModeRestartPromptAsync(selectedMode); + } } private async void OnSearchWeatherCityClick(object? sender, RoutedEventArgs e) diff --git a/LanMountainDesktop/Views/MainWindow.axaml b/LanMountainDesktop/Views/MainWindow.axaml index 2542355..9d75e88 100644 --- a/LanMountainDesktop/Views/MainWindow.axaml +++ b/LanMountainDesktop/Views/MainWindow.axaml @@ -377,88 +377,138 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - + - + - - - - + + + + - + - - - + + + + + + + + + + + + + + + + + - - + + diff --git a/LanMountainDesktop/Views/MainWindow.axaml.cs b/LanMountainDesktop/Views/MainWindow.axaml.cs index 126c77e..c94f831 100644 --- a/LanMountainDesktop/Views/MainWindow.axaml.cs +++ b/LanMountainDesktop/Views/MainWindow.axaml.cs @@ -169,6 +169,7 @@ public partial class MainWindow : Window private bool _suppressAutoStartToggleEvents; private bool _suppressAppRenderModeSelectionEvents; private string _selectedAppRenderMode = AppRenderingModeHelper.Default; + private string _runningAppRenderMode = AppRenderingModeHelper.Default; private string _weatherSearchKeyword = string.Empty; private bool _isWeatherSearchInProgress; private bool _isWeatherPreviewInProgress; @@ -190,6 +191,7 @@ public partial class MainWindow : Window _fluentAvaloniaTheme = Application.Current?.Styles.OfType().FirstOrDefault(); AppSettingsService.SettingsSaved += OnExternalAppSettingsSaved; LauncherSettingsService.SettingsSaved += OnExternalLauncherSettingsSaved; + PendingRestartStateService.StateChanged += OnPendingRestartStateChanged; PropertyChanged += OnWindowPropertyChanged; InitializeDesktopSurfaceSwipeHandlers(); InitializeDesktopComponentDragHandlers(); @@ -314,6 +316,7 @@ public partial class MainWindow : Window InitializeWeatherSettings(snapshot); _ = _componentSettingsService.Load(); InitializeAutoStartWithWindowsSetting(snapshot); + InitializeAppRenderModeSetting(snapshot); InitializeUpdateSettings(snapshot); InitializeDesktopSurfaceState(desktopLayoutSnapshot); InitializeLauncherVisibilitySettings(launcherSnapshot); @@ -379,6 +382,7 @@ public partial class MainWindow : Window _wallpaperBitmap = null; AppSettingsService.SettingsSaved -= OnExternalAppSettingsSaved; LauncherSettingsService.SettingsSaved -= OnExternalLauncherSettingsSaved; + PendingRestartStateService.StateChanged -= OnPendingRestartStateChanged; PropertyChanged -= OnWindowPropertyChanged; DesktopHost.SizeChanged -= OnDesktopHostSizeChanged; WallpaperPreviewHost.SizeChanged -= OnWallpaperPreviewHostSizeChanged; diff --git a/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml b/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml index 64606ab..2075e2d 100644 --- a/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml +++ b/LanMountainDesktop/Views/SettingsPages/AboutSettingsPage.axaml @@ -64,6 +64,7 @@ diff --git a/LanMountainDesktop/Views/SettingsWindow.Core.cs b/LanMountainDesktop/Views/SettingsWindow.Core.cs index 6ef04a3..45ef0f1 100644 --- a/LanMountainDesktop/Views/SettingsWindow.Core.cs +++ b/LanMountainDesktop/Views/SettingsWindow.Core.cs @@ -12,6 +12,7 @@ using FluentIcons.Avalonia.Fluent; using FluentIcons.Common; using LanMountainDesktop.ComponentSystem; using LanMountainDesktop.Models; +using LanMountainDesktop.Services; using LanMountainDesktop.Views.Components; namespace LanMountainDesktop.Views; @@ -43,6 +44,7 @@ public partial class SettingsWindow } _launcherIconCache.Clear(); + PendingRestartStateService.StateChanged -= OnPendingRestartStateChanged; base.OnClosed(e); } diff --git a/LanMountainDesktop/Views/SettingsWindow.Localization.cs b/LanMountainDesktop/Views/SettingsWindow.Localization.cs index 15cd30a..77a5fb3 100644 --- a/LanMountainDesktop/Views/SettingsWindow.Localization.cs +++ b/LanMountainDesktop/Views/SettingsWindow.Localization.cs @@ -137,6 +137,7 @@ public partial class SettingsWindow SetAppRenderModeComboItemContent(AppRenderingModeHelper.Wgl, L("settings.about.render_mode.wgl", "WGL")); SetAppRenderModeComboItemContent(AppRenderingModeHelper.Vulkan, L("settings.about.render_mode.vulkan", "Vulkan")); UpdateCurrentRenderBackendStatus(); + UpdatePendingRestartDock(); var placementItems = WallpaperPlacementComboBox.Items.OfType().ToList(); if (placementItems.Count >= 5) diff --git a/LanMountainDesktop/Views/SettingsWindow.RestartPrompt.cs b/LanMountainDesktop/Views/SettingsWindow.RestartPrompt.cs new file mode 100644 index 0000000..38f5205 --- /dev/null +++ b/LanMountainDesktop/Views/SettingsWindow.RestartPrompt.cs @@ -0,0 +1,112 @@ +using System.Threading.Tasks; +using Avalonia.Interactivity; +using Avalonia.Threading; +using FluentAvalonia.UI.Controls; +using LanMountainDesktop.Services; + +namespace LanMountainDesktop.Views; + +public partial class SettingsWindow +{ + private bool _isRestartPromptVisible; + + private void OnPendingRestartStateChanged() + { + if (Dispatcher.UIThread.CheckAccess()) + { + UpdatePendingRestartDock(); + return; + } + + Dispatcher.UIThread.Post(UpdatePendingRestartDock); + } + + private void UpdatePendingRestartDock() + { + PendingRestartDock.IsVisible = PendingRestartStateService.HasPendingRestart; + PendingRestartDockTitleTextBlock.Text = L("settings.restart_dock.title", "Restart required"); + PendingRestartDockDescriptionTextBlock.Text = L( + "settings.restart_dock.description", + "Some changes will take effect after restarting the app."); + PendingRestartDockButtonTextBlock.Text = L("settings.restart_dock.button", "Restart app"); + } + + private async void OnPendingRestartDockButtonClick(object? sender, RoutedEventArgs e) + { + await ShowGenericRestartPromptAsync(); + } + + private Task ShowRenderModeRestartPromptAsync(string selectedMode) + { + var message = Lf( + "settings.restart_dialog.render_mode_message", + "Restart the app to switch the rendering mode from \"{0}\" to \"{1}\". Restart now?", + GetLocalizedAppRenderModeDisplayName(_runningAppRenderMode), + GetLocalizedAppRenderModeDisplayName(selectedMode)); + + return ShowRestartPromptCoreAsync(message); + } + + private Task ShowGenericRestartPromptAsync() + { + return ShowRestartPromptCoreAsync(L( + "settings.restart_dock.description", + "Some changes will take effect after restarting the app.")); + } + + private async Task ShowRestartPromptCoreAsync(string message) + { + if (_isRestartPromptVisible) + { + return; + } + + _isRestartPromptVisible = true; + + try + { + var dialog = new ContentDialog + { + Title = L("settings.restart_dialog.title", "Restart required"), + Content = message, + PrimaryButtonText = L("settings.restart_dialog.restart", "Restart now"), + CloseButtonText = L("settings.restart_dialog.cancel", "Cancel"), + DefaultButton = ContentDialogButton.Primary + }; + + var result = await dialog.ShowAsync(this); + if (result == ContentDialogResult.Primary) + { + if (!AppRestartService.TryRestartApplication()) + { + UpdatePendingRestartDock(); + } + + return; + } + + UpdatePendingRestartDock(); + } + finally + { + _isRestartPromptVisible = false; + } + } + + private string GetLocalizedAppRenderModeDisplayName(string renderMode) + { + if (renderMode == AppRenderBackendDiagnostics.Unknown) + { + return L("settings.about.render_mode.unknown", "Unknown"); + } + + return AppRenderingModeHelper.Normalize(renderMode) switch + { + AppRenderingModeHelper.Software => L("settings.about.render_mode.software", "Software"), + AppRenderingModeHelper.AngleEgl => L("settings.about.render_mode.angle_egl", "angleEgl"), + AppRenderingModeHelper.Wgl => L("settings.about.render_mode.wgl", "WGL"), + AppRenderingModeHelper.Vulkan => L("settings.about.render_mode.vulkan", "Vulkan"), + _ => L("settings.about.render_mode.default", "Default") + }; + } +} diff --git a/LanMountainDesktop/Views/SettingsWindow.WeatherLauncher.cs b/LanMountainDesktop/Views/SettingsWindow.WeatherLauncher.cs index f4172bc..8abcebd 100644 --- a/LanMountainDesktop/Views/SettingsWindow.WeatherLauncher.cs +++ b/LanMountainDesktop/Views/SettingsWindow.WeatherLauncher.cs @@ -92,12 +92,16 @@ public partial class SettingsWindow private void InitializeAppRenderModeSetting(AppSettingsSnapshot snapshot) { _selectedAppRenderMode = AppRenderingModeHelper.Normalize(snapshot.AppRenderMode); + _runningAppRenderMode = ResolveActiveAppRenderModeForUi(_selectedAppRenderMode); + var renderModeForUi = PendingRestartStateService.HasPendingReason(PendingRestartStateService.RenderModeReason) + ? _selectedAppRenderMode + : _runningAppRenderMode; _suppressAppRenderModeSelectionEvents = true; try { AppRenderModeComboBox.IsEnabled = OperatingSystem.IsWindows(); - SelectAppRenderModeInUi(_selectedAppRenderMode); + SelectAppRenderModeInUi(renderModeForUi); } finally { @@ -107,13 +111,27 @@ public partial class SettingsWindow private void SelectAppRenderModeInUi(string renderMode) { - var selectedItem = AppRenderModeComboBox.Items - .OfType() - .FirstOrDefault(item => - string.Equals(item.Tag?.ToString(), renderMode, StringComparison.OrdinalIgnoreCase)); + AppRenderModeComboBox.SelectedIndex = GetAppRenderModeComboBoxIndex(renderMode); + } - AppRenderModeComboBox.SelectedItem = selectedItem - ?? AppRenderModeComboBox.Items.OfType().FirstOrDefault(); + private static int GetAppRenderModeComboBoxIndex(string renderMode) + { + return AppRenderingModeHelper.Normalize(renderMode) switch + { + AppRenderingModeHelper.Software => 1, + AppRenderingModeHelper.AngleEgl => 2, + AppRenderingModeHelper.Wgl => 3, + AppRenderingModeHelper.Vulkan => 4, + _ => 0 + }; + } + + private static string ResolveActiveAppRenderModeForUi(string configuredRenderMode) + { + var detectedRenderMode = AppRenderBackendDiagnostics.Detect().ActualBackend; + return string.Equals(detectedRenderMode, AppRenderBackendDiagnostics.Unknown, StringComparison.Ordinal) + ? configuredRenderMode + : AppRenderingModeHelper.Normalize(detectedRenderMode); } private static WeatherLocationMode ParseWeatherLocationMode(string? value) @@ -354,7 +372,7 @@ public partial class SettingsWindow } var selectedMode = AppRenderingModeHelper.Normalize( - (AppRenderModeComboBox.SelectedItem as ComboBoxItem)?.Tag?.ToString()); + TryGetSelectedComboBoxTag(AppRenderModeComboBox)); if (string.Equals(_selectedAppRenderMode, selectedMode, StringComparison.Ordinal)) { @@ -363,6 +381,14 @@ public partial class SettingsWindow _selectedAppRenderMode = selectedMode; PersistSettings(); + var requiresRestart = !string.Equals(_runningAppRenderMode, selectedMode, StringComparison.Ordinal); + PendingRestartStateService.SetPending(PendingRestartStateService.RenderModeReason, requiresRestart); + UpdatePendingRestartDock(); + + if (requiresRestart) + { + _ = ShowRenderModeRestartPromptAsync(selectedMode); + } } private async void OnSearchWeatherCityClick(object? sender, RoutedEventArgs e) diff --git a/LanMountainDesktop/Views/SettingsWindow.axaml b/LanMountainDesktop/Views/SettingsWindow.axaml index f148556..de22e31 100644 --- a/LanMountainDesktop/Views/SettingsWindow.axaml +++ b/LanMountainDesktop/Views/SettingsWindow.axaml @@ -79,7 +79,10 @@ Classes="mica-strong" CornerRadius="0,0,24,24" Padding="18"> + + + + + + + + + + + + + + + diff --git a/LanMountainDesktop/Views/SettingsWindow.axaml.cs b/LanMountainDesktop/Views/SettingsWindow.axaml.cs index 5364fc8..4d0b289 100644 --- a/LanMountainDesktop/Views/SettingsWindow.axaml.cs +++ b/LanMountainDesktop/Views/SettingsWindow.axaml.cs @@ -142,6 +142,7 @@ public partial class SettingsWindow : Window private int _statusBarCustomSpacingPercent = 12; private int _desktopEdgeInsetPercent = DefaultEdgeInsetPercent; private string _selectedAppRenderMode = AppRenderingModeHelper.Default; + private string _runningAppRenderMode = AppRenderingModeHelper.Default; private string _taskbarLayoutMode = TaskbarLayoutBottomFullRowMacStyle; private string _languageCode = "zh-CN"; private WeatherLocationMode _weatherLocationMode = WeatherLocationMode.CitySearch; @@ -165,6 +166,7 @@ public partial class SettingsWindow : Window InitializePluginSettingsNavigation(); _fluentAvaloniaTheme = Application.Current?.Styles.OfType().FirstOrDefault(); RequestedThemeVariant = Application.Current?.RequestedThemeVariant ?? ThemeVariant.Default; + PendingRestartStateService.StateChanged += OnPendingRestartStateChanged; HookEvents(); }