MainWindow.xaml.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Threading.Tasks; 7 using ManagedCommon; 8 using Microsoft.PowerLauncher.Telemetry; 9 using Microsoft.PowerToys.Settings.UI.Helpers; 10 using Microsoft.PowerToys.Settings.UI.Library; 11 using Microsoft.PowerToys.Settings.UI.Library.Helpers; 12 using Microsoft.PowerToys.Settings.UI.Views; 13 using Microsoft.PowerToys.Telemetry; 14 using Microsoft.UI; 15 using Microsoft.UI.Windowing; 16 using Microsoft.UI.Xaml; 17 using Windows.Data.Json; 18 using WinRT.Interop; 19 using WinUIEx; 20 21 namespace Microsoft.PowerToys.Settings.UI 22 { 23 public sealed partial class MainWindow : WindowEx 24 { 25 public MainWindow(bool createHidden = false) 26 { 27 var bootTime = new System.Diagnostics.Stopwatch(); 28 bootTime.Start(); 29 30 this.Activated += Window_Activated_SetIcon; 31 32 App.ThemeService.ThemeChanged += OnThemeChanged; 33 App.ThemeService.ApplyTheme(); 34 35 this.ExtendsContentIntoTitleBar = true; 36 37 ShellPage.SetElevationStatus(App.IsElevated); 38 ShellPage.SetIsUserAnAdmin(App.IsUserAnAdmin); 39 40 var hWnd = WindowNative.GetWindowHandle(this); 41 var placement = WindowHelper.DeserializePlacementOrDefault(hWnd); 42 if (createHidden) 43 { 44 placement.ShowCmd = NativeMethods.SW_HIDE; 45 46 // Restore the last known placement on the first activation 47 this.Activated += Window_Activated; 48 } 49 50 NativeMethods.SetWindowPlacement(hWnd, ref placement); 51 52 var loader = ResourceLoaderInstance.ResourceLoader; 53 Title = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title"); 54 55 // send IPC Message 56 ShellPage.SetDefaultSndMessageCallback(msg => 57 { 58 // IPC Manager is null when launching runner directly 59 App.GetTwoWayIPCManager()?.Send(msg); 60 }); 61 62 // send IPC Message 63 ShellPage.SetRestartAdminSndMessageCallback(msg => 64 { 65 App.GetTwoWayIPCManager()?.Send(msg); 66 Environment.Exit(0); // close application 67 }); 68 69 // send IPC Message 70 ShellPage.SetCheckForUpdatesMessageCallback(msg => 71 { 72 App.GetTwoWayIPCManager()?.Send(msg); 73 }); 74 75 // open main window 76 ShellPage.SetOpenMainWindowCallback(type => 77 { 78 DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => 79 App.OpenSettingsWindow(type)); 80 }); 81 82 // open main window 83 ShellPage.SetUpdatingGeneralSettingsCallback((ModuleType moduleType, bool isEnabled) => 84 { 85 SettingsRepository<GeneralSettings> repository = SettingsRepository<GeneralSettings>.GetInstance(SettingsUtils.Default); 86 GeneralSettings generalSettingsConfig = repository.SettingsConfig; 87 bool needToUpdate = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType) != isEnabled; 88 89 if (needToUpdate) 90 { 91 ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, moduleType, isEnabled); 92 var outgoing = new OutGoingGeneralSettings(generalSettingsConfig); 93 94 // Save settings to file 95 SettingsUtils.Default.SaveSettings(generalSettingsConfig.ToJsonString()); 96 97 // Send IPC message asynchronously to avoid blocking UI and potential recursive calls 98 Task.Run(() => 99 { 100 ShellPage.SendDefaultIPCMessage(outgoing.ToString()); 101 }); 102 103 ShellPage.ShellHandler?.SignalGeneralDataUpdate(); 104 } 105 106 return needToUpdate; 107 }); 108 109 // open oobe 110 ShellPage.SetOpenOobeCallback(() => 111 { 112 if (App.GetOobeWindow() == null) 113 { 114 App.SetOobeWindow(new OobeWindow(OOBE.Enums.PowerToysModules.Overview)); 115 } 116 117 App.GetOobeWindow().Activate(); 118 }); 119 120 // open whats new window 121 ShellPage.SetOpenWhatIsNewCallback(() => 122 { 123 if (App.GetScoobeWindow() == null) 124 { 125 App.SetScoobeWindow(new ScoobeWindow()); 126 } 127 128 App.GetScoobeWindow().Activate(); 129 }); 130 131 this.InitializeComponent(); 132 SetAppTitleBar(); 133 134 // receive IPC Message 135 App.IPCMessageReceivedCallback = (string msg) => 136 { 137 if (ShellPage.ShellHandler.IPCResponseHandleList != null) 138 { 139 var success = JsonObject.TryParse(msg, out JsonObject json); 140 if (success) 141 { 142 foreach (Action<JsonObject> handle in ShellPage.ShellHandler.IPCResponseHandleList) 143 { 144 handle(json); 145 } 146 } 147 else 148 { 149 Logger.LogError("Failed to parse JSON from IPC message."); 150 } 151 } 152 }; 153 154 bootTime.Stop(); 155 156 PowerToysTelemetry.Log.WriteEvent(new SettingsBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds }); 157 } 158 159 private void SetAppTitleBar() 160 { 161 // We need to assign the window here so it can configure the custom title bar area correctly. 162 shellPage.TitleBar.Window = this; 163 WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(WindowNative.GetWindowHandle(this)); 164 } 165 166 public void NavigateToSection(System.Type type) 167 { 168 ShellPage.Navigate(type); 169 } 170 171 public void CloseHiddenWindow() 172 { 173 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); 174 if (!NativeMethods.IsWindowVisible(hWnd)) 175 { 176 Close(); 177 } 178 } 179 180 private void Window_Closed(object sender, WindowEventArgs args) 181 { 182 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); 183 WindowHelper.SerializePlacement(hWnd); 184 185 if (App.GetOobeWindow() == null && App.GetScoobeWindow() == null) 186 { 187 App.ClearSettingsWindow(); 188 } 189 else 190 { 191 args.Handled = true; 192 NativeMethods.ShowWindow(hWnd, NativeMethods.SW_HIDE); 193 } 194 195 App.ThemeService.ThemeChanged -= OnThemeChanged; 196 } 197 198 private void Window_Activated_SetIcon(object sender, WindowActivatedEventArgs args) 199 { 200 // Set window icon 201 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); 202 WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd); 203 AppWindow appWindow = AppWindow.GetFromWindowId(windowId); 204 appWindow.SetIcon("Assets\\Settings\\icon.ico"); 205 } 206 207 private void Window_Activated(object sender, WindowActivatedEventArgs args) 208 { 209 if (args.WindowActivationState != WindowActivationState.Deactivated) 210 { 211 this.Activated -= Window_Activated; 212 var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); 213 var placement = WindowHelper.DeserializePlacementOrDefault(hWnd); 214 NativeMethods.SetWindowPlacement(hWnd, ref placement); 215 } 216 } 217 218 private void OnThemeChanged(object sender, ElementTheme theme) 219 { 220 WindowHelper.SetTheme(this, theme); 221 } 222 223 internal void EnsurePageIsSelected() 224 { 225 ShellPage.EnsurePageIsSelected(); 226 } 227 } 228 }