-
Notifications
You must be signed in to change notification settings - Fork 824
Expand file tree
/
Copy pathApp.axaml.cs
More file actions
193 lines (171 loc) · 6.77 KB
/
App.axaml.cs
File metadata and controls
193 lines (171 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
using System.Diagnostics;
using System.IO;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.Threading;
using UniGetUI.Avalonia.Infrastructure;
using UniGetUI.Avalonia.Views;
using UniGetUI.Avalonia.Views.DialogPages;
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.PackageEngine;
using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings;
namespace UniGetUI.Avalonia;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
#if AVALONIA_DIAGNOSTICS_ENABLED
this.AttachDeveloperTools();
#endif
string platform = OperatingSystem.IsWindows() ? "Windows"
: OperatingSystem.IsMacOS() ? "macOS"
: "Linux";
Styles.Add(new StyleInclude(new Uri("avares://UniGetUI.Avalonia/"))
{
Source = new Uri($"avares://UniGetUI.Avalonia/Assets/Styles/Styles.{platform}.axaml")
});
}
public override void OnFrameworkInitializationCompleted()
{
if (OperatingSystem.IsWindows())
{
// Redirect WebView2 user-data folder to a writable temp location.
// Without this, WebView2 tries to write next to the executable in
// C:\Program Files\, which is read-only for non-admin users and
// causes UnauthorizedAccessException (E_ACCESSDENIED) on startup.
SetUpWebViewUserDataFolder();
// Safety net for NativeWebView (WebView2) initialization failures thrown
// asynchronously on the dispatcher. Without this the app crashes; with it
// the Help page shows a fallback "Open in browser" button.
Dispatcher.UIThread.UnhandledException += (_, e) =>
{
if (e.Exception is InvalidOperationException { Message: var msg }
&& msg.Contains("child window for native control host"))
{
e.Handled = true;
}
};
}
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
if (OperatingSystem.IsMacOS())
{
ExpandMacOSPath();
using var stream = AssetLoader.Open(new Uri("avares://UniGetUI.Avalonia/Assets/icon.png"));
using var ms = new MemoryStream();
stream.CopyTo(ms);
MacOsNotificationBridge.SetDockIcon(ms.ToArray());
}
PEInterface.LoadLoaders();
ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme));
var mainWindow = new MainWindow();
desktop.MainWindow = mainWindow;
Program.SecondaryInstanceArgsReceived += args =>
HandleSecondaryInstanceArgs(mainWindow, args);
if (CoreData.WasDaemon)
{
// Start silently: hide the window on first open only.
// Opened fires on every Show() in Avalonia, so we must unsubscribe
// immediately or every ShowFromTray() call would hide the window again.
void HideOnce(object? s, EventArgs e)
{
mainWindow.Opened -= HideOnce;
mainWindow.Hide();
}
mainWindow.Opened += HideOnce;
}
_ = StartupAsync(mainWindow);
}
base.OnFrameworkInitializationCompleted();
}
/// <summary>
/// macOS GUI apps start with a minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin).
/// Ask the user's login shell for its full PATH so package managers (npm, pip,
/// cargo, brew-installed tools, …) can be found.
/// </summary>
private static void ExpandMacOSPath()
{
try
{
using var process = new Process
{
StartInfo = new ProcessStartInfo("zsh", ["-l", "-c", "printenv PATH"])
{
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
},
};
process.Start();
string shellPath = process.StandardOutput.ReadToEnd().Trim();
process.WaitForExit(5000);
if (!string.IsNullOrEmpty(shellPath))
Environment.SetEnvironmentVariable("PATH", shellPath);
}
catch { /* keep the existing PATH if the shell can't be launched */ }
}
private static async Task StartupAsync(MainWindow mainWindow)
{
// Show crash report from the previous session and wait for the user
// to dismiss it before continuing with normal startup.
if (File.Exists(CrashHandler.PendingCrashFile))
{
try
{
string report = File.ReadAllText(CrashHandler.PendingCrashFile);
File.Delete(CrashHandler.PendingCrashFile);
// Yield once so the main window has time to open before
// ShowDialog tries to attach to it as owner.
await Task.Yield();
// ShowDialog requires a visible owner. In daemon mode the main window
// is hidden, so temporarily show it and re-hide after the dialog closes.
bool reshide = CoreData.WasDaemon;
if (reshide) mainWindow.Show();
await new CrashReportWindow(report).ShowDialog(mainWindow);
if (reshide) mainWindow.Hide();
}
catch { /* must not prevent normal startup */ }
}
await AvaloniaBootstrapper.InitializeAsync();
}
private static void HandleSecondaryInstanceArgs(MainWindow mainWindow, string[] args)
{
bool isDaemonLaunch = args.Contains(AvaloniaCliHandler.DAEMON);
CoreData.IsDaemon = isDaemonLaunch;
if (isDaemonLaunch)
return;
if (!mainWindow.IsVisible)
mainWindow.Show();
mainWindow.Activate();
}
public static void ApplyTheme(string value)
{
Current!.RequestedThemeVariant = value switch
{
"light" => ThemeVariant.Light,
"dark" => ThemeVariant.Dark,
_ => ThemeVariant.Default,
};
}
private static void SetUpWebViewUserDataFolder()
{
try
{
string webViewPath = Path.Join(Path.GetTempPath(), "UniGetUI", "WebView");
if (!Directory.Exists(webViewPath))
Directory.CreateDirectory(webViewPath);
Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", webViewPath);
}
catch (Exception e)
{
Logger.Warn("Could not set up data folder for WebView2");
Logger.Warn(e);
}
}
}