user32: Add more listbox message tests, make them pass under Wine

Dmitry Timoshkov dmitry at codeweavers.com
Tue Oct 16 01:25:56 CDT 2007


Hello,

this patch should fix the bug 5449.

Changelog:
    user32: Add more listbox message tests, make them pass under Wine.

---
 dlls/user32/listbox.c   |   97 +++++++++++++++++++++++++++++++---------------
 dlls/user32/tests/msg.c |   91 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 143 insertions(+), 45 deletions(-)

diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c
index fad5a48..3a2e1b4 100644
--- a/dlls/user32/listbox.c
+++ b/dlls/user32/listbox.c
@@ -300,6 +300,9 @@ static void LISTBOX_UpdateScroll( LB_DESCR *descr )
 static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
 {
     INT max = LISTBOX_GetMaxTopIndex( descr );
+
+    TRACE("setting top item %d, scroll %d\n", index, scroll);
+
     if (index > max) index = max;
     if (index < 0) index = 0;
     if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
@@ -473,6 +476,8 @@ static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
         rect->right += descr->horz_pos;
     }
 
+    TRACE("item %d, rect %s\n", index, wine_dbgstr_rect(rect));
+
     return ((rect->left < descr->width) && (rect->right > 0) &&
             (rect->top < descr->height) && (rect->bottom > 0));
 }
@@ -533,8 +538,11 @@ static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
 static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect, 
 			       INT index, UINT action, BOOL ignoreFocus )
 {
-    LB_ITEMDATA *item = NULL;
-    if (index < descr->nb_items) item = &descr->items[index];
+    LB_ITEMDATA *item;
+
+    if (index >= descr->nb_items) return;
+    
+    item = &descr->items[index];
 
     if (IS_OWNERDRAW(descr))
     {
@@ -542,15 +550,6 @@ static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
         RECT r;
         HRGN hrgn;
 
-	if (!item)
-	{
-	    if (action == ODA_FOCUS)
-		DrawFocusRect( hdc, rect );
-	    else
-	        ERR("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
-	    return;
-	}
-
         /* some programs mess with the clipping region when
         drawing the item, *and* restore the previous region
         after they are done, so a region has better to exist
@@ -680,7 +679,7 @@ static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
     if (!IsWindowEnabled(descr->self))
         SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
     SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
-    LISTBOX_PaintItem( descr, hdc, &rect, index, action, FALSE );
+    LISTBOX_PaintItem( descr, hdc, &rect, index, action, TRUE );
     if (oldFont) SelectObject( hdc, oldFont );
     if (oldBrush) SelectObject( hdc, oldBrush );
     ReleaseDC( descr->self, hdc );
@@ -688,6 +687,33 @@ static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
 
 
 /***********************************************************************
+ *           LISTBOX_DrawFocusRect
+ */
+static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on )
+{
+    HDC hdc;
+    RECT rect;
+    HFONT oldFont = 0;
+
+    /* Do not repaint the item if the item is not visible */
+    if (!IsWindowVisible(descr->self)) return;
+
+    if (descr->focus_item == -1) return;
+    if (!descr->caret_on || !descr->in_focus) return;
+
+    if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) != 1) return;
+    if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
+    if (descr->font) oldFont = SelectObject( hdc, descr->font );
+    if (!IsWindowEnabled(descr->self))
+        SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
+    SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
+    LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, on ? FALSE : TRUE );
+    if (oldFont) SelectObject( hdc, oldFont );
+    ReleaseDC( descr->self, hdc );
+}
+
+
+/***********************************************************************
  *           LISTBOX_InitStorage
  */
 static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
