PowerToys/src/modules/launcher/PowerLauncher/App.xaml.cs

300 lines
10 KiB
C#
Raw Normal View History

2020-08-18 01:00:56 +08:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
2020-08-18 01:00:56 +08:00
using System.Windows;
using Common.UI;
using interop;
2020-08-18 01:00:56 +08:00
using ManagedCommon;
using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Telemetry;
using PowerLauncher.Helper;
2020-11-04 04:45:01 +08:00
using PowerLauncher.Plugin;
2020-08-18 01:00:56 +08:00
using PowerLauncher.ViewModel;
using Wox;
using Wox.Infrastructure;
using Wox.Infrastructure.Image;
using Wox.Infrastructure.UserSettings;
using Wox.Plugin;
using Wox.Plugin.Logger;
2020-08-18 01:00:56 +08:00
using Stopwatch = Wox.Infrastructure.Stopwatch;
namespace PowerLauncher
{
public partial class App : IDisposable, ISingleInstanceApp
{
public static PublicAPIInstance API { get; private set; }
2020-08-22 03:40:31 +08:00
private static bool _disposed;
[fxcop] Wox.Infrastructure (#7590) * CA1052: Static holder types should be Static or NotInheritable * CA1041: Provide ObsoleteAttribute message * CA1062: Validate arguments of public methods * CA1304: Specify CultureInfo / CA1305: Specify IFormatProvider / CA1307: Specify StringComparison for clarity * CA1802: Use Literals Where Appropriate * CA1820: Test for empty strings using string length * CA1707: Identifiers should not contain underscores * CA1805: Do not initialize unnecessarily. * CA1822: Mark members as static * CA2227: Collection properties should be read only * CA1054: URI parameters should not be strings * CA1031: Do not catch general exception types * CA1060: Move P/Invokes to NativeMethods class * CA1308: Normalize strings to uppercase * CA2000: Dispose objects before losing scope / CA2234: Pass System.Uri objects instead of strings * CA2234: Pass System.Uri objects instead of strings * CA1044: Properties should not be write only * CA1716: Identifiers should not match keywords * CA2007: Do not directly await a Task * CA2007: Do not directly await a Task (Suppressed) * CA5350: Do Not Use Weak Cryptographic Algorithms (Suppressed) * CA1724: Type names should not match namespaces (renamed Settings.cs to PowerToysRunSettings.cs) * CA1033: Interface methods should be callable by child types (Added sealed modifier to class) * CA1724: Type names should not match namespaces (Renamed Plugin.cs to RunPlugin.cs) * CA1724: Type names should not match namespaces (Renamed Http.cs to HttpClient.cs) * CA5364: Do not use deprecated security protocols (Remove unused code) * Enabled FxCopAnalyzer for Wox.Infrastructure * fixed comment * Addressed comments - Changed Ordinal to InvariantCulture - Added comments - Removed unused obsolete code - Removed unused method (CA2007: Do not directly await a Task) * Addressed comments - fixed justification for CA1031 suppression * Addressed comments - Fixed justification for CA1031 suppression in Wox.Core/Wox.Plugin
2020-10-30 08:52:35 +08:00
private PowerToysRunSettings _settings;
2020-08-18 01:00:56 +08:00
private MainViewModel _mainVM;
private MainWindow _mainWindow;
private ThemeManager _themeManager;
private SettingWindowViewModel _settingsVM;
private StringMatcher _stringMatcher;
private SettingsReader _settingsReader;
2020-08-18 01:00:56 +08:00
// To prevent two disposals running at the same time.
private static readonly object _disposingLock = new object();
2020-08-18 01:00:56 +08:00
[STAThread]
public static void Main()
2020-08-18 01:00:56 +08:00
{
Log.Info($"Starting PowerToys Run with PID={Environment.ProcessId}", typeof(App));
int powerToysPid = GetPowerToysPId();
if (powerToysPid != 0)
2020-08-18 01:00:56 +08:00
{
// The process started from the PT Run module interface. One instance is handled there.
Log.Info($"Runner pid={powerToysPid}", typeof(App));
SingleInstance<App>.CreateInstanceMutex();
}
else
{
// If PT Run is started as standalone application check if there is already running instance
if (!SingleInstance<App>.InitializeAsFirstInstance())
{
Log.Warn("There is already running PowerToys Run instance. Exiting PowerToys Run", typeof(App));
return;
}
}
using (var application = new App())
{
application.InitializeComponent();
new Thread(() =>
2020-08-18 01:00:56 +08:00
{
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RunExitEvent());
if (eventHandle.WaitOne())
{
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
ExitPowerToys(application);
}
}).Start();
if (powerToysPid != 0)
{
RunnerHelper.WaitForPowerToysRunner(powerToysPid, () =>
{
Log.Info($"Runner with pid={powerToysPid} exited. Exiting PowerToys Run", typeof(App));
ExitPowerToys(application);
});
2020-08-18 01:00:56 +08:00
}
application.Run();
2021-05-21 22:24:33 +08:00
}
2020-08-18 01:00:56 +08:00
}
private void OnStartup(object sender, StartupEventArgs e)
{
2021-05-21 22:24:33 +08:00
Log.Info("On Startup.", GetType());
// Fix for .net 3.1.19 making PowerToys Run not adapt to DPI changes.
PowerLauncher.Helper.NativeMethods.SetProcessDPIAware();
2020-08-18 01:00:56 +08:00
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
Stopwatch.Normal("App.OnStartup - Startup cost", () =>
2020-08-18 01:00:56 +08:00
{
var textToLog = new StringBuilder();
textToLog.AppendLine("Begin PowerToys Run startup ----------------------------------------------------");
textToLog.AppendLine(CultureInfo.InvariantCulture, $"Runtime info:{ErrorReporting.RuntimeInfo()}");
2020-08-18 01:00:56 +08:00
RegisterAppDomainExceptions();
RegisterDispatcherUnhandledException();
_themeManager = new ThemeManager(this);
ImageLoader.Initialize(_themeManager.GetCurrentTheme());
_settingsVM = new SettingWindowViewModel();
_settings = _settingsVM.Settings;
_settings.StartedFromPowerToysRunner = e.Args.Contains("--started-from-runner");
2020-08-18 01:00:56 +08:00
_stringMatcher = new StringMatcher();
2020-08-18 01:00:56 +08:00
StringMatcher.Instance = _stringMatcher;
_stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision;
_mainVM = new MainViewModel(_settings);
_mainWindow = new MainWindow(_settings, _mainVM);
API = new PublicAPIInstance(_settingsVM, _mainVM, _themeManager);
_settingsReader = new SettingsReader(_settings, _themeManager);
_settingsReader.ReadSettings();
2020-08-18 01:00:56 +08:00
PluginManager.InitializePlugins(API);
Current.MainWindow = _mainWindow;
Current.MainWindow.Title = Constant.ExeFileName;
RegisterExitEvents();
_settingsReader.ReadSettingsOnChange();
2020-08-18 01:00:56 +08:00
_mainVM.MainWindowVisibility = Visibility.Visible;
_mainVM.ColdStartFix();
_themeManager.ThemeChanged += OnThemeChanged;
textToLog.AppendLine("End PowerToys Run startup ---------------------------------------------------- ");
2020-08-18 01:00:56 +08:00
bootTime.Stop();
Log.Info(textToLog.ToString(), GetType());
2020-08-18 01:00:56 +08:00
PowerToysTelemetry.Log.WriteEvent(new LauncherBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds });
// [Conditional("RELEASE")]
// check update every 5 hours
// check updates on startup
});
}
private static void ExitPowerToys(App app)
{
SingleInstance<App>.SingleInstanceMutex.Close();
try
{
app.Dispose();
}
finally
{
Environment.Exit(0);
}
}
private static int GetPowerToysPId()
{
var args = Environment.GetCommandLineArgs();
for (int i = 0; i + 1 < args.Length; i++)
{
if (args[i] == "-powerToysPid")
{
int powerToysPid;
if (int.TryParse(args[i + 1], out powerToysPid))
{
return powerToysPid;
}
break;
}
}
return 0;
}
2020-08-18 01:00:56 +08:00
private void RegisterExitEvents()
{
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
Log.Info("AppDomain.CurrentDomain.ProcessExit", GetType());
Dispose();
};
Current.Exit += (s, e) =>
{
Log.Info("Application.Current.Exit", GetType());
Dispose();
};
Current.SessionEnding += (s, e) =>
{
Log.Info("Application.Current.SessionEnding", GetType());
Dispose();
};
2020-08-18 01:00:56 +08:00
}
/// <summary>
/// Callback when windows theme is changed.
/// </summary>
/// <param name="oldTheme">Previous Theme</param>
/// <param name="newTheme">Current Theme</param>
private void OnThemeChanged(Theme oldTheme, Theme newTheme)
{
ImageLoader.UpdateIconPath(newTheme);
_mainVM.Query();
2020-08-18 01:00:56 +08:00
}
/// <summary>
/// let exception throw as normal is better for Debug
/// </summary>
[Conditional("RELEASE")]
private void RegisterDispatcherUnhandledException()
{
DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
}
/// <summary>
/// let exception throw as normal is better for Debug
/// </summary>
[Conditional("RELEASE")]
private static void RegisterAppDomainExceptions()
{
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
}
public void OnSecondAppStarted()
{
Current.MainWindow.Visibility = Visibility.Visible;
}
protected virtual void Dispose(bool disposing)
{
// Prevent two disposes at the same time.
lock (_disposingLock)
{
if (!disposing)
{
return;
}
if (_disposed)
{
return;
}
_disposed = true;
}
Stopwatch.Normal("App.OnExit - Exit cost", () =>
2020-08-18 01:00:56 +08:00
{
Log.Info("Start PowerToys Run Exit---------------------------------------------------- ", GetType());
if (disposing)
2020-08-18 01:00:56 +08:00
{
if (_themeManager != null)
2020-08-18 01:00:56 +08:00
{
_themeManager.ThemeChanged -= OnThemeChanged;
2020-08-18 01:00:56 +08:00
}
API?.SaveAppAllSettings();
PluginManager.Dispose();
[build]Update to .net 6 framework and VS 2022 (#15741) * Update release.yml * Update ColorPickerUI.csproj * Update release.yml adding in .net6 sdk and moving stuff sooner * Update release.yml * Update release.yml * fixing test * Forcing vs17 and adding in .net 6 sdk * forcing pool * fixing issues in each pipeline * moving release .net up * fixing diff on agent version for nuget installer * Removing system.text.json.dll as included now * getting unit tests it looks like to work * updating everythign to .net 6 minus wxs for runtime * unit test still have * getting 6.0 stuff up and going. Terminal Unit tests have file max length issue .... * found i think the last .net 5 issue * looks like i wasn't aggressive enough with the 6.0 upgrade * Getting stuff .net 6 buildable again * tweaking with new stuff for installer * Update newly added merged projects to .net 6 * Fix HeatDirectory bug on VS 2022 * Settings still needs JSON dependency * Revert "getting 6.0 stuff up and going. Terminal Unit tests have file max length issue ...." This reverts commit b9cb4586dcaf693272b8bd895fc19783421262cc. * Update sln version * supress obsolete warning, since this is not a new development * Partially Revert "Getting stuff .net 6 buildable again" This reverts commit 42b4201c6bb36354fb9d7d7935403dcb5b45a17c. * supress another obsolete warning, since this is not a new development * Reduce the unit test project name to avoid MAX PATH in CI * Upgrade project's toolset in the main solution * Some TODOs to review HttpClient usage * Upgrade project toolsets from other solutions * Install .net 6 instead of .net 5 * Fix issue when disabling PowerToys Run on .net framework 6 * Update docs for Visual Studio 2022 * PR comments: manually upgrade missing VS 2019 references * Discard no discard values to solve compiler warnings Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2022-02-07 22:08:30 +08:00
// Dispose needs to be called on the main Windows thread, since some resources owned by the thread need to be disposed.
_mainWindow?.Dispatcher.Invoke(Dispose);
API?.Dispose();
_mainVM?.Dispose();
_themeManager?.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
Log.Info("End PowerToys Run Exit ---------------------------------------------------- ", GetType());
});
2020-08-18 01:00:56 +08:00
}
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~App()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}