[COMCTL32] tab: Use DrawThemeText when drawing text with themes. CORE-13855
[reactos.git] / dll / win32 / comctl32 / tab.c
index fe82d59..c5e3a86 100644 (file)
  *
  */
 
-#include <stdarg.h>
-#include <string.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "commctrl.h"
 #include "comctl32.h"
-#include "uxtheme.h"
-#include "tmschema.h"
-#include "wine/debug.h"
-#include <math.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(tab);
 
@@ -110,7 +97,6 @@ typedef struct
   INT        iSelected;       /* the currently selected item */
   INT        iHotTracked;     /* the highlighted item under the mouse */
   INT        uFocus;          /* item which has the focus */
-  TAB_ITEM*  items;           /* pointer to an array of TAB_ITEM's */
   BOOL       DoRedraw;        /* flag for redrawing when tab contents is changed*/
   BOOL       needsScrolling;  /* TRUE if the size of the tabs is greater than
                                * the size of the control */
@@ -122,6 +108,8 @@ typedef struct
   DWORD      exStyle;         /* Extended style used, currently:
                                  TCS_EX_FLATSEPARATORS, TCS_EX_REGISTERDROP */
   DWORD      dwStyle;         /* the cached window GWL_STYLE */
+
+  HDPA       items;           /* dynamic array of TAB_ITEM* pointers */
 } TAB_INFO;
 
 /******************************************************************************
@@ -141,9 +129,6 @@ typedef struct
 #define EXTRA_ICON_PADDING      3
 
 #define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0))
-/* Since items are variable sized, cannot directly access them */
-#define TAB_GetItem(info,i) \
-  ((TAB_ITEM*)((LPBYTE)info->items + (i) * TAB_ITEM_SIZE(info)))
 
 #define GET_DEFAULT_MIN_TAB_WIDTH(infoPtr) (DEFAULT_MIN_TAB_WIDTH - (DEFAULT_PADDING_X - (infoPtr)->uHItemPadding) * 2)
 
@@ -155,6 +140,12 @@ typedef struct
 
 static const WCHAR themeClass[] = { 'T','a','b',0 };
 
+static inline TAB_ITEM* TAB_GetItem(const TAB_INFO *infoPtr, INT i)
+{
+    assert(i >= 0 && i < infoPtr->uNumItem);
+    return DPA_GetPtr(infoPtr->items, i);
+}
+
 /******************************************************************************
  * Prototypes
  */
