I don't like this, but add the treeview refresh hack.
[reactos.git] / reactos / dll / win32 / comctl32 / treeview.c
index 2aaf41e..8d2a6f3 100644 (file)
  *
  * 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
  *
  * Note that TREEVIEW_INFO * and HTREEITEM are the same thing.
  *
- * Note2: All items always! have valid (allocated) pszText field.
- *      If item's text == LPSTR_TEXTCALLBACKA we allocate buffer
+ * Note2: If item's text == LPSTR_TEXTCALLBACKA we allocate buffer
  *      of size TEXT_CALLBACK_SIZE in DoSetItem.
  *      We use callbackMask to keep track of fields to be updated.
  *
  * TODO:
- *   missing notifications: NM_SETCURSOR, TVN_GETINFOTIP, TVN_KEYDOWN,
+ *   missing notifications: TVN_GETINFOTIP, TVN_KEYDOWN,
  *      TVN_SETDISPINFO, TVN_SINGLEEXPAND
  *
  *   missing styles: TVS_FULLROWSELECT, TVS_INFOTIP, TVS_RTLREADING,
@@ -64,6 +63,8 @@
 #include "wine/unicode.h"
 #include "wine/debug.h"
 
+WINE_DEFAULT_DEBUG_CHANNEL(treeview);
+
 /* internal structures */
 
 typedef struct _TREEITEM    /* HTREEITEM is a _TREEINFO *. */
@@ -120,6 +121,7 @@ typedef struct tagTREEVIEW_INFO
   HTREEITEM     selectedItem;   /* handle to selected item or 0 if none */
   HTREEITEM     hotItem;        /* handle currently under cursor, 0 if none */
   HTREEITEM    focusedItem;    /* item that was under the cursor when WM_LBUTTONDOWN was received */
+  HTREEITEM     editItem;       /* item being edited with builtin edit box */
 
   HTREEITEM     firstVisible;   /* handle to first visible item */
   LONG          maxVisibleOrder;
@@ -153,10 +155,10 @@ typedef struct tagTREEVIEW_INFO
   int           stateImageWidth;
   HDPA          items;
 
-  DWORD lastKeyPressTimestamp; /* Added */
-  WPARAM charCode; /* Added */
-  INT nSearchParamLength; /* Added */
-  WCHAR szSearchParam[ MAX_PATH ]; /* Added */
+  DWORD lastKeyPressTimestamp;
+  WPARAM charCode;
+  INT nSearchParamLength;
+  WCHAR szSearchParam[ MAX_PATH ];
 } TREEVIEW_INFO;
 
 
@@ -169,7 +171,7 @@ typedef struct tagTREEVIEW_INFO
 #define TV_VSCROLL     0x02    /* (horizontal/vertical) */
 #define TV_LDRAG               0x04    /* Lbutton pushed to start drag */
 #define TV_LDRAGGING   0x08    /* Lbutton pushed, mouse moved. */
-#define TV_RDRAG               0x10    /* dito Rbutton */
+#define TV_RDRAG               0x10    /* ditto Rbutton */
 #define TV_RDRAGGING   0x20
 
 /* bitflags for infoPtr->timer */
@@ -177,14 +179,6 @@ typedef struct tagTREEVIEW_INFO
 #define TV_EDIT_TIMER    2
 #define TV_EDIT_TIMER_SET 2
 
-
-VOID TREEVIEW_Register (VOID);
-VOID TREEVIEW_Unregister (VOID);
-
-
-WINE_DEFAULT_DEBUG_CHANNEL(treeview);
-
-
 #define TEXT_CALLBACK_SIZE 260
 
 #define TREEVIEW_LEFT_MARGIN 8
@@ -197,6 +191,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(treeview);
 #define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f)
 #define ISVISIBLE(x)         ((x)->visibleOrder >= 0)
 
+#define GETLINECOLOR(x) ((x) == CLR_DEFAULT ? comctl32_color.clrGrayText   : (x))
+#define GETBKCOLOR(x)   ((x) == CLR_NONE    ? comctl32_color.clrWindow     : (x))
+#define GETTXTCOLOR(x)  ((x) == CLR_NONE    ? comctl32_color.clrWindowText : (x))
+#define GETINSCOLOR(x)  ((x) == CLR_DEFAULT ? comctl32_color.clrBtnText    : (x))
 
 static const WCHAR themeClass[] = { 'T','r','e','e','v','i','e','w',0 };
 
@@ -204,17 +202,15 @@ static const WCHAR themeClass[] = { 'T','r','e','e','v','i','e','w',0 };
 typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID);
 
 
-static VOID TREEVIEW_Invalidate(TREEVIEW_INFO *, TREEVIEW_ITEM *);
+static VOID TREEVIEW_Invalidate(const TREEVIEW_INFO *, const TREEVIEW_ITEM *);
 
 static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT);
 static VOID TREEVIEW_SetFirstVisible(TREEVIEW_INFO *, TREEVIEW_ITEM *, BOOL);
 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM, BOOL);
-static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT);
+static LRESULT TREEVIEW_RButtonUp(const TREEVIEW_INFO *, const POINT *);
 static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel);
 static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr);
 static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM);
-static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND wParam, UINT lParam);
-
 
 /* Random Utilities *****************************************************/
 
@@ -239,15 +235,14 @@ TREEVIEW_GetInfoPtr(HWND hwnd)
 
 /* Don't call this. Nothing wants an item index. */
 static inline int
-TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle)
+TREEVIEW_GetItemIndex(const TREEVIEW_INFO *infoPtr, HTREEITEM handle)
 {
-    assert(infoPtr != NULL);
-
     return DPA_GetPtrIndex(infoPtr->items, handle);
 }
 
 /* Checks if item has changed and needs to be redrawn */
-static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPTVITEMEXW tvChange)
+static inline BOOL item_changed (const TREEVIEW_ITEM *tiOld, const TREEVIEW_ITEM *tiNew,
+                                 const TVITEMEXW *tvChange)
 {
     /* Number of children has changed */
     if ((tvChange->mask & TVIF_CHILDREN) && (tiOld->cChildren != tiNew->cChildren))
@@ -283,7 +278,7 @@ static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPT
  * This method checks that handle is an item for this tree.
  */
 static BOOL
-TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr, HTREEITEM handle)
+TREEVIEW_ValidItem(const TREEVIEW_INFO *infoPtr, HTREEITEM handle)
 {
     if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1)
     {
@@ -315,7 +310,7 @@ TREEVIEW_CreateUnderlineFont(HFONT hOrigFont)
 }
 
 static inline HFONT
-TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_FontForItem(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item)
 {
     if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (item == infoPtr->hotItem))
         return infoPtr->hUnderlineFont;
@@ -326,7 +321,7 @@ TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 
 /* for trace/debugging purposes only */
 static const char *
-TREEVIEW_ItemName(TREEVIEW_ITEM *item)
+TREEVIEW_ItemName(const TREEVIEW_ITEM *item)
 {
     if (item == NULL) return "<null item>";
     if (item->pszText == LPSTR_TEXTCALLBACKW) return "<callback>";
@@ -336,7 +331,7 @@ TREEVIEW_ItemName(TREEVIEW_ITEM *item)
 
 /* An item is not a child of itself. */
 static BOOL
-TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child)
+TREEVIEW_IsChildOf(const TREEVIEW_ITEM *parent, const TREEVIEW_ITEM *child)
 {
     do
     {
@@ -355,7 +350,7 @@ TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child)
  * of a tree node
  */
 static TREEVIEW_ITEM *
-TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
+TREEVIEW_GetLastListItem(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
 {
     if (!wineItem)
        return NULL;
@@ -379,7 +374,7 @@ TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
  * considering the tree hierarchy.
  */
 static TREEVIEW_ITEM *
-TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
+TREEVIEW_GetPrevListItem(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *tvItem)
 {
     if (tvItem->prevSibling)
     {
@@ -404,10 +399,8 @@ TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
  * considering the tree hierarchy.
  */
 static TREEVIEW_ITEM *
-TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
+TREEVIEW_GetNextListItem(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *tvItem)
 {
-    assert(tvItem != NULL);
-
     /*
      * If this item has children and is expanded, return the first child
      */
@@ -445,10 +438,10 @@ TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem)
  *             forward if count is >0.
  */
 static TREEVIEW_ITEM *
-TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
+TREEVIEW_GetListItem(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                     LONG count)
 {
-    TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *);
+    TREEVIEW_ITEM *(*next_item)(const TREEVIEW_INFO *, const TREEVIEW_ITEM *);
     TREEVIEW_ITEM *previousItem;
 
     assert(wineItem != NULL);
@@ -478,7 +471,7 @@ TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
 
 /* Notifications ************************************************************/
 
-static INT get_notifycode(TREEVIEW_INFO *infoPtr, INT code)
+static INT get_notifycode(const TREEVIEW_INFO *infoPtr, INT code)
 {
     if (!infoPtr->bNtfUnicode) {
        switch (code) {
@@ -500,14 +493,14 @@ static INT get_notifycode(TREEVIEW_INFO *infoPtr, INT code)
 }
 
 static LRESULT
-TREEVIEW_SendRealNotify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_SendRealNotify(const TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
-    TRACE("wParam=%d, lParam=%ld\n", wParam, lParam);
+    TRACE("wParam=%ld, lParam=%ld\n", wParam, lParam);
     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
 }
 
 static BOOL
-TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code)
+TREEVIEW_SendSimpleNotify(const TREEVIEW_INFO *infoPtr, UINT code)
 {
     NMHDR nmhdr;
     HWND hwnd = infoPtr->hwnd;
@@ -517,12 +510,11 @@ TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code)
     nmhdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID);
     nmhdr.code = get_notifycode(infoPtr, code);
 
-    return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
-                                 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
+    return (BOOL)TREEVIEW_SendRealNotify(infoPtr, nmhdr.idFrom, (LPARAM)&nmhdr);
 }
 
 static VOID
-TREEVIEW_TVItemFromItem(TREEVIEW_INFO *infoPtr, UINT mask, TVITEMW *tvItem, TREEVIEW_ITEM *item)
+TREEVIEW_TVItemFromItem(const TREEVIEW_INFO *infoPtr, UINT mask, TVITEMW *tvItem, TREEVIEW_ITEM *item)
 {
     tvItem->mask = mask;
     tvItem->hItem = item;
@@ -555,7 +547,7 @@ TREEVIEW_TVItemFromItem(TREEVIEW_INFO *infoPtr, UINT mask, TVITEMW *tvItem, TREE
 }
 
 static BOOL
-TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action,
+TREEVIEW_SendTreeviewNotify(const TREEVIEW_INFO *infoPtr, UINT code, UINT action,
                            UINT mask, HTREEITEM oldItem, HTREEITEM newItem)
 {
     HWND hwnd = infoPtr->hwnd;
@@ -581,9 +573,7 @@ TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action,
     nmhdr.ptDrag.x = 0;
     nmhdr.ptDrag.y = 0;
 
-    ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr,
-                              (WPARAM)nmhdr.hdr.idFrom,
-                             (LPARAM)&nmhdr);
+    ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
     if (!infoPtr->bNtfUnicode)
     {
        Free(nmhdr.itemOld.pszText);
@@ -593,7 +583,7 @@ TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action,
 }
 
 static BOOL
-TREEVIEW_SendTreeviewDnDNotify(TREEVIEW_INFO *infoPtr, UINT code,
+TREEVIEW_SendTreeviewDnDNotify(const TREEVIEW_INFO *infoPtr, UINT code,
                               HTREEITEM dragItem, POINT pt)
 {
     HWND hwnd = infoPtr->hwnd;
@@ -613,21 +603,19 @@ TREEVIEW_SendTreeviewDnDNotify(TREEVIEW_INFO *infoPtr, UINT code,
     nmhdr.ptDrag.x = pt.x;
     nmhdr.ptDrag.y = pt.y;
 
-    return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
-                             (WPARAM)nmhdr.hdr.idFrom,
-                             (LPARAM)&nmhdr);
+    return (BOOL)TREEVIEW_SendRealNotify(infoPtr, nmhdr.hdr.idFrom, (LPARAM)&nmhdr);
 }
 
 
 static BOOL
-TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
+TREEVIEW_SendCustomDrawNotify(const TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
                              HDC hdc, RECT rc)
 {
     HWND hwnd = infoPtr->hwnd;
     NMTVCUSTOMDRAW nmcdhdr;
     LPNMCUSTOMDRAW nmcd;
 
-    TRACE("drawstage:%lx hdc:%p\n", dwDrawStage, hdc);
+    TRACE("drawstage:%x hdc:%p\n", dwDrawStage, hdc);
 
     nmcd = &nmcdhdr.nmcd;
     nmcd->hdr.hwndFrom = hwnd;
@@ -643,9 +631,7 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
     nmcdhdr.clrTextBk = infoPtr->clrBk;
     nmcdhdr.iLevel = 0;
 
-    return (BOOL)TREEVIEW_SendRealNotify(infoPtr,
-                             (WPARAM)nmcd->hdr.idFrom,
-                             (LPARAM)&nmcdhdr);
+    return (BOOL)TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, (LPARAM)&nmcdhdr);
 }
 
 
@@ -653,7 +639,7 @@ TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage,
 /* FIXME: need to find out when the flags in uItemState need to be set */
 
 static BOOL
-TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
+TREEVIEW_SendCustomDrawItemNotify(const TREEVIEW_INFO *infoPtr, HDC hdc,
                                  TREEVIEW_ITEM *wineItem, UINT uItemDrawState,
                                  NMTVCUSTOMDRAW *nmcdhdr)
 {
@@ -686,19 +672,17 @@ TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc,
     nmcd->lItemlParam = wineItem->lParam;
     nmcdhdr->iLevel = wineItem->iLevel;
 
-    TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n",
+    TRACE("drawstage:%x hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n",
          nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec,
          nmcd->uItemState, nmcd->lItemlParam);
 
-    retval = TREEVIEW_SendRealNotify(infoPtr,
-                          (WPARAM)nmcd->hdr.idFrom,
-                         (LPARAM)nmcdhdr);
+    retval = TREEVIEW_SendRealNotify(infoPtr, nmcd->hdr.idFrom, (LPARAM)nmcdhdr);
 
-    return (BOOL)retval;
+    return retval;
 }
 
 static BOOL
-TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem)
+TREEVIEW_BeginLabelEditNotify(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem)
 {
     HWND hwnd = infoPtr->hwnd;
     NMTVDISPINFOW tvdi;
@@ -720,10 +704,10 @@ TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem)
 }
 
 static void
-TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
+TREEVIEW_UpdateDispInfo(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                        UINT mask)
 {
-    NMTVDISPINFOW callback;
+    NMTVDISPINFOEXW callback;
     HWND hwnd = infoPtr->hwnd;
 
     TRACE("mask %x callbackMask %x\n", mask, wineItem->callbackMask);
@@ -749,8 +733,7 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
     if (mask & TVIF_TEXT)
        wineItem->textWidth = 0;
 
-    TREEVIEW_SendRealNotify(infoPtr,
-                            (WPARAM)callback.hdr.idFrom, (LPARAM)&callback);
+    TREEVIEW_SendRealNotify(infoPtr, callback.hdr.idFrom, (LPARAM)&callback);
 
     /* It may have changed due to a call to SetItem. */
     mask &= wineItem->callbackMask;
@@ -765,7 +748,7 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                                           (LPSTR)callback.item.pszText, -1,
                                            NULL, 0);
            buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE);
-           newText = (LPWSTR)ReAlloc(wineItem->pszText, buflen);
+            newText = ReAlloc(wineItem->pszText, buflen);
 
            TRACE("returned str %s, len=%d, buflen=%d\n",
                  debugstr_a((LPSTR)callback.item.pszText), len, buflen);
@@ -807,7 +790,7 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                                          (LPSTR)callback.item.pszText, -1,
                                            NULL, 0);
            buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE);
