diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c index fad5a4831ff..0a39582b6fe 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)); } @@ -680,13 +685,40 @@ 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 ); } +/*********************************************************************** + * 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 */ @@ -1317,6 +1349,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 +1388,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 +1474,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 +1494,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 +1507,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 +1532,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 +2037,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 +2051,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 +2103,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 +2941,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 +3102,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 a73e6b91901..c6c1cd7c184 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);