comctl32: correct handling of toolbar separators' size

Igor Tarasov tarasov.igor at gmail.com
Tue Mar 17 18:37:22 CDT 2009


Currently, wine uses iBitmap property for determining toolbar
separators width all the time, stating it's an undocumented feature.
This is not correct.

According to MSDN, iBitmap is used only on inserting separator (since
there is no cx field in TBBUTTON structure).
http://msdn.microsoft.com/en-us/library/bb760476(VS.85).aspx

In other cases, cx property that can be updated via get/set buttoninfo
is used, as tests show. Also, tests show that this property differs
from zero only if application specifically sets. Setting it to 0 makes
separator display in default width. All this is implemented in this
patch. More tests results in bugtracker (link below).

As of setting iBitmap for separators: native comctl32 starts behaving
very buggy, misplacing button bitmaps, even outside of the buttons,
thus producing visual glitches. While autosizing toolbar puts bitmaps
at their places, but, IMHO, it's rather bug than feature.

This patch fixes bug 17654
http://bugs.winehq.org/show_bug.cgi?id=17654

P.S: Best used with my previous patch ;)
http://www.winehq.org/pipermail/wine-patches/2009-March/070808.html

--
Igor
-------------- next part --------------
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index 8635ff5..820c345 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -1326,17 +1326,15 @@ TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
        if (btnPtr[i].fsState & TBSTATE_HIDDEN)
            continue;

-       /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
-       /* it is the actual width of the separator. This is used for */
-       /* custom controls in toolbars.                              */
-       /*                                                           */
-       /* horizontal separators are treated as buttons for width    */
-       if ((btnPtr[i].fsStyle & BTNS_SEP) &&
+        if (btnPtr[i].cx > 0)
+            cx = btnPtr[i].cx;
+        /* BTNS_DROPDOWN separators are treated as buttons for    */
+        /* width.  - GA 8/01                                      */
+        else if ((btnPtr[i].fsStyle & BTNS_SEP) &&
            !(infoPtr->dwStyle & CCS_VERT))
-           cx = (btnPtr[i].iBitmap > 0) ?
-                       btnPtr[i].iBitmap : SEPARATOR_WIDTH;
+            cx = SEPARATOR_WIDTH;
        else
-           cx = (btnPtr[i].cx) ? btnPtr[i].cx : infoPtr->nButtonWidth;
+            cx = infoPtr->nButtonWidth;

        /* Two or more adjacent separators form a separator group.   */
        /* The first separator in a group should be wrapped to the   */
@@ -1684,18 +1682,13 @@ TOOLBAR_LayoutToolbar(HWND hwnd)

        cy = infoPtr->nButtonHeight;

-       /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
-       /* it is the actual width of the separator. This is used for */
-       /* custom controls in toolbars.                              */
        if (btnPtr->fsStyle & BTNS_SEP) {
            if (infoPtr->dwStyle & CCS_VERT) {
-               cy = (btnPtr->iBitmap > 0) ?
-                    btnPtr->iBitmap : SEPARATOR_WIDTH;
+                cy = (btnPtr->cx > 0) ? btnPtr->cx : SEPARATOR_WIDTH;
                cx = infoPtr->nButtonWidth;
            }
            else
-               cx = (btnPtr->iBitmap > 0) ?
-                    btnPtr->iBitmap : SEPARATOR_WIDTH;
+                cx = (btnPtr->cx > 0) ? btnPtr->cx : SEPARATOR_WIDTH;
        }
        else
        {
@@ -1758,12 +1751,9 @@ TOOLBAR_LayoutToolbar(HWND hwnd)
                y += cy;
            else
            {
-               /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
-               /* it is the actual width of the separator. This is used for */
-               /* custom controls in toolbars.                              */
                if ( !(btnPtr->fsStyle & BTNS_DROPDOWN))
-                   y += cy + ( (btnPtr->iBitmap > 0 ) ?
-                               btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
+                    y += cy + ( (btnPtr->cx > 0 ) ?
+                                btnPtr->cx : SEPARATOR_WIDTH) * 2 /3;
                else
                    y += cy;

@@ -1845,7 +1835,14 @@ TOOLBAR_InternalInsertButtonsT(TOOLBAR_INFO *infoPtr, INT iIndex, UINT nAd
         TOOLBAR_DumpTBButton(lpTbb, fUnicode);

         ZeroMemory(btnPtr, sizeof(*btnPtr));
-        btnPtr->iBitmap   = lpTbb[iButton].iBitmap;
+
+        /* When inserting separator, iBitmap controls it's size */
+        if (lpTbb[iButton].fsStyle & BTNS_SEP) {
+            btnPtr->iBitmap   = 0;
+            btnPtr->cx        = lpTbb[iButton].iBitmap;
+        } else
+            btnPtr->iBitmap   = lpTbb[iButton].iBitmap;
+
         btnPtr->idCommand = lpTbb[iButton].idCommand;
         btnPtr->fsState   = lpTbb[iButton].fsState;
         btnPtr->fsStyle   = lpTbb[iButton].fsStyle;
@@ -3400,7 +3397,11 @@ TOOLBAR_GetButtonInfoT(HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL bUnic
     if (lpTbInfo->dwMask & TBIF_LPARAM)
        lpTbInfo->lParam = btnPtr->dwData;
     if (lpTbInfo->dwMask & TBIF_SIZE)
-       lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
+        /* tests show that for separators TBIF_SIZE returns not calculated width,
+           but cx property, that differs from 0 only if application have
+           specifically set it */
+        lpTbInfo->cx = (btnPtr->fsStyle & BTNS_SEP)
+            ? btnPtr->cx : (WORD)(btnPtr->rect.right - btnPtr->rect.left);
     if (lpTbInfo->dwMask & TBIF_STATE)
        lpTbInfo->fsState = btnPtr->fsState;
     if (lpTbInfo->dwMask & TBIF_STYLE)
@@ -4240,7 +4241,9 @@ TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, const TBSAVEPARAMSW *lpSave)
                 {
                     /* separator */
                     nmtbr.tbButton.fsStyle = TBSTYLE_SEP;
-                    nmtbr.tbButton.iBitmap = SEPARATOR_WIDTH;
+                    /* when inserting separators, iBitmap controls it's size.
+                       0 sets default size (width) */
+                    nmtbr.tbButton.iBitmap = 0;
                 }
                 else if (*nmtbr.pCurrent == (DWORD)-2)
                     /* hidden button */
@@ -4428,7 +4431,7 @@ TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
     if (lptbbi->dwMask & TBIF_LPARAM)
        btnPtr->dwData = lptbbi->lParam;
     if (lptbbi->dwMask & TBIF_SIZE)
-       btnPtr->cx = lptbbi->cx;
+        btnPtr->cx = lptbbi->cx;
     if (lptbbi->dwMask & TBIF_STATE)
        btnPtr->fsState = lptbbi->fsState;
     if (lptbbi->dwMask & TBIF_STYLE)


More information about the wine-patches mailing list