@@ -209,9 +200,8 @@ static void
 TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
 {
     if (TRACE_ON(tab)) {
-       TAB_ITEM *ti;
+       TAB_ITEM *ti = TAB_GetItem(infoPtr, iItem);
 
-       ti = TAB_GetItem(infoPtr, iItem);
        TRACE("tab %d, dwState=0x%08x, pszText=%s, iImage=%d\n",
              iItem, ti->dwState, debugstr_w(ti->pszText), ti->iImage);
        TRACE("tab %d, rect.left=%d, rect.top(row)=%d\n",
@@ -248,22 +238,29 @@ static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem)
 
   TRACE("(%p %d)\n", infoPtr, iItem);
 
-  if (iItem < 0)
-      infoPtr->iSelected = -1;
-  else if (iItem >= infoPtr->uNumItem)
+  if (iItem >= (INT)infoPtr->uNumItem)
       return -1;
-  else {
-      if (prevItem != iItem) {
-          if (prevItem != -1)
-              TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
-          TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
 
+  if (prevItem != iItem) {
+      if (prevItem != -1)
+          TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
+
+      if (iItem >= 0)
+      {
+          TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
           infoPtr->iSelected = iItem;
           infoPtr->uFocus = iItem;
-          TAB_EnsureSelectionVisible(infoPtr);
-          TAB_InvalidateTabArea(infoPtr);
       }
+      else
+      {
+          infoPtr->iSelected = -1;
+          infoPtr->uFocus = -1;
+      }
+
+      TAB_EnsureSelectionVisible(infoPtr);
+      TAB_InvalidateTabArea(infoPtr);
   }
+
   return prevItem;
 }
 
@@ -360,14 +357,8 @@ static BOOL TAB_InternalGetItemRect(
          (itemIndex < infoPtr->leftmostVisible)))
     {
         TRACE("Not Visible\n");
-        /* need to initialize these to empty rects */
-        if (itemRect)
-        {
-            memset(itemRect,0,sizeof(RECT));
-            itemRect->bottom = infoPtr->tabHeight;
-        }
-        if (selectedRect)
-            memset(selectedRect,0,sizeof(RECT));
+        SetRect(itemRect, 0, 0, 0, infoPtr->tabHeight);
+        SetRectEmpty(selectedRect);
         return FALSE;
     }
 
@@ -447,7 +438,7 @@ static BOOL TAB_InternalGetItemRect(
   /* Now, calculate the position of the item as if it were selected. */
   if (selectedRect!=NULL)
   {
-    CopyRect(selectedRect, itemRect);
+    *selectedRect = *itemRect;
 
     /* The rectangle of a selected item is a bit wider. */
     if(infoPtr->dwStyle & TCS_VERTICAL)
@@ -680,7 +671,8 @@ TAB_LButtonDown (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
           break;
         }
 
-      TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING);
+      if (TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
+        return 0;
 
       if (pressed)
         TAB_DeselectAll (infoPtr, FALSE);
@@ -702,11 +694,10 @@ TAB_LButtonUp (const TAB_INFO *infoPtr)
   return 0;
 }
 
-static inline LRESULT
-TAB_RButtonDown (const TAB_INFO *infoPtr)
+static inline void
+TAB_RButtonUp (const TAB_INFO *infoPtr)
 {
   TAB_SendSimpleNotify(infoPtr, NM_RCLICK);
-  return 0;
 }
 
 /******************************************************************************
@@ -1019,37 +1010,18 @@ static void TAB_SetupScrolling(
     /*
      * Calculate the position of the scroll control.
      */
-    if(infoPtr->dwStyle & TCS_VERTICAL)
-    {
-      controlPos.right = clientRect->right;
-      controlPos.left  = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
+    controlPos.right = clientRect->right;
+    controlPos.left  = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
 
-      if (infoPtr->dwStyle & TCS_BOTTOM)
-      {
-        controlPos.top    = clientRect->bottom - infoPtr->tabHeight;
-        controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
-      }
-      else
-      {
-        controlPos.bottom = clientRect->top + infoPtr->tabHeight;
-        controlPos.top    = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
-      }
+    if (infoPtr->dwStyle & TCS_BOTTOM)
+    {
+      controlPos.top    = clientRect->bottom - infoPtr->tabHeight;
+      controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
     }
     else
     {
-      controlPos.right = clientRect->right;
-      controlPos.left  = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
-
-      if (infoPtr->dwStyle & TCS_BOTTOM)
-      {
-        controlPos.top    = clientRect->bottom - infoPtr->tabHeight;
-        controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
-      }
-      else
-      {
-        controlPos.bottom = clientRect->top + infoPtr->tabHeight;
-        controlPos.top    = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
-      }
+      controlPos.bottom = clientRect->top + infoPtr->tabHeight;
+      controlPos.top    = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
     }
 
     /*
@@ -1251,8 +1223,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
         tabwidth = max(tabwidth, infoPtr->tabMinWidth);
 
       curr->rect.right = curr->rect.left + tabwidth;
-      TRACE("for <%s>, l,r=%d,%d\n",
-         debugstr_w(curr->pszText), curr->rect.left, curr->rect.right);
+      TRACE("for <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
     }
 
     /*
@@ -1271,8 +1242,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
 
        curr->rect.left = 0;
         curItemRowCount++;
-       TRACE("wrapping <%s>, l,r=%d,%d\n", debugstr_w(curr->pszText),
-           curr->rect.left, curr->rect.right);
+       TRACE("wrapping <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
     }
 
     curr->rect.bottom = 0;
@@ -1385,9 +1355,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
           else
             curItemLeftPos = curr->rect.right;
 
-          TRACE("arranging <%s>, l,r=%d,%d, row=%d\n",
-             debugstr_w(curr->pszText), curr->rect.left,
-             curr->rect.right, curr->rect.top);
+          TRACE("arranging <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
       }
 
       /*
@@ -1437,9 +1405,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
              item->rect.left += iCount * widthDiff;
              item->rect.right += (iCount + 1) * widthDiff;
 
-              TRACE("adjusting 1 <%s>, l,r=%d,%d\n",
-                 debugstr_w(item->pszText),
-                 item->rect.left, item->rect.right);
+              TRACE("adjusting 1 <%s>, rect %s\n", debugstr_w(item->pszText), wine_dbgstr_rect(&item->rect));
 
            }
            TAB_GetItem(infoPtr, iIndex - 1)->rect.right += remainder;
@@ -1449,13 +1415,9 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
            start->rect.left = clientRect.left;
            start->rect.right = clientRect.right - 4;
 
-            TRACE("adjusting 2 <%s>, l,r=%d,%d\n",
-               debugstr_w(start->pszText),
-               start->rect.left, start->rect.right);
-
+            TRACE("adjusting 2 <%s>, rect %s\n", debugstr_w(start->pszText), wine_dbgstr_rect(&start->rect));
          }
 
-
          iIndexStart = iIndexEnd;
        }
       }
@@ -1572,6 +1534,9 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
   HPEN   holdPen;
   INT    oldBkMode;
   HFONT  hOldFont;
+#ifdef __REACTOS__
+HTHEME    theme = GetWindowTheme (infoPtr->hwnd);
+#endif
   
 /*  if (drawRect == NULL) */
   {
@@ -1627,12 +1592,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
        }
       }
       else
-      {
-       drawRect->left   += 2;
-       drawRect->top    += 2;
-       drawRect->right  -= 2;
-       drawRect->bottom -= 2;
-      }
+        InflateRect(drawRect, -2, -2);
     }
     else
     {
@@ -1641,8 +1601,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
         if (iItem != infoPtr->iSelected)
        {
          drawRect->left   += 2;
-         drawRect->top    += 2;
-         drawRect->bottom -= 2;
+          InflateRect(drawRect, 0, -2);
        }
       }
       else if (infoPtr->dwStyle & TCS_VERTICAL)
@@ -1653,9 +1612,8 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
        }
        else
        {
-         drawRect->top    += 2;
          drawRect->right  -= 2;
-         drawRect->bottom -= 2;
+          InflateRect(drawRect, 0, -2);
        }
       }
       else if (infoPtr->dwStyle & TCS_BOTTOM)
