[Light Switch] Switch desktop wallpapers with the Light/Dark mode (#42624)

I'm not sure how to set the AccentColor and ColorizationColor that is
consistent with the Settings App, and the same goes for switching
themes. If anyone has a solution, please let me know.


<img width="2010" height="1274" alt="2025-10-26 235808"
src="https://github.com/user-attachments/assets/b3eda45a-09f3-43bc-b87c-1b05bc308c24"
/>


- [x] Closes: #42436
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

---------

Co-authored-by: Jaylyn Barbee <51131738+Jaylyn-Barbee@users.noreply.github.com>
This commit is contained in:
Yexuan Xiao
2026-01-07 01:55:55 +08:00
committed by GitHub
parent d9709b2b91
commit 19c9b4e1fd
25 changed files with 1118 additions and 310 deletions

View File

@@ -5,7 +5,9 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
@@ -15,9 +17,12 @@ using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.SerializationContext;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Newtonsoft.Json.Linq;
using Settings.UI.Library;
using Settings.UI.Library.Helpers;
using Windows.Storage;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
@@ -46,6 +51,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
};
_toggleThemeHotkey = _moduleSettings.Properties.ToggleThemeHotkey.Value;
PropertyChanged += WallpaperPath_Changed;
}
public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
@@ -524,6 +530,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
OnPropertyChanged(nameof(Latitude));
OnPropertyChanged(nameof(Longitude));
OnPropertyChanged(nameof(ScheduleMode));
OnPropertyChanged(nameof(IsWallpaperEnabled));
OnPropertyChanged(nameof(WallpaperPathLight));
OnPropertyChanged(nameof(WallpaperPathDark));
OnPropertyChanged(nameof(WallpaperStyleLight));
OnPropertyChanged(nameof(WallpaperStyleDark));
}
private void UpdateSunTimes(double latitude, double longitude, string city = "n/a")
@@ -574,6 +585,222 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool IsWallpaperEnabled
{
get
{
return ModuleSettings.Properties.WallpaperEnabled.Value;
}
set
{
if (ModuleSettings.Properties.WallpaperEnabled.Value != value)
{
ModuleSettings.Properties.WallpaperEnabled.Value = value;
NotifyPropertyChanged();
}
}
}
public bool IsVirtualDesktopEnabled
{
get
{
return ModuleSettings.Properties.WallpaperVirtualDesktopEnabled.Value;
}
set
{
if (ModuleSettings.Properties.WallpaperVirtualDesktopEnabled.Value != value)
{
ModuleSettings.Properties.WallpaperVirtualDesktopEnabled.Value = value;
NotifyPropertyChanged();
}
}
}
public string WallpaperPathLight
{
get
{
return ModuleSettings.Properties.WallpaperPathLight.Value;
}
set
{
if (ModuleSettings.Properties.WallpaperPathLight.Value != value)
{
ModuleSettings.Properties.WallpaperPathLight.Value = value;
NotifyPropertyChanged();
}
}
}
public string WallpaperPathDark
{
get
{
return ModuleSettings.Properties.WallpaperPathDark.Value;
}
set
{
if (ModuleSettings.Properties.WallpaperPathDark.Value != value)
{
ModuleSettings.Properties.WallpaperPathDark.Value = value;
NotifyPropertyChanged();
}
}
}
public bool IsLightWallpaperValid
{
get => _isLightWallpaperValid;
set
{
if (_isLightWallpaperValid != value)
{
_isLightWallpaperValid = value;
}
}
}
public bool IsDarkWallpaperValid
{
get => _isDarkWallpaperValid;
set
{
if (_isDarkWallpaperValid != value)
{
_isDarkWallpaperValid = value;
}
}
}
public ImageSource WallpaperSourceLight
{
get => _wallpaperSourceLight;
set
{
if (_wallpaperSourceLight != value)
{
_wallpaperSourceLight = value;
NotifyPropertyChanged();
}
}
}
public ImageSource WallpaperSourceDark
{
get => _wallpaperSourceDark;
set
{
if (_wallpaperSourceDark != value)
{
_wallpaperSourceDark = value;
NotifyPropertyChanged();
}
}
}
public int WallpaperStyleLight
{
get => ModuleSettings.Properties.WallpaperStyleLight.Value;
set
{
if (ModuleSettings.Properties.WallpaperStyleLight.Value != value)
{
ModuleSettings.Properties.WallpaperStyleLight.Value = value;
NotifyPropertyChanged();
}
}
}
public int WallpaperStyleDark
{
get => ModuleSettings.Properties.WallpaperStyleDark.Value;
set
{
if (ModuleSettings.Properties.WallpaperStyleDark.Value != value)
{
ModuleSettings.Properties.WallpaperStyleDark.Value = value;
NotifyPropertyChanged();
}
}
}
public static void DeleteFile(string path)
{
// Prevent attackers from damaging files through specially crafted JSON
var dataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Microsoft\\PowerToys\\LightSwitch";
if (!string.IsNullOrEmpty(path) && path.StartsWith(dataPath, StringComparison.OrdinalIgnoreCase))
{
try
{
File.Delete(path);
}
catch (Exception)
{
}
}
}
private async void WallpaperPath_Changed(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(WallpaperPathLight))
{
var lightImage = new BitmapImage();
try
{
var lightFile = await StorageFile.GetFileFromPathAsync(WallpaperPathLight);
await lightImage.SetSourceAsync(await lightFile.OpenReadAsync()); // thrown here when the image is invalid
WallpaperSourceLight = lightImage;
IsLightWallpaperValid = true;
}
catch (Exception)
{
DeleteFile(WallpaperPathLight);
WallpaperPathLight = null;
IsLightWallpaperValid = false;
WallpaperSourceLight = null;
IsWallpaperEnabled = false;
}
}
else if (e.PropertyName == nameof(WallpaperPathDark))
{
var darkImage = new BitmapImage();
try
{
var darkFile = await StorageFile.GetFileFromPathAsync(WallpaperPathDark);
await darkImage.SetSourceAsync(await darkFile.OpenReadAsync());
WallpaperSourceDark = darkImage;
IsDarkWallpaperValid = true;
}
catch (Exception)
{
DeleteFile(WallpaperPathDark);
WallpaperPathDark = null;
IsDarkWallpaperValid = false;
WallpaperSourceDark = null;
IsWallpaperEnabled = false;
}
}
}
private int GetRegistryBuildNumber()
{
var value = Win32.Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "CurrentBuildNumber", string.Empty);
#pragma warning disable CA1305
return int.Parse(value as string);
#pragma warning restore CA1305
}
public bool Is24H2OrLater
{
get => GetRegistryBuildNumber() > 26100;
}
private bool _enabledStateIsGPOConfigured;
private bool _enabledGPOConfiguration;
private LightSwitchSettings _moduleSettings;
@@ -581,6 +808,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private HotkeySettings _toggleThemeHotkey;
private TimeSpan? _sunriseTimeSpan;
private TimeSpan? _sunsetTimeSpan;
private bool _isLightWallpaperValid;
private bool _isDarkWallpaperValid;
private ImageSource _wallpaperSourceLight;
private ImageSource _wallpaperSourceDark;
public ICommand ForceLightCommand { get; }