comctl32/toolbar: Erase the background in TOOLBAR_Refresh() when TBSTYLE_TRANSPARENT is present for comctl32 v6.
Comctl32 v6 erases the background when TBSTYLE_TRANSPARENT is present when handling WM_PAINT, not when handling WM_ERASEBKGND. WxWidgets relies on this behavior to draw the toolbar background. Please see https://github.com/wxWidgets/wxWidgets/blob/v2.9.4/src/msw/toolbar.cpp#L1805.
Fix tlReader 10.1.0.2004 toolbar broken rendering after 5e70fef5. After the commit, the comctl32 v6 version is properly reported and wxWidgets decides to use a comctl32 v6 specific code path.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/comctl32/tests/toolbar.c | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index 97d6acb781f..93fe68bdec9 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -2959,6 +2959,62 @@ static void test_unicode_format(void) DestroyWindow(hwnd); }
+static void test_WM_ERASEBKGND(BOOL v6) +{ + COLORREF color; + HBRUSH brush; + LRESULT lr; + HWND hwnd; + RECT rect; + HDC hdc; + + /* Check WM_ERASEBKGND without TBSTYLE_TRANSPARENT */ + hwnd = CreateWindowA(TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE, 100, 100, 100, 100, + hMainWnd, NULL, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "CreateWindowA failed.\n"); + + GetClientRect(hwnd, &rect); + brush = CreateSolidBrush(RGB(255, 0, 0)); + hdc = GetDC(hwnd); + FillRect(hdc, &rect, brush); + color = GetPixel(hdc, 10, 10); + ok(color == RGB(255, 0, 0), "Got unexpected color %#lx.\n", color); + + lr = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok(lr == 1, "Got unexpected %Id.\n", lr); + color = GetPixel(hdc, 10, 10); + ok(color != RGB(255, 0, 0), "Got unexpected color %#lx.\n", color); + + DeleteObject(brush); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); + + /* Check WM_ERASEBKGND with TBSTYLE_TRANSPARENT */ + hwnd = CreateWindowA(TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_TRANSPARENT, 100, + 100, 100, 100, hMainWnd, NULL, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "CreateWindowA failed.\n"); + + GetClientRect(hwnd, &rect); + brush = CreateSolidBrush(RGB(255, 0, 0)); + hdc = GetDC(hwnd); + FillRect(hdc, &rect, brush); + color = GetPixel(hdc, 10, 10); + ok(color == RGB(255, 0, 0), "Got unexpected color %#lx.\n", color); + + lr = SendMessageA(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0); + ok(lr == 1, "Got unexpected %Id.\n", lr); + color = GetPixel(hdc, 10, 10); + if (v6) + todo_wine + ok(color == RGB(255, 0, 0), "Got unexpected color %#lx.\n", color); + else + ok(color == GetSysColor(COLOR_WINDOW), "Got unexpected color %#lx.\n", color); + + DeleteObject(brush); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); +} + START_TEST(toolbar) { ULONG_PTR ctx_cookie; @@ -3012,6 +3068,7 @@ START_TEST(toolbar) test_BTNS_SEP(); test_WM_NOTIFY(); test_unicode_format(); + test_WM_ERASEBKGND(FALSE);
if (!load_v6_module(&ctx_cookie, &ctx)) return; @@ -3020,6 +3077,7 @@ START_TEST(toolbar) test_visual(); test_BTNS_SEP(); test_unicode_format(); + test_WM_ERASEBKGND(TRUE);
PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) {
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/comctl32/tests/toolbar.c | 90 +++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+)
diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index 93fe68bdec9..b3e8efd1759 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -104,6 +104,22 @@ static const struct message restore_parent_seq[] = { { 0 } };
+static const struct message wm_paint_parent_seq[] = { + { WM_NOTIFY, sent }, + { 0 } +}; + +static const struct message wm_paint_transparent_parent_v5_seq[] = { + { WM_NOTIFY, sent }, + { 0 } +}; + +static const struct message wm_paint_transparent_parent_v6_seq[] = { + { WM_ERASEBKGND, sent }, + { WM_NOTIFY, sent }, + { 0 } +}; + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
@@ -3015,6 +3031,78 @@ static void test_WM_ERASEBKGND(BOOL v6) DestroyWindow(hwnd); }
+static LRESULT CALLBACK wm_paint_parent_wnd_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) +{ + static LONG defwndproc_counter = 0; + struct message msg; + LRESULT ret; + + msg.message = message; + msg.flags = sent | wparam | lparam; + if (defwndproc_counter) + msg.flags |= defwinproc; + msg.wParam = wp; + msg.lParam = lp; + + add_message(sequences, PARENT_SEQ_INDEX, &msg); + + defwndproc_counter++; + ret = DefWindowProcW(hwnd, message, wp, lp); + defwndproc_counter--; + return ret; +} + +static void test_WM_PAINT(BOOL v6) +{ + WNDCLASSW wc = {0}; + HWND parent, hwnd; + + wc.hInstance = GetModuleHandleW(NULL); + wc.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_IBEAM); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszClassName = L"ToolbarWmPaintParentClass"; + wc.lpfnWndProc = wm_paint_parent_wnd_proc; + RegisterClassW(&wc); + + parent = CreateWindowW(wc.lpszClassName, L"Parent", WS_POPUP | WS_VISIBLE, 100, 100, 100, 100, + NULL, NULL, GetModuleHandleW(NULL), 0); + ok(parent != NULL, "CreateWindowW failed.\n"); + + /* Check WM_PAINT without TBSTYLE_TRANSPARENT */ + hwnd = CreateWindowW(TOOLBARCLASSNAMEW, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, parent, + NULL, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "CreateWindowW failed.\n"); + flush_events(); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + InvalidateRect(hwnd, NULL, FALSE); + flush_events(); + ok_sequence(sequences, PARENT_SEQ_INDEX, wm_paint_parent_seq, "WM_PAINT without TBSTYLE_TRANSPARENT", FALSE); + + DestroyWindow(hwnd); + + /* Check WM_PAINT with TBSTYLE_TRANSPARENT */ + hwnd = CreateWindowW(TOOLBARCLASSNAMEW, NULL, WS_CHILD | WS_VISIBLE | TBSTYLE_TRANSPARENT, 0, 0, + 100, 100, parent, NULL, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "CreateWindowW failed.\n"); + flush_events(); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + InvalidateRect(hwnd, NULL, FALSE); + flush_events(); + if (v6) + ok_sequence(sequences, PARENT_SEQ_INDEX, wm_paint_transparent_parent_v6_seq, + "WM_PAINT with TBSTYLE_TRANSPARENT v6", TRUE); + else + ok_sequence(sequences, PARENT_SEQ_INDEX, wm_paint_transparent_parent_v5_seq, + "WM_PAINT with TBSTYLE_TRANSPARENT v5", FALSE); + DestroyWindow(hwnd); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + DestroyWindow(parent); + UnregisterClassW(wc.lpszClassName, 0); +} + START_TEST(toolbar) { ULONG_PTR ctx_cookie; @@ -3069,6 +3157,7 @@ START_TEST(toolbar) test_WM_NOTIFY(); test_unicode_format(); test_WM_ERASEBKGND(FALSE); + test_WM_PAINT(FALSE);
if (!load_v6_module(&ctx_cookie, &ctx)) return; @@ -3078,6 +3167,7 @@ START_TEST(toolbar) test_BTNS_SEP(); test_unicode_format(); test_WM_ERASEBKGND(TRUE); + test_WM_PAINT(TRUE);
PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) {
From: Zhiyi Zhang zzhang@codeweavers.com
Comctl32 v6 erases the background when TBSTYLE_TRANSPARENT is present when handling WM_PAINT, not when handling WM_ERASEBKGND. WxWidgets relies on this behavior to draw the toolbar background. Please see https://github.com/wxWidgets/wxWidgets/blob/v2.9.4/src/msw/toolbar.cpp#L1805.
Fix tlReader 10.1.0.2004 toolbar broken rendering after 5e70fef5. After the commit, the comctl32 v6 version is properly reported and wxWidgets decides to use a comctl32 v6 specific code path.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58800 --- dlls/comctl32/tests/toolbar.c | 3 +-- dlls/comctl32/toolbar.c | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c index b3e8efd1759..eed70df2a64 100644 --- a/dlls/comctl32/tests/toolbar.c +++ b/dlls/comctl32/tests/toolbar.c @@ -3021,7 +3021,6 @@ static void test_WM_ERASEBKGND(BOOL v6) ok(lr == 1, "Got unexpected %Id.\n", lr); color = GetPixel(hdc, 10, 10); if (v6) - todo_wine ok(color == RGB(255, 0, 0), "Got unexpected color %#lx.\n", color); else ok(color == GetSysColor(COLOR_WINDOW), "Got unexpected color %#lx.\n", color); @@ -3092,7 +3091,7 @@ static void test_WM_PAINT(BOOL v6) flush_events(); if (v6) ok_sequence(sequences, PARENT_SEQ_INDEX, wm_paint_transparent_parent_v6_seq, - "WM_PAINT with TBSTYLE_TRANSPARENT v6", TRUE); + "WM_PAINT with TBSTYLE_TRANSPARENT v6", FALSE); else ok_sequence(sequences, PARENT_SEQ_INDEX, wm_paint_transparent_parent_v5_seq, "WM_PAINT with TBSTYLE_TRANSPARENT v5", FALSE); diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c index 64d09cb0b62..df4a6e73415 100644 --- a/dlls/comctl32/toolbar.c +++ b/dlls/comctl32/toolbar.c @@ -233,6 +233,7 @@ typedef enum #define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id) #define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id)
+static LRESULT TOOLBAR_DoEraseBackground(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam); static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb); static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, const CUSTOMBUTTON *btnInfo); static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id); @@ -1188,6 +1189,13 @@ TOOLBAR_Refresh (TOOLBAR_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps) if (!infoPtr->bDoRedraw) return;
+ /* Comctl32 v6 erases the background when TBSTYLE_TRANSPARENT is present when handling WM_PAINT, + * not when handling WM_ERASEBKGND */ +#if __WINE_COMCTL32_VERSION == 6 + if (infoPtr->dwStyle & TBSTYLE_TRANSPARENT) + TOOLBAR_DoEraseBackground(infoPtr, (WPARAM)hdc, 0); +#endif + /* if imagelist belongs to the app, it can be changed by the app after setting it */ if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt) @@ -5393,7 +5401,7 @@ TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr)
static LRESULT -TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +TOOLBAR_DoEraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) { NMTBCUSTOMDRAW tbcd; INT ret = FALSE; @@ -5463,6 +5471,18 @@ TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) return ret; }
+static LRESULT +TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + /* In comctl32 v6, erasing the background when TBSTYLE_TRANSPARENT is present is done in the + * WM_PAINT handler, not WM_ERASEBKGND */ +#if __WINE_COMCTL32_VERSION == 6 + if (infoPtr->dwStyle & TBSTYLE_TRANSPARENT) + return TRUE; +#endif + + return TOOLBAR_DoEraseBackground(infoPtr, wParam, lParam); +}
static inline LRESULT TOOLBAR_GetFont (const TOOLBAR_INFO *infoPtr)