@@ -1738,10 +1696,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
     drawRect->top += 2;
     drawRect->right -= 1;
     if ( iItem == infoPtr->iSelected )
-    {
-        drawRect->right -= 1;
-        drawRect->left += 1;
-    }
+        InflateRect(drawRect, -1, 0);
 
     id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
 
@@ -1757,7 +1712,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
       dis.itemState |= ODS_FOCUS;
     dis.hwndItem = infoPtr->hwnd;
     dis.hDC      = hdc;
-    CopyRect(&dis.rcItem,drawRect);
+    dis.rcItem = *drawRect;
 
     /* when extra data fits ULONG_PTR, store it directly */
     if (infoPtr->cbInfo > sizeof(LPARAM))
@@ -1766,6 +1721,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
     {
         /* this could be considered broken on 64 bit, but that's how it works -
            only first 4 bytes are copied */
+        dis.itemData = 0;
         memcpy(&dis.itemData, (ULONG_PTR*)TAB_GetItem(infoPtr, iItem)->extra, 4);
     }
 
@@ -1786,8 +1742,7 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
     rcImage = *drawRect;
 
     rcTemp = *drawRect;
-
-    rcText.left = rcText.top = rcText.right = rcText.bottom = 0;
+    SetRectEmpty(&rcText);
 
     /* get the rectangle that the text fits in */
     if (item->pszText)
