comctl32/listview: Fix hittest flag calculation for negative Y values on report mode.
[wine] / dlls / comctl32 / tab.c
index e36ddf6..4b439b2 100644 (file)
@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * NOTES
  *
@@ -32,7 +32,7 @@
  * TODO:
  *
  *  Styles:
- *   TCS_MULTISELECT
+ *   TCS_MULTISELECT - implement for VK_SPACE selection
  *   TCS_RIGHT
  *   TCS_RIGHTJUSTIFY
  *   TCS_SCROLLOPPOSITE
  *   TCIF_RTLREADING
  *
  *  Extended Styles:
- *   TCS_EX_FLATSEPARATORS
  *   TCS_EX_REGISTERDROP
  *
- *  States:
- *   TCIS_BUTTONPRESSED
- *
  *  Notifications:
  *   NM_RELEASEDCAPTURE
  *   TCN_FOCUSCHANGE
  *   TCN_GETOBJECT
  *   TCN_KEYDOWN
  *
- *  Messages:
- *   TCM_REMOVEIMAGE
- *   TCM_DESELECTALL
- *   TCM_GETEXTENDEDSTYLE
- *   TCM_SETEXTENDEDSTYLE
- *
  *  Macros:
  *   TabCtrl_AdjustRect
  *
@@ -82,7 +72,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(tab);
 
 typedef struct
 {
-  UINT   mask;
   DWORD  dwState;
   LPWSTR pszText;
   INT    iImage;
@@ -96,7 +85,7 @@ typedef struct
 } TAB_ITEM;
 
 /* The size of a tab item depends on how much extra data is requested */
-#define TAB_ITEM_SIZE(infoPtr) (sizeof(TAB_ITEM) - sizeof(BYTE) + infoPtr->cbInfo)
+#define TAB_ITEM_SIZE(infoPtr) (FIELD_OFFSET(TAB_ITEM, extra[(infoPtr)->cbInfo]))
 
 typedef struct
 {
@@ -128,6 +117,9 @@ typedef struct
   BOOL       bUnicode;        /* Unicode control? */
   HWND       hwndUpDown;      /* Updown control used for scrolling */
   INT        cbInfo;          /* Number of bytes of caller supplied info per tab */
+
+  DWORD      exStyle;         /* Extended style used, currently:
+                                 TCS_EX_FLATSEPARATORS, TCS_EX_REGISTERDROP */
 } TAB_INFO;
 
 /******************************************************************************
@@ -143,7 +135,6 @@ typedef struct
 #define BUTTON_SPACINGY         3
 #define FLAT_BTN_SPACINGX       8
 #define DEFAULT_MIN_TAB_WIDTH   54
-#define DEFAULT_TAB_WIDTH_FIXED 96
 #define DEFAULT_PADDING_X       6
 #define EXTRA_ICON_PADDING      3
 
@@ -165,9 +156,10 @@ static const WCHAR themeClass[] = { 'T','a','b',0 };
 /******************************************************************************
  * Prototypes
  */
-static void TAB_InvalidateTabArea(TAB_INFO *);
+static void TAB_InvalidateTabArea(const TAB_INFO *);
 static void TAB_EnsureSelectionVisible(TAB_INFO *);
-static void TAB_DrawItemInterior(TAB_INFO *, HDC, INT, RECT*);
+static void TAB_DrawItemInterior(const TAB_INFO *, HDC, INT, RECT*);
+static LRESULT TAB_DeselectAll(TAB_INFO *, BOOL);
 
 static BOOL
 TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code)
@@ -179,7 +171,7 @@ TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code)
     nmhdr.code = code;
 
     return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
-            (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr);
+            nmhdr.idFrom, (LPARAM) &nmhdr);
 }
 
 static void
@@ -193,17 +185,17 @@ TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
     msg.wParam = wParam;
     msg.lParam = lParam;
     msg.time = GetMessageTime ();
-    msg.pt.x = LOWORD(GetMessagePos ());
-    msg.pt.y = HIWORD(GetMessagePos ());
+    msg.pt.x = (short)LOWORD(GetMessagePos ());
+    msg.pt.y = (short)HIWORD(GetMessagePos ());
 
     SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
 }
 
 static void
-TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW)
+TAB_DumpItemExternalT(const TCITEMW *pti, UINT iItem, BOOL isW)
 {
     if (TRACE_ON(tab)) {
-       TRACE("external tab %d, mask=0x%08x, dwState=0x%08lx, dwStateMask=0x%08lx, cchTextMax=0x%08x\n",
+       TRACE("external tab %d, mask=0x%08x, dwState=0x%08x, dwStateMask=0x%08x, cchTextMax=0x%08x\n",
              iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax);
        TRACE("external tab %d,   iImage=%d, lParam=0x%08lx, pszTextW=%s\n",
              iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText));
@@ -211,16 +203,15 @@ TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW)
 }
 
 static void
-TAB_DumpItemInternal(TAB_INFO *infoPtr, UINT iItem)
+TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
 {
     if (TRACE_ON(tab)) {
        TAB_ITEM *ti;
 
        ti = TAB_GetItem(infoPtr, iItem);
-       TRACE("tab %d, mask=0x%08x, dwState=0x%08lx, pszText=%s, iImage=%d\n",
-             iItem, ti->mask, ti->dwState, debugstr_w(ti->pszText),
-             ti->iImage);
-       TRACE("tab %d, rect.left=%ld, rect.top(row)=%ld\n",
+       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",
              iItem, ti->rect.left, ti->rect.top);
     }
 }
@@ -233,19 +224,10 @@ static inline LRESULT TAB_GetCurSel (const TAB_INFO *infoPtr)
 }
 
 /* RETURNS
- *   the index of the tab item that has the focus
- * NOTE
- *   we have not to return negative value
- * TODO
- *   test for windows */
+ *   the index of the tab item that has the focus. */
 static inline LRESULT
 TAB_GetCurFocus (const TAB_INFO *infoPtr)
 {
-    if (infoPtr->uFocus<0)
-    {
-        FIXME("we have not to return negative value");
-        return 0;
-    }
     return infoPtr->uFocus;
 }
 
