Runner TrayIcon: Monochrome icon should adapt to windows theme instead of the app theme (#44931)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
As title
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #44891
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **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
- [ ] **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

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
============ System light + App Light
<img width="903" height="239" alt="image"
src="https://github.com/user-attachments/assets/581606fb-99b5-4df9-a520-545a0c04676c"
/>
============ System Light + App Dark
<img width="991" height="239" alt="image"
src="https://github.com/user-attachments/assets/822009e9-57cf-452b-b3aa-f1cbc25883f8"
/>
============ System Dark + App Light
<img width="932" height="236" alt="image"
src="https://github.com/user-attachments/assets/98a56d48-31f0-4f75-95a4-8c7dc83c3866"
/>
============ System Dark + App Dark
<img width="903" height="236" alt="image"
src="https://github.com/user-attachments/assets/2500a0d5-6b27-403e-89b4-69b7d3b91e79"
/>
============
This commit is contained in:
Kai Tao
2026-01-23 10:47:19 +08:00
committed by GitHub
parent d46a996fcd
commit 60b8419366
4 changed files with 97 additions and 14 deletions

View File

@@ -103,7 +103,6 @@ ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS ASYNCWINDOWPOS
atl atl
ATRIOX ATRIOX
ATX
aumid aumid
authenticode authenticode
AUTOBUDDY AUTOBUDDY
@@ -298,7 +297,6 @@ cpcontrols
cph cph
cplusplus cplusplus
CPower CPower
cppcoreguidelines
cpptools cpptools
cppvsdbg cppvsdbg
cppwinrt cppwinrt
@@ -327,7 +325,7 @@ CURRENTDIR
CURSORINFO CURSORINFO
cursorpos cursorpos
CURSORSHOWING CURSORSHOWING
CURSORWRAP cursorwrap
customaction customaction
CUSTOMACTIONTEST CUSTOMACTIONTEST
CUSTOMFORMATPLACEHOLDER CUSTOMFORMATPLACEHOLDER
@@ -1760,7 +1758,6 @@ SUBMODULEUPDATE
subresource subresource
Superbar Superbar
sut sut
swe
svchost svchost
SVGIn SVGIn
SVGIO SVGIO

View File

@@ -16,13 +16,50 @@ DWORD WINAPI _checkTheme(LPVOID lpParam)
void ThemeListener::AddChangedHandler(THEME_HANDLE handle) void ThemeListener::AddChangedHandler(THEME_HANDLE handle)
{ {
std::lock_guard<std::mutex> lock(handlesMutex);
handles.push_back(handle); handles.push_back(handle);
} }
void ThemeListener::DelChangedHandler(THEME_HANDLE handle) void ThemeListener::DelChangedHandler(THEME_HANDLE handle)
{ {
std::lock_guard<std::mutex> lock(handlesMutex);
auto it = std::find(handles.begin(), handles.end(), handle); auto it = std::find(handles.begin(), handles.end(), handle);
handles.erase(it); if (it != handles.end())
{
handles.erase(it);
}
}
void ThemeListener::AddAppThemeChangedHandler(THEME_HANDLE handle)
{
std::lock_guard<std::mutex> lock(handlesMutex);
appThemeHandles.push_back(handle);
}
void ThemeListener::DelAppThemeChangedHandler(THEME_HANDLE handle)
{
std::lock_guard<std::mutex> lock(handlesMutex);
auto it = std::find(appThemeHandles.begin(), appThemeHandles.end(), handle);
if (it != appThemeHandles.end())
{
appThemeHandles.erase(it);
}
}
void ThemeListener::AddSystemThemeChangedHandler(THEME_HANDLE handle)
{
std::lock_guard<std::mutex> lock(handlesMutex);
systemThemeHandles.push_back(handle);
}
void ThemeListener::DelSystemThemeChangedHandler(THEME_HANDLE handle)
{
std::lock_guard<std::mutex> lock(handlesMutex);
auto it = std::find(systemThemeHandles.begin(), systemThemeHandles.end(), handle);
if (it != systemThemeHandles.end())
{
systemThemeHandles.erase(it);
}
} }
void ThemeListener::CheckTheme() void ThemeListener::CheckTheme()
@@ -48,13 +85,51 @@ void ThemeListener::CheckTheme()
WaitForSingleObject(hEvent, INFINITE); WaitForSingleObject(hEvent, INFINITE);
auto _theme = ThemeHelpers::GetAppTheme(); auto _appTheme = ThemeHelpers::GetAppTheme();
if (AppTheme != _theme) auto _systemTheme = ThemeHelpers::GetSystemTheme();
bool appThemeChanged = (AppTheme != _appTheme);
bool systemThemeChanged = (SystemTheme != _systemTheme);
if (appThemeChanged || systemThemeChanged)
{ {
AppTheme = _theme; AppTheme = _appTheme;
for (int i = 0; i < handles.size(); i++) SystemTheme = _systemTheme;
// Copy handlers under lock, then invoke outside lock to avoid deadlock
std::vector<THEME_HANDLE> handlesCopy;
std::vector<THEME_HANDLE> appThemeHandlesCopy;
std::vector<THEME_HANDLE> systemThemeHandlesCopy;
{ {
handles[i](); std::lock_guard<std::mutex> lock(handlesMutex);
handlesCopy = handles;
if (appThemeChanged)
{
appThemeHandlesCopy = appThemeHandles;
}
if (systemThemeChanged)
{
systemThemeHandlesCopy = systemThemeHandles;
}
}
// Call generic handlers (backward compatible)
for (const auto& handler : handlesCopy)
{
handler();
}
// Call app theme specific handlers
for (const auto& handler : appThemeHandlesCopy)
{
handler();
}
// Call system theme specific handlers
for (const auto& handler : systemThemeHandlesCopy)
{
handler();
} }
} }
} }

