[PATCH v2 10/10] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes

Gabriel Ivăncescu gabrielopcode at gmail.com
Mon Feb 11 11:03:13 CST 2019


The LBS_NODATA style's purpose is to drastically improve performance and
memory usage on very large lists, since they should function as virtual
lists. Thus, don't store any data for single-selection listboxes (descr->items
always NULL).

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=32374
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

remove_item is part of this patch because it would otherwise have to be
rewritten due to indentation, amounting to same amount of changes, and it's
just moving the small part into a helper. The patch should be small enough
now, hopefully.

 dlls/comctl32/listbox.c | 59 +++++++++++++++++++++++++++--------------
 1 file changed, 39 insertions(+), 20 deletions(-)

diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index 1f56c99..1b8f874 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -19,7 +19,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * TODO:
- *    - LBS_NODATA
+ *    - LBS_NODATA for multi-selection listboxes
  */
 
 #include <string.h>
@@ -126,6 +126,17 @@ typedef enum
 static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
 
 static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index );
+
+static BOOL is_singlesel_NODATA(const LB_DESCR *descr)
+{
+    return (descr->style & (LBS_NODATA | LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) == LBS_NODATA;
+}
+
+static BOOL is_multisel_NODATA(const LB_DESCR *descr)
+{
+    return (descr->style & LBS_NODATA) && (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL));
+}
 
 static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
 {
@@ -135,17 +146,20 @@ static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
         items_size + LB_ARRAY_GRANULARITY * 2 < descr->items_size)
     {
         items_size = (items_size + LB_ARRAY_GRANULARITY - 1) & ~(LB_ARRAY_GRANULARITY - 1);
-        items = heap_realloc(descr->items, items_size * sizeof(LB_ITEMDATA));
-        if (!items)
+        if (!is_singlesel_NODATA(descr))
         {
-            SEND_NOTIFICATION(descr, LBN_ERRSPACE);
-            return FALSE;
+            items = heap_realloc(descr->items, items_size * sizeof(LB_ITEMDATA));
+            if (!items)
+            {
+                SEND_NOTIFICATION(descr, LBN_ERRSPACE);
+                return FALSE;
+            }
+            descr->items = items;
         }
         descr->items_size = items_size;
-        descr->items = items;
     }
 
-    if ((descr->style & LBS_NODATA) && items_size > descr->nb_items)
+    if (is_multisel_NODATA(descr) && items_size > descr->nb_items)
     {
         memset(&descr->items[descr->nb_items], 0,
                (items_size - descr->nb_items) * sizeof(LB_ITEMDATA));
@@ -186,6 +200,7 @@ static void insert_item(LB_DESCR *descr, INT index, WCHAR *str, ULONG_PTR data)
 {
     LB_ITEMDATA *item;
 
+    if (is_singlesel_NODATA(descr)) return;
     item = &descr->items[index];
 
     if (index < descr->nb_items - 1)
@@ -214,6 +229,20 @@ static void insert_item(LB_DESCR *descr, INT index, WCHAR *str, ULONG_PTR data)
     }
 }
 
+static void remove_item(LB_DESCR *descr, INT index)
+{
+    if (!is_singlesel_NODATA(descr))
+    {
+        LB_ITEMDATA *item = &descr->items[index];
+
+        LISTBOX_DeleteItem(descr, index);
+        if (index < descr->nb_items)
+            RtlMoveMemory(item, item + 1,
+                          (descr->nb_items - index) * sizeof(LB_ITEMDATA));
+    }
+    descr->anchor_item = min(descr->anchor_item, descr->nb_items - 1);
+}
+
 /***********************************************************************
  *           LISTBOX_GetCurrentPageSize
  *
@@ -1696,8 +1725,6 @@ static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
  */
 static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
 {
-    LB_ITEMDATA *item;
-
     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
 
     /* We need to invalidate the original rect instead of the updated one. */
@@ -1709,16 +1736,7 @@ static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
         return LB_OKAY;
     }
     descr->nb_items--;
-    LISTBOX_DeleteItem( descr, index );
-
-    /* Remove the item */
-
-    item = &descr->items[index];
-    if (index < descr->nb_items)
-        RtlMoveMemory( item, item + 1,
-                       (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
-    if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
-
+    remove_item(descr, index);
     resize_storage(descr, descr->nb_items);
 
     /* Repaint the items */
@@ -1758,7 +1776,8 @@ static void LISTBOX_ResetContent( LB_DESCR *descr )
 {
     INT i;
 
-    for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
+    if (!(descr->style & LBS_NODATA))
+        for(i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i);
     HeapFree( GetProcessHeap(), 0, descr->items );
     descr->nb_items      = 0;
     descr->top_item      = 0;
-- 
2.20.1




More information about the wine-devel mailing list