-           newText = (LPWSTR)Alloc(buflen);
+            newText = Alloc(buflen);
 
            TRACE("same buffer str %s, len=%d, buflen=%d\n",
                  debugstr_a((LPSTR)callback.item.pszText), len, buflen);
@@ -820,8 +803,7 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                                     (LPSTR)callback.item.pszText, -1,
                                     wineItem->pszText, buflen/sizeof(WCHAR));
                wineItem->cchTextMax = buflen/sizeof(WCHAR);
-               if (oldText)
-                   Free(oldText);
+               Free(oldText);
            }
        }
     }
@@ -849,20 +831,36 @@ TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
  * Just use wineItem->firstChild to check for physical children.
  */
 static BOOL
-TREEVIEW_HasChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
+TREEVIEW_HasChildren(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
 {
     TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_CHILDREN);
 
     return wineItem->cChildren > 0;
 }
 
+static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND hwndFrom, UINT nCommand)
+{
+    INT format;
+
+    TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand);
+
+    if (nCommand != NF_REQUERY) return 0;
+
+    format = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwnd, NF_QUERY);
+    TRACE("format=%d\n", format);
+
+    if (format != NFR_ANSI && format != NFR_UNICODE) return 0;
+
+    infoPtr->bNtfUnicode = (format == NFR_UNICODE);
+
+    return format;
+}
 
 /* Item Position ********************************************************/
 
 /* Compute linesOffset, stateOffset, imageOffset, textOffset of an item. */
 static VOID
-TREEVIEW_ComputeItemInternalMetrics(TREEVIEW_INFO *infoPtr,
-                                   TREEVIEW_ITEM *item)
+TREEVIEW_ComputeItemInternalMetrics(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 {
     /* Same effect, different optimisation. */
 #if 0
@@ -874,7 +872,7 @@ TREEVIEW_ComputeItemInternalMetrics(TREEVIEW_INFO *infoPtr,
                > TVS_LINESATROOT);
 #endif
 
-    item->linesOffset = infoPtr->uIndent * (item->iLevel + lar - 1)
+    item->linesOffset = infoPtr->uIndent * (lar ? item->iLevel : item->iLevel - 1)
        - infoPtr->scrollX;
     item->stateOffset = item->linesOffset + infoPtr->uIndent;
     item->imageOffset = item->stateOffset
@@ -883,7 +881,7 @@ TREEVIEW_ComputeItemInternalMetrics(TREEVIEW_INFO *infoPtr,
 }
 
 static VOID
-TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item, HDC hDC)
+TREEVIEW_ComputeTextWidth(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item, HDC hDC)
 {
     HDC hdc;
     HFONT hOldFont=0;
@@ -917,7 +915,7 @@ TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item, HDC hDC)
 }
 
 static VOID
-TREEVIEW_ComputeItemRect(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_ComputeItemRect(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 {
     item->rect.top = infoPtr->uItemHeight *
        (item->visibleOrder - infoPtr->firstVisible->visibleOrder);
@@ -947,6 +945,8 @@ TREEVIEW_RecalculateVisibleOrder(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *start)
     for (item = start; item != NULL;
          item = TREEVIEW_GetNextListItem(infoPtr, item))
     {
+       if (!ISVISIBLE(item) && order > 0)
+               TREEVIEW_ComputeItemInternalMetrics(infoPtr, item);
        item->visibleOrder = order;
        order += item->iIntegral;
     }
@@ -965,7 +965,7 @@ TREEVIEW_RecalculateVisibleOrder(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *start)
  * root must be expanded
  */
 static VOID
-TREEVIEW_UpdateSubTree(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *root)
+TREEVIEW_UpdateSubTree(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *root)
 {
    TREEVIEW_ITEM *sibling;
    HDC hdc;
@@ -1003,15 +1003,19 @@ TREEVIEW_UpdateSubTree(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *root)
 /* Item Allocation **********************************************************/
 
 static TREEVIEW_ITEM *
-TREEVIEW_AllocateItem(TREEVIEW_INFO *infoPtr)
+TREEVIEW_AllocateItem(const TREEVIEW_INFO *infoPtr)
 {
     TREEVIEW_ITEM *newItem = Alloc(sizeof(TREEVIEW_ITEM));
 
     if (!newItem)
        return NULL;
 
-    newItem->iImage = -1;
-    newItem->iSelectedImage = -1;
+    /* I_IMAGENONE would make more sense but this is neither what is
+     * documented (MSDN doesn't specify) nor what Windows actually does
+     * (it sets it to zero)... and I can so imagine an application using
+     * inc/dec to toggle the images. */
+    newItem->iImage = 0;
+    newItem->iSelectedImage = 0;
 
     if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1)
     {
@@ -1028,7 +1032,6 @@ static void
 TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 {
     DPA_DeletePtr(infoPtr->items, DPA_GetPtrIndex(infoPtr->items, item));
-    Free(item);
     if (infoPtr->selectedItem == item)
         infoPtr->selectedItem = NULL;
     if (infoPtr->hotItem == item)
@@ -1041,6 +1044,7 @@ TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
         infoPtr->dropItem = NULL;
     if (infoPtr->insertMarkItem == item)
         infoPtr->insertMarkItem = NULL;
+    Free(item);
 }
 
 
@@ -1054,7 +1058,6 @@ static void
 TREEVIEW_InsertBefore(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling,
                      TREEVIEW_ITEM *parent)
 {
-    assert(newItem != NULL);
     assert(parent != NULL);
 
     if (sibling != NULL)
@@ -1087,7 +1090,6 @@ static void
 TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling,
                     TREEVIEW_ITEM *parent)
 {
-    assert(newItem != NULL);
     assert(parent != NULL);
 
     if (sibling != NULL)
@@ -1113,7 +1115,7 @@ TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling,
 }
 
 static BOOL
-TREEVIEW_DoSetItemT(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
+TREEVIEW_DoSetItemT(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                   const TVITEMEXW *tvItem, BOOL isW)
 {
     UINT callbackClear = 0;
@@ -1124,7 +1126,7 @@ TREEVIEW_DoSetItemT(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
     if (tvItem->mask & TVIF_TEXT)
     {
         wineItem->textWidth = 0; /* force width recalculation */
-       if (tvItem->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */
+       if (tvItem->pszText != LPSTR_TEXTCALLBACKW && tvItem->pszText != NULL) /* covers != TEXTCALLBACKA too, and undocumented: pszText of NULL also means TEXTCALLBACK */
        {
             int len;
             LPWSTR newText;
@@ -1232,7 +1234,7 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
        if (!TREEVIEW_ValidItem(infoPtr, parentItem))
        {
            WARN("invalid parent %p\n", parentItem);
-           return (LRESULT)(HTREEITEM)NULL;
+            return 0;
        }
     }
 
@@ -1263,13 +1265,14 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
 
     newItem = TREEVIEW_AllocateItem(infoPtr);
     if (newItem == NULL)
-       return (LRESULT)(HTREEITEM)NULL;
+        return 0;
 
     newItem->parent = parentItem;
     newItem->iIntegral = 1;
+    newItem->visibleOrder = -1;
 
     if (!TREEVIEW_DoSetItemT(infoPtr, newItem, tvItem, isW))
-       return (LRESULT)(HTREEITEM)NULL;
+        return 0;
 
     /* After this point, nothing can fail. (Except for TVI_SORT.) */
 
@@ -1299,6 +1302,7 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
        {
            TREEVIEW_ITEM *aChild;
            TREEVIEW_ITEM *previousChild = NULL;
+            TREEVIEW_ITEM *originalFirst = parentItem->firstChild;
            BOOL bItemInserted = FALSE;
 
            aChild = parentItem->firstChild;
@@ -1317,6 +1321,9 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
                if (comp < 0)   /* we are smaller than the current one */
                {
                    TREEVIEW_InsertBefore(newItem, aChild, parentItem);
+                    if (infoPtr->firstVisible == originalFirst &&
+                        aChild == originalFirst)
+                        TREEVIEW_SetFirstVisible(infoPtr, newItem, TRUE);
                    bItemInserted = TRUE;
                    break;
                }
@@ -1375,6 +1382,8 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
 
     TREEVIEW_VerifyTree(infoPtr);
 
+    if (!infoPtr->bRedraw) return (LRESULT)newItem;
+
     if (parentItem == infoPtr->root ||
         (ISVISIBLE(parentItem) && parentItem->state & TVIS_EXPANDED))
     {
@@ -1400,8 +1409,6 @@ TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL i
     }
     else
     {
-       newItem->visibleOrder = -1;
-
        /* refresh treeview if newItem is the first item inserted under parentItem */
        if (ISVISIBLE(parentItem) && newItem->prevSibling == newItem->nextSibling)
        {
@@ -1418,7 +1425,7 @@ static void
 TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem);
 
 static void
-TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem)
+TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *parentItem)
 {
     TREEVIEW_ITEM *kill = parentItem->firstChild;
 
@@ -1437,7 +1444,7 @@ TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem)
 }
 
 static void
-TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item)
+TREEVIEW_UnlinkItem(const TREEVIEW_ITEM *item)
 {
     TREEVIEW_ITEM *parentItem = item->parent;
 
@@ -1476,7 +1483,7 @@ TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem)
 
     infoPtr->uNumItems--;
 
-    if (wineItem->pszText && wineItem->pszText != LPSTR_TEXTCALLBACKW)
+    if (wineItem->pszText != LPSTR_TEXTCALLBACKW)
        Free(wineItem->pszText);
 
     TREEVIEW_FreeItem(infoPtr, wineItem);
@@ -1572,6 +1579,7 @@ TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem)
 
     TREEVIEW_VerifyTree(infoPtr);
 
+    if (!infoPtr->bRedraw) return TRUE;
 
     if (visible)
     {
@@ -1592,18 +1600,22 @@ TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem)
 
 /* Get/Set Messages *********************************************************/
 static LRESULT
-TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam)
 {
-  if(wParam)
-    infoPtr->bRedraw = TRUE;
-  else
-    infoPtr->bRedraw = FALSE;
+    infoPtr->bRedraw = wParam ? TRUE : FALSE;
 
-  return 0;
+    if (infoPtr->bRedraw)
+    {
+        TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root);
+        TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL);
+        TREEVIEW_UpdateScrollBars(infoPtr);
+        TREEVIEW_Invalidate(infoPtr, NULL);
+    }
+    return 0;
 }
 
 static LRESULT
-TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetIndent(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return infoPtr->uIndent;
@@ -1630,7 +1642,7 @@ TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, UINT newIndent)
 
 
 static LRESULT
-TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetToolTips(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return (LRESULT)infoPtr->hwndToolTip;
@@ -1657,13 +1669,13 @@ TREEVIEW_SetUnicodeFormat(TREEVIEW_INFO *infoPtr, BOOL fUnicode)
 }
 
 static LRESULT
-TREEVIEW_GetUnicodeFormat(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetUnicodeFormat(const TREEVIEW_INFO *infoPtr)
 {
      return infoPtr->bNtfUnicode;
 }
 
 static LRESULT
-TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetScrollTime(const TREEVIEW_INFO *infoPtr)
 {
     return infoPtr->uScrollTime;
 }
@@ -1680,16 +1692,16 @@ TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime)
 
 
 static LRESULT
-TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam)
+TREEVIEW_GetImageList(const TREEVIEW_INFO *infoPtr, WPARAM wParam)
 {
     TRACE("\n");
 
     switch (wParam)
     {
-    case (WPARAM)TVSIL_NORMAL:
+    case TVSIL_NORMAL:
        return (LRESULT)infoPtr->himlNormal;
 
-    case (WPARAM)TVSIL_STATE:
+    case TVSIL_STATE:
        return (LRESULT)infoPtr->himlState;
 
     default:
@@ -1702,7 +1714,7 @@ TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 
 /* Compute the natural height for items. */
 static UINT
-TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr)
+TREEVIEW_NaturalHeight(const TREEVIEW_INFO *infoPtr)
 {
     TEXTMETRICW tm;
     HDC hdc = GetDC(0);
@@ -1723,6 +1735,11 @@ TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr)
         height = tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST;
     if (height < infoPtr->normalImageHeight)
         height = infoPtr->normalImageHeight;
+
+    /* Round down, unless we support odd ("non even") heights. */
+    if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT))
+        height &= ~1;
+
     return height;
 }
 
@@ -1734,11 +1751,11 @@ TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, HIMAGELIST himlNew)
     int oldHeight = infoPtr->normalImageHeight;
 
 
