mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
0.5.4
项目重启优化。
This commit is contained in:
@@ -101,42 +101,12 @@ public partial class App : Application
|
||||
return;
|
||||
}
|
||||
|
||||
if (TryStartCurrentProcess())
|
||||
if (AppRestartService.TryRestartCurrentProcess())
|
||||
{
|
||||
desktop.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryStartCurrentProcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
if (args.Length == 0 || string.IsNullOrWhiteSpace(args[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = args[0],
|
||||
UseShellExecute = false
|
||||
};
|
||||
|
||||
for (var i = 1; i < args.Length; i++)
|
||||
{
|
||||
startInfo.ArgumentList.Add(args[i]);
|
||||
}
|
||||
|
||||
Process.Start(startInfo);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableAvaloniaDataAnnotationValidation()
|
||||
{
|
||||
// Get an array of plugins to remove
|
||||
|
||||
@@ -244,6 +244,11 @@
|
||||
"settings.about.render_mode.angle_egl": "angleEgl",
|
||||
"settings.about.render_mode.wgl": "WGL",
|
||||
"settings.about.render_mode.vulkan": "Vulkan",
|
||||
"settings.about.render_mode.unknown": "Unknown",
|
||||
"settings.about.render_mode.current_label": "Current actual backend",
|
||||
"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.footer": "LanMountainDesktop Settings",
|
||||
"filepicker.title": "Select wallpaper",
|
||||
"filepicker.image_files": "Image files",
|
||||
|
||||
@@ -244,6 +244,11 @@
|
||||
"settings.about.render_mode.angle_egl": "angleEgl",
|
||||
"settings.about.render_mode.wgl": "WGL",
|
||||
"settings.about.render_mode.vulkan": "Vulkan",
|
||||
"settings.about.render_mode.unknown": "未知",
|
||||
"settings.about.render_mode.current_label": "当前实际渲染后端",
|
||||
"settings.about.render_mode.current_format": "当前后端:{0}",
|
||||
"settings.about.render_mode.impl_format": "运行时实现:{0}",
|
||||
"settings.about.render_mode.impl_unavailable": "当前无法获取运行时实现信息。",
|
||||
"settings.footer": "LanMountainDesktop 设置",
|
||||
"filepicker.title": "选择壁纸",
|
||||
"filepicker.image_files": "图片文件",
|
||||
|
||||
73
LanMountainDesktop/Services/AppRenderBackendDiagnostics.cs
Normal file
73
LanMountainDesktop/Services/AppRenderBackendDiagnostics.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Avalonia;
|
||||
using Avalonia.Platform;
|
||||
|
||||
namespace LanMountainDesktop.Services;
|
||||
|
||||
public readonly record struct AppRenderBackendInfo(
|
||||
string ActualBackend,
|
||||
string? ImplementationTypeName);
|
||||
|
||||
public static class AppRenderBackendDiagnostics
|
||||
{
|
||||
public const string Unknown = "Unknown";
|
||||
|
||||
public static AppRenderBackendInfo Detect()
|
||||
{
|
||||
var platformGraphics = GetPlatformGraphics();
|
||||
var implementationTypeName = platformGraphics?.GetType().FullName;
|
||||
var actualBackend = DetectBackendFromImplementationType(implementationTypeName, platformGraphics is null);
|
||||
|
||||
return new AppRenderBackendInfo(actualBackend, implementationTypeName);
|
||||
}
|
||||
|
||||
private static object? GetPlatformGraphics()
|
||||
{
|
||||
var currentResolver = typeof(AvaloniaLocator)
|
||||
.GetProperty("Current", BindingFlags.Public | BindingFlags.Static)
|
||||
?.GetValue(null);
|
||||
|
||||
var getServiceMethod = currentResolver?
|
||||
.GetType()
|
||||
.GetMethod(
|
||||
"GetService",
|
||||
BindingFlags.Public | BindingFlags.Instance,
|
||||
binder: null,
|
||||
types: [typeof(Type)],
|
||||
modifiers: null);
|
||||
|
||||
return getServiceMethod?.Invoke(currentResolver, [typeof(IPlatformGraphics)]);
|
||||
}
|
||||
|
||||
private static string DetectBackendFromImplementationType(string? implementationTypeName, bool isSoftwareFallback)
|
||||
{
|
||||
if (isSoftwareFallback)
|
||||
{
|
||||
return AppRenderingModeHelper.Software;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(implementationTypeName))
|
||||
{
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
if (implementationTypeName.Contains("Vulkan", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return AppRenderingModeHelper.Vulkan;
|
||||
}
|
||||
|
||||
if (implementationTypeName.Contains("Wgl", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return AppRenderingModeHelper.Wgl;
|
||||
}
|
||||
|
||||
if (implementationTypeName.Contains("Angle", StringComparison.OrdinalIgnoreCase) ||
|
||||
implementationTypeName.Contains("Egl", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return AppRenderingModeHelper.AngleEgl;
|
||||
}
|
||||
|
||||
return Unknown;
|
||||
}
|
||||
}
|
||||
154
LanMountainDesktop/Services/AppRestartService.cs
Normal file
154
LanMountainDesktop/Services/AppRestartService.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace LanMountainDesktop.Services;
|
||||
|
||||
public static class AppRestartService
|
||||
{
|
||||
public static bool TryRestartCurrentProcess()
|
||||
{
|
||||
try
|
||||
{
|
||||
var startInfo = CreateRestartStartInfo();
|
||||
if (startInfo is null)
|
||||
{
|
||||
Debug.WriteLine("[AppRestart] Failed to resolve restart start info.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Process.Start(startInfo);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[AppRestart] Failed to restart app: {ex}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static ProcessStartInfo? CreateRestartStartInfo(
|
||||
string[]? commandLineArgs = null,
|
||||
string? processPath = null,
|
||||
string? entryAssemblyLocation = null)
|
||||
{
|
||||
var args = commandLineArgs ?? Environment.GetCommandLineArgs();
|
||||
var resolvedProcessPath = NormalizeExistingPath(processPath ?? Environment.ProcessPath);
|
||||
var resolvedEntryAssemblyPath = NormalizeExistingPath(
|
||||
entryAssemblyLocation ?? Assembly.GetEntryAssembly()?.Location);
|
||||
|
||||
if (IsDotnetHost(resolvedProcessPath))
|
||||
{
|
||||
return CreateDotnetStartInfo(
|
||||
resolvedProcessPath!,
|
||||
resolvedEntryAssemblyPath,
|
||||
args);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(resolvedProcessPath))
|
||||
{
|
||||
return CreateExecutableStartInfo(
|
||||
resolvedProcessPath,
|
||||
resolvedEntryAssemblyPath,
|
||||
args);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(resolvedEntryAssemblyPath) &&
|
||||
string.Equals(Path.GetExtension(resolvedEntryAssemblyPath), ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CreateDotnetStartInfo(
|
||||
"dotnet",
|
||||
resolvedEntryAssemblyPath,
|
||||
args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static ProcessStartInfo CreateExecutableStartInfo(
|
||||
string executablePath,
|
||||
string? entryAssemblyPath,
|
||||
IReadOnlyList<string> commandLineArgs)
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = executablePath,
|
||||
UseShellExecute = false,
|
||||
WorkingDirectory = ResolveWorkingDirectory(executablePath, entryAssemblyPath)
|
||||
};
|
||||
|
||||
AppendArguments(startInfo, commandLineArgs);
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private static ProcessStartInfo? CreateDotnetStartInfo(
|
||||
string dotnetHostPath,
|
||||
string? entryAssemblyPath,
|
||||
IReadOnlyList<string> commandLineArgs)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entryAssemblyPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = dotnetHostPath,
|
||||
UseShellExecute = false,
|
||||
WorkingDirectory = ResolveWorkingDirectory(dotnetHostPath, entryAssemblyPath)
|
||||
};
|
||||
|
||||
startInfo.ArgumentList.Add(entryAssemblyPath);
|
||||
AppendArguments(startInfo, commandLineArgs);
|
||||
return startInfo;
|
||||
}
|
||||
|
||||
private static void AppendArguments(ProcessStartInfo startInfo, IReadOnlyList<string> commandLineArgs)
|
||||
{
|
||||
for (var i = 1; i < commandLineArgs.Count; i++)
|
||||
{
|
||||
startInfo.ArgumentList.Add(commandLineArgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? NormalizeExistingPath(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var fullPath = Path.GetFullPath(path);
|
||||
return File.Exists(fullPath) ? fullPath : null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDotnetHost(string? processPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(processPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(processPath);
|
||||
return string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(fileName, "dotnet.exe", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string ResolveWorkingDirectory(string launchPath, string? entryAssemblyPath)
|
||||
{
|
||||
var basePath = !string.IsNullOrWhiteSpace(entryAssemblyPath)
|
||||
? entryAssemblyPath
|
||||
: launchPath;
|
||||
|
||||
return Path.GetDirectoryName(basePath) ?? AppContext.BaseDirectory;
|
||||
}
|
||||
}
|
||||
@@ -326,6 +326,7 @@ public partial class MainWindow
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.AngleEgl, L("settings.about.render_mode.angle_egl", "angleEgl"));
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.Wgl, L("settings.about.render_mode.wgl", "WGL"));
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.Vulkan, L("settings.about.render_mode.vulkan", "Vulkan"));
|
||||
UpdateCurrentRenderBackendStatus();
|
||||
|
||||
if (WallpaperPlacementComboBox?.ItemCount >= 5)
|
||||
{
|
||||
|
||||
42
LanMountainDesktop/Views/MainWindow.RenderBackend.cs
Normal file
42
LanMountainDesktop/Views/MainWindow.RenderBackend.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using LanMountainDesktop.Services;
|
||||
|
||||
namespace LanMountainDesktop.Views;
|
||||
|
||||
public partial class MainWindow
|
||||
{
|
||||
private void UpdateCurrentRenderBackendStatus()
|
||||
{
|
||||
var backendInfo = AppRenderBackendDiagnostics.Detect();
|
||||
var localizedBackend = GetLocalizedRenderBackendName(backendInfo.ActualBackend);
|
||||
|
||||
CurrentRenderBackendLabelTextBlock.Text = L(
|
||||
"settings.about.render_mode.current_label",
|
||||
"Current actual backend");
|
||||
CurrentRenderBackendValueTextBlock.Text = Lf(
|
||||
"settings.about.render_mode.current_format",
|
||||
"Current backend: {0}",
|
||||
localizedBackend);
|
||||
CurrentRenderBackendImplementationTextBlock.Text = string.IsNullOrWhiteSpace(backendInfo.ImplementationTypeName)
|
||||
? L(
|
||||
"settings.about.render_mode.impl_unavailable",
|
||||
"Runtime implementation is unavailable.")
|
||||
: Lf(
|
||||
"settings.about.render_mode.impl_format",
|
||||
"Runtime implementation: {0}",
|
||||
backendInfo.ImplementationTypeName);
|
||||
}
|
||||
|
||||
private string GetLocalizedRenderBackendName(string renderBackend)
|
||||
{
|
||||
return renderBackend switch
|
||||
{
|
||||
AppRenderingModeHelper.Default => L("settings.about.render_mode.default", "Default"),
|
||||
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.unknown", "Unknown")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2701,6 +2701,9 @@ public partial class MainWindow
|
||||
internal FluentAvalonia.UI.Controls.SettingsExpander AboutRenderModeSettingsExpander => AboutSettingsPanel.FindControl<FluentAvalonia.UI.Controls.SettingsExpander>("AboutRenderModeSettingsExpander")!;
|
||||
internal ToggleSwitch AutoStartWithWindowsToggleSwitch => AboutSettingsPanel.FindControl<ToggleSwitch>("AutoStartWithWindowsToggleSwitch")!;
|
||||
internal ComboBox AppRenderModeComboBox => AboutSettingsPanel.FindControl<ComboBox>("AppRenderModeComboBox")!;
|
||||
internal TextBlock CurrentRenderBackendLabelTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendLabelTextBlock")!;
|
||||
internal TextBlock CurrentRenderBackendValueTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendValueTextBlock")!;
|
||||
internal TextBlock CurrentRenderBackendImplementationTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendImplementationTextBlock")!;
|
||||
internal TextBlock VersionTextBlock => AboutSettingsPanel.FindControl<TextBlock>("VersionTextBlock")!;
|
||||
internal TextBlock CodeNameTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CodeNameTextBlock")!;
|
||||
internal TextBlock FontInfoTextBlock => AboutSettingsPanel.FindControl<TextBlock>("FontInfoTextBlock")!;
|
||||
|
||||
@@ -43,6 +43,24 @@
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="Window" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
<StackPanel Spacing="4"
|
||||
Margin="0,4,0,0">
|
||||
<TextBlock x:Name="CurrentRenderBackendLabelTextBlock"
|
||||
Text="Current actual backend"
|
||||
FontSize="12"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||
<TextBlock x:Name="CurrentRenderBackendValueTextBlock"
|
||||
Text="Current backend: Software"
|
||||
FontSize="13"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||
<TextBlock x:Name="CurrentRenderBackendImplementationTextBlock"
|
||||
Text="Runtime implementation is unavailable."
|
||||
FontSize="12"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{DynamicResource AdaptiveTextSecondaryBrush}" />
|
||||
</StackPanel>
|
||||
<ui:SettingsExpander.Footer>
|
||||
<ComboBox x:Name="AppRenderModeComboBox"
|
||||
MinWidth="180"
|
||||
|
||||
@@ -192,6 +192,9 @@ public partial class SettingsWindow
|
||||
internal FluentAvalonia.UI.Controls.SettingsExpander AboutRenderModeSettingsExpander => AboutSettingsPanel.FindControl<FluentAvalonia.UI.Controls.SettingsExpander>("AboutRenderModeSettingsExpander")!;
|
||||
internal ToggleSwitch AutoStartWithWindowsToggleSwitch => AboutSettingsPanel.FindControl<ToggleSwitch>("AutoStartWithWindowsToggleSwitch")!;
|
||||
internal ComboBox AppRenderModeComboBox => AboutSettingsPanel.FindControl<ComboBox>("AppRenderModeComboBox")!;
|
||||
internal TextBlock CurrentRenderBackendLabelTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendLabelTextBlock")!;
|
||||
internal TextBlock CurrentRenderBackendValueTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendValueTextBlock")!;
|
||||
internal TextBlock CurrentRenderBackendImplementationTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CurrentRenderBackendImplementationTextBlock")!;
|
||||
internal TextBlock VersionTextBlock => AboutSettingsPanel.FindControl<TextBlock>("VersionTextBlock")!;
|
||||
internal TextBlock CodeNameTextBlock => AboutSettingsPanel.FindControl<TextBlock>("CodeNameTextBlock")!;
|
||||
internal TextBlock FontInfoTextBlock => AboutSettingsPanel.FindControl<TextBlock>("FontInfoTextBlock")!;
|
||||
|
||||
@@ -136,6 +136,7 @@ public partial class SettingsWindow
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.AngleEgl, L("settings.about.render_mode.angle_egl", "angleEgl"));
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.Wgl, L("settings.about.render_mode.wgl", "WGL"));
|
||||
SetAppRenderModeComboItemContent(AppRenderingModeHelper.Vulkan, L("settings.about.render_mode.vulkan", "Vulkan"));
|
||||
UpdateCurrentRenderBackendStatus();
|
||||
|
||||
var placementItems = WallpaperPlacementComboBox.Items.OfType<ComboBoxItem>().ToList();
|
||||
if (placementItems.Count >= 5)
|
||||
|
||||
42
LanMountainDesktop/Views/SettingsWindow.RenderBackend.cs
Normal file
42
LanMountainDesktop/Views/SettingsWindow.RenderBackend.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using LanMountainDesktop.Services;
|
||||
|
||||
namespace LanMountainDesktop.Views;
|
||||
|
||||
public partial class SettingsWindow
|
||||
{
|
||||
private void UpdateCurrentRenderBackendStatus()
|
||||
{
|
||||
var backendInfo = AppRenderBackendDiagnostics.Detect();
|
||||
var localizedBackend = GetLocalizedRenderBackendName(backendInfo.ActualBackend);
|
||||
|
||||
CurrentRenderBackendLabelTextBlock.Text = L(
|
||||
"settings.about.render_mode.current_label",
|
||||
"Current actual backend");
|
||||
CurrentRenderBackendValueTextBlock.Text = Lf(
|
||||
"settings.about.render_mode.current_format",
|
||||
"Current backend: {0}",
|
||||
localizedBackend);
|
||||
CurrentRenderBackendImplementationTextBlock.Text = string.IsNullOrWhiteSpace(backendInfo.ImplementationTypeName)
|
||||
? L(
|
||||
"settings.about.render_mode.impl_unavailable",
|
||||
"Runtime implementation is unavailable.")
|
||||
: Lf(
|
||||
"settings.about.render_mode.impl_format",
|
||||
"Runtime implementation: {0}",
|
||||
backendInfo.ImplementationTypeName);
|
||||
}
|
||||
|
||||
private string GetLocalizedRenderBackendName(string renderBackend)
|
||||
{
|
||||
return renderBackend switch
|
||||
{
|
||||
AppRenderingModeHelper.Default => L("settings.about.render_mode.default", "Default"),
|
||||
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.unknown", "Unknown")
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user