https://bugs.winehq.org/show_bug.cgi?id=51348
Bug ID: 51348 Summary: uxtheme.SetWindowTheme should use SendMessage to send WM_THEMECHANGED Product: Wine Version: 6.11 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: uxtheme Assignee: wine-bugs@winehq.org Reporter: x1917x@gmail.com Distribution: ---
Created attachment 70205 --> https://bugs.winehq.org/attachment.cgi?id=70205 Bad behavior
The issue affects SourceInsight 4 in particular. SourceInsight has its own built-in theme functionality which doesn't get along well with any non-standard Wine theme.
When a non-standard Wine theme is selected, then the main toolbar in SI4 ignores its app theme and always gets drawn with the selected Wine theme. Selecting the default Wine theme fixes the issue - the toolbar is drawn according to the app theme. On Windows it's ok no matter which UI theme is set. Screenshot of the issue is attached.
The root cause of the issue is that UXTHEME_broadcast_msg/UXTHEME_broadcast_msg_enumchild in dlls/uxtheme/system.c both use a PostMessage() call to send WM_THEMECHANGED to affected window(s).
In SI4 the main toolbar is implemented as a combination of a custom container window (si_Rebar class) and a standard win32 Rebar control (RebarWindow32 class).
Immediately after creating the RebarWindow32 window, SI4 does SetWindowTheme(hwndRebar, L" ", L" ") for it.
According to MSDN (https://docs.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-setwin...)
The theme manager retains the pszSubAppName and the pszSubIdList associations through the lifetime of the window, even if visual styles subsequently change. The window is sent a WM_THEMECHANGED message at the end of a SetWindowTheme call, so that the new visual style can be found and applied.
When pszSubAppName and pszSubIdList are NULL, the theme manager removes the previously applied associations. You can prevent visual styles from being applied to a specified window by specifying an empty string, (L" "), which does not match any section entries.
- this L" ", L" " stuff means that SI4 DOES NOT want for system visual styles being applied to its RebarWindow32 control. However, according to WINEDEBUG logs they were applied to all bg erase, painting etc operations no matter the SetWindowTheme(, L" ", L" ") call.
Turns out that RebarWindow32' WndProc receives WM_THEMECHANGED too late, after all stuff including drawing already happened with the system-wide theme being applied. The reason why it was received so late is simple - SetWindowTheme implementation in wine uses PostMessage() instead of SendMessage(). Replacing it with a SendMessage() call allows to fix the bug.
I've checked what Windows actually does in SetWindowTheme and found out that it always uses SendMessage to send WM_THEMECHANGED (for any HWND).
So. suggested fix:
diff --git a/dlls/uxtheme/system.c b/dlls/uxtheme/system.c index a37e532500a..3b6e6d2b6b6 100644 --- a/dlls/uxtheme/system.c +++ b/dlls/uxtheme/system.c @@ -59,7 +59,7 @@ static WCHAR szCurrentSize[64];
static BOOL CALLBACK UXTHEME_broadcast_msg_enumchild (HWND hWnd, LPARAM msg) { - PostMessageW(hWnd, msg, 0, 0); + SendMessageW(hWnd, msg, 0, 0); return TRUE; }
@@ -72,7 +72,7 @@ static BOOL CALLBACK UXTHEME_broadcast_msg (HWND hWnd, LPARAM msg) } else { - PostMessageW(hWnd, msg, 0, 0); + SendMessageW(hWnd, msg, 0, 0); EnumChildWindows (hWnd, UXTHEME_broadcast_msg_enumchild, msg); } return TRUE;