-    TRACE("%x,%p\n", wParam, himlNew);
+    TRACE("%lx,%p\n", wParam, himlNew);
 
     switch (wParam)
     {
-    case (WPARAM)TVSIL_NORMAL:
+    case TVSIL_NORMAL:
        himlOld = infoPtr->himlNormal;
        infoPtr->himlNormal = himlNew;
 
@@ -1753,7 +1770,7 @@ TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, HIMAGELIST himlNew)
 
        break;
 
-    case (WPARAM)TVSIL_STATE:
+    case TVSIL_STATE:
        himlOld = infoPtr->himlState;
        infoPtr->himlState = himlNew;
 
@@ -1818,7 +1835,7 @@ TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, INT newHeight)
     }
 
     /* Round down, unless we support odd ("non even") heights. */
-    if (!(infoPtr->dwStyle) & TVS_NONEVENHEIGHT)
+    if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT))
        infoPtr->uItemHeight &= ~1;
 
     if (infoPtr->uItemHeight != prevHeight)
@@ -1832,7 +1849,7 @@ TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, INT newHeight)
 }
 
 static LRESULT
-TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetItemHeight(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return infoPtr->uItemHeight;
@@ -1840,7 +1857,7 @@ TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr)
 
 
 static LRESULT
-TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetFont(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("%p\n", infoPtr->hFont);
     return (LRESULT)infoPtr->hFont;
@@ -1867,6 +1884,7 @@ TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
     infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont;
 
     DeleteObject(infoPtr->hBoldFont);
+    DeleteObject(infoPtr->hUnderlineFont);
     infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont);
     infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont);
 
@@ -1889,7 +1907,7 @@ TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
 
 
 static LRESULT
-TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetLineColor(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return (LRESULT)infoPtr->clrLine;
@@ -1907,7 +1925,7 @@ TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, COLORREF color)
 
 
 static LRESULT
-TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetTextColor(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return (LRESULT)infoPtr->clrText;
@@ -1929,7 +1947,7 @@ TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, COLORREF color)
 
 
 static LRESULT
-TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetBkColor(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return (LRESULT)infoPtr->clrBk;
@@ -1951,7 +1969,7 @@ TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, COLORREF newColor)
 
 
 static LRESULT
-TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetInsertMarkColor(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
     return (LRESULT)infoPtr->clrInsertMark;
@@ -1962,7 +1980,7 @@ TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, COLORREF color)
 {
     COLORREF prevColor = infoPtr->clrInsertMark;
 
-    TRACE("%lx\n", color);
+    TRACE("%x\n", color);
     infoPtr->clrInsertMark = color;
 
     return (LRESULT)prevColor;
@@ -1991,7 +2009,7 @@ TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, BOOL wParam, HTREEITEM item)
  * input HTREEITEM and the output RECT.
  */
 static LRESULT
-TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect)
+TREEVIEW_GetItemRect(const TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect)
 {
     TREEVIEW_ITEM *wineItem;
     const HTREEITEM *pItem = (HTREEITEM *)lpRect;
@@ -2019,29 +2037,31 @@ TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect)
        lpRect->bottom = wineItem->rect.bottom;
 
        lpRect->left = wineItem->textOffset;
-       lpRect->right = wineItem->textOffset + wineItem->textWidth;
+       if (!wineItem->textWidth)
+               TREEVIEW_ComputeTextWidth(infoPtr, wineItem, 0);
+
+       lpRect->right = wineItem->textOffset + wineItem->textWidth + 4;
     }
     else
     {
        *lpRect = wineItem->rect;
     }
 
-    TRACE("%s [L:%ld R:%ld T:%ld B:%ld]\n", fTextRect ? "text" : "item",
-         lpRect->left, lpRect->right, lpRect->top, lpRect->bottom);
+    TRACE("%s [%s]\n", fTextRect ? "text" : "item", wine_dbgstr_rect(lpRect));
 
     return TRUE;
 }
 
 static inline LRESULT
-TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetVisibleCount(const TREEVIEW_INFO *infoPtr)
 {
-    /* Suprise! This does not take integral height into account. */
+    /* Surprise! This does not take integral height into account. */
     return infoPtr->clientHeight / infoPtr->uItemHeight;
 }
 
 
 static LRESULT
-TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
+TREEVIEW_GetItemT(const TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
 {
     TREEVIEW_ITEM *wineItem;
 
@@ -2083,7 +2103,12 @@ TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
 
     if (tvItem->mask & TVIF_TEXT)
     {
-        if (isW)
+        if (wineItem->pszText == NULL)
+        {
+            if (tvItem->cchTextMax > 0)
+                tvItem->pszText[0] = '\0';
+        }
+        else if (isW)
         {
             if (wineItem->pszText == LPSTR_TEXTCALLBACKW)
             {
@@ -2118,7 +2143,7 @@ TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
 /* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success,
  * which is wrong. */
 static LRESULT
-TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
+TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, const TVITEMEXW *tvItem, BOOL isW)
 {
     TREEVIEW_ITEM *wineItem;
     TREEVIEW_ITEM originalItem;
@@ -2131,7 +2156,7 @@ TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
     if (!TREEVIEW_ValidItem(infoPtr, wineItem))
        return FALSE;
 
-    /* store the orignal item values */
+    /* store the original item values */
     originalItem = *wineItem;
 
     if (!TREEVIEW_DoSetItemT(infoPtr, wineItem, tvItem, isW))
@@ -2173,7 +2198,7 @@ TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
 }
 
 static LRESULT
-TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask)
+TREEVIEW_GetItemState(const TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask)
 {
     TRACE("\n");
 
@@ -2184,7 +2209,7 @@ TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask)
 }
 
 static LRESULT
-TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem)
+TREEVIEW_GetNextItem(const TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem)
 {
     TREEVIEW_ITEM *retval;
 
@@ -2260,14 +2285,14 @@ TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem)
 
 
 static LRESULT
-TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetCount(const TREEVIEW_INFO *infoPtr)
 {
     TRACE(" %d\n", infoPtr->uNumItems);
     return (LRESULT)infoPtr->uNumItems;
 }
 
 static VOID
-TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_ToggleItemState(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 {
     if (infoPtr->dwStyle & TVS_CHECKBOXES)
     {
@@ -2295,20 +2320,21 @@ TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 /* Draw the lines and expand button for an item. Also draws one section
  * of the line from item's parent to item's parent's next sibling. */
 static void
-TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
+TREEVIEW_DrawItemLines(const TREEVIEW_INFO *infoPtr, HDC hdc, const TREEVIEW_ITEM *item)
 {
     LONG centerx, centery;
     BOOL lar = ((infoPtr->dwStyle
                 & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS))
                > TVS_LINESATROOT);
     HBRUSH hbr, hbrOld;
+    COLORREF clrBk = GETBKCOLOR(infoPtr->clrBk);
 
     if (!lar && item->iLevel == 0)
        return;
 
-    hbr    = CreateSolidBrush(infoPtr->clrBk);
+    hbr    = CreateSolidBrush(clrBk);
     hbrOld = SelectObject(hdc, hbr);
-    
+
     centerx = (item->linesOffset + item->stateOffset) / 2;
     centery = (item->rect.top + item->rect.bottom) / 2;
 
@@ -2316,13 +2342,18 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
     {
        HPEN hOldPen, hNewPen;
        HTREEITEM parent;
+        LOGBRUSH lb;
 
-       /*
-        * Get a dotted grey pen
-        */
-       hNewPen = CreatePen(PS_ALTERNATE, 0, infoPtr->clrLine);
+       /* Get a dotted grey pen */
+        lb.lbStyle = BS_SOLID;
+        lb.lbColor = GETLINECOLOR(infoPtr->clrLine);
+        hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
        hOldPen = SelectObject(hdc, hNewPen);
 
+        /* Make sure the center is on a dot (using +2 instead
+         * of +1 gives us pixel-by-pixel compat with native) */
+        centery = (centery + 2) & ~1;
+
        MoveToEx(hdc, item->stateOffset, centery, NULL);
        LineTo(hdc, centerx - 1, centery);
 
@@ -2384,16 +2415,20 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
                 LONG rectsize = min(height, width) / 4;
                 /* plussize = ceil(rectsize * 3/4) */
                 LONG plussize = (rectsize + 1) * 3 / 4;
-    
-                HPEN hNewPen  = CreatePen(PS_SOLID, 0, infoPtr->clrLine);
-                HPEN hOldPen  = SelectObject(hdc, hNewPen);
-    
+
+                HPEN new_pen  = CreatePen(PS_SOLID, 0, GETLINECOLOR(infoPtr->clrLine));
+                HPEN old_pen  = SelectObject(hdc, new_pen);
+
                 Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1,
                           centerx + rectsize + 2, centery + rectsize + 2);
-    
-                SelectObject(hdc, hOldPen);
-                DeleteObject(hNewPen);
-    
+
+                SelectObject(hdc, old_pen);
+                DeleteObject(new_pen);
+
+                /* draw +/- signs with current text color */
+                new_pen = CreatePen(PS_SOLID, 0, GETTXTCOLOR(infoPtr->clrText));
+                old_pen = SelectObject(hdc, new_pen);
+
                 if (height < 18 || width < 18)
                 {
                     MoveToEx(hdc, centerx - plussize + 1, centery, NULL);
@@ -2414,10 +2449,13 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
                     {
                         Rectangle(hdc, centerx - 1, centery - plussize + 1,
                         centerx + 2, centery + plussize);
-                        SetPixel(hdc, centerx - 1, centery, infoPtr->clrBk);
-                        SetPixel(hdc, centerx + 1, centery, infoPtr->clrBk);
+                        SetPixel(hdc, centerx - 1, centery, clrBk);
+                        SetPixel(hdc, centerx + 1, centery, clrBk);
                     }
                 }
+
+                SelectObject(hdc, old_pen);
+                DeleteObject(new_pen);
             }
        }
     }
@@ -2426,7 +2464,7 @@ TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item)
 }
 
 static void
-TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
+TREEVIEW_DrawItem(const TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
 {
     INT cditem;
     HFONT hOldFont;
@@ -2449,27 +2487,22 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
     {
        if ((wineItem->state & TVIS_DROPHILITED) || inFocus)
        {
-           nmcdhdr.clrTextBk = GetSysColor(COLOR_HIGHLIGHT);
-           nmcdhdr.clrText   = GetSysColor(COLOR_HIGHLIGHTTEXT);
+           nmcdhdr.clrTextBk = comctl32_color.clrHighlight;
+           nmcdhdr.clrText   = comctl32_color.clrHighlightText;
        }
        else
        {
-           nmcdhdr.clrTextBk = GetSysColor(COLOR_BTNFACE);
-           if (infoPtr->clrText == -1)
-               nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT);
-           else
-               nmcdhdr.clrText = infoPtr->clrText;
+           nmcdhdr.clrTextBk = comctl32_color.clrBtnFace;
+           nmcdhdr.clrText   = GETTXTCOLOR(infoPtr->clrText);
        }
     }
     else
     {
-       nmcdhdr.clrTextBk = infoPtr->clrBk;
+       nmcdhdr.clrTextBk = GETBKCOLOR(infoPtr->clrBk);
        if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (wineItem == infoPtr->hotItem))
            nmcdhdr.clrText = comctl32_color.clrHighlight;
-       else if (infoPtr->clrText == -1)
-           nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT);
        else
-           nmcdhdr.clrText = infoPtr->clrText;
+           nmcdhdr.clrText = GETTXTCOLOR(infoPtr->clrText);
     }
 
     hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem));
@@ -2568,9 +2601,8 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
            rcText.left = wineItem->textOffset;
            rcText.right = rcText.left + wineItem->textWidth + 4;
 
-           TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n",
-                 debugstr_w(wineItem->pszText),
-                 rcText.left, rcText.top, rcText.right, rcText.bottom);
+            TRACE("drawing text %s at (%s)\n",
+                  debugstr_w(wineItem->pszText), wine_dbgstr_rect(&rcText));
 
            /* Draw it */
            ExtTextOutW(hdc, rcText.left + 2, rcText.top + 1,
@@ -2602,7 +2634,7 @@ TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem)
        int offset;
        int left, right;
 
-       hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark);
+       hNewPen = CreatePen(PS_SOLID, 2, GETINSCOLOR(infoPtr->clrInsertMark));
        hOldPen = SelectObject(hdc, hNewPen);
 
        if (infoPtr->insertBeforeorAfter)
@@ -2691,7 +2723,7 @@ TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr)
            > infoPtr->clientWidth - GetSystemMetrics(SM_CXVSCROLL))
            horz = TRUE;
     }
-    else if (infoPtr->treeWidth > infoPtr->clientWidth)
+    else if (infoPtr->treeWidth > infoPtr->clientWidth || infoPtr->scrollX > 0)
        horz = TRUE;
 
     if (!vert && horz && infoPtr->treeHeight
@@ -2749,6 +2781,8 @@ TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr)
        infoPtr->uInternalStatus |= TV_HSCROLL;
 
        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
+       TREEVIEW_HScroll(infoPtr,
+                       MAKEWPARAM(SB_THUMBPOSITION, scrollX));
     }
     else
     {
@@ -2757,34 +2791,44 @@ TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr)
        infoPtr->uInternalStatus &= ~TV_HSCROLL;
 
        scrollX = 0;
-    }
-
-    if (infoPtr->scrollX != scrollX)
-    {
-       TREEVIEW_HScroll(infoPtr,
-                        MAKEWPARAM(SB_THUMBPOSITION, scrollX));
+        if (infoPtr->scrollX != 0)
+        {
+           TREEVIEW_HScroll(infoPtr,
+                           MAKEWPARAM(SB_THUMBPOSITION, scrollX));
+        }
     }
 
     if (!horz)
        infoPtr->uInternalStatus &= ~TV_HSCROLL;
 }
 
+static void
+TREEVIEW_FillBkgnd(const TREEVIEW_INFO *infoPtr, HDC hdc, const RECT *rc)
+{
+    HBRUSH hBrush;
+    COLORREF clrBk = GETBKCOLOR(infoPtr->clrBk);
+
+    hBrush =  CreateSolidBrush(clrBk);
+    FillRect(hdc, rc, hBrush);
+    DeleteObject(hBrush);
+}
+
 /* CtrlSpy doesn't mention this, but CorelDRAW's object manager needs it. */
 static LRESULT
-TREEVIEW_EraseBackground(TREEVIEW_INFO *infoPtr, HDC hDC)
+TREEVIEW_EraseBackground(const TREEVIEW_INFO *infoPtr, HDC hdc)
 {
-    HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
     RECT rect;
 
+    TRACE("%p\n", infoPtr);
+
     GetClientRect(infoPtr->hwnd, &rect);
-    FillRect(hDC, &rect, hBrush);
-    DeleteObject(hBrush);
+    TREEVIEW_FillBkgnd(infoPtr, hdc, &rect);
 
     return 1;
 }
 
 static void
-TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr, HDC hdc, RECT *rc)
+TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr, HDC hdc, const RECT *rc)
 {
     HWND hwnd = infoPtr->hwnd;
     RECT rect = *rc;
@@ -2821,22 +2865,35 @@ TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr, HDC hdc, RECT *rc)
        }
     }
 
+    //
+    // This is correct, but is causes and infinite loop of WM_PAINT messages, resulting
+    // in continuous painting of the scroll bar in reactos. Comment out until the real
+    // bug is found
+    // 
+    //TREEVIEW_UpdateScrollBars(infoPtr);
+
     if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT)
        infoPtr->cdmode =
            TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect);
 }
 
+static inline void
+TREEVIEW_InvalidateItem(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item)
+{
+    if (item) InvalidateRect(infoPtr->hwnd, &item->rect, TRUE);
+}
+
 static void
-TREEVIEW_Invalidate(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_Invalidate(const TREEVIEW_INFO *infoPtr, const TREEVIEW_ITEM *item)
 {
-    if (item != NULL)
+    if (item)
        InvalidateRect(infoPtr->hwnd, &item->rect, TRUE);
     else
         InvalidateRect(infoPtr->hwnd, NULL, TRUE);
 }
 
 static LRESULT
-TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, WPARAM wParam)
+TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, HDC hdc_ref)
 {
     HDC hdc;
     PAINTSTRUCT ps;
@@ -2844,27 +2901,48 @@ TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 
     TRACE("\n");
 
-    if (wParam)
+    if (hdc_ref)
     {
-        hdc = (HDC)wParam;
-        GetClientRect(infoPtr->hwnd, &rc);        
-        TREEVIEW_EraseBackground(infoPtr, hdc);
+        hdc = hdc_ref;
+        GetClientRect(infoPtr->hwnd, &rc);
     }
     else
     {
         hdc = BeginPaint(infoPtr->hwnd, &ps);
-        rc = ps.rcPaint;
+        rc  = ps.rcPaint;
+        if(ps.fErase)
+            TREEVIEW_FillBkgnd(infoPtr, hdc, &rc);
     }
 
     if(infoPtr->bRedraw) /* WM_SETREDRAW sets bRedraw */
         TREEVIEW_Refresh(infoPtr, hdc, &rc);
 
-    if (!wParam)
+    if (!hdc_ref)
        EndPaint(infoPtr->hwnd, &ps);
 
     return 0;
 }
 
+static LRESULT
+TREEVIEW_PrintClient(TREEVIEW_INFO *infoPtr, HDC hdc, DWORD options)
+{
+    FIXME("Partial Stub: (hdc=%p options=0x%08x)\n", hdc, options);
+
+    if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwnd))
+        return 0;
+
+    if (options & PRF_ERASEBKGND)
+        TREEVIEW_EraseBackground(infoPtr, hdc);
+
+    if (options & PRF_CLIENT)
+    {
+        RECT rc;
+        GetClientRect(infoPtr->hwnd, &rc);
+        TREEVIEW_Refresh(infoPtr, hdc, &rc);
+    }
+
+    return 0;
+}
 
 /* Sorting **************************************************************/
 
@@ -2872,7 +2950,8 @@ TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, WPARAM wParam)
  * Forward the DPA local callback to the treeview owner callback
  */
 static INT WINAPI
-TREEVIEW_CallBackCompare(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, LPTVSORTCB pCallBackSort)
+TREEVIEW_CallBackCompare(const TREEVIEW_ITEM *first, const TREEVIEW_ITEM *second,
+                         const TVSORTCB *pCallBackSort)
 {
     /* Forward the call to the client-defined callback */
     return pCallBackSort->lpfnCompare(first->lParam,
@@ -2885,7 +2964,7 @@ TREEVIEW_CallBackCompare(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, LPTVSORTCB
  */
 static INT WINAPI
 TREEVIEW_SortOnName(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second,
-                     TREEVIEW_INFO *infoPtr)
+                    const TREEVIEW_INFO *infoPtr)
 {
     TREEVIEW_UpdateDispInfo(infoPtr, first, TVIF_TEXT);
     TREEVIEW_UpdateDispInfo(infoPtr, second, TVIF_TEXT);
@@ -2902,7 +2981,7 @@ TREEVIEW_SortOnName(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second,
 
 /* Returns the number of physical children belonging to item. */
 static INT
-TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_CountChildren(const TREEVIEW_ITEM *item)
 {
     INT cChildren = 0;
     HTREEITEM hti;
@@ -2916,7 +2995,7 @@ TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 /* Returns a DPA containing a pointer to each physical child of item in
  * sibling order. If item has no children, an empty DPA is returned. */
 static HDPA
-TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
+TREEVIEW_BuildChildDPA(const TREEVIEW_ITEM *item)
 {
     HTREEITEM child = item->firstChild;
 
@@ -2947,7 +3026,7 @@ TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
  */
 
 static LRESULT
-TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent,
+TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, HTREEITEM parent,
              LPTVSORTCB pSort)
 {
     INT cChildren;
@@ -2976,7 +3055,7 @@ TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent,
        lpCompare = (LPARAM)infoPtr;
     }
 
-    cChildren = TREEVIEW_CountChildren(infoPtr, parent);
+    cChildren = TREEVIEW_CountChildren(parent);
 
     /* Make sure there is something to sort */
     if (cChildren > 1)
@@ -2987,7 +3066,7 @@ TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent,
        HTREEITEM nextItem = 0;
        HTREEITEM prevItem = 0;
 
-       HDPA sortList = TREEVIEW_BuildChildDPA(infoPtr, parent);
+       HDPA sortList = TREEVIEW_BuildChildDPA(parent);
 
        if (sortList == NULL)
            return FALSE;
@@ -2998,10 +3077,10 @@ TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent,
        /* The order of DPA entries has been changed, so fixup the
         * nextSibling and prevSibling pointers. */
 
-       item = (HTREEITEM)DPA_GetPtr(sortList, count++);
-       while ((nextItem = (HTREEITEM)DPA_GetPtr(sortList, count++)) != NULL)
+        item = DPA_GetPtr(sortList, count++);
+        while ((nextItem = DPA_GetPtr(sortList, count++)) != NULL)
        {
-           /* link the two current item toghether */
+           /* link the two current item together */
            item->nextSibling = nextItem;
            nextItem->prevSibling = item;
 
@@ -3068,9 +3147,9 @@ TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent,
  * and sort the children of the TV item specified in lParam
  */
 static LRESULT
-TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPTVSORTCB pSort)
+TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, LPTVSORTCB pSort)
 {
-    return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort);
+    return TREEVIEW_Sort(infoPtr, pSort->hParent, pSort);
 }
 
 
@@ -3078,16 +3157,16 @@ TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPTVSORTCB pSort)
  * Sort the children of the TV item specified in lParam.
  */
 static LRESULT
-TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, LPARAM lParam)
 {
-    return TREEVIEW_Sort(infoPtr, (BOOL)wParam, (HTREEITEM)lParam, NULL);
+    return TREEVIEW_Sort(infoPtr, (HTREEITEM)lParam, NULL);
 }
 
 
 /* Expansion/Collapse ***************************************************/
 
 static BOOL
-TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
+TREEVIEW_SendExpanding(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                       UINT action)
 {
     return !TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDINGW, action,
@@ -3097,7 +3176,7 @@ TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
 }
 
 static VOID
-TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
+TREEVIEW_SendExpanded(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
                      UINT action)
 {
     TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDEDW, action,
@@ -3201,7 +3280,7 @@ TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
     {
         scrollRect.top = nextItem->rect.top;
 
-        ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL,
+        ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, &scrollRect,
                        NULL, NULL, SW_ERASE | SW_INVALIDATE);
         TREEVIEW_Invalidate(infoPtr, wineItem);
     } else {
@@ -3274,58 +3353,60 @@ TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem,
     if (bExpandPartial)
        FIXME("TVE_EXPANDPARTIAL not implemented\n");
 
-    TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem);
-    TREEVIEW_UpdateSubTree(infoPtr, wineItem);
-    TREEVIEW_UpdateScrollBars(infoPtr);
-
-    scrollRect.left = 0;
-    scrollRect.bottom = infoPtr->treeHeight;
-    scrollRect.right = infoPtr->clientWidth;
-    if (nextItem)
+    if (ISVISIBLE(wineItem))
     {
-        scrollDist = nextItem->rect.top - orgNextTop;
-        scrollRect.top = orgNextTop;
+        TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem);
+        TREEVIEW_UpdateSubTree(infoPtr, wineItem);
+        TREEVIEW_UpdateScrollBars(infoPtr);
 
-        ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL,
-                       NULL, NULL, SW_ERASE | SW_INVALIDATE);
-        TREEVIEW_Invalidate (infoPtr, wineItem);
-    } else {
-        scrollRect.top = wineItem->rect.top;
-        InvalidateRect(infoPtr->hwnd, &scrollRect, FALSE);
-    }
+        scrollRect.left = 0;
+        scrollRect.bottom = infoPtr->treeHeight;
+        scrollRect.right = infoPtr->clientWidth;
+        if (nextItem)
+        {
+            scrollDist = nextItem->rect.top - orgNextTop;
+            scrollRect.top = orgNextTop;
+
+            ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL,
+                        NULL, NULL, SW_ERASE | SW_INVALIDATE);
+            TREEVIEW_Invalidate (infoPtr, wineItem);
+        } else {
+            scrollRect.top = wineItem->rect.top;
+            InvalidateRect(infoPtr->hwnd, &scrollRect, FALSE);
+        }
 