@@ -1317,6 +1343,8 @@ static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully )
 {
     INT top;
 
+    TRACE("current top item %d, index %d, fully %d\n", descr->top_item, index, fully);
+
     if (index <= descr->top_item) top = index;
     else if (descr->style & LBS_MULTICOLUMN)
     {
@@ -1354,16 +1382,17 @@ static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_vis
 {
     INT oldfocus = descr->focus_item;
 
+    TRACE("old focus %d, index %d\n", oldfocus, index);
+
     if (descr->style & LBS_NOSEL) return LB_ERR;
     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
     if (index == oldfocus) return LB_OKAY;
+
+    LISTBOX_DrawFocusRect( descr, FALSE );
     descr->focus_item = index;
-    if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
-        LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
 
     LISTBOX_MakeItemVisible( descr, index, fully_visible );
-    if (descr->caret_on && (descr->in_focus))
-        LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
+    LISTBOX_DrawFocusRect( descr, TRUE );
 
     return LB_OKAY;
 }
@@ -1439,8 +1468,8 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
         if (index == oldsel) return LB_OKAY;
         if (oldsel != -1) descr->items[oldsel].selected = FALSE;
         if (index != -1) descr->items[index].selected = TRUE;
-        descr->selected_item = index;
         if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
+        descr->selected_item = index;
         if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
         if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
                                (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
@@ -1459,7 +1488,7 @@ static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
  */
 static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
 {
-    INT oldfocus = descr->focus_item;
+    TRACE("old focus %d, index %d\n", descr->focus_item, index);
 
     if ((index <  0) || (index >= descr->nb_items))
         return;
@@ -1472,9 +1501,7 @@ static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
        4. Set the focus to 'index' and repaint the item */
 
     /* 1. remove the focus and repaint the item */
-    descr->focus_item = -1;
-    if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
-        LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
+    LISTBOX_DrawFocusRect( descr, FALSE );
 
     /* 2. then turn off the previous selection */
     /* 3. repaint the new selected item */
@@ -1499,8 +1526,7 @@ static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
     /* 4. repaint the new item with the focus */
     descr->focus_item = index;
     LISTBOX_MakeItemVisible( descr, index, fully_visible );
-    if (descr->caret_on && (descr->in_focus))
-        LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
+    LISTBOX_DrawFocusRect( descr, TRUE );
 }
 
 
@@ -2005,7 +2031,10 @@ static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
 static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, INT y )
 {
     INT index = LISTBOX_GetItemFromPoint( descr, x, y );
-    TRACE("[%p]: lbuttondown %d,%d item %d\n", descr->self, x, y, index );
+
+    TRACE("[%p]: lbuttondown %d,%d item %d, focus item %d\n",
+          descr->self, x, y, index, descr->focus_item);
+
     if (!descr->caret_on && (descr->in_focus)) return 0;
 
     if (!descr->in_focus)
@@ -2016,6 +2045,16 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, IN
 
     if (index == -1) return 0;
 
+    if (!descr->lphc)
+    {
+        if (descr->style & LBS_NOTIFY )
+            SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
+                            MAKELPARAM( x, y ) );
+    }
+
+    descr->captured = TRUE;
+    SetCapture( descr->self );
+
     if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL))
     {
         /* we should perhaps make sure that all items are deselected
@@ -2058,14 +2097,8 @@ static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, IN
                               TRUE, (descr->style & LBS_NOTIFY) != 0 );
     }
 
-    descr->captured = TRUE;
-    SetCapture( descr->self );
-
     if (!descr->lphc)
     {
-        if (descr->style & LBS_NOTIFY )
-            SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
-                            MAKELPARAM( x, y ) );
         if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
         {
             POINT pt;
@@ -2902,7 +2935,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
         if (IS_MULTISELECT(descr)) return LB_ERR;
         LISTBOX_SetCaretIndex( descr, wParam, FALSE );
         ret = LISTBOX_SetSelection( descr, wParam, TRUE, FALSE );
-	if (lphc && ret != LB_ERR) ret = descr->selected_item;
+	if (ret != LB_ERR) ret = descr->selected_item;
 	return ret;
 
     case LB_GETSELCOUNT16:
@@ -3063,7 +3096,7 @@ static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
         descr->in_focus = TRUE;
         descr->caret_on = TRUE;
         if (descr->focus_item != -1)
-            LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
+            LISTBOX_DrawFocusRect( descr, TRUE );
         SEND_NOTIFICATION( descr, LBN_SETFOCUS );
         return 0;
     case WM_KILLFOCUS:
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index a73e6b9..c6c1cd7 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9848,16 +9848,63 @@ static const struct message wm_lb_setcursel_0[] =
 {
     { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
     { WM_CTLCOLORLISTBOX, sent|parent },
-    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x00120f2 },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
+    { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
     { 0 }
 };
 static const struct message wm_lb_setcursel_1[] =
 {
     { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
     { WM_CTLCOLORLISTBOX, sent|parent },
-    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x00020f2 },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
     { WM_CTLCOLORLISTBOX, sent|parent },
-    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x00121f2 },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
+    { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
+    { 0 }
+};
+static const struct message wm_lb_setcursel_2[] =
+{
+    { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
+    { WM_CTLCOLORLISTBOX, sent|parent },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
+    { WM_CTLCOLORLISTBOX, sent|parent },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
+    { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
+    { 0 }
+};
+static const struct message wm_lb_click_0[] =
+{
+    { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
+    { HCBT_SETFOCUS, hook },
+    { WM_KILLFOCUS, sent|parent },
+    { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
+    { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
+    { WM_SETFOCUS, sent },
+
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
+    { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
+    { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
+    { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
+
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
+    { WM_CTLCOLORLISTBOX, sent|parent },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
+    { WM_CTLCOLORLISTBOX, sent|parent },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
+    { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
+
+    { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
+    { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
+
+    { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
+    { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
+    { WM_CAPTURECHANGED, sent|wparam|lparam, 0, 0 },
+    { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
     { 0 }
 };
 
@@ -9896,13 +9943,14 @@ static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
 {
     LRESULT ret;
 
-    ret = SendMessage(listbox, LB_GETCOUNT, 0, 0);
+    /* calling an orig proc helps to avoid unnecessary message logging */
+    ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
     ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
-    ret = SendMessage(listbox, LB_GETCURSEL, 0, 0);
+    ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
     ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
-    ret = SendMessage(listbox, LB_GETCARETINDEX, 0, 0);
+    ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
     ok_(__FILE__, line)(ret == caret_index, "expected caret index %d, got %ld\n", caret_index, ret);
-    ret = SendMessage(listbox, LB_GETTOPINDEX, 0, 0);
+    ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
     ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
 }
 
