2020-04-11 06:22:07 +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.
|
|
|
|
|
|
2022-04-20 04:00:28 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
2021-02-26 19:21:58 +08:00
|
|
|
|
using System.Globalization;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using interop;
|
|
|
|
|
using ManagedCommon;
|
2020-10-30 05:24:16 +08:00
|
|
|
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
2021-02-26 19:21:58 +08:00
|
|
|
|
using Microsoft.PowerToys.Settings.UI.Library;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
|
2022-07-05 20:25:25 +08:00
|
|
|
|
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
using Microsoft.PowerToys.Telemetry;
|
|
|
|
|
using Microsoft.UI.Xaml;
|
|
|
|
|
using Windows.UI.Popups;
|
|
|
|
|
using WinRT.Interop;
|
2020-03-07 09:46:51 +08:00
|
|
|
|
|
2020-03-12 01:43:32 +08:00
|
|
|
|
namespace Microsoft.PowerToys.Settings.UI
|
2020-03-07 09:46:51 +08:00
|
|
|
|
{
|
2022-04-20 04:00:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Provides application-specific behavior to supplement the default Application class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public partial class App : Application
|
2020-03-07 09:46:51 +08:00
|
|
|
|
{
|
2022-04-20 04:00:28 +08:00
|
|
|
|
private enum Arguments
|
|
|
|
|
{
|
|
|
|
|
PTPipeName = 1,
|
|
|
|
|
SettingsPipeName,
|
|
|
|
|
PTPid,
|
|
|
|
|
Theme, // used in the old settings
|
|
|
|
|
ElevatedStatus,
|
|
|
|
|
IsUserAdmin,
|
|
|
|
|
ShowOobeWindow,
|
|
|
|
|
ShowScoobeWindow,
|
|
|
|
|
SettingsWindow,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Quantity of arguments
|
|
|
|
|
private const int RequiredArgumentsQty = 9;
|
|
|
|
|
private const int RequiredAndOptionalArgumentsQty = 10;
|
|
|
|
|
|
|
|
|
|
// Create an instance of the IPC wrapper.
|
|
|
|
|
private static TwoWayPipeMessageIPCManaged ipcmanager;
|
|
|
|
|
|
|
|
|
|
public static bool IsElevated { get; set; }
|
|
|
|
|
|
|
|
|
|
public static bool IsUserAnAdmin { get; set; }
|
|
|
|
|
|
|
|
|
|
public static int PowerToysPID { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool ShowOobe { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool ShowScoobe { get; set; }
|
|
|
|
|
|
|
|
|
|
public Type StartupPage { get; set; } = typeof(Views.GeneralPage);
|
|
|
|
|
|
|
|
|
|
public static Action<string> IPCMessageReceivedCallback { get; set; }
|
|
|
|
|
|
2022-07-05 20:25:25 +08:00
|
|
|
|
private static bool loggedImmersiveDarkException;
|
|
|
|
|
|
2022-04-20 04:00:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="App"/> class.
|
|
|
|
|
/// Initializes the singleton application object. This is the first line of authored code
|
|
|
|
|
/// executed, and as such is the logical equivalent of main() or WinMain().
|
|
|
|
|
/// </summary>
|
2020-03-07 09:46:51 +08:00
|
|
|
|
public App()
|
|
|
|
|
{
|
2022-04-20 04:00:28 +08:00
|
|
|
|
this.InitializeComponent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void OpenSettingsWindow(Type type)
|
|
|
|
|
{
|
|
|
|
|
if (settingsWindow == null)
|
|
|
|
|
{
|
2022-07-01 17:52:48 +08:00
|
|
|
|
settingsWindow = new MainWindow(IsDarkTheme());
|
2022-04-20 04:00:28 +08:00
|
|
|
|
}
|
2020-05-10 05:10:57 +08:00
|
|
|
|
|
2022-04-20 04:00:28 +08:00
|
|
|
|
settingsWindow.Activate();
|
|
|
|
|
settingsWindow.NavigateToSection(type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Invoked when the application is launched normally by the end user. Other entry points
|
|
|
|
|
/// will be used such as when the application is launched to open a specific file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="args">Details about the launch request and process.</param>
|
|
|
|
|
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
var cmdArgs = Environment.GetCommandLineArgs();
|
2022-07-01 17:52:48 +08:00
|
|
|
|
var isDark = IsDarkTheme();
|
2022-04-20 04:00:28 +08:00
|
|
|
|
|
|
|
|
|
if (cmdArgs != null && cmdArgs.Length >= RequiredArgumentsQty)
|
|
|
|
|
{
|
|
|
|
|
// Skip the first argument which is prepended when launched by explorer
|
|
|
|
|
if (cmdArgs[0].EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) && cmdArgs[1].EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase) && (cmdArgs.Length >= RequiredArgumentsQty + 1))
|
|
|
|
|
{
|
|
|
|
|
cmdArgs = cmdArgs.Skip(1).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ = int.TryParse(cmdArgs[(int)Arguments.PTPid], out int powerToysPID);
|
|
|
|
|
PowerToysPID = powerToysPID;
|
|
|
|
|
|
|
|
|
|
IsElevated = cmdArgs[(int)Arguments.ElevatedStatus] == "true";
|
|
|
|
|
IsUserAnAdmin = cmdArgs[(int)Arguments.IsUserAdmin] == "true";
|
|
|
|
|
ShowOobe = cmdArgs[(int)Arguments.ShowOobeWindow] == "true";
|
|
|
|
|
ShowScoobe = cmdArgs[(int)Arguments.ShowScoobeWindow] == "true";
|
|
|
|
|
|
|
|
|
|
if (cmdArgs.Length == RequiredAndOptionalArgumentsQty)
|
|
|
|
|
{
|
|
|
|
|
// open specific window
|
|
|
|
|
switch (cmdArgs[(int)Arguments.SettingsWindow])
|
|
|
|
|
{
|
|
|
|
|
case "Overview": StartupPage = typeof(Views.GeneralPage); break;
|
|
|
|
|
case "AlwaysOnTop": StartupPage = typeof(Views.AlwaysOnTopPage); break;
|
|
|
|
|
case "Awake": StartupPage = typeof(Views.AwakePage); break;
|
|
|
|
|
case "ColorPicker": StartupPage = typeof(Views.ColorPickerPage); break;
|
|
|
|
|
case "FancyZones": StartupPage = typeof(Views.FancyZonesPage); break;
|
|
|
|
|
case "Run": StartupPage = typeof(Views.PowerLauncherPage); break;
|
|
|
|
|
case "ImageResizer": StartupPage = typeof(Views.ImageResizerPage); break;
|
|
|
|
|
case "KBM": StartupPage = typeof(Views.KeyboardManagerPage); break;
|
|
|
|
|
case "MouseUtils": StartupPage = typeof(Views.MouseUtilsPage); break;
|
|
|
|
|
case "PowerRename": StartupPage = typeof(Views.PowerRenamePage); break;
|
2022-09-01 03:43:23 +08:00
|
|
|
|
case "QuickAccent": StartupPage = typeof(Views.PowerAccentPage); break;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
case "FileExplorer": StartupPage = typeof(Views.PowerPreviewPage); break;
|
|
|
|
|
case "ShortcutGuide": StartupPage = typeof(Views.ShortcutGuidePage); break;
|
2022-09-01 03:43:23 +08:00
|
|
|
|
case "TextExtractor": StartupPage = typeof(Views.PowerOcrPage); break;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
case "VideoConference": StartupPage = typeof(Views.VideoConferencePage); break;
|
2022-08-27 07:17:20 +08:00
|
|
|
|
case "MeasureTool": StartupPage = typeof(Views.MeasureToolPage); break;
|
2022-10-13 19:05:43 +08:00
|
|
|
|
case "Hosts": StartupPage = typeof(Views.HostsPage); break;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
default: Debug.Assert(false, "Unexpected SettingsWindow argument value"); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
|
|
|
|
{
|
|
|
|
|
Environment.Exit(0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName], cmdArgs[(int)Arguments.PTPipeName], (string message) =>
|
|
|
|
|
{
|
|
|
|
|
if (IPCMessageReceivedCallback != null && message.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
IPCMessageReceivedCallback(message);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
ipcmanager.Start();
|
|
|
|
|
|
|
|
|
|
if (!ShowOobe && !ShowScoobe)
|
|
|
|
|
{
|
2022-07-01 17:52:48 +08:00
|
|
|
|
settingsWindow = new MainWindow(isDark);
|
2022-04-20 04:00:28 +08:00
|
|
|
|
settingsWindow.Activate();
|
|
|
|
|
settingsWindow.NavigateToSection(StartupPage);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-05-19 21:12:59 +08:00
|
|
|
|
// Create the Settings window hidden so that it's fully initialized and
|
2022-04-20 04:00:28 +08:00
|
|
|
|
// it will be ready to receive the notification if the user opens
|
|
|
|
|
// the Settings from the tray icon.
|
2022-07-01 17:52:48 +08:00
|
|
|
|
settingsWindow = new MainWindow(isDark, true);
|
2022-05-19 21:12:59 +08:00
|
|
|
|
|
2022-04-20 04:00:28 +08:00
|
|
|
|
if (ShowOobe)
|
|
|
|
|
{
|
|
|
|
|
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
2022-07-01 17:52:48 +08:00
|
|
|
|
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview, isDark);
|
2022-04-20 04:00:28 +08:00
|
|
|
|
oobeWindow.Activate();
|
|
|
|
|
SetOobeWindow(oobeWindow);
|
|
|
|
|
}
|
|
|
|
|
else if (ShowScoobe)
|
|
|
|
|
{
|
|
|
|
|
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
|
2022-07-01 17:52:48 +08:00
|
|
|
|
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew, isDark);
|
2022-04-20 04:00:28 +08:00
|
|
|
|
scoobeWindow.Activate();
|
|
|
|
|
SetOobeWindow(scoobeWindow);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// For debugging purposes
|
|
|
|
|
// Window is also needed to show MessageDialog
|
2022-07-01 17:52:48 +08:00
|
|
|
|
settingsWindow = new MainWindow(isDark);
|
2022-04-20 04:00:28 +08:00
|
|
|
|
settingsWindow.Activate();
|
2022-07-27 18:39:31 +08:00
|
|
|
|
|
|
|
|
|
#if !DEBUG
|
|
|
|
|
ShowMessageDialogAndExit("The application cannot be run as a standalone process. Please start the application through the runner.", "Forbidden");
|
|
|
|
|
#else
|
2022-04-20 04:00:28 +08:00
|
|
|
|
ShowMessageDialog("The application cannot be run as a standalone process. Please start the application through the runner.", "Forbidden");
|
2022-07-27 18:39:31 +08:00
|
|
|
|
#endif
|
2022-04-20 04:00:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-27 18:39:31 +08:00
|
|
|
|
#if !DEBUG
|
|
|
|
|
private async void ShowMessageDialogAndExit(string content, string title = null)
|
|
|
|
|
#else
|
2022-04-20 04:00:28 +08:00
|
|
|
|
private async void ShowMessageDialog(string content, string title = null)
|
2022-07-27 18:39:31 +08:00
|
|
|
|
#endif
|
2022-04-20 04:00:28 +08:00
|
|
|
|
{
|
|
|
|
|
await ShowDialogAsync(content, title);
|
2022-07-27 18:39:31 +08:00
|
|
|
|
#if !DEBUG
|
|
|
|
|
this.Exit();
|
|
|
|
|
#endif
|
2022-04-20 04:00:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Task<IUICommand> ShowDialogAsync(string content, string title = null)
|
|
|
|
|
{
|
|
|
|
|
var dialog = new MessageDialog(content, title ?? string.Empty);
|
|
|
|
|
var handle = NativeMethods.GetActiveWindow();
|
|
|
|
|
if (handle == IntPtr.Zero)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitializeWithWindow.Initialize(dialog, handle);
|
|
|
|
|
return dialog.ShowAsync().AsTask<IUICommand>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static TwoWayPipeMessageIPCManaged GetTwoWayIPCManager()
|
|
|
|
|
{
|
|
|
|
|
return ipcmanager;
|
2020-03-07 09:46:51 +08:00
|
|
|
|
}
|
2021-02-26 19:21:58 +08:00
|
|
|
|
|
2022-07-01 17:52:48 +08:00
|
|
|
|
public static string SelectedTheme()
|
|
|
|
|
{
|
|
|
|
|
return SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpper(CultureInfo.InvariantCulture);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 19:21:58 +08:00
|
|
|
|
public static bool IsDarkTheme()
|
|
|
|
|
{
|
2022-07-01 17:52:48 +08:00
|
|
|
|
var selectedTheme = SelectedTheme();
|
|
|
|
|
return selectedTheme == "DARK" || (selectedTheme == "SYSTEM" && ThemeHelpers.GetAppTheme() == AppTheme.Dark);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void HandleThemeChange()
|
|
|
|
|
{
|
2022-07-05 20:25:25 +08:00
|
|
|
|
try
|
2022-07-01 17:52:48 +08:00
|
|
|
|
{
|
2022-07-05 20:25:25 +08:00
|
|
|
|
var isDark = IsDarkTheme();
|
|
|
|
|
if (settingsWindow != null)
|
|
|
|
|
{
|
|
|
|
|
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(settingsWindow);
|
|
|
|
|
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
|
|
|
|
|
}
|
2022-07-01 17:52:48 +08:00
|
|
|
|
|
2022-07-05 20:25:25 +08:00
|
|
|
|
if (oobeWindow != null)
|
|
|
|
|
{
|
|
|
|
|
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(oobeWindow);
|
|
|
|
|
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
|
|
|
|
|
}
|
2022-07-01 17:52:48 +08:00
|
|
|
|
|
2022-07-05 20:25:25 +08:00
|
|
|
|
var selectedTheme = SelectedTheme();
|
|
|
|
|
if (selectedTheme == "SYSTEM")
|
|
|
|
|
{
|
|
|
|
|
themeListener = new ThemeListener();
|
|
|
|
|
themeListener.ThemeChanged += (_) => HandleThemeChange();
|
|
|
|
|
}
|
|
|
|
|
else if (themeListener != null)
|
|
|
|
|
{
|
|
|
|
|
themeListener.Dispose();
|
|
|
|
|
themeListener = null;
|
|
|
|
|
}
|
2022-07-01 17:52:48 +08:00
|
|
|
|
}
|
2022-07-05 20:25:25 +08:00
|
|
|
|
catch (Exception e)
|
2022-07-01 17:52:48 +08:00
|
|
|
|
{
|
2022-07-05 20:25:25 +08:00
|
|
|
|
if (!loggedImmersiveDarkException)
|
|
|
|
|
{
|
|
|
|
|
Logger.LogError($"HandleThemeChange exception. Please install .NET 4.", e);
|
|
|
|
|
loggedImmersiveDarkException = true;
|
|
|
|
|
}
|
2022-07-01 17:52:48 +08:00
|
|
|
|
}
|
2021-02-26 19:21:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ISettingsUtils settingsUtils = new SettingsUtils();
|
2022-04-20 04:00:28 +08:00
|
|
|
|
|
|
|
|
|
private static MainWindow settingsWindow;
|
|
|
|
|
private static OobeWindow oobeWindow;
|
2022-07-01 17:52:48 +08:00
|
|
|
|
private static ThemeListener themeListener;
|
2022-04-20 04:00:28 +08:00
|
|
|
|
|
|
|
|
|
public static void ClearSettingsWindow()
|
|
|
|
|
{
|
|
|
|
|
settingsWindow = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MainWindow GetSettingsWindow()
|
|
|
|
|
{
|
|
|
|
|
return settingsWindow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static OobeWindow GetOobeWindow()
|
|
|
|
|
{
|
|
|
|
|
return oobeWindow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SetOobeWindow(OobeWindow window)
|
|
|
|
|
{
|
|
|
|
|
oobeWindow = window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void ClearOobeWindow()
|
|
|
|
|
{
|
|
|
|
|
oobeWindow = null;
|
|
|
|
|
}
|
2020-03-07 09:46:51 +08:00
|
|
|
|
}
|
|
|
|
|
}
|