[PATCH v4 3/4] comctl32/listbox: Implement LBS_NODATA for single-selection listboxes
Gabriel Ivăncescu
gabrielopcode at gmail.com
Mon Feb 18 07:47:53 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>
---
v4: Get rid of the nodata helpers and open code the checks.
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 | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index 214bfb0..032a3b3 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>
@@ -136,17 +136,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 ((descr->style & (LBS_NODATA | LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != LBS_NODATA)
{
- 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 ((descr->style & LBS_NODATA) && descr->items && items_size > descr->nb_items)
{
memset(&descr->items[descr->nb_items], 0,
(items_size - descr->nb_items) * sizeof(LB_ITEMDATA));
@@ -181,6 +184,7 @@ static void insert_item_data(LB_DESCR *descr, INT index, WCHAR *str, ULONG_PTR d
{
LB_ITEMDATA *item;
+ if (!descr->items) return;
item = &descr->items[index];
if (index < descr->nb_items - 1)
@@ -211,6 +215,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 (!descr->items) return;
+
LISTBOX_DeleteItem(descr, index);
if (index < descr->nb_items)
RtlMoveMemory(&descr->items[index], &descr->items[index + 1],
@@ -1751,7 +1757,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