[PATCH 4/4] user32/listbox: Implement LBS_NODATA for multi-selection listboxes
Gabriel Ivăncescu
gabrielopcode at gmail.com
Fri Feb 22 06:00:59 CST 2019
Use a byte array to store selection state of items, since we don't need any
other data for LBS_NODATA multi-selection listboxes. This improves memory
usage dramatically for large lists, and performance boosts are nice too.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
dlls/user32/listbox.c | 48 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 41 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c
index 0e9f97c..cc06238 100644
--- a/dlls/user32/listbox.c
+++ b/dlls/user32/listbox.c
@@ -17,8 +17,6 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * TODO:
- * - LBS_NODATA for multi-selection listboxes
*/
#include <string.h>
@@ -122,6 +120,15 @@ static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+/*
+ Resize the item storage array if needed.
+
+ For single-selection LBS_NODATA listboxes, no storage is allocated,
+ and thus descr->items will always be NULL.
+
+ For multi-selection LBS_NODATA listboxes, one byte per item is stored
+ for the item's selection state, instead of the usual LB_ITEMDATA.
+*/
static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
{
LB_ITEMDATA *items;
@@ -132,7 +139,10 @@ static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
items_size = (items_size + LB_ARRAY_GRANULARITY - 1) & ~(LB_ARRAY_GRANULARITY - 1);
if ((descr->style & (LBS_NODATA | LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != LBS_NODATA)
{
- items = heap_realloc(descr->items, items_size * sizeof(LB_ITEMDATA));
+ size_t size = items_size;
+ if (!(descr->style & LBS_NODATA)) size *= sizeof(LB_ITEMDATA);
+
+ items = heap_realloc(descr->items, size);
if (!items)
{
SEND_NOTIFICATION(descr, LBN_ERRSPACE);
@@ -145,8 +155,7 @@ static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
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));
+ memset((BYTE*)descr->items + descr->nb_items, 0, items_size - descr->nb_items);
}
return TRUE;
}
@@ -175,13 +184,21 @@ static BOOL is_item_selected( const LB_DESCR *descr, UINT index )
{
if (!(descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)))
return index == descr->selected_item;
- return descr->items[index].selected;
+ if (descr->style & LBS_NODATA)
+ return ((BYTE*)descr->items)[index];
+ else
+ return descr->items[index].selected;
}
static void set_item_selected_state(LB_DESCR *descr, UINT index, BOOL state)
{
if (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
- descr->items[index].selected = state;
+ {
+ if (descr->style & LBS_NODATA)
+ ((BYTE*)descr->items)[index] = state;
+ else
+ descr->items[index].selected = state;
+ }
}
static void insert_item_data(LB_DESCR *descr, UINT index, WCHAR *str, ULONG_PTR data)
@@ -189,6 +206,15 @@ static void insert_item_data(LB_DESCR *descr, UINT index, WCHAR *str, ULONG_PTR
LB_ITEMDATA *item;
if (!descr->items) return;
+ if (descr->style & LBS_NODATA)
+ {
+ BYTE *item = (BYTE*)descr->items + index;
+
+ if (index < descr->nb_items)
+ memmove(item + 1, item, descr->nb_items - index);
+ *item = FALSE;
+ return;
+ }
item = descr->items + index;
if (index < descr->nb_items)
@@ -205,6 +231,14 @@ static void remove_item_data(LB_DESCR *descr, UINT index)
LB_ITEMDATA *item;
if (!descr->items) return;
+ if (descr->style & LBS_NODATA)
+ {
+ BYTE *item = (BYTE*)descr->items + index;
+
+ if (index < descr->nb_items)
+ memmove(item, item + 1, descr->nb_items - index);
+ return;
+ }
item = descr->items + index;
if (index < descr->nb_items)
--
2.20.1
More information about the wine-devel
mailing list