@@ -257,36 +239,47 @@ static inline LRESULT TAB_GetToolTips (const TAB_INFO *infoPtr)
 
 static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem)
 {
-  INT prevItem = -1;
+  INT prevItem = infoPtr->iSelected;
 
-  if (iItem >= 0 && iItem < infoPtr->uNumItem) {
-      prevItem=infoPtr->iSelected;
-      infoPtr->iSelected=iItem;
-      TAB_EnsureSelectionVisible(infoPtr);
-      TAB_InvalidateTabArea(infoPtr);
+  if (iItem < 0)
+      infoPtr->iSelected=-1;
+  else if (iItem >= infoPtr->uNumItem)
+      return -1;
+  else {
+      if (infoPtr->iSelected != iItem) {
+          TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
+          TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
+
+          infoPtr->iSelected=iItem;
+          infoPtr->uFocus=iItem;
+          TAB_EnsureSelectionVisible(infoPtr);
+          TAB_InvalidateTabArea(infoPtr);
+      }
   }
   return prevItem;
 }
 
 static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem)
 {
-  if (iItem < 0 || iItem >= infoPtr->uNumItem) return 0;
-
-  if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) {
-    FIXME("Should set input focus\n");
-  } else {
-    int oldFocus = infoPtr->uFocus;
-    if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
-      infoPtr->uFocus = iItem;
-      if (oldFocus != -1) {
-        if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))  {
-          infoPtr->iSelected = iItem;
-          TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+  if (iItem < 0)
+      infoPtr->uFocus = -1;
+  else if (iItem < infoPtr->uNumItem) {
+    if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) {
+      FIXME("Should set input focus\n");
+    } else {
+      int oldFocus = infoPtr->uFocus;
+      if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
+        infoPtr->uFocus = iItem;
+        if (oldFocus != -1) {
+          if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))  {
+            infoPtr->iSelected = iItem;
+            TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+          }
+          else
+            infoPtr->iSelected = iItem;
+          TAB_EnsureSelectionVisible(infoPtr);
+          TAB_InvalidateTabArea(infoPtr);
         }
-        else
-          infoPtr->iSelected = iItem;
-        TAB_EnsureSelectionVisible(infoPtr);
-        TAB_InvalidateTabArea(infoPtr);
       }
     }
   }
@@ -417,9 +410,8 @@ static BOOL TAB_InternalGetItemRect(
             SELECTED_TAB_OFFSET,
             0);
   }
-  TRACE("item %d tab h=%d, rect=(%ld,%ld)-(%ld,%ld)\n",
-       itemIndex, infoPtr->tabHeight,
-       itemRect->left, itemRect->top, itemRect->right, itemRect->bottom);
+  TRACE("item %d tab h=%d, rect=(%s)\n",
+        itemIndex, infoPtr->tabHeight, wine_dbgstr_rect(itemRect));
 
   /* Now, calculate the position of the item as if it were selected. */
   if (selectedRect!=NULL)
@@ -462,9 +454,9 @@ static BOOL TAB_InternalGetItemRect(
 }
 
 static inline BOOL
-TAB_GetItemRect(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TAB_GetItemRect(const TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
-  return TAB_InternalGetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam, (LPRECT)NULL);
+  return TAB_InternalGetItemRect(infoPtr, wParam, (LPRECT)lParam, NULL);
 }
 
 /******************************************************************************
@@ -495,12 +487,8 @@ static LRESULT TAB_KeyUp(TAB_INFO* infoPtr, WPARAM keyCode)
   {
     if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
     {
-      infoPtr->iSelected = newItem;
-      infoPtr->uFocus    = newItem;
+      TAB_SetCurSel(infoPtr, newItem);
       TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
-
-      TAB_EnsureSelectionVisible(infoPtr);
-      TAB_InvalidateTabArea(infoPtr);
     }
   }
 
@@ -532,18 +520,12 @@ static void TAB_FocusChanging(const TAB_INFO *infoPtr)
    */
   if (isVisible)
   {
-      TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n",
-           selectedRect.left,selectedRect.top,
-           selectedRect.right,selectedRect.bottom);
+    TRACE("invalidate (%s)\n", wine_dbgstr_rect(&selectedRect));
     InvalidateRect(infoPtr->hwnd, &selectedRect, TRUE);
   }
 }
 
