[PATCH v3 3/4] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes

Gabriel Iv─âncescu gabrielopcode at gmail.com
Mon Feb 18 06:09:05 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>
---

Hopefully the patch is small enough now.

I have kept the check in ResetContent because it reduces algorithm complexity
from O(n) to O(1) and does not depend on the list size. LBS_NODATA listboxes
can be large and possibly have millions of virtual items (that's what
they are for), so I think a single extra line check is really worth it
to avoid this scenario (it can reduce annoying stuttering when resetting
such a listbox to instant), and also to be consistent with SetCount(0) in
effect. The linked bug report is an indirect example of such case (an IDE
with a large database: https://forum.winehq.org/viewtopic.php?f=8&t=17812).

As a bonus, it also cleans up the formatting since it indents the line
anyway. This will also help with multi-selection nodata listboxes later.

 dlls/comctl32/listbox.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index 214bfb0..423d044 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>
@@ -128,6 +128,16 @@ 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)
 {
     LB_ITEMDATA *items;
@@ -136,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));
@@ -181,6 +194,7 @@ static void insert_item_data(LB_DESCR *descr, INT index, WCHAR *str, ULONG_PTR d
 {
     LB_ITEMDATA *item;
 
+    if (is_singlesel_NODATA(descr)) return;
     item = &descr->items[index];
 
     if (index < descr->nb_items - 1)
@@ -211,6 +225,8 @@ static void insert_item_data(LB_DESCR *descr, INT index, WCHAR *str, ULONG_PTR d
 
 static void remove_item_data(LB_DESCR *descr, INT index)
 {
+    if (is_singlesel_NODATA(descr)) return;
+
     LISTBOX_DeleteItem(descr, index);
     if (index < descr->nb_items)
         RtlMoveMemory(&descr->items[index], &descr->items[index + 1],
@@ -1751,7 +1767,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