Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/user32/listbox.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 826ce01..9bf9f90 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -156,6 +156,11 @@ static ULONG_PTR get_item_data( const LB_DESCR *descr, UINT index ) return (descr->style & LBS_NODATA) ? 0 : descr->items[index].data; }
+static void set_item_data( LB_DESCR *descr, UINT index, ULONG_PTR data ) +{ + if (!(descr->style & LBS_NODATA)) descr->items[index].data = data; +} + static WCHAR *get_item_string( const LB_DESCR *descr, UINT index ) { return HAS_STRINGS(descr) ? descr->items[index].str : NULL; @@ -2743,7 +2748,7 @@ LRESULT ListBoxWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam SetLastError(ERROR_INVALID_INDEX); return LB_ERR; } - if (!(descr->style & LBS_NODATA)) descr->items[wParam].data = lParam; + set_item_data(descr, wParam, lParam); /* undocumented: returns TRUE, not LB_OKAY (0) */ return TRUE;
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/user32/listbox.c | 57 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 30 deletions(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 9bf9f90..75257ad 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -1003,8 +1003,7 @@ static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str ) */ static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact ) { - INT i; - LB_ITEMDATA *item; + INT i, index;
if (descr->style & LBS_NODATA) { @@ -1012,41 +1011,38 @@ static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exa return LB_ERR; }
- if (start >= descr->nb_items) start = -1; - item = descr->items + start + 1; + start++; + if (start >= descr->nb_items) start = 0; if (HAS_STRINGS(descr)) { if (!str || ! str[0] ) return LB_ERR; if (exact) { - for (i = start + 1; i < descr->nb_items; i++, item++) - if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; - for (i = 0, item = descr->items; i <= start; i++, item++) - if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i; + for (i = 0, index = start; i < descr->nb_items; i++, index++) + { + if (index == descr->nb_items) index = 0; + if (!LISTBOX_lstrcmpiW(descr->locale, str, get_item_string(descr, index))) + return index; + } } else { - /* Special case for drives and directories: ignore prefix */ -#define CHECK_DRIVE(item) \ - if ((item)->str[0] == '[') \ - { \ - if (!strncmpiW( str, (item)->str+1, len )) return i; \ - if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \ - return i; \ - } - + /* Special case for drives and directories: ignore prefix */ INT len = strlenW(str); - for (i = start + 1; i < descr->nb_items; i++, item++) - { - if (!strncmpiW( str, item->str, len )) return i; - CHECK_DRIVE(item); - } - for (i = 0, item = descr->items; i <= start; i++, item++) + WCHAR *item_str; + + for (i = 0, index = start; i < descr->nb_items; i++, index++) { - if (!strncmpiW( str, item->str, len )) return i; - CHECK_DRIVE(item); + if (index == descr->nb_items) index = 0; + item_str = get_item_string(descr, index); + + if (!strncmpiW(str, item_str, len)) return index; + if (item_str[0] == '[') + { + if (!strncmpiW(str, item_str + 1, len)) return index; + if (item_str[1] == '-' && !strncmpiW(str, item_str + 2, len)) return index; + } } -#undef CHECK_DRIVE } } else @@ -1056,10 +1052,11 @@ static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exa return LISTBOX_FindStringPos( descr, str, TRUE );
/* Otherwise use a linear search */ - for (i = start + 1; i < descr->nb_items; i++, item++) - if (item->data == (ULONG_PTR)str) return i; - for (i = 0, item = descr->items; i <= start; i++, item++) - if (item->data == (ULONG_PTR)str) return i; + for (i = 0, index = start; i < descr->nb_items; i++, index++) + { + if (index == descr->nb_items) index = 0; + if (get_item_data(descr, index) == (ULONG_PTR)str) return index; + } } return LB_ERR; }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=48417
Your paranoid android.
=== debian9 (32 bit report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (32 bit Chinese:China report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (32 bit WoW report) ===
user32: menu.c:2354: Test failed: test 23 menu: Timeout
Signed-off-by: Huw Davies huw@codeweavers.com
From: Huw Davies huw@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/user32/listbox.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 75257ad..127ba35 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -166,6 +166,11 @@ static WCHAR *get_item_string( const LB_DESCR *descr, UINT index ) return HAS_STRINGS(descr) ? descr->items[index].str : NULL; }
+static void set_item_string( const LB_DESCR *descr, UINT index, WCHAR *string ) +{ + if (!(descr->style & LBS_NODATA)) descr->items[index].str = string; +} + static UINT get_item_height( const LB_DESCR *descr, UINT index ) { return (descr->style & LBS_NODATA) ? 0 : descr->items[index].height; @@ -189,7 +194,7 @@ static void set_item_selected_state(LB_DESCR *descr, UINT index, BOOL state) descr->items[index].selected = state; }
-static void insert_item_data(LB_DESCR *descr, UINT index, WCHAR *str, ULONG_PTR data) +static void insert_item_data(LB_DESCR *descr, UINT index) { LB_ITEMDATA *item;
@@ -198,11 +203,6 @@ static void insert_item_data(LB_DESCR *descr, UINT index, WCHAR *str, ULONG_PTR item = descr->items + index; if (index < descr->nb_items) memmove(item + 1, item, (descr->nb_items - index) * sizeof(LB_ITEMDATA)); - - item->str = str; - item->data = HAS_STRINGS(descr) ? 0 : data; - item->height = 0; - item->selected = FALSE; }
static void remove_item_data(LB_DESCR *descr, UINT index) @@ -1609,8 +1609,12 @@ static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index, else if ((index < 0) || (index > descr->nb_items)) return LB_ERR; if (!resize_storage(descr, descr->nb_items + 1)) return LB_ERR;
- insert_item_data(descr, index, str, data); + insert_item_data(descr, index); descr->nb_items++; + set_item_string(descr, index, str); + set_item_data(descr, index, HAS_STRINGS(descr) ? 0 : data); + set_item_height(descr, index, 0); + set_item_selected_state(descr, index, FALSE);
/* Get item height */
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/user32/listbox.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 127ba35..219910b 100644 --- a/dlls/user32/listbox.c +++ b/dlls/user32/listbox.c @@ -122,6 +122,11 @@ static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+static size_t get_sizeof_item( const LB_DESCR *descr ) +{ + return sizeof(LB_ITEMDATA); +} + static BOOL resize_storage(LB_DESCR *descr, UINT items_size) { LB_ITEMDATA *items; @@ -132,7 +137,7 @@ 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)); + items = heap_realloc(descr->items, items_size * get_sizeof_item(descr)); if (!items) { SEND_NOTIFICATION(descr, LBN_ERRSPACE); @@ -146,7 +151,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)); + (items_size - descr->nb_items) * get_sizeof_item(descr)); } return TRUE; } @@ -196,24 +201,26 @@ static void set_item_selected_state(LB_DESCR *descr, UINT index, BOOL state)
static void insert_item_data(LB_DESCR *descr, UINT index) { + size_t size = get_sizeof_item(descr); LB_ITEMDATA *item;
if (!descr->items) return;
item = descr->items + index; if (index < descr->nb_items) - memmove(item + 1, item, (descr->nb_items - index) * sizeof(LB_ITEMDATA)); + memmove(item + 1, item, (descr->nb_items - index) * size); }
static void remove_item_data(LB_DESCR *descr, UINT index) { + size_t size = get_sizeof_item(descr); LB_ITEMDATA *item;
if (!descr->items) return;
item = descr->items + index; if (index < descr->nb_items) - memmove(item, item + 1, (descr->nb_items - index) * sizeof(LB_ITEMDATA)); + memmove(item, item + 1, (descr->nb_items - index) * size); }
/*********************************************************************
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=48419
Your paranoid android.
=== debian9 (32 bit report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (32 bit Chinese:China report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (32 bit WoW report) ===
user32: menu.c:2354: Test failed: test 21 menu: Timeout msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (64 bit WoW report) ===
user32: clipboard.c:760: Test failed: 4: gle 5 clipboard.c:765: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:805: Test failed: 4: gle 1418 clipboard.c:815: Test failed: 4: count 2 clipboard.c:818: Test failed: 4: gle 1418 clipboard.c:852: Test failed: 4: format 0003 got data 0x1c512 clipboard.c:853: Test failed: 4.0: formats 00000000 have been rendered clipboard.c:858: Test failed: 4.0: formats 00000000 have been rendered clipboard.c:852: Test failed: 4: format 000e got data 0x20045 clipboard.c:853: Test failed: 4.1: formats 00000000 have been rendered clipboard.c:858: Test failed: 4.1: formats 00000000 have been rendered msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
Signed-off-by: Huw Davies huw@codeweavers.com
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@gmail.com --- dlls/user32/listbox.c | 72 +++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 27 deletions(-)
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index 219910b..95621b8 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> @@ -66,7 +64,11 @@ typedef struct UINT style; /* Window style */ INT width; /* Window width */ INT height; /* Window height */ - LB_ITEMDATA *items; /* Array of items */ + union + { + LB_ITEMDATA *items; /* Array of items */ + BYTE *nodata_items; /* For multi-selection LBS_NODATA */ + } u; INT nb_items; /* Number of items */ UINT items_size; /* Total number of allocated items in the array */ INT top_item; /* Top visible item */ @@ -122,9 +124,19 @@ static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
+/* + For listboxes without LBS_NODATA, an array of LB_ITEMDATA is allocated + to store the states of each item into descr->u.items. + + For single-selection LBS_NODATA listboxes, no storage is allocated, + and thus descr->u.nodata_items will always be NULL. + + For multi-selection LBS_NODATA listboxes, one byte per item is stored + for the item's selection state into descr->u.nodata_items. +*/ static size_t get_sizeof_item( const LB_DESCR *descr ) { - return sizeof(LB_ITEMDATA); + return (descr->style & LBS_NODATA) ? sizeof(BYTE) : sizeof(LB_ITEMDATA); }
static BOOL resize_storage(LB_DESCR *descr, UINT items_size) @@ -137,20 +149,20 @@ 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 * get_sizeof_item(descr)); + items = heap_realloc(descr->u.items, items_size * get_sizeof_item(descr)); if (!items) { SEND_NOTIFICATION(descr, LBN_ERRSPACE); return FALSE; } - descr->items = items; + descr->u.items = items; } descr->items_size = items_size; }
- if ((descr->style & LBS_NODATA) && descr->items && items_size > descr->nb_items) + if ((descr->style & LBS_NODATA) && descr->u.nodata_items && items_size > descr->nb_items) { - memset(&descr->items[descr->nb_items], 0, + memset(descr->u.nodata_items + descr->nb_items, 0, (items_size - descr->nb_items) * get_sizeof_item(descr)); } return TRUE; @@ -158,69 +170,75 @@ static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
static ULONG_PTR get_item_data( const LB_DESCR *descr, UINT index ) { - return (descr->style & LBS_NODATA) ? 0 : descr->items[index].data; + return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].data; }
static void set_item_data( LB_DESCR *descr, UINT index, ULONG_PTR data ) { - if (!(descr->style & LBS_NODATA)) descr->items[index].data = data; + if (!(descr->style & LBS_NODATA)) descr->u.items[index].data = data; }
static WCHAR *get_item_string( const LB_DESCR *descr, UINT index ) { - return HAS_STRINGS(descr) ? descr->items[index].str : NULL; + return HAS_STRINGS(descr) ? descr->u.items[index].str : NULL; }
static void set_item_string( const LB_DESCR *descr, UINT index, WCHAR *string ) { - if (!(descr->style & LBS_NODATA)) descr->items[index].str = string; + if (!(descr->style & LBS_NODATA)) descr->u.items[index].str = string; }
static UINT get_item_height( const LB_DESCR *descr, UINT index ) { - return (descr->style & LBS_NODATA) ? 0 : descr->items[index].height; + return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].height; }
static void set_item_height( LB_DESCR *descr, UINT index, UINT height ) { - if (!(descr->style & LBS_NODATA)) descr->items[index].height = height; + if (!(descr->style & LBS_NODATA)) descr->u.items[index].height = height; }
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 descr->u.nodata_items[index]; + else + return descr->u.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) + descr->u.nodata_items[index] = state; + else + descr->u.items[index].selected = state; + } }
static void insert_item_data(LB_DESCR *descr, UINT index) { size_t size = get_sizeof_item(descr); - LB_ITEMDATA *item; + BYTE *p = descr->u.nodata_items + index * size;
- if (!descr->items) return; + if (!descr->u.items) return;
- item = descr->items + index; if (index < descr->nb_items) - memmove(item + 1, item, (descr->nb_items - index) * size); + memmove(p + size, p, (descr->nb_items - index) * size); }
static void remove_item_data(LB_DESCR *descr, UINT index) { size_t size = get_sizeof_item(descr); - LB_ITEMDATA *item; + BYTE *p = descr->u.nodata_items + index * size;
- if (!descr->items) return; + if (!descr->u.items) return;
- item = descr->items + index; if (index < descr->nb_items) - memmove(item, item + 1, (descr->nb_items - index) * size); + memmove(p, p + size, (descr->nb_items - index) * size); }
/********************************************************************* @@ -1792,14 +1810,14 @@ static void LISTBOX_ResetContent( LB_DESCR *descr )
if (!(descr->style & LBS_NODATA)) for (i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i); - HeapFree( GetProcessHeap(), 0, descr->items ); + HeapFree( GetProcessHeap(), 0, descr->u.items ); descr->nb_items = 0; descr->top_item = 0; descr->selected_item = -1; descr->focus_item = 0; descr->anchor_item = -1; descr->items_size = 0; - descr->items = NULL; + descr->u.items = NULL; }
@@ -2550,7 +2568,7 @@ static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc ) descr->style = GetWindowLongW( descr->self, GWL_STYLE ); descr->width = rect.right - rect.left; descr->height = rect.bottom - rect.top; - descr->items = NULL; + descr->u.items = NULL; descr->items_size = 0; descr->nb_items = 0; descr->top_item = 0;
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=48420
Your paranoid android.
=== debian9 (32 bit report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
Signed-off-by: Huw Davies huw@codeweavers.com
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=48416
Your paranoid android.
=== debian9 (32 bit Chinese:China report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000
=== debian9 (32 bit WoW report) ===
user32: msg.c:8713: Test failed: WaitForSingleObject failed 102 msg.c:8719: Test failed: destroy child on thread exit: 0: the msg 0x0082 was expected, but got msg 0x000f instead msg.c:8719: Test failed: destroy child on thread exit: 1: the msg 0x000f was expected, but got msg 0x0014 instead msg.c:8719: Test failed: destroy child on thread exit: 2: the msg sequence is not complete: expected 0014 - actual 0000