mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-27 14:59:16 +08:00
[Run] Switch to WPF UI theme manager (#30520)
* Switch to WPF UI theme manager * fix * add theme manager * fix * fix * update error icon * moved image initialization * cleanup
This commit is contained in:
parent
e73e73fa6c
commit
ae21b0dc09
@ -50,15 +50,7 @@ public partial class OCROverlay : Window
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// workaround for #30177
|
||||
try
|
||||
{
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, Wpf.Ui.Controls.WindowBackdropType.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Exception in SystemThemeWatcher.Watch, issue 30177. {ex.Message}");
|
||||
}
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, Wpf.Ui.Controls.WindowBackdropType.None);
|
||||
|
||||
PopulateLanguageMenu();
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Common.UI;
|
||||
using ImageResizer.ViewModels;
|
||||
using ManagedCommon;
|
||||
using Microsoft.Win32;
|
||||
using Wpf.Ui.Controls;
|
||||
using AppResources = ImageResizer.Properties.Resources;
|
||||
@ -31,15 +30,7 @@ namespace ImageResizer.Views
|
||||
WindowBackdropType = WindowBackdropType.None;
|
||||
}
|
||||
|
||||
// workaround for #30177
|
||||
try
|
||||
{
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, WindowBackdropType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Exception in SystemThemeWatcher.Watch, issue 30177. {ex.Message}");
|
||||
}
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, WindowBackdropType);
|
||||
}
|
||||
|
||||
public IEnumerable<string> OpenPictureFiles()
|
||||
|
@ -2,13 +2,11 @@
|
||||
x:Class="PowerLauncher.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:theming="clr-namespace:Common.UI;assembly=PowerToys.Common.UI"
|
||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||
ShutdownMode="OnMainWindowClose"
|
||||
Startup="OnStartup">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<theming:CustomLibraryThemeProvider x:Key="{x:Static theming:CustomLibraryThemeProvider.DefaultInstance}" />
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ui:ThemesDictionary Theme="Dark" />
|
||||
<ui:ControlsDictionary />
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@ -9,7 +9,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerLauncher.Telemetry;
|
||||
@ -23,7 +22,6 @@ using Wox.Infrastructure.Image;
|
||||
using Wox.Infrastructure.UserSettings;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.Logger;
|
||||
using Wpf.Ui.Appearance;
|
||||
using Stopwatch = Wox.Infrastructure.Stopwatch;
|
||||
|
||||
namespace PowerLauncher
|
||||
@ -82,7 +80,7 @@ namespace PowerLauncher
|
||||
{
|
||||
application.InitializeComponent();
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Common.UI.NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.RunExitEvent(),
|
||||
() =>
|
||||
{
|
||||
@ -122,8 +120,7 @@ namespace PowerLauncher
|
||||
RegisterAppDomainExceptions();
|
||||
RegisterDispatcherUnhandledException();
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
ImageLoader.Initialize(_themeManager.GetCurrentTheme());
|
||||
ImageLoader.Initialize();
|
||||
|
||||
_settingsVM = new SettingWindowViewModel();
|
||||
_settings = _settingsVM.Settings;
|
||||
@ -136,6 +133,7 @@ namespace PowerLauncher
|
||||
|
||||
_mainVM = new MainViewModel(_settings, NativeThreadCTS.Token);
|
||||
_mainWindow = new MainWindow(_settings, _mainVM, NativeThreadCTS.Token);
|
||||
_themeManager = new ThemeManager(_settings, _mainWindow);
|
||||
API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet, _themeManager);
|
||||
_settingsReader = new SettingsReader(_settings, _themeManager);
|
||||
_settingsReader.ReadSettings();
|
||||
@ -152,10 +150,6 @@ namespace PowerLauncher
|
||||
|
||||
_settingsReader.ReadSettingsOnChange();
|
||||
|
||||
_themeManager.ThemeChanged += OnThemeChanged;
|
||||
|
||||
OnThemeChanged(_settings.Theme, _settings.Theme);
|
||||
|
||||
textToLog.AppendLine("End PowerToys Run startup ---------------------------------------------------- ");
|
||||
|
||||
bootTime.Stop();
|
||||
@ -214,48 +208,6 @@ namespace PowerLauncher
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when windows theme is changed.
|
||||
/// </summary>
|
||||
/// <param name="oldTheme">Previous Theme</param>
|
||||
/// <param name="newTheme">Current Theme</param>
|
||||
private void OnThemeChanged(Theme oldTheme, Theme newTheme)
|
||||
{
|
||||
// If OS theme is high contrast, don't change theme.
|
||||
if (SystemParameters.HighContrast)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationTheme theme = ApplicationTheme.Unknown;
|
||||
|
||||
switch (newTheme)
|
||||
{
|
||||
case Theme.Dark:
|
||||
theme = ApplicationTheme.Dark; break;
|
||||
case Theme.Light:
|
||||
theme = ApplicationTheme.Light; break;
|
||||
case Theme.HighContrastWhite:
|
||||
case Theme.HighContrastBlack:
|
||||
case Theme.HighContrastOne:
|
||||
case Theme.HighContrastTwo:
|
||||
theme = ApplicationTheme.HighContrast; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_mainWindow?.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (theme != ApplicationTheme.Unknown)
|
||||
{
|
||||
ApplicationThemeManager.Apply(theme);
|
||||
}
|
||||
});
|
||||
|
||||
ImageLoader.UpdateIconPath(newTheme);
|
||||
_mainVM.Query();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// let exception throw as normal is better for Debug
|
||||
/// </summary>
|
||||
@ -302,19 +254,12 @@ namespace PowerLauncher
|
||||
Log.Info("Start PowerToys Run Exit---------------------------------------------------- ", GetType());
|
||||
if (disposing)
|
||||
{
|
||||
if (_themeManager != null)
|
||||
{
|
||||
_themeManager.ThemeChanged -= OnThemeChanged;
|
||||
}
|
||||
|
||||
API?.SaveAppAllSettings();
|
||||
PluginManager.Dispose();
|
||||
|
||||
// Dispose needs to be called on the main Windows thread, since some resources owned by the thread need to be disposed.
|
||||
_mainWindow?.Dispatcher.Invoke(Dispose);
|
||||
API?.Dispose();
|
||||
_mainVM?.Dispose();
|
||||
_themeManager?.Dispose();
|
||||
}
|
||||
|
||||
Log.Info("End PowerToys Run Exit ---------------------------------------------------- ", GetType());
|
||||
|
46
src/modules/launcher/PowerLauncher/Helper/ThemeExtensions.cs
Normal file
46
src/modules/launcher/PowerLauncher/Helper/ThemeExtensions.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.Win32;
|
||||
using Wpf.Ui.Appearance;
|
||||
|
||||
namespace PowerLauncher.Helper
|
||||
{
|
||||
public static class ThemeExtensions
|
||||
{
|
||||
public static Theme ToTheme(this ApplicationTheme applicationTheme)
|
||||
{
|
||||
return applicationTheme switch
|
||||
{
|
||||
ApplicationTheme.Dark => Theme.Dark,
|
||||
ApplicationTheme.Light => Theme.Light,
|
||||
ApplicationTheme.HighContrast => GetHighContrastBaseType(),
|
||||
_ => Theme.Light,
|
||||
};
|
||||
}
|
||||
|
||||
private static Theme GetHighContrastBaseType()
|
||||
{
|
||||
string registryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes";
|
||||
string theme = (string)Registry.GetValue(registryKey, "CurrentTheme", string.Empty);
|
||||
theme = theme.Split('\\').Last().Split('.').First().ToString();
|
||||
|
||||
switch (theme)
|
||||
{
|
||||
case "hc1":
|
||||
return Theme.HighContrastOne;
|
||||
case "hc2":
|
||||
return Theme.HighContrastTwo;
|
||||
case "hcwhite":
|
||||
return Theme.HighContrastWhite;
|
||||
case "hcblack":
|
||||
return Theme.HighContrastBlack;
|
||||
default:
|
||||
return Theme.HighContrastOne;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
src/modules/launcher/PowerLauncher/Helper/ThemeManager.cs
Normal file
90
src/modules/launcher/PowerLauncher/Helper/ThemeManager.cs
Normal file
@ -0,0 +1,90 @@
|
||||
// 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 Wox.Infrastructure.Image;
|
||||
using Wox.Infrastructure.UserSettings;
|
||||
using Wpf.Ui.Appearance;
|
||||
|
||||
namespace PowerLauncher.Helper
|
||||
{
|
||||
public class ThemeManager : IDisposable
|
||||
{
|
||||
private readonly PowerToysRunSettings _settings;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private Theme _currentTheme;
|
||||
private bool _disposed;
|
||||
|
||||
public Theme CurrentTheme => _currentTheme;
|
||||
|
||||
public event Common.UI.ThemeChangedHandler ThemeChanged;
|
||||
|
||||
public ThemeManager(PowerToysRunSettings settings, MainWindow mainWindow)
|
||||
{
|
||||
_settings = settings;
|
||||
_mainWindow = mainWindow;
|
||||
_currentTheme = ApplicationThemeManager.GetAppTheme().ToTheme();
|
||||
SetTheme(false);
|
||||
|
||||
ApplicationThemeManager.Changed += ApplicationThemeManager_Changed;
|
||||
}
|
||||
|
||||
public void SetTheme(bool fromSettings)
|
||||
{
|
||||
if (_settings.Theme == Theme.Light)
|
||||
{
|
||||
_currentTheme = Theme.Light;
|
||||
_mainWindow?.Dispatcher.Invoke(() => ApplicationThemeManager.Apply(ApplicationTheme.Light, _mainWindow.WindowBackdropType));
|
||||
}
|
||||
else if (_settings.Theme == Theme.Dark)
|
||||
{
|
||||
_currentTheme = Theme.Dark;
|
||||
_mainWindow?.Dispatcher.Invoke(() => ApplicationThemeManager.Apply(ApplicationTheme.Dark, _mainWindow.WindowBackdropType));
|
||||
}
|
||||
else if (fromSettings)
|
||||
{
|
||||
_mainWindow?.Dispatcher.Invoke(ApplicationThemeManager.ApplySystemTheme);
|
||||
}
|
||||
|
||||
ImageLoader.UpdateIconPath(_currentTheme);
|
||||
|
||||
// oldTheme isn't used
|
||||
ThemeChanged?.Invoke(_currentTheme, _currentTheme);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void ApplicationThemeManager_Changed(ApplicationTheme currentApplicationTheme, System.Windows.Media.Color systemAccent)
|
||||
{
|
||||
var newTheme = currentApplicationTheme.ToTheme();
|
||||
if (_currentTheme == newTheme)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentTheme = newTheme;
|
||||
SetTheme(false);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
ApplicationThemeManager.Changed -= ApplicationThemeManager_Changed;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ using PowerLauncher.ViewModel;
|
||||
using Wox.Infrastructure.UserSettings;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.Interfaces;
|
||||
using Wpf.Ui.Appearance;
|
||||
using CancellationToken = System.Threading.CancellationToken;
|
||||
using Image = Wox.Infrastructure.Image;
|
||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||
@ -65,15 +66,7 @@ namespace PowerLauncher
|
||||
WindowBackdropType = Wpf.Ui.Controls.WindowBackdropType.None;
|
||||
}
|
||||
|
||||
// workaround for #30217
|
||||
try
|
||||
{
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this, WindowBackdropType);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception("Exception in SystemThemeWatcher.Watch, issue 30217.", ex, GetType());
|
||||
}
|
||||
SystemThemeWatcher.Watch(this, WindowBackdropType);
|
||||
|
||||
_firstDeleteTimer.Elapsed += CheckForFirstDelete;
|
||||
_firstDeleteTimer.Interval = 1000;
|
||||
@ -803,11 +796,7 @@ namespace PowerLauncher
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_firstDeleteTimer != null)
|
||||
{
|
||||
_firstDeleteTimer.Dispose();
|
||||
}
|
||||
|
||||
_firstDeleteTimer?.Dispose();
|
||||
_hwndSource?.Dispose();
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,6 @@
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" />
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
|
||||
<PackageReference Include="ModernWpfUI" />
|
||||
<PackageReference Include="ScipBe.Common.Office.OneNote" />
|
||||
<PackageReference Include="System.Reactive" />
|
||||
<PackageReference Include="System.Data.OleDb" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@ -6,18 +6,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
using Common.UI;
|
||||
|
||||
using ManagedCommon;
|
||||
|
||||
using Microsoft.Toolkit.Uwp.Notifications;
|
||||
|
||||
using PowerLauncher.Helper;
|
||||
using PowerLauncher.Plugin;
|
||||
using PowerLauncher.ViewModel;
|
||||
|
||||
using Windows.UI.Notifications;
|
||||
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Infrastructure.Image;
|
||||
using Wox.Plugin;
|
||||
@ -32,7 +26,7 @@ namespace Wox
|
||||
private readonly ThemeManager _themeManager;
|
||||
private bool _disposed;
|
||||
|
||||
public event ThemeChangedHandler ThemeChanged;
|
||||
public event Common.UI.ThemeChangedHandler ThemeChanged;
|
||||
|
||||
public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, Alphabet alphabet, ThemeManager themeManager)
|
||||
{
|
||||
@ -108,7 +102,7 @@ namespace Wox
|
||||
|
||||
public Theme GetCurrentTheme()
|
||||
{
|
||||
return _themeManager.GetCurrentTheme();
|
||||
return _themeManager.CurrentTheme;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -9,7 +9,6 @@ using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
using Common.UI;
|
||||
using global::PowerToys.GPOWrapper;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using PowerLauncher.Helper;
|
||||
@ -44,9 +43,6 @@ namespace PowerLauncher
|
||||
var overloadSettings = _settingsUtils.GetSettingsOrDefault<PowerLauncherSettings>(PowerLauncherSettings.ModuleName);
|
||||
UpdateSettings(overloadSettings);
|
||||
_settingsUtils.SaveSettings(overloadSettings.ToJsonString(), PowerLauncherSettings.ModuleName);
|
||||
|
||||
// Apply theme at startup
|
||||
_themeManager.ChangeTheme(_settings.Theme, true);
|
||||
}
|
||||
|
||||
public void CreateSettingsIfNotExists()
|
||||
@ -161,7 +157,7 @@ namespace PowerLauncher
|
||||
if (_settings.Theme != overloadSettings.Properties.Theme)
|
||||
{
|
||||
_settings.Theme = overloadSettings.Properties.Theme;
|
||||
_themeManager.ChangeTheme(_settings.Theme, true);
|
||||
_themeManager.SetTheme(true);
|
||||
}
|
||||
|
||||
if (_settings.StartupPosition != overloadSettings.Properties.Position)
|
||||
|
@ -31,7 +31,7 @@ namespace Wox.Infrastructure.Image
|
||||
|
||||
private static IImageHashGenerator _hashGenerator;
|
||||
|
||||
public static string ErrorIconPath { get; set; }
|
||||
public static string ErrorIconPath { get; set; } = Constant.LightThemedErrorIcon;
|
||||
|
||||
private static readonly string[] ImageExtensions =
|
||||
{
|
||||
@ -54,7 +54,7 @@ namespace Wox.Infrastructure.Image
|
||||
return fs.Read(buffer, 0, buffer.Length) == buffer.Length && pngSignature.SequenceEqual(buffer);
|
||||
}
|
||||
|
||||
public static void Initialize(Theme theme)
|
||||
public static void Initialize()
|
||||
{
|
||||
_hashGenerator = new ImageHashGenerator();
|
||||
|
||||
@ -86,7 +86,6 @@ namespace Wox.Infrastructure.Image
|
||||
}
|
||||
}
|
||||
|
||||
UpdateIconPath(theme);
|
||||
Task.Run(() =>
|
||||
{
|
||||
Stopwatch.Normal("ImageLoader.Initialize - Preload images cost", async () =>
|
||||
|
@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using ManagedCommon;
|
||||
using Wpf.Ui.Controls;
|
||||
using Point = PowerAccent.Core.Point;
|
||||
using Size = PowerAccent.Core.Size;
|
||||
@ -40,15 +39,7 @@ public partial class Selector : FluentWindow, IDisposable, INotifyPropertyChange
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// workaround for #30177
|
||||
try
|
||||
{
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Exception in SystemThemeWatcher.Watch, issue 30177. {ex.Message}");
|
||||
}
|
||||
Wpf.Ui.Appearance.SystemThemeWatcher.Watch(this);
|
||||
|
||||
Application.Current.MainWindow.ShowActivated = false;
|
||||
Application.Current.MainWindow.Topmost = true;
|
||||
|
Loading…
Reference in New Issue
Block a user