[2/2] comctl32/listview: Don't check for state changes we are not aware to store (with some tests)

Nikolay Sivov bunglehead at gmail.com
Tue May 12 17:25:19 CDT 2009


http://bugs.winehq.org/show_bug.cgi?id=5131

Control affected in this bug has LVS_OWNERDATA style and
callback mask set LVIS_OVERLAYMASK. That causes to uneeded LVN_GETDISPINFO
notifications sent to parent (we're checking for not zero mask)
that leads to infinite loop for this application.

Setting item state we're checking for changes. In ownerdata case
there's no need to query for whole status word (initial patch seems to be
correct here).

Changelog:
    - Don't check for state changes we are not aware to store (with some tests)

>From edf2b4c1ec76906c4e6cb02a6c6e4428972349f1 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <bunglehead at gmail.com>
Date: Wed, 13 May 2009 02:09:18 +0400
Subject: Don't check for state changes we are not aware to store

---
 dlls/comctl32/listview.c       |    6 +++-
 dlls/comctl32/tests/listview.c |   52 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index f31175f..2f99ad2 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -3508,7 +3508,8 @@ static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL
     item.iItem = lpLVItem->iItem;
     item.iSubItem = lpLVItem->iSubItem;
     item.mask = LVIF_STATE | LVIF_PARAM;
-    item.stateMask = ~0;
+    item.stateMask = (infoPtr->dwStyle & LVS_OWNERDATA) ? LVIS_FOCUSED | LVIS_SELECTED : ~0;
+
     item.state = 0;
     item.lParam = 0;
     if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE;
@@ -5553,7 +5554,8 @@ static BOOL LISTVIEW_GetItemT(const LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem,
 	dispInfo.item.state = 0;
 
 	/* apparently, we should not callback for lParam in LVS_OWNERDATA */
-	if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) || infoPtr->uCallbackMask)
+	if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) ||
+	   ((lpLVItem->mask & LVIF_STATE) && (infoPtr->uCallbackMask & lpLVItem->stateMask)))
 	{
 	    UINT mask = lpLVItem->mask;
 
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index 43eb274..6386655 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -180,6 +180,11 @@ static const struct message textcallback_set_again_parent_seq[] = {
     { 0 }
 };
 
+static const struct message single_getdispinfo_parent_seq[] = {
+    { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
+    { 0 }
+};
+
 struct subclass_info
 {
     WNDPROC oldproc;
@@ -2045,6 +2050,53 @@ static void test_ownerdata(void)
     ok_sequence(sequences, PARENT_SEQ_INDEX, ownderdata_select_focus_parent_seq,
                 "ownerdata focus notification", TRUE);
     DestroyWindow(hwnd);
+
+    /* check notifications on LVM_GETITEM */
+    /* zero callback mask */
+    hwnd = create_listview_control(LVS_OWNERDATA);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    res = SendMessageA(hwnd, LVM_SETITEMCOUNT, 1, 0);
+    ok(res != 0, "Expected LVM_SETITEMCOUNT to succeed\n");
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "ownerdata getitem selected state 1", FALSE);
+
+    /* non zero callback mask but not we asking for */
+    res = SendMessageA(hwnd, LVM_SETCALLBACKMASK, LVIS_OVERLAYMASK, 0);
+    expect(TRUE, res);
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_SELECTED;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+                "ownerdata getitem selected state 2", FALSE);
+
+    /* LVIS_OVERLAYMASK callback mask, asking for index */
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+    memset(&item, 0, sizeof(item));
+    item.stateMask = LVIS_OVERLAYMASK;
+    item.mask      = LVIF_STATE;
+    res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, res);
+
+    ok_sequence(sequences, PARENT_SEQ_INDEX, single_getdispinfo_parent_seq,
+                "ownerdata getitem selected state 2", FALSE);
+
+    DestroyWindow(hwnd);
 }
 
 static void test_norecompute(void)
-- 
1.5.6.5





More information about the wine-patches mailing list