-    /* Scroll up so that as many children as possible are visible.
-     * This fails when expanding causes an HScroll bar to appear, but we
-     * don't know that yet, so the last item is obscured. */
-    if (wineItem->firstChild != NULL)
-    {
-       int nChildren = wineItem->lastChild->visibleOrder
-           - wineItem->firstChild->visibleOrder + 1;
+        /* Scroll up so that as many children as possible are visible.
+        * This fails when expanding causes an HScroll bar to appear, but we
+        * don't know that yet, so the last item is obscured. */
+        if (wineItem->firstChild != NULL)
+        {
+            int nChildren = wineItem->lastChild->visibleOrder
+                - wineItem->firstChild->visibleOrder + 1;
 
-       int visible_pos = wineItem->visibleOrder
-           - infoPtr->firstVisible->visibleOrder;
+            int visible_pos = wineItem->visibleOrder
+                - infoPtr->firstVisible->visibleOrder;
 
-       int rows_below = TREEVIEW_GetVisibleCount(infoPtr) - visible_pos - 1;
+            int rows_below = TREEVIEW_GetVisibleCount(infoPtr) - visible_pos - 1;
 
-       if (visible_pos > 0 && nChildren > rows_below)
-       {
-           int scroll = nChildren - rows_below;
+            if (visible_pos > 0 && nChildren > rows_below)
+            {
+                int scroll = nChildren - rows_below;
 
-           if (scroll > visible_pos)
-               scroll = visible_pos;
+                if (scroll > visible_pos)
+                    scroll = visible_pos;
 
-           if (scroll > 0)
-           {
-               TREEVIEW_ITEM *newFirstVisible
-                   = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible,
-                                          scroll);
+                if (scroll > 0)
+                {
+                    TREEVIEW_ITEM *newFirstVisible
+                        = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible,
+                                            scroll);
 
 
-               TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE);
-           }
-       }
+                    TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE);
+                }
+            }
+        }
     }
-    TREEVIEW_UpdateScrollBars(infoPtr);
 
     return TRUE;
 }
@@ -3394,7 +3475,7 @@ TREEVIEW_ExpandMsg(TREEVIEW_INFO *infoPtr, UINT flag, HTREEITEM wineItem)
 /* Hit-Testing **********************************************************/
 
 static TREEVIEW_ITEM *
-TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr, POINT pt)
+TREEVIEW_HitTestPoint(const TREEVIEW_INFO *infoPtr, POINT pt)
 {
     TREEVIEW_ITEM *wineItem;
     LONG row;
@@ -3416,7 +3497,7 @@ TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr, POINT pt)
 }
 
 static LRESULT
-TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht)
+TREEVIEW_HitTest(const TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht)
 {
     TREEVIEW_ITEM *wineItem;
     RECT rect;
@@ -3450,14 +3531,14 @@ TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht)
     if (status)
     {
        lpht->flags = status;
-       return (LRESULT)(HTREEITEM)NULL;
+        return 0;
     }
 
     wineItem = TREEVIEW_HitTestPoint(infoPtr, lpht->pt);
     if (!wineItem)
     {
        lpht->flags = TVHT_NOWHERE;
-       return (LRESULT)(HTREEITEM)NULL;
+        return 0;
     }
 
     if (x >= wineItem->textOffset + wineItem->textWidth)
@@ -3486,7 +3567,7 @@ TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht)
     }
 
     lpht->hItem = wineItem;
-    TRACE("(%ld,%ld):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags);
+    TRACE("(%d,%d):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags);
 
     return (LRESULT)wineItem;
 }
@@ -3494,7 +3575,7 @@ TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht)
 /* Item Label Editing ***************************************************/
 
 static LRESULT
-TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr)
+TREEVIEW_GetEditControl(const TREEVIEW_INFO *infoPtr)
 {
     return (LRESULT)infoPtr->hwndEdit;
 }
@@ -3520,16 +3601,24 @@ TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            return TRUE;
        break;
 
+    case WM_DESTROY:
+    {
+       WNDPROC editProc = infoPtr->wpEditOrig;
+       infoPtr->wpEditOrig = 0;
+       SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
+       return CallWindowProcW(editProc, hwnd, uMsg, wParam, lParam);
+    }
+
     case WM_GETDLGCODE:
        return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
 
     case WM_KEYDOWN:
-       if (wParam == (WPARAM)VK_ESCAPE)
+       if (wParam == VK_ESCAPE)
        {
            bCancel = TRUE;
            break;
        }
-       else if (wParam == (WPARAM)VK_RETURN)
+       else if (wParam == VK_RETURN)
        {
            break;
        }
@@ -3555,7 +3644,7 @@ TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 static LRESULT
 TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
-    TRACE("%x %ld\n", wParam, lParam);
+    TRACE("code=%x, id=%x, handle=%lx\n", HIWORD(wParam), LOWORD(wParam), lParam);
 
     switch (HIWORD(wParam))
     {
@@ -3565,15 +3654,18 @@ TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
             * Adjust the edit window size
             */
            WCHAR buffer[1024];
-           TREEVIEW_ITEM *editItem = infoPtr->selectedItem;
+           TREEVIEW_ITEM *editItem = infoPtr->editItem;
            HDC hdc = GetDC(infoPtr->hwndEdit);
            SIZE sz;
-           int len;
            HFONT hFont, hOldFont = 0;
 
+           TRACE("edit=%p\n", infoPtr->hwndEdit);
+
+           if (!IsWindow(infoPtr->hwndEdit) || !hdc) return FALSE;
+
            infoPtr->bLabelChanged = TRUE;
 
-           len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer));
+           GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)/sizeof(buffer[0]));
 
            /* Select font to get the right dimension of the string */
            hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0);
@@ -3612,6 +3704,12 @@ TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
            ReleaseDC(infoPtr->hwnd, hdc);
            break;
        }
+    case EN_KILLFOCUS:
+       /* apparently we should respect passed handle value */
+       if (infoPtr->hwndEdit != (HWND)lParam) return FALSE;
+
+       TREEVIEW_EndEditLabelNow(infoPtr, FALSE);
+       break;
 
     default:
        return SendMessageW(infoPtr->hwndNotify, WM_COMMAND, wParam, lParam);
@@ -3626,15 +3724,13 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
     HWND hwnd = infoPtr->hwnd;
     HWND hwndEdit;
     SIZE sz;
-    TREEVIEW_ITEM *editItem = hItem;
     HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE);
     HDC hdc;
     HFONT hOldFont=0;
     TEXTMETRICW textMetric;
-    static const WCHAR EditW[] = {'E','d','i','t',0};
 
     TRACE("%p %p\n", hwnd, hItem);
-    if (!TREEVIEW_ValidItem(infoPtr, editItem))
+    if (!TREEVIEW_ValidItem(infoPtr, hItem))
        return NULL;
 
     if (infoPtr->hwndEdit)
@@ -3642,11 +3738,10 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
 
     infoPtr->bLabelChanged = FALSE;
 
-    /* Make sure that edit item is selected */
-    TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, hItem, TVC_UNKNOWN);
+    /* make edit item visible */
     TREEVIEW_EnsureVisible(infoPtr, hItem, TRUE);
 
-    TREEVIEW_UpdateDispInfo(infoPtr, editItem, TVIF_TEXT);
+    TREEVIEW_UpdateDispInfo(infoPtr, hItem, TVIF_TEXT);
 
     hdc = GetDC(hwnd);
     /* Select the font to get appropriate metric dimensions */
@@ -3656,15 +3751,18 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
     }
 
     /* Get string length in pixels */
-    GetTextExtentPoint32W(hdc, editItem->pszText, strlenW(editItem->pszText),
-                         &sz);
+    if (hItem->pszText)
+        GetTextExtentPoint32W(hdc, hItem->pszText, strlenW(hItem->pszText),
+                        &sz);
+    else
+        GetTextExtentPoint32A(hdc, "", 0, &sz);
 
     /* Add Extra spacing for the next character */
     GetTextMetricsW(hdc, &textMetric);
     sz.cx += (textMetric.tmMaxCharWidth * 2);
 
     sz.cx = max(sz.cx, textMetric.tmMaxCharWidth * 3);
-    sz.cx = min(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2);
+    sz.cx = min(sz.cx, infoPtr->clientWidth - hItem->textOffset + 2);
 
     if (infoPtr->hFont != 0)
     {
@@ -3672,15 +3770,18 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
     }
 
     ReleaseDC(hwnd, hdc);
+
+    infoPtr->editItem = hItem;
+
     hwndEdit = CreateWindowExW(WS_EX_LEFT,
-                              EditW,
+                              WC_EDITW,
                               0,
                               WS_CHILD | WS_BORDER | ES_AUTOHSCROLL |
                               WS_CLIPSIBLINGS | ES_WANTRETURN |
-                              ES_LEFT, editItem->textOffset - 2,
-                              editItem->rect.top - 1, sz.cx + 3,
-                              editItem->rect.bottom -
-                              editItem->rect.top + 3, hwnd, 0, hinst, 0);
+                              ES_LEFT, hItem->textOffset - 2,
+                              hItem->rect.top - 1, sz.cx + 3,
+                              hItem->rect.bottom -
+                              hItem->rect.top + 3, hwnd, 0, hinst, 0);
 /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0); */
 
     infoPtr->hwndEdit = hwndEdit;