-static INT TAB_InternalHitTest (
-  TAB_INFO* infoPtr,
-  POINT     pt,
-  UINT*     flags)
-
+static INT TAB_InternalHitTest (const TAB_INFO *infoPtr, POINT pt, UINT *flags)
 {
   RECT rect;
   INT iCount;
@@ -564,7 +546,7 @@ static INT TAB_InternalHitTest (
 }
 
 static inline LRESULT
-TAB_HitTest (TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
+TAB_HitTest (const TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
 {
   return TAB_InternalHitTest (infoPtr, lptest->pt, &lptest->flags);
 }
@@ -582,13 +564,13 @@ TAB_HitTest (TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
  * doesn't do it that way. Maybe depends on tab control styles ?
  */
 static inline LRESULT
-TAB_NCHitTest (TAB_INFO *infoPtr, LPARAM lParam)
+TAB_NCHitTest (const TAB_INFO *infoPtr, LPARAM lParam)
 {
   POINT pt;
   UINT dummyflag;
 
-  pt.x = LOWORD(lParam);
-  pt.y = HIWORD(lParam);
+  pt.x = (short)LOWORD(lParam);
+  pt.y = (short)HIWORD(lParam);
   ScreenToClient(infoPtr->hwnd, &pt);
 
   if (TAB_InternalHitTest(infoPtr, pt, &dummyflag) == -1)
@@ -603,6 +585,7 @@ TAB_LButtonDown (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
   POINT pt;
   INT newItem;
   UINT dummy;
+  LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
 
   if (infoPtr->hwndToolTip)
     TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
@@ -616,26 +599,50 @@ TAB_LButtonDown (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
                    WM_LBUTTONDOWN, wParam, lParam);
 
-  pt.x = (INT)LOWORD(lParam);
-  pt.y = (INT)HIWORD(lParam);
+  pt.x = (short)LOWORD(lParam);
+  pt.y = (short)HIWORD(lParam);
 
   newItem = TAB_InternalHitTest (infoPtr, pt, &dummy);
 
   TRACE("On Tab, item %d\n", newItem);
 
-  if (newItem != -1 && infoPtr->iSelected != newItem)
+  if ((newItem != -1) && (infoPtr->iSelected != newItem))
   {
-    if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
+    if ((lStyle & TCS_BUTTONS) && (lStyle & TCS_MULTISELECT) &&
+        (wParam & MK_CONTROL))
     {
-      infoPtr->iSelected = newItem;
-      infoPtr->uFocus    = newItem;
-      TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+      RECT r;
 
-      TAB_EnsureSelectionVisible(infoPtr);
+      /* toggle multiselection */
+      TAB_GetItem(infoPtr, newItem)->dwState ^= TCIS_BUTTONPRESSED;
+      if (TAB_InternalGetItemRect (infoPtr, newItem, &r, NULL))
+        InvalidateRect (infoPtr->hwnd, &r, TRUE);
+    }
+    else
+    {
+      INT i;
+      BOOL pressed = FALSE;
 
-      TAB_InvalidateTabArea(infoPtr);
+      /* any button pressed ? */
+      for (i = 0; i < infoPtr->uNumItem; i++)
+        if ((TAB_GetItem (infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
+            (infoPtr->iSelected != i))
+        {
+          pressed = TRUE;
+          break;
+        }
+
+      TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING);
+
+      if (pressed)
+        TAB_DeselectAll (infoPtr, FALSE);
+      else
+        TAB_SetCurSel(infoPtr, newItem);
+
+      TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
     }
   }
+
   return 0;
 }
 
@@ -663,7 +670,7 @@ TAB_RButtonDown (const TAB_INFO *infoPtr)
  * only calls TAB_DrawItemInterior for the single specified item.
  */
 static void
-TAB_DrawLoneItemInterior(TAB_INFO* infoPtr, int iItem)
+TAB_DrawLoneItemInterior(const TAB_INFO* infoPtr, int iItem)
 {
   HDC hdc = GetDC(infoPtr->hwnd);
   RECT r, rC;
@@ -681,7 +688,7 @@ TAB_DrawLoneItemInterior(TAB_INFO* infoPtr, int iItem)
 
 /* update a tab after hottracking - invalidate it or just redraw the interior,
  * based on whether theming is used or not */
-static inline void hottrack_refresh (TAB_INFO* infoPtr, int tabIndex)
+static inline void hottrack_refresh(const TAB_INFO *infoPtr, int tabIndex)
 {
     if (tabIndex == -1) return;
 
@@ -788,8 +795,8 @@ TAB_RecalcHotTrack
     }
     else
     {
-      pt.x = LOWORD(*pos);
-      pt.y = HIWORD(*pos);
+      pt.x = (short)LOWORD(*pos);
+      pt.y = (short)HIWORD(*pos);
     }
 
     item = TAB_InternalHitTest(infoPtr, pt, &flags);
@@ -866,15 +873,15 @@ TAB_MouseMove (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
  * Calculates the tab control's display area given the window rectangle or
  * the window rectangle given the requested display rectangle.
  */
-static LRESULT TAB_AdjustRect(
-  TAB_INFO *infoPtr,
-  WPARAM fLarger,
-  LPRECT prc)
+static LRESULT TAB_AdjustRect(const TAB_INFO *infoPtr, WPARAM fLarger, LPRECT prc)
 {
     DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
     LONG *iRightBottom, *iLeftTop;
 
-    TRACE ("hwnd=%p fLarger=%d (%ld,%ld)-(%ld,%ld)\n", infoPtr->hwnd, fLarger, prc->left, prc->top, prc->right, prc->bottom);
+    TRACE ("hwnd=%p fLarger=%ld (%s)\n", infoPtr->hwnd, fLarger,
+           wine_dbgstr_rect(prc));
+
+    if (!prc) return -1;
 
     if(lStyle & TCS_VERTICAL)
     {
@@ -927,11 +934,7 @@ static LRESULT TAB_AdjustRect(
  * This method will handle the notification from the scroll control and
  * perform the scrolling operation on the tab control.
  */
-static LRESULT TAB_OnHScroll(
-  TAB_INFO *infoPtr,
-  int     nScrollCode,
-  int     nPos,
-  HWND    hwndScroll)
+static LRESULT TAB_OnHScroll(TAB_INFO *infoPtr, int nScrollCode, int nPos)
 {
   if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible)
   {
@@ -1143,11 +1146,11 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
                         ((lStyle & TCS_BUTTONS) ? 2 : 1) *
                           infoPtr->uVItemPadding;
 
-    TRACE("tabH=%d, tmH=%ld, iconh=%d\n",
+    TRACE("tabH=%d, tmH=%d, iconh=%d\n",
          infoPtr->tabHeight, fontMetrics.tmHeight, icon_height);
   }
 
-  TRACE("client right=%ld\n", clientRect.right);
+  TRACE("client right=%d\n", clientRect.right);
 
   /* Get the icon width */
   if (infoPtr->himl)
@@ -1204,7 +1207,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=%ld,%ld\n",
+      TRACE("for <%s>, l,r=%d,%d\n",
          debugstr_w(curr->pszText), curr->rect.left, curr->rect.right);
     }
 
@@ -1224,15 +1227,14 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
 
        curr->rect.left = 0;
         curItemRowCount++;
-       TRACE("wrapping <%s>, l,r=%ld,%ld\n", debugstr_w(curr->pszText),
+       TRACE("wrapping <%s>, l,r=%d,%d\n", debugstr_w(curr->pszText),
            curr->rect.left, curr->rect.right);
     }
 
     curr->rect.bottom = 0;
     curr->rect.top = curItemRowCount - 1;
 
-    TRACE("Rect: T %li, L %li, B %li, R %li\n", curr->rect.top,
-         curr->rect.left, curr->rect.bottom, curr->rect.right);
+    TRACE("Rect: %s\n", wine_dbgstr_rect(&curr->rect));
 
     /*
      * The leftmost position of the next item is the rightmost position
@@ -1302,7 +1304,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
           curr->rect.right -= curr->rect.left;
           curr->rect.left = 0;
 
-         TRACE("r=%ld, cl=%d, cl.r=%ld, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n",
+          TRACE("r=%d, cl=%d, cl.r=%d, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n",
              curr->rect.right, curItemLeftPos, clientRect.right,
              iCount, iRow, infoPtr->uNumRows, remTab, tabPerRow);
 
@@ -1339,7 +1341,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
           else
             curItemLeftPos = curr->rect.right;
 
-         TRACE("arranging <%s>, l,r=%ld,%ld, row=%ld\n",
+          TRACE("arranging <%s>, l,r=%d,%d, row=%d\n",
              debugstr_w(curr->pszText), curr->rect.left,
              curr->rect.right, curr->rect.top);
       }
@@ -1391,7 +1393,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=%ld,%ld\n",
+              TRACE("adjusting 1 <%s>, l,r=%d,%d\n",
                  debugstr_w(item->pszText),
                  item->rect.left, item->rect.right);
 
@@ -1403,7 +1405,7 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
            start->rect.left = clientRect.left;
            start->rect.right = clientRect.right - 4;
 
-           TRACE("adjusting 2 <%s>, l,r=%ld,%ld\n",
+            TRACE("adjusting 2 <%s>, l,r=%d,%d\n",
                debugstr_w(start->pszText),
                start->rect.left, start->rect.right);
 
@@ -1443,20 +1445,13 @@ static void TAB_SetItemBounds (TAB_INFO *infoPtr)
 
 
 static void
-TAB_EraseTabInterior
-    (
-    TAB_INFO*   infoPtr,
-    HDC         hdc,
-    INT         iItem,
-    RECT*       drawRect
-    )
+TAB_EraseTabInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, const RECT *drawRect)
 {
     LONG     lStyle  = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
     HBRUSH   hbr = CreateSolidBrush (comctl32_color.clrBtnFace);
     BOOL     deleteBrush = TRUE;
     RECT     rTemp = *drawRect;
 
-    InflateRect(&rTemp, -2, -2);
     if (lStyle & TCS_BUTTONS)
     {
        if (iItem == infoPtr->iSelected)
@@ -1485,9 +1480,10 @@ TAB_EraseTabInterior
        {
            if (lStyle & TCS_FLATBUTTONS)
            {
-               FillRect(hdc, drawRect, hbr);
+               InflateRect(&rTemp, 2, 2);
+               FillRect(hdc, &rTemp, hbr);
                if (iItem == infoPtr->iHotTracked)
-                   DrawEdge(hdc, drawRect, EDGE_RAISED, BF_SOFT|BF_RECT);
+                   DrawEdge(hdc, &rTemp, BDR_RAISEDINNER, BF_RECT);
            }
            else
                FillRect(hdc, &rTemp, hbr);
@@ -1496,10 +1492,23 @@ TAB_EraseTabInterior
     }
     else /* !TCS_BUTTONS */
     {
+        InflateRect(&rTemp, -2, -2);
         if (!GetWindowTheme (infoPtr->hwnd))
            FillRect(hdc, &rTemp, hbr);
     }
 
+    /* highlighting is drawn on top of previous fills */
+    if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
+    {
+        if (deleteBrush)
+        {
+            DeleteObject(hbr);
+            deleteBrush = FALSE;
+        }
+        hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
+        FillRect(hdc, &rTemp, hbr);
+    }
+
     /* Cleanup */
     if (deleteBrush) DeleteObject(hbr);
 }
@@ -1511,13 +1520,7 @@ TAB_EraseTabInterior
  * into the tab control.
  */
 static void
-TAB_DrawItemInterior
-  (
-  TAB_INFO*   infoPtr,
-  HDC         hdc,
-  INT         iItem,
-  RECT*       drawRect
-  )
+TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect)
 {
   LONG      lStyle  = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
 
@@ -1564,7 +1567,22 @@ TAB_DrawItemInterior
        drawRect->left   += 4;
        drawRect->top    += 4;
        drawRect->right  -= 4;
-       drawRect->bottom -= 1;
+
+       if (lStyle & TCS_VERTICAL)
+       {
+         if (!(lStyle & TCS_BOTTOM)) drawRect->right  += 1;
+         drawRect->bottom   -= 4;
+       }
+       else
+       {
+         if (lStyle & TCS_BOTTOM)
+         {
+           drawRect->top    -= 2;
+           drawRect->bottom -= 4;
+         }
+         else
+           drawRect->bottom -= 1;
+       }
       }
       else
       {
@@ -1624,8 +1642,7 @@ TAB_DrawItemInterior
       }
     }
   }
-  TRACE("drawRect=(%ld,%ld)-(%ld,%ld)\n",
-         drawRect->left, drawRect->top, drawRect->right, drawRect->bottom);
+  TRACE("drawRect=(%s)\n", wine_dbgstr_rect(drawRect));
 
   /* Clear interior */
   TAB_EraseTabInterior (infoPtr, hdc, iItem, drawRect);
@@ -1651,7 +1668,7 @@ TAB_DrawItemInterior
   /*
    * Text pen
    */
-  htextPen = CreatePen( PS_SOLID, 1, GetSysColor(COLOR_BTNTEXT) );
+  htextPen = CreatePen( PS_SOLID, 1, comctl32_color.clrBtnText );
   holdPen  = SelectObject(hdc, htextPen);
   hOldFont = SelectObject(hdc, infoPtr->hFont);
 
@@ -1660,10 +1677,15 @@ TAB_DrawItemInterior
   */
   oldBkMode = SetBkMode(hdc, TRANSPARENT);
   if (!GetWindowTheme (infoPtr->hwnd) || (lStyle & TCS_BUTTONS))
-      SetTextColor(hdc, (((lStyle & TCS_HOTTRACK) && (iItem == infoPtr->iHotTracked) 
-                          && !(lStyle & TCS_FLATBUTTONS)) 
-                        | (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)) ?
-                        comctl32_color.clrHighlight : comctl32_color.clrBtnText);
+  {
+    if ((lStyle & TCS_HOTTRACK) && (iItem == infoPtr->iHotTracked) &&
+        !(lStyle & TCS_FLATBUTTONS))
+      SetTextColor(hdc, comctl32_color.clrHighlight);
+    else if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
+      SetTextColor(hdc, comctl32_color.clrHighlightText);
+    else
+      SetTextColor(hdc, comctl32_color.clrBtnText);
+  }
 
   /*
    * if owner draw, tell the owner to draw
@@ -1735,7 +1757,7 @@ TAB_DrawItemInterior
      *
      * Draw the icon.
      */
-    if (infoPtr->himl && (item->mask & TCIF_IMAGE))
+    if (infoPtr->himl && item->iImage != -1)
     {
       INT cx;
       INT cy;
@@ -1745,14 +1767,20 @@ TAB_DrawItemInterior
       if(lStyle & TCS_VERTICAL)
       {
         center_offset_h = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right  - rcText.left))) / 2;
-        center_offset_v = ((drawRect->right - drawRect->left) - (cx + infoPtr->uVItemPadding)) / 2;
+        center_offset_v = ((drawRect->right - drawRect->left) - cx) / 2;
       }
       else
       {
         center_offset_h = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right  - rcText.left))) / 2;
-        center_offset_v = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uVItemPadding)) / 2;
+        center_offset_v = ((drawRect->bottom - drawRect->top) - cy) / 2;
       }
 
