[PATCH 5/6] comctl32/toolbar: Don't use outside theme handles.

Zhiyi Zhang zzhang at codeweavers.com
Tue Jun 22 03:21:15 CDT 2021


Fix Spy++ Toolbar buttons have artifacts. Spy++ first creates a Toolbar window, then calls
OpenThemeData(hwnd, "Rebar") with the Toolbar window. Then when the Toolbar control uses the theme
handle from GetWindowTheme(), it gets a Rebar theme the next time it draws, thus drawing wrong theme
parts.

According the tests, not all of the common controls have such behaviors. Some of them do have theme
handles opened by their window and then use that theme handle afterwards even it's changed from the
outside. However, for other controls, the behaviors are not very consistent across all Windows
versions. Also no applications depend on such behaviors for other controls yet. So, only modify the
Toolbar control for now.

Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/comctl32/tests/toolbar.c |  2 --
 dlls/comctl32/toolbar.c       | 36 ++++++++++++++++-------------------
 2 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/dlls/comctl32/tests/toolbar.c b/dlls/comctl32/tests/toolbar.c
index d6ee358b04a..87b4611d056 100644
--- a/dlls/comctl32/tests/toolbar.c
+++ b/dlls/comctl32/tests/toolbar.c
@@ -2641,7 +2641,6 @@ static void test_visual(void)
     ok(ret, "TB_ADDBUTTONSA failed.\n");
 
     theme = pGetWindowTheme(toolbar);
-    todo_wine
     ok(!theme, "Expected theme not opened by window.\n");
 
     toolbar_dc = GetDC(toolbar);
@@ -2672,7 +2671,6 @@ static void test_visual(void)
     BitBlt(mem_dc2, 0, 0, width, height, toolbar_dc, 0, 0, SRCCOPY);
 
     ret = equal_dc(mem_dc1, mem_dc2, width, height);
-    todo_wine
     ok(ret, "Expected same content.\n");
 
     pCloseThemeData(theme);
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index a8777ae5480..2585e11530e 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -142,6 +142,7 @@ typedef struct
     INT      iListGap;        /* default gap between text and image for toolbar with list style */
     HFONT    hDefaultFont;
     HFONT    hFont;           /* text font */
+    HTHEME   hTheme;          /* theme */
     HIMAGELIST himlInt;       /* image list created internally */
     PIMLENTRY *himlDef;       /* default image list array */
     INT       cimlDef;        /* default image list array count */
@@ -780,7 +781,7 @@ TOOLBAR_DrawImage(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, I
     }
     else if (tbcd->nmcd.uItemState & CDIS_CHECKED ||
       ((tbcd->nmcd.uItemState & CDIS_HOT) 
-      && ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))))
+      && ((infoPtr->dwStyle & TBSTYLE_FLAT) || infoPtr->hTheme)))
     {
         /* if hot, attempt to draw with hot image list, if fails, 
            use default image list */
@@ -900,7 +901,7 @@ TOOLBAR_DrawButton (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HDC hdc,
     INT oldBkMode;
     DWORD dwItemCustDraw;
     DWORD dwItemCDFlag;
-    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
+    HTHEME theme = infoPtr->hTheme;
 
     rc = btnPtr->rect;
     rcArrow = rc;
@@ -1053,8 +1054,7 @@ TOOLBAR_DrawButton (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HDC hdc,
         ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE)))
         TOOLBAR_DrawPattern (&rc, &tbcd);
 
-    if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 
-        && (tbcd.nmcd.uItemState & CDIS_HOT))
+    if (((infoPtr->dwStyle & TBSTYLE_FLAT) || theme) && (tbcd.nmcd.uItemState & CDIS_HOT))
     {
         if ( dwItemCDFlag & TBCDRF_HILITEHOTTRACK )
         {
@@ -3506,7 +3506,7 @@ TOOLBAR_GetHotImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam)
 static LRESULT
 TOOLBAR_GetHotItem (const TOOLBAR_INFO *infoPtr)
 {
-    if (!((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)))
+    if (!((infoPtr->dwStyle & TBSTYLE_FLAT) || infoPtr->hTheme))
 	return -1;
 
     if (infoPtr->nHotItem < 0)
@@ -5313,8 +5313,7 @@ TOOLBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
 
     SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
     infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont);
-    
-    OpenThemeData (hwnd, themeClass);
+    infoPtr->hTheme = OpenThemeData (NULL, themeClass);
 
     TOOLBAR_CheckStyle (infoPtr);
 
@@ -5358,8 +5357,8 @@ TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr)
 
     /* delete default font */
     DeleteObject (infoPtr->hDefaultFont);
-        
-    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
+
+    CloseThemeData (infoPtr->hTheme);
 
     /* free toolbar info data */
     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
@@ -5375,7 +5374,6 @@ TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     NMTBCUSTOMDRAW tbcd;
     INT ret = FALSE;
     DWORD ntfret;
-    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
     DWORD dwEraseCustDraw = 0;
 
     /* the app has told us not to redraw the toolbar */
@@ -5405,7 +5403,7 @@ TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up
      * to my parent for processing.
      */
-    if (theme || (infoPtr->dwStyle & TBSTYLE_TRANSPARENT)) {
+    if (infoPtr->hTheme || (infoPtr->dwStyle & TBSTYLE_TRANSPARENT)) {
 	POINT pt, ptorig;
 	HDC hdc = (HDC)wParam;
 	HWND parent;
@@ -5957,7 +5955,7 @@ TOOLBAR_MouseMove (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     if ((infoPtr->dwStyle & TBSTYLE_TOOLTIPS) && (infoPtr->hwndToolTip == NULL))
         TOOLBAR_TooltipCreateControl(infoPtr);
     
-    if ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) {
+    if ((infoPtr->dwStyle & TBSTYLE_FLAT) || infoPtr->hTheme) {
         /* fill in the TRACKMOUSEEVENT struct */
         trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
         trackinfo.dwFlags = TME_QUERY;
@@ -5985,8 +5983,7 @@ TOOLBAR_MouseMove (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 
     nHit = TOOLBAR_InternalHitTest (infoPtr, &pt, &button);
 
-    if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 
-        && (!infoPtr->bAnchor || button))
+    if (((infoPtr->dwStyle & TBSTYLE_FLAT) || infoPtr->hTheme) && (!infoPtr->bAnchor || button))
         TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE);
 
     if (infoPtr->nOldHit != nHit)
@@ -6550,12 +6547,11 @@ TOOLBAR_SysColorChange (void)
 
 
 /* update theme after a WM_THEMECHANGED message */
-static LRESULT theme_changed (HWND hwnd)
+static LRESULT theme_changed (TOOLBAR_INFO *infoPtr)
 {
-    HTHEME theme = GetWindowTheme (hwnd);
-    CloseThemeData (theme);
-    OpenThemeData (hwnd, themeClass);
-    InvalidateRect (hwnd, NULL, TRUE);
+    CloseThemeData (infoPtr->hTheme);
+    infoPtr->hTheme = OpenThemeData (NULL, themeClass);
+    InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
     return 0;
 }
 
@@ -6945,7 +6941,7 @@ ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 	    return TOOLBAR_SysColorChange ();
             
         case WM_THEMECHANGED:
-            return theme_changed (hwnd);
+            return theme_changed (infoPtr);
 
 /*	case WM_WININICHANGE: */
 
-- 
2.30.2




More information about the wine-devel mailing list