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