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