@@ -1912,9 +1867,8 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
     /* Draw the text */
     if(infoPtr->dwStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */
     {
-      static const WCHAR ArialW[] = { 'A','r','i','a','l',0 };
       LOGFONTW logfont;
-      HFONT hFont = 0;
+      HFONT hFont;
       INT nEscapement = 900;
       INT nOrientation = 900;
 
@@ -1925,21 +1879,9 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
       }
 
       /* to get a font with the escapement and orientation we are looking for, we need to */
-      /* call CreateFontIndirectA, which requires us to set the values of the logfont we pass in */
-      if (!GetObjectW((infoPtr->hFont) ?
-                infoPtr->hFont : GetStockObject(SYSTEM_FONT),
-                sizeof(LOGFONTW),&logfont))
-      {
-        INT iPointSize = 9;
-
-        lstrcpyW(logfont.lfFaceName, ArialW);
-        logfont.lfHeight = -MulDiv(iPointSize, GetDeviceCaps(hdc, LOGPIXELSY),
-                                    72);
-        logfont.lfWeight = FW_NORMAL;
-        logfont.lfItalic = 0;
-        logfont.lfUnderline = 0;
-        logfont.lfStrikeOut = 0;
-      }
+      /* call CreateFontIndirect, which requires us to set the values of the logfont we pass in */
+      if (!GetObjectW(infoPtr->hFont, sizeof(logfont), &logfont))
+        GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(logfont), &logfont);
 
       logfont.lfEscapement = nEscapement;
       logfont.lfOrientation = nOrientation;
@@ -1965,6 +1907,29 @@ TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect
       TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%s), textlen=%d\n",
          debugstr_w(item->pszText), center_offset_h, center_offset_v,
           wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
