Immersive dark mode + Theme Listener (#18315)

* C++ impl of immersive dark mode

* Stop using the hardcoded value.

* Conjured up theme listener based on registry.

* Update MainWindow.xaml.cpp

* Update expect.txt

* Moved themehelpers to the common themes lib.

* Ported theme helpers back to .NET

* Update expect.txt

* Updated C# Theme Listening logic to mimic the one from Windows Community Toolkit.

* Replaced unmanaged code for RegisterForImmersiveDarkMode with unmanaged ThemeListener class.

* Fix upstream changes

* Update ThemeListener.h

* Update ThemeListener.h

* Proper formatting

* Added handler to Keyboard Manager.

* Update EditKeyboardWindow.cpp

* Added dwmapi.lib to runner, removed condition from additional dependencies.

* Update PowerRenameUI.vcxproj

* Added new deps for ManagedCommon to Product.wxs

* Crude attempts and understanding installer

* Removed Microsoft.Win32.Registry.dll from product.wxs.

* Updated dictionary

* Renamed ThemeListener class file for consistency, removed unused CheckImmersiveDarkMode in theme_helpers.

* Update Themes.vcxproj

* Update theme_listener.cpp

* Removed SupportsImmersiveDarkMode version check

* Removed SupportsImmersiveDarkMode version check

* Whoops

* Update expect.txt
This commit is contained in:
William Bradley
2022-07-01 21:52:48 +12:00
committed by GitHub
parent e637902892
commit b7fccc3211
22 changed files with 393 additions and 78 deletions

View File

@@ -15,7 +15,6 @@ using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using WinRT.Interop;
namespace Microsoft.PowerToys.Settings.UI
@@ -73,7 +72,7 @@ namespace Microsoft.PowerToys.Settings.UI
{
if (settingsWindow == null)
{
settingsWindow = new MainWindow();
settingsWindow = new MainWindow(IsDarkTheme());
}
settingsWindow.Activate();
@@ -88,6 +87,7 @@ namespace Microsoft.PowerToys.Settings.UI
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
var cmdArgs = Environment.GetCommandLineArgs();
var isDark = IsDarkTheme();
if (cmdArgs != null && cmdArgs.Length >= RequiredArgumentsQty)
{
@@ -143,7 +143,7 @@ namespace Microsoft.PowerToys.Settings.UI
if (!ShowOobe && !ShowScoobe)
{
settingsWindow = new MainWindow();
settingsWindow = new MainWindow(isDark);
settingsWindow.Activate();
settingsWindow.NavigateToSection(StartupPage);
}
@@ -152,19 +152,19 @@ namespace Microsoft.PowerToys.Settings.UI
// 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);
settingsWindow = new MainWindow(isDark, true);
if (ShowOobe)
{
PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent());
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview);
OobeWindow oobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.Overview, isDark);
oobeWindow.Activate();
SetOobeWindow(oobeWindow);
}
else if (ShowScoobe)
{
PowerToysTelemetry.Log.WriteEvent(new ScoobeStartedEvent());
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew);
OobeWindow scoobeWindow = new OobeWindow(OOBE.Enums.PowerToysModules.WhatsNew, isDark);
scoobeWindow.Activate();
SetOobeWindow(scoobeWindow);
}
@@ -174,7 +174,7 @@ namespace Microsoft.PowerToys.Settings.UI
{
// For debugging purposes
// Window is also needed to show MessageDialog
settingsWindow = new MainWindow();
settingsWindow = new MainWindow(isDark);
settingsWindow.Activate();
ShowMessageDialog("The application cannot be run as a standalone process. Please start the application through the runner.", "Forbidden");
}
@@ -203,18 +203,50 @@ namespace Microsoft.PowerToys.Settings.UI
return ipcmanager;
}
public static string SelectedTheme()
{
return SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpper(CultureInfo.InvariantCulture);
}
public static bool IsDarkTheme()
{
var selectedTheme = SettingsRepository<GeneralSettings>.GetInstance(settingsUtils).SettingsConfig.Theme.ToUpper(CultureInfo.InvariantCulture);
var defaultTheme = new UISettings();
var uiTheme = defaultTheme.GetColorValue(UIColorType.Background).ToString(System.Globalization.CultureInfo.InvariantCulture);
return selectedTheme == "DARK" || (selectedTheme == "SYSTEM" && uiTheme == "#FF000000");
var selectedTheme = SelectedTheme();
return selectedTheme == "DARK" || (selectedTheme == "SYSTEM" && ThemeHelpers.GetAppTheme() == AppTheme.Dark);
}
public static void HandleThemeChange()
{
var isDark = IsDarkTheme();
if (settingsWindow != null)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(settingsWindow);
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
}
if (oobeWindow != null)
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(oobeWindow);
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
}
var selectedTheme = SelectedTheme();
if (selectedTheme == "SYSTEM")
{
themeListener = new ThemeListener();
themeListener.ThemeChanged += (_) => HandleThemeChange();
}
else if (themeListener != null)
{
themeListener.Dispose();
themeListener = null;
}
}
private static ISettingsUtils settingsUtils = new SettingsUtils();
private static MainWindow settingsWindow;
private static OobeWindow oobeWindow;
private static ThemeListener themeListener;
public static void ClearSettingsWindow()
{

View File

@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Drawing;
using ManagedCommon;
using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
@@ -22,7 +22,7 @@ namespace Microsoft.PowerToys.Settings.UI
/// </summary>
public sealed partial class MainWindow : Window
{
public MainWindow(bool createHidden = false)
public MainWindow(bool isDark, bool createHidden = false)
{
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
@@ -36,6 +36,12 @@ namespace Microsoft.PowerToys.Settings.UI
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
appWindow.SetIcon("icon.ico");
// Passed by parameter, as it needs to be evaluated ASAP, otherwise there is a white flash
if (isDark)
{
ThemeHelpers.SetImmersiveDarkMode(hWnd, isDark);
}
var placement = Utils.DeserializePlacementOrDefault(hWnd);
if (createHidden)
{
@@ -72,7 +78,7 @@ namespace Microsoft.PowerToys.Settings.UI
{
if (App.GetOobeWindow() == null)
{
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.Overview));
App.SetOobeWindow(new OobeWindow(Microsoft.PowerToys.Settings.UI.OOBE.Enums.PowerToysModules.Overview, App.IsDarkTheme()));
}
App.GetOobeWindow().Activate();

View File

@@ -4,6 +4,7 @@
using System;
using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
using Microsoft.PowerToys.Settings.UI.OOBE.Views;
@@ -30,7 +31,7 @@ namespace Microsoft.PowerToys.Settings.UI
private IntPtr _hWnd;
private AppWindow _appWindow;
public OobeWindow(PowerToysModules initialModule)
public OobeWindow(PowerToysModules initialModule, bool isDark)
{
this.InitializeComponent();
@@ -40,6 +41,12 @@ namespace Microsoft.PowerToys.Settings.UI
_appWindow = AppWindow.GetFromWindowId(_windowId);
_appWindow.SetIcon("icon.ico");
// Passed by parameter, as it needs to be evaluated ASAP, otherwise there is a white flash
if (isDark)
{
ThemeHelpers.SetImmersiveDarkMode(_hWnd, isDark);
}
OverlappedPresenter presenter = _appWindow.Presenter as OverlappedPresenter;
presenter.IsMinimizable = false;
presenter.IsMaximizable = false;

View File

@@ -78,6 +78,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
break;
}
App.HandleThemeChange();
return 0;
}