diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index ffb0654c40..79bf8cfcea 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -103,7 +103,6 @@ ASYNCWINDOWPLACEMENT ASYNCWINDOWPOS atl ATRIOX -ATX aumid authenticode AUTOBUDDY @@ -298,7 +297,6 @@ cpcontrols cph cplusplus CPower -cppcoreguidelines cpptools cppvsdbg cppwinrt @@ -327,7 +325,7 @@ CURRENTDIR CURSORINFO cursorpos CURSORSHOWING -CURSORWRAP +cursorwrap customaction CUSTOMACTIONTEST CUSTOMFORMATPLACEHOLDER @@ -1760,7 +1758,6 @@ SUBMODULEUPDATE subresource Superbar sut -swe svchost SVGIn SVGIO diff --git a/src/common/Themes/theme_listener.cpp b/src/common/Themes/theme_listener.cpp index 3a31b0db3c..972953a53c 100644 --- a/src/common/Themes/theme_listener.cpp +++ b/src/common/Themes/theme_listener.cpp @@ -16,13 +16,50 @@ DWORD WINAPI _checkTheme(LPVOID lpParam) void ThemeListener::AddChangedHandler(THEME_HANDLE handle) { + std::lock_guard lock(handlesMutex); handles.push_back(handle); } void ThemeListener::DelChangedHandler(THEME_HANDLE handle) { + std::lock_guard lock(handlesMutex); 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 lock(handlesMutex); + appThemeHandles.push_back(handle); +} + +void ThemeListener::DelAppThemeChangedHandler(THEME_HANDLE handle) +{ + std::lock_guard 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 lock(handlesMutex); + systemThemeHandles.push_back(handle); +} + +void ThemeListener::DelSystemThemeChangedHandler(THEME_HANDLE handle) +{ + std::lock_guard lock(handlesMutex); + auto it = std::find(systemThemeHandles.begin(), systemThemeHandles.end(), handle); + if (it != systemThemeHandles.end()) + { + systemThemeHandles.erase(it); + } } void ThemeListener::CheckTheme() @@ -48,13 +85,51 @@ void ThemeListener::CheckTheme() WaitForSingleObject(hEvent, INFINITE); - auto _theme = ThemeHelpers::GetAppTheme(); - if (AppTheme != _theme) + auto _appTheme = ThemeHelpers::GetAppTheme(); + auto _systemTheme = ThemeHelpers::GetSystemTheme(); + + bool appThemeChanged = (AppTheme != _appTheme); + bool systemThemeChanged = (SystemTheme != _systemTheme); + + if (appThemeChanged || systemThemeChanged) { - AppTheme = _theme; - for (int i = 0; i < handles.size(); i++) + AppTheme = _appTheme; + SystemTheme = _systemTheme; + + // Copy handlers under lock, then invoke outside lock to avoid deadlock + std::vector handlesCopy; + std::vector appThemeHandlesCopy; + std::vector systemThemeHandlesCopy; + { - handles[i](); + std::lock_guard 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(); } } } diff --git a/src/common/Themes/theme_listener.h b/src/common/Themes/theme_listener.h index a6ab4464fc..6937f60dd2 100644 --- a/src/common/Themes/theme_listener.h +++ b/src/common/Themes/theme_listener.h @@ -3,6 +3,7 @@ #include #include #include +#include typedef void (*THEME_HANDLE)(); DWORD WINAPI _checkTheme(LPVOID lpParam); @@ -14,6 +15,7 @@ public: ThemeListener() { AppTheme = ThemeHelpers::GetAppTheme(); + SystemTheme = ThemeHelpers::GetSystemTheme(); dwThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)_checkTheme, this, 0, &dwThreadId); } ~ThemeListener() @@ -23,12 +25,20 @@ public: } Theme AppTheme; + Theme SystemTheme; void ThemeListener::AddChangedHandler(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(); private: HANDLE dwThreadHandle; DWORD dwThreadId; std::vector handles; + std::vector appThemeHandles; + std::vector systemThemeHandles; + mutable std::mutex handlesMutex; }; \ No newline at end of file diff --git a/src/runner/tray_icon.cpp b/src/runner/tray_icon.cpp index 633c2c1b42..8fa892e312 100644 --- a/src/runner/tray_icon.cpp +++ b/src/runner/tray_icon.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "bug_report.h" namespace @@ -293,7 +294,7 @@ static void handle_theme_change() { 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); } } @@ -310,7 +311,7 @@ void start_tray_icon(bool isProcessElevated, bool theme_adaptive) { theme_adaptive_enabled = theme_adaptive; auto h_instance = reinterpret_cast(&__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) { 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); 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 BugReportManager::instance().register_callback([](bool isRunning) { @@ -389,7 +390,7 @@ void set_tray_icon_theme_adaptive(bool theme_adaptive) if (theme_adaptive) { - icon = get_icon(theme_listener.AppTheme); + icon = get_icon(ThemeHelpers::GetSystemTheme()); if (!icon) { Logger::warn(L"set_tray_icon_theme_adaptive: Failed to load theme adaptive icon, falling back to default");