+#ifdef __REACTOS__
+      if (theme && item->pszText)
+      {
+          int partIndex = iItem == infoPtr->iSelected ? TABP_TABITEM : TABP_TOPTABITEM;
+          int stateId = TIS_NORMAL;
+
+          if (iItem == infoPtr->iSelected)
+              stateId = TIS_SELECTED;
+          else if (iItem == infoPtr->iHotTracked)
+              stateId = TIS_HOT;
+          else if (iItem == infoPtr->uFocus)
+              stateId = TIS_FOCUSED;
+
+          DrawThemeText(theme, 
+                        hdc, 
+                        partIndex, 
+                        stateId,
+                        item->pszText, 
+                        lstrlenW(item->pszText), 
+                        DT_LEFT | DT_SINGLELINE, 0, drawRect);
+      }
+      else
+#endif
       if (item->pszText)
       {
         DrawTextW
@@ -2113,9 +2078,10 @@ static void TAB_DrawItem(const TAB_INFO *infoPtr, HDC  hdc, INT  iItem)
               partIndex += 4;
           /* The part also differs on the position of a tab on a line.
            * "Visually" determining the position works well enough. */
+          GetClientRect(infoPtr->hwnd, &r1);
           if(selectedRect.left == 0)
               partIndex += 1;
-          if(selectedRect.right == clRight)
+          if(selectedRect.right == r1.right)
               partIndex += 2;
 
           if (iItem == infoPtr->iSelected)
@@ -2436,6 +2402,9 @@ static void TAB_EnsureSelectionVisible(
   INT iSelected = infoPtr->iSelected;
   INT iOrigLeftmostVisible = infoPtr->leftmostVisible;
 
+  if (iSelected < 0)
+    return;
+
   /* set the items row to the bottommost row or topmost row depending on
    * style */
   if ((infoPtr->uNumRows > 1) && !(infoPtr->dwStyle & TCS_BUTTONS))
@@ -2640,42 +2609,21 @@ TAB_InsertItemT (TAB_INFO *infoPtr, INT iItem, const TCITEMW *pti, BOOL bUnicode
 
   TAB_DumpItemExternalT(pti, iItem, bUnicode);
 
-
-  if (infoPtr->uNumItem == 0) {
-    infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr));
-    infoPtr->uNumItem++;
-    infoPtr->iSelected = 0;
+  if (!(item = Alloc(TAB_ITEM_SIZE(infoPtr)))) return FALSE;
+  if (DPA_InsertPtr(infoPtr->items, iItem, item) == -1)
+  {
+      Free(item);
+      return FALSE;
   }
-  else {
-    LPBYTE oldItems = (LPBYTE)infoPtr->items;
-
-    infoPtr->uNumItem++;
-    infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem);
-
-    /* pre insert copy */
-    if (iItem > 0) {
-      memcpy (infoPtr->items, oldItems,
-              iItem * TAB_ITEM_SIZE(infoPtr));
-    }
-
-    /* post insert copy */
-    if (iItem < infoPtr->uNumItem - 1) {
-      memcpy (TAB_GetItem(infoPtr, iItem + 1),
-              oldItems + iItem * TAB_ITEM_SIZE(infoPtr),
-              (infoPtr->uNumItem - iItem - 1) * TAB_ITEM_SIZE(infoPtr));
-
-    }
 
-    if (iItem <= infoPtr->iSelected)
+  if (infoPtr->uNumItem == 0)
+      infoPtr->iSelected = 0;
+  else if (iItem <= infoPtr->iSelected)
       infoPtr->iSelected++;
 
-    Free (oldItems);
-  }
-
-  item = TAB_GetItem(infoPtr, iItem);
+  infoPtr->uNumItem++;
 
   item->pszText = NULL;
-
   if (pti->mask & TCIF_TEXT)
   {
     if (bUnicode)
@@ -2885,64 +2833,48 @@ TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
 
 static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
 {
-    BOOL bResult = FALSE;
+    TAB_ITEM *item;
 
     TRACE("(%p, %d)\n", infoPtr, iItem);
 
-    if ((iItem >= 0) && (iItem < infoPtr->uNumItem))
-    {
-        TAB_ITEM *item = TAB_GetItem(infoPtr, iItem);
-        LPBYTE oldItems = (LPBYTE)infoPtr->items;
+    if (iItem < 0 || iItem >= infoPtr->uNumItem) return FALSE;
 
-       TAB_InvalidateTabArea(infoPtr);
-        Free(item->pszText);
-       infoPtr->uNumItem--;
+    TAB_InvalidateTabArea(infoPtr);
+    item = TAB_GetItem(infoPtr, iItem);
+    Free(item->pszText);
+    Free(item);
+    infoPtr->uNumItem--;
+    DPA_DeletePtr(infoPtr->items, iItem);
 
-       if (!infoPtr->uNumItem)
+    if (infoPtr->uNumItem == 0)
+    {
+        if (infoPtr->iHotTracked >= 0)
         {
-            infoPtr->items = NULL;
-            if (infoPtr->iHotTracked >= 0)
-            {
-                KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER);
-                infoPtr->iHotTracked = -1;
-            }
+            KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER);
+            infoPtr->iHotTracked = -1;
         }
-        else
-       {
-           infoPtr->items = Alloc(TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem);
-
-           if (iItem > 0)
-               memcpy(infoPtr->items, oldItems, iItem * TAB_ITEM_SIZE(infoPtr));
-
-           if (iItem < infoPtr->uNumItem)
-               memcpy(TAB_GetItem(infoPtr, iItem),
-                       oldItems + (iItem + 1) * TAB_ITEM_SIZE(infoPtr),
-                      (infoPtr->uNumItem - iItem) * TAB_ITEM_SIZE(infoPtr));
-
-            if (iItem <= infoPtr->iHotTracked)
-            {
-                /* When tabs move left/up, the hot track item may change */
-                FIXME("Recalc hot track\n");
-            }
-       }
-       Free(oldItems);
-
-       /* Readjust the selected index */
-       if (iItem == infoPtr->iSelected)
-           infoPtr->iSelected = -1;
-       else if (iItem < infoPtr->iSelected)
-           infoPtr->iSelected--;
 
-       if (infoPtr->uNumItem == 0)
-           infoPtr->iSelected = -1;
+        infoPtr->iSelected = -1;
+    }
+    else
+    {
+        if (iItem <= infoPtr->iHotTracked)
+        {
+            /* When tabs move left/up, the hot track item may change */
+            FIXME("Recalc hot track\n");
+        }
+    }
 
-       /* Reposition and repaint tabs */
-       TAB_SetItemBounds(infoPtr);
+    /* adjust the selected index */
+    if (iItem == infoPtr->iSelected)
+        infoPtr->iSelected = -1;
+    else if (iItem < infoPtr->iSelected)
+        infoPtr->iSelected--;
 
-       bResult = TRUE;
-    }
+    /* reposition and repaint tabs */
+    TAB_SetItemBounds(infoPtr);
 
-    return bResult;
+    return TRUE;
 }
 
 static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr)