@@ -9915,16 +9963,16 @@ static void test_listbox(void)
                              100, 100, 200, 200, 0, 0, 0, NULL);
     listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
                               WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
-                              10, 10, 80, 20, parent, (HMENU)ID_LISTBOX, 0, NULL);
+                              10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
     listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
 
     check_lb_state(listbox, 0, LB_ERR, 0, 0);
 
-    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
+    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
     ok(ret == 0, "expected 0, got %ld\n", ret);
-    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
+    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
     ok(ret == 1, "expected 1, got %ld\n", ret);
-    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 3");
+    ret = SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
     ok(ret == 2, "expected 2, got %ld\n", ret);
 
     check_lb_state(listbox, 3, LB_ERR, 0, 0);
@@ -9934,16 +9982,33 @@ static void test_listbox(void)
     log_all_parent_messages++;
 
     trace("selecting item 0\n");
-    SendMessage(listbox, LB_SETCURSEL, 0, 0);
+    ret = SendMessage(listbox, LB_SETCURSEL, 0, 0);
+    ok(ret == 0, "expected 0, got %ld\n", ret);
     ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
     check_lb_state(listbox, 3, 0, 0, 0);
     flush_sequence();
 
     trace("selecting item 1\n");
-    SendMessage(listbox, LB_SETCURSEL, 1, 0);
+    ret = SendMessage(listbox, LB_SETCURSEL, 1, 0);
+    ok(ret == 1, "expected 1, got %ld\n", ret);
     ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
     check_lb_state(listbox, 3, 1, 1, 0);
 
+    trace("selecting item 2\n");
+    ret = SendMessage(listbox, LB_SETCURSEL, 2, 0);
+    ok(ret == 2, "expected 2, got %ld\n", ret);
+    ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
+    check_lb_state(listbox, 3, 2, 2, 0);
+
+    trace("clicking on item 0\n");
+    ret = SendMessage(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
+    ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
+    ret = SendMessage(listbox, WM_LBUTTONUP, 0, 0);
+    ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
+    ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
+    check_lb_state(listbox, 3, 0, 0, 0);
+    flush_sequence();
+
     log_all_parent_messages--;
 
     DestroyWindow(parent);
-- 
1.5.3.4






More information about the wine-patches mailing list