@@ -3692,21 +3793,23 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
                   GetWindowLongW(hwndEdit, GWL_STYLE) | WS_BORDER);
 
     SendMessageW(hwndEdit, WM_SETFONT,
-                (WPARAM)TREEVIEW_FontForItem(infoPtr, editItem), FALSE);
+                (WPARAM)TREEVIEW_FontForItem(infoPtr, hItem), FALSE);
 
     infoPtr->wpEditOrig = (WNDPROC)SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC,
                                                  (DWORD_PTR)
                                                  TREEVIEW_Edit_SubclassProc);
 
-    if (TREEVIEW_BeginLabelEditNotify(infoPtr, editItem))
+    if (TREEVIEW_BeginLabelEditNotify(infoPtr, hItem))
     {
        DestroyWindow(hwndEdit);
        infoPtr->hwndEdit = 0;
+       infoPtr->editItem = NULL;
        return NULL;
     }
 
-    infoPtr->selectedItem = hItem;
-    SetWindowTextW(hwndEdit, editItem->pszText);
+    if (hItem->pszText)
+        SetWindowTextW(hwndEdit, hItem->pszText);
+
     SetFocus(hwndEdit);
     SendMessageW(hwndEdit, EM_SETSEL, 0, -1);
     ShowWindow(hwndEdit, SW_SHOW);
@@ -3719,15 +3822,14 @@ static LRESULT
 TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel)
 {
     HWND hwnd = infoPtr->hwnd;
-    TREEVIEW_ITEM *editedItem = infoPtr->selectedItem;
+    TREEVIEW_ITEM *editedItem = infoPtr->editItem;
     NMTVDISPINFOW tvdi;
     BOOL bCommit;
     WCHAR tmpText[1024] = { '\0' };
     WCHAR *newText = tmpText;
     int iLength = 0;
 
-    if (!infoPtr->hwndEdit)
-       return FALSE;
+    if (!IsWindow(infoPtr->hwndEdit)) return FALSE;
 
     tvdi.hdr.hwndFrom = hwnd;
     tvdi.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID);
@@ -3759,8 +3861,7 @@ TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel)
        tvdi.item.cchTextMax = 0;
     }
 
-    bCommit = (BOOL)TREEVIEW_SendRealNotify(infoPtr,
-                                (WPARAM)tvdi.hdr.idFrom, (LPARAM)&tvdi);
+    bCommit = (BOOL)TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, (LPARAM)&tvdi);
 
     if (!bCancel && bCommit)   /* Apply the changes */
     {
@@ -3774,17 +3875,22 @@ TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel)
 
         if (strcmpW(newText, editedItem->pszText) != 0)
         {
-            if (NULL == ReAlloc(editedItem->pszText, iLength + 1))
+            WCHAR *ptr = ReAlloc(editedItem->pszText, sizeof(WCHAR)*(iLength + 1));
+            if (ptr == NULL)
             {
                 ERR("OutOfMemory, cannot allocate space for label\n");
+                if(newText != tmpText) Free(newText);
                 DestroyWindow(infoPtr->hwndEdit);
                 infoPtr->hwndEdit = 0;
+                infoPtr->editItem = NULL;
                 return FALSE;
             }
             else
             {
+                editedItem->pszText = ptr;
                 editedItem->cchTextMax = iLength + 1;
                 strcpyW(editedItem->pszText, newText);
+                TREEVIEW_ComputeTextWidth(infoPtr, editedItem, 0);
             }
         }
         if(newText != tmpText) Free(newText);
@@ -3793,6 +3899,7 @@ TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel)
     ShowWindow(infoPtr->hwndEdit, SW_HIDE);
     DestroyWindow(infoPtr->hwndEdit);
     infoPtr->hwndEdit = 0;
+    infoPtr->editItem = NULL;
     return TRUE;
 }
 
@@ -3821,7 +3928,7 @@ TREEVIEW_HandleTimer(TREEVIEW_INFO *infoPtr, WPARAM wParam)
  * Windows.
  */
 static LRESULT
-TREEVIEW_TrackMouse(TREEVIEW_INFO *infoPtr, POINT pt)
+TREEVIEW_TrackMouse(const TREEVIEW_INFO *infoPtr, POINT pt)
 {
     INT cxDrag = GetSystemMetrics(SM_CXDRAG);
     INT cyDrag = GetSystemMetrics(SM_CYDRAG);
@@ -3944,7 +4051,6 @@ TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam)
     HWND hwnd = infoPtr->hwnd;
     TVHITTESTINFO ht;
     BOOL bTrack, bDoLabelEdit;
-    HTREEITEM tempItem;
 
     /* If Edit control is active - kill it and return.
      * The best way to do it is to set focus to itself.
@@ -3967,10 +4073,8 @@ TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam)
     if(ht.hItem && (ht.flags & TVHT_ONITEM))
     {
         infoPtr->focusedItem = ht.hItem;
-        InvalidateRect(hwnd, &(((HTREEITEM)(ht.hItem))->rect), TRUE);
-
-        if(infoPtr->selectedItem)
-            InvalidateRect(hwnd, &(infoPtr->selectedItem->rect), TRUE);
+        TREEVIEW_InvalidateItem(infoPtr, infoPtr->focusedItem);
+        TREEVIEW_InvalidateItem(infoPtr, infoPtr->selectedItem);
     }
 
     bTrack = (ht.flags & TVHT_ONITEM)
@@ -4004,12 +4108,11 @@ TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam)
             if(infoPtr->focusedItem)
             {
                 /* refresh the item that was focused */
-                tempItem = infoPtr->focusedItem;
-                infoPtr->focusedItem = 0;
-                InvalidateRect(infoPtr->hwnd, &tempItem->rect, TRUE);
+                TREEVIEW_InvalidateItem(infoPtr, infoPtr->focusedItem);
+                infoPtr->focusedItem = NULL;
 
                 /* refresh the selected item to return the filled background */
-                InvalidateRect(infoPtr->hwnd, &(infoPtr->selectedItem->rect), TRUE);
+                TREEVIEW_InvalidateItem(infoPtr, infoPtr->selectedItem);
             }
 
            return 0;
@@ -4129,14 +4232,29 @@ TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam)
 }
 
 static LRESULT
-TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt)
+TREEVIEW_RButtonUp(const TREEVIEW_INFO *infoPtr, const POINT *pPt)
 {
+    TVHITTESTINFO ht;
+
+    ht.pt = *pPt;
+
+    TREEVIEW_HitTest(infoPtr, &ht);
+
+    if (ht.hItem)
+    {
+        /* Change to screen coordinate for WM_CONTEXTMENU */
+        ClientToScreen(infoPtr->hwnd, &ht.pt);
+
+        /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
+        SendMessageW(infoPtr->hwnd, WM_CONTEXTMENU,
+            (WPARAM)infoPtr->hwnd, MAKELPARAM(ht.pt.x, ht.pt.y));
+    }
     return 0;
 }
 
 
 static LRESULT
-TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, LPARAM lParam)
 {
     TREEVIEW_ITEM *dragItem = (HTREEITEM)lParam;
     INT cx, cy;
@@ -4162,10 +4280,14 @@ TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     hdc = CreateCompatibleDC(htopdc);
 
     hOldFont = SelectObject(hdc, infoPtr->hFont);
-    GetTextExtentPoint32W(hdc, dragItem->pszText, strlenW(dragItem->pszText),
+
+    if (dragItem->pszText)
+        GetTextExtentPoint32W(hdc, dragItem->pszText, strlenW(dragItem->pszText),
                          &size);
-    TRACE("%ld %ld %s %d\n", size.cx, size.cy, debugstr_w(dragItem->pszText),
-         strlenW(dragItem->pszText));
+    else
+        GetTextExtentPoint32A(hdc, "", 0, &size);
+
+    TRACE("%d %d %s\n", size.cx, size.cy, debugstr_w(dragItem->pszText));
     hbmp = CreateCompatibleBitmap(htopdc, size.cx, size.cy);
     hOldbmp = SelectObject(hdc, hbmp);
 
@@ -4186,8 +4308,11 @@ TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 /* draw item text */
 
     SetRect(&rc, cx, 0, size.cx, size.cy);
-    DrawTextW(hdc, dragItem->pszText, strlenW(dragItem->pszText), &rc,
-             DT_LEFT);
+
+    if (dragItem->pszText)
+        DrawTextW(hdc, dragItem->pszText, strlenW(dragItem->pszText), &rc,
+                  DT_LEFT);
+
     SelectObject(hdc, hOldFont);
     SelectObject(hdc, hOldbmp);
 
@@ -4207,7 +4332,6 @@ TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect,
                      INT cause)
 {
     TREEVIEW_ITEM *prevSelect;
-    RECT rcFocused;
 
     assert(newSelect == NULL || TREEVIEW_ValidItem(infoPtr, newSelect));
 
@@ -4217,12 +4341,8 @@ TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect,
 
     /* reset and redraw focusedItem if focusedItem was set so we don't */
     /* have to worry about the previously focused item when we set a new one */
-    if(infoPtr->focusedItem)
-    {
-        rcFocused = (infoPtr->focusedItem)->rect;
-        infoPtr->focusedItem = 0;
-        InvalidateRect(infoPtr->hwnd, &rcFocused, TRUE);
-    }
+    TREEVIEW_InvalidateItem(infoPtr, infoPtr->focusedItem);
+    infoPtr->focusedItem = NULL;
 
     switch (action)
     {
@@ -4237,7 +4357,7 @@ TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect,
        if (TREEVIEW_SendTreeviewNotify(infoPtr,
                                        TVN_SELCHANGINGW,
                                        cause,
-                                       TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,
+                                       TVIF_TEXT | TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,
                                        prevSelect,
                                        newSelect))
            return FALSE;
@@ -4251,15 +4371,13 @@ TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect,
 
        TREEVIEW_EnsureVisible(infoPtr, infoPtr->selectedItem, FALSE);
 
-       if (prevSelect)
-           TREEVIEW_Invalidate(infoPtr, prevSelect);
-       if (newSelect)
-           TREEVIEW_Invalidate(infoPtr, newSelect);
+        TREEVIEW_InvalidateItem(infoPtr, prevSelect);
+        TREEVIEW_InvalidateItem(infoPtr, newSelect);
 
        TREEVIEW_SendTreeviewNotify(infoPtr,
                                    TVN_SELCHANGEDW,
                                    cause,
-                                   TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,
+                                   TVIF_TEXT | TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,
                                    prevSelect,
                                    newSelect);
        break;
@@ -4334,7 +4452,7 @@ TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item)
  * BUGS
  *
  *  - The current implementation has a list of characters it will
- *    accept and it ignores averything else. In particular it will
+ *    accept and it ignores everything else. In particular it will
  *    ignore accentuated characters which seems to match what
  *    Windows does. But I'm not sure it makes sense to follow
  *    Windows there.
@@ -4347,13 +4465,8 @@ TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item)
  *
  *  TREEVIEW_ProcessLetterKeys
  */
-static INT TREEVIEW_ProcessLetterKeys(
-    HWND hwnd, /* handle to the window */
-    WPARAM charCode, /* the character code, the actual character */
-    LPARAM keyData /* key data */
-    )
+static INT TREEVIEW_ProcessLetterKeys(TREEVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData)
 {
-    TREEVIEW_INFO *infoPtr;
     HTREEITEM nItem;
     HTREEITEM endidx,idx;
     TVITEMEXW item;
@@ -4361,12 +4474,7 @@ static INT TREEVIEW_ProcessLetterKeys(
     DWORD timestamp,elapsed;
 
     /* simple parameter checking */
-    if (!hwnd || !charCode || !keyData)
-        return 0;
-
-    infoPtr=(TREEVIEW_INFO*)GetWindowLongPtrW(hwnd, 0);
-    if (!infoPtr)
-        return 0;
+    if (!charCode || !keyData) return 0;
 
     /* only allow the valid WM_CHARs through */
     if (!isalnum(charCode) &&
@@ -4484,7 +4592,7 @@ TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr, HTREEITEM item, BOOL bHScroll)
        /* Expand parents as necessary. */
        HTREEITEM parent;
 
-        /* see if we are trying to ensure that root is vislble */
+        /* see if we are trying to ensure that root is visible */
         if((item != infoPtr->root) && TREEVIEW_ValidItem(infoPtr, item))
           parent = item->parent;
         else
@@ -4501,7 +4609,7 @@ TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr, HTREEITEM item, BOOL bHScroll)
 
     viscount = TREEVIEW_GetVisibleCount(infoPtr);
 
-    TRACE("%p (%s) %ld - %ld viscount(%d)\n", item, TREEVIEW_ItemName(item), item->visibleOrder,
+    TRACE("%p (%s) %d - %d viscount(%d)\n", item, TREEVIEW_ItemName(item), item->visibleOrder,
         hasFirstVisible ? infoPtr->firstVisible->visibleOrder : -1, viscount);
 
     if (hasFirstVisible)
@@ -4636,14 +4744,11 @@ TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 
     int nScrollCode = LOWORD(wParam);
 
-    TRACE("wp %x\n", wParam);
+    TRACE("wp %lx\n", wParam);
 
     if (!(infoPtr->uInternalStatus & TV_VSCROLL))
        return 0;
 
-    if (infoPtr->hwndEdit)
-       SetFocus(infoPtr->hwnd);
-
     if (!oldFirstVisible)
     {
        assert(infoPtr->root->firstChild == NULL);
@@ -4709,14 +4814,11 @@ TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam)
     int scrollX = infoPtr->scrollX;
     int nScrollCode = LOWORD(wParam);
 
-    TRACE("wp %x\n", wParam);
+    TRACE("wp %lx\n", wParam);
 
     if (!(infoPtr->uInternalStatus & TV_HSCROLL))
        return FALSE;
 
-    if (infoPtr->hwndEdit)
-       SetFocus(infoPtr->hwnd);
-
     maxWidth = infoPtr->treeWidth - infoPtr->clientWidth;
     /* shall never occur */
     if (maxWidth <= 0)
@@ -4781,11 +4883,14 @@ scroll:
 }
 
 static LRESULT
-TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam)
+TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     short gcWheelDelta;
     UINT pulScrollLines = 3;
 
+    if (wParam & (MK_SHIFT | MK_CONTROL))
+        return DefWindowProcW(infoPtr->hwnd, WM_MOUSEWHEEL, wParam, lParam);
+
     if (infoPtr->firstVisible == NULL)
        return TRUE;
 
@@ -4812,17 +4917,56 @@ TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 
 /* Create/Destroy *******************************************************/
 
+static void
+initialize_checkboxes(TREEVIEW_INFO *infoPtr)
+{
+    RECT rc;
+    HBITMAP hbm, hbmOld;
+    HDC hdc, hdcScreen;
+    int nIndex;
+
+    infoPtr->himlState = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 3, 0);
+
+    hdcScreen = GetDC(0);
+
+    hdc = CreateCompatibleDC(hdcScreen);
+    hbm = CreateCompatibleBitmap(hdcScreen, 48, 16);
+    hbmOld = SelectObject(hdc, hbm);
+
+    SetRect(&rc, 0, 0, 48, 16);
+    FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
+
+    SetRect(&rc, 18, 2, 30, 14);
+    DrawFrameControl(hdc, &rc, DFC_BUTTON,
+                     DFCS_BUTTONCHECK|DFCS_FLAT);
+
+    SetRect(&rc, 34, 2, 46, 14);
+    DrawFrameControl(hdc, &rc, DFC_BUTTON,
+                     DFCS_BUTTONCHECK|DFCS_FLAT|DFCS_CHECKED);
+
+    SelectObject(hdc, hbmOld);
+    nIndex = ImageList_AddMasked(infoPtr->himlState, hbm,
+                                 comctl32_color.clrWindow);
+    TRACE("checkbox index %d\n", nIndex);
+
+    DeleteObject(hbm);
+    DeleteDC(hdc);
+    ReleaseDC(0, hdcScreen);
+
+    infoPtr->stateImageWidth = 16;
+    infoPtr->stateImageHeight = 16;
+}
+
 static LRESULT
 TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
 {
-    static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' };
     RECT rcClient;
     TREEVIEW_INFO *infoPtr;
     LOGFONTW lf;
 
-    TRACE("wnd %p, style %lx\n", hwnd, GetWindowLongW(hwnd, GWL_STYLE));
+    TRACE("wnd %p, style %x\n", hwnd, GetWindowLongW(hwnd, GWL_STYLE));
 
-    infoPtr = (TREEVIEW_INFO *)Alloc(sizeof(TREEVIEW_INFO));
+    infoPtr = Alloc(sizeof(TREEVIEW_INFO));
 
     if (infoPtr == NULL)
     {
@@ -4851,26 +4995,27 @@ TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
     infoPtr->treeHeight = 0;
 
     infoPtr->uIndent = MINIMUM_INDENT;
-    infoPtr->selectedItem = 0;
-    infoPtr->focusedItem = 0;
-    infoPtr->hotItem = 0;
-    infoPtr->firstVisible = 0;
+    infoPtr->selectedItem = NULL;
+    infoPtr->focusedItem = NULL;
+    infoPtr->hotItem = NULL;
+    infoPtr->editItem = NULL;
+    infoPtr->firstVisible = NULL;
     infoPtr->maxVisibleOrder = 0;
-    infoPtr->dropItem = 0;
-    infoPtr->insertMarkItem = 0;
+    infoPtr->dropItem = NULL;
+    infoPtr->insertMarkItem = NULL;
     infoPtr->insertBeforeorAfter = 0;
     /* dragList */
 
     infoPtr->scrollX = 0;
 
-    infoPtr->clrBk = GetSysColor(COLOR_WINDOW);
-    infoPtr->clrText = -1;     /* use system color */
-    infoPtr->clrLine = RGB(128, 128, 128);
-    infoPtr->clrInsertMark = GetSysColor(COLOR_BTNTEXT);
+    infoPtr->clrBk   = CLR_NONE; /* use system color */
+    infoPtr->clrText = CLR_NONE; /* use system color */
+    infoPtr->clrLine = CLR_DEFAULT;
+    infoPtr->clrInsertMark = CLR_DEFAULT;
 
     /* hwndToolTip */
 
-    infoPtr->hwndEdit = 0;
+    infoPtr->hwndEdit = NULL;
     infoPtr->wpEditOrig = NULL;
     infoPtr->bIgnoreEditKillFocus = FALSE;
     infoPtr->bLabelChanged = FALSE;
@@ -4911,51 +5056,12 @@ TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
     TREEVIEW_NotifyFormat(infoPtr, infoPtr->hwndNotify, NF_REQUERY);
 
     if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS))
-       infoPtr->hwndToolTip = COMCTL32_CreateToolTip(hwnd);
+        infoPtr->hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
+            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+            hwnd, 0, 0, 0);
 
     if (infoPtr->dwStyle & TVS_CHECKBOXES)
-    {
-       RECT rc;
-       HBITMAP hbm, hbmOld;
-       HDC hdc,hdcScreen;
-       int nIndex;
-
-       infoPtr->himlState =
-           ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 3, 0);
-
-       hdcScreen = CreateDCW(szDisplayW, NULL, NULL, NULL);
-
-       /* Create a coloured bitmap compatible with the screen depth
-          because checkboxes are not black&white */
-       hdc = CreateCompatibleDC(hdcScreen);
-       hbm = CreateCompatibleBitmap(hdcScreen, 48, 16);
-       hbmOld = SelectObject(hdc, hbm);
-
-       rc.left  = 0;   rc.top    = 0;
-       rc.right = 48;  rc.bottom = 16;
-       FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
-
-       rc.left  = 18;   rc.top    = 2;
-       rc.right = 30;   rc.bottom = 14;
-       DrawFrameControl(hdc, &rc, DFC_BUTTON,
-                         DFCS_BUTTONCHECK|DFCS_FLAT);
-
-       rc.left  = 34;   rc.right  = 46;
-       DrawFrameControl(hdc, &rc, DFC_BUTTON,
-                         DFCS_BUTTONCHECK|DFCS_FLAT|DFCS_CHECKED);
-
-       SelectObject(hdc, hbmOld);
-       nIndex = ImageList_AddMasked(infoPtr->himlState, hbm,
-                                     GetSysColor(COLOR_WINDOW));
-       TRACE("checkbox index %d\n", nIndex);
-
-       DeleteObject(hbm);
-       DeleteDC(hdc);
-       DeleteDC(hdcScreen);
-
-       infoPtr->stateImageWidth = 16;
-       infoPtr->stateImageHeight = 16;
-    }
+        initialize_checkboxes(infoPtr);
 
     /* Make sure actual scrollbar state is consistent with uInternalStatus */
     ShowScrollBar(hwnd, SB_VERT, FALSE);
@@ -4972,7 +5078,11 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
 
+    /* free item data */
     TREEVIEW_RemoveTree(infoPtr);
+    /* root isn't freed with other items */
+    TREEVIEW_FreeItem(infoPtr, infoPtr->root);
+    DPA_Destroy(infoPtr->items);
 
     /* tool tip is automatically destroyed: we are its owner */
 
@@ -4984,7 +5094,7 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr)
     CloseThemeData (GetWindowTheme (infoPtr->hwnd));
 
     /* Deassociate treeview from the window before doing anything drastic. */
-    SetWindowLongPtrW(infoPtr->hwnd, 0, (DWORD_PTR)NULL);
+    SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
 
 
     DeleteObject(infoPtr->hDefaultFont);
@@ -5055,7 +5165,7 @@ TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 
     TREEVIEW_ITEM *prevItem = infoPtr->selectedItem;
 
-    TRACE("%x\n", wParam);
+    TRACE("%lx\n", wParam);
 
     if (prevItem == NULL)
        return FALSE;
@@ -5160,27 +5270,26 @@ TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam)
 static LRESULT
 TREEVIEW_MouseLeave (TREEVIEW_INFO * infoPtr)
 {
-    if (infoPtr->hotItem)
-    {
-        /* remove hot effect from item */
-        InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE);
-        infoPtr->hotItem = NULL;
-    }
+    /* remove hot effect from item */
+    TREEVIEW_InvalidateItem(infoPtr, infoPtr->hotItem);
+    infoPtr->hotItem = NULL;
+
     return 0;
 }
 
 static LRESULT
-TREEVIEW_MouseMove (TREEVIEW_INFO * infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_MouseMove (TREEVIEW_INFO * infoPtr, LPARAM lParam)
 {
     POINT pt;
     TRACKMOUSEEVENT trackinfo;
     TREEVIEW_ITEM * item;
 
+    if (!(infoPtr->dwStyle & TVS_TRACKSELECT)) return 0;
+
     /* fill in the TRACKMOUSEEVENT struct */
     trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
     trackinfo.dwFlags = TME_QUERY;
     trackinfo.hwndTrack = infoPtr->hwnd;
-    trackinfo.dwHoverTime = HOVER_DEFAULT;
 
     /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
     _TrackMouseEvent(&trackinfo);
@@ -5189,33 +5298,34 @@ TREEVIEW_MouseMove (TREEVIEW_INFO * infoPtr, WPARAM wParam, LPARAM lParam)
     if(!(trackinfo.dwFlags & TME_LEAVE))
     {
         trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
+        trackinfo.hwndTrack = infoPtr->hwnd;
+        /* do it as fast as possible, minimal systimer latency will be used */
+        trackinfo.dwHoverTime = 1;
 
         /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
         /* and can properly deactivate the hot item */
         _TrackMouseEvent(&trackinfo);
     }
 
-    pt.x = (INT)LOWORD(lParam);
-    pt.y = (INT)HIWORD(lParam);
+    pt.x = (short)LOWORD(lParam);
+    pt.y = (short)HIWORD(lParam);
 
     item = TREEVIEW_HitTestPoint(infoPtr, pt);
 
     if (item != infoPtr->hotItem)
     {
         /* redraw old hot item */
-        if (infoPtr->hotItem)
-            InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE);
+        TREEVIEW_InvalidateItem(infoPtr, infoPtr->hotItem);
         infoPtr->hotItem = item;
         /* redraw new hot item */
-        if (infoPtr->hotItem)
-            InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE);
+        TREEVIEW_InvalidateItem(infoPtr, infoPtr->hotItem);
     }
 
     return 0;
 }
 
 /* Draw themed border */
-static BOOL nc_paint (TREEVIEW_INFO *infoPtr, HRGN region)
+static BOOL TREEVIEW_NCPaint (const TREEVIEW_INFO *infoPtr, HRGN region, LPARAM lParam)
 {
     HTHEME theme = GetWindowTheme (infoPtr->hwnd);
     HDC dc;
@@ -5224,7 +5334,8 @@ static BOOL nc_paint (TREEVIEW_INFO *infoPtr, HRGN region)
     int cxEdge = GetSystemMetrics (SM_CXEDGE),
         cyEdge = GetSystemMetrics (SM_CYEDGE);
 
-    if (!theme) return FALSE;
+    if (!theme)
+        return DefWindowProcW (infoPtr->hwnd, WM_NCPAINT, (WPARAM)region, lParam);
 
     GetWindowRect(infoPtr->hwnd, &r);
 
@@ -5249,7 +5360,7 @@ static BOOL nc_paint (TREEVIEW_INFO *infoPtr, HRGN region)
 }
 
 static LRESULT
-TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_Notify(const TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     LPNMHDR lpnmh = (LPNMHDR)lParam;
 
@@ -5258,12 +5369,12 @@ TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 
        if (lppgc->dwFlag == PGF_CALCWIDTH) {
            lppgc->iWidth = infoPtr->treeWidth;
-           TRACE("got PGN_CALCSIZE, returning horz size = %ld, client=%ld\n",
+            TRACE("got PGN_CALCSIZE, returning horz size = %d, client=%d\n",
                  infoPtr->treeWidth, infoPtr->clientWidth);
        }
        else {
            lppgc->iHeight = infoPtr->treeHeight;
-           TRACE("got PGN_CALCSIZE, returning vert size = %ld, client=%ld\n",
+            TRACE("got PGN_CALCSIZE, returning vert size = %d, client=%d\n",
                  infoPtr->treeHeight, infoPtr->clientHeight);
        }
        return 0;
@@ -5271,24 +5382,6 @@ TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     return DefWindowProcW(infoPtr->hwnd, WM_NOTIFY, wParam, lParam);
 }
 
-static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND hwndFrom, UINT nCommand)
-{
-    INT format;
-
-    TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand);
-
-    if (nCommand != NF_REQUERY) return 0;
-
-    format = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwnd, NF_QUERY);
-    TRACE("format=%d\n", format);
-
-    if (format != NFR_ANSI && format != NFR_UNICODE) return 0;
-
-    infoPtr->bNtfUnicode = (format == NFR_UNICODE);
-
-    return format;
-}
-
 static LRESULT
 TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
@@ -5303,7 +5396,7 @@ TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     }
     else
     {
-       FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
+       FIXME("WM_SIZE flag %lx %lx not handled\n", wParam, lParam);
     }
 
     TREEVIEW_Invalidate(infoPtr, NULL);
@@ -5313,28 +5406,41 @@ TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 static LRESULT
 TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
-    TRACE("(%x %lx)\n", wParam, lParam);
+    TRACE("(%lx %lx)\n", wParam, lParam);
 
     if (wParam == GWL_STYLE)
     {
-       DWORD dwNewStyle = ((LPSTYLESTRUCT)lParam)->styleNew;
+        DWORD dwNewStyle = ((LPSTYLESTRUCT)lParam)->styleNew;
 
-       /* we have to take special care about tooltips */
-       if ((infoPtr->dwStyle ^ dwNewStyle) & TVS_NOTOOLTIPS)
-       {
-          if (infoPtr->dwStyle & TVS_NOTOOLTIPS)
-          {
-              infoPtr->hwndToolTip = COMCTL32_CreateToolTip(infoPtr->hwnd);
-              TRACE("\n");
-          }
-          else
-          {
-             DestroyWindow(infoPtr->hwndToolTip);
-             infoPtr->hwndToolTip = 0;
-          }
-       }
+        if ((infoPtr->dwStyle ^ dwNewStyle) & TVS_CHECKBOXES)
+        {
+            if (dwNewStyle & TVS_CHECKBOXES)
+            {
+                initialize_checkboxes(infoPtr);
+                TRACE("checkboxes enabled\n");
+            }
+            else
+            {
+                FIXME("tried to disable checkboxes\n");
+            }
+        }
+
+        if ((infoPtr->dwStyle ^ dwNewStyle) & TVS_NOTOOLTIPS)
+        {
+            if (infoPtr->dwStyle & TVS_NOTOOLTIPS)
+            {
+                infoPtr->hwndToolTip = COMCTL32_CreateToolTip(infoPtr->hwnd);
+                TRACE("tooltips enabled\n");
+            }
+            else
+            {
+                DestroyWindow(infoPtr->hwndToolTip);
+                infoPtr->hwndToolTip = 0;
+                TRACE("tooltips disabled\n");
+            }
+        }
 
-       infoPtr->dwStyle = dwNewStyle;
+        infoPtr->dwStyle = dwNewStyle;
     }
 
     TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root);
@@ -5345,17 +5451,31 @@ TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 }
 
 static LRESULT
-TREEVIEW_SetCursor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TREEVIEW_SetCursor(const TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
 {
     POINT pt;
     TREEVIEW_ITEM * item;
+    NMMOUSE nmmouse;
 
     GetCursorPos(&pt);
     ScreenToClient(infoPtr->hwnd, &pt);
 
     item = TREEVIEW_HitTestPoint(infoPtr, pt);
 
-    /* FIXME: send NM_SETCURSOR */
+    memset(&nmmouse, 0, sizeof(nmmouse));
+    nmmouse.hdr.hwndFrom = infoPtr->hwnd;
+    nmmouse.hdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID);
+    nmmouse.hdr.code = NM_SETCURSOR;
+    if (item)
+    {
+        nmmouse.dwItemSpec = (DWORD_PTR)item;
+        nmmouse.dwItemData = item->lParam;
+    }
+    nmmouse.pt.x = 0;
+    nmmouse.pt.y = 0;
+    nmmouse.dwHitInfo = lParam;
+    if (TREEVIEW_SendRealNotify(infoPtr, nmmouse.hdr.idFrom, (LPARAM)&nmmouse))
+        return 0;
 
     if (item && (infoPtr->dwStyle & TVS_TRACKSELECT))
     {
@@ -5383,7 +5503,7 @@ TREEVIEW_SetFocus(TREEVIEW_INFO *infoPtr)
 }
 
 static LRESULT
-TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr)
+TREEVIEW_KillFocus(const TREEVIEW_INFO *infoPtr)
 {
     TRACE("\n");
 
@@ -5394,7 +5514,7 @@ TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr)
 }
 
 /* update theme after a WM_THEMECHANGED message */
-static LRESULT theme_changed (TREEVIEW_INFO* infoPtr)
+static LRESULT TREEVIEW_ThemeChanged(const TREEVIEW_INFO *infoPtr)
 {
     HTHEME theme = GetWindowTheme (infoPtr->hwnd);
     CloseThemeData (theme);
@@ -5408,7 +5528,7 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
 
-    TRACE("hwnd %p msg %04x wp=%08x lp=%08lx\n", hwnd, uMsg, wParam, lParam);
+    TRACE("hwnd %p msg %04x wp=%08lx lp=%08lx\n", hwnd, uMsg, wParam, lParam);
 
     if (infoPtr) TREEVIEW_VerifyTree(infoPtr);
     else
@@ -5422,14 +5542,12 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     switch (uMsg)
     {
     case TVM_CREATEDRAGIMAGE:
-       return TREEVIEW_CreateDragImage(infoPtr, wParam, lParam);
+       return TREEVIEW_CreateDragImage(infoPtr, lParam);
 
     case TVM_DELETEITEM:
        return TREEVIEW_DeleteItem(infoPtr, (HTREEITEM)lParam);
 
     case TVM_EDITLABELA:
-       return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam);
-
     case TVM_EDITLABELW:
        return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam);
 
@@ -5469,11 +5587,9 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return 0;
 
     case TVM_GETITEMA:
-       return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE);
-
     case TVM_GETITEMW:
-       return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE);
-
+       return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam,
+                                uMsg == TVM_GETITEMW);
     case TVM_GETITEMHEIGHT:
        return TREEVIEW_GetItemHeight(infoPtr);
 
@@ -5508,11 +5624,9 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_HitTest(infoPtr, (LPTVHITTESTINFO)lParam);
 
     case TVM_INSERTITEMA:
-       return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, FALSE);
-
     case TVM_INSERTITEMW:
-       return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, TRUE);
-
+       return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam,
+                                   uMsg == TVM_INSERTITEMW);
     case TVM_SELECTITEM:
        return TREEVIEW_SelectItem(infoPtr, (INT)wParam, (HTREEITEM)lParam);
 
@@ -5532,11 +5646,9 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_SetInsertMarkColor(infoPtr, (COLORREF)lParam);
 
     case TVM_SETITEMA:
-       return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE);
-
     case TVM_SETITEMW:
-        return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE);
-
+        return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam,
+                                uMsg == TVM_SETITEMW);
     case TVM_SETLINECOLOR:
        return TREEVIEW_SetLineColor(infoPtr, (COLORREF)lParam);
 
@@ -5556,13 +5668,13 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
         return TREEVIEW_SetUnicodeFormat(infoPtr, (BOOL)wParam);
 
     case TVM_SORTCHILDREN:
-       return TREEVIEW_SortChildren(infoPtr, wParam, lParam);
+       return TREEVIEW_SortChildren(infoPtr, lParam);
 
     case TVM_SORTCHILDRENCB:
-       return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam);
+       return TREEVIEW_SortChildrenCB(infoPtr, (LPTVSORTCB)lParam);
 
     case WM_CHAR:
-        return TREEVIEW_ProcessLetterKeys( hwnd, wParam, lParam );
+        return TREEVIEW_ProcessLetterKeys(infoPtr, wParam, lParam);
 
     case WM_COMMAND:
        return TREEVIEW_Command(infoPtr, wParam, lParam);
@@ -5602,16 +5714,16 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_MouseLeave(infoPtr);
 
     case WM_MOUSEMOVE:
-        if (infoPtr->dwStyle & TVS_TRACKSELECT)
-            return TREEVIEW_MouseMove(infoPtr, wParam, lParam);
-        else
-            return 0;
+       return TREEVIEW_MouseMove(infoPtr, lParam);
 
-    case WM_NCPAINT:
-        if (nc_paint (infoPtr, (HRGN)wParam))
-            return 0;
+    case WM_NCLBUTTONDOWN:
+        if (infoPtr->hwndEdit)
+            SetFocus(infoPtr->hwnd);
         goto def;
 
+    case WM_NCPAINT:
+        return TREEVIEW_NCPaint (infoPtr, (HRGN)wParam, lParam);
+
     case WM_NOTIFY:
        return TREEVIEW_Notify(infoPtr, wParam, lParam);
 
@@ -5619,8 +5731,10 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_NotifyFormat(infoPtr, (HWND)wParam, (UINT)lParam);
 
     case WM_PRINTCLIENT:
+        return TREEVIEW_PrintClient(infoPtr, (HDC)wParam, lParam);
+
     case WM_PAINT:
-       return TREEVIEW_Paint(infoPtr, wParam);
+       return TREEVIEW_Paint(infoPtr, (HDC)wParam);
 
     case WM_RBUTTONDOWN:
        return TREEVIEW_RButtonDown(infoPtr, lParam);
@@ -5635,7 +5749,7 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
 
     case WM_SETREDRAW:
-        return TREEVIEW_SetRedraw(infoPtr, wParam, lParam);
+        return TREEVIEW_SetRedraw(infoPtr, wParam);
 
     case WM_SIZE:
        return TREEVIEW_Size(infoPtr, wParam, lParam);
@@ -5643,7 +5757,9 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     case WM_STYLECHANGED:
        return TREEVIEW_StyleChanged(infoPtr, wParam, lParam);
 
-       /* WM_SYSCOLORCHANGE */
+    case WM_SYSCOLORCHANGE:
+        COMCTL32_RefreshSysColors();
+        return 0;
 
        /* WM_SYSKEYDOWN */
 
@@ -5651,7 +5767,7 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        return TREEVIEW_HandleTimer(infoPtr, wParam);
 
     case WM_THEMECHANGED:
-        return theme_changed (infoPtr);
+        return TREEVIEW_ThemeChanged (infoPtr);
 
     case WM_VSCROLL:
        return TREEVIEW_VScroll(infoPtr, wParam);
@@ -5659,9 +5775,7 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
        /* WM_WININICHANGE */
 
     case WM_MOUSEWHEEL:
-       if (wParam & (MK_SHIFT | MK_CONTROL))
-           goto def;
-       return TREEVIEW_MouseWheel(infoPtr, wParam);
+       return TREEVIEW_MouseWheel(infoPtr, wParam, lParam);
 
     case WM_DRAWITEM:
        TRACE("drawItem\n");
@@ -5669,8 +5783,8 @@ TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 
     default:
        /* This mostly catches MFC and Delphi messages. :( */
-       if ((uMsg >= WM_USER) && (uMsg < WM_APP))
-           TRACE("Unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
+       if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
+           TRACE("Unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
 def:
        return DefWindowProcW(hwnd, uMsg, wParam, lParam);
     }