From eace5486359ecfbf5cea9625903ca454f1ee05a2 Mon Sep 17 00:00:00 2001 From: Gleb Khmyznikov Date: Tue, 16 Dec 2025 21:39:13 -0800 Subject: [PATCH] Introduce common library for themes and fix tests --- PowerToys.slnx | 1 + .../LightSwitchLib/LightSwitchLib.vcxproj | 123 ++++++++++++++++++ .../LightSwitchLib.vcxproj.filters | 33 +++++ .../ThemeHelper.cpp | 11 +- .../LightSwitch/LightSwitchLib/ThemeHelper.h | 10 ++ .../LightSwitch/LightSwitchLib/pch.cpp | 1 + src/modules/LightSwitch/LightSwitchLib/pch.h | 5 + .../ExportedFunctions.cpp | 22 ++++ .../LightSwitchModuleInterface.vcxproj | 8 +- .../ThemeHelper.cpp | 106 --------------- .../LightSwitchModuleInterface/ThemeHelper.h | 5 - .../LightSwitchService.vcxproj | 8 +- .../LightSwitchService/SettingsConstants.h | 3 - .../LightSwitchService/ThemeHelper.h | 6 - .../LightSwitch.UITests.csproj | 5 + .../Tests/LightSwitch.UITests/TestHelper.cs | 87 ++++++++++--- 16 files changed, 286 insertions(+), 148 deletions(-) create mode 100644 src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj create mode 100644 src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj.filters rename src/modules/LightSwitch/{LightSwitchService => LightSwitchLib}/ThemeHelper.cpp (94%) create mode 100644 src/modules/LightSwitch/LightSwitchLib/ThemeHelper.h create mode 100644 src/modules/LightSwitch/LightSwitchLib/pch.cpp create mode 100644 src/modules/LightSwitch/LightSwitchLib/pch.h create mode 100644 src/modules/LightSwitch/LightSwitchModuleInterface/ExportedFunctions.cpp delete mode 100644 src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.cpp delete mode 100644 src/modules/LightSwitch/LightSwitchModuleInterface/ThemeHelper.h delete mode 100644 src/modules/LightSwitch/LightSwitchService/ThemeHelper.h diff --git a/PowerToys.slnx b/PowerToys.slnx index 1884b2d58b..69db025332 100644 --- a/PowerToys.slnx +++ b/PowerToys.slnx @@ -640,6 +640,7 @@ + diff --git a/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj b/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj new file mode 100644 index 0000000000..dbc97ab86e --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj @@ -0,0 +1,123 @@ + + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 17.0 + Win32Proj + {79267138-2895-4346-9021-21408d65379f} + LightSwitchLib + 10.0.26100.0 + LightSwitchLib + + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\$(Platform)\$(Configuration)\$(MSBuildProjectName)\ + + + + Level3 + true + _LIB;%(PreprocessorDefinitions) + true + Use + pch.h + + ./; + ..\..\..\common; + ..\..\..\common\logger; + ..\..\..\common\utils; + ..\..\..\..\deps\spdlog\include; + %(AdditionalIncludeDirectories) + + + + Windows + true + + + + + + + + + Create + Create + Create + Create + + + + + + {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} + + + + + + + + diff --git a/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj.filters b/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj.filters new file mode 100644 index 0000000000..0792aad8f7 --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchLib/LightSwitchLib.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + diff --git a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp b/src/modules/LightSwitch/LightSwitchLib/ThemeHelper.cpp similarity index 94% rename from src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp rename to src/modules/LightSwitch/LightSwitchLib/ThemeHelper.cpp index cfa858c636..ccd8ff244f 100644 --- a/src/modules/LightSwitch/LightSwitchService/ThemeHelper.cpp +++ b/src/modules/LightSwitch/LightSwitchLib/ThemeHelper.cpp @@ -1,9 +1,6 @@ -#include -#include -#include -#include +#include "pch.h" #include "ThemeHelper.h" -#include +#include // Controls changing the themes. @@ -63,7 +60,7 @@ void SetSystemTheme(bool mode) if (mode) // if are changing to light mode { ResetColorPrevalence(); - Logger::info(L"[LightSwitchService] Reset ColorPrevalence to default when switching to light mode."); + Logger::info(L"[LightSwitchLib] Reset ColorPrevalence to default when switching to light mode."); } SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, reinterpret_cast(L"ImmersiveColorSet"), SMTO_ABORTIFHUNG, 5000, nullptr); @@ -136,4 +133,4 @@ bool IsNightLightEnabled() RegCloseKey(hKey); return data[23] == 0x10 && data[24] == 0x00; -} \ No newline at end of file +} diff --git a/src/modules/LightSwitch/LightSwitchLib/ThemeHelper.h b/src/modules/LightSwitch/LightSwitchLib/ThemeHelper.h new file mode 100644 index 0000000000..8720a3b19d --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchLib/ThemeHelper.h @@ -0,0 +1,10 @@ +#pragma once + +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"; + +void SetSystemTheme(bool isLight); +void SetAppsTheme(bool isLight); +bool GetCurrentSystemTheme(); +bool GetCurrentAppsTheme(); +bool IsNightLightEnabled(); diff --git a/src/modules/LightSwitch/LightSwitchLib/pch.cpp b/src/modules/LightSwitch/LightSwitchLib/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchLib/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/src/modules/LightSwitch/LightSwitchLib/pch.h b/src/modules/LightSwitch/LightSwitchLib/pch.h new file mode 100644 index 0000000000..b8d235d9c5 --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchLib/pch.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include +#include diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/ExportedFunctions.cpp b/src/modules/LightSwitch/LightSwitchModuleInterface/ExportedFunctions.cpp new file mode 100644 index 0000000000..d9046c361e --- /dev/null +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/ExportedFunctions.cpp @@ -0,0 +1,22 @@ +#include "pch.h" +#include "ThemeHelper.h" + +extern "C" __declspec(dllexport) void __cdecl LightSwitch_SetSystemTheme(bool isLight) +{ + SetSystemTheme(isLight); +} + +extern "C" __declspec(dllexport) void __cdecl LightSwitch_SetAppsTheme(bool isLight) +{ + SetAppsTheme(isLight); +} + +extern "C" __declspec(dllexport) bool __cdecl LightSwitch_GetCurrentSystemTheme() +{ + return GetCurrentSystemTheme(); +} + +extern "C" __declspec(dllexport) bool __cdecl LightSwitch_GetCurrentAppsTheme() +{ + return GetCurrentAppsTheme(); +} diff --git a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj index 261cfab1e6..a7ef9f21d7 100644 --- a/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj +++ b/src/modules/LightSwitch/LightSwitchModuleInterface/LightSwitchModuleInterface.vcxproj @@ -166,7 +166,7 @@ - ..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\LightSwitchLib;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) $(CoreLibraryDependencies);%(AdditionalDependencies);advapi32.lib @@ -175,11 +175,11 @@ - + Create Create @@ -190,7 +190,6 @@ pch.h pch.h - @@ -206,6 +205,9 @@ {6955446d-23f7-4023-9bb3-8657f904af99} + + {79267138-2895-4346-9021-21408d65379f} + 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/LightSwitchService/LightSwitchService.vcxproj b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj index e1c8052de6..0aff50ccab 100644 --- a/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj +++ b/src/modules/LightSwitch/LightSwitchService/LightSwitchService.vcxproj @@ -55,6 +55,7 @@ %(PreprocessorDefinitions) ./../; + ..\LightSwitchLib; ..\..\..\common; ..\..\..\common\logger; ..\..\..\common\utils; @@ -78,7 +79,6 @@ - @@ -92,7 +92,6 @@ - @@ -109,6 +108,9 @@ {8f021b46-362b-485c-bfba-ccf83e820cbd} + + {79267138-2895-4346-9021-21408d65379f} + @@ -116,4 +118,4 @@ - \ No newline at end of file + diff --git a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h b/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h index 8015c9b3e6..1ec1f36340 100644 --- a/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h +++ b/src/modules/LightSwitch/LightSwitchService/SettingsConstants.h @@ -12,6 +12,3 @@ enum class SettingId 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.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/modules/LightSwitch/Tests/LightSwitch.UITests/LightSwitch.UITests.csproj b/src/modules/LightSwitch/Tests/LightSwitch.UITests/LightSwitch.UITests.csproj index 9770255af6..f457025c0e 100644 --- a/src/modules/LightSwitch/Tests/LightSwitch.UITests/LightSwitch.UITests.csproj +++ b/src/modules/LightSwitch/Tests/LightSwitch.UITests/LightSwitch.UITests.csproj @@ -19,4 +19,9 @@ + + + + + \ No newline at end of file diff --git a/src/modules/LightSwitch/Tests/LightSwitch.UITests/TestHelper.cs b/src/modules/LightSwitch/Tests/LightSwitch.UITests/TestHelper.cs index 37041b4b2d..d7748fc2f5 100644 --- a/src/modules/LightSwitch/Tests/LightSwitch.UITests/TestHelper.cs +++ b/src/modules/LightSwitch/Tests/LightSwitch.UITests/TestHelper.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.PowerToys.UITest; @@ -17,6 +18,20 @@ namespace LightSwitch.UITests { private static readonly string[] ShortcutSeparators = { " + ", "+", " " }; + [DllImport("PowerToys.LightSwitchModuleInterface.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void LightSwitch_SetSystemTheme(bool isLight); + + [DllImport("PowerToys.LightSwitchModuleInterface.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern void LightSwitch_SetAppsTheme(bool isLight); + + [DllImport("PowerToys.LightSwitchModuleInterface.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool LightSwitch_GetCurrentSystemTheme(); + + [DllImport("PowerToys.LightSwitchModuleInterface.dll", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private static extern bool LightSwitch_GetCurrentAppsTheme(); + /// /// Performs common test initialization: navigate to settings, enable toggle, verify shortcut /// @@ -127,8 +142,7 @@ namespace LightSwitch.UITests /// The test base instance public static void CleanupTest(UITestBase testBase) { - // TODO: Make sure the task kills? - // CloseLightSwitch(testBase); + CloseLightSwitch(testBase); // Ensure we're attached to settings after cleanup try @@ -141,6 +155,51 @@ namespace LightSwitch.UITests } } + /// + /// Switch to white/light theme for both system and apps + /// + /// The test base instance + public static void CloseLightSwitch(UITestBase testBase) + { + // Kill LightSwitch process before setting themes + KillLightSwitchProcess(); + + // Set both themes to light (white) + SetSystemTheme(true); + SetAppsTheme(true); + } + + /// + /// Kill the LightSwitch service process if it's running + /// + private static void KillLightSwitchProcess() + { + try + { + var processes = System.Diagnostics.Process.GetProcessesByName("PowerToys.LightSwitchService"); + foreach (var process in processes) + { + try + { + process.Kill(); + process.WaitForExit(2000); + } + catch + { + // Ignore errors killing individual processes + } + finally + { + process.Dispose(); + } + } + } + catch + { + // Ignore errors enumerating processes + } + } + /// /// Perform a update time test operation /// @@ -408,24 +467,22 @@ namespace LightSwitch.UITests /* Helpers */ private static int GetSystemTheme() { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); - if (key is null) - { - return 1; - } - - return (int)key.GetValue("SystemUsesLightTheme", 1); + return LightSwitch_GetCurrentSystemTheme() ? 1 : 0; } private static int GetAppsTheme() { - using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); - if (key is null) - { - return 1; - } + return LightSwitch_GetCurrentAppsTheme() ? 1 : 0; + } - return (int)key.GetValue("AppsUseLightTheme", 1); + private static void SetSystemTheme(bool isLight) + { + LightSwitch_SetSystemTheme(isLight); + } + + private static void SetAppsTheme(bool isLight) + { + LightSwitch_SetAppsTheme(isLight); } private static string GetHelpTextValue(string helpText, string key)