View File

@@ -3,6 +3,7 @@
#include <windows.h> #include <windows.h>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <mutex>
typedef void (*THEME_HANDLE)(); typedef void (*THEME_HANDLE)();
DWORD WINAPI _checkTheme(LPVOID lpParam); DWORD WINAPI _checkTheme(LPVOID lpParam);
@@ -14,6 +15,7 @@ public:
ThemeListener() ThemeListener()
{ {
AppTheme = ThemeHelpers::GetAppTheme(); AppTheme = ThemeHelpers::GetAppTheme();
SystemTheme = ThemeHelpers::GetSystemTheme();
dwThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_checkTheme, this, 0, &dwThreadId); dwThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_checkTheme, this, 0, &dwThreadId);
} }
~ThemeListener() ~ThemeListener()
@@ -23,12 +25,20 @@ public:
} }
Theme AppTheme; Theme AppTheme;
Theme SystemTheme;
void ThemeListener::AddChangedHandler(THEME_HANDLE handle); void ThemeListener::AddChangedHandler(THEME_HANDLE handle);
void ThemeListener::DelChangedHandler(THEME_HANDLE handle); void ThemeListener::DelChangedHandler(THEME_HANDLE handle);
void ThemeListener::AddAppThemeChangedHandler(THEME_HANDLE handle);
void ThemeListener::DelAppThemeChangedHandler(THEME_HANDLE handle);
void ThemeListener::AddSystemThemeChangedHandler(THEME_HANDLE handle);
void ThemeListener::DelSystemThemeChangedHandler(THEME_HANDLE handle);
void CheckTheme(); void CheckTheme();
private: private:
HANDLE dwThreadHandle; HANDLE dwThreadHandle;
DWORD dwThreadId; DWORD dwThreadId;
std::vector<THEME_HANDLE> handles; std::vector<THEME_HANDLE> handles;
std::vector<THEME_HANDLE> appThemeHandles;
std::vector<THEME_HANDLE> systemThemeHandles;
mutable std::mutex handlesMutex;
}; };

View File

@@ -14,6 +14,7 @@
#include <common/logger/logger.h> #include <common/logger/logger.h>
#include <common/utils/elevation.h> #include <common/utils/elevation.h>
#include <common/Themes/theme_listener.h> #include <common/Themes/theme_listener.h>
#include <common/Themes/theme_helpers.h>
#include "bug_report.h" #include "bug_report.h"
namespace namespace
@@ -293,7 +294,7 @@ static void handle_theme_change()
{ {
if (theme_adaptive_enabled) if (theme_adaptive_enabled)
{ {
tray_icon_data.hIcon = get_icon(theme_listener.AppTheme); tray_icon_data.hIcon = get_icon(ThemeHelpers::GetSystemTheme());
Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data); Shell_NotifyIcon(NIM_MODIFY, &tray_icon_data);
} }
} }
@@ -310,7 +311,7 @@ void start_tray_icon(bool isProcessElevated, bool theme_adaptive)
{ {
theme_adaptive_enabled = theme_adaptive; theme_adaptive_enabled = theme_adaptive;
auto h_instance = reinterpret_cast<HINSTANCE>(&__ImageBase); auto h_instance = reinterpret_cast<HINSTANCE>(&__ImageBase);
HICON const icon = theme_adaptive ? get_icon(theme_listener.AppTheme) : LoadIcon(h_instance, MAKEINTRESOURCE(APPICON)); HICON const icon = theme_adaptive ? get_icon(ThemeHelpers::GetSystemTheme()) : LoadIcon(h_instance, MAKEINTRESOURCE(APPICON));
if (icon) if (icon)
{ {
UINT id_tray_icon = 1; UINT id_tray_icon = 1;
@@ -357,7 +358,7 @@ void start_tray_icon(bool isProcessElevated, bool theme_adaptive)
ChangeWindowMessageFilterEx(hwnd, WM_COMMAND, MSGFLT_ALLOW, nullptr); ChangeWindowMessageFilterEx(hwnd, WM_COMMAND, MSGFLT_ALLOW, nullptr);
tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE; tray_icon_created = Shell_NotifyIcon(NIM_ADD, &tray_icon_data) == TRUE;
theme_listener.AddChangedHandler(&handle_theme_change); theme_listener.AddSystemThemeChangedHandler(&handle_theme_change);
// Register callback to update bug report menu item status // Register callback to update bug report menu item status
BugReportManager::instance().register_callback([](bool isRunning) { BugReportManager::instance().register_callback([](bool isRunning) {
@@ -389,7 +390,7 @@ void set_tray_icon_theme_adaptive(bool theme_adaptive)
if (theme_adaptive) if (theme_adaptive)
{ {
icon = get_icon(theme_listener.AppTheme); icon = get_icon(ThemeHelpers::GetSystemTheme());
if (!icon) if (!icon)
{ {
Logger::warn(L"set_tray_icon_theme_adaptive: Failed to load theme adaptive icon, falling back to default"); Logger::warn(L"set_tray_icon_theme_adaptive: Failed to load theme adaptive icon, falling back to default");