@@ -3048,7 +2980,7 @@ static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
   TEXTMETRICW fontMetrics;
   HDC hdc;
   HFONT hOldFont;
-  DWORD dwStyle;
+  DWORD style;
 
   infoPtr = Alloc (sizeof(TAB_INFO));
 
@@ -3063,7 +2995,7 @@ static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
   infoPtr->uHItemPadding_s = 6;
   infoPtr->uVItemPadding_s = 3;
   infoPtr->hFont           = 0;
-  infoPtr->items           = 0;
+  infoPtr->items           = DPA_Create(8);
   infoPtr->hcurArrow       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
   infoPtr->iSelected       = -1;
   infoPtr->iHotTracked     = -1;
@@ -3082,11 +3014,13 @@ static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
   /* The tab control always has the WS_CLIPSIBLINGS style. Even
      if you don't specify it in CreateWindow. This is necessary in
      order for paint to work correctly. This follows windows behaviour. */
-  dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
-  SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS);
+  style = GetWindowLongW(hwnd, GWL_STYLE);
+  if (style & TCS_VERTICAL) style |= TCS_MULTILINE;
+  style |= WS_CLIPSIBLINGS;
+  SetWindowLongW(hwnd, GWL_STYLE, style);
 
-  infoPtr->dwStyle = dwStyle | WS_CLIPSIBLINGS;
-  infoPtr->exStyle = (dwStyle & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
+  infoPtr->dwStyle = style;
+  infoPtr->exStyle = (style & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
 
   if (infoPtr->dwStyle & TCS_TOOLTIPS) {
     /* Create tooltip control */
@@ -3147,16 +3081,22 @@ static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
 static LRESULT
 TAB_Destroy (TAB_INFO *infoPtr)
 {
-  UINT iItem;
+  INT iItem;
 
   SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
 
-  if (infoPtr->items) {
-    for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
-      Free (TAB_GetItem(infoPtr, iItem)->pszText);
-    }
-    Free (infoPtr->items);
+  for (iItem = infoPtr->uNumItem - 1; iItem >= 0; iItem--)
+  {
+      TAB_ITEM *tab = TAB_GetItem(infoPtr, iItem);
+
+      DPA_DeletePtr(infoPtr->items, iItem);
+      infoPtr->uNumItem--;
+
+      Free(tab->pszText);
+      Free(tab);
   }
+  DPA_Destroy(infoPtr->items);
+  infoPtr->items = NULL;
 
   if (infoPtr->hwndToolTip)
     DestroyWindow (infoPtr->hwndToolTip);
@@ -3450,8 +3390,9 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     case WM_NOTIFY:
       return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
 
-    case WM_RBUTTONDOWN:
-      return TAB_RButtonDown (infoPtr);
+    case WM_RBUTTONUP:
+      TAB_RButtonUp (infoPtr);
+      return DefWindowProcW (hwnd, uMsg, wParam, lParam);
 
     case WM_MOUSEMOVE:
       return TAB_MouseMove (infoPtr, wParam, lParam);