comctl32/listview: Use LVM_SETITEMSTATE directly in tests.
[wine] / dlls / comctl32 / tests / tab.c
1 /* Unit test suite for tab control.
2  *
3  * Copyright 2003 Vitaliy Margolen
4  * Copyright 2007 Hagop Hagopian
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <stdio.h>
25
26 #include "wine/test.h"
27 #include "msg.h"
28
29 #define DEFAULT_MIN_TAB_WIDTH 54
30 #define TAB_PADDING_X 6
31 #define EXTRA_ICON_PADDING 3
32 #define MAX_TABLEN 32
33
34 #define NUM_MSG_SEQUENCES  2
35 #define PARENT_SEQ_INDEX   0
36 #define TAB_SEQ_INDEX      1
37
38 #define expect(expected, got) ok ( expected == got, "Expected %d, got %d\n", expected, got)
39 #define expect_str(expected, got)\
40  ok ( strcmp(expected, got) == 0, "Expected '%s', got '%s'\n", expected, got)
41
42 #define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
43
44 static void CheckSize(HWND hwnd, INT width, INT height, const char *msg, int line)
45 {
46     RECT r;
47
48     SendMessage(hwnd, TCM_GETITEMRECT, 0, (LPARAM)&r);
49     if (width >= 0 && height < 0)
50         ok_(__FILE__,line) (width == r.right - r.left, "%s: Expected width [%d] got [%d]\n",
51             msg, width, r.right - r.left);
52     else if (height >= 0 && width < 0)
53         ok_(__FILE__,line) (height == r.bottom - r.top,  "%s: Expected height [%d] got [%d]\n",
54             msg, height, r.bottom - r.top);
55     else
56         ok_(__FILE__,line) ((width  == r.right  - r.left) && (height == r.bottom - r.top ),
57             "%s: Expected [%d,%d] got [%d,%d]\n", msg, width, height,
58             r.right - r.left, r.bottom - r.top);
59 }
60
61 #define CHECKSIZE(hwnd,width,height,msg) CheckSize(hwnd,width,height,msg,__LINE__)
62
63 static void TabCheckSetSize(HWND hwnd, INT set_width, INT set_height, INT exp_width,
64     INT exp_height, const char *msg, int line)
65 {
66     SendMessage(hwnd, TCM_SETITEMSIZE, 0,
67         (LPARAM) MAKELPARAM((set_width >= 0) ? set_width : 0, (set_height >= 0) ? set_height : 0));
68     if (winetest_interactive) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW);
69     CheckSize(hwnd, exp_width, exp_height, msg, line);
70 }
71
72 #define TABCHECKSETSIZE(hwnd,set_width,set_height,exp_width,exp_height,msg) \
73     TabCheckSetSize(hwnd,set_width,set_height,exp_width,exp_height,msg,__LINE__)
74
75 static HFONT hFont;
76 static DRAWITEMSTRUCT g_drawitem;
77 static HWND parent_wnd;
78
79 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
80
81 static const struct message create_parent_wnd_seq[] = {
82     { WM_GETMINMAXINFO, sent },
83     { WM_NCCREATE, sent },
84     { WM_NCCALCSIZE, sent|wparam, 0 },
85     { WM_CREATE, sent },
86     { WM_SHOWWINDOW, sent|wparam, 1 },
87     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
88     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
89     { WM_ACTIVATEAPP, sent|wparam, 1 },
90     { WM_NCACTIVATE, sent|wparam, 1 },
91     { WM_ACTIVATE, sent|wparam, 1 },
92     { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
93     { WM_IME_NOTIFY, sent|defwinproc|optional },
94     { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
95     /* Win9x adds SWP_NOZORDER below */
96     { WM_WINDOWPOSCHANGED, sent},
97     { WM_NCCALCSIZE, sent|wparam|optional, 1 },
98     { WM_SIZE, sent },
99     { WM_MOVE, sent },
100     { 0 }
101 };
102
103 static const struct message add_tab_to_parent[] = {
104     { TCM_INSERTITEMA, sent },
105     { TCM_INSERTITEMA, sent|optional },
106     { WM_NOTIFYFORMAT, sent|defwinproc },
107     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc|optional, 0, 0 },
108     { WM_PARENTNOTIFY, sent|defwinproc },
109     { TCM_INSERTITEMA, sent },
110     { TCM_INSERTITEMA, sent },
111     { TCM_INSERTITEMA, sent },
112     { TCM_INSERTITEMA, sent|optional },
113     { 0 }
114 };
115
116 static const struct message add_tab_to_parent_interactive[] = {
117     { TCM_INSERTITEMA, sent },
118     { TCM_INSERTITEMA, sent },
119     { WM_NOTIFYFORMAT, sent|defwinproc },
120     { WM_QUERYUISTATE, sent|wparam|lparam|defwinproc, 0, 0 },
121     { WM_PARENTNOTIFY, sent|defwinproc },
122     { TCM_INSERTITEMA, sent },
123     { TCM_INSERTITEMA, sent },
124     { TCM_INSERTITEMA, sent },
125     { WM_SHOWWINDOW, sent},
126     { WM_WINDOWPOSCHANGING, sent},
127     { WM_WINDOWPOSCHANGING, sent},
128     { WM_NCACTIVATE, sent},
129     { WM_ACTIVATE, sent},
130     { WM_IME_SETCONTEXT, sent|defwinproc|optional},
131     { WM_IME_NOTIFY, sent|defwinproc|optional},
132     { WM_SETFOCUS, sent|defwinproc},
133     { WM_WINDOWPOSCHANGED, sent},
134     { WM_SIZE, sent},
135     { WM_MOVE, sent},
136     { 0 }
137 };
138
139 static const struct message add_tab_control_parent_seq[] = {
140     { WM_NOTIFYFORMAT, sent },
141     { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 },
142     { 0 }
143 };
144
145 static const struct message add_tab_control_parent_seq_interactive[] = {
146     { WM_NOTIFYFORMAT, sent },
147     { WM_QUERYUISTATE, sent|wparam|lparam, 0, 0 },
148     { WM_WINDOWPOSCHANGING, sent|optional},
149     { WM_NCACTIVATE, sent},
150     { WM_ACTIVATE, sent},
151     { WM_WINDOWPOSCHANGING, sent|optional},
152     { WM_KILLFOCUS, sent},
153     { WM_IME_SETCONTEXT, sent|optional},
154     { WM_IME_NOTIFY, sent|optional},
155     { 0 }
156 };
157
158 static const struct message empty_sequence[] = {
159     { 0 }
160 };
161
162 static const struct message set_min_tab_width_seq[] = {
163     { TCM_SETMINTABWIDTH, sent|wparam, 0 },
164     { TCM_SETMINTABWIDTH, sent|wparam, 0 },
165     { 0 }
166 };
167
168 static const struct message get_item_count_seq[] = {
169     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
170     { 0 }
171 };
172
173 static const struct message get_row_count_seq[] = {
174     { TCM_GETROWCOUNT, sent|wparam|lparam, 0, 0 },
175     { 0 }
176 };
177
178 static const struct message get_item_rect_seq[] = {
179     { TCM_GETITEMRECT, sent },
180     { TCM_GETITEMRECT, sent },
181     { 0 }
182 };
183
184 static const struct message getset_cur_focus_seq[] = {
185     { TCM_SETCURFOCUS, sent|lparam, 0 },
186     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
187     { TCM_SETCURFOCUS, sent|lparam, 0 },
188     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
189     { TCM_SETCURSEL, sent|lparam, 0 },
190     { TCM_SETCURFOCUS, sent|lparam, 0 },
191     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
192     { 0 }
193 };
194
195 static const struct message getset_cur_sel_seq[] = {
196     { TCM_SETCURSEL, sent|lparam, 0 },
197     { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
198     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
199     { TCM_SETCURSEL, sent|lparam, 0 },
200     { TCM_GETCURSEL, sent|wparam|lparam, 0, 0 },
201     { TCM_SETCURSEL, sent|lparam, 0 },
202     { TCM_SETCURSEL, sent|lparam, 0 },
203     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
204     { 0 }
205 };
206
207 static const struct message getset_extended_style_seq[] = {
208     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
209     { TCM_SETEXTENDEDSTYLE, sent },
210     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
211     { TCM_SETEXTENDEDSTYLE, sent },
212     { TCM_GETEXTENDEDSTYLE, sent|wparam|lparam, 0, 0 },
213     { 0 }
214 };
215
216 static const struct message getset_unicode_format_seq[] = {
217     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
218     { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
219     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
220     { CCM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
221     { CCM_SETUNICODEFORMAT, sent|lparam, 0 },
222     { 0 }
223 };
224
225 static const struct message getset_item_seq[] = {
226     { TCM_SETITEMA, sent },
227     { TCM_GETITEMA, sent },
228     { TCM_GETITEMA, sent },
229     { 0 }
230 };
231
232 static const struct message getset_tooltip_seq[] = {
233     { WM_NOTIFYFORMAT, sent|optional },
234     { WM_QUERYUISTATE, sent|wparam|lparam|optional, 0, 0 },
235     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
236     { WM_NOTIFYFORMAT, sent|optional },
237     { TCM_SETTOOLTIPS, sent|lparam, 0 },
238     { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
239     { TCM_SETTOOLTIPS, sent|lparam, 0 },
240     { TCM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
241     { 0 }
242 };
243
244 static const struct message getset_tooltip_parent_seq[] = {
245     { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
246     { 0 }
247 };
248
249 static const struct message insert_focus_seq[] = {
250     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
251     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
252     { TCM_INSERTITEM, sent|wparam, 1 },
253     { WM_NOTIFYFORMAT, sent|defwinproc|optional },
254     { WM_QUERYUISTATE, sent|defwinproc|optional },
255     { WM_PARENTNOTIFY, sent|defwinproc|optional },
256     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
257     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
258     { TCM_INSERTITEM, sent|wparam, 2 },
259     { WM_NOTIFYFORMAT, sent|defwinproc|optional },
260     { WM_QUERYUISTATE, sent|defwinproc|optional, },
261     { WM_PARENTNOTIFY, sent|defwinproc|optional },
262     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
263     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
264     { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
265     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
266     { TCM_INSERTITEM, sent|wparam, 3 },
267     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
268     { 0 }
269 };
270
271 static const struct message delete_focus_seq[] = {
272     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
273     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
274     { TCM_DELETEITEM, sent|wparam|lparam, 1, 0 },
275     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
276     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
277     { TCM_SETCURFOCUS, sent|wparam|lparam, -1, 0 },
278     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
279     { TCM_DELETEITEM, sent|wparam|lparam, 0, 0 },
280     { TCM_GETITEMCOUNT, sent|wparam|lparam, 0, 0 },
281     { TCM_GETCURFOCUS, sent|wparam|lparam, 0, 0 },
282     { 0 }
283 };
284
285 static const struct message rbuttonup_seq[] = {
286     { WM_RBUTTONUP, sent|wparam|lparam, 0, 0 },
287     { WM_CONTEXTMENU, sent|defwinproc },
288     { 0 }
289 };
290
291 static HWND
292 create_tabcontrol (DWORD style, DWORD mask)
293 {
294     HWND handle;
295     TCITEM tcNewTab;
296     static char text1[] = "Tab 1",
297     text2[] = "Wide Tab 2",
298     text3[] = "T 3";
299
300     handle = CreateWindow (
301         WC_TABCONTROLA,
302         "TestTab",
303         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
304         10, 10, 300, 100,
305         NULL, NULL, NULL, 0);
306
307     assert (handle);
308
309     SetWindowLong(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style);
310     SendMessage (handle, WM_SETFONT, 0, (LPARAM) hFont);
311
312     tcNewTab.mask = mask;
313     tcNewTab.pszText = text1;
314     tcNewTab.iImage = 0;
315     SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab);
316     tcNewTab.pszText = text2;
317     tcNewTab.iImage = 1;
318     SendMessage (handle, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
319     tcNewTab.pszText = text3;
320     tcNewTab.iImage = 2;
321     SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
322
323     if (winetest_interactive)
324     {
325         ShowWindow (handle, SW_SHOW);
326         RedrawWindow (handle, NULL, 0, RDW_UPDATENOW);
327         Sleep (1000);
328     }
329
330     return handle;
331 }
332
333 static LRESULT WINAPI parentWindowProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
334 {
335     static LONG defwndproc_counter = 0;
336     LRESULT ret;
337     struct message msg;
338
339     /* do not log painting messages */
340     if (message != WM_PAINT &&
341         message != WM_ERASEBKGND &&
342         message != WM_NCPAINT &&
343         message != WM_NCHITTEST &&
344         message != WM_GETTEXT &&
345         message != WM_GETICON &&
346         message != WM_DEVICECHANGE)
347     {
348         trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
349
350         msg.message = message;
351         msg.flags = sent|wparam|lparam;
352         if (defwndproc_counter) msg.flags |= defwinproc;
353         msg.wParam = wParam;
354         msg.lParam = lParam;
355         msg.id = 0;
356         add_message(sequences, PARENT_SEQ_INDEX, &msg);
357     }
358
359     /* dump sent structure data */
360     if (message == WM_DRAWITEM)
361         g_drawitem = *(DRAWITEMSTRUCT*)lParam;
362
363     defwndproc_counter++;
364     ret = DefWindowProcA(hwnd, message, wParam, lParam);
365     defwndproc_counter--;
366
367     return ret;
368 }
369
370 static BOOL registerParentWindowClass(void)
371 {
372     WNDCLASSA cls;
373
374     cls.style = 0;
375     cls.lpfnWndProc = parentWindowProcess;
376     cls.cbClsExtra = 0;
377     cls.cbWndExtra = 0;
378     cls.hInstance = GetModuleHandleA(NULL);
379     cls.hIcon = 0;
380     cls.hCursor = LoadCursorA(0, IDC_ARROW);
381     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
382     cls.lpszMenuName = NULL;
383     cls.lpszClassName = "Tab test parent class";
384     return RegisterClassA(&cls);
385 }
386
387 static HWND createParentWindow(void)
388 {
389     if (!registerParentWindowClass())
390         return NULL;
391
392     return CreateWindowEx(0, "Tab test parent class",
393                           "Tab test parent window",
394                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
395                           WS_MAXIMIZEBOX | WS_VISIBLE,
396                           0, 0, 100, 100,
397                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
398 }
399
400 static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
401 {
402     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
403     static LONG defwndproc_counter = 0;
404     LRESULT ret;
405     struct message msg;
406
407     /* do not log painting messages */
408     if (message != WM_PAINT &&
409         message != WM_ERASEBKGND &&
410         message != WM_NCPAINT &&
411         message != WM_NCHITTEST &&
412         message != WM_GETTEXT &&
413         message != WM_GETICON &&
414         message != WM_DEVICECHANGE)
415     {
416         trace("tab: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
417
418         msg.message = message;
419         msg.flags = sent|wparam|lparam;
420         if (defwndproc_counter) msg.flags |= defwinproc;
421         msg.wParam = wParam;
422         msg.lParam = lParam;
423         msg.id = 0;
424         add_message(sequences, TAB_SEQ_INDEX, &msg);
425     }
426
427     defwndproc_counter++;
428     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
429     defwndproc_counter--;
430
431     return ret;
432 }
433
434 static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs)
435 {
436     HWND tabHandle;
437     TCITEM tcNewTab;
438     WNDPROC oldproc;
439     RECT rect;
440     INT i;
441
442     GetClientRect(parent_wnd, &rect);
443
444     tabHandle = CreateWindow (
445         WC_TABCONTROLA,
446         "TestTab",
447         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
448         0, 0, rect.right, rect.bottom,
449         parent_wnd, NULL, NULL, 0);
450
451     assert(tabHandle);
452
453     oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
454     SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
455
456     tcNewTab.mask = mask;
457
458     for (i = 0; i < nTabs; i++)
459     {
460         char tabName[MAX_TABLEN];
461
462         sprintf(tabName, "Tab %d", i+1);
463         tcNewTab.pszText = tabName;
464         tcNewTab.iImage = i;
465         SendMessage (tabHandle, TCM_INSERTITEM, i, (LPARAM) &tcNewTab);
466     }
467
468     if (winetest_interactive)
469     {
470         ShowWindow (tabHandle, SW_SHOW);
471         RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW);
472         Sleep (1000);
473     }
474
475     return tabHandle;
476 }
477
478 static HWND create_tooltip (HWND hTab, char toolTipText[])
479 {
480     HWND hwndTT;
481
482     TOOLINFO ti;
483     LPTSTR lptstr = toolTipText;
484     RECT rect;
485
486     /* Creating a tooltip window*/
487     hwndTT = CreateWindowEx(
488         WS_EX_TOPMOST,
489         TOOLTIPS_CLASS,
490         NULL,
491         WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
492         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
493         hTab, NULL, 0, NULL);
494
495     SetWindowPos(
496         hwndTT,
497         HWND_TOPMOST,
498         0, 0, 0, 0,
499         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
500
501     GetClientRect (hTab, &rect);
502
503     /* Initialize members of toolinfo*/
504     ti.cbSize = sizeof(TOOLINFO);
505     ti.uFlags = TTF_SUBCLASS;
506     ti.hwnd = hTab;
507     ti.hinst = 0;
508     ti.uId = 0;
509     ti.lpszText = lptstr;
510
511     ti.rect = rect;
512
513     /* Add toolinfo structure to the tooltip control */
514     SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti);
515
516     return hwndTT;
517 }
518
519 static void test_tab(INT nMinTabWidth)
520 {
521     HWND hwTab;
522     RECT rTab;
523     HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4);
524     SIZE size;
525     HDC hdc;
526     HFONT hOldFont;
527     INT i, dpi, exp;
528
529     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
530     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
531     /* Get System default MinTabWidth */
532     if (nMinTabWidth < 0)
533         nMinTabWidth = SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
534
535     hdc = GetDC(hwTab);
536     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
537     hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
538     GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
539     trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy);
540     SelectObject(hdc, hOldFont);
541     ReleaseDC(hwTab, hdc);
542
543     trace ("  TCS_FIXEDWIDTH tabs no icon...\n");
544     CHECKSIZE(hwTab, dpi, -1, "default width");
545     TABCHECKSETSIZE(hwTab, 50, 20, 50, 20, "set size");
546     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
547
548     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
549
550     trace ("  TCS_FIXEDWIDTH tabs with icon...\n");
551     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
552     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
553     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
554
555     DestroyWindow (hwTab);
556
557     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
558     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
559
560     hdc = GetDC(hwTab);
561     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
562     ReleaseDC(hwTab, hdc);
563     trace ("  TCS_FIXEDWIDTH buttons no icon...\n");
564     CHECKSIZE(hwTab, dpi, -1, "default width");
565     TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "set size 1");
566     TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "set size 2");
567     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
568
569     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
570
571     trace ("  TCS_FIXEDWIDTH buttons with icon...\n");
572     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
573     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
574     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
575     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
576     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
577
578     DestroyWindow (hwTab);
579
580     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
581     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
582
583     hdc = GetDC(hwTab);
584     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
585     ReleaseDC(hwTab, hdc);
586     trace ("  TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
587     CHECKSIZE(hwTab, dpi, -1, "no icon, default width");
588
589     TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "no icon, set size 1");
590     TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "no icon, set size 2");
591     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "no icon, min size");
592
593     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
594
595     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
596     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
597     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "with icon, min size");
598     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
599     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
600
601     DestroyWindow (hwTab);
602
603     hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
604     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
605
606     trace ("  non fixed width, with text...\n");
607     exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth);
608     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
609     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
610         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
611
612     for (i=0; i<8; i++)
613     {
614         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
615
616         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
617         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
618
619         TABCHECKSETSIZE(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
620         TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
621
622         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
623         nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
624
625         TABCHECKSETSIZE(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
626         TABCHECKSETSIZE(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
627         TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
628     }
629     DestroyWindow (hwTab);
630
631     hwTab = create_tabcontrol(0, TCIF_IMAGE);
632     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
633
634     trace ("  non fixed width, no text...\n");
635     exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth;
636     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
637     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
638         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
639
640     for (i=0; i<8; i++)
641     {
642         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
643
644         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
645         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
646
647         TABCHECKSETSIZE(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
648         TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
649
650         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
651         if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
652             nTabWidth += EXTRA_ICON_PADDING *(i-1);
653
654         TABCHECKSETSIZE(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
655         TABCHECKSETSIZE(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
656         TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
657     }
658
659     DestroyWindow (hwTab);
660
661     ImageList_Destroy(himl);
662 }
663
664 static void test_width(void)
665 {
666     trace ("Testing with default MinWidth\n");
667     test_tab(-1);
668     trace ("Testing with MinWidth set to -3\n");
669     test_tab(-3);
670     trace ("Testing with MinWidth set to 24\n");
671     test_tab(24);
672     trace ("Testing with MinWidth set to 54\n");
673     test_tab(54);
674     trace ("Testing with MinWidth set to 94\n");
675     test_tab(94);
676 }
677
678 static void test_curfocus(void)
679 {
680     const INT nTabs = 5;
681     INT focusIndex;
682     HWND hTab;
683
684     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
685     ok(hTab != NULL, "Failed to create tab control\n");
686
687     flush_sequences(sequences, NUM_MSG_SEQUENCES);
688
689     /* Testing CurFocus with largest appropriate value */
690     SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
691     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
692     expect(nTabs-1, focusIndex);
693
694     /* Testing CurFocus with negative value */
695     SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
696     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
697     expect(-1, focusIndex);
698
699     /* Testing CurFocus with value larger than number of tabs */
700     focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
701     expect(-1, focusIndex);
702
703     SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
704     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
705     expect(1, focusIndex);
706
707     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
708
709     DestroyWindow(hTab);
710 }
711
712 static void test_cursel(void)
713 {
714     const INT nTabs = 5;
715     INT selectionIndex;
716     INT focusIndex;
717     TCITEM tcItem;
718     HWND hTab;
719
720     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
721     ok(hTab != NULL, "Failed to create tab control\n");
722
723     flush_sequences(sequences, NUM_MSG_SEQUENCES);
724
725     /* Testing CurSel with largest appropriate value */
726     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0);
727     expect(0, selectionIndex);
728     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
729     expect(nTabs-1, selectionIndex);
730
731     /* Focus should switch with selection */
732     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
733     expect(nTabs-1, focusIndex);
734
735     /* Testing CurSel with negative value */
736     SendMessage(hTab, TCM_SETCURSEL, -10, 0);
737     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
738     expect(-1, selectionIndex);
739
740     /* Testing CurSel with value larger than number of tabs */
741     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
742     expect(-1, selectionIndex);
743
744     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0);
745     expect(-1, selectionIndex);
746     selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
747     expect(1, selectionIndex);
748
749     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE);
750     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE);
751
752     /* selected item should have TCIS_BUTTONPRESSED state
753        It doesn't depend on button state */
754     memset(&tcItem, 0, sizeof(TCITEM));
755     tcItem.mask = TCIF_STATE;
756     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
757     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
758     SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem);
759     ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */
760         "Selected item should have TCIS_BUTTONPRESSED\n");
761
762     DestroyWindow(hTab);
763 }
764
765 static void test_extendedstyle(void)
766 {
767     const INT nTabs = 5;
768     DWORD prevExtendedStyle;
769     DWORD extendedStyle;
770     HWND hTab;
771
772     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
773     ok(hTab != NULL, "Failed to create tab control\n");
774
775     flush_sequences(sequences, NUM_MSG_SEQUENCES);
776
777     /* Testing Flat Separators */
778     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
779     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
780     expect(extendedStyle, prevExtendedStyle);
781
782     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
783     expect(TCS_EX_FLATSEPARATORS, extendedStyle);
784
785     /* Testing Register Drop */
786     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
787     expect(extendedStyle, prevExtendedStyle);
788
789     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
790     todo_wine{
791         expect(TCS_EX_REGISTERDROP, extendedStyle);
792     }
793
794     ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE);
795     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE);
796
797     DestroyWindow(hTab);
798 }
799
800 static void test_unicodeformat(void)
801 {
802     const INT nTabs = 5;
803     INT unicodeFormat;
804     HWND hTab;
805
806     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
807     ok(hTab != NULL, "Failed to create tab control\n");
808
809     flush_sequences(sequences, NUM_MSG_SEQUENCES);
810
811     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
812     todo_wine{
813         expect(0, unicodeFormat);
814     }
815     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
816     expect(1, unicodeFormat);
817
818     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
819     expect(1, unicodeFormat);
820     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
821     expect(0, unicodeFormat);
822
823     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
824     expect(0, unicodeFormat);
825
826     ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE);
827     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE);
828
829     DestroyWindow(hTab);
830 }
831
832 static void test_getset_item(void)
833 {
834     char szText[32] = "New Label";
835     const INT nTabs = 5;
836     TCITEM tcItem;
837     LPARAM lparam;
838     DWORD ret;
839     HWND hTab;
840
841     hTab = CreateWindowA(
842         WC_TABCONTROLA,
843         "TestTab",
844         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
845         10, 10, 300, 100,
846         parent_wnd, NULL, NULL, 0);
847
848     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
849
850     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
851     ok(ret == TRUE, "got %d\n", ret);
852
853     /* set some item data */
854     tcItem.lParam = ~0;
855     tcItem.mask = TCIF_PARAM;
856
857     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&tcItem);
858     ok(ret == 0, "got %d\n", ret);
859
860     /* all sizeof(LPARAM) returned anyway when using sizeof(LPARAM)-1 size */
861     memset(&lparam, 0xaa, sizeof(lparam));
862     tcItem.lParam = lparam;
863     tcItem.mask = TCIF_PARAM;
864     ret = SendMessage(hTab, TCM_GETITEM, 0, (LPARAM)&tcItem);
865     expect(TRUE, ret);
866     /* everything higher specified size is preserved */
867     memset(&lparam, 0xff, sizeof(lparam)-1);
868     ok(tcItem.lParam == lparam, "Expected 0x%lx, got 0x%lx\n", lparam, tcItem.lParam);
869
870     DestroyWindow(hTab);
871
872     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
873     ok(hTab != NULL, "Failed to create tab control\n");
874
875     /* passing invalid index should result in initialization to zero
876        for members mentioned in mask requested */
877
878     /* valid range here is [0,4] */
879     memset(&tcItem, 0xcc, sizeof(tcItem));
880     tcItem.mask = TCIF_PARAM;
881     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
882     expect(FALSE, ret);
883     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
884
885     memset(&tcItem, 0xcc, sizeof(tcItem));
886     tcItem.mask = TCIF_IMAGE;
887     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
888     expect(FALSE, ret);
889     expect(0, tcItem.iImage);
890
891     memset(&tcItem, 0xcc, sizeof(tcItem));
892     tcItem.mask = TCIF_TEXT;
893     tcItem.pszText = szText;
894     szText[0] = 'a';
895     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
896     expect(FALSE, ret);
897     expect('a', szText[0]);
898
899     memset(&tcItem, 0xcc, sizeof(tcItem));
900     tcItem.mask = TCIF_STATE;
901     tcItem.dwStateMask = 0;
902     tcItem.dwState = TCIS_BUTTONPRESSED;
903     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
904     expect(FALSE, ret);
905     ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState);
906
907     memset(&tcItem, 0xcc, sizeof(tcItem));
908     tcItem.mask = TCIF_STATE;
909     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
910     tcItem.dwState = TCIS_BUTTONPRESSED;
911     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
912     expect(FALSE, ret);
913     ok(tcItem.dwState == 0, "Expected zero dwState\n");
914
915     /* check with negative index to be sure */
916     memset(&tcItem, 0xcc, sizeof(tcItem));
917     tcItem.mask = TCIF_PARAM;
918     ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem);
919     expect(FALSE, ret);
920     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
921
922     memset(&tcItem, 0xcc, sizeof(tcItem));
923     tcItem.mask = TCIF_PARAM;
924     ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem);
925     expect(FALSE, ret);
926     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
927
928     flush_sequences(sequences, NUM_MSG_SEQUENCES);
929
930     tcItem.mask = TCIF_TEXT;
931     tcItem.pszText = &szText[0];
932     tcItem.cchTextMax = sizeof(szText);
933
934     strcpy(szText, "New Label");
935     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
936     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
937     expect_str("New Label", tcItem.pszText);
938
939     ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n");
940     expect_str("Tab 2", tcItem.pszText);
941
942     ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE);
943     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE);
944
945     /* TCIS_BUTTONPRESSED doesn't depend on tab style */
946     memset(&tcItem, 0, sizeof(tcItem));
947     tcItem.mask = TCIF_STATE;
948     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
949     tcItem.dwState = TCIS_BUTTONPRESSED;
950     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
951     tcItem.dwState = 0;
952     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
953     if (tcItem.dwState)
954     {
955         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
956         /* next highlight item, test that dwStateMask actually masks */
957         tcItem.mask = TCIF_STATE;
958         tcItem.dwStateMask = TCIS_HIGHLIGHTED;
959         tcItem.dwState = TCIS_HIGHLIGHTED;
960         ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
961         tcItem.dwState = 0;
962         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
963         ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n");
964         tcItem.mask = TCIF_STATE;
965         tcItem.dwStateMask = TCIS_BUTTONPRESSED;
966         tcItem.dwState = 0;
967         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
968         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
969     }
970     else win_skip( "Item state mask not supported\n" );
971
972     DestroyWindow(hTab);
973 }
974
975 static void test_getset_tooltips(void)
976 {
977     char toolTipText[32] = "ToolTip Text Test";
978     const INT nTabs = 5;
979     HWND hTab, toolTip;
980
981     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
982     ok(hTab != NULL, "Failed to create tab control\n");
983
984     flush_sequences(sequences, NUM_MSG_SEQUENCES);
985
986     toolTip = create_tooltip(hTab, toolTipText);
987     SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0);
988     ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
989
990     SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0);
991     ok (NULL  == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
992
993     ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE);
994     ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE);
995
996     DestroyWindow(hTab);
997 }
998
999 static void test_misc(void)
1000 {
1001     const INT nTabs = 5;
1002     HWND hTab;
1003     RECT rTab;
1004     INT nTabsRetrieved;
1005     INT rowCount;
1006     INT dpi;
1007     HDC hdc;
1008
1009     ok(parent_wnd != NULL, "no parent window!\n");
1010     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1011
1012     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
1013     ok(hTab != NULL, "Failed to create tab control\n");
1014
1015     if(!winetest_interactive)
1016         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent,
1017                     "Tab sequence, after adding tab control to parent", TRUE);
1018     else
1019         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent_interactive,
1020                     "Tab sequence, after adding tab control to parent", TRUE);
1021
1022     if(!winetest_interactive)
1023         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq,
1024                     "Parent after sequence, adding tab control to parent", TRUE);
1025     else
1026         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq_interactive,
1027                     "Parent after sequence, adding tab control to parent", TRUE);
1028
1029     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1030     ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n");
1031     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE);
1032
1033     /* Testing GetItemCount */
1034     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1035     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1036     expect(nTabs, nTabsRetrieved);
1037     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_count_seq, "Get itemCount test sequence", FALSE);
1038     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset itemCount test parent sequence", FALSE);
1039
1040     /* Testing GetRowCount */
1041     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1042     rowCount = SendMessage(hTab, TCM_GETROWCOUNT, 0, 0);
1043     expect(1, rowCount);
1044     ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE);
1045     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE);
1046
1047     /* Testing GetItemRect */
1048     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1049     ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n");
1050
1051     hdc = GetDC(hTab);
1052     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
1053     ReleaseDC(hTab, hdc);
1054     CHECKSIZE(hTab, dpi, -1 , "Default Width");
1055     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE);
1056     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE);
1057
1058     DestroyWindow(hTab);
1059 }
1060
1061 static void test_adjustrect(void)
1062 {
1063     HWND hTab;
1064     INT r;
1065
1066     ok(parent_wnd != NULL, "no parent window!\n");
1067
1068     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, 0, 0);
1069     ok(hTab != NULL, "Failed to create tab control\n");
1070
1071     r = SendMessage(hTab, TCM_ADJUSTRECT, FALSE, 0);
1072     expect(-1, r);
1073
1074     r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0);
1075     expect(-1, r);
1076 }
1077
1078 static void test_insert_focus(void)
1079 {
1080     HWND hTab;
1081     INT nTabsRetrieved;
1082     INT r;
1083     TCITEM tcNewTab;
1084     DWORD mask = TCIF_TEXT|TCIF_IMAGE;
1085     static char tabName[] = "TAB";
1086     tcNewTab.mask = mask;
1087     tcNewTab.pszText = tabName;
1088
1089     ok(parent_wnd != NULL, "no parent window!\n");
1090
1091     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0);
1092     ok(hTab != NULL, "Failed to create tab control\n");
1093
1094     r = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1095     expect(-1, r);
1096
1097     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1098
1099     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1100     expect(0, nTabsRetrieved);
1101
1102     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1103     expect(-1, r);
1104
1105     tcNewTab.iImage = 1;
1106     r = SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
1107     expect(0, r);
1108
1109     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1110     expect(1, nTabsRetrieved);
1111
1112     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1113     expect(0, r);
1114
1115     tcNewTab.iImage = 2;
1116     r = SendMessage(hTab, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
1117     expect(1, r);
1118
1119     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1120     expect(2, nTabsRetrieved);
1121
1122     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1123     expect(0, r);
1124
1125     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1126     expect(0, r);
1127
1128     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1129     expect(-1, r);
1130
1131     tcNewTab.iImage = 3;
1132     r = SendMessage(hTab, TCM_INSERTITEM, 3, (LPARAM) &tcNewTab);
1133     expect(2, r);
1134
1135     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1136     expect(2, r);
1137
1138     ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE);
1139     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE);
1140
1141     DestroyWindow(hTab);
1142 }
1143
1144 static void test_delete_focus(void)
1145 {
1146     HWND hTab;
1147     INT nTabsRetrieved;
1148     INT r;
1149
1150     ok(parent_wnd != NULL, "no parent window!\n");
1151
1152     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2);
1153     ok(hTab != NULL, "Failed to create tab control\n");
1154
1155     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1156
1157     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1158     expect(2, nTabsRetrieved);
1159
1160     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1161     expect(0, r);
1162
1163     r = SendMessage(hTab, TCM_DELETEITEM, 1, 0);
1164     expect(1, r);
1165
1166     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1167     expect(1, nTabsRetrieved);
1168
1169     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1170     expect(0, r);
1171
1172     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1173     expect(0, r);
1174
1175     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1176     expect(-1, r);
1177
1178     r = SendMessage(hTab, TCM_DELETEITEM, 0, 0);
1179     expect(1, r);
1180
1181     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1182     expect(0, nTabsRetrieved);
1183
1184     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1185     expect(-1, r);
1186
1187     ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
1188     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE);
1189
1190     DestroyWindow(hTab);
1191 }
1192
1193 static void test_removeimage(void)
1194 {
1195     static const BYTE bits[32];
1196     HWND hwTab;
1197     INT i;
1198     TCITEM item;
1199     HICON hicon;
1200     HIMAGELIST himl = ImageList_Create(16, 16, ILC_COLOR, 3, 4);
1201
1202     hicon = CreateIcon(NULL, 16, 16, 1, 1, bits, bits);
1203     ImageList_AddIcon(himl, hicon);
1204     ImageList_AddIcon(himl, hicon);
1205     ImageList_AddIcon(himl, hicon);
1206
1207     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
1208     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
1209
1210     memset(&item, 0, sizeof(TCITEM));
1211     item.mask = TCIF_IMAGE;
1212
1213     for(i = 0; i < 3; i++) {
1214         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1215         expect(i, item.iImage);
1216     }
1217
1218     /* remove image middle image */
1219     SendMessage(hwTab, TCM_REMOVEIMAGE, 1, 0);
1220     expect(2, ImageList_GetImageCount(himl));
1221     item.iImage = -1;
1222     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1223     expect(0, item.iImage);
1224     item.iImage = 0;
1225     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1226     expect(-1, item.iImage);
1227     item.iImage = 0;
1228     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1229     expect(1, item.iImage);
1230     /* remove first image */
1231     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1232     expect(1, ImageList_GetImageCount(himl));
1233     item.iImage = 0;
1234     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1235     expect(-1, item.iImage);
1236     item.iImage = 0;
1237     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1238     expect(-1, item.iImage);
1239     item.iImage = -1;
1240     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1241     expect(0, item.iImage);
1242     /* remove the last one */
1243     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1244     expect(0, ImageList_GetImageCount(himl));
1245     for(i = 0; i < 3; i++) {
1246         item.iImage = 0;
1247         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1248         expect(-1, item.iImage);
1249     }
1250
1251     DestroyWindow(hwTab);
1252     ImageList_Destroy(himl);
1253     DestroyIcon(hicon);
1254 }
1255
1256 static void test_delete_selection(void)
1257 {
1258     HWND hTab;
1259     INT ret;
1260
1261     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1262     ok(hTab != NULL, "Failed to create tab control\n");
1263
1264     ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0);
1265     expect(0, ret);
1266     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1267     expect(3, ret);
1268     /* delete selected item - selection goes to -1 */
1269     ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0);
1270     expect(TRUE, ret);
1271
1272     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1273     expect(-1, ret);
1274
1275     DestroyWindow(hTab);
1276 }
1277
1278 static void test_TCM_SETITEMEXTRA(void)
1279 {
1280     HWND hTab;
1281     DWORD ret;
1282
1283     hTab = CreateWindowA(
1284         WC_TABCONTROLA,
1285         "TestTab",
1286         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH,
1287         10, 10, 300, 100,
1288         parent_wnd, NULL, NULL, 0);
1289
1290     /* zero is valid size too */
1291     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 0, 0);
1292     if (ret == FALSE)
1293     {
1294         win_skip("TCM_SETITEMEXTRA not supported\n");
1295         DestroyWindow(hTab);
1296         return;
1297     }
1298
1299     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, -1, 0);
1300     ok(ret == FALSE, "got %d\n", ret);
1301
1302     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
1303     ok(ret == TRUE, "got %d\n", ret);
1304     DestroyWindow(hTab);
1305
1306     /* it's not possible to change extra data size for control with tabs */
1307     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1308     ok(hTab != NULL, "Failed to create tab control\n");
1309
1310     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
1311     ok(ret == FALSE, "got %d\n", ret);
1312     DestroyWindow(hTab);
1313 }
1314
1315 static void test_TCS_OWNERDRAWFIXED(void)
1316 {
1317     LPARAM lparam;
1318     ULONG_PTR itemdata, itemdata2;
1319     TCITEMA item;
1320     HWND hTab;
1321     BOOL ret;
1322
1323     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH|TCS_OWNERDRAWFIXED, TCIF_TEXT|TCIF_IMAGE, 4);
1324     ok(hTab != NULL, "Failed to create tab control\n");
1325
1326     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1327
1328     /* set some item data */
1329     memset(&lparam, 0xde, sizeof(LPARAM));
1330
1331     item.mask = TCIF_PARAM;
1332     item.lParam = lparam;
1333     ret = SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&item);
1334     ok(ret == TRUE, "got %d\n", ret);
1335
1336     memset(&g_drawitem, 0, sizeof(g_drawitem));
1337
1338     ShowWindow(hTab, SW_SHOW);
1339     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1340
1341     itemdata = 0;
1342     memset(&itemdata, 0xde, 4);
1343     ok(g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1344
1345     DestroyWindow(hTab);
1346
1347     /* now with custom extra data length */
1348     hTab = CreateWindowA(
1349         WC_TABCONTROLA,
1350         "TestTab",
1351         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
1352         10, 10, 300, 100,
1353         parent_wnd, NULL, NULL, 0);
1354
1355     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1356
1357     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)+1, 0);
1358     ok(ret == TRUE, "got %d\n", ret);
1359
1360     /* set some item data */
1361     memset(&lparam, 0xde, sizeof(LPARAM));
1362     item.mask = TCIF_PARAM;
1363     item.lParam = lparam;
1364
1365     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
1366     ok(ret == 0, "got %d\n", ret);
1367
1368     memset(&g_drawitem, 0, sizeof(g_drawitem));
1369
1370     ShowWindow(hTab, SW_SHOW);
1371     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1372
1373     memset(&itemdata, 0xde, sizeof(ULONG_PTR));
1374     ok(*(ULONG_PTR*)g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1375
1376     DestroyWindow(hTab);
1377
1378     /* same thing, but size smaller than default */
1379     hTab = CreateWindowA(
1380         WC_TABCONTROLA,
1381         "TestTab",
1382         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
1383         10, 10, 300, 100,
1384         parent_wnd, NULL, NULL, 0);
1385
1386     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1387
1388     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
1389     ok(ret == TRUE, "got %d\n", ret);
1390
1391     memset(&lparam, 0xde, sizeof(lparam));
1392     item.mask = TCIF_PARAM;
1393     item.lParam = lparam;
1394
1395     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
1396     ok(ret == 0, "got %d\n", ret);
1397
1398     memset(&g_drawitem, 0, sizeof(g_drawitem));
1399
1400     ShowWindow(hTab, SW_SHOW);
1401     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1402
1403     itemdata = itemdata2 = 0;
1404     memset(&itemdata, 0xde, 4);
1405     memset(&itemdata2, 0xde, sizeof(LPARAM)-1);
1406     ok(g_drawitem.itemData == itemdata || broken(g_drawitem.itemData == itemdata2) /* win98 */,
1407         "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1408
1409     DestroyWindow(hTab);
1410 }
1411
1412 static void test_WM_CONTEXTMENU(void)
1413 {
1414     HWND hTab;
1415
1416     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1417     ok(hTab != NULL, "Failed to create tab control\n");
1418
1419     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1420
1421     SendMessageA(hTab, WM_RBUTTONUP, 0, 0);
1422
1423     ok_sequence(sequences, TAB_SEQ_INDEX, rbuttonup_seq, "WM_RBUTTONUP response sequence", FALSE);
1424
1425     DestroyWindow(hTab);
1426 }
1427
1428 struct tabcreate_style {
1429     DWORD style;
1430     DWORD act_style;
1431 };
1432
1433 static const struct tabcreate_style create_styles[] =
1434 {
1435     { WS_CHILD|TCS_BOTTOM|TCS_VERTICAL, WS_CHILD|WS_CLIPSIBLINGS|TCS_BOTTOM|TCS_VERTICAL|TCS_MULTILINE },
1436     { WS_CHILD|TCS_VERTICAL,            WS_CHILD|WS_CLIPSIBLINGS|TCS_VERTICAL|TCS_MULTILINE },
1437     { 0 }
1438 };
1439
1440 static void test_create(void)
1441 {
1442     const struct tabcreate_style *ptr = create_styles;
1443     DWORD style;
1444     HWND hTab;
1445
1446     while (ptr->style)
1447     {
1448         hTab = CreateWindowA(WC_TABCONTROLA, "TestTab", ptr->style,
1449             10, 10, 300, 100, parent_wnd, NULL, NULL, 0);
1450         style = GetWindowLongA(hTab, GWL_STYLE);
1451         ok(style == ptr->act_style, "expected style 0x%08x, got style 0x%08x\n", ptr->act_style, style);
1452
1453         DestroyWindow(hTab);
1454         ptr++;
1455     }
1456 }
1457
1458 START_TEST(tab)
1459 {
1460     LOGFONTA logfont;
1461
1462     lstrcpyA(logfont.lfFaceName, "Arial");
1463     memset(&logfont, 0, sizeof(logfont));
1464     logfont.lfHeight = -12;
1465     logfont.lfWeight = FW_NORMAL;
1466     logfont.lfCharSet = ANSI_CHARSET;
1467     hFont = CreateFontIndirectA(&logfont);
1468
1469     InitCommonControls();
1470
1471     test_width();
1472
1473     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1474
1475     parent_wnd = createParentWindow();
1476     ok(parent_wnd != NULL, "Failed to create parent window!\n");
1477
1478     test_curfocus();
1479     test_cursel();
1480     test_extendedstyle();
1481     test_unicodeformat();
1482     test_getset_item();
1483     test_getset_tooltips();
1484     test_misc();
1485
1486     test_adjustrect();
1487
1488     test_insert_focus();
1489     test_delete_focus();
1490     test_delete_selection();
1491     test_removeimage();
1492     test_TCM_SETITEMEXTRA();
1493     test_TCS_OWNERDRAWFIXED();
1494     test_WM_CONTEXTMENU();
1495     test_create();
1496
1497     DestroyWindow(parent_wnd);
1498 }