diff --git a/rostests/winetests/comctl32/button.c b/rostests/winetests/comctl32/button.c index f368bfcb650..b56b1af7875 100644 --- a/rostests/winetests/comctl32/button.c +++ b/rostests/winetests/comctl32/button.c @@ -321,6 +321,7 @@ static const struct message setstyle_seq[] = { WM_PAINT, sent }, { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, + { WM_PAINT, sent|optional }, { 0 } }; @@ -368,6 +369,7 @@ static const struct message setstate_seq[] = { WM_PAINT, sent }, { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */ { WM_ERASEBKGND, sent|defwinproc|optional }, + { WM_PAINT, sent|optional }, { 0 } }; @@ -429,6 +431,7 @@ static const struct message setcheck_ignored_seq[] = { { BM_SETCHECK, sent }, { WM_APP, sent|wparam|lparam, 0, 0 }, + { WM_PAINT, sent|optional }, { 0 } }; diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c index 468da56a2cb..9387fcb25e1 100644 --- a/rostests/winetests/comctl32/listview.c +++ b/rostests/winetests/comctl32/listview.c @@ -179,6 +179,16 @@ static const struct message listview_ownerdata_switchto_seq[] = { static const struct message listview_getorderarray_seq[] = { { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID }, { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID }, + { LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID }, + { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID }, + { 0 } +}; + +static const struct message listview_setorderarray_seq[] = { + { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID }, + { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID }, + { LVM_SETCOLUMNORDERARRAY, sent|id|wparam, 0, 0, LISTVIEW_ID }, + { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID }, { 0 } }; @@ -1416,13 +1426,28 @@ static void test_items(void) static void test_columns(void) { - HWND hwnd; + HWND hwnd, header; LVCOLUMNA column; LVITEMA item; INT order[2]; CHAR buff[5]; DWORD rc; + hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_LIST, + 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); + ok(hwnd != NULL, "failed to create listview window\n"); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(header == NULL, "got %p\n", header); + + rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 2, (LPARAM)&order); + ok(rc == 0, "got %d\n", rc); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(header == NULL, "got %p\n", header); + + DestroyWindow(hwnd); + hwnd = CreateWindowExA(0, "SysListView32", "foo", LVS_REPORT, 10, 10, 100, 200, hwndparent, NULL, NULL, NULL); ok(hwnd != NULL, "failed to create listview window\n"); @@ -1460,8 +1485,24 @@ static void test_columns(void) ok(order[0] == 0, "Expected order 0, got %d\n", order[0]); ok(order[1] == 1, "Expected order 1, got %d\n", order[1]); + rc = SendMessageA(hwnd, LVM_GETCOLUMNORDERARRAY, 0, 0); + expect(0, rc); + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_getorderarray_seq, "get order array", FALSE); + /* LVM_SETCOLUMNORDERARRAY */ + flush_sequences(sequences, NUM_MSG_SEQUENCES); + + order[0] = 0; + order[1] = 1; + rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 2, (LPARAM)&order); + expect(1, rc); + + rc = SendMessageA(hwnd, LVM_SETCOLUMNORDERARRAY, 0, 0); + expect(0, rc); + + ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_setorderarray_seq, "set order array", FALSE); + /* after column added subitem is considered as present */ insert_item(hwnd, 0); @@ -3877,7 +3918,6 @@ static void test_getitemrect(void) LVCOLUMNA col; INT order[2]; POINT pt; - HDC hdc; /* rectangle isn't empty for empty text items */ hwnd = create_listview_control(LVS_LIST); @@ -3891,9 +3931,9 @@ static void test_getitemrect(void) expect(TRUE, r); expect(0, rect.left); expect(0, rect.top); - hdc = GetDC(hwnd); - todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, rect.right); - ReleaseDC(hwnd, hdc); + /* estimate it as width / height ratio */ +todo_wine + ok((rect.right / rect.bottom) >= 5, "got right %d, bottom %d\n", rect.right, rect.bottom); DestroyWindow(hwnd); hwnd = create_listview_control(LVS_REPORT); @@ -4557,6 +4597,12 @@ static void test_get_set_view(void) style = GetWindowLongPtrA(hwnd, GWL_STYLE); ok(style & LVS_LIST, "Expected style to be preserved\n"); + /* now change window style to see if view is remapped */ + style = GetWindowLongPtrA(hwnd, GWL_STYLE); + SetWindowLongPtrA(hwnd, GWL_STYLE, style | LVS_SHOWSELALWAYS); + ret = SendMessageA(hwnd, LVM_GETVIEW, 0, 0); + expect(LV_VIEW_SMALLICON, ret); + DestroyWindow(hwnd); } @@ -4789,6 +4835,36 @@ static void test_getitemspacing(void) DestroyWindow(hwnd); } +static INT get_current_font_height(HWND listview) +{ + TEXTMETRICA tm; + HFONT hfont; + HWND hwnd; + HDC hdc; + + hwnd = (HWND)SendMessageA(listview, LVM_GETHEADER, 0, 0); + if (!hwnd) + hwnd = listview; + + hfont = (HFONT)SendMessageA(hwnd, WM_GETFONT, 0, 0); + if (!hfont) { + hdc = GetDC(hwnd); + GetTextMetricsA(hdc, &tm); + ReleaseDC(hwnd, hdc); + } + else { + HFONT oldfont; + + hdc = GetDC(0); + oldfont = SelectObject(hdc, hfont); + GetTextMetricsA(hdc, &tm); + SelectObject(hdc, oldfont); + ReleaseDC(0, hdc); + } + + return tm.tmHeight; +} + static void test_getcolumnwidth(void) { HWND hwnd; @@ -4796,7 +4872,7 @@ static void test_getcolumnwidth(void) DWORD_PTR style; LVCOLUMNA col; LVITEMA itema; - HDC hdc; + INT height; /* default column width */ hwnd = create_listview_control(LVS_ICON); @@ -4820,9 +4896,8 @@ static void test_getcolumnwidth(void) memset(&itema, 0, sizeof(itema)); SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&itema); ret = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0); - hdc = GetDC(hwnd); - todo_wine expect(((GetDeviceCaps(hdc, LOGPIXELSX) + 15) / 16) * 16, ret); - ReleaseDC(hwnd, hdc); + height = get_current_font_height(hwnd); + ok((ret / height) >= 6, "got width %d, height %d\n", ret, height); DestroyWindow(hwnd); } @@ -5106,10 +5181,18 @@ static void test_LVS_EX_HEADERINALLVIEWS(void) static void test_hover(void) { - HWND hwnd; + HWND hwnd, fg; DWORD r; hwnd = create_listview_control(LVS_ICON); + SetForegroundWindow(hwndparent); + fg = GetForegroundWindow(); + if (fg != hwndparent) + { + skip("Window is not in the foreground. Skipping hover tests.\n"); + DestroyWindow(hwnd); + return; + } /* test WM_MOUSEHOVER forwarding */ flush_sequences(sequences, NUM_MSG_SEQUENCES); @@ -5641,6 +5724,30 @@ static void test_insertitem(void) DestroyWindow(hwnd); } +static void test_header_proc(void) +{ + HWND hwnd, header, hdr; + WNDPROC proc1, proc2; + + hwnd = create_listview_control(LVS_REPORT); + + header = (HWND)SendMessageA(hwnd, LVM_GETHEADER, 0, 0); + ok(header != NULL, "got %p\n", header); + + hdr = CreateWindowExA(0, WC_HEADERA, NULL, + WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ, + 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(hdr != NULL, "got %p\n", hdr); + + proc1 = (WNDPROC)GetWindowLongPtrW(header, GWLP_WNDPROC); + proc2 = (WNDPROC)GetWindowLongPtrW(hdr, GWLP_WNDPROC); + ok(proc1 == proc2, "got %p, expected %p\n", proc1, proc2); + + DestroyWindow(hdr); + DestroyWindow(hwnd); +} + START_TEST(listview) { HMODULE hComctl32; @@ -5709,6 +5816,7 @@ START_TEST(listview) test_imagelists(); test_deleteitem(); test_insertitem(); + test_header_proc(); if (!load_v6_module(&ctx_cookie, &hCtx)) { @@ -5726,6 +5834,7 @@ START_TEST(listview) test_deleteitem(); test_multiselect(); test_insertitem(); + test_header_proc(); unload_v6_module(ctx_cookie, hCtx); diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c index 466612bc9c6..4653f52ca10 100644 --- a/rostests/winetests/comctl32/monthcal.c +++ b/rostests/winetests/comctl32/monthcal.c @@ -615,7 +615,9 @@ static LRESULT WINAPI monthcal_subclass_proc(HWND hwnd, UINT message, WPARAM wPa static HWND create_monthcal_control(DWORD style) { WNDPROC oldproc; + RECT rect; HWND hwnd; + BOOL ret; hwnd = CreateWindowExA(0, MONTHCAL_CLASSA, "", WS_CHILD | WS_BORDER | WS_VISIBLE | style, 0, 0, 300, 400, parent_wnd, NULL, GetModuleHandleA(NULL), NULL); @@ -628,6 +630,13 @@ static HWND create_monthcal_control(DWORD style) SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FONT), 0); + /* make sure calendar grid is 2x1 */ + ret = SendMessageA(hwnd, MCM_GETMINREQRECT, 0, (LPARAM)&rect); + ok(ret, "got %d\n", ret); + + ret = SetWindowPos(hwnd, NULL, 0, 0, rect.right * 5 / 2, rect.bottom * 3 / 2, SWP_NOMOVE); + ok(ret, "got %d\n", ret); + return hwnd; } diff --git a/rostests/winetests/comctl32/propsheet.c b/rostests/winetests/comctl32/propsheet.c index 93a75d9fadc..0ba78d37292 100644 --- a/rostests/winetests/comctl32/propsheet.c +++ b/rostests/winetests/comctl32/propsheet.c @@ -877,6 +877,7 @@ if (0) r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); ok(r == 3, "got %d\n", r); + DestroyPropertySheetPage(hpsp[4]); DestroyWindow(hdlg); } diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c index da21924da94..23eb25080a3 100644 --- a/rostests/winetests/comctl32/toolbar.c +++ b/rostests/winetests/comctl32/toolbar.c @@ -54,6 +54,40 @@ static const struct message ttgetdispinfo_parent_seq[] = { { 0 } }; +static const struct message save_parent_seq[] = { + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, -1 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 0 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 1 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 2 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 3 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 4 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 5 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_SAVE, 6 }, + { 0 } +}; + +static const struct message restore_parent_seq[] = { + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, -1 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 0 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 1 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 2 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 3 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 4 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 5 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 6 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 7 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 8 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 9 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_RESTORE, 0xa }, + { WM_NOTIFY, sent|id, 0, 0, TBN_BEGINADJUST }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 0 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 1 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 2 }, + { WM_NOTIFY, sent|id|custdraw, 0, 0, TBN_GETBUTTONINFOA, 3 }, + { WM_NOTIFY, sent|id, 0, 0, TBN_ENDADJUST }, + { 0 } +}; + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -93,6 +127,8 @@ static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) { p->iString = nString; } +static void *alloced_str; + static LRESULT parent_wnd_notify(LPARAM lParam) { NMHDR *hdr = (NMHDR *)lParam; @@ -133,6 +169,135 @@ static LRESULT parent_wnd_notify(LPARAM lParam) compare(nmdisp->dwMask, g_dwExpectedDispInfoMask, "%x"); ok(nmdisp->pszText == NULL, "pszText is not NULL\n"); break; + case TBN_SAVE: + { + NMTBSAVE *save = (NMTBSAVE *)lParam; + if (save->iItem == -1) + { + save->cbData = save->cbData * 2 + 11 * sizeof(DWORD); + save->pData = HeapAlloc( GetProcessHeap(), 0, save->cbData ); + save->pData[0] = 0xcafe; + save->pCurrent = save->pData + 1; + } + else + { + save->pCurrent[0] = 0xcafe0000 + save->iItem; + save->pCurrent++; + } + + /* Add on 5 more pseudo buttons. */ + if (save->iItem == save->cButtons - 1) + { + save->pCurrent[0] = 0xffffffff; + save->pCurrent[1] = 0xcafe0007; + save->pCurrent[2] = 0xfffffffe; + save->pCurrent[3] = 0xcafe0008; + save->pCurrent[4] = 0x80000000; + save->pCurrent[5] = 0xcafe0009; + save->pCurrent[6] = 0x7fffffff; + save->pCurrent[7] = 0xcafe000a; + save->pCurrent[8] = 0x100; + save->pCurrent[9] = 0xcafe000b; + } + + /* Return value is ignored */ + return 1; + } + case TBN_RESTORE: + { + NMTBRESTORE *restore = (NMTBRESTORE *)lParam; + + if (restore->iItem == -1) + { + ok( restore->cButtons == 25, "got %d\n", restore->cButtons ); + ok( *restore->pCurrent == 0xcafe, "got %08x\n", *restore->pCurrent ); + /* Skip the last one */ + restore->cButtons = 11; + restore->pCurrent++; + /* BytesPerRecord is ignored */ + restore->cbBytesPerRecord = 10; + } + else + { + ok( *restore->pCurrent == 0xcafe0000 + restore->iItem, "got %08x\n", *restore->pCurrent ); + if (restore->iItem < 7 || restore->iItem == 10) + { + ok( restore->tbButton.iBitmap == -1, "got %08x\n", restore->tbButton.iBitmap ); + if (restore->iItem < 7) + ok( restore->tbButton.idCommand == restore->iItem * 2 + 1, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand ); + else + ok( restore->tbButton.idCommand == 0x7fffffff, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand ); + ok( restore->tbButton.fsState == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState ); + ok( restore->tbButton.fsStyle == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsStyle ); + } + else + { + ok( restore->tbButton.iBitmap == 8, "got %08x\n", restore->tbButton.iBitmap ); + ok( restore->tbButton.idCommand == 0, "%d: got %08x\n", restore->iItem, restore->tbButton.idCommand ); + if (restore->iItem == 7) + ok( restore->tbButton.fsState == 0, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState ); + else + ok( restore->tbButton.fsState == TBSTATE_HIDDEN, "%d: got %02x\n", restore->iItem, restore->tbButton.fsState ); + ok( restore->tbButton.fsStyle == BTNS_SEP, "%d: got %02x\n", restore->iItem, restore->tbButton.fsStyle ); + } + + ok( restore->tbButton.dwData == 0, "got %08lx\n", restore->tbButton.dwData ); + ok( restore->tbButton.iString == 0, "got %08lx\n", restore->tbButton.iString ); + + restore->tbButton.iBitmap = 0; + restore->tbButton.fsState = TBSTATE_ENABLED; + restore->tbButton.fsStyle = 0; + restore->tbButton.dwData = restore->iItem; + + if (restore->iItem == 0) + { + restore->tbButton.iString = (INT_PTR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 8 ); + strcpy( (char *)restore->tbButton.iString, "foo" ); + } + else if (restore->iItem == 1) + restore->tbButton.iString = 2; + else + restore->tbButton.iString = -1; + + restore->pCurrent++; + /* Altering cButtons after the 1st call makes no difference. */ + restore->cButtons--; + } + + /* Returning non-zero from the 1st call aborts the restore, + otherwise the return value is ignored. */ + if (restore->iItem == -1) return 0; + return 1; + } + case TBN_GETBUTTONINFOA: + { + NMTOOLBARA *tb = (NMTOOLBARA *)lParam; + tb->tbButton.iBitmap = 0; + tb->tbButton.fsState = 0; + tb->tbButton.fsStyle = 0; + tb->tbButton.dwData = 0; + ok( tb->cchText == 128, "got %d\n", tb->cchText ); + switch (tb->iItem) + { + case 0: + tb->tbButton.idCommand = 7; + alloced_str = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 8 ); + strcpy( alloced_str, "foo" ); + tb->tbButton.iString = (INT_PTR)alloced_str; + return 1; + case 1: + tb->tbButton.idCommand = 9; + tb->tbButton.iString = 0; + /* tb->pszText is ignored */ + strcpy( tb->pszText, "foo" ); + return 1; + case 2: + tb->tbButton.idCommand = 11; + tb->tbButton.iString = 3; + return 1; + } + return 0; + } } return 0; } @@ -148,7 +313,31 @@ static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; - if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code; + if (message == WM_NOTIFY && lParam) + { + msg.id = ((NMHDR*)lParam)->code; + switch (msg.id) + { + case TBN_SAVE: + { + NMTBSAVE *save = (NMTBSAVE *)lParam; + msg.stage = save->iItem; + } + break; + case TBN_RESTORE: + { + NMTBRESTORE *restore = (NMTBRESTORE *)lParam; + msg.stage = restore->iItem; + } + break; + case TBN_GETBUTTONINFOA: + { + NMTOOLBARA *tb = (NMTOOLBARA *)lParam; + msg.stage = tb->iItem; + } + break; + } + } /* log system messages, except for painting */ if (message < WM_USER && @@ -748,7 +937,7 @@ static void tbsize_addbutton(tbsize_result_t *tbsr, int left, int top, int right static tbsize_result_t *tbsize_results; -#define tbsize_results_num 24 +#define tbsize_results_num 28 static void init_tbsize_results(void) { int fontheight = system_font_height(); @@ -991,6 +1180,18 @@ static void init_tbsize_results(void) { tbsize_results[23] = init_tbsize_result(2, 0, 0, 672, 42, 67, 41); tbsize_addbutton(&tbsize_results[23], 0, 2, 672, 25 + fontheight); tbsize_addbutton(&tbsize_results[23], 0, 25 + fontheight, 672, 48 + 2*fontheight); + + tbsize_results[24] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40); + tbsize_addbutton(&tbsize_results[24], 0, 2, 11 + string_width(STRING2), 24); + + tbsize_results[25] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40); + tbsize_addbutton(&tbsize_results[25], 0, 2, 40, 24); + + tbsize_results[26] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40); + tbsize_addbutton(&tbsize_results[26], 0, 2, 40, 24); + + tbsize_results[27] = init_tbsize_result(1, 0, 0, 672, 42, 67, 40); + tbsize_addbutton(&tbsize_results[27], 0, 2, 40, 24); } static void free_tbsize_results(void) { @@ -1062,12 +1263,18 @@ static TBBUTTON buttons3[] = { {0, 32, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, 1}, {0, 33, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)STRING2} }; +static TBBUTTON buttons4[] = { + {0, 40, TBSTATE_ENABLED, BTNS_AUTOSIZE, {0, }, 0, (UINT_PTR)STRING2}, + {0, 41, TBSTATE_ENABLED, 0, {0, }, 0, (UINT_PTR)STRING2}, + {0, 41, TBSTATE_ENABLED, BTNS_SHOWTEXT, {0, }, 0, (UINT_PTR)STRING2} +}; static void test_sizes(void) { HWND hToolbar = NULL; HIMAGELIST himl, himl2; TBBUTTONINFOA tbinfo; + TBBUTTON button; int style; int i; int fontheight = system_font_height(); @@ -1083,9 +1290,13 @@ static void test_sizes(void) check_sizes(); SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0); check_sizes(); + SendMessageA(hToolbar, TB_GETBUTTON, 5, (LPARAM)&button); + ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "got %08x\n", button.fsState); /* after setting the TBSTYLE_WRAPABLE the TBSTATE_WRAP is ignored */ SetWindowLongA(hToolbar, GWL_STYLE, style|TBSTYLE_WRAPABLE); check_sizes(); + SendMessageA(hToolbar, TB_GETBUTTON, 5, (LPARAM)&button); + ok(button.fsState == TBSTATE_ENABLED, "got %08x\n", button.fsState); /* adding new buttons with TBSTYLE_WRAPABLE doesn't add a new row */ SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1); check_sizes(); @@ -1094,6 +1305,11 @@ static void test_sizes(void) for (i=0; i<15; i++) SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1); check_sizes_todo(0x4); + SendMessageA(hToolbar, TB_GETBUTTON, 31, (LPARAM)&button); + ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "got %08x\n", button.fsState); + SetWindowLongA(hToolbar, GWL_STYLE, style); + SendMessageA(hToolbar, TB_GETBUTTON, 31, (LPARAM)&button); + ok(button.fsState == TBSTATE_ENABLED, "got %08x\n", button.fsState); rebuild_toolbar_with_buttons(&hToolbar); SendMessageA(hToolbar, TB_ADDBUTTONSA, 2, (LPARAM)buttons1); @@ -1300,8 +1516,41 @@ static void test_sizes(void) { tbinfo.dwMask = TBIF_SIZE; ok(SendMessageA(hToolbar, TB_SETBUTTONINFOA, 33, (LPARAM)&tbinfo) != 0, "TB_SETBUTTONINFOA failed\n"); + tbsize_numtests++; } + /* Single BTNS_AUTOSIZE button with string. */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[0]) == 1, "TB_ADDBUTTONSA failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + + /* Single non-BTNS_AUTOSIZE button with string. */ + rebuild_toolbar(&hToolbar); + ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[1]) == 1, "TB_ADDBUTTONSA failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + + /* Single non-BTNS_AUTOSIZE button with string with TBSTYLE_EX_MIXEDBUTTONS set. */ + rebuild_toolbar(&hToolbar); + SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS); + style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0); + ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[1]) == 1, "TB_ADDBUTTONSA failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + + /* Single non-BTNS_AUTOSIZE, BTNS_SHOWTEXT button with string with TBSTYLE_EX_MIXEDBUTTONS set. */ + rebuild_toolbar(&hToolbar); + SendMessageA(hToolbar, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_MIXEDBUTTONS); + style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0); + ok(SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons4[2]) == 1, "TB_ADDBUTTONSA failed\n"); + ok(SendMessageA(hToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(40, 20)) == 1, "TB_SETBUTTONSIZE failed\n"); + SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0 ); + check_sizes(); + free_tbsize_results(); DestroyWindow(hToolbar); } @@ -1338,12 +1587,12 @@ static void restore_recalc_state(HWND hToolbar) RECT rect; /* return to style with a 2px top margin */ SetWindowLongA(hToolbar, GWL_STYLE, - GetWindowLongA(hToolbar, GWL_STYLE) & ~TBSTYLE_FLAT); + SendMessageA(hToolbar, TB_GETSTYLE, 0, 0) & ~TBSTYLE_FLAT); /* recalc */ SendMessageA(hToolbar, TB_ADDBUTTONSA, 1, (LPARAM)&buttons3[3]); /* top margin will be 0px if a recalc occurs */ SetWindowLongA(hToolbar, GWL_STYLE, - GetWindowLongA(hToolbar, GWL_STYLE) | TBSTYLE_FLAT); + SendMessageA(hToolbar, TB_GETSTYLE, 0, 0) | TBSTYLE_FLAT); /* safety check */ SendMessageA(hToolbar, TB_GETITEMRECT, 1, (LPARAM)&rect); ok(rect.top == 2, "Test will make no sense because initial top is %d instead of 2\n", @@ -1358,6 +1607,7 @@ static void test_recalc(void) const int EX_STYLES_COUNT = 5; int i; BOOL recalc; + DWORD style; /* Like TB_ADDBUTTONSA tested in test_sized, inserting a button without text * results in a relayout, while adding one with text forces a recalc */ @@ -1418,6 +1668,47 @@ static void test_recalc(void) /* undocumented exstyle 0x2 seems to change the top margin, which * interferes with these tests */ + /* Show that a change in TBSTYLE_WRAPABLE causes a recalc */ + prepare_recalc_test(&hToolbar); + style = SendMessageA(hToolbar, TB_GETSTYLE, 0, 0); + SendMessageA(hToolbar, TB_SETSTYLE, 0, style); + recalc = did_recalc(hToolbar); + ok(!recalc, "recalc %d\n", recalc); + + SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | CCS_BOTTOM); + recalc = did_recalc(hToolbar); + ok(!recalc, "recalc %d\n", recalc); + + SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_WRAPABLE); + recalc = did_recalc(hToolbar); + ok(recalc, "recalc %d\n", recalc); + restore_recalc_state(hToolbar); + + SendMessageA(hToolbar, TB_SETSTYLE, 0, style | TBSTYLE_WRAPABLE); + recalc = did_recalc(hToolbar); + ok(!recalc, "recalc %d\n", recalc); + + SendMessageA(hToolbar, TB_SETSTYLE, 0, style); + recalc = did_recalc(hToolbar); + ok(recalc, "recalc %d\n", recalc); + restore_recalc_state(hToolbar); + + /* Changing CCS_VERT does not recalc */ + SendMessageA(hToolbar, TB_SETSTYLE, 0, style | CCS_VERT); + recalc = did_recalc(hToolbar); + ok(!recalc, "recalc %d\n", recalc); + restore_recalc_state(hToolbar); + + SendMessageA(hToolbar, TB_SETSTYLE, 0, style); + recalc = did_recalc(hToolbar); + ok(!recalc, "recalc %d\n", recalc); + restore_recalc_state(hToolbar); + + /* Setting the window's style directly also causes recalc */ + SetWindowLongA(hToolbar, GWL_STYLE, style | TBSTYLE_WRAPABLE); + recalc = did_recalc(hToolbar); + ok(recalc, "recalc %d\n", recalc); + DestroyWindow(hToolbar); } @@ -1917,11 +2208,161 @@ static void test_TB_GET_SET_EXTENDEDSTYLE(void) ok(style == TBSTYLE_EX_VERTICAL, "got style 0x%08x, expected 0x%08x\n", style, TBSTYLE_EX_VERTICAL); style = SendMessageA(hwnd, TB_GETSTYLE, 0, 0); todo_wine - ok(style == CCS_VERT, "got style 0x%08x, expected 0x%08x\n", style, CCS_VERT); + ok(style == CCS_VERT, "got style 0x%08x, expected CCS_VERT\n", style); DestroyWindow(hwnd); } +static void test_noresize(void) +{ + HWND wnd; + int i; + TBBUTTON button = {0, 10, TBSTATE_ENABLED, 0, {0, }, 0, -1}; + + wnd = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, WS_CHILD | WS_VISIBLE | CCS_NORESIZE | TBSTYLE_WRAPABLE, 0, 0, 100, 20, + hMainWnd, (HMENU)5, GetModuleHandleA(NULL), NULL); + SendMessageA(wnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + + for (i=0; i<30; i++) + { + button.idCommand = 10 + i; + SendMessageA(wnd, TB_ADDBUTTONSA, 1, (LPARAM)&button); + } + + SendMessageA(wnd, TB_SETSTATE, 10, TBSTATE_WRAP|TBSTATE_ENABLED); + + /* autosize clears the wrap on button 0 */ + SendMessageA(wnd, TB_AUTOSIZE, 0, 0); + for (i=0; i<30; i++) + { + SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button); + if (i % 4 == 3) + ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState); + else + ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState); + } + + /* changing the parent doesn't do anything */ + MoveWindow(hMainWnd, 0,0, 400, 200, FALSE); + for (i=0; i<30; i++) + { + SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button); + if (i % 4 == 3) + ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState); + else + ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState); + } + + /* again nothing here */ + SendMessageA(wnd, TB_AUTOSIZE, 0, 0); + for (i=0; i<30; i++) + { + SendMessageA(wnd, TB_GETBUTTON, i, (LPARAM)&button); + if (i % 4 == 3) + ok(button.fsState == (TBSTATE_WRAP|TBSTATE_ENABLED), "%d: got %08x\n", i, button.fsState); + else + ok(button.fsState == TBSTATE_ENABLED, "%d: got %08x\n", i, button.fsState); + } + + DestroyWindow(wnd); + +} + +static void test_save(void) +{ + HWND wnd = NULL; + TBSAVEPARAMSW params; + static const WCHAR subkey[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','T','e','s','t',0}; + static const WCHAR value[] = {'t','o','o','l','b','a','r','t','e','s','t',0}; + LONG res; + HKEY key; + BYTE data[100]; + DWORD size = sizeof(data), type, i, count; + TBBUTTON tb; + static const TBBUTTON more_btns[2] = + { + {0, 11, TBSTATE_HIDDEN, BTNS_BUTTON, {0}, 0, -1}, + {0, 13, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, -1} + }; + static const DWORD expect[] = {0xcafe, 1, 0xcafe0000, 3, 0xcafe0001, 5, 0xcafe0002, 7, 0xcafe0003, + 9, 0xcafe0004, 11, 0xcafe0005, 13, 0xcafe0006, 0xffffffff, 0xcafe0007, + 0xfffffffe, 0xcafe0008, 0x80000000, 0xcafe0009, 0x7fffffff, 0xcafe000a, + 0x100, 0xcafe000b}; + static const TBBUTTON expect_btns[] = + { + {0, 1, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, + {0, 3, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 1, 2}, + {0, 5, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 2, 0}, + {0, 7, 0, BTNS_BUTTON, {0}, 0, (INT_PTR)"foo"}, + {0, 9, 0, BTNS_BUTTON, {0}, 0, 0}, + {0, 11, 0, BTNS_BUTTON, {0}, 0, 3}, + {0, 13, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 6, 0}, + {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 7, 0}, + {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 8, 0}, + {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 9, 0}, + {0, 0x7fffffff, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0xa, 0}, + }; + + params.hkr = HKEY_CURRENT_USER; + params.pszSubKey = subkey; + params.pszValueName = value; + + rebuild_toolbar_with_buttons( &wnd ); + SendMessageW( wnd, TB_ADDBUTTONSW, sizeof(more_btns) / sizeof(more_btns[0]), (LPARAM)more_btns ); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + res = SendMessageW( wnd, TB_SAVERESTOREW, TRUE, (LPARAM)¶ms ); + ok( res, "saving failed\n" ); + ok_sequence(sequences, PARENT_SEQ_INDEX, save_parent_seq, "save", FALSE); + DestroyWindow( wnd ); + + res = RegOpenKeyW( HKEY_CURRENT_USER, subkey, &key ); + ok( !res, "got %08x\n", res ); + res = RegQueryValueExW( key, value, NULL, &type, data, &size ); + ok( !res, "got %08x\n", res ); + ok( type == REG_BINARY, "got %08x\n", type ); + ok( size == sizeof(expect), "got %08x\n", size ); + ok( !memcmp( data, expect, size ), "mismatch\n" ); + + RegCloseKey( key ); + + wnd = NULL; + rebuild_toolbar( &wnd ); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + res = SendMessageW( wnd, TB_SAVERESTOREW, FALSE, (LPARAM)¶ms ); + ok( res, "restoring failed\n" ); + ok_sequence(sequences, PARENT_SEQ_INDEX, restore_parent_seq, "restore", FALSE); + count = SendMessageW( wnd, TB_BUTTONCOUNT, 0, 0 ); + ok( count == sizeof(expect_btns) / sizeof(expect_btns[0]), "got %d\n", count ); + + for (i = 0; i < count; i++) + { + res = SendMessageW( wnd, TB_GETBUTTON, i, (LPARAM)&tb ); + ok( res, "got %d\n", res ); + + ok( tb.iBitmap == expect_btns[i].iBitmap, "%d: got %d\n", i, tb.iBitmap ); + ok( tb.idCommand == expect_btns[i].idCommand, "%d: got %d\n", i, tb.idCommand ); + ok( tb.fsState == expect_btns[i].fsState, "%d: got %02x\n", i, tb.fsState ); + ok( tb.fsStyle == expect_btns[i].fsStyle, "%d: got %02x\n", i, tb.fsStyle ); + ok( tb.dwData == expect_btns[i].dwData, "%d: got %lx\n", i, tb.dwData ); + if (IS_INTRESOURCE(expect_btns[i].iString)) + ok( tb.iString == expect_btns[i].iString, "%d: got %lx\n", i, tb.iString ); + else + ok( !strcmp( (char *)tb.iString, (char *)expect_btns[i].iString ), + "%d: got %s\n", i, (char *)tb.iString ); + + /* In fact the ptr value set in TBN_GETBUTTONINFOA is simply copied */ + if (tb.idCommand == 7) + ok( tb.iString == (INT_PTR)alloced_str, "string not set\n"); + } + + DestroyWindow( wnd ); + RegOpenKeyW( HKEY_CURRENT_USER, subkey, &key ); + RegDeleteValueW( key, value ); + RegCloseKey( key ); +} + START_TEST(toolbar) { WNDCLASSA wc; @@ -1964,6 +2405,8 @@ START_TEST(toolbar) test_get_set_style(); test_create(); test_TB_GET_SET_EXTENDEDSTYLE(); + test_noresize(); + test_save(); PostQuitMessage(0); while(GetMessageA(&msg,0,0,0)) { diff --git a/rostests/winetests/comctl32/tooltips.c b/rostests/winetests/comctl32/tooltips.c index 272c2e4f6ad..4c0c7dfb1b8 100644 --- a/rostests/winetests/comctl32/tooltips.c +++ b/rostests/winetests/comctl32/tooltips.c @@ -26,6 +26,8 @@ #include #include +#include "resources.h" + #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got) static void test_create_tooltip(void) @@ -330,6 +332,30 @@ static void test_gettext(void) SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA); ok(toolinfoA.lpszText == NULL, "expected NULL, got %p\n", toolinfoA.lpszText); + + /* NULL hinst, valid resource id for text */ + toolinfoA.cbSize = sizeof(TTTOOLINFOA); + toolinfoA.hwnd = NULL; + toolinfoA.hinst = NULL; + toolinfoA.uFlags = 0; + toolinfoA.uId = 0x1233ABCD; + toolinfoA.lpszText = MAKEINTRESOURCEA(IDS_TBADD1); + toolinfoA.lParam = 0xdeadbeef; + GetClientRect(hwnd, &toolinfoA.rect); + r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA); + ok(r, "failed to add a tool\n"); + + toolinfoA.hwnd = NULL; + toolinfoA.uId = 0x1233ABCD; + toolinfoA.lpszText = bufA; + SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA); + ok(strcmp(toolinfoA.lpszText, "abc") == 0, "lpszText should be an empty string\n"); + + toolinfoA.hinst = (HINSTANCE)0xdeadbee; + SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA); + ok(toolinfoA.hinst == NULL, "expected NULL, got %p\n", toolinfoA.hinst); + + SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&toolinfoA); } else { @@ -817,6 +843,154 @@ static void test_track(void) DestroyWindow(parent); } +static LRESULT CALLBACK info_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + + case WM_DESTROY: + PostQuitMessage(0); + break; + + default: + return DefWindowProcA(hWnd, msg, wParam, lParam); + } + return 0; +} + +static void test_setinfo(void) +{ + WNDCLASSA wc; + LRESULT lResult; + HWND parent, parent2, hwndTip, hwndTip2; + TTTOOLINFOA toolInfo = { 0 }; + TTTOOLINFOA toolInfo2 = { 0 }; + WNDPROC wndProc; + + /* Create a class to use the custom draw wndproc */ + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandleA(NULL); + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); + wc.lpszMenuName = NULL; + wc.lpszClassName = "SetInfoClass"; + wc.lpfnWndProc = info_wnd_proc; + RegisterClassA(&wc); + + /* Create a main window */ + parent = CreateWindowExA(0, "SetInfoClass", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 50, 50, + 300, 300, + NULL, NULL, NULL, 0); + ok(parent != NULL, "Creation of main window failed\n"); + + parent2 = CreateWindowExA(0, "SetInfoClass", NULL, + WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | + WS_MAXIMIZEBOX | WS_VISIBLE, + 50, 50, + 300, 300, + NULL, NULL, NULL, 0); + ok(parent2 != NULL, "Creation of main window failed\n"); + + /* Make it show */ + ShowWindow(parent2, SW_SHOWNORMAL); + flush_events(100); + + /* Create Tooltip */ + hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, + NULL, TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, NULL, GetModuleHandleA(NULL), 0); + ok(hwndTip != NULL, "Creation of tooltip window failed\n"); + + hwndTip2 = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, + NULL, TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, NULL, GetModuleHandleA(NULL), 0); + ok(hwndTip2 != NULL, "Creation of tooltip window failed\n"); + + + /* Make it topmost, as per the MSDN */ + SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + /* Create a tool */ + toolInfo.cbSize = TTTOOLINFOA_V1_SIZE; + toolInfo.hwnd = parent; + toolInfo.hinst = GetModuleHandleA(NULL); + toolInfo.uFlags = TTF_SUBCLASS; + toolInfo.uId = 0x1234ABCD; + toolInfo.lpszText = (LPSTR)"This is a test tooltip"; + toolInfo.lParam = 0xdeadbeef; + GetClientRect (parent, &toolInfo.rect); + lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo); + ok(lResult, "Adding the tool to the tooltip failed\n"); + + toolInfo.cbSize = TTTOOLINFOA_V1_SIZE; + toolInfo.hwnd = parent2; + toolInfo.hinst = GetModuleHandleA(NULL); + toolInfo.uFlags = 0; + toolInfo.uId = 0x1234ABCE; + toolInfo.lpszText = (LPSTR)"This is a test tooltip"; + toolInfo.lParam = 0xdeadbeef; + GetClientRect (parent, &toolInfo.rect); + lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo); + ok(lResult, "Adding the tool to the tooltip failed\n"); + + /* Try to Remove Subclass */ + toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE; + toolInfo2.hwnd = parent; + toolInfo2.uId = 0x1234ABCD; + lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2); + ok(lResult, "GetToolInfo failed\n"); + ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n"); + wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC); + ok (wndProc != info_wnd_proc, "Window Proc is wrong\n"); + + toolInfo2.uFlags &= ~TTF_SUBCLASS; + SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2); + lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2); + ok(lResult, "GetToolInfo failed\n"); + ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n"); + wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC); + ok (wndProc != info_wnd_proc, "Window Proc is wrong\n"); + + /* Try to Add Subclass */ + + /* Make it topmost, as per the MSDN */ + SetWindowPos(hwndTip2, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE; + toolInfo2.hwnd = parent2; + toolInfo2.uId = 0x1234ABCE; + lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2); + ok(lResult, "GetToolInfo failed\n"); + ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n"); + wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC); + ok (wndProc == info_wnd_proc, "Window Proc is wrong\n"); + + toolInfo2.uFlags |= TTF_SUBCLASS; + SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2); + lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2); + ok(lResult, "GetToolInfo failed\n"); + ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n"); + wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC); + ok (wndProc == info_wnd_proc, "Window Proc is wrong\n"); + + /* Clean up */ + DestroyWindow(hwndTip); + DestroyWindow(hwndTip2); + DestroyWindow(parent); + DestroyWindow(parent2); +} + START_TEST(tooltips) { InitCommonControls(); @@ -828,4 +1002,5 @@ START_TEST(tooltips) test_longtextA(); test_longtextW(); test_track(); + test_setinfo(); } diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c index dc4e4784233..7068bc96110 100644 --- a/rostests/winetests/comctl32/treeview.c +++ b/rostests/winetests/comctl32/treeview.c @@ -19,6 +19,7 @@ */ #include +#include #include "windef.h" #include "winbase.h" @@ -226,7 +227,8 @@ static const struct message parent_expand_empty_kb_seq[] = { { 0 } }; -static const struct message parent_singleexpand_seq[] = { +static const struct message parent_singleexpand_seq0[] = { + /* alpha expands */ { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, @@ -235,6 +237,84 @@ static const struct message parent_singleexpand_seq[] = { { 0 } }; +static const struct message parent_singleexpand_seq1[] = { + /* bravo expands */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { 0 } +}; + +static const struct message parent_singleexpand_seq2[] = { + /* delta expands, bravo collapses */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { 0 } +}; + +static const struct message parent_singleexpand_seq3[] = { + /* foxtrot expands, alpha and delta collapse */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { 0 } +}; + +static const struct message parent_singleexpand_seq4[] = { + /* alpha expands, foxtrot collapses */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { 0 } +}; + +static const struct message parent_singleexpand_seq5[] = { + /* foxtrot expands while golf is selected, then golf expands and alpha collapses */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA }, + { 0 } +}; + +static const struct message parent_singleexpand_seq6[] = { + /* hotel does not expand and india does not collapse because they have no children */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { 0 } +}; + +static const struct message parent_singleexpand_seq7[] = { + /* india does not expand and hotel does not collapse because they have no children */ + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA }, + { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND }, + { 0 } +}; + static const struct message parent_get_dispinfo_seq[] = { { WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA }, { 0 } @@ -1637,21 +1717,95 @@ static void test_expandedimage(void) static void test_TVS_SINGLEEXPAND(void) { HWND hTree; + HTREEITEM alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet; + TVINSERTSTRUCTA ins; + char foo[] = "foo"; + char context[32]; + int i; BOOL ret; + /* build a fairly complex tree + * - TVI_ROOT + * - alpha + * - bravo + * - charlie + * - delta + * - echo + * - foxtrot + * - golf + * - hotel + * - india + * - juliet + */ + struct + { + HTREEITEM *handle; + HTREEITEM *parent; + UINT final_state; + } + items[] = + { + { &alpha, NULL, TVIS_EXPANDEDONCE }, + { &bravo, &alpha, TVIS_EXPANDEDONCE }, + { &charlie, &bravo, 0 }, + { &delta, &alpha, TVIS_EXPANDEDONCE }, + { &echo, &delta, 0 }, + { &foxtrot, NULL, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, + { &golf, &foxtrot, TVIS_EXPANDEDONCE|TVIS_EXPANDED }, + { &hotel, &golf, 0 }, + { &india, &golf, TVIS_SELECTED }, + { &juliet, &foxtrot, 0 } + }; + + struct + { + HTREEITEM *select; + const struct message *sequence; + } + sequence_tests[] = + { + { &alpha, parent_singleexpand_seq0 }, + { &bravo, parent_singleexpand_seq1 }, + { &delta, parent_singleexpand_seq2 }, + { &foxtrot, parent_singleexpand_seq3 }, + { &alpha, parent_singleexpand_seq4 }, + { &golf, parent_singleexpand_seq5 }, + { &hotel, parent_singleexpand_seq6 }, + { &india, parent_singleexpand_seq7 }, + { &india, empty_seq } + }; + hTree = create_treeview_control(0); SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_SINGLEEXPAND); /* to avoid painting related notifications */ ShowWindow(hTree, SW_HIDE); - fill_tree(hTree); + for (i = 0; i < sizeof(items)/sizeof(items[0]); i++) + { + ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT; + ins.hInsertAfter = TVI_FIRST; + U(ins).item.mask = TVIF_TEXT; + U(ins).item.pszText = foo; + *items[i].handle = TreeView_InsertItemA(hTree, &ins); + } - flush_sequences(sequences, NUM_MSG_SEQUENCES); - ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); - ok(ret, "got %d\n", ret); - ok_sequence(sequences, PARENT_SEQ_INDEX, parent_singleexpand_seq, "singleexpand notifications", FALSE); + for (i = 0; i < sizeof(sequence_tests)/sizeof(sequence_tests[0]); i++) + { + flush_sequences(sequences, NUM_MSG_SEQUENCES); + ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select)); + ok(ret, "got %d\n", ret); + sprintf(context, "singleexpand notifications %d", i); + ok_sequence(sequences, PARENT_SEQ_INDEX, sequence_tests[i].sequence, context, FALSE); + } + + for (i = 0; i < sizeof(items)/sizeof(items[0]); i++) + { + ret = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)(*items[i].handle), 0xFFFF); + ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n", + i, items[i].final_state, ret); + } /* a workaround for NT4 that sends expand notifications when nothing is about to expand */ - ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hRoot); + ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); ok(ret, "got %d\n", ret); fill_tree(hTree); ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);