// 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 ManagedCommon;
using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Windows.Data.Json;
using WinUIEx;
namespace Microsoft.PowerToys.Settings.UI
{
///
/// An empty window that can be used on its own or navigated to within a Frame.
///
public sealed partial class MainWindow : WindowEx
{
public MainWindow(bool createHidden = false)
{
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
this.Activated += Window_Activated_SetIcon;
App.ThemeService.ThemeChanged += OnThemeChanged;
App.ThemeService.ApplyTheme();
ShellPage.SetElevationStatus(App.IsElevated);
ShellPage.SetIsUserAnAdmin(App.IsUserAnAdmin);
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
var placement = WindowHelper.DeserializePlacementOrDefault(hWnd);
if (createHidden)
{
placement.ShowCmd = NativeMethods.SW_HIDE;
// Restore the last known placement on the first activation
this.Activated += Window_Activated;
}
NativeMethods.SetWindowPlacement(hWnd, ref placement);
var loader = ResourceLoaderInstance.ResourceLoader;
Title = App.IsElevated ? loader.GetString("SettingsWindow_AdminTitle") : loader.GetString("SettingsWindow_Title");
// send IPC Message
ShellPage.SetDefaultSndMessageCallback(msg =>
{
// IPC Manager is null when launching runner directly
App.GetTwoWayIPCManager()?.Send(msg);
});
// send IPC Message
ShellPage.SetRestartAdminSndMessageCallback(msg =>
{
App.GetTwoWayIPCManager()?.Send(msg);
Environment.Exit(0); // close application
});
// send IPC Message
ShellPage.SetCheckForUpdatesMessageCallback(msg =>
{
App.GetTwoWayIPCManager()?.Send(msg);
});
// open main window
ShellPage.SetOpenMainWindowCallback(type =>
{
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
App.OpenSettingsWindow(type));
});
// open main window
ShellPage.SetUpdatingGeneralSettingsCallback((ModuleType moduleType, bool isEnabled) =>
{
SettingsRepository repository = SettingsRepository.GetInstance(new SettingsUtils());
GeneralSettings generalSettingsConfig = repository.SettingsConfig;
bool needToUpdate = ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType) != isEnabled;
if (needToUpdate)
{
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, moduleType, isEnabled);
var outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{
ShellPage.SendDefaultIPCMessage(outgoing.ToString());
ShellPage.ShellHandler?.SignalGeneralDataUpdate();
});
}
return needToUpdate;
});
// open oobe
ShellPage.SetOpenOobeCallback(() =>
{
if (App.GetOobeWindow() == null)
{
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.Overview));
}
App.GetOobeWindow().Activate();
});
// open whats new window
ShellPage.SetOpenWhatIsNewCallback(() =>
{
if (App.GetOobeWindow() == null)
{
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.WhatsNew));
}
else
{
App.GetOobeWindow().SetAppWindow(OOBE.Enums.PowerToysModules.WhatsNew);
}
App.GetOobeWindow().Activate();
});
// open flyout
ShellPage.SetOpenFlyoutCallback((POINT? p) =>
{
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{
if (App.GetFlyoutWindow() == null)
{
App.SetFlyoutWindow(new FlyoutWindow(p));
}
FlyoutWindow flyout = App.GetFlyoutWindow();
flyout.FlyoutAppearPosition = p;
flyout.Activate();
// 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(flyout.GetWindowHandle());
});
});
// disable flyout hiding
ShellPage.SetDisableFlyoutHidingCallback(() =>
{
this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
{
if (App.GetFlyoutWindow() == null)
{
App.SetFlyoutWindow(new FlyoutWindow(null));
}
App.GetFlyoutWindow().ViewModel.DisableHiding();
});
});
this.InitializeComponent();
// receive IPC Message
App.IPCMessageReceivedCallback = (string msg) =>
{
if (ShellPage.ShellHandler.IPCResponseHandleList != null)
{
var success = JsonObject.TryParse(msg, out JsonObject json);
if (success)
{
foreach (Action handle in ShellPage.ShellHandler.IPCResponseHandleList)
{
handle(json);
}
}
else
{
Logger.LogError("Failed to parse JSON from IPC message.");
}
}
};
bootTime.Stop();
PowerToysTelemetry.Log.WriteEvent(new SettingsBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds });
}
public void NavigateToSection(System.Type type)
{
ShellPage.Navigate(type);
}
public void CloseHiddenWindow()
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
if (!NativeMethods.IsWindowVisible(hWnd))
{
Close();
}
}
private void Window_Closed(object sender, WindowEventArgs args)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowHelper.SerializePlacement(hWnd);
if (App.GetOobeWindow() == null)
{
App.ClearSettingsWindow();
}
else
{
args.Handled = true;
NativeMethods.ShowWindow(hWnd, NativeMethods.SW_HIDE);
}
App.ThemeService.ThemeChanged -= OnThemeChanged;
}
private void Window_Activated_SetIcon(object sender, WindowActivatedEventArgs args)
{
// Set window icon
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("Assets\\Settings\\icon.ico");
}
private void Window_Activated(object sender, WindowActivatedEventArgs args)
{
if (args.WindowActivationState != WindowActivationState.Deactivated)
{
this.Activated -= Window_Activated;
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
var placement = WindowHelper.DeserializePlacementOrDefault(hWnd);
NativeMethods.SetWindowPlacement(hWnd, ref placement);
}
}
private void OnThemeChanged(object sender, ElementTheme theme)
{
WindowHelper.SetTheme(this, theme);
}
internal void EnsurePageIsSelected()
{
ShellPage.EnsurePageIsSelected();
}
}
}