+      /* if an item is selected, the icon is shifted up instead of down */
+      if (iItem == infoPtr->iSelected)
+        center_offset_v -= infoPtr->uVItemPadding / 2;
+      else
+        center_offset_v += infoPtr->uVItemPadding / 2;
+
       if (lStyle & TCS_FIXEDWIDTH && lStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT))
        center_offset_h = infoPtr->uHItemPadding;
 
@@ -1762,10 +1790,9 @@ TAB_DrawItemInterior
       if (center_offset_v < 0)
         center_offset_v = 0;
        
-      TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n",
+      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,
-         drawRect->left, drawRect->top, drawRect->right, drawRect->bottom,
-         (rcText.right-rcText.left));
+          wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
 
       if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM))
       {
@@ -1789,7 +1816,7 @@ TAB_DrawItemInterior
         drawRect->left += cx + infoPtr->uHItemPadding;
       }
 
-      TRACE("drawing image=%d, left=%ld, top=%ld\n",
+      TRACE("drawing image=%d, left=%d, top=%d\n",
            item->iImage, rcImage.left, rcImage.top-1);
       ImageList_Draw
         (
@@ -1893,10 +1920,9 @@ TAB_DrawItemInterior
     }
     else
     {
-      TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n",
+      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,
-         drawRect->left, drawRect->top, drawRect->right, drawRect->bottom,
-         (rcText.right-rcText.left));
+          wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
       if (item->pszText)
       {
         DrawTextW
@@ -1927,10 +1953,7 @@ TAB_DrawItemInterior
  *
  * This method is used to draw a single tab into the tab control.
  */
-static void TAB_DrawItem(
-  TAB_INFO *infoPtr,
-  HDC  hdc,
-  INT  iItem)
+static void TAB_DrawItem(const TAB_INFO *infoPtr, HDC  hdc, INT  iItem)
 {
   LONG      lStyle  = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
   RECT      itemRect;
@@ -1976,7 +1999,7 @@ static void TAB_DrawItem(
       r = itemRect;
 
       /* Separators between flat buttons */
-      if (lStyle & TCS_FLATBUTTONS)
+      if ((lStyle & TCS_FLATBUTTONS) && (infoPtr->exStyle & TCS_EX_FLATSEPARATORS))
       {
        r1 = r;
        r1.right += (FLAT_BTN_SPACINGX -2);
@@ -1991,8 +2014,13 @@ static void TAB_DrawItem(
       }
       else  /* ! selected */
       {
-       if (!(lStyle & TCS_FLATBUTTONS))
-         DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT);
+        DWORD state = TAB_GetItem(infoPtr, iItem)->dwState;
+
+        if (state & TCIS_BUTTONPRESSED)
+          DrawEdge(hdc, &r, EDGE_SUNKEN, BF_SOFT|BF_RECT);
+        else
+          if (!(lStyle & TCS_FLATBUTTONS))
+            DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT);
       }
     }
     else /* !TCS_BUTTONS */
@@ -2067,7 +2095,7 @@ static void TAB_DrawItem(
       {
        /* These are for adjusting the drawing of a Selected tab      */
        /* The initial values are for the normal case of non-Selected */
-       int ZZ = 1;   /* Do not strech if selected */
+       int ZZ = 1;   /* Do not stretch if selected */
        if (iItem == infoPtr->iSelected) {
            ZZ = 0;
 
@@ -2084,10 +2112,8 @@ static void TAB_DrawItem(
          /* Adjust both rectangles to match native */
          r.left += (1-ZZ);
 
-         TRACE("<right> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
-               iItem,
-               fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
-               r.left,r.top,r.right,r.bottom);
+          TRACE("<right> item=%d, fill=(%s), edge=(%s)\n",
+                iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
 
          /* Clear interior */
          SetBkColor(hdc, bkgnd);
@@ -2125,10 +2151,8 @@ static void TAB_DrawItem(
         }
         else
         {
-         TRACE("<left> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
-               iItem,
-               fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
-               r.left,r.top,r.right,r.bottom);
+          TRACE("<left> item=%d, fill=(%s), edge=(%s)\n",
+                iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
 
          /* Clear interior */
          SetBkColor(hdc, bkgnd);
@@ -2179,10 +2203,8 @@ static void TAB_DrawItem(
            r.top -= 1;
          }
 
-         TRACE("<bottom> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
-               iItem,
-               fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
-               r.left,r.top,r.right,r.bottom);
+          TRACE("<bottom> item=%d, fill=(%s), edge=(%s)\n",
+                iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
 
          /* Clear interior */
          SetBkColor(hdc, bkgnd);
@@ -2233,10 +2255,8 @@ static void TAB_DrawItem(
            r.bottom += 2;
          }
 
-         TRACE("<top> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
-               iItem,
-               fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
-               r.left,r.top,r.right,r.bottom);
+          TRACE("<top> item=%d, fill=(%s), edge=(%s)\n",
+                iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
 
          /* Clear interior */
          SetBkColor(hdc, bkgnd);
@@ -2280,7 +2300,7 @@ static void TAB_DrawItem(
  * This method is used to draw the raised border around the tab control
  * "content" area.
  */
-static void TAB_DrawBorder (TAB_INFO *infoPtr, HDC hdc)
+static void TAB_DrawBorder(const TAB_INFO *infoPtr, HDC hdc)
 {
   RECT rect;
   DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
@@ -2304,8 +2324,7 @@ static void TAB_DrawBorder (TAB_INFO *infoPtr, HDC hdc)
       rect.top    += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
   }
 
-  TRACE("border=(%ld,%ld)-(%ld,%ld)\n",
-       rect.left, rect.top, rect.right, rect.bottom);
+  TRACE("border=(%s)\n", wine_dbgstr_rect(&rect));
 
   if (theme)
       DrawThemeBackground (theme, hdc, TABP_PANE, 0, &rect, NULL);
@@ -2348,11 +2367,6 @@ static void TAB_Refresh (TAB_INFO *infoPtr, HDC hdc)
 
     /* Then, draw the selected item */
     TAB_DrawItem (infoPtr, hdc, infoPtr->iSelected);
-
-    /* If we haven't set the current focus yet, set it now.
-     * Only happens when we first paint the tab controls */
-    if (infoPtr->uFocus == -1)
-      TAB_SetCurFocus(infoPtr, infoPtr->iSelected);
   }
 
   SelectObject (hdc, hOldFont);
@@ -2495,7 +2509,7 @@ static void TAB_EnsureSelectionVisible(
  * tabs. It is called when the state of the control changes and needs
  * to be redisplayed
  */
-static void TAB_InvalidateTabArea(TAB_INFO* infoPtr)
+static void TAB_InvalidateTabArea(const TAB_INFO *infoPtr)
 {
   RECT clientRect, rInvalidate, rAdjClient;
   DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
@@ -2545,11 +2559,9 @@ static void TAB_InvalidateTabArea(TAB_INFO* infoPtr)
     else
       rInvalidate.right = clientRect.right - r.left;
   }
-  
-  TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n",
-       rInvalidate.left,  rInvalidate.top,
-       rInvalidate.right, rInvalidate.bottom);
+
+  TRACE("invalidate (%s)\n", wine_dbgstr_rect(&rInvalidate));
+
   InvalidateRect(infoPtr->hwnd, &rInvalidate, TRUE);
 }
 
@@ -2563,9 +2575,7 @@ static inline LRESULT TAB_Paint (TAB_INFO *infoPtr, HDC hdcPaint)
   else
   {
     hdc = BeginPaint (infoPtr->hwnd, &ps);
-    TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n",
-         ps.fErase,
-         ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right,ps.rcPaint.bottom);
+    TRACE("erase %d, rect=(%s)\n", ps.fErase, wine_dbgstr_rect(&ps.rcPaint));
   }
 
   TAB_Refresh (infoPtr, hdc);
@@ -2585,8 +2595,7 @@ TAB_InsertItemT (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
   RECT rect;
 
   GetClientRect (infoPtr->hwnd, &rect);
-  TRACE("Rect: %p T %li, L %li, B %li, R %li\n", infoPtr->hwnd,
-        rect.top, rect.left, rect.bottom, rect.right);
+  TRACE("Rect: %p %s\n", infoPtr->hwnd, wine_dbgstr_rect(&rect));
 
   pti = (TCITEMW *)lParam;
   iItem = (INT)wParam;
@@ -2631,7 +2640,6 @@ TAB_InsertItemT (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
 
   item = TAB_GetItem(infoPtr, iItem);
 
-  item->mask = pti->mask;
   item->pszText = NULL;
 
   if (pti->mask & TCIF_TEXT)
@@ -2661,6 +2669,10 @@ TAB_InsertItemT (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
   TRACE("[%p]: added item %d %s\n",
         infoPtr->hwnd, iItem, debugstr_w(item->pszText));
 
+  /* If we haven't set the current focus yet, set it now. */
+  if (infoPtr->uFocus == -1)
+    TAB_SetCurFocus(infoPtr, iItem);
+
   return iItem;
 }
 
@@ -2706,12 +2718,12 @@ static inline LRESULT TAB_SetMinTabWidth (TAB_INFO *infoPtr, INT cx)
 
   TRACE("(%p,%d)\n", infoPtr, cx);
 
-  if (infoPtr) {
+  if (infoPtr->tabMinWidth < 0)
+    oldcx = DEFAULT_MIN_TAB_WIDTH;
+  else
     oldcx = infoPtr->tabMinWidth;
-    infoPtr->tabMinWidth = cx;
-  }
+  infoPtr->tabMinWidth = cx;
   TAB_SetItemBounds(infoPtr);
-
   return oldcx;
 }
 
@@ -2719,6 +2731,8 @@ static inline LRESULT
 TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight)
 {
   LPDWORD lpState;
+  DWORD oldState;
+  RECT r;
 
   TRACE("(%p,%d,%s)\n", infoPtr, iItem, fHighlight ? "true" : "false");
 
@@ -2726,12 +2740,16 @@ TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight)
     return FALSE;
   
   lpState = &TAB_GetItem(infoPtr, iItem)->dwState;
+  oldState = *lpState;
 
   if (fHighlight)
     *lpState |= TCIS_HIGHLIGHTED;
   else
     *lpState &= ~TCIS_HIGHLIGHTED;
 
+  if ((oldState != *lpState) && TAB_InternalGetItemRect (infoPtr, iItem, &r, NULL))
+    InvalidateRect (infoPtr->hwnd, &r, TRUE);
+
   return TRUE;
 }
 
@@ -2759,15 +2777,13 @@ TAB_SetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
     FIXME("TCIF_RTLREADING\n");
 
   if (tabItem->mask & TCIF_STATE)
-    wineItem->dwState = tabItem->dwState;
+    wineItem->dwState = (wineItem->dwState & ~tabItem->dwStateMask) |
+                        ( tabItem->dwState &  tabItem->dwStateMask);
 
   if (tabItem->mask & TCIF_TEXT)
   {
-    if (wineItem->pszText)
-    {
-      Free(wineItem->pszText);
-      wineItem->pszText = NULL;
-    }
+    Free(wineItem->pszText);
+    wineItem->pszText = NULL;
     if (bUnicode)
       Str_SetPtrW(&wineItem->pszText, tabItem->pszText);
     else
@@ -2809,7 +2825,7 @@ TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
     FIXME("TCIF_RTLREADING\n");
 
   if (tabItem->mask & TCIF_STATE)
-    tabItem->dwState = wineItem->dwState;
+    tabItem->dwState = wineItem->dwState & tabItem->dwStateMask;
 
   if (tabItem->mask & TCIF_TEXT)
   {
@@ -2835,12 +2851,9 @@ static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
     {
         TAB_ITEM *item = TAB_GetItem(infoPtr, iItem);
         LPBYTE oldItems = (LPBYTE)infoPtr->items;
-       
-       TAB_InvalidateTabArea(infoPtr);
-
-       if ((item->mask & TCIF_TEXT) && item->pszText)
-            Free(item->pszText);
 
+       TAB_InvalidateTabArea(infoPtr);
+        Free(item->pszText);
        infoPtr->uNumItem--;
 
        if (!infoPtr->uNumItem)
@@ -2867,7 +2880,7 @@ static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
             if (iItem <= infoPtr->iHotTracked)
             {
                 /* When tabs move left/up, the hot track item may change */
-                FIXME("Recalc hot track");
+                FIXME("Recalc hot track\n");
             }
        }
        Free(oldItems);
@@ -2931,6 +2944,8 @@ static inline LRESULT TAB_SetImageList (TAB_INFO *infoPtr, HIMAGELIST himlNew)
     HIMAGELIST himlPrev = infoPtr->himl;
     TRACE("\n");
     infoPtr->himl = himlNew;
+    TAB_SetItemBounds(infoPtr);
+    InvalidateRect(infoPtr->hwnd, NULL, TRUE);
     return (LRESULT)himlPrev;
 }
 
@@ -2984,7 +2999,7 @@ static inline LRESULT TAB_Size (TAB_INFO *infoPtr)
 }
 
 
-static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
+static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
 {
   TAB_INFO *infoPtr;
   TEXTMETRICW fontMetrics;
@@ -2992,7 +3007,7 @@ static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
   HFONT hOldFont;
   DWORD dwStyle;
 
-  infoPtr = (TAB_INFO *)Alloc (sizeof(TAB_INFO));
+  infoPtr = Alloc (sizeof(TAB_INFO));
 
   SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
 
@@ -3027,10 +3042,12 @@ static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
   dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
   SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS);
 
+  infoPtr->exStyle = (dwStyle & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
+
   if (dwStyle & TCS_TOOLTIPS) {
     /* Create tooltip control */
     infoPtr->hwndToolTip =
-      CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0,
+      CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
                       CW_USEDEFAULT, CW_USEDEFAULT,
                       CW_USEDEFAULT, CW_USEDEFAULT,
                       hwnd, 0, 0, 0);
@@ -3071,7 +3088,7 @@ static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
 
   /* Initialize the width of a tab. */
   if (dwStyle & TCS_FIXEDWIDTH)
-    infoPtr->tabWidth = DEFAULT_TAB_WIDTH_FIXED;
+    infoPtr->tabWidth = GetDeviceCaps(hdc, LOGPIXELSX);
 
   infoPtr->tabMinWidth = -1;
 
@@ -3095,8 +3112,7 @@ TAB_Destroy (TAB_INFO *infoPtr)
 
   if (infoPtr->items) {
     for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
-      if (TAB_GetItem(infoPtr, iItem)->pszText)
-       Free (TAB_GetItem(infoPtr, iItem)->pszText);
+      Free (TAB_GetItem(infoPtr, iItem)->pszText);
     }
     Free (infoPtr->items);
   }
@@ -3117,7 +3133,7 @@ TAB_Destroy (TAB_INFO *infoPtr)
 }
 
 /* update theme after a WM_THEMECHANGED message */
-static LRESULT theme_changed (TAB_INFO* infoPtr)
+static LRESULT theme_changed(const TAB_INFO *infoPtr)
 {
     HTHEME theme = GetWindowTheme (infoPtr->hwnd);
     CloseThemeData (theme);
@@ -3125,7 +3141,7 @@ static LRESULT theme_changed (TAB_INFO* infoPtr)
     return 0;
 }
 
-static LRESULT TAB_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
+static LRESULT TAB_NCCalcSize(WPARAM wParam)
 {
   if (!wParam)
     return 0;
@@ -3148,12 +3164,109 @@ TAB_SetItemExtra (TAB_INFO *infoPtr, INT cbInfo)
   return TRUE;
 }
 
+static LRESULT TAB_RemoveImage (TAB_INFO *infoPtr, INT image)
+{
+  if (!infoPtr)
+    return 0;
+
+  if (ImageList_Remove (infoPtr->himl, image))
+  {
+    INT i, *idx;
+    RECT r;
+
+    /* shift indices, repaint items if needed */
+    for (i = 0; i < infoPtr->uNumItem; i++)
+    {
+      idx = &TAB_GetItem(infoPtr, i)->iImage;
+      if (*idx >= image)
+      {
+        if (*idx == image)
+          *idx = -1;
+        else
+          (*idx)--;
+
+        /* repaint item */
+        if (TAB_InternalGetItemRect (infoPtr, i, &r, NULL))
+          InvalidateRect (infoPtr->hwnd, &r, TRUE);
+      }
+    }
+  }
+
+  return 0;
+}
+
+static LRESULT
+TAB_SetExtendedStyle (TAB_INFO *infoPtr, DWORD exMask, DWORD exStyle)
+{
+  DWORD prevstyle = infoPtr->exStyle;
+
+  /* zero mask means all styles */
+  if (exMask == 0) exMask = ~0;
+
+  if (exMask & TCS_EX_REGISTERDROP)
+  {
+    FIXME("TCS_EX_REGISTERDROP style unimplemented\n");
+    exMask  &= ~TCS_EX_REGISTERDROP;
+    exStyle &= ~TCS_EX_REGISTERDROP;
+  }
+
+  if (exMask & TCS_EX_FLATSEPARATORS)
+  {
+    if ((prevstyle ^ exStyle) & TCS_EX_FLATSEPARATORS)
+    {
+        infoPtr->exStyle ^= TCS_EX_FLATSEPARATORS;
+        TAB_InvalidateTabArea(infoPtr);
+    }
+  }
+
+  return prevstyle;
+}
+
+static inline LRESULT
+TAB_GetExtendedStyle (const TAB_INFO *infoPtr)
+{
+  return infoPtr->exStyle;
+}
+
+static LRESULT
+TAB_DeselectAll (TAB_INFO *infoPtr, BOOL excludesel)
+{
+  LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+  BOOL paint = FALSE;
+  INT i, selected = infoPtr->iSelected;
+
+  if (!(style & TCS_BUTTONS))
+    return 0;
+
+  for (i = 0; i < infoPtr->uNumItem; i++)
+  {
+    if ((TAB_GetItem(infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
+        (selected != i))
+    {
+      TAB_GetItem(infoPtr, i)->dwState &= ~TCIS_BUTTONPRESSED;
+      paint = TRUE;
+    }
+  }
+
+  if (!excludesel && (selected != -1))
+  {
+    TAB_GetItem(infoPtr, selected)->dwState &= ~TCIS_BUTTONPRESSED;
+    infoPtr->iSelected = -1;
+    paint = TRUE;
+  }
+
+  if (paint)
+    TAB_InvalidateTabArea (infoPtr);
+
+  return 0;
+}
+
 static LRESULT WINAPI
 TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
 
-    TRACE("hwnd=%p msg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
+    TRACE("hwnd=%p msg=%x wParam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
     if (!infoPtr && (uMsg != WM_CREATE))
       return DefWindowProcW (hwnd, uMsg, wParam, lParam);
 
@@ -3208,8 +3321,7 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       return TAB_SetItemSize (infoPtr, lParam);
 
     case TCM_REMOVEIMAGE:
-      FIXME("Unimplemented msg TCM_REMOVEIMAGE\n");
-      return 0;
+      return TAB_RemoveImage (infoPtr, wParam);
 
     case TCM_SETPADDING:
       return TAB_SetPadding (infoPtr, lParam);
@@ -3242,16 +3354,13 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       return TAB_SetMinTabWidth(infoPtr, (INT)lParam);
 
     case TCM_DESELECTALL:
-      FIXME("Unimplemented msg TCM_DESELECTALL\n");
-      return 0;
+      return TAB_DeselectAll (infoPtr, (BOOL)wParam);
 
     case TCM_GETEXTENDEDSTYLE:
-      FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
-      return 0;
+      return TAB_GetExtendedStyle (infoPtr);
 
     case TCM_SETEXTENDEDSTYLE:
-      FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
-      return 0;
+      return TAB_SetExtendedStyle (infoPtr, wParam, lParam);
 
     case WM_GETFONT:
       return TAB_GetFont (infoPtr);
@@ -3260,7 +3369,7 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       return TAB_SetFont (infoPtr, (HFONT)wParam);
 
     case WM_CREATE:
-      return TAB_Create (hwnd, wParam, lParam);
+      return TAB_Create (hwnd, lParam);
 
     case WM_NCDESTROY:
       return TAB_Destroy (infoPtr);
@@ -3283,6 +3392,7 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     case WM_MOUSEMOVE:
       return TAB_MouseMove (infoPtr, wParam, lParam);
 
+    case WM_PRINTCLIENT:
     case WM_PAINT:
       return TAB_Paint (infoPtr, (HDC)wParam);
 
@@ -3293,7 +3403,7 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       return TAB_SetRedraw (infoPtr, (BOOL)wParam);
 
     case WM_HSCROLL:
-      return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam);
+      return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam));
 
     case WM_STYLECHANGED:
       TAB_SetItemBounds (infoPtr);
@@ -3318,11 +3428,11 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
       return TAB_NCHitTest(infoPtr, lParam);
 
     case WM_NCCALCSIZE:
-      return TAB_NCCalcSize(hwnd, wParam, lParam);
+      return TAB_NCCalcSize(wParam);
 
     default:
-      if (uMsg >= WM_USER && uMsg < WM_APP)
-       WARN("unknown msg %04x wp=%08x lp=%08lx\n",
+      if (uMsg >= WM_USER && uMsg < WM_APP && !COMCTL32_IsReflectedMessage(uMsg))
+       WARN("unknown msg %04x wp=%08lx lp=%08lx\n",
             uMsg, wParam, lParam);
       break;
     }