diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 85f42a267b..91df199e2c 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -456,6 +456,7 @@ DWMWINDOWATTRIBUTE DWMWINDOWMAXIMIZEDCHANGE DWORDLONG dworigin +DWPOS dwrite dxgi eab @@ -676,6 +677,7 @@ hicon HICONSM HIDEREADONLY HIDEWINDOW +hif Hif HIMAGELIST himl @@ -837,6 +839,7 @@ jpe jpnime Jsons jsonval +jxl jxr keybd KEYBDDATA @@ -1460,6 +1463,7 @@ recyclebin Redist Reencode REFCLSID +REFGUID REFIID REGCLS regfile @@ -1566,6 +1570,7 @@ SETBUDDYINT SETCONTEXT SETCURSEL setcursor +SETDESKWALLPAPER SETFOCUS SETFOREGROUND SETHOTKEY @@ -1654,6 +1659,7 @@ SKEXP SKIPOWNPROCESS sku SLGP +slideshow sln slnf slnx @@ -1890,6 +1896,7 @@ unwide unzoom UOffset UOI +UPDATEINIFILE UPDATENOW UPDATEREGISTRY updown diff --git a/src/modules/LightSwitch/LightSwitchCommon/SettingsConstants.h b/src/modules/LightSwitch/LightSwitchCommon/SettingsConstants.h new file mode 100644 index 0000000000..964258de1e --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchCommon/SettingsConstants.h @@ -0,0 +1,23 @@ +#pragma once + +enum class SettingId +{ + ScheduleMode = 0, + Latitude, + Longitude, + LightTime, + DarkTime, + Sunrise_Offset, + Sunset_Offset, + ChangeSystem, + ChangeApps, + WallpaperEnabled, + WallpaperVirtualDesktopEnabled, + WallpaperStyleLight, + WallpaperStyleDark, + WallpaperPathLight, + WallpaperPathDark +}; + +inline constexpr wchar_t PERSONALIZATION_REGISTRY_PATH[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +inline constexpr wchar_t NIGHT_LIGHT_REGISTRY_PATH[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\CloudStore\\Store\\DefaultAccount\\Current\\default$windows.data.bluelightreduction.bluelightreductionstate\\windows.data.bluelightreduction.bluelightreductionstate"; diff --git a/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.cpp b/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.cpp new file mode 100644 index 0000000000..d3f7e3e86b --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.cpp @@ -0,0 +1,370 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include "ThemeHelper.h" +#include +#include "SettingsConstants.h" + +static auto RegKeyGuard(HKEY& hKey) noexcept +{ + return wil::scope_exit([&hKey]() { + if (hKey == nullptr) + return; + if (RegCloseKey(hKey) != ERROR_SUCCESS) + std::terminate(); + }); +} + +// Controls changing the themes. +static void ResetColorPrevalence() noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + if (RegOpenKeyEx(HKEY_CURRENT_USER, + PERSONALIZATION_REGISTRY_PATH, + 0, + KEY_SET_VALUE, + &hKey) == ERROR_SUCCESS) + { + DWORD value = 0; // back to default value + RegSetValueEx(hKey, L"ColorPrevalence", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + + SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); + + SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); + + SendMessageTimeout(HWND_BROADCAST, WM_DWMCOLORIZATIONCOLORCHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); + } +} + +void SetAppsTheme(bool mode) noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + if (RegOpenKeyEx(HKEY_CURRENT_USER, + PERSONALIZATION_REGISTRY_PATH, + 0, + KEY_SET_VALUE, + &hKey) == ERROR_SUCCESS) + { + DWORD value = mode; + RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + + SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); + + SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); + } +} + +void SetSystemTheme(bool mode) noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + if (RegOpenKeyEx(HKEY_CURRENT_USER, + PERSONALIZATION_REGISTRY_PATH, + 0, + KEY_SET_VALUE, + &hKey) == ERROR_SUCCESS) + { + DWORD value = mode; + RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + + if (mode) // if are changing to light mode + { + ResetColorPrevalence(); + Logger::info(L"[LightSwitchService] Reset ColorPrevalence to default when switching to light mode."); + } + + SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); + + SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); + } +} + +// Can think of this as "is the current theme light?" +bool GetCurrentSystemTheme() noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + DWORD value = 1; // default = light + DWORD size = sizeof(value); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, + PERSONALIZATION_REGISTRY_PATH, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) + { + RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); + } + + return value == 1; // true = light, false = dark +} + +bool GetCurrentAppsTheme() noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + DWORD value = 1; + DWORD size = sizeof(value); + + if (RegOpenKeyEx(HKEY_CURRENT_USER, + PERSONALIZATION_REGISTRY_PATH, + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) + { + RegQueryValueEx(hKey, L"AppsUseLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); + } + + return value == 1; // true = light, false = dark +} + +bool IsNightLightEnabled() noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + + if (RegOpenKeyExW(HKEY_CURRENT_USER, NIGHT_LIGHT_REGISTRY_PATH, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return false; + + // RegGetValueW will set size to the size of the data and we expect that to be at least 25 bytes (we need to access bytes 23 and 24) + DWORD size = 0; + if (RegGetValueW(hKey, nullptr, L"Data", RRF_RT_REG_BINARY, nullptr, nullptr, &size) != ERROR_SUCCESS || size < 25) + { + return false; + } + + std::vector data(size); + if (RegGetValueW(hKey, nullptr, L"Data", RRF_RT_REG_BINARY, nullptr, data.data(), &size) != ERROR_SUCCESS) + { + return false; + } + + return data[23] == 0x10 && data[24] == 0x00; +} + +#include +#include +#include +#include + +static bool GetWindowsVersionFromRegistryInternal(int& build, int& revision) noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey) != ERROR_SUCCESS) + { + return false; + } + wchar_t buffer[11]{}; + DWORD bufferSize{ sizeof(buffer) }; + if (RegGetValueW(hKey, nullptr, L"CurrentBuildNumber", RRF_RT_REG_SZ, nullptr, static_cast(buffer), &bufferSize)) + { + return false; + } + char bufferA[11]{}; + std::transform(std::begin(buffer), std::end(buffer), std::begin(bufferA), [](auto c) { return static_cast(c); }); + int bld{}; + if (std::from_chars(bufferA, bufferA + sizeof(bufferA), bld).ec != std::errc{}) + { + return false; + } + DWORD rev{}; + DWORD revSize{ sizeof(rev) }; + if (RegGetValueW(hKey, nullptr, L"UBR", RRF_RT_DWORD, nullptr, &rev, &revSize) != ERROR_SUCCESS) + { + return false; + } + revision = static_cast(rev); + build = static_cast(bld); + return true; +} + +static bool GetWindowsVersionFromRegistry(int& build, int& revision) noexcept +{ + static std::atomic build_cache{}; + static std::atomic rev_cache{}; + + if (auto bld = build_cache.load(); bld != 0) + { + build = bld; + revision = rev_cache.load(); + return true; + } + + int bld{}; + int rev{}; + if (auto e = GetWindowsVersionFromRegistryInternal(bld, rev); e == false) + { + return e; + } + build = bld; + revision = rev; + rev_cache.store(rev); + // Write after rev_cache for condition + build_cache.store(bld); + return true; +} + +// This function will supplement the wallpaper path setting. It does not cause the wallpaper to change, but for consistency, it is better to set it +static int SetRemainWallpaperPathRegistry(std::wstring const& wallpaperPath) noexcept +{ + HKEY hKey{}; + auto closeKey = RegKeyGuard(hKey); + + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Wallpapers", 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) + { + // The key may not exist after updating Windows, so it is not an error + // The key will be created by the Settings app + return 0; + } + if (RegSetValueExW(hKey, L"CurrentWallpaperPath", 0, REG_SZ, reinterpret_cast(wallpaperPath.data()), static_cast((wallpaperPath.size() + 1u) * sizeof(wchar_t))) != ERROR_SUCCESS) + { + return 0x301; + } + DWORD backgroundType = 0; // 0 = picture, 1 = solid color, 2 = slideshow + if (RegSetValueExW(hKey, L"BackgroundType", 0, REG_DWORD, reinterpret_cast(&backgroundType), static_cast(sizeof(DWORD))) != ERROR_SUCCESS) + { + return 0x302; + } + return 0; +} + +#define WIN32_LEAN_AND_MEAN +#define COM_NO_WINDOWS_H +#include +#include +#include +#include +#include "Shobjidl.h" +#include +#include + +#pragma comment(lib, "runtimeobject.lib") + +// COM interface definition from https://github.com/MScholtes/VirtualDesktop + +inline constexpr GUID CLSID_ImmersiveShell{ 0xC2F03A33, 0x21F5, 0x47FA, { 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 } }; +inline constexpr GUID CLSID_VirtualDesktopManagerInternal{ 0xC5E0CDCA, 0x7B6E, 0x41B2, { 0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B } }; + +struct __declspec(novtable) __declspec(uuid("6D5140C1-7436-11CE-8034-00AA006009FA")) IServiceProvider10 : public IUnknown +{ + virtual HRESULT __stdcall QueryService(REFGUID service, REFIID riid, void** obj) = 0; +}; + +#undef CreateDesktop + +struct __declspec(novtable) __declspec(uuid("53F5CA0B-158F-4124-900C-057158060B27")) IVirtualDesktopManagerInternal24H2 : public IUnknown +{ + virtual HRESULT __stdcall GetCount(int* count) = 0; + virtual HRESULT __stdcall MoveViewToDesktop(IInspectable* view, IUnknown* desktop) = 0; + virtual HRESULT __stdcall CanViewMoveDesktops(IInspectable* view, bool* result) = 0; + virtual HRESULT __stdcall GetCurrentDesktop(IUnknown** desktop) = 0; + virtual HRESULT __stdcall GetDesktops(IObjectArray** desktops) = 0; + virtual HRESULT __stdcall GetAdjacentDesktop(IUnknown* from, int direction, IUnknown** desktop) = 0; + virtual HRESULT __stdcall SwitchDesktop(IUnknown* desktop) = 0; + virtual HRESULT __stdcall SwitchDesktopAndMoveForegroundView(IUnknown* desktop) = 0; + virtual HRESULT __stdcall CreateDesktop(IUnknown** desktop) = 0; + virtual HRESULT __stdcall MoveDesktop(IUnknown* desktop, int nIndex) = 0; + virtual HRESULT __stdcall RemoveDesktop(IUnknown* desktop, IUnknown* fallback) = 0; + virtual HRESULT __stdcall FindDesktop(const GUID* desktopId, IUnknown** desktop) = 0; + virtual HRESULT __stdcall GetDesktopSwitchIncludeExcludeViews(IUnknown* desktop, IObjectArray** unknown1, IObjectArray** unknown2) = 0; + virtual HRESULT __stdcall SetDesktopName(IUnknown* desktop, HSTRING name) = 0; + virtual HRESULT __stdcall SetDesktopWallpaper(IUnknown* desktop, HSTRING path) = 0; + virtual HRESULT __stdcall UpdateWallpaperPathForAllDesktops(HSTRING path) = 0; + virtual HRESULT __stdcall CopyDesktopState(IInspectable* pView0, IInspectable* pView1) = 0; + virtual HRESULT __stdcall CreateRemoteDesktop(HSTRING path, IUnknown** desktop) = 0; + virtual HRESULT __stdcall SwitchRemoteDesktop(IUnknown* desktop, void* switchType) = 0; + virtual HRESULT __stdcall SwitchDesktopWithAnimation(IUnknown* desktop) = 0; + virtual HRESULT __stdcall GetLastActiveDesktop(IUnknown** desktop) = 0; + virtual HRESULT __stdcall WaitForAnimationToComplete() = 0; +}; + +// Using this method to set the wallpaper works across virtual desktops, but it does not provide the functionality to set the style +static int SetWallpaperViaIVirtualDesktopManagerInternal(const std::wstring& path) noexcept +{ + int build{}; + int revision{}; + if (!GetWindowsVersionFromRegistry(build, revision)) + { + return 0x201; + } + // Unstable Windows internal API, at least 24H2 required + if (build < 26100) + { + return 0x202; + } + auto shell = winrt::try_create_instance(CLSID_ImmersiveShell, CLSCTX_LOCAL_SERVER); + if (!shell) + { + return 0x203; + } + winrt::com_ptr virtualDesktopManagerInternal; + if (shell->QueryService( + CLSID_VirtualDesktopManagerInternal, + __uuidof(IVirtualDesktopManagerInternal24H2), + virtualDesktopManagerInternal.put_void()) != S_OK) + { + return 0x204; + } + if (virtualDesktopManagerInternal->UpdateWallpaperPathForAllDesktops(static_cast(winrt::detach_abi(path))) != S_OK) + { + return 0x205; + } + return 0; +} + +// After setting the wallpaper using this method, switching to other virtual desktops will cause the wallpaper to be restored +static int SetWallpaperViaIDesktopWallpaper(const std::wstring& path, int style) noexcept +{ + auto pos = static_cast(style); + switch (pos) + { + case DWPOS_CENTER: + case DWPOS_TILE: + case DWPOS_STRETCH: + case DWPOS_FIT: + case DWPOS_FILL: + case DWPOS_SPAN: + break; + default: + std::terminate(); + } + auto desktopWallpaper = winrt::try_create_instance(__uuidof(DesktopWallpaper), CLSCTX_LOCAL_SERVER); + if (!desktopWallpaper) + { + return 0x301; + } + if (desktopWallpaper->SetPosition(pos) != S_OK) + { + return 0x302; + } + if (desktopWallpaper->SetWallpaper(nullptr, path.c_str()) != S_OK) + { + return 0x303; + } + return 0; +} + +int SetDesktopWallpaper(const std::wstring& path, int style, bool virtualDesktop) noexcept +{ + if (virtualDesktop) + { + if (auto e = SetWallpaperViaIVirtualDesktopManagerInternal(path); e != 0) + { + return e; + } + } + if (auto e = SetWallpaperViaIDesktopWallpaper(path, style); e != 0) + { + return e; + } + if (auto e = SetRemainWallpaperPathRegistry(path); e != 0) + { + return e; + } + return 0; +} \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.h b/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.h new file mode 100644 index 0000000000..8c8766ad8b --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchCommon/ThemeHelper.h @@ -0,0 +1,9 @@ +#pragma once +#include +void SetSystemTheme(bool dark) noexcept; +void SetAppsTheme(bool dark) noexcept; +bool GetCurrentSystemTheme() noexcept; +bool GetCurrentAppsTheme() noexcept; +bool IsNightLightEnabled() noexcept; +// Returned 0 indicates success; otherwise, the reason is returned, see definition +int SetDesktopWallpaper(std::wstring const& wallpaperPath, int style, bool virtualDesktop) noexcept; \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj index b86b25a4d1..6ab7dea696 100644 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj @@ -166,13 +166,14 @@ - ..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\LightSwitchCommon;..\..\..\common;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) - + + @@ -187,7 +188,12 @@ pch.h pch.h - + + NotUsing + NotUsing + NotUsing + NotUsing + @@ -210,6 +216,7 @@ + diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj.filters b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj.filters index 45352efe4b..18968990c5 100644 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj.filters +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj.filters @@ -10,7 +10,7 @@ Source Files - + Source Files @@ -24,7 +24,10 @@ Header Files - + + Header Files + + Header Files @@ -47,4 +50,7 @@ + + + \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.cpp b/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.cpp deleted file mode 100644 index 3593a5bbae..0000000000 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "pch.h" -#include -#include "ThemeHelper.h" - -// Controls changing the themes. -static void ResetColorPrevalence() -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = 0; // back to default value - RegSetValueEx(hKey, L"ColorPrevalence", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_DWMCOLORIZATIONCOLORCHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -void SetAppsTheme(bool mode) -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = mode; - RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -void SetSystemTheme(bool mode) -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = mode; - RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - if (mode) // if are changing to light mode - { - ResetColorPrevalence(); - } - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -bool GetCurrentSystemTheme() -{ - HKEY hKey; - DWORD value = 1; // default = light - DWORD size = sizeof(value); - - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) - { - RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); - RegCloseKey(hKey); - } - - return value == 1; // true = light, false = dark -} - -bool GetCurrentAppsTheme() -{ - HKEY hKey; - DWORD value = 1; - DWORD size = sizeof(value); - - if (RegOpenKeyEx(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) - { - RegQueryValueEx(hKey, L"AppsUseLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); - RegCloseKey(hKey); - } - - return value == 1; // true = light, false = dark -} diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.h b/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.h deleted file mode 100644 index 5985fd95c8..0000000000 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once -void SetSystemTheme(bool dark); -void SetAppsTheme(bool dark); -bool GetCurrentSystemTheme(); -bool GetCurrentAppsTheme(); diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp b/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp index bab4e30797..2cab8c1299 100644 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/dllmain.cpp @@ -94,6 +94,12 @@ struct ModuleSettings int m_sunset_offset = 0; std::wstring m_latitude = L"0.0"; std::wstring m_longitude = L"0.0"; + bool m_wallpaper = false; + bool m_wallpaper_virtual_desktop = false; + int m_wallpaper_style_light = 0; + int m_wallpaper_style_dark = 0; + std::wstring m_wallpaper_path_light; + std::wstring m_wallpaper_path_dark; } g_settings; class LightSwitchInterface : public PowertoyModuleIface @@ -351,6 +357,30 @@ public: { g_settings.m_longitude = *v; } + if (auto v = values.get_bool_value(L"wallpaperEnabled")) + { + g_settings.m_wallpaper = *v; + } + if (auto v = values.get_bool_value(L"wallpaperVirtualDesktopEnabled")) + { + g_settings.m_wallpaper_virtual_desktop = *v; + } + if (auto v = values.get_int_value(L"wallpaperStyleLight")) + { + g_settings.m_wallpaper_style_light = *v; + } + if (auto v = values.get_int_value(L"wallpaperStyleDark")) + { + g_settings.m_wallpaper_style_dark = *v; + } + if (auto v = values.get_string_value(L"wallpaperPathLight")) + { + g_settings.m_wallpaper_path_light = *v; + } + if (auto v = values.get_string_value(L"wallpaperPathDark")) + { + g_settings.m_wallpaper_path_dark = *v; + } values.save_to_settings_file(); } @@ -566,15 +596,53 @@ public: }; +static bool IsValidPath(const std::wstring& path) +{ + std::error_code ec; + return !path.empty() && std::filesystem::exists(path, ec); +} + void LightSwitchInterface::ToggleTheme() { + bool current_system_theme = GetCurrentSystemTheme(); + bool current_apps_theme = GetCurrentAppsTheme(); + if (g_settings.m_changeSystem) { - SetSystemTheme(!GetCurrentSystemTheme()); + SetSystemTheme(!current_system_theme); } if (g_settings.m_changeApps) { - SetAppsTheme(!GetCurrentAppsTheme()); + SetAppsTheme(!current_apps_theme); + } + + bool new_system_theme = GetCurrentSystemTheme(); + bool new_apps_theme = GetCurrentAppsTheme(); + + bool changeWallpaper = + g_settings.m_wallpaper && + IsValidPath(g_settings.m_wallpaper_path_light) && + IsValidPath(g_settings.m_wallpaper_path_dark); + + // if something changed and wallpaper change is enabled and paths are valid + if ((new_system_theme != current_system_theme || new_apps_theme != current_apps_theme) && changeWallpaper) + { + bool shouldBeLight; + + if (g_settings.m_changeSystem && new_system_theme != current_system_theme) + { + shouldBeLight = new_system_theme; + } + else + { + // Either apps-only changed, or system didn't move + shouldBeLight = new_apps_theme; + } + + auto&& wallpaperPath = shouldBeLight ? g_settings.m_wallpaper_path_light : g_settings.m_wallpaper_path_dark; + auto style = shouldBeLight ? g_settings.m_wallpaper_style_light : g_settings.m_wallpaper_style_dark; + + SetDesktopWallpaper(wallpaperPath, style, g_settings.m_wallpaper_virtual_desktop); } if (!m_manual_override_event_handle) @@ -693,6 +761,18 @@ void LightSwitchInterface::init_settings() g_settings.m_latitude = *v; if (auto v = settings.get_string_value(L"longitude")) g_settings.m_longitude = *v; + if (auto v = settings.get_bool_value(L"wallpaperEnabled")) + g_settings.m_wallpaper = *v; + if (auto v = settings.get_bool_value(L"wallpaperVirtualDesktopEnabled")) + g_settings.m_wallpaper_virtual_desktop = *v; + if (auto v = settings.get_int_value(L"wallpaperStyleLight")) + g_settings.m_wallpaper_style_light = *v; + if (auto v = settings.get_int_value(L"wallpaperStyleDark")) + g_settings.m_wallpaper_style_dark = *v; + if (auto v = settings.get_string_value(L"wallpaperPathLight")) + g_settings.m_wallpaper_path_light = *v; + if (auto v = settings.get_string_value(L"wallpaperPathDark")) + g_settings.m_wallpaper_path_dark = *v; Logger::info(L"[Light Switch] init_settings: loaded successfully"); } diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.cpp b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.cpp index 8919f4274b..d561731fec 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.cpp +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.cpp @@ -24,7 +24,7 @@ static LightSwitchStateManager* g_stateManagerPtr = nullptr; VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv); VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl); DWORD WINAPI ServiceWorkerThread(LPVOID lpParam); -void ApplyTheme(bool shouldBeLight); +void ApplyTheme(bool shouldBeLight, bool changeWallpaper); // Entry point for the executable int _tmain(int argc, TCHAR* argv[]) @@ -125,9 +125,29 @@ VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl) } } -void ApplyTheme(bool shouldBeLight) +void SetWallpaper(bool shouldBeLight) +{ + const auto& settings = LightSwitchSettings::settings(); + + if (settings.wallpaperEnabled) + { + std::wstring const& wallpaperPath = shouldBeLight ? settings.wallpaperPathLight : settings.wallpaperPathDark; + auto style = shouldBeLight ? settings.wallpaperStyleLight : settings.wallpaperStyleDark; + if (auto e = SetDesktopWallpaper(wallpaperPath, style, settings.wallpaperVirtualDesktop) == 0) + { + Logger::info(L"[LightSwitchService] Wallpaper is changed to {}.", wallpaperPath); + } + else + { + Logger::error(L"[LightSwitchService] Failed to set wallpaper, error: {}.", e); + } + } +}; + +void ApplyTheme(bool shouldBeLight, bool changeWallpaper) { const auto& s = LightSwitchSettings::settings(); + bool somethingChanged = false; if (s.changeSystem) { @@ -136,6 +156,7 @@ void ApplyTheme(bool shouldBeLight) { SetSystemTheme(shouldBeLight); Logger::info(L"[LightSwitchService] Changed system theme to {}.", shouldBeLight ? L"light" : L"dark"); + somethingChanged = true; } } @@ -146,6 +167,15 @@ void ApplyTheme(bool shouldBeLight) { SetAppsTheme(shouldBeLight); Logger::info(L"[LightSwitchService] Changed apps theme to {}.", shouldBeLight ? L"light" : L"dark"); + somethingChanged = true; + } + } + + if (somethingChanged) + { + if (changeWallpaper) + { + SetWallpaper(shouldBeLight); } } } @@ -175,7 +205,7 @@ static void DetectAndHandleExternalThemeChange(LightSwitchStateManager& stateMan if (s.scheduleMode == ScheduleMode::FollowNightLight) { shouldBeLight = !IsNightLightEnabled(); - } + } else { shouldBeLight = ShouldBeLight(nowMinutes, effectiveLight, effectiveDark); diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj index b8e51ee489..3f42cd0ebc 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj @@ -53,18 +53,7 @@ true NotUsing %(PreprocessorDefinitions) - - ./../; - ..\..\..\common; - ..\..\..\common\logger; - ..\..\..\common\utils; - ..\..\..\common\SettingsAPI; - ..\..\..\common\Telemetry; - ..\..\..\; - ..\..\..\..\deps\spdlog\include; - ./; - %(AdditionalIncludeDirectories) - + ..\LightSwitchCommon;.\..\;..\..\..\common;..\..\..\common\logger;..\..\..\common\utils;..\..\..\common\SettingsAPI;..\..\..\common\Telemetry;..\..\..\;..\..\..\..\deps\spdlog\include;./;%(AdditionalIncludeDirectories) Windows @@ -77,8 +66,7 @@ - - + @@ -91,9 +79,9 @@ - - + + diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj.filters b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj.filters index a704e87073..43ba0352d7 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj.filters +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj.filters @@ -21,15 +21,12 @@ Source Files - + Source Files Source Files - - Source Files - Source Files @@ -50,10 +47,10 @@ Header Files - + Header Files - + Header Files diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp index 488142b95b..b31840da50 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.cpp @@ -253,6 +253,66 @@ void LightSwitchSettings::LoadSettings() { Trace::LightSwitch::ThemeTargetChanged(m_settings.changeApps, m_settings.changeSystem); } + + if (const auto jsonVal = values.get_bool_value(L"wallpaperEnabled")) + { + auto val = *jsonVal; + if (m_settings.wallpaperEnabled != val) + { + m_settings.wallpaperEnabled = val; + NotifyObservers(SettingId::WallpaperEnabled); + } + } + + if (const auto jsonVal = values.get_bool_value(L"wallpaperVirtualDesktopEnabled")) + { + auto val = *jsonVal; + if (m_settings.wallpaperVirtualDesktop != val) + { + m_settings.wallpaperVirtualDesktop = val; + NotifyObservers(SettingId::WallpaperVirtualDesktopEnabled); + } + } + + if (const auto jsonVal = values.get_int_value(L"wallpaperStyleLight")) + { + auto val = *jsonVal; + if (m_settings.wallpaperStyleLight != val) + { + m_settings.wallpaperStyleLight = val; + NotifyObservers(SettingId::WallpaperStyleLight); + } + } + + if (const auto jsonVal = values.get_int_value(L"wallpaperStyleDark")) + { + auto val = *jsonVal; + if (m_settings.wallpaperStyleDark != val) + { + m_settings.wallpaperStyleDark = val; + NotifyObservers(SettingId::WallpaperStyleDark); + } + } + + if (const auto jsonVal = values.get_string_value(L"wallpaperPathLight")) + { + auto val = *jsonVal; + if (m_settings.wallpaperPathLight != val) + { + m_settings.wallpaperPathLight = val; + NotifyObservers(SettingId::WallpaperPathLight); + } + } + + if (const auto jsonVal = values.get_string_value(L"wallpaperPathDark")) + { + auto val = *jsonVal; + if (m_settings.wallpaperPathDark != val) + { + m_settings.wallpaperPathDark = val; + NotifyObservers(SettingId::WallpaperPathDark); + } + } } catch (...) { diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.h b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.h index 1d1c7953fe..352570cbf5 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.h +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchSettings.h @@ -67,6 +67,13 @@ struct LightSwitchConfig bool changeSystem = false; bool changeApps = false; + + bool wallpaperEnabled = false; + bool wallpaperVirtualDesktop = false; + int wallpaperStyleLight = 0; + int wallpaperStyleDark = 0; + std::wstring wallpaperPathLight; + std::wstring wallpaperPathDark; }; class LightSwitchSettings diff --git a/src/modules/LightSwitch/LightSwitchService/LightSwitchStateManager.cpp b/src/modules/LightSwitch/LightSwitchService/LightSwitchStateManager.cpp index f562d38c41..c9abf663a2 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchStateManager.cpp +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchStateManager.cpp @@ -4,8 +4,9 @@ #include #include "ThemeScheduler.h" #include +#include -void ApplyTheme(bool shouldBeLight); +void ApplyTheme(bool shouldBeLight, bool changeWallpaper); // Constructor LightSwitchStateManager::LightSwitchStateManager() @@ -147,6 +148,11 @@ static std::pair update_sun_times(auto& settings) return { newLightTime, newDarkTime }; } +static bool IsValidPath(const std::wstring& path) +{ + return !path.empty() && std::filesystem::exists(path); +} + // Internal: decide what should happen now void LightSwitchStateManager::EvaluateAndApplyIfNeeded() { @@ -240,6 +246,11 @@ void LightSwitchStateManager::EvaluateAndApplyIfNeeded() bool appsNeedsToChange = _currentSettings.changeApps && (_state.isAppsLightActive != shouldBeLight); bool systemNeedsToChange = _currentSettings.changeSystem && (_state.isSystemLightActive != shouldBeLight); + bool changeWallpaper = + _currentSettings.wallpaperEnabled && + IsValidPath(_currentSettings.wallpaperPathDark) && + IsValidPath(_currentSettings.wallpaperPathLight); + /* Logger::debug( L"[LightSwitchStateManager] now = {:02d}:{:02d}, light boundary = {:02d}:{:02d} ({}), dark boundary = {:02d}:{:02d} ({})", now / 60, @@ -260,11 +271,11 @@ void LightSwitchStateManager::EvaluateAndApplyIfNeeded() if (!_state.isManualOverride && (appsNeedsToChange || systemNeedsToChange)) { Logger::info(L"[LightSwitchStateManager] Applying {} theme", shouldBeLight ? L"light" : L"dark"); - ApplyTheme(shouldBeLight); + ApplyTheme(shouldBeLight, changeWallpaper); _state.isSystemLightActive = GetCurrentSystemTheme(); _state.isAppsLightActive = GetCurrentAppsTheme(); } _state.lastTickMinutes = now; -} +} \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.cpp b/src/modules/LightSwitch/LightSwitchService/SettingsConstants.cpp deleted file mode 100644 index 534e55f5e3..0000000000 --- a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "SettingsConstants.h" diff --git a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h b/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h deleted file mode 100644 index 8015c9b3e6..0000000000 --- a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -enum class SettingId -{ - ScheduleMode = 0, - Latitude, - Longitude, - LightTime, - DarkTime, - Sunrise_Offset, - Sunset_Offset, - ChangeSystem, - ChangeApps -}; - -constexpr wchar_t PERSONALIZATION_REGISTRY_PATH[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr wchar_t NIGHT_LIGHT_REGISTRY_PATH[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\CloudStore\\Store\\DefaultAccount\\Current\\default$windows.data.bluelightreduction.bluelightreductionstate\\windows.data.bluelightreduction.bluelightreductionstate"; diff --git a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp b/src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp deleted file mode 100644 index cfa858c636..0000000000 --- a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include -#include "ThemeHelper.h" -#include - -// Controls changing the themes. - -static void ResetColorPrevalence() -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - PERSONALIZATION_REGISTRY_PATH, - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = 0; // back to default value - RegSetValueEx(hKey, L"ColorPrevalence", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_DWMCOLORIZATIONCOLORCHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -void SetAppsTheme(bool mode) -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - PERSONALIZATION_REGISTRY_PATH, - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = mode; - RegSetValueEx(hKey, L"AppsUseLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -void SetSystemTheme(bool mode) -{ - HKEY hKey; - if (RegOpenKeyEx(HKEY_CURRENT_USER, - PERSONALIZATION_REGISTRY_PATH, - 0, - KEY_SET_VALUE, - &hKey) == ERROR_SUCCESS) - { - DWORD value = mode; - RegSetValueEx(hKey, L"SystemUsesLightTheme", 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); - RegCloseKey(hKey); - - if (mode) // if are changing to light mode - { - ResetColorPrevalence(); - Logger::info(L"[LightSwitchService] Reset ColorPrevalence to default when switching to light mode."); - } - - SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); - - SendMessageTimeout(HWND_BROADCAST, WM_THEMECHANGED, 0, 0, SMTO_ABORTIFHUNG, 5000, nullptr); - } -} - -// Can think of this as "is the current theme light?" -bool GetCurrentSystemTheme() -{ - HKEY hKey; - DWORD value = 1; // default = light - DWORD size = sizeof(value); - - if (RegOpenKeyEx(HKEY_CURRENT_USER, - PERSONALIZATION_REGISTRY_PATH, - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) - { - RegQueryValueEx(hKey, L"SystemUsesLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); - RegCloseKey(hKey); - } - - return value == 1; // true = light, false = dark -} - -bool GetCurrentAppsTheme() -{ - HKEY hKey; - DWORD value = 1; - DWORD size = sizeof(value); - - if (RegOpenKeyEx(HKEY_CURRENT_USER, - PERSONALIZATION_REGISTRY_PATH, - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) - { - RegQueryValueEx(hKey, L"AppsUseLightTheme", nullptr, nullptr, reinterpret_cast(&value), &size); - RegCloseKey(hKey); - } - - return value == 1; // true = light, false = dark -} - -bool IsNightLightEnabled() -{ - HKEY hKey; - const wchar_t* path = NIGHT_LIGHT_REGISTRY_PATH; - - if (RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKey) != ERROR_SUCCESS) - return false; - - // RegGetValueW will set size to the size of the data and we expect that to be at least 25 bytes (we need to access bytes 23 and 24) - DWORD size = 0; - if (RegGetValueW(hKey, nullptr, L"Data", RRF_RT_REG_BINARY, nullptr, nullptr, &size) != ERROR_SUCCESS || size < 25) - { - RegCloseKey(hKey); - return false; - } - - std::vector data(size); - if (RegGetValueW(hKey, nullptr, L"Data", RRF_RT_REG_BINARY, nullptr, data.data(), &size) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return false; - } - - RegCloseKey(hKey); - return data[23] == 0x10 && data[24] == 0x00; -} \ No newline at end of file diff --git a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.h b/src/modules/LightSwitch/LightSwitchService/ThemeHelper.h deleted file mode 100644 index e8d45e9c2a..0000000000 --- a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -void SetSystemTheme(bool dark); -void SetAppsTheme(bool dark); -bool GetCurrentSystemTheme(); -bool GetCurrentAppsTheme(); -bool IsNightLightEnabled(); \ No newline at end of file diff --git a/src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs b/src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs index 8f5bf88a19..5f104e40d5 100644 --- a/src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs +++ b/src/settings-ui/Settings.UI.Library/LightSwitchProperties.cs @@ -17,6 +17,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library public const string DefaultLatitude = "0.0"; public const string DefaultLongitude = "0.0"; public const string DefaultScheduleMode = "Off"; + public const bool DefaultWallpaperEnabled = false; + public const bool DefaultWallpaperVirtualDesktopEnabled = false; + public const int DefaultWallpaperStyle = 0; + public const string DefaultWallpaperPath = ""; public static readonly HotkeySettings DefaultToggleThemeHotkey = new HotkeySettings(true, true, false, true, 0x44); // Ctrl+Win+Shift+D public LightSwitchProperties() @@ -30,6 +34,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library SunriseOffset = new IntProperty(DefaultSunriseOffset); SunsetOffset = new IntProperty(DefaultSunsetOffset); ScheduleMode = new StringProperty(DefaultScheduleMode); + WallpaperEnabled = new BoolProperty(DefaultWallpaperEnabled); + WallpaperVirtualDesktopEnabled = new BoolProperty(DefaultWallpaperVirtualDesktopEnabled); + WallpaperStyleLight = new IntProperty(DefaultWallpaperStyle); + WallpaperStyleDark = new IntProperty(DefaultWallpaperStyle); + WallpaperPathLight = new StringProperty(DefaultWallpaperPath); + WallpaperPathDark = new StringProperty(DefaultWallpaperPath); ToggleThemeHotkey = new KeyboardKeysProperty(DefaultToggleThemeHotkey); } @@ -62,5 +72,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library [JsonPropertyName("toggle-theme-hotkey")] public KeyboardKeysProperty ToggleThemeHotkey { get; set; } + + [JsonPropertyName("wallpaperEnabled")] + public BoolProperty WallpaperEnabled { get; set; } + + [JsonPropertyName("wallpaperVirtualDesktopEnabled")] + public BoolProperty WallpaperVirtualDesktopEnabled { get; set; } + + [JsonPropertyName("wallpaperStyleLight")] + public IntProperty WallpaperStyleLight { get; set; } + + [JsonPropertyName("wallpaperStyleDark")] + public IntProperty WallpaperStyleDark { get; set; } + + [JsonPropertyName("wallpaperPathLight")] + public StringProperty WallpaperPathLight { get; set; } + + [JsonPropertyName("wallpaperPathDark")] + public StringProperty WallpaperPathDark { get; set; } } } diff --git a/src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs b/src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs index b4eae2d1ba..41b13a82a4 100644 --- a/src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs +++ b/src/settings-ui/Settings.UI.Library/LightSwitchSettings.cs @@ -60,6 +60,12 @@ namespace Settings.UI.Library Latitude = new StringProperty(Properties.Latitude.Value), Longitude = new StringProperty(Properties.Longitude.Value), ToggleThemeHotkey = new KeyboardKeysProperty(Properties.ToggleThemeHotkey.Value), + WallpaperEnabled = new BoolProperty(Properties.WallpaperEnabled.Value), + WallpaperVirtualDesktopEnabled = new BoolProperty(Properties.WallpaperVirtualDesktopEnabled.Value), + WallpaperStyleLight = new IntProperty((int)Properties.WallpaperStyleLight.Value), + WallpaperStyleDark = new IntProperty((int)Properties.WallpaperStyleDark.Value), + WallpaperPathLight = new StringProperty(Properties.WallpaperPathLight.Value), + WallpaperPathDark = new StringProperty(Properties.WallpaperPathDark.Value), }, }; } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/LightSwitchPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/LightSwitchPage.xaml index a44d482a04..21cc2e3411 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/LightSwitchPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/LightSwitchPage.xaml @@ -9,6 +9,7 @@ xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls" + xmlns:tkconverters="using:CommunityToolkit.WinUI.Converters" xmlns:ui="using:CommunityToolkit.WinUI" xmlns:viewModels="using:Microsoft.PowerToys.Settings.UI.ViewModels" d:DataContext="{d:DesignInstance Type=viewModels:LightSwitchViewModel}" @@ -17,6 +18,12 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +