Listview updates (B0)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is another large ListView update:
 listview.c | 1325 +++++++++++++++++++++++++++++--------------------------------
 1 files changed, 642 insertions(+), 683 deletions(-)

It is relative to the other large listview patch that I sent
a few days ago (namely Sat, Sep. 15, named "Listview updates (take 2)").

Just a comment on performance: the listview is very inefficient.
Why have expensive computations that are invariant on loop indices 
done inside one, or even two, nested loops? We should pay more
attention to these things, Wine is sluggish as is, we have X, etc:
we gonna end up orders of magnitude slower that Winblows :(.

ChangeLog
  -- Reorganization and cleanup of selection code
  -- Complete rewrite of focus handling and drawing code
  -- Many bugs fixed (including a serious memory corruption)
  -- Many performance fixes
  -- Lots of cleanups, simplifications, etc.
  -- Documentation updates

--- dlls/comctl32/listview.c.A0	Sat Sep 14 17:12:20 2002
+++ dlls/comctl32/listview.c	Mon Sep 16 14:02:03 2002
@@ -124,10 +124,9 @@
   HIMAGELIST himlState;
   BOOL bLButtonDown;
   BOOL bRButtonDown;
-  INT nFocusedItem;
-  HDPA hdpaSelectionRanges;
   INT nItemHeight;
   INT nItemWidth;
+  HDPA hdpaSelectionRanges;
   INT nSelectionMark;
   INT nHotItem;
   SHORT notifyFormat;
@@ -143,6 +142,8 @@
   INT ntmHeight;               /*  from GetTextMetrics from above font */
   INT ntmAveCharWidth;         /*  from GetTextMetrics from above font */
   BOOL bFocus;
+  INT nFocusedItem;
+  RECT rcFocus;
   DWORD dwExStyle;             /* extended listview style */
   HDPA hdpaItems;
   PFNLVCOMPARE pfnCompare;
@@ -246,8 +247,6 @@
 static LRESULT LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL, BOOL);
 static INT LISTVIEW_SuperHitTestItem(LISTVIEW_INFO *, LPLV_INTHIT, BOOL);
 static INT LISTVIEW_HitTestItem(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL);
-static INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *);
-static INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *);
 static void LISTVIEW_AlignLeft(LISTVIEW_INFO *);
 static void LISTVIEW_AlignTop(LISTVIEW_INFO *);
 static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *, INT);
@@ -261,12 +260,10 @@
 static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT);
 static LRESULT LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT);
 static LRESULT LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT);
-static INT LISTVIEW_MouseSelection(LISTVIEW_INFO *, POINT);
 static BOOL LISTVIEW_RemoveColumn(HDPA, INT);
 static BOOL LISTVIEW_RemoveSubItem(HDPA, INT);
 static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT);
 static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL);
-static BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *, INT);
 static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *, INT, LONG, LONG);
 static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *);
 static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT);
@@ -281,7 +278,6 @@
 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT);
 static LRESULT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT);
 static LRESULT LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, LPLVITEMW);
-static void LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *, INT, INT);
 static void LISTVIEW_UpdateLargeItemLabelRect (LISTVIEW_INFO *, int, RECT*);
 static LRESULT LISTVIEW_GetColumnT(LISTVIEW_INFO *, INT, LPLVCOLUMNW, BOOL);
 static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND);
@@ -340,7 +336,7 @@
   LPWSTR wstr = (LPWSTR)text;
 
   TRACE("(text=%s, isW=%d)\n", debugtext_t(text, isW), isW);
-  if (!isW && text)
+  if (!isW && is_textT(text, isW))
   {
     INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0);
     wstr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
@@ -352,7 +348,7 @@
 
 static inline void textfreeT(LPWSTR wstr, BOOL isW)
 {
-  if (!isW && wstr) HeapFree(GetProcessHeap(), 0, wstr);
+  if (!isW && is_textT(wstr, isW)) HeapFree(GetProcessHeap(), 0, wstr);
 }
 
 /*
@@ -655,11 +651,82 @@
  return (BOOL) retval;
 }
 
-static inline int get_listview_type(LISTVIEW_INFO *infoPtr)
+static inline int LISTVIEW_GetType(LISTVIEW_INFO *infoPtr)
 {
     return GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & LVS_TYPEMASK;
 }
 
+/***
+ * DESCRIPTION:
+ * Retrieves the number of items that can fit vertically in the client area.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ *
+ * RETURN:
+ * Number of items per row.
+ */
+static inline INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *infoPtr)
+{
+  INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
+
+  return max(nListWidth/infoPtr->nItemWidth, 1);
+}
+
+/***
+ * DESCRIPTION:
+ * Retrieves the number of items that can fit horizontally in the client
+ * area.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ *
+ * RETURN:
+ * Number of items per column.
+ */
+static inline INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *infoPtr)
+{
+  INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
+
+  return max(nListHeight / infoPtr->nItemHeight, 1);
+}
+
+/***
+ * DESCRIPTION:
+ * Retrieves the count of visible items. Note that the returned count may 
+ * be a bit larger than the actual count.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ *
+ * RETURN:
+ * maximum visible item count
+ */
+static INT LISTVIEW_GetVisibleCount(LISTVIEW_INFO *infoPtr)
+{
+    UINT uView = LISTVIEW_GetType(infoPtr);
+    INT nPerCol, nPerRow;
+    
+    if (uView == LVS_REPORT)
+    {
+	nPerCol = LISTVIEW_GetCountPerColumn(infoPtr) + 1;
+	nPerRow = 1;
+    }
+    else if (uView == LVS_LIST)
+    {
+	nPerCol = LISTVIEW_GetCountPerColumn(infoPtr) + 1;
+	nPerRow = LISTVIEW_GetCountPerRow(infoPtr);
+    }
+    else
+    {
+	nPerCol = LISTVIEW_GetCountPerColumn(infoPtr) + 1;
+	nPerRow = LISTVIEW_GetCountPerRow(infoPtr) + 1;
+    }
+
+    return nPerCol * nPerRow;
+}
+
+
 /*************************************************************************
  *		LISTVIEW_ProcessLetterKeys
  *
@@ -802,13 +869,8 @@
         idx++;
     } while (idx != endidx);
 
-    if (nItem != -1) {
-        if (LISTVIEW_KeySelection(infoPtr, nItem)) {
-            /* refresh client area */
-            InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
-            UpdateWindow(infoPtr->hwndSelf);
-        }
-    }
+    if (nItem != -1)
+        LISTVIEW_KeySelection(infoPtr, nItem);
 
     return 0;
 }
@@ -971,6 +1033,45 @@
   }
 }
 
+
+/***
+ * Toggles (draws/erase) the focus rectangle. 
+ */
+static inline void LISTVIEW_ToggleFocusRect(LISTVIEW_INFO *infoPtr)
+{
+    /* if we have a focus rectagle, draw it */
+    if (!IsRectEmpty(&infoPtr->rcFocus))
+    {
+	HDC hdc = GetDC(infoPtr->hwndSelf);
+	DrawFocusRect(hdc, &infoPtr->rcFocus);
+	ReleaseDC(infoPtr->hwndSelf, hdc);
+    }
+}
+
+/***
+ * Invalidates all visible selected items.
+ */
+static void LISTVIEW_InvalidateSelectedItems(LISTVIEW_INFO *infoPtr)
+{
+    INT i, nTop, nBottom;
+
+    nTop = LISTVIEW_GetTopIndex(infoPtr);
+    nBottom = nTop + LISTVIEW_GetVisibleCount(infoPtr);
+    if (nBottom > GETITEMCOUNT(infoPtr)) nBottom = GETITEMCOUNT(infoPtr);
+    
+    for (i = nTop; i <= nBottom; i++)
+    {
+	if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
+	{
+	    RECT rcItem;
+	    rcItem.left = LVIR_BOUNDS;
+	    LISTVIEW_GetItemRect(infoPtr, i, &rcItem);
+	    InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
+	}
+    }
+}
+
+	    
 /***
  * DESCRIPTION:
  * Prints a message for unsupported window styles.
@@ -1012,7 +1113,7 @@
  */
 static void LISTVIEW_AlignTop(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
   POINT ptItem;
   RECT rcView;
@@ -1080,7 +1181,7 @@
  */
 static void LISTVIEW_AlignLeft(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
   POINT ptItem;
   RECT rcView;
@@ -1244,7 +1345,7 @@
  */
 static INT LISTVIEW_CalculateWidth(LISTVIEW_INFO *infoPtr, INT nItem)
 {
-    UINT uView = get_listview_type(infoPtr);
+    UINT uView = LISTVIEW_GetType(infoPtr);
     INT nItemWidth = 0, i;
 
     if (uView == LVS_ICON) 
@@ -1345,7 +1446,7 @@
  */
 static INT LISTVIEW_GetItemHeight(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nItemHeight = 0;
 
   if (uView == LVS_ICON)
@@ -1363,7 +1464,7 @@
   return nItemHeight;
 }
 
-
+#if 0
 static void LISTVIEW_PrintSelectionRanges(LISTVIEW_INFO *infoPtr)
 {
   LISTVIEW_SELECTION *selection;
@@ -1377,37 +1478,208 @@
     TRACE("     %lu - %lu\n",selection->lower,selection->upper);
   }
 }
+#endif
 
 /***
  * DESCRIPTION:
  * A compare function for selection ranges
  *
  *PARAMETER(S)
- * [I] LPVOID : Item 1;
- * [I] LPVOID : Item 2;
- * [I] LPARAM : flags
+ * [I] range1 : pointer to selection range 1;
+ * [I] range2 : pointer to selection range 2;
+ * [I] flags : flags
  *
  *RETURNS:
  * >0 : if Item 1 > Item 2
  * <0 : if Item 2 > Item 1
  * 0 : if Item 1 == Item 2
  */
-static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2,
-                                                    LPARAM flags)
+static INT CALLBACK LISTVIEW_CompareSelectionRanges(LPVOID range1, LPVOID range2, LPARAM flags)
+{
+    if (((LISTVIEW_SELECTION*)(range1))->upper < 
+	((LISTVIEW_SELECTION*)(range2))->lower) 
+	return -1;
+    if (((LISTVIEW_SELECTION*)(range2))->upper < 
+	((LISTVIEW_SELECTION*)(range1))->lower) 
+	return 1;
+    return 0;
+}
+
+/***
+ * Helper function for LISTVIEW_AddSelectionRange, and LISTVIEW_SetItem.
+ */
+static BOOL add_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
+{
+    LISTVIEW_SELECTION selection;
+    LVITEMW lvItem;
+    INT index, i;
+
+    TRACE("range (%i - %i)\n", lower, upper);
+
+    /* try find overlapping selections first */
+    selection.lower = lower - 1;
+    selection.upper = upper + 1;
+    index = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, 0,
+		       LISTVIEW_CompareSelectionRanges, 0, 0);
+   
+    if (index == -1)
+    {
+	LISTVIEW_SELECTION *newsel;
+
+	/* create the brand new selection to insert */	
+        newsel = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+	if(!newsel) return FALSE;
+	newsel->lower = lower;
+	newsel->upper = upper;
+	
+	/* figure out where to insert it */
+	index = DPA_Search(infoPtr->hdpaSelectionRanges, newsel, 0,
+			   LISTVIEW_CompareSelectionRanges, 0, DPAS_INSERTAFTER);
+	if (index == -1) index = 0;
+	
+	/* and get it over with */
+	DPA_InsertPtr(infoPtr->hdpaSelectionRanges, index, newsel);
+    }
+    else
+    {
+	LISTVIEW_SELECTION *chksel, *mrgsel;
+	INT fromindex, mergeindex;
+
+	chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index);
+	if (!chksel) return FALSE;
+	TRACE("Merge with index %i (%lu - %lu)\n",
+	      index,chksel->lower, chksel->upper);
+
+	chksel->lower = min(lower, chksel->lower);
+	chksel->upper = max(upper, chksel->upper);
+	
+	TRACE("New range %i (%lu - %lu)\n",
+	      index,chksel->lower, chksel->upper);
+
+        /* merge now common selection ranges */
+	fromindex = 0;
+	selection.lower = chksel->lower - 1;
+	selection.upper = chksel->upper + 1;
+	    
+	do
+	{
+	    mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, &selection, fromindex,
+				    LISTVIEW_CompareSelectionRanges, 0, 0);
+	    if (mergeindex == -1) break;
+	    if (mergeindex == index) 
+	    {
+		fromindex = index + 1;
+		continue;
+	    }
+	  
+	    TRACE("Merge with index %i\n", mergeindex);
+	    
+	    mrgsel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, mergeindex);
+	    if (!mrgsel) return FALSE;
+	    
+	    chksel->lower = min(chksel->lower, mrgsel->lower);
+	    chksel->upper = max(chksel->upper, mrgsel->upper);
+	    COMCTL32_Free(mrgsel);
+	    DPA_DeletePtr(infoPtr->hdpaSelectionRanges, mergeindex);
+	    if (mergeindex < index) index --;
+	} while(1);
+    }
+
+    /* FIXME: do we really need it? */
+    DPA_Sort(infoPtr->hdpaSelectionRanges, LISTVIEW_CompareSelectionRanges, 0);
+   
+    if (adj_sel_only) return TRUE;
+   
+    /* set the selection on items */
+    ZeroMemory(&lvItem, sizeof(lvItem));
+    lvItem.state = LVIS_SELECTED;
+    lvItem.stateMask = LVIS_SELECTED;
+    for(i = lower; i <= upper; i++)
+	LISTVIEW_SetItemState(infoPtr, i, &lvItem);
+
+    return TRUE;
+}
+   
+/***
+ * Helper function for LISTVIEW_RemoveSelectionRange, and LISTVIEW_SetItem.
+ */
+static BOOL remove_selection_range(LISTVIEW_INFO *infoPtr, INT lower, INT upper, BOOL adj_sel_only)
 {
-  int l1 = ((LISTVIEW_SELECTION*)(range1))->lower;
-  int l2 = ((LISTVIEW_SELECTION*)(range2))->lower;
-  int u1 = ((LISTVIEW_SELECTION*)(range1))->upper;
-  int u2 = ((LISTVIEW_SELECTION*)(range2))->upper;
-  int rc=0;
+    LISTVIEW_SELECTION remsel, tmpsel, *chksel;
+    BOOL done = FALSE;
+    LVITEMW lvItem;
+    INT index, i;
+
+    ZeroMemory(&lvItem, sizeof(lvItem));
+    lvItem.stateMask = LVIS_SELECTED;
+    
+    remsel.lower = lower;
+    remsel.upper = upper;
+
+    TRACE("range: (%lu - %lu)\n", remsel.lower, remsel.upper);
 
-  if (u1 < l2)
-    rc= -1;
+    do 
+    {
+	index = DPA_Search(infoPtr->hdpaSelectionRanges, &remsel, 0,
+			   LISTVIEW_CompareSelectionRanges, 0, 0);
+	if (index == -1) return TRUE;
 
-  if (u2 < l1)
-     rc= 1;
+	chksel = DPA_GetPtr(infoPtr->hdpaSelectionRanges, index);
+	if (!chksel) return FALSE;
+	
+        TRACE("Matches range index %i (%lu-%lu)\n", 
+	      index, chksel->lower, chksel->upper);
 
-  return rc;
+	/* case 1: Same range */
+	if ( (chksel->upper == remsel.upper) &&
+	     (chksel->lower == remsel.lower) )
+	{
+	    DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index);
+	    done = TRUE;
+	}
+	/* case 2: engulf */
+	else if ( (chksel->upper <= remsel.upper) &&
+		  (chksel->lower >= remsel.lower) ) 
+	{
+	    DPA_DeletePtr(infoPtr->hdpaSelectionRanges, index);
+	}
+	/* case 3: overlap upper */
+	else if ( (chksel->upper < remsel.upper) &&
+		  (chksel->lower < remsel.lower) )
+	{
+	    chksel->upper = remsel.lower - 1;
+	}
+	/* case 4: overlap lower */
+	else if ( (chksel->upper > remsel.upper) &&
+		  (chksel->lower > remsel.lower) )
+	{
+	    chksel->lower = remsel.upper + 1;
+	}
+	/* case 5: fully internal */
+	else
+	{
+	    LISTVIEW_SELECTION *newsel = 
+		(LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
+	    if (!newsel) return FALSE;
+	    tmpsel = *chksel;
+	    newsel->lower = chksel->lower;
+	    newsel->upper = remsel.lower - 1;
+	    chksel->lower = remsel.upper + 1;
+	    DPA_InsertPtr(infoPtr->hdpaSelectionRanges, index, newsel);
+	    /*FIXME: why do we need the sort??? */
+	    DPA_Sort(infoPtr->hdpaSelectionRanges, LISTVIEW_CompareSelectionRanges, 0);
+	    chksel = &tmpsel;
+	}
+
+	if (adj_sel_only) continue;
+	
+	/* here, chksel holds the selection to delete */
+	for (i = chksel->lower; i <= chksel->upper; i++)
+	    LISTVIEW_SetItemState(infoPtr, i, &lvItem);
+    }
+    while(!done);
+
+    return TRUE;
 }
 
 /**
@@ -1416,295 +1688,68 @@
 *
 * PARAMETER(S):
 * [I] infoPtr : valid pointer to the listview structure
-* [I] INT : lower item index
-* [I] INT : upper item index
+* [I] lower : lower item index
+* [I] upper : upper item index
 *
 * RETURN:
-* None
+*   Success: TRUE
+*   Failure: FALSE
 */
-static void LISTVIEW_AddSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
+static inline BOOL LISTVIEW_AddSelectionRange(LISTVIEW_INFO *infoPtr, INT lower, INT upper)
 {
- LISTVIEW_SELECTION *selection;
- INT topSelection = infoPtr->hdpaSelectionRanges->nItemCount;
- BOOL lowerzero = FALSE;
-
- selection = (LISTVIEW_SELECTION *)COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
- selection->lower = lItem;
- selection->upper = uItem;
-
- TRACE("Add range %i - %i\n", lItem, uItem);
- if (topSelection)
- {
-   LISTVIEW_SELECTION *checkselection,*checkselection2;
-   INT index,mergeindex;
-
-   /* find overlapping selections */
-   /* we want to catch adjacent ranges so expand our range by 1 */
-
-   selection->upper++;
-   if (selection->lower == 0)
-     lowerzero = TRUE;
-   else
-     selection->lower--;
-
-   index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
-                      LISTVIEW_CompareSelectionRanges,
-                      0,0);
-   selection->upper --;
-   if (lowerzero)
-     lowerzero = FALSE;
-   else
-     selection->lower ++;
-
-   if (index >=0)
-   {
-     checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,index);
-     TRACE("Merge with index %i (%lu - %lu)\n",index,checkselection->lower,
-           checkselection->upper);
-
-     checkselection->lower = min(selection->lower,checkselection->lower);
-     checkselection->upper = max(selection->upper,checkselection->upper);
-
-     TRACE("New range (%lu - %lu)\n", checkselection->lower,
-           checkselection->upper);
-
-     COMCTL32_Free(selection);
-
-     /* merge now common selection ranges in the lower group*/
-     do
-     {
-        checkselection->upper ++;
-        if (checkselection->lower == 0)
-          lowerzero = TRUE;
-        else
-          checkselection->lower --;
-
-        TRACE("search lower range (%lu - %lu)\n", checkselection->lower,
-              checkselection->upper);
-
-        /* not sorted yet */
-        mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection, 0,
-                                LISTVIEW_CompareSelectionRanges, 0,
-                                0);
-
-        checkselection->upper --;
-        if (lowerzero)
-          lowerzero = FALSE;
-        else
-	  checkselection->lower ++;
-
-	if (mergeindex >=0  && mergeindex != index)
-        {
-	  TRACE("Merge with index %i\n",mergeindex);
-          checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
-                                       mergeindex);
-          checkselection->lower = min(checkselection->lower,
-                                      checkselection2->lower);
-          checkselection->upper = max(checkselection->upper,
-                                      checkselection2->upper);
-          COMCTL32_Free(checkselection2);
-          DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
-          index --;
-        }
-     }
-     while (mergeindex > -1 && mergeindex <index);
-
-     /* merge now common selection ranges in the upper group*/
-    do
-    {
-       checkselection->upper ++;
-       if (checkselection->lower == 0)
-         lowerzero = TRUE;
-       else
-         checkselection->lower --;
-
-       TRACE("search upper range %i (%lu - %lu)\n",index,
-             checkselection->lower, checkselection->upper);
-
-       /* not sorted yet */
-       mergeindex = DPA_Search(infoPtr->hdpaSelectionRanges, checkselection,
-                               index+1,
-			       LISTVIEW_CompareSelectionRanges, 0,
-			       0);
-
-       checkselection->upper --;
-       if (lowerzero)
-         lowerzero = FALSE;
-       else
-         checkselection->lower ++;
-
-       if (mergeindex >=0 && mergeindex !=index)
-       {
-	 TRACE("Merge with index %i\n",mergeindex);
-	 checkselection2 = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
-				      mergeindex);
-	 checkselection->lower = min(checkselection->lower,
-				     checkselection2->lower);
-	 checkselection->upper = max(checkselection->upper,
-				     checkselection2->upper);
-	 COMCTL32_Free(checkselection2);
-	 DPA_DeletePtr(infoPtr->hdpaSelectionRanges,mergeindex);
-       }
-    }
-    while (mergeindex > -1);
-   }
-   else
-   {
-
-     index = DPA_Search(infoPtr->hdpaSelectionRanges, selection, 0,
-                       LISTVIEW_CompareSelectionRanges, 0,
-                       DPAS_INSERTAFTER);
-
-     TRACE("Insert before index %i\n",index);
-     if (index == -1)
-       index = 0;
-     DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,selection);
-   }
- }
- else
- {
-   DPA_InsertPtr(infoPtr->hdpaSelectionRanges,0,selection);
- }
- /*
-  * Incase of error
-  */
- DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
- LISTVIEW_PrintSelectionRanges(infoPtr);
+    return add_selection_range(infoPtr, lower, upper, FALSE);
 }
 
 /***
 * DESCRIPTION:
-* Removes all selection ranges
+* Removes a range selections.
 *
-* Parameters(s):
+* PARAMETER(S):
 * [I] infoPtr : valid pointer to the listview structure
+* [I] lower : lower item index
+* [I] upper : upper item index
 *
-* RETURNS:
-*   SUCCESS : TRUE
-*   FAILURE : TRUE
+* RETURN:
+*   Success: TRUE
+*   Failure: FALSE
 */
-static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr)
+static inline BOOL LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *infoPtr, INT lower, INT upper)
 {
-  LISTVIEW_SELECTION *selection;
-  INT i;
-  LVITEMW item;
-
-  TRACE("()\n");
-
-  ZeroMemory(&item,sizeof(item));
-  item.stateMask = LVIS_SELECTED;
-
-  do
-  {
-    selection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
-    if (selection)
-    {
-      TRACE("Removing %lu to %lu\n",selection->lower, selection->upper);
-      for (i = selection->lower; i<=selection->upper; i++)
-        LISTVIEW_SetItemState(infoPtr,i,&item);
-      LISTVIEW_RemoveSelectionRange(infoPtr,selection->lower,selection->upper);
-    }
-  }
-  while (infoPtr->hdpaSelectionRanges->nItemCount>0);
-
-  TRACE("done\n");
-  return TRUE;
+    return remove_selection_range(infoPtr, lower, upper, FALSE);
 }
 
-/**
+/***
 * DESCRIPTION:
-* Removes a range selections.
+* Removes all selection ranges
 *
-* PARAMETER(S):
+* Parameters(s):
 * [I] infoPtr : valid pointer to the listview structure
-* [I] INT : lower item index
-* [I] INT : upper item index
 *
-* RETURN:
-* None
+* RETURNS:
+*   SUCCESS : TRUE
+*   FAILURE : TRUE
 */
-static void LISTVIEW_RemoveSelectionRange(LISTVIEW_INFO *infoPtr, INT lItem, INT uItem)
+static LRESULT LISTVIEW_RemoveAllSelections(LISTVIEW_INFO *infoPtr)
 {
-  LISTVIEW_SELECTION removeselection,*checkselection;
-  INT index;
-
-  removeselection.lower = lItem;
-  removeselection.upper = uItem;
+    LISTVIEW_SELECTION *sel;
+    static BOOL removing_all_selections = FALSE;
 
-  TRACE("Remove range %lu - %lu\n",removeselection.lower,removeselection.upper);
-  LISTVIEW_PrintSelectionRanges(infoPtr);
+    if (removing_all_selections) return TRUE;
 
-  index = DPA_Search(infoPtr->hdpaSelectionRanges, &removeselection, 0,
-                     LISTVIEW_CompareSelectionRanges,
-                     0,0);
+    removing_all_selections = TRUE;
 
-  if (index == -1)
-    return;
+    TRACE("()\n");
 
+    do
+    {
+	sel = DPA_GetPtr(infoPtr->hdpaSelectionRanges,0);
+	if (sel) LISTVIEW_RemoveSelectionRange(infoPtr, sel->lower, sel->upper);
+    }
+    while (infoPtr->hdpaSelectionRanges->nItemCount > 0);
 
-  checkselection = DPA_GetPtr(infoPtr->hdpaSelectionRanges,
-                              index);
-
-  TRACE("Matches range index %i (%lu-%lu)\n",index,checkselection->lower,
-        checkselection->upper);
-
-  /* case 1: Same */
-  if ((checkselection->upper == removeselection.upper) &&
-     (checkselection->lower == removeselection.lower))
-  {
-    DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
-    TRACE("Case 1\n");
-  }
-  /* case 2: engulf */
-  else if (((checkselection->upper < removeselection.upper) &&
-      (checkselection->lower > removeselection.lower))||
-     ((checkselection->upper <= removeselection.upper) &&
-      (checkselection->lower > removeselection.lower)) ||
-     ((checkselection->upper < removeselection.upper) &&
-      (checkselection->lower >= removeselection.lower)))
-
-  {
-    DPA_DeletePtr(infoPtr->hdpaSelectionRanges,index);
-    /* do it again because others may also get caught */
-    TRACE("Case 2\n");
-    LISTVIEW_RemoveSelectionRange(infoPtr,lItem,uItem);
-  }
-  /* case 3: overlap upper */
-  else if ((checkselection->upper < removeselection.upper) &&
-      (checkselection->lower < removeselection.lower))
-  {
-    checkselection->upper = removeselection.lower - 1;
-    TRACE("Case 3\n");
-    LISTVIEW_RemoveSelectionRange(infoPtr,lItem,uItem);
-  }
-  /* case 4: overlap lower */
-  else if ((checkselection->upper > removeselection.upper) &&
-      (checkselection->lower > removeselection.lower))
-  {
-    checkselection->lower = removeselection.upper + 1;
-    TRACE("Case 4\n");
-    LISTVIEW_RemoveSelectionRange(infoPtr,lItem,uItem);
-  }
-  /* case 5: fully internal */
-  else if (checkselection->upper == removeselection.upper)
-    checkselection->upper = removeselection.lower - 1;
-  else if (checkselection->lower == removeselection.lower)
-    checkselection->lower = removeselection.upper + 1;
-  else
-  {
-    /* bisect the range */
-    LISTVIEW_SELECTION *newselection;
+    removing_all_selections = FALSE;
 
-    newselection = (LISTVIEW_SELECTION *)
-                          COMCTL32_Alloc(sizeof(LISTVIEW_SELECTION));
-    newselection -> lower = checkselection->lower;
-    newselection -> upper = removeselection.lower - 1;
-    checkselection -> lower = removeselection.upper + 1;
-    DPA_InsertPtr(infoPtr->hdpaSelectionRanges,index,newselection);
-    TRACE("Case 5\n");
-    DPA_Sort(infoPtr->hdpaSelectionRanges,LISTVIEW_CompareSelectionRanges,0);
-  }
-  LISTVIEW_PrintSelectionRanges(infoPtr);
+    return TRUE;
 }
 
 /***
@@ -1724,6 +1769,7 @@
     INT oldFocus = infoPtr->nFocusedItem;
     LVITEMW lvItem;
 
+    ZeroMemory(&lvItem, sizeof(lvItem));
     lvItem.state =  LVIS_FOCUSED;
     lvItem.stateMask = LVIS_FOCUSED;
     LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
@@ -1824,7 +1870,8 @@
   item.state = LVIS_SELECTED;
 
   /* FIXME: this is not correct LVS_OWNERDATA
-   * See docu for LVN_ITEMCHANGED
+   * See docu for LVN_ITEMCHANGED. Is there something similar for
+   * RemoveGroupSelection (is there such a thing?)?
    */
   for (i = nFirst; i <= nLast; i++)
     LISTVIEW_SetItemState(infoPtr,i,&item);
@@ -1865,30 +1912,28 @@
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
- * [I] RECT : selection rectangle
+ * [I] rcSelRect : selection rectangle
  *
  * RETURN:
  * None
  */
 static void LISTVIEW_SetSelectionRect(LISTVIEW_INFO *infoPtr, RECT rcSelRect)
 {
-  POINT ptItem;
-  INT i;
-  LVITEMW item;
+    POINT ptItem;
+    INT i;
+    LVITEMW item;
 
-  ZeroMemory(&item,sizeof(item));
-  item.stateMask = LVIS_SELECTED;
+    ZeroMemory(&item,sizeof(item));
+    item.stateMask = LVIS_SELECTED;
 
-  for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
-  {
-    LISTVIEW_GetItemPosition(infoPtr, i, &ptItem);
+    /* FIXME: shouldn't we iterate over visible items only? */
+    for (i = 0; i < GETITEMCOUNT(infoPtr); i++)
+    {
+	LISTVIEW_GetItemPosition(infoPtr, i, &ptItem);
 
-    if (PtInRect(&rcSelRect, ptItem))
-      item.state = LVIS_SELECTED;
-    else
-      item.state = 0;
-    LISTVIEW_SetItemState(infoPtr,i,&item);
-  }
+	item.state = PtInRect(&rcSelRect, ptItem) ? LVIS_SELECTED : 0;
+	LISTVIEW_SetItemState(infoPtr,i,&item);
+    }
 }
 
 /***
@@ -1904,7 +1949,7 @@
  */
 static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   LVITEMW item;
 
   ZeroMemory(&item,sizeof(item));
@@ -1972,14 +2017,11 @@
 {
   LVITEMW lvItem;
 
-  ZeroMemory(&lvItem, sizeof(lvItem));
-  lvItem.stateMask = LVIS_FOCUSED;
-  LISTVIEW_SetItemState(infoPtr, infoPtr->nFocusedItem, &lvItem);
-
   LISTVIEW_RemoveAllSelections(infoPtr);
 
-  lvItem.state =   LVIS_FOCUSED|LVIS_SELECTED;
-  lvItem.stateMask = LVIS_FOCUSED|LVIS_SELECTED;
+  ZeroMemory(&lvItem, sizeof(lvItem));
+  lvItem.state =   LVIS_FOCUSED | LVIS_SELECTED;
+  lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
   LISTVIEW_SetItemState(infoPtr, nItem, &lvItem);
 
   infoPtr->nSelectionMark = nItem;
@@ -1999,6 +2041,7 @@
  */
 static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem)
 {
+  /* FIXME: pass in the state */
   LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
   WORD wShift = HIWORD(GetKeyState(VK_SHIFT));
   WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL));
@@ -2032,11 +2075,42 @@
     }
   }
 
+  UpdateWindow(infoPtr->hwndSelf); /* update client area */
   return bResult;
 }
 
 /***
  * DESCRIPTION:
+ * Selects an item based on coordinates.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] pt : mouse click ccordinates
+ *
+ * RETURN:
+ *   SUCCESS : item index
+ *   FAILURE : -1
+ */
+static INT LISTVIEW_GetItemAtPt(LISTVIEW_INFO *infoPtr, POINT pt)
+{
+    INT i, nTop, nBottom;
+    RECT rcItem;
+
+    nTop = LISTVIEW_GetTopIndex(infoPtr);
+    nBottom = nTop + LISTVIEW_GetVisibleCount(infoPtr);
+    if (nBottom > GETITEMCOUNT(infoPtr)) nBottom = GETITEMCOUNT(infoPtr);
+    
+    for (i = nTop; i <= nBottom; i++)
+    {
+	rcItem.left = LVIR_SELECTBOUNDS;
+	if (LISTVIEW_GetItemRect(infoPtr, i, &rcItem))
+	    if (PtInRect(&rcItem, pt)) return i;
+    }
+    return -1;
+}
+
+/***
+ * DESCRIPTION:
  * Called when the mouse is being actively tracked and has hovered for a specified
  * amount of time
  *
@@ -2055,14 +2129,13 @@
  */
 static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, POINTS pts)
 {
-  POINT pt = { pts.x, pts.y };
+    POINT pt = { pts.x, pts.y };
 
-  if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT) {
-    /* FIXME: select the item under the cursor */
-    LISTVIEW_MouseSelection(infoPtr, pt);
-  }
+    if(infoPtr->dwExStyle & LVS_EX_TRACKSELECT)
+	/* FIXME: select the item!!! */
+	LISTVIEW_GetItemAtPt(infoPtr, pt);
 
-  return 0;
+    return 0;
 }
 
 /***
@@ -2105,44 +2178,6 @@
 
 /***
  * DESCRIPTION:
- * Selects an item based on coordinates.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- * [I] pt : mouse click ccordinates
- *
- * RETURN:
- *   SUCCESS : item index
- *   FAILURE : -1
- */
-static INT LISTVIEW_MouseSelection(LISTVIEW_INFO *infoPtr, POINT pt)
-{
-  LONG uView = get_listview_type(infoPtr);
-  INT i, topindex, bottomindex;
-  RECT rcItem;
-
-  topindex = LISTVIEW_GetTopIndex(infoPtr);
-  if (uView == LVS_REPORT) {
-    bottomindex = topindex + LISTVIEW_GetCountPerColumn(infoPtr) + 1;
-    bottomindex = min(bottomindex, GETITEMCOUNT(infoPtr));
-  } else {
-    bottomindex = GETITEMCOUNT(infoPtr);
-  }
-
-  for (i = topindex; i < bottomindex; i++)
-  {
-    rcItem.left = LVIR_SELECTBOUNDS;
-    if (LISTVIEW_GetItemRect(infoPtr, i, &rcItem))
-    {
-      if (PtInRect(&rcItem, pt)) return i;
-    }
-  }
-
-  return -1;
-}
-
-/***
- * DESCRIPTION:
  * Removes a column.
  *
  * PARAMETER(S):
@@ -2251,14 +2286,13 @@
     LISTVIEW_ITEM *lpItem;
     NMLISTVIEW nmlv;
     UINT uChanged = 0;
-    RECT rcItem;
 
     TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
 
   
     if (lStyle & LVS_OWNERDATA)
     {
-	INT oldState, oldFocus;
+	INT oldState;
 
 	/* a virtual livst view stores only state for the mai item */
 	if (lpLVItem->iSubItem || !(lpLVItem->mask & LVIF_STATE)) return FALSE;
@@ -2275,7 +2309,6 @@
          */
 
 	/* if we handle the focus, and we're asked to change it, do it now */
-	oldFocus = infoPtr->nFocusedItem;
 	if ( lpLVItem->stateMask & LVIS_FOCUSED )
 	{
 	    if (lpLVItem->state & LVIS_FOCUSED)
@@ -2290,10 +2323,10 @@
 	    if (lpLVItem->state & LVIS_SELECTED)
 	    {
 		if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr);
-		LISTVIEW_AddSelectionRange(infoPtr, lpLVItem->iItem, lpLVItem->iItem);
+		add_selection_range(infoPtr, lpLVItem->iItem, lpLVItem->iItem, TRUE);
 	    }
 	    else
-		LISTVIEW_RemoveSelectionRange(infoPtr, lpLVItem->iItem, lpLVItem->iItem);
+		remove_selection_range(infoPtr, lpLVItem->iItem, lpLVItem->iItem, TRUE);
 	}
 
 	/* notify the parent now that things have changed */
@@ -2304,21 +2337,6 @@
 	nmlv.uChanged = LVIF_STATE;
 	listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
 
-	/* Redraw items that have changed */
-	if (!infoPtr->bIsDrawing)
-	{
-	    if (oldFocus != infoPtr->nFocusedItem)
-	    {
-		rcItem.left = LVIR_BOUNDS;
-		LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
-		InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
-	    }
-	    /* FIXME: shouldn't the selection changes invaidated those rects? */
-	    rcItem.left = LVIR_BOUNDS;
-	    LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
-	    InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
-	}
-	
 	return TRUE;
     }
 
@@ -2381,10 +2399,10 @@
 	if (nmlv.uNewState & LVIS_SELECTED)
 	{
 	    if (lStyle & LVS_SINGLESEL) LISTVIEW_RemoveAllSelections(infoPtr);
-	    LISTVIEW_AddSelectionRange(infoPtr,lpLVItem->iItem, lpLVItem->iItem);
+	    add_selection_range(infoPtr, lpLVItem->iItem, lpLVItem->iItem, TRUE);
 	}
 	else if (lpLVItem->stateMask & LVIS_SELECTED)
-	    LISTVIEW_RemoveSelectionRange(infoPtr,lpLVItem->iItem, lpLVItem->iItem);
+	    remove_selection_range(infoPtr, lpLVItem->iItem, lpLVItem->iItem, TRUE);
 	
 	/* if we are asked to change focus, and we manage it, do it */
 	if (nmlv.uNewState & ~infoPtr->uCallbackMask & LVIS_FOCUSED)
@@ -2412,13 +2430,8 @@
     /* send LVN_ITEMCHANGED notification */
     nmlv.lParam = lpItem->lParam;
     listview_notify(infoPtr, LVN_ITEMCHANGED, &nmlv);
-		   
-    rcItem.left = LVIR_BOUNDS;
-    LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
-    if (!infoPtr->bIsDrawing)
-	InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
 
-  return TRUE;
+    return TRUE;
 }
 
 /***
@@ -2439,7 +2452,6 @@
     LONG lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
     HDPA hdpaSubItems;
     LISTVIEW_SUBITEM *lpSubItem;
-    RECT rcItem;
 
     TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW);
 
@@ -2489,10 +2501,6 @@
     if (lpLVItem->mask & LVIF_TEXT)
 	textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW);
 	  
-    rcItem.left = LVIR_BOUNDS;
-    LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
-    InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
-
     return TRUE;
 }
 
@@ -2511,18 +2519,41 @@
  */
 static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW)
 {
+    INT oldFocus = infoPtr->nFocusedItem;
+    LPWSTR pszText = NULL;
+    RECT rcItem;
     BOOL bResult;
-    LPWSTR pszText = lpLVItem->pszText;
     
     if (!lpLVItem || lpLVItem->iItem < 0 ||
 	lpLVItem->iItem>=GETITEMCOUNT(infoPtr))
 	return FALSE;
    
     /* For efficiency, we transform the lpLVItem->pszText to Unicode here */
-    lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
-    bResult = (lpLVItem->iSubItem ? set_sub_item : set_main_item)(infoPtr, lpLVItem, TRUE);
-    textfreeT(lpLVItem->pszText, isW);
-    lpLVItem->pszText = pszText;
+    if ((lpLVItem->mask & LVIF_TEXT) && lpLVItem->pszText)
+    {
+	pszText = lpLVItem->pszText;
+	lpLVItem->pszText = textdupTtoW(lpLVItem->pszText, isW);
+    }
+    /* actually set the fields */
+    if (lpLVItem->iSubItem)
+	bResult = set_sub_item(infoPtr, lpLVItem, TRUE);
+    else
+	bResult = set_main_item(infoPtr, lpLVItem, TRUE);
+    /* redraw item, if necessary */
+    if (bResult && !infoPtr->bIsDrawing)
+    {
+	if (oldFocus != infoPtr->nFocusedItem && infoPtr->bFocus)
+	    LISTVIEW_ToggleFocusRect(infoPtr);
+	rcItem.left = LVIR_BOUNDS;
+	LISTVIEW_GetItemRect(infoPtr, lpLVItem->iItem, &rcItem);
+	InvalidateRect(infoPtr->hwndSelf, &rcItem, TRUE);
+    }
+    /* restore text */
+    if (pszText)
+    {
+	textfreeT(lpLVItem->pszText, isW);
+	lpLVItem->pszText = pszText;
+    }
 
     return bResult;
 }
@@ -2562,6 +2593,7 @@
   return nItem;
 }
 
+
 /***
  * DESCRIPTION:
  * Draws a subitem.
@@ -2690,14 +2722,16 @@
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
- * [I] HDC : device context handle
- * [I] INT : item index
- * [I] RECT * : clipping rectangle
+ * [I] hdc : device context handle
+ * [I] nItem : item index
+ * [I] rcItem : item rectangle
+ * [I] bFullSelect : TRUE if all item is selected
+ * [O] lprcFocus : pointer to rectangle to receive focus rect
  *
  * RETURN:
  * None
  */
-static void LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, BOOL FullSelect, RECT* SuggestedFocus)
+static void LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem, BOOL bFullSelect, RECT* lprcFocus)
 {
   WCHAR szDispText[DISP_TEXT_SIZE];
   INT nLabelWidth;
@@ -2712,7 +2746,6 @@
 
   TRACE("(hdc=%x, nItem=%d)\n", hdc, nItem);
 
-
   /* get information needed for drawing the item */
   ZeroMemory(&lvItem, sizeof(lvItem));
   lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
@@ -2738,9 +2771,6 @@
   if (lvItem.iIndent>0 && infoPtr->iconSize.cx > 0)
   {
     rcItem.left += infoPtr->iconSize.cx * lvItem.iIndent;
-
-    if (SuggestedFocus)
-      SuggestedFocus->left += infoPtr->iconSize.cx * lvItem.iIndent;
   }
 
   /* state icons */
@@ -2748,14 +2778,10 @@
   {
      UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12;
      if (uStateImage > 0)
-     {
        ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcItem.left,
                       rcItem.top, ILD_NORMAL);
-     }
 
      rcItem.left += infoPtr->iconSize.cx;
-     if (SuggestedFocus)
-       SuggestedFocus->left += infoPtr->iconSize.cx;
      bImage = TRUE;
   }
 
@@ -2777,15 +2803,15 @@
     }
 
     rcItem.left += infoPtr->iconSize.cx;
-
-    if (SuggestedFocus)
-      SuggestedFocus->left += infoPtr->iconSize.cx;
     bImage = TRUE;
   }
 
   /* Don't bother painting item being edited */
-  if (infoPtr->bEditing && lvItem.state & LVIS_FOCUSED && !FullSelect)
-      return;
+  if (infoPtr->bEditing && lprcFocus && !bFullSelect) 
+  {
+    SetRectEmpty(lprcFocus);
+    return;
+  }
 
   if ((lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus))
   {
@@ -2826,7 +2852,7 @@
   nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE);
   if (rcItem.left + nLabelWidth < rcItem.right)
   {
-    if (!FullSelect)
+    if (!bFullSelect)
       rcItem.right = rcItem.left + nLabelWidth + TRAILING_PADDING;
     if (bImage)
       rcItem.right += IMAGE_PADDING;
@@ -2837,14 +2863,26 @@
   if (bImage)
     dwTextX += IMAGE_PADDING;
 
-  if (lvItem.pszText) {
+  /* compute the focus rectangle */
+  if(lprcFocus) 
+  {
+    if (lvItem.pszText)
+    {
+      *lprcFocus = rcItem;
+      lprcFocus->right -= 2;
+    }
+    else SetRectEmpty(lprcFocus);
+  }
+  
+  if (lvItem.pszText)
+  {
     TRACE("drawing text  rect=(%d,%d)-(%d,%d)\n",
 	  rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
     ExtTextOutW(hdc, dwTextX, rcItem.top, textoutOptions,
                 &rcItem, lvItem.pszText, lstrlenW(lvItem.pszText), NULL);
   }
 
-  if ((FullSelect)&&(Header_GetItemCount(infoPtr->hwndHeader) > 1))
+  if ((bFullSelect) && (Header_GetItemCount(infoPtr->hwndHeader) > 1))
   {
     /* fill in the gap */
     RECT rec;
@@ -2855,9 +2893,6 @@
 		&rec, NULL, 0, NULL);
   }
 
-  if (!FullSelect)
-      CopyRect(SuggestedFocus,&rcItem);
-
   if (nMixMode != 0)
   {
     SetROP2(hdc, R2_COPYPEN);
@@ -2874,16 +2909,16 @@
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
- * [I] HDC : device context handle
- * [I] INT : item index
- * [I] RECT : clipping rectangle
- * [O] RECT * : The text rectangle about which to draw the focus
+ * [I] hdc : device context handle
+ * [I] nItem : item index
+ * [I] rcItem : clipping rectangle
+ * [O] lprcFocus : the text rectangle about which to draw the focus
  *
  * RETURN:
  * None
  */
 static void LISTVIEW_DrawLargeItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, RECT rcItem,
-                                   RECT *SuggestedFocus)
+                                   RECT *lprcFocus)
 {
   WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' };
   LVITEMW lvItem;
@@ -2965,10 +3000,7 @@
    * wrapping and both word and end ellipsis.  (I don't yet know about path
    * ellipsis)
    */
-  uFormat |= ( (lvItem.state & LVIS_FOCUSED) && infoPtr->bFocus) ?
-          DT_NOCLIP
-      :
-          DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
+  uFormat |= lprcFocus ?  DT_NOCLIP : DT_WORD_ELLIPSIS | DT_END_ELLIPSIS;
 
   /* draw the icon */
   if (infoPtr->himlNormal != NULL)
@@ -2986,10 +3018,9 @@
   /* Draw the text below the icon */
 
   /* Don't bother painting item being edited */
-  if ((infoPtr->bEditing && (lvItem.state & LVIS_FOCUSED)) ||
-      !lstrlenW(lvItem.pszText))
+  if ((infoPtr->bEditing && lprcFocus) || !lvItem.pszText || !lstrlenW(lvItem.pszText))
   {
-    SetRectEmpty(SuggestedFocus);
+    if(lprcFocus) SetRectEmpty(lprcFocus);
     return;
   }
 
@@ -3052,7 +3083,7 @@
 	rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
 	debugstr_w(lvItem.pszText));
 
-  CopyRect(SuggestedFocus, &rcItem);
+  if(lprcFocus) CopyRect(lprcFocus, &rcItem);
 }
 
 /***
@@ -3071,7 +3102,7 @@
   SCROLLINFO scrollInfo;
   INT nDrawPosY = infoPtr->rcList.top;
   INT nColumnCount;
-  RECT rcItem;
+  RECT rcItem, rcFull, *lprcFocus;
   INT  j;
   INT nItem;
   INT nLast;
@@ -3110,6 +3141,18 @@
   if(GETITEMCOUNT(infoPtr) == 0)
     return;
 
+  /* if we have focus, precompute full select rect, if need be */
+  if (infoPtr->bFocus && FullSelected)
+  {
+    RECT br;
+
+    Header_GetItemRect(infoPtr->hwndHeader, 0, &rcFull);
+    Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
+
+    rcFull.left += REPORT_MARGINX;
+    rcFull.right = max(rcFull.left, br.right - REPORT_MARGINX);
+  }
+    
   /* Get scroll bar info once before loop */
   ZeroMemory(&scrollInfo, sizeof(SCROLLINFO));
   scrollInfo.cbSize = sizeof(SCROLLINFO);
@@ -3119,8 +3162,6 @@
 
   for (; nItem < nLast; nItem++)
   {
-    RECT SuggestedFocusRect;
-
     /* Do Owner Draw */
     if (lStyle & LVS_OWNERDRAWFIXED)
     {
@@ -3165,20 +3206,11 @@
         }
     }
 
-    if (FullSelected)
-    {
-      RECT ir,br;
-
-      Header_GetItemRect(infoPtr->hwndHeader, 0, &ir);
-      Header_GetItemRect(infoPtr->hwndHeader, nColumnCount-1, &br);
-
-      ir.left += REPORT_MARGINX;
-      ir.right = max(ir.left, br.right - REPORT_MARGINX);
-      ir.top = nDrawPosY;
-      ir.bottom = ir.top + infoPtr->nItemHeight;
-
-      CopyRect(&SuggestedFocusRect,&ir);
-    }
+    /* if we have focus, calculate focus rect */
+    if (infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
+      lprcFocus = &infoPtr->rcFocus;
+    else
+      lprcFocus = 0;
 
     for (j = 0; j < nColumnCount; j++)
     {
@@ -3200,114 +3232,27 @@
       rcItem.right -= scrollOffset;
 
       if (j == 0)
-      {
-        LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, FullSelected,
-                          &SuggestedFocusRect);
-      }
+        LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, FullSelected, lprcFocus);
       else
-      {
         LISTVIEW_DrawSubItem(infoPtr, hdc, nItem, j, rcItem, FullSelected);
-      }
 
       if (cditemmode & CDRF_NOTIFYPOSTPAINT)
         LISTVIEW_SendCustomDrawItemNotify(infoPtr, hdc, nItem, 0,
 				      CDDS_ITEMPOSTPAINT);
     }
-    /*
-     * Draw Focus Rect
-     */
-    if (LISTVIEW_GetItemState(infoPtr,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
-	
+    
+    /* Adjust focus if we have it, and we are in full select */
+    if (lprcFocus && FullSelected)
     {
-      BOOL rop=FALSE;
-      if (FullSelected && LISTVIEW_GetItemState(infoPtr,nItem,LVIS_SELECTED))
-        rop = SetROP2(hdc, R2_XORPEN);
-
-      Rectangle(hdc, SuggestedFocusRect.left, SuggestedFocusRect.top,
-                SuggestedFocusRect.right,SuggestedFocusRect.bottom);
-
-      if (rop)
-        SetROP2(hdc, R2_COPYPEN);
+	rcFull.top = nDrawPosY;
+	rcFull.bottom = rcFull.top + infoPtr->nItemHeight;
+	infoPtr->rcFocus = rcFull;
     }
-    nDrawPosY += infoPtr->nItemHeight;
-  }
-}
-
-/***
- * DESCRIPTION:
- * Retrieves the number of items that can fit vertically in the client area.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- *
- * RETURN:
- * Number of items per row.
- */
-static INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *infoPtr)
-{
-  UINT uView = get_listview_type(infoPtr);
-  INT nCountPerRow = 0;
-
-  if (uView != LVS_REPORT)
-      nCountPerRow = (infoPtr->rcList.right - infoPtr->rcList.left) / infoPtr->nItemWidth;
 
-  return max(nCountPerRow, 1);
-}
-
-/***
- * DESCRIPTION:
- * Retrieves the number of items that can fit horizontally in the client
- * area.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- *
- * RETURN:
- * Number of items per column.
- */
-static INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *infoPtr)
-{
-  INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top;
-  INT nCountPerColumn = 1;
-
-  if (nListHeight > 0)
-  {
-    TRACE("rcList=(%d,%d)-(%d,%d), nItemHeight=%d, CYHSCROLL=%d\n",
-	  infoPtr->rcList.left,infoPtr->rcList.top,
-	  infoPtr->rcList.right,infoPtr->rcList.bottom,
-	  infoPtr->nItemHeight,
-	  GetSystemMetrics(SM_CYHSCROLL));
-    nCountPerColumn =  nListHeight / infoPtr->nItemHeight;
-    if (nCountPerColumn == 0) nCountPerColumn = 1;
+    nDrawPosY += infoPtr->nItemHeight;
   }
-
-  return nCountPerColumn;
-}
-
-/***
- * DESCRIPTION:
- * Retrieves the number of columns needed to display all the items when in
- * list display mode.
- *
- * PARAMETER(S):
- * [I] infoPtr : valid pointer to the listview structure
- *
- * RETURN:
- * Number of columns.
- */
-static INT LISTVIEW_GetColumnCount(LISTVIEW_INFO *infoPtr)
-{
-    INT nColumnCount = 0;
-
-    if (get_listview_type(infoPtr) == LVS_LIST) {
-        nColumnCount = infoPtr->rcList.right / infoPtr->nItemWidth;
-        if (infoPtr->rcList.right % infoPtr->nItemWidth) nColumnCount++;
-    }
-
-    return nColumnCount;
 }
 
-
 /***
  * DESCRIPTION:
  * Draws listview items when in list display mode.
@@ -3321,17 +3266,19 @@
  */
 static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD cdmode)
 {
-  RECT rcItem, FocusRect;
+  RECT rcItem, *lprcFocus;
   INT i, j;
   INT nItem;
   INT nColumnCount;
   INT nCountPerColumn;
   INT nItemWidth = infoPtr->nItemWidth;
   INT nItemHeight = infoPtr->nItemHeight;
+  INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left;
   DWORD cditemmode = CDRF_DODEFAULT;
 
   /* get number of fully visible columns */
-  nColumnCount = LISTVIEW_GetColumnCount(infoPtr);
+  nColumnCount = nListWidth / nItemWidth;
+  if (nListWidth % nItemWidth) nColumnCount++;
   infoPtr->nColumnCount = nColumnCount;
   nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr);
   nItem = ListView_GetTopIndex(infoPtr->hwndSelf);
@@ -3359,13 +3306,14 @@
       rcItem.left = i * nItemWidth;
       rcItem.bottom = rcItem.top + nItemHeight;
       rcItem.right = rcItem.left + nItemWidth;
-      LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, FALSE, &FocusRect);
-      /*
-       * Draw Focus Rect
-       */
-      if (LISTVIEW_GetItemState(infoPtr,nItem,LVIS_FOCUSED) && infoPtr->bFocus)
-      Rectangle(hdc, FocusRect.left, FocusRect.top,
-                FocusRect.right,FocusRect.bottom);
+
+      /* if we have focus, calculate focus rect */
+      if (infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED))
+	lprcFocus = &infoPtr->rcFocus;
+      else
+	lprcFocus = 0;
+      
+      LISTVIEW_DrawItem(infoPtr, hdc, nItem, rcItem, FALSE, lprcFocus);
 
       if (cditemmode & CDRF_NOTIFYPOSTPAINT)
         LISTVIEW_SendCustomDrawItemNotify(infoPtr, hdc, nItem, 0,
@@ -3390,7 +3338,7 @@
 {
   POINT ptPosition;
   POINT ptOrigin;
-  RECT rcItem, SuggestedFocus;
+  RECT rcItem, *lprcFocus;
   INT i;
   DWORD cditemmode = CDRF_DODEFAULT;
 
@@ -3427,17 +3375,17 @@
             rcItem.left = ptPosition.x;
             rcItem.bottom = rcItem.top + infoPtr->nItemHeight;
             rcItem.right = rcItem.left + infoPtr->nItemWidth;
+	    
+            /* if we have focus, calculate focus rect */
+            if (infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, i, LVIS_FOCUSED))
+	      lprcFocus = &infoPtr->rcFocus;
+            else
+	      lprcFocus = 0;
+      
             if (bSmall)
-              LISTVIEW_DrawItem(infoPtr, hdc, i, rcItem, FALSE, &SuggestedFocus);
+              LISTVIEW_DrawItem(infoPtr, hdc, i, rcItem, FALSE, lprcFocus);
             else
-              LISTVIEW_DrawLargeItem(infoPtr, hdc, i, rcItem, &SuggestedFocus);
-            /*
-             * Draw Focus Rect
-             */
-            if (LISTVIEW_GetItemState(infoPtr,i,LVIS_FOCUSED) &&
-                infoPtr->bFocus && !IsRectEmpty(&SuggestedFocus))
-              Rectangle(hdc, SuggestedFocus.left, SuggestedFocus.top,
-	                SuggestedFocus.right,SuggestedFocus.bottom);
+              LISTVIEW_DrawLargeItem(infoPtr, hdc, i, rcItem, lprcFocus);
           }
         }
       }
@@ -3461,28 +3409,23 @@
  */
 static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   HFONT hOldFont;
-  HPEN hPen, hOldPen;
   DWORD cdmode;
-  RECT rect, rcTemp;
+  RECT rcClient, rcTemp;
 
   LISTVIEW_DUMP(infoPtr);
   
-  infoPtr->bIsDrawing = TRUE;
-
-  GetClientRect(infoPtr->hwndSelf, &rect);
-  cdmode = LISTVIEW_SendCustomDrawNotify(infoPtr,CDDS_PREPAINT,hdc,rect);
-
+  GetClientRect(infoPtr->hwndSelf, &rcClient);
+  
+  cdmode = LISTVIEW_SendCustomDrawNotify(infoPtr, CDDS_PREPAINT, hdc, rcClient);
   if (cdmode == CDRF_SKIPDEFAULT) return;
 
+  infoPtr->bIsDrawing = TRUE;
+
   /* select font */
   hOldFont = SelectObject(hdc, infoPtr->hFont);
 
-  /* select the dotted pen (for drawing the focus box) */
-  hPen = CreatePen(PS_ALTERNATE, 1, 0);
-  hOldPen = SelectObject(hdc, hPen);
-
   /* select transparent brush (for drawing the focus box) */
   SelectObject(hdc, GetStockObject(NULL_BRUSH));
 
@@ -3497,15 +3440,15 @@
   else
     LISTVIEW_RefreshIcon(infoPtr, hdc, uView == LVS_SMALLICON, cdmode);
 
+  /* if we have a focus rect, draw it */
+  if (infoPtr->bFocus && !IsRectEmpty(&infoPtr->rcFocus))
+    DrawFocusRect(hdc, &infoPtr->rcFocus);
+
   /* unselect objects */
   SelectObject(hdc, hOldFont);
-  SelectObject(hdc, hOldPen);
-
-  /* delete pen */
-  DeleteObject(hPen);
 
   if (cdmode & CDRF_NOTIFYPOSTPAINT)
-      LISTVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect);
+      LISTVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rcClient);
 
   infoPtr->bIsDrawing = FALSE;
 }
@@ -3527,7 +3470,7 @@
 static LRESULT LISTVIEW_ApproximateViewRect(LISTVIEW_INFO *infoPtr, INT nItemCount,
                                             WORD wWidth, WORD wHeight)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nItemCountPerColumn = 1;
   INT nColumnCount = 0;
   DWORD dwViewRect = 0;
@@ -3591,7 +3534,7 @@
  */
 static LRESULT LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   BOOL bResult = FALSE;
 
   if ((uView == LVS_ICON) || (uView == LVS_SMALLICON))
@@ -3747,7 +3690,7 @@
  */
 static LRESULT LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   UINT uOwnerData = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & LVS_OWNERDATA;
   BOOL bResult = FALSE;
 
@@ -4067,7 +4010,7 @@
  */
 static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nScrollPosHeight = 0;
   INT nScrollPosWidth = 0;
   SCROLLINFO scrollInfo;
@@ -4528,7 +4471,7 @@
  */
 static LRESULT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nColumnWidth = 0;
   HDITEMW hdi;
 
@@ -4562,7 +4505,7 @@
  */
 static LRESULT LISTVIEW_GetCountPerPage(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   INT nItemCount = 0;
 
   if (uView == LVS_LIST)
@@ -4954,7 +4897,7 @@
  */
 static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   BOOL bResult = FALSE;
   RECT rcBounding;
 
@@ -5175,7 +5118,7 @@
  */
 static LRESULT LISTVIEW_GetItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   BOOL bResult = FALSE;
   POINT ptOrigin;
   POINT ptItem;
@@ -5555,7 +5498,7 @@
 static LRESULT LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem, INT
 flags, LPRECT lprc)
 {
-    UINT uView = get_listview_type(infoPtr);
+    UINT uView = LISTVIEW_GetType(infoPtr);
     INT  count;
 
     TRACE("(nItem=%d, nSubItem=%d lprc=%p)\n", nItem, nSubItem,
@@ -5635,7 +5578,7 @@
   }
   else
   {
-    if (get_listview_type(infoPtr) == LVS_ICON)
+    if (LISTVIEW_GetType(infoPtr) == LVS_ICON)
       lResult = MAKELONG(DEFAULT_COLUMN_WIDTH, GetSystemMetrics(SM_CXSMICON)+HEIGHT_PADDING);
     else
       lResult = MAKELONG(infoPtr->nItemWidth, infoPtr->nItemHeight);
@@ -5720,7 +5663,7 @@
  */
 static LRESULT LISTVIEW_GetNextItem(LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
   UINT uMask = 0;
   LVFINDINFOW lvFindInfo;
   INT nCountPerColumn;
@@ -6529,7 +6472,7 @@
  */
 static LRESULT LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
 {
-    switch(get_listview_type(infoPtr)) {
+    switch(LISTVIEW_GetType(infoPtr)) {
     case LVS_REPORT:
 	dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2;
         dy /= infoPtr->nItemHeight;
@@ -6565,7 +6508,7 @@
     if(infoPtr->clrBk != clrBk) {
 	infoPtr->clrBk = clrBk;
 	if (infoPtr->hBkBrush) DeleteObject(infoPtr->hBkBrush);
-	infoPtr->hBkBrush = CreateSolidBrush(clrBk);
+	infoPtr->hBkBrush = clrBk == CLR_NONE ? 0 : CreateSolidBrush(clrBk);
 	InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
     }
 
@@ -7032,7 +6975,7 @@
 {
   HIMAGELIST himlOld = 0;
   INT oldHeight;
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
 
   switch (nType)
   {
@@ -7424,25 +7367,25 @@
 static LRESULT LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
 {
     UINT lStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
-    HDPA hdpaSubItems=NULL;
-    LISTVIEW_ITEM *pLVItem=NULL;
+    HDPA hdpaSubItems;
+    LISTVIEW_ITEM *lpItem;
     LPVOID selectionMarkItem;
-    int nCount, i;
+    int i;
 
     TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort);
 
     if (lStyle & LVS_OWNERDATA) return FALSE;
 
-    if (!infoPtr || !infoPtr->hdpaItems) return FALSE;
+    if (!infoPtr->hdpaItems) return FALSE;
 
-    nCount = GETITEMCOUNT(infoPtr);
     /* if there are 0 or 1 items, there is no need to sort */
-    if (nCount < 2)
-        return TRUE;
+    if (GETITEMCOUNT(infoPtr) < 2) return TRUE;
 
     if (infoPtr->nFocusedItem >= 0)
     {
-	/* FIXME: set the LVIS_FOCUSED in pLVItem->state*/
+	hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem);
+	lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
+	if (lpItem) lpItem->state |= LVIS_FOCUSED;
     }
     
     infoPtr->pfnCompare = pfnCompare;
@@ -7455,20 +7398,23 @@
      * selected instead)
      */
     selectionMarkItem=(infoPtr->nSelectionMark>=0)?DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark):NULL;
-    for (i=0; i < nCount; i++)
+    for (i=0; i < GETITEMCOUNT(infoPtr); i++)
     {
-       hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
-       pLVItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
+	hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i);
+	lpItem = (LISTVIEW_ITEM *)DPA_GetPtr(hdpaSubItems, 0);
 
-       if (pLVItem->state & LVIS_SELECTED)
-          LISTVIEW_AddSelectionRange(infoPtr, i, i);
-       else
-          LISTVIEW_RemoveSelectionRange(infoPtr, i, i);
-       if (pLVItem->state & LVIS_FOCUSED)
-          infoPtr->nFocusedItem = i;
+	if (lpItem->state & LVIS_SELECTED)
+	    LISTVIEW_AddSelectionRange(infoPtr, i, i);
+	else
+	    LISTVIEW_RemoveSelectionRange(infoPtr, i, i);
+	if (lpItem->state & LVIS_FOCUSED)
+	{
+            infoPtr->nFocusedItem = i;
+	    lpItem->state &= ~LVIS_FOCUSED;
+	}
     }
     if (selectionMarkItem != NULL)
-       infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
+	infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem);
     /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */
 
     /* align the items */
@@ -7659,7 +7605,6 @@
 
     TRACE("(wParam=%x, lParam=%lx)\n", wParam, lParam);
 
-    /* FIXME: whu erase background, if we're doing it individually for every item? */
     if (infoPtr->clrBk == CLR_NONE)
 	return SendMessageW(GetParent(infoPtr->hwndSelf), WM_ERASEBKGND, wParam, lParam);
     
@@ -7671,6 +7616,33 @@
 
 /***
  * DESCRIPTION:
+ * Helper function for LISTVIEW_[HV]Scroll *only*.
+ * Performs vertical/horizontal scrolling by a give amount.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] dx : amount of horizontal scroll
+ * [I] dy : amount of vertical scroll
+ */
+static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy)
+{
+    /* if we have a focus rectagle, we have to erase it before we scroll */ 
+    if (infoPtr->bFocus) LISTVIEW_ToggleFocusRect(infoPtr);
+    
+    /* now we can scroll the list */
+    ScrollWindowEx( infoPtr->hwndSelf, dx, dy, &infoPtr->rcList, 
+		    &infoPtr->rcList, 0, 0, SW_INVALIDATE);
+    
+    /* if we have focus, adjust rect, and redraw the rectangle */
+    if (infoPtr->bFocus)
+    {
+	OffsetRect(&infoPtr->rcFocus, dx, dy);
+	LISTVIEW_ToggleFocusRect(infoPtr);
+    }
+}
+
+/***
+ * DESCRIPTION:
  * Performs vertical scrolling.
  *
  * PARAMETER(S):
@@ -7692,7 +7664,7 @@
 static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, 
 				INT nScrollDiff, HWND hScrollWnd)
 {
-    UINT uView = get_listview_type(infoPtr);
+    UINT uView = LISTVIEW_GetType(infoPtr);
     INT nOldScrollPos, nNewScrollPos;
     SCROLLINFO scrollInfo;
     BOOL is_an_icon;
@@ -7768,8 +7740,7 @@
     if (uView == LVS_REPORT) nScrollDiff *= infoPtr->nItemHeight;
    
     /* and scroll the window */ 
-    ScrollWindowEx( infoPtr->hwndSelf, 0, nScrollDiff, &infoPtr->rcList, 
-		    &infoPtr->rcList, 0, 0, SW_INVALIDATE);
+    scroll_list(infoPtr, 0, nScrollDiff);
 
     return 0;
 }
@@ -7798,7 +7769,7 @@
 static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode,
                                 INT nScrollDiff, HWND hScrollWnd)
 {
-    UINT uView = get_listview_type(infoPtr);
+    UINT uView = LISTVIEW_GetType(infoPtr);
     INT nOldScrollPos, nNewScrollPos;
     SCROLLINFO scrollInfo;
 
@@ -7874,16 +7845,15 @@
     nScrollDiff = nOldScrollPos - nNewScrollPos;
     if (uView == LVS_LIST) nScrollDiff *= infoPtr->nItemWidth;
    
-    /* and scroll the window */ 
-    ScrollWindowEx( infoPtr->hwndSelf, nScrollDiff, 0, &infoPtr->rcList,
-		    &infoPtr->rcList, 0, 0, SW_INVALIDATE);
+    /* and scroll the window */
+    scroll_list(infoPtr, nScrollDiff, 0);
 
   return 0;
 }
 
 static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta)
 {
-    UINT uView = get_listview_type(infoPtr);
+    UINT uView = LISTVIEW_GetType(infoPtr);
     INT gcWheelDelta = 0;
     UINT pulScrollLines = 3;
     SCROLLINFO scrollInfo;
@@ -7945,7 +7915,7 @@
  */
 static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData)
 {
-  UINT uView =  get_listview_type(infoPtr);
+  UINT uView =  LISTVIEW_GetType(infoPtr);
   INT nItem = -1;
   NMLVKEYDOWN nmKeyDown;
 
@@ -8012,10 +7982,7 @@
   }
 
   if ((nItem != -1) && (nItem != infoPtr->nFocusedItem))
-  {
-    if (LISTVIEW_KeySelection(infoPtr, nItem))
-      UpdateWindow(infoPtr->hwndSelf); /* update client area */
-  }
+      LISTVIEW_KeySelection(infoPtr, nItem);
 
   return 0;
 }
@@ -8032,41 +7999,24 @@
  */
 static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr)
 {
-  UINT uView =  get_listview_type(infoPtr);
-  INT i,nTop,nBottom;
+    TRACE("()\n");
 
-  TRACE("()\n");
-
-  /* send NM_KILLFOCUS notification */
-  notify_killfocus(infoPtr);
-
-  /* set window focus flag */
-  infoPtr->bFocus = FALSE;
+    /* if we did not have the focus, there's nothing to do */
+    if (!infoPtr->bFocus) return 0;
+   
+    /* send NM_KILLFOCUS notification */
+    notify_killfocus(infoPtr);
 
-  /* NEED drawing optimization ; redraw the selected items */
-  if (uView & LVS_REPORT)
-  {
-    nTop = LISTVIEW_GetTopIndex(infoPtr);
-    nBottom = nTop +
-              LISTVIEW_GetCountPerColumn(infoPtr) + 1;
-  }
-  else
-  {
-    nTop = 0;
-    nBottom = GETITEMCOUNT(infoPtr);
-  }
-  for (i = nTop; i<nBottom; i++)
-  {
-    if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED))
-    {
-      RECT rcItem;
-      rcItem.left = LVIR_BOUNDS;
-      LISTVIEW_GetItemRect(infoPtr, i, &rcItem);
-      InvalidateRect(infoPtr->hwndSelf, &rcItem, FALSE);
-    }
-  }
+    /* if we have a focus rectagle, get rid of it */
+    LISTVIEW_ToggleFocusRect(infoPtr);
+    
+    /* set window focus flag */
+    infoPtr->bFocus = FALSE;
 
-  return 0;
+    /* redraw the selected items */
+    LISTVIEW_InvalidateSelectedItems(infoPtr);
+    
+    return 0;
 }
 
 /***
@@ -8144,7 +8094,7 @@
   /* set left button down flag */
   infoPtr->bLButtonDown = TRUE;
 
-  nItem = LISTVIEW_MouseSelection(infoPtr, pt);
+  nItem = LISTVIEW_GetItemAtPt(infoPtr, pt);
   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
   {
     if (lStyle & LVS_SINGLESEL)
@@ -8484,7 +8434,7 @@
   infoPtr->bRButtonDown = TRUE;
 
   /* determine the index of the selected item */
-  nItem = LISTVIEW_MouseSelection(infoPtr, pt);
+  nItem = LISTVIEW_GetItemAtPt(infoPtr, pt);
   if ((nItem >= 0) && (nItem < GETITEMCOUNT(infoPtr)))
   {
     LISTVIEW_SetItemFocus(infoPtr,nItem);
@@ -8570,16 +8520,18 @@
  */
 static BOOL LISTVIEW_SetCursor(LISTVIEW_INFO *infoPtr, HWND hwnd, UINT nHittest, UINT wMouseMsg)
 {
-  POINT pt;
+    POINT pt;
 
-  if(!(infoPtr->dwExStyle & LVS_EX_TRACKSELECT)) return FALSE;
+    if(!(infoPtr->dwExStyle & LVS_EX_TRACKSELECT)) return FALSE;
 
-  GetCursorPos(&pt);
-  if (LISTVIEW_MouseSelection(infoPtr, pt) < 0) return FALSE;
+    if(!infoPtr->hHotCursor)  return FALSE;
+  
+    GetCursorPos(&pt);
+    if (LISTVIEW_GetItemAtPt(infoPtr, pt) < 0) return FALSE;
 
-  SetCursor(infoPtr->hHotCursor);
+    SetCursor(infoPtr->hHotCursor);
 
-  return TRUE;
+    return TRUE;
 }
 
 /***
@@ -8588,24 +8540,31 @@
  *
  * PARAMETER(S):
  * [I] infoPtr : valid pointer to the listview structure
- * [I] infoPtr : valid pointer to the listview structureof previously focused window
+ * [I] infoPtr : handle of previously focused window
  *
  * RETURN:
  * Zero
  */
 static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus)
 {
-  TRACE("(hwndLoseFocus=%x)\n", hwndLoseFocus);
+    TRACE("(hwndLoseFocus=%x)\n", hwndLoseFocus);
 
-  /* send NM_SETFOCUS notification */
-  notify_setfocus(infoPtr);
+    /* if we have the focus already, there's nothing to do */
+    if (infoPtr->bFocus) return 0;
+   
+    /* send NM_SETFOCUS notification */
+    notify_setfocus(infoPtr);
 
-  /* set window focus flag */
-  infoPtr->bFocus = TRUE;
+    /* put the focus rect back on */
+    LISTVIEW_ToggleFocusRect(infoPtr);
 
-  UpdateWindow(infoPtr->hwndSelf);
+    /* set window focus flag */
+    infoPtr->bFocus = TRUE;
 
-  return 0;
+    /* redraw all visible selected items */
+    LISTVIEW_InvalidateSelectedItems(infoPtr);
+
+    return 0;
 }
 
 /***
@@ -8622,7 +8581,7 @@
  */
 static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw)
 {
-  UINT uView = get_listview_type(infoPtr);
+  UINT uView = LISTVIEW_GetType(infoPtr);
 
   TRACE("(hfont=%x,redraw=%hu)\n", hFont, fRedraw);
 



[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux