uxtheme: Remove unused variable.
[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         add_message(sequences, PARENT_SEQ_INDEX, &msg);
356     }
357
358     /* dump sent structure data */
359     if (message == WM_DRAWITEM)
360         g_drawitem = *(DRAWITEMSTRUCT*)lParam;
361
362     defwndproc_counter++;
363     ret = DefWindowProcA(hwnd, message, wParam, lParam);
364     defwndproc_counter--;
365
366     return ret;
367 }
368
369 static BOOL registerParentWindowClass(void)
370 {
371     WNDCLASSA cls;
372
373     cls.style = 0;
374     cls.lpfnWndProc = parentWindowProcess;
375     cls.cbClsExtra = 0;
376     cls.cbWndExtra = 0;
377     cls.hInstance = GetModuleHandleA(NULL);
378     cls.hIcon = 0;
379     cls.hCursor = LoadCursorA(0, IDC_ARROW);
380     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
381     cls.lpszMenuName = NULL;
382     cls.lpszClassName = "Tab test parent class";
383     return RegisterClassA(&cls);
384 }
385
386 static HWND createParentWindow(void)
387 {
388     if (!registerParentWindowClass())
389         return NULL;
390
391     return CreateWindowEx(0, "Tab test parent class",
392                           "Tab test parent window",
393                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
394                           WS_MAXIMIZEBOX | WS_VISIBLE,
395                           0, 0, 100, 100,
396                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
397 }
398
399 static LRESULT WINAPI tabSubclassProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
400 {
401     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
402     static LONG defwndproc_counter = 0;
403     LRESULT ret;
404     struct message msg;
405
406     /* do not log painting messages */
407     if (message != WM_PAINT &&
408         message != WM_ERASEBKGND &&
409         message != WM_NCPAINT &&
410         message != WM_NCHITTEST &&
411         message != WM_GETTEXT &&
412         message != WM_GETICON &&
413         message != WM_DEVICECHANGE)
414     {
415         trace("tab: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
416
417         msg.message = message;
418         msg.flags = sent|wparam|lparam;
419         if (defwndproc_counter) msg.flags |= defwinproc;
420         msg.wParam = wParam;
421         msg.lParam = lParam;
422         add_message(sequences, TAB_SEQ_INDEX, &msg);
423     }
424
425     defwndproc_counter++;
426     ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
427     defwndproc_counter--;
428
429     return ret;
430 }
431
432 static HWND createFilledTabControl(HWND parent_wnd, DWORD style, DWORD mask, INT nTabs)
433 {
434     HWND tabHandle;
435     TCITEM tcNewTab;
436     WNDPROC oldproc;
437     RECT rect;
438     INT i;
439
440     GetClientRect(parent_wnd, &rect);
441
442     tabHandle = CreateWindow (
443         WC_TABCONTROLA,
444         "TestTab",
445         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
446         0, 0, rect.right, rect.bottom,
447         parent_wnd, NULL, NULL, 0);
448
449     assert(tabHandle);
450
451     oldproc = (WNDPROC)SetWindowLongPtrA(tabHandle, GWLP_WNDPROC, (LONG_PTR)tabSubclassProcess);
452     SetWindowLongPtrA(tabHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
453
454     tcNewTab.mask = mask;
455
456     for (i = 0; i < nTabs; i++)
457     {
458         char tabName[MAX_TABLEN];
459
460         sprintf(tabName, "Tab %d", i+1);
461         tcNewTab.pszText = tabName;
462         tcNewTab.iImage = i;
463         SendMessage (tabHandle, TCM_INSERTITEM, i, (LPARAM) &tcNewTab);
464     }
465
466     if (winetest_interactive)
467     {
468         ShowWindow (tabHandle, SW_SHOW);
469         RedrawWindow (tabHandle, NULL, 0, RDW_UPDATENOW);
470         Sleep (1000);
471     }
472
473     return tabHandle;
474 }
475
476 static HWND create_tooltip (HWND hTab, char toolTipText[])
477 {
478     HWND hwndTT;
479
480     TOOLINFO ti;
481     LPTSTR lptstr = toolTipText;
482     RECT rect;
483
484     /* Creating a tooltip window*/
485     hwndTT = CreateWindowEx(
486         WS_EX_TOPMOST,
487         TOOLTIPS_CLASS,
488         NULL,
489         WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
490         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
491         hTab, NULL, 0, NULL);
492
493     SetWindowPos(
494         hwndTT,
495         HWND_TOPMOST,
496         0, 0, 0, 0,
497         SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
498
499     GetClientRect (hTab, &rect);
500
501     /* Initialize members of toolinfo*/
502     ti.cbSize = sizeof(TOOLINFO);
503     ti.uFlags = TTF_SUBCLASS;
504     ti.hwnd = hTab;
505     ti.hinst = 0;
506     ti.uId = 0;
507     ti.lpszText = lptstr;
508
509     ti.rect = rect;
510
511     /* Add toolinfo structure to the tooltip control */
512     SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) &ti);
513
514     return hwndTT;
515 }
516
517 static void test_tab(INT nMinTabWidth)
518 {
519     HWND hwTab;
520     RECT rTab;
521     HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4);
522     SIZE size;
523     HDC hdc;
524     HFONT hOldFont;
525     INT i, dpi, exp;
526
527     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
528     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
529     /* Get System default MinTabWidth */
530     if (nMinTabWidth < 0)
531         nMinTabWidth = SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
532
533     hdc = GetDC(hwTab);
534     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
535     hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
536     GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
537     trace("Tab1 text size: size.cx=%d size.cy=%d\n", size.cx, size.cy);
538     SelectObject(hdc, hOldFont);
539     ReleaseDC(hwTab, hdc);
540
541     trace ("  TCS_FIXEDWIDTH tabs no icon...\n");
542     CHECKSIZE(hwTab, dpi, -1, "default width");
543     TABCHECKSETSIZE(hwTab, 50, 20, 50, 20, "set size");
544     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
545
546     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
547
548     trace ("  TCS_FIXEDWIDTH tabs with icon...\n");
549     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
550     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
551     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
552
553     DestroyWindow (hwTab);
554
555     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
556     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
557
558     hdc = GetDC(hwTab);
559     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
560     ReleaseDC(hwTab, hdc);
561     trace ("  TCS_FIXEDWIDTH buttons no icon...\n");
562     CHECKSIZE(hwTab, dpi, -1, "default width");
563     TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "set size 1");
564     TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "set size 2");
565     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "min size");
566
567     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
568
569     trace ("  TCS_FIXEDWIDTH buttons with icon...\n");
570     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "set size > icon");
571     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "set size < icon");
572     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "min size");
573     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
574     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
575
576     DestroyWindow (hwTab);
577
578     hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
579     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
580
581     hdc = GetDC(hwTab);
582     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
583     ReleaseDC(hwTab, hdc);
584     trace ("  TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
585     CHECKSIZE(hwTab, dpi, -1, "no icon, default width");
586
587     TABCHECKSETSIZE(hwTab, 20, 20, 20, 20, "no icon, set size 1");
588     TABCHECKSETSIZE(hwTab, 10, 50, 10, 50, "no icon, set size 2");
589     TABCHECKSETSIZE(hwTab, 0, 1, 0, 1, "no icon, min size");
590
591     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
592
593     TABCHECKSETSIZE(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
594     TABCHECKSETSIZE(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
595     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "with icon, min size");
596     SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
597     TABCHECKSETSIZE(hwTab, 0, 1, 25, 1, "set padding, min size");
598
599     DestroyWindow (hwTab);
600
601     hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
602     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
603
604     trace ("  non fixed width, with text...\n");
605     exp = max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth);
606     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
607     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
608         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
609
610     for (i=0; i<8; i++)
611     {
612         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
613
614         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
615         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
616
617         TABCHECKSETSIZE(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
618         TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
619
620         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
621         nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
622
623         TABCHECKSETSIZE(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
624         TABCHECKSETSIZE(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
625         TABCHECKSETSIZE(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
626     }
627     DestroyWindow (hwTab);
628
629     hwTab = create_tabcontrol(0, TCIF_IMAGE);
630     SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
631
632     trace ("  non fixed width, no text...\n");
633     exp = (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth;
634     SendMessage( hwTab, TCM_GETITEMRECT, 0, (LPARAM)&rTab );
635     ok( rTab.right  - rTab.left == exp || broken(rTab.right  - rTab.left == DEFAULT_MIN_TAB_WIDTH),
636         "no icon, default width: Expected width [%d] got [%d]\n", exp, rTab.right - rTab.left );
637
638     for (i=0; i<8; i++)
639     {
640         INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
641
642         SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
643         SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
644
645         TABCHECKSETSIZE(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
646         TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
647
648         SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
649         if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
650             nTabWidth += EXTRA_ICON_PADDING *(i-1);
651
652         TABCHECKSETSIZE(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
653         TABCHECKSETSIZE(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
654         TABCHECKSETSIZE(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
655     }
656
657     DestroyWindow (hwTab);
658
659     ImageList_Destroy(himl);
660 }
661
662 static void test_width(void)
663 {
664     trace ("Testing with default MinWidth\n");
665     test_tab(-1);
666     trace ("Testing with MinWidth set to -3\n");
667     test_tab(-3);
668     trace ("Testing with MinWidth set to 24\n");
669     test_tab(24);
670     trace ("Testing with MinWidth set to 54\n");
671     test_tab(54);
672     trace ("Testing with MinWidth set to 94\n");
673     test_tab(94);
674 }
675
676 static void test_curfocus(void)
677 {
678     const INT nTabs = 5;
679     INT focusIndex;
680     HWND hTab;
681
682     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
683     ok(hTab != NULL, "Failed to create tab control\n");
684
685     flush_sequences(sequences, NUM_MSG_SEQUENCES);
686
687     /* Testing CurFocus with largest appropriate value */
688     SendMessage(hTab, TCM_SETCURFOCUS, nTabs-1, 0);
689     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
690     expect(nTabs-1, focusIndex);
691
692     /* Testing CurFocus with negative value */
693     SendMessage(hTab, TCM_SETCURFOCUS, -10, 0);
694     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
695     expect(-1, focusIndex);
696
697     /* Testing CurFocus with value larger than number of tabs */
698     focusIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
699     expect(-1, focusIndex);
700
701     SendMessage(hTab, TCM_SETCURFOCUS, nTabs+1, 0);
702     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
703     expect(1, focusIndex);
704
705     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_focus_seq, "Getset curFoc test sequence", FALSE);
706
707     DestroyWindow(hTab);
708 }
709
710 static void test_cursel(void)
711 {
712     const INT nTabs = 5;
713     INT selectionIndex;
714     INT focusIndex;
715     TCITEM tcItem;
716     HWND hTab;
717
718     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
719     ok(hTab != NULL, "Failed to create tab control\n");
720
721     flush_sequences(sequences, NUM_MSG_SEQUENCES);
722
723     /* Testing CurSel with largest appropriate value */
724     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs-1, 0);
725     expect(0, selectionIndex);
726     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
727     expect(nTabs-1, selectionIndex);
728
729     /* Focus should switch with selection */
730     focusIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
731     expect(nTabs-1, focusIndex);
732
733     /* Testing CurSel with negative value */
734     SendMessage(hTab, TCM_SETCURSEL, -10, 0);
735     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
736     expect(-1, selectionIndex);
737
738     /* Testing CurSel with value larger than number of tabs */
739     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, 1, 0);
740     expect(-1, selectionIndex);
741
742     selectionIndex = SendMessage(hTab, TCM_SETCURSEL, nTabs+1, 0);
743     expect(-1, selectionIndex);
744     selectionIndex = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
745     expect(1, selectionIndex);
746
747     ok_sequence(sequences, TAB_SEQ_INDEX, getset_cur_sel_seq, "Getset curSel test sequence", FALSE);
748     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset curSel test parent sequence", FALSE);
749
750     /* selected item should have TCIS_BUTTONPRESSED state
751        It doesn't depend on button state */
752     memset(&tcItem, 0, sizeof(TCITEM));
753     tcItem.mask = TCIF_STATE;
754     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
755     selectionIndex = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
756     SendMessage(hTab, TCM_GETITEM, selectionIndex, (LPARAM) &tcItem);
757     ok (tcItem.dwState & TCIS_BUTTONPRESSED || broken(tcItem.dwState == 0), /* older comctl32 */
758         "Selected item should have TCIS_BUTTONPRESSED\n");
759
760     DestroyWindow(hTab);
761 }
762
763 static void test_extendedstyle(void)
764 {
765     const INT nTabs = 5;
766     DWORD prevExtendedStyle;
767     DWORD extendedStyle;
768     HWND hTab;
769
770     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
771     ok(hTab != NULL, "Failed to create tab control\n");
772
773     flush_sequences(sequences, NUM_MSG_SEQUENCES);
774
775     /* Testing Flat Separators */
776     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
777     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_FLATSEPARATORS);
778     expect(extendedStyle, prevExtendedStyle);
779
780     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
781     expect(TCS_EX_FLATSEPARATORS, extendedStyle);
782
783     /* Testing Register Drop */
784     prevExtendedStyle = SendMessage(hTab, TCM_SETEXTENDEDSTYLE, 0, TCS_EX_REGISTERDROP);
785     expect(extendedStyle, prevExtendedStyle);
786
787     extendedStyle = SendMessage(hTab, TCM_GETEXTENDEDSTYLE, 0, 0);
788     todo_wine{
789         expect(TCS_EX_REGISTERDROP, extendedStyle);
790     }
791
792     ok_sequence(sequences, TAB_SEQ_INDEX, getset_extended_style_seq, "Getset extendedStyle test sequence", FALSE);
793     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset extendedStyle test parent sequence", FALSE);
794
795     DestroyWindow(hTab);
796 }
797
798 static void test_unicodeformat(void)
799 {
800     const INT nTabs = 5;
801     INT unicodeFormat;
802     HWND hTab;
803
804     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
805     ok(hTab != NULL, "Failed to create tab control\n");
806
807     flush_sequences(sequences, NUM_MSG_SEQUENCES);
808
809     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
810     todo_wine{
811         expect(0, unicodeFormat);
812     }
813     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
814     expect(1, unicodeFormat);
815
816     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, FALSE, 0);
817     expect(1, unicodeFormat);
818     unicodeFormat = SendMessage(hTab, TCM_GETUNICODEFORMAT, 0, 0);
819     expect(0, unicodeFormat);
820
821     unicodeFormat = SendMessage(hTab, TCM_SETUNICODEFORMAT, TRUE, 0);
822     expect(0, unicodeFormat);
823
824     ok_sequence(sequences, TAB_SEQ_INDEX, getset_unicode_format_seq, "Getset unicodeFormat test sequence", FALSE);
825     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset unicodeFormat test parent sequence", FALSE);
826
827     DestroyWindow(hTab);
828 }
829
830 static void test_getset_item(void)
831 {
832     char szText[32] = "New Label";
833     const INT nTabs = 5;
834     TCITEM tcItem;
835     LPARAM lparam;
836     DWORD ret;
837     HWND hTab;
838
839     hTab = CreateWindowA(
840         WC_TABCONTROLA,
841         "TestTab",
842         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
843         10, 10, 300, 100,
844         parent_wnd, NULL, NULL, 0);
845
846     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
847
848     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
849     ok(ret == TRUE, "got %d\n", ret);
850
851     /* set some item data */
852     tcItem.lParam = ~0;
853     tcItem.mask = TCIF_PARAM;
854
855     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&tcItem);
856     ok(ret == 0, "got %d\n", ret);
857
858     /* all sizeof(LPARAM) returned anyway when using sizeof(LPARAM)-1 size */
859     memset(&lparam, 0xaa, sizeof(lparam));
860     tcItem.lParam = lparam;
861     tcItem.mask = TCIF_PARAM;
862     ret = SendMessage(hTab, TCM_GETITEM, 0, (LPARAM)&tcItem);
863     expect(TRUE, ret);
864     /* everything higher specified size is preserved */
865     memset(&lparam, 0xff, sizeof(lparam)-1);
866     ok(tcItem.lParam == lparam, "Expected 0x%lx, got 0x%lx\n", lparam, tcItem.lParam);
867
868     DestroyWindow(hTab);
869
870     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
871     ok(hTab != NULL, "Failed to create tab control\n");
872
873     /* passing invalid index should result in initialization to zero
874        for members mentioned in mask requested */
875
876     /* valid range here is [0,4] */
877     memset(&tcItem, 0xcc, sizeof(tcItem));
878     tcItem.mask = TCIF_PARAM;
879     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
880     expect(FALSE, ret);
881     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
882
883     memset(&tcItem, 0xcc, sizeof(tcItem));
884     tcItem.mask = TCIF_IMAGE;
885     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
886     expect(FALSE, ret);
887     expect(0, tcItem.iImage);
888
889     memset(&tcItem, 0xcc, sizeof(tcItem));
890     tcItem.mask = TCIF_TEXT;
891     tcItem.pszText = szText;
892     szText[0] = 'a';
893     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
894     expect(FALSE, ret);
895     expect('a', szText[0]);
896
897     memset(&tcItem, 0xcc, sizeof(tcItem));
898     tcItem.mask = TCIF_STATE;
899     tcItem.dwStateMask = 0;
900     tcItem.dwState = TCIS_BUTTONPRESSED;
901     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
902     expect(FALSE, ret);
903     ok(tcItem.dwState == 0, "Expected zero dwState, got %u\n", tcItem.dwState);
904
905     memset(&tcItem, 0xcc, sizeof(tcItem));
906     tcItem.mask = TCIF_STATE;
907     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
908     tcItem.dwState = TCIS_BUTTONPRESSED;
909     ret = SendMessage(hTab, TCM_GETITEM, 5, (LPARAM)&tcItem);
910     expect(FALSE, ret);
911     ok(tcItem.dwState == 0, "Expected zero dwState\n");
912
913     /* check with negative index to be sure */
914     memset(&tcItem, 0xcc, sizeof(tcItem));
915     tcItem.mask = TCIF_PARAM;
916     ret = SendMessage(hTab, TCM_GETITEM, -1, (LPARAM)&tcItem);
917     expect(FALSE, ret);
918     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
919
920     memset(&tcItem, 0xcc, sizeof(tcItem));
921     tcItem.mask = TCIF_PARAM;
922     ret = SendMessage(hTab, TCM_GETITEM, -2, (LPARAM)&tcItem);
923     expect(FALSE, ret);
924     ok(tcItem.lParam == 0, "Expected zero lParam, got %lu\n", tcItem.lParam);
925
926     flush_sequences(sequences, NUM_MSG_SEQUENCES);
927
928     tcItem.mask = TCIF_TEXT;
929     tcItem.pszText = &szText[0];
930     tcItem.cchTextMax = sizeof(szText);
931
932     strcpy(szText, "New Label");
933     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
934     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
935     expect_str("New Label", tcItem.pszText);
936
937     ok ( SendMessage(hTab, TCM_GETITEM, 1, (LPARAM) &tcItem), "Getting item failed.\n");
938     expect_str("Tab 2", tcItem.pszText);
939
940     ok_sequence(sequences, TAB_SEQ_INDEX, getset_item_seq, "Getset item test sequence", FALSE);
941     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset item test parent sequence", FALSE);
942
943     /* TCIS_BUTTONPRESSED doesn't depend on tab style */
944     memset(&tcItem, 0, sizeof(tcItem));
945     tcItem.mask = TCIF_STATE;
946     tcItem.dwStateMask = TCIS_BUTTONPRESSED;
947     tcItem.dwState = TCIS_BUTTONPRESSED;
948     ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
949     tcItem.dwState = 0;
950     ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
951     if (tcItem.dwState)
952     {
953         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
954         /* next highlight item, test that dwStateMask actually masks */
955         tcItem.mask = TCIF_STATE;
956         tcItem.dwStateMask = TCIS_HIGHLIGHTED;
957         tcItem.dwState = TCIS_HIGHLIGHTED;
958         ok ( SendMessage(hTab, TCM_SETITEM, 0, (LPARAM) &tcItem), "Setting new item failed.\n");
959         tcItem.dwState = 0;
960         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
961         ok (tcItem.dwState == TCIS_HIGHLIGHTED, "TCIS_HIGHLIGHTED should be set.\n");
962         tcItem.mask = TCIF_STATE;
963         tcItem.dwStateMask = TCIS_BUTTONPRESSED;
964         tcItem.dwState = 0;
965         ok ( SendMessage(hTab, TCM_GETITEM, 0, (LPARAM) &tcItem), "Getting item failed.\n");
966         ok (tcItem.dwState == TCIS_BUTTONPRESSED, "TCIS_BUTTONPRESSED should be set.\n");
967     }
968     else win_skip( "Item state mask not supported\n" );
969
970     DestroyWindow(hTab);
971 }
972
973 static void test_getset_tooltips(void)
974 {
975     char toolTipText[32] = "ToolTip Text Test";
976     const INT nTabs = 5;
977     HWND hTab, toolTip;
978
979     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
980     ok(hTab != NULL, "Failed to create tab control\n");
981
982     flush_sequences(sequences, NUM_MSG_SEQUENCES);
983
984     toolTip = create_tooltip(hTab, toolTipText);
985     SendMessage(hTab, TCM_SETTOOLTIPS, (LPARAM) toolTip, 0);
986     ok (toolTip == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
987
988     SendMessage(hTab, TCM_SETTOOLTIPS, 0, 0);
989     ok (NULL  == (HWND) SendMessage(hTab,TCM_GETTOOLTIPS,0,0), "ToolTip was set incorrectly.\n");
990
991     ok_sequence(sequences, TAB_SEQ_INDEX, getset_tooltip_seq, "Getset tooltip test sequence", TRUE);
992     ok_sequence(sequences, PARENT_SEQ_INDEX, getset_tooltip_parent_seq, "Getset tooltip test parent sequence", TRUE);
993
994     DestroyWindow(hTab);
995 }
996
997 static void test_misc(void)
998 {
999     const INT nTabs = 5;
1000     HWND hTab;
1001     RECT rTab;
1002     INT nTabsRetrieved;
1003     INT rowCount;
1004     INT dpi;
1005     HDC hdc;
1006
1007     ok(parent_wnd != NULL, "no parent window!\n");
1008     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1009
1010     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, nTabs);
1011     ok(hTab != NULL, "Failed to create tab control\n");
1012
1013     if(!winetest_interactive)
1014         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent,
1015                     "Tab sequence, after adding tab control to parent", TRUE);
1016     else
1017         ok_sequence(sequences, TAB_SEQ_INDEX, add_tab_to_parent_interactive,
1018                     "Tab sequence, after adding tab control to parent", TRUE);
1019
1020     if(!winetest_interactive)
1021         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq,
1022                     "Parent after sequence, adding tab control to parent", TRUE);
1023     else
1024         ok_sequence(sequences, PARENT_SEQ_INDEX, add_tab_control_parent_seq_interactive,
1025                     "Parent after sequence, adding tab control to parent", TRUE);
1026
1027     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1028     ok(SendMessage(hTab, TCM_SETMINTABWIDTH, 0, -1) > 0,"TCM_SETMINTABWIDTH returned < 0\n");
1029     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Set minTabWidth test parent sequence", FALSE);
1030
1031     /* Testing GetItemCount */
1032     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1033     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1034     expect(nTabs, nTabsRetrieved);
1035     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_count_seq, "Get itemCount test sequence", FALSE);
1036     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Getset itemCount test parent sequence", FALSE);
1037
1038     /* Testing GetRowCount */
1039     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1040     rowCount = SendMessage(hTab, TCM_GETROWCOUNT, 0, 0);
1041     expect(1, rowCount);
1042     ok_sequence(sequences, TAB_SEQ_INDEX, get_row_count_seq, "Get rowCount test sequence", FALSE);
1043     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get rowCount test parent sequence", FALSE);
1044
1045     /* Testing GetItemRect */
1046     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1047     ok(SendMessage(hTab, TCM_GETITEMRECT, 0, (LPARAM) &rTab), "GetItemRect failed.\n");
1048
1049     hdc = GetDC(hTab);
1050     dpi = GetDeviceCaps(hdc, LOGPIXELSX);
1051     ReleaseDC(hTab, hdc);
1052     CHECKSIZE(hTab, dpi, -1 , "Default Width");
1053     ok_sequence(sequences, TAB_SEQ_INDEX, get_item_rect_seq, "Get itemRect test sequence", FALSE);
1054     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "Get itemRect test parent sequence", FALSE);
1055
1056     DestroyWindow(hTab);
1057 }
1058
1059 static void test_adjustrect(void)
1060 {
1061     HWND hTab;
1062     INT r;
1063
1064     ok(parent_wnd != NULL, "no parent window!\n");
1065
1066     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, 0, 0);
1067     ok(hTab != NULL, "Failed to create tab control\n");
1068
1069     r = SendMessage(hTab, TCM_ADJUSTRECT, FALSE, 0);
1070     expect(-1, r);
1071
1072     r = SendMessage(hTab, TCM_ADJUSTRECT, TRUE, 0);
1073     expect(-1, r);
1074 }
1075
1076 static void test_insert_focus(void)
1077 {
1078     HWND hTab;
1079     INT nTabsRetrieved;
1080     INT r;
1081     TCITEM tcNewTab;
1082     DWORD mask = TCIF_TEXT|TCIF_IMAGE;
1083     static char tabName[] = "TAB";
1084     tcNewTab.mask = mask;
1085     tcNewTab.pszText = tabName;
1086
1087     ok(parent_wnd != NULL, "no parent window!\n");
1088
1089     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, mask, 0);
1090     ok(hTab != NULL, "Failed to create tab control\n");
1091
1092     r = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1093     expect(-1, r);
1094
1095     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1096
1097     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1098     expect(0, nTabsRetrieved);
1099
1100     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1101     expect(-1, r);
1102
1103     tcNewTab.iImage = 1;
1104     r = SendMessage(hTab, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
1105     expect(0, r);
1106
1107     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1108     expect(1, nTabsRetrieved);
1109
1110     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1111     expect(0, r);
1112
1113     tcNewTab.iImage = 2;
1114     r = SendMessage(hTab, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
1115     expect(1, r);
1116
1117     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1118     expect(2, nTabsRetrieved);
1119
1120     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1121     expect(0, r);
1122
1123     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1124     expect(0, r);
1125
1126     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1127     expect(-1, r);
1128
1129     tcNewTab.iImage = 3;
1130     r = SendMessage(hTab, TCM_INSERTITEM, 3, (LPARAM) &tcNewTab);
1131     expect(2, r);
1132
1133     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1134     expect(2, r);
1135
1136     ok_sequence(sequences, TAB_SEQ_INDEX, insert_focus_seq, "insert_focus test sequence", FALSE);
1137     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "insert_focus parent test sequence", TRUE);
1138
1139     DestroyWindow(hTab);
1140 }
1141
1142 static void test_delete_focus(void)
1143 {
1144     HWND hTab;
1145     INT nTabsRetrieved;
1146     INT r;
1147
1148     ok(parent_wnd != NULL, "no parent window!\n");
1149
1150     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 2);
1151     ok(hTab != NULL, "Failed to create tab control\n");
1152
1153     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1154
1155     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1156     expect(2, nTabsRetrieved);
1157
1158     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1159     expect(0, r);
1160
1161     r = SendMessage(hTab, TCM_DELETEITEM, 1, 0);
1162     expect(1, r);
1163
1164     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1165     expect(1, nTabsRetrieved);
1166
1167     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1168     expect(0, r);
1169
1170     r = SendMessage(hTab, TCM_SETCURFOCUS, -1, 0);
1171     expect(0, r);
1172
1173     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1174     expect(-1, r);
1175
1176     r = SendMessage(hTab, TCM_DELETEITEM, 0, 0);
1177     expect(1, r);
1178
1179     nTabsRetrieved = SendMessage(hTab, TCM_GETITEMCOUNT, 0, 0);
1180     expect(0, nTabsRetrieved);
1181
1182     r = SendMessage(hTab, TCM_GETCURFOCUS, 0, 0);
1183     expect(-1, r);
1184
1185     ok_sequence(sequences, TAB_SEQ_INDEX, delete_focus_seq, "delete_focus test sequence", FALSE);
1186     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_sequence, "delete_focus parent test sequence", TRUE);
1187
1188     DestroyWindow(hTab);
1189 }
1190
1191 static void test_removeimage(void)
1192 {
1193     static const BYTE bits[32];
1194     HWND hwTab;
1195     INT i;
1196     TCITEM item;
1197     HICON hicon;
1198     HIMAGELIST himl = ImageList_Create(16, 16, ILC_COLOR, 3, 4);
1199
1200     hicon = CreateIcon(NULL, 16, 16, 1, 1, bits, bits);
1201     ImageList_AddIcon(himl, hicon);
1202     ImageList_AddIcon(himl, hicon);
1203     ImageList_AddIcon(himl, hicon);
1204
1205     hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
1206     SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
1207
1208     memset(&item, 0, sizeof(TCITEM));
1209     item.mask = TCIF_IMAGE;
1210
1211     for(i = 0; i < 3; i++) {
1212         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1213         expect(i, item.iImage);
1214     }
1215
1216     /* remove image middle image */
1217     SendMessage(hwTab, TCM_REMOVEIMAGE, 1, 0);
1218     expect(2, ImageList_GetImageCount(himl));
1219     item.iImage = -1;
1220     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1221     expect(0, item.iImage);
1222     item.iImage = 0;
1223     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1224     expect(-1, item.iImage);
1225     item.iImage = 0;
1226     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1227     expect(1, item.iImage);
1228     /* remove first image */
1229     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1230     expect(1, ImageList_GetImageCount(himl));
1231     item.iImage = 0;
1232     SendMessage(hwTab, TCM_GETITEM, 0, (LPARAM)&item);
1233     expect(-1, item.iImage);
1234     item.iImage = 0;
1235     SendMessage(hwTab, TCM_GETITEM, 1, (LPARAM)&item);
1236     expect(-1, item.iImage);
1237     item.iImage = -1;
1238     SendMessage(hwTab, TCM_GETITEM, 2, (LPARAM)&item);
1239     expect(0, item.iImage);
1240     /* remove the last one */
1241     SendMessage(hwTab, TCM_REMOVEIMAGE, 0, 0);
1242     expect(0, ImageList_GetImageCount(himl));
1243     for(i = 0; i < 3; i++) {
1244         item.iImage = 0;
1245         SendMessage(hwTab, TCM_GETITEM, i, (LPARAM)&item);
1246         expect(-1, item.iImage);
1247     }
1248
1249     DestroyWindow(hwTab);
1250     ImageList_Destroy(himl);
1251     DestroyIcon(hicon);
1252 }
1253
1254 static void test_delete_selection(void)
1255 {
1256     HWND hTab;
1257     INT ret;
1258
1259     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1260     ok(hTab != NULL, "Failed to create tab control\n");
1261
1262     ret = SendMessage(hTab, TCM_SETCURSEL, 3, 0);
1263     expect(0, ret);
1264     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1265     expect(3, ret);
1266     /* delete selected item - selection goes to -1 */
1267     ret = SendMessage(hTab, TCM_DELETEITEM, 3, 0);
1268     expect(TRUE, ret);
1269
1270     ret = SendMessage(hTab, TCM_GETCURSEL, 0, 0);
1271     expect(-1, ret);
1272
1273     DestroyWindow(hTab);
1274 }
1275
1276 static void test_TCM_SETITEMEXTRA(void)
1277 {
1278     HWND hTab;
1279     DWORD ret;
1280
1281     hTab = CreateWindowA(
1282         WC_TABCONTROLA,
1283         "TestTab",
1284         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH,
1285         10, 10, 300, 100,
1286         parent_wnd, NULL, NULL, 0);
1287
1288     /* zero is valid size too */
1289     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 0, 0);
1290     if (ret == FALSE)
1291     {
1292         win_skip("TCM_SETITEMEXTRA not supported\n");
1293         DestroyWindow(hTab);
1294         return;
1295     }
1296
1297     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, -1, 0);
1298     ok(ret == FALSE, "got %d\n", ret);
1299
1300     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
1301     ok(ret == TRUE, "got %d\n", ret);
1302     DestroyWindow(hTab);
1303
1304     /* it's not possible to change extra data size for control with tabs */
1305     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1306     ok(hTab != NULL, "Failed to create tab control\n");
1307
1308     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, 2, 0);
1309     ok(ret == FALSE, "got %d\n", ret);
1310     DestroyWindow(hTab);
1311 }
1312
1313 static void test_TCS_OWNERDRAWFIXED(void)
1314 {
1315     LPARAM lparam;
1316     ULONG_PTR itemdata, itemdata2;
1317     TCITEMA item;
1318     HWND hTab;
1319     BOOL ret;
1320
1321     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH|TCS_OWNERDRAWFIXED, TCIF_TEXT|TCIF_IMAGE, 4);
1322     ok(hTab != NULL, "Failed to create tab control\n");
1323
1324     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1325
1326     /* set some item data */
1327     memset(&lparam, 0xde, sizeof(LPARAM));
1328
1329     item.mask = TCIF_PARAM;
1330     item.lParam = lparam;
1331     ret = SendMessageA(hTab, TCM_SETITEMA, 0, (LPARAM)&item);
1332     ok(ret == TRUE, "got %d\n", ret);
1333
1334     memset(&g_drawitem, 0, sizeof(g_drawitem));
1335
1336     ShowWindow(hTab, SW_SHOW);
1337     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1338
1339     itemdata = 0;
1340     memset(&itemdata, 0xde, 4);
1341     ok(g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1342
1343     DestroyWindow(hTab);
1344
1345     /* now with custom extra data length */
1346     hTab = CreateWindowA(
1347         WC_TABCONTROLA,
1348         "TestTab",
1349         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
1350         10, 10, 300, 100,
1351         parent_wnd, NULL, NULL, 0);
1352
1353     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1354
1355     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)+1, 0);
1356     ok(ret == TRUE, "got %d\n", ret);
1357
1358     /* set some item data */
1359     memset(&lparam, 0xde, sizeof(LPARAM));
1360     item.mask = TCIF_PARAM;
1361     item.lParam = lparam;
1362
1363     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
1364     ok(ret == 0, "got %d\n", ret);
1365
1366     memset(&g_drawitem, 0, sizeof(g_drawitem));
1367
1368     ShowWindow(hTab, SW_SHOW);
1369     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1370
1371     memset(&itemdata, 0xde, sizeof(ULONG_PTR));
1372     ok(*(ULONG_PTR*)g_drawitem.itemData == itemdata, "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1373
1374     DestroyWindow(hTab);
1375
1376     /* same thing, but size smaller than default */
1377     hTab = CreateWindowA(
1378         WC_TABCONTROLA,
1379         "TestTab",
1380         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED,
1381         10, 10, 300, 100,
1382         parent_wnd, NULL, NULL, 0);
1383
1384     ok(GetParent(hTab) == NULL, "got %p, expected null parent\n", GetParent(hTab));
1385
1386     ret = SendMessageA(hTab, TCM_SETITEMEXTRA, sizeof(LPARAM)-1, 0);
1387     ok(ret == TRUE, "got %d\n", ret);
1388
1389     memset(&lparam, 0xde, sizeof(lparam));
1390     item.mask = TCIF_PARAM;
1391     item.lParam = lparam;
1392
1393     ret = SendMessageA(hTab, TCM_INSERTITEMA, 0, (LPARAM)&item);
1394     ok(ret == 0, "got %d\n", ret);
1395
1396     memset(&g_drawitem, 0, sizeof(g_drawitem));
1397
1398     ShowWindow(hTab, SW_SHOW);
1399     RedrawWindow(hTab, NULL, 0, RDW_UPDATENOW);
1400
1401     itemdata = itemdata2 = 0;
1402     memset(&itemdata, 0xde, 4);
1403     memset(&itemdata2, 0xde, sizeof(LPARAM)-1);
1404     ok(g_drawitem.itemData == itemdata || broken(g_drawitem.itemData == itemdata2) /* win98 */,
1405         "got 0x%lx, expected 0x%lx\n", g_drawitem.itemData, itemdata);
1406
1407     DestroyWindow(hTab);
1408 }
1409
1410 static void test_WM_CONTEXTMENU(void)
1411 {
1412     HWND hTab;
1413
1414     hTab = createFilledTabControl(parent_wnd, TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE, 4);
1415     ok(hTab != NULL, "Failed to create tab control\n");
1416
1417     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1418
1419     SendMessageA(hTab, WM_RBUTTONUP, 0, 0);
1420
1421     ok_sequence(sequences, TAB_SEQ_INDEX, rbuttonup_seq, "WM_RBUTTONUP response sequence", FALSE);
1422
1423     DestroyWindow(hTab);
1424 }
1425
1426 struct tabcreate_style {
1427     DWORD style;
1428     DWORD act_style;
1429 };
1430
1431 static const struct tabcreate_style create_styles[] =
1432 {
1433     { WS_CHILD|TCS_BOTTOM|TCS_VERTICAL, WS_CHILD|WS_CLIPSIBLINGS|TCS_BOTTOM|TCS_VERTICAL|TCS_MULTILINE },
1434     { WS_CHILD|TCS_VERTICAL,            WS_CHILD|WS_CLIPSIBLINGS|TCS_VERTICAL|TCS_MULTILINE },
1435     { 0 }
1436 };
1437
1438 static void test_create(void)
1439 {
1440     const struct tabcreate_style *ptr = create_styles;
1441     DWORD style;
1442     HWND hTab;
1443
1444     while (ptr->style)
1445     {
1446         hTab = CreateWindowA(WC_TABCONTROLA, "TestTab", ptr->style,
1447             10, 10, 300, 100, parent_wnd, NULL, NULL, 0);
1448         style = GetWindowLongA(hTab, GWL_STYLE);
1449         ok(style == ptr->act_style, "expected style 0x%08x, got style 0x%08x\n", ptr->act_style, style);
1450
1451         DestroyWindow(hTab);
1452         ptr++;
1453     }
1454 }
1455
1456 START_TEST(tab)
1457 {
1458     LOGFONTA logfont;
1459
1460     lstrcpyA(logfont.lfFaceName, "Arial");
1461     memset(&logfont, 0, sizeof(logfont));
1462     logfont.lfHeight = -12;
1463     logfont.lfWeight = FW_NORMAL;
1464     logfont.lfCharSet = ANSI_CHARSET;
1465     hFont = CreateFontIndirectA(&logfont);
1466
1467     InitCommonControls();
1468
1469     test_width();
1470
1471     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1472
1473     parent_wnd = createParentWindow();
1474     ok(parent_wnd != NULL, "Failed to create parent window!\n");
1475
1476     test_curfocus();
1477     test_cursel();
1478     test_extendedstyle();
1479     test_unicodeformat();
1480     test_getset_item();
1481     test_getset_tooltips();
1482     test_misc();
1483
1484     test_adjustrect();
1485
1486     test_insert_focus();
1487     test_delete_focus();
1488     test_delete_selection();
1489     test_removeimage();
1490     test_TCM_SETITEMEXTRA();
1491     test_TCS_OWNERDRAWFIXED();
1492     test_WM_CONTEXTMENU();
1493     test_create();
1494
1495     DestroyWindow(parent_wnd);
1496 }