From 177e874ef97df111d87fd05d4e65d792bcc062b6 Mon Sep 17 00:00:00 2001 From: Michael Maltsev <4129781+m417z@users.noreply.github.com> Date: Fri, 1 Nov 2024 23:28:03 +0200 Subject: [PATCH] Taskbar Background Helper v1.0.2 (#1188) * Fixed the background not updating in some cases, e.g. when exiting Firefox. * Added support for Win+Tab and other fullscreen windows. --- mods/taskbar-background-helper.wh.cpp | 185 +++++++++++++++++--------- 1 file changed, 120 insertions(+), 65 deletions(-) diff --git a/mods/taskbar-background-helper.wh.cpp b/mods/taskbar-background-helper.wh.cpp index 860ae0f5..a6b102a2 100644 --- a/mods/taskbar-background-helper.wh.cpp +++ b/mods/taskbar-background-helper.wh.cpp @@ -2,7 +2,7 @@ // @id taskbar-background-helper // @name Taskbar Background Helper // @description Sets the taskbar background for the transparent parts, always or only when there's a maximized window, designed to be used with Windows 11 Taskbar Styler -// @version 1.0.1 +// @version 1.0.2 // @author m417z // @github https://github.com/m417z // @twitter https://twitter.com/m417z @@ -86,6 +86,8 @@ a workaround. #include +#include +#include #include #include @@ -106,10 +108,19 @@ struct { std::optional darkModeStyle; } g_settings; -HANDLE g_winObjectLocationChangeThread; +std::mutex g_winEventHookThreadMutex; +std::atomic g_winEventHookThread; std::unordered_set g_pendingMonitors; UINT_PTR g_pendingMonitorsTimer; +// Missing in older MinGW headers. +#ifndef EVENT_OBJECT_CLOAKED +#define EVENT_OBJECT_CLOAKED 0x8017 +#endif +#ifndef EVENT_OBJECT_UNCLOAKED +#define EVENT_OBJECT_UNCLOAKED 0x8018 +#endif + enum WINDOWCOMPOSITIONATTRIB { WCA_UNDEFINED = 0, WCA_NCRENDERING_ENABLED = 1, @@ -303,7 +314,13 @@ HWND GetTaskbarForMonitor(HMONITOR monitor) { bool DoesMonitorHaveMaximizedWindow(HMONITOR monitor) { bool hasMaximized = false; - auto enumWindowsProc = [monitor, &hasMaximized](HWND hWnd) -> BOOL { + MONITORINFO monitorInfo{ + .cbSize = sizeof(monitorInfo), + }; + GetMonitorInfo(monitor, &monitorInfo); + + auto enumWindowsProc = [monitor, &monitorInfo, + &hasMaximized](HWND hWnd) -> BOOL { if (MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST) != monitor) { return TRUE; } @@ -312,20 +329,27 @@ bool DoesMonitorHaveMaximizedWindow(HMONITOR monitor) { return TRUE; } - if (GetWindowLong(hWnd, GWL_EXSTYLE) & - (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW)) { + if (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) { return TRUE; } WINDOWPLACEMENT wp{ .length = sizeof(WINDOWPLACEMENT), }; - if (!GetWindowPlacement(hWnd, &wp) || wp.showCmd != SW_SHOWMAXIMIZED) { - return TRUE; + if (GetWindowPlacement(hWnd, &wp) && wp.showCmd == SW_SHOWMAXIMIZED) { + hasMaximized = true; + return FALSE; } - hasMaximized = true; - return FALSE; + RECT rc; + if (GetWindowRect(hWnd, &rc) && + EqualRect(&rc, &monitorInfo.rcMonitor)) { + // Spans across the whole monitor, e.g. Win+Tab view. + hasMaximized = true; + return FALSE; + } + + return TRUE; }; EnumWindows( @@ -338,13 +362,13 @@ bool DoesMonitorHaveMaximizedWindow(HMONITOR monitor) { return hasMaximized; } -void CALLBACK LocationChangeWinEventProc(HWINEVENTHOOK hWinEventHook, - DWORD event, - HWND hWnd, - LONG idObject, - LONG idChild, - DWORD dwEventThread, - DWORD dwmsEventTime) { +void CALLBACK WinEventProc(HWINEVENTHOOK hWinEventHook, + DWORD event, + HWND hWnd, + LONG idObject, + LONG idChild, + DWORD dwEventThread, + DWORD dwmsEventTime) { if (idObject != OBJID_WINDOW) { return; } @@ -383,8 +407,71 @@ void CALLBACK LocationChangeWinEventProc(HWINEVENTHOOK hWinEventHook, }); } +DWORD WINAPI WinEventHookThread(LPVOID lpThreadParameter) { + HWINEVENTHOOK winObjectEventHook1 = + SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_HIDE, nullptr, + WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); + if (!winObjectEventHook1) { + Wh_Log(L"Error: SetWinEventHook"); + } + + HWINEVENTHOOK winObjectEventHook2 = SetWinEventHook( + EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, nullptr, + WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); + if (!winObjectEventHook2) { + Wh_Log(L"Error: SetWinEventHook"); + } + + HWINEVENTHOOK winObjectEventHook3 = + SetWinEventHook(EVENT_OBJECT_CLOAKED, EVENT_OBJECT_UNCLOAKED, nullptr, + WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); + if (!winObjectEventHook3) { + Wh_Log(L"Error: SetWinEventHook"); + } + + BOOL bRet; + MSG msg; + while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { + if (bRet == -1) { + msg.wParam = 0; + break; + } + + if (msg.hwnd == NULL && msg.message == WM_APP) { + PostQuitMessage(0); + continue; + } + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (winObjectEventHook1) { + UnhookWinEvent(winObjectEventHook1); + } + + if (winObjectEventHook2) { + UnhookWinEvent(winObjectEventHook2); + } + + if (winObjectEventHook3) { + UnhookWinEvent(winObjectEventHook3); + } + + return 0; +} + BOOL AdjustTaskbarStyle(HWND hWnd) { if (g_settings.onlyWhenMaximized) { + if (!g_winEventHookThread) { + std::lock_guard guard(g_winEventHookThreadMutex); + + if (!g_winEventHookThread) { + g_winEventHookThread = CreateThread( + nullptr, 0, WinEventHookThread, nullptr, 0, nullptr); + } + } + HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); if (!DoesMonitorHaveMaximizedWindow(monitor)) { return ResetTaskbarStyle(hWnd); @@ -550,57 +637,22 @@ BOOL Wh_ModInit() { } void Wh_ModAfterInit() { + Wh_Log(L">"); + WNDCLASS wndclass; if (GetClassInfo(GetModuleHandle(NULL), L"Shell_TrayWnd", &wndclass)) { AdjustAllTaskbarStyles(); } - - if (g_settings.onlyWhenMaximized) { - g_winObjectLocationChangeThread = CreateThread( - nullptr, 0, - [](LPVOID lpParameter) WINAPI -> DWORD { - HWINEVENTHOOK winObjectLocationChangeEventHook = - SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, - EVENT_OBJECT_LOCATIONCHANGE, nullptr, - LocationChangeWinEventProc, 0, 0, - WINEVENT_OUTOFCONTEXT); - if (!winObjectLocationChangeEventHook) { - Wh_Log(L"Error: SetWinEventHook"); - return 0; - } - - BOOL bRet; - MSG msg; - while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { - if (bRet == -1) { - msg.wParam = 0; - break; - } - - if (msg.hwnd == NULL && msg.message == WM_APP) { - PostQuitMessage(0); - continue; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - UnhookWinEvent(winObjectLocationChangeEventHook); - return 0; - }, - nullptr, 0, nullptr); - } } void Wh_ModUninit() { Wh_Log(L">"); - if (g_winObjectLocationChangeThread) { - PostThreadMessage(GetThreadId(g_winObjectLocationChangeThread), WM_APP, - 0, 0); - WaitForSingleObject(g_winObjectLocationChangeThread, INFINITE); - CloseHandle(g_winObjectLocationChangeThread); + if (g_winEventHookThread) { + PostThreadMessage(GetThreadId(g_winEventHookThread), WM_APP, 0, 0); + WaitForSingleObject(g_winEventHookThread, INFINITE); + CloseHandle(g_winEventHookThread); + g_winEventHookThread = nullptr; } std::unordered_set secondaryTaskbarWindows; @@ -614,18 +666,21 @@ void Wh_ModUninit() { } } -BOOL Wh_ModSettingsChanged(BOOL* bReload) { +void Wh_ModSettingsChanged() { Wh_Log(L">"); - bool prevOnlyWhenMaximized = g_settings.onlyWhenMaximized; - LoadSettings(); - *bReload = g_settings.onlyWhenMaximized != prevOnlyWhenMaximized; + if (!g_settings.onlyWhenMaximized) { + std::lock_guard guard(g_winEventHookThreadMutex); - if (!*bReload) { - AdjustAllTaskbarStyles(); + if (g_winEventHookThread) { + PostThreadMessage(GetThreadId(g_winEventHookThread), WM_APP, 0, 0); + WaitForSingleObject(g_winEventHookThread, INFINITE); + CloseHandle(g_winEventHookThread); + g_winEventHookThread = nullptr; + } } - return TRUE; + AdjustAllTaskbarStyles(); }