mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
* Data diagnostics opt-in
* [c++] Drop DROP_PII flag
* Bump telemtry package to 2.0.2
* Drop DropPii from custom actions
* Cleanup
* Do not start manually C# EtwTrace. FZ engine exit event.
* ImageResizer, PowerRename, FileLocksmith prev handlers
* Revert C# handlers exe logging
* Revert "Revert C# handlers exe logging"
This reverts commit 4c75a3953b.
* Do not recreate EtwTrace
* consume package
* xaml formatting
* Fix deps.json audit
* Update telem package paths
* Address PR comments
* Fix AdvancedPaste close on PT close
* Override etl file name for explorer loaded dlls
Start/stop tracer when needed for explorer loaded dlls to prevent explorer overload
* Fix setting desc
* Fix missing events
* Add infobar to restart when enable data viewing
* Flush on timer every 30s
* [Settings] Update View Data diagnostic description text
[New+] Add tracer
* Show Restart info bar for both enable/disable data viewer
* Fix newplus
* Fix stuck on restart and terminate AdvPaste exe on destroy()
* [Installer] Add tracer
* Address PR comment
* Add missing tracers
* Exclude etw dir from BugReport
* Fix bad merge
* [Hosts] Proper exit on initial dialog
* [OOBE] Make Data diagnostic setting visible without scroll
* [OOBE] Add hiperlynk to open general settings
* Disable data view on disabling data diagnostics
* Don't disable View data button
* Fix disabling data viewing
* Add missing dot
* Revert formatting
453 lines
17 KiB
C#
453 lines
17 KiB
C#
// 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.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
|
|
using ManagedCommon;
|
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
|
using Microsoft.PowerToys.Settings.UI.Library;
|
|
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
|
|
using Microsoft.PowerToys.Settings.UI.Services;
|
|
using Microsoft.PowerToys.Settings.UI.Views;
|
|
using Microsoft.PowerToys.Telemetry;
|
|
using Microsoft.UI.Xaml;
|
|
using PowerToys.Interop;
|
|
using Windows.UI.Popups;
|
|
using WinRT.Interop;
|
|
using WinUIEx;
|
|
|
|
namespace Microsoft.PowerToys.Settings.UI
|
|
{
|
|
/// <summary>
|
|
/// Provides application-specific behavior to supplement the default Application class.
|
|
/// </summary>
|
|
public partial class App : Application
|
|
{
|
|
private enum Arguments
|
|
{
|
|
PTPipeName = 1,
|
|
SettingsPipeName,
|
|
PTPid,
|
|
Theme, // used in the old settings
|
|
ElevatedStatus,
|
|
IsUserAdmin,
|
|
ShowOobeWindow,
|
|
ShowScoobeWindow,
|
|
ShowFlyout,
|
|
ContainsSettingsWindow,
|
|
ContainsFlyoutPosition,
|
|
}
|
|
|
|
private const int RequiredArgumentsSetSettingQty = 4;
|
|
private const int RequiredArgumentsSetAdditionalSettingsQty = 4;
|
|
private const int RequiredArgumentsGetSettingQty = 3;
|
|
|
|
private const int RequiredArgumentsLaunchedFromRunnerQty = 12;
|
|
|
|
// 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 ShowFlyout { get; set; }
|
|
|
|
public bool ShowScoobe { get; set; }
|
|
|
|
public Type StartupPage { get; set; } = typeof(Views.DashboardPage);
|
|
|
|
public static Action<string> IPCMessageReceivedCallback { get; set; }
|
|
|
|
public ETWTrace EtwTrace { get; private set; } = new ETWTrace();
|
|
|
|
/// <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>
|
|
public App()
|
|
{
|
|
Logger.InitializeLogger(@"\Settings\Logs");
|
|
|
|
string appLanguage = LanguageHelper.LoadLanguage();
|
|
if (!string.IsNullOrEmpty(appLanguage))
|
|
{
|
|
Microsoft.Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = appLanguage;
|
|
}
|
|
|
|
InitializeComponent();
|
|
|
|
UnhandledException += App_UnhandledException;
|
|
|
|
NativeEventWaiter.WaitForEventLoop(
|
|
Constants.PowerToysRunnerTerminateSettingsEvent(), () =>
|
|
{
|
|
EtwTrace?.Dispose();
|
|
Environment.Exit(0);
|
|
});
|
|
}
|
|
|
|
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
|
{
|
|
Logger.LogError("Unhandled exception", e.Exception);
|
|
}
|
|
|
|
public static void OpenSettingsWindow(Type type = null, bool ensurePageIsSelected = false)
|
|
{
|
|
if (settingsWindow == null)
|
|
{
|
|
settingsWindow = new MainWindow();
|
|
}
|
|
|
|
settingsWindow.Activate();
|
|
|
|
if (type != null)
|
|
{
|
|
settingsWindow.NavigateToSection(type);
|
|
|
|
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
|
|
}
|
|
|
|
if (ensurePageIsSelected)
|
|
{
|
|
settingsWindow.EnsurePageIsSelected();
|
|
}
|
|
}
|
|
|
|
private void OnLaunchedToSetSetting(string[] cmdArgs)
|
|
{
|
|
var settingName = cmdArgs[2];
|
|
var settingValue = cmdArgs[3];
|
|
try
|
|
{
|
|
SetSettingCommandLineCommand.Execute(settingName, settingValue, new SettingsUtils());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError($"SetSettingCommandLineCommand exception: '{settingName}' setting couldn't be set to {settingValue}", ex);
|
|
}
|
|
|
|
Exit();
|
|
}
|
|
|
|
private void OnLaunchedToSetAdditionalSetting(string[] cmdArgs)
|
|
{
|
|
var moduleName = cmdArgs[2];
|
|
var ipcFileName = cmdArgs[3];
|
|
try
|
|
{
|
|
using (var settings = JsonDocument.Parse(File.ReadAllText(ipcFileName)))
|
|
{
|
|
SetAdditionalSettingsCommandLineCommand.Execute(moduleName, settings, new SettingsUtils());
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError($"SetAdditionalSettingsCommandLineCommand exception: couldn't set additional settings for '{moduleName}'", ex);
|
|
}
|
|
|
|
Exit();
|
|
}
|
|
|
|
private void OnLaunchedToGetSetting(string[] cmdArgs)
|
|
{
|
|
var ipcFileName = cmdArgs[2];
|
|
|
|
try
|
|
{
|
|
var requestedSettings = JsonSerializer.Deserialize<Dictionary<string, List<string>>>(File.ReadAllText(ipcFileName));
|
|
File.WriteAllText(ipcFileName, GetSettingCommandLineCommand.Execute(requestedSettings));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError($"GetSettingCommandLineCommand exception", ex);
|
|
}
|
|
|
|
Exit();
|
|
}
|
|
|
|
private void OnLaunchedFromRunner(string[] cmdArgs)
|
|
{
|
|
// 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 >= RequiredArgumentsLaunchedFromRunnerQty + 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";
|
|
ShowFlyout = cmdArgs[(int)Arguments.ShowFlyout] == "true";
|
|
bool containsSettingsWindow = cmdArgs[(int)Arguments.ContainsSettingsWindow] == "true";
|
|
bool containsFlyoutPosition = cmdArgs[(int)Arguments.ContainsFlyoutPosition] == "true";
|
|
|
|
// To keep track of variable arguments
|
|
int currentArgumentIndex = RequiredArgumentsLaunchedFromRunnerQty;
|
|
|
|
if (containsSettingsWindow)
|
|
{
|
|
// Open specific window
|
|
StartupPage = GetPage(cmdArgs[currentArgumentIndex]);
|
|
|
|
currentArgumentIndex++;
|
|
}
|
|
|
|
int flyout_x = 0;
|
|
int flyout_y = 0;
|
|
if (containsFlyoutPosition)
|
|
{
|
|
// get the flyout position arguments
|
|
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_x);
|
|
_ = int.TryParse(cmdArgs[currentArgumentIndex++], out flyout_y);
|
|
}
|
|
|
|
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 && !ShowFlyout)
|
|
{
|
|
settingsWindow = new MainWindow();
|
|
settingsWindow.Activate();
|
|
settingsWindow.ExtendsContentIntoTitleBar = true;
|
|
settingsWindow.NavigateToSection(StartupPage);
|
|
|
|
// https://github.com/microsoft/microsoft-ui-xaml/issues/7595 - Activate doesn't bring window to the foreground
|
|
// Need to call SetForegroundWindow to actually gain focus.
|
|
WindowHelpers.BringToForeground(settingsWindow.GetWindowHandle());
|
|
}
|
|
else
|
|
{
|
|
// Create the Settings window hidden so that it's fully initialized and
|
|
// it will be ready to receive the notification if the user opens
|
|
// the Settings from the tray icon.
|
|
settingsWindow = new MainWindow(true);
|
|
|
|
if (ShowOobe)
|
|
{
|
|
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
|
|
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
|
|
oobeWindow.Activate();
|
|
oobeWindow.ExtendsContentIntoTitleBar = true;
|
|
SetOobeWindow(oobeWindow);
|
|
}
|
|
else if (ShowScoobe)
|
|
{
|
|
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
|
|
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
|
|
scoobeWindow.Activate();
|
|
scoobeWindow.ExtendsContentIntoTitleBar = true;
|
|
SetOobeWindow(scoobeWindow);
|
|
}
|
|
else if (ShowFlyout)
|
|
{
|
|
POINT? p = null;
|
|
if (containsFlyoutPosition)
|
|
{
|
|
p = new POINT(flyout_x, flyout_y);
|
|
}
|
|
|
|
ShellPage.OpenFlyoutCallback(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <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();
|
|
|
|
if (cmdArgs?.Length >= RequiredArgumentsLaunchedFromRunnerQty)
|
|
{
|
|
OnLaunchedFromRunner(cmdArgs);
|
|
}
|
|
else if (cmdArgs?.Length == RequiredArgumentsSetSettingQty && cmdArgs[1] == "set")
|
|
{
|
|
OnLaunchedToSetSetting(cmdArgs);
|
|
}
|
|
else if (cmdArgs?.Length == RequiredArgumentsSetAdditionalSettingsQty && cmdArgs[1] == "setAdditional")
|
|
{
|
|
OnLaunchedToSetAdditionalSetting(cmdArgs);
|
|
}
|
|
else if (cmdArgs?.Length == RequiredArgumentsGetSettingQty && cmdArgs[1] == "get")
|
|
{
|
|
OnLaunchedToGetSetting(cmdArgs);
|
|
}
|
|
else
|
|
{
|
|
#if DEBUG
|
|
// For debugging purposes
|
|
// Window is also needed to show MessageDialog
|
|
settingsWindow = new MainWindow();
|
|
settingsWindow.ExtendsContentIntoTitleBar = true;
|
|
settingsWindow.Activate();
|
|
settingsWindow.NavigateToSection(StartupPage);
|
|
ShowMessageDialog("The application is running in Debug mode.", "DEBUG");
|
|
#else
|
|
/* If we try to run Settings as a standalone app, it will start PowerToys.exe if not running and open Settings again through it in the Dashboard page. */
|
|
Common.UI.SettingsDeepLink.OpenSettings(Common.UI.SettingsDeepLink.SettingsWindow.Dashboard, true);
|
|
Exit();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if !DEBUG
|
|
private async void ShowMessageDialogAndExit(string content, string title = null)
|
|
#else
|
|
private async void ShowMessageDialog(string content, string title = null)
|
|
#endif
|
|
{
|
|
await ShowDialogAsync(content, title);
|
|
#if !DEBUG
|
|
this.Exit();
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public static bool IsDarkTheme()
|
|
{
|
|
return ThemeService.Theme == ElementTheme.Dark || (ThemeService.Theme == ElementTheme.Default && ThemeHelpers.GetAppTheme() == AppTheme.Dark);
|
|
}
|
|
|
|
public static int UpdateUIThemeMethod(string themeName)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
private static ISettingsUtils settingsUtils = new SettingsUtils();
|
|
private static ThemeService themeService = new ThemeService(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils));
|
|
|
|
public static ThemeService ThemeService => themeService;
|
|
|
|
private static MainWindow settingsWindow;
|
|
private static OobeWindow oobeWindow;
|
|
private static FlyoutWindow flyoutWindow;
|
|
|
|
public static void ClearSettingsWindow()
|
|
{
|
|
settingsWindow = null;
|
|
}
|
|
|
|
public static MainWindow GetSettingsWindow()
|
|
{
|
|
return settingsWindow;
|
|
}
|
|
|
|
public static OobeWindow GetOobeWindow()
|
|
{
|
|
return oobeWindow;
|
|
}
|
|
|
|
public static FlyoutWindow GetFlyoutWindow()
|
|
{
|
|
return flyoutWindow;
|
|
}
|
|
|
|
public static void SetOobeWindow(OobeWindow window)
|
|
{
|
|
oobeWindow = window;
|
|
}
|
|
|
|
public static void SetFlyoutWindow(FlyoutWindow window)
|
|
{
|
|
flyoutWindow = window;
|
|
}
|
|
|
|
public static void ClearOobeWindow()
|
|
{
|
|
oobeWindow = null;
|
|
}
|
|
|
|
public static void ClearFlyoutWindow()
|
|
{
|
|
flyoutWindow = null;
|
|
}
|
|
|
|
public static Type GetPage(string settingWindow)
|
|
{
|
|
switch (settingWindow)
|
|
{
|
|
case "Dashboard": return typeof(DashboardPage);
|
|
case "Overview": return typeof(GeneralPage);
|
|
case "AdvancedPaste": return typeof(AdvancedPastePage);
|
|
case "AlwaysOnTop": return typeof(AlwaysOnTopPage);
|
|
case "Awake": return typeof(AwakePage);
|
|
case "CmdNotFound": return typeof(CmdNotFoundPage);
|
|
case "ColorPicker": return typeof(ColorPickerPage);
|
|
case "FancyZones": return typeof(FancyZonesPage);
|
|
case "FileLocksmith": return typeof(FileLocksmithPage);
|
|
case "Run": return typeof(PowerLauncherPage);
|
|
case "ImageResizer": return typeof(ImageResizerPage);
|
|
case "KBM": return typeof(KeyboardManagerPage);
|
|
case "MouseUtils": return typeof(MouseUtilsPage);
|
|
case "MouseWithoutBorders": return typeof(MouseWithoutBordersPage);
|
|
case "PowerRename": return typeof(PowerRenamePage);
|
|
case "QuickAccent": return typeof(PowerAccentPage);
|
|
case "FileExplorer": return typeof(PowerPreviewPage);
|
|
case "ShortcutGuide": return typeof(ShortcutGuidePage);
|
|
case "PowerOcr": return typeof(PowerOcrPage);
|
|
case "VideoConference": return typeof(VideoConferencePage);
|
|
case "MeasureTool": return typeof(MeasureToolPage);
|
|
case "Hosts": return typeof(HostsPage);
|
|
case "RegistryPreview": return typeof(RegistryPreviewPage);
|
|
case "Peek": return typeof(PeekPage);
|
|
case "CropAndLock": return typeof(CropAndLockPage);
|
|
case "EnvironmentVariables": return typeof(EnvironmentVariablesPage);
|
|
case "NewPlus": return typeof(NewPlusPage);
|
|
case "Workspaces": return typeof(WorkspacesPage);
|
|
default:
|
|
// Fallback to Dashboard
|
|
Debug.Assert(false, "Unexpected SettingsWindow argument value");
|
|
return typeof(DashboardPage);
|
|
}
|
|
}
|
|
}
|
|
}
|