push 0a0aa53cd365a71ca6121b6df157ca635450378f
[wine/hacks.git] / dlls / comctl32 / tests / tooltips.c
blob6a927aa28e8b688520fab5cc3fc3a75ed7a6cf47
1 /*
2 * Copyright 2005 Dmitry Timoshkov
3 * Copyright 2008 Jason Edmeades
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <assert.h>
21 #include <windows.h>
22 #include <commctrl.h>
24 #include "wine/test.h"
26 static void test_create_tooltip(void)
28 HWND parent, hwnd;
29 DWORD style, exp_style;
31 parent = CreateWindowEx(0, "static", NULL, WS_POPUP,
32 0, 0, 0, 0,
33 NULL, NULL, NULL, 0);
34 assert(parent);
36 hwnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, 0x7fffffff | WS_POPUP,
37 10, 10, 300, 100,
38 parent, NULL, NULL, 0);
39 assert(hwnd);
41 style = GetWindowLong(hwnd, GWL_STYLE);
42 trace("style = %08x\n", style);
43 exp_style = 0x7fffffff | WS_POPUP;
44 exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
45 ok(style == exp_style,"wrong style %08x/%08x\n", style, exp_style);
47 DestroyWindow(hwnd);
49 hwnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, 0,
50 10, 10, 300, 100,
51 parent, NULL, NULL, 0);
52 assert(hwnd);
54 style = GetWindowLong(hwnd, GWL_STYLE);
55 trace("style = %08x\n", style);
56 ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER),
57 "wrong style %08x\n", style);
59 DestroyWindow(hwnd);
61 DestroyWindow(parent);
64 /* try to make sure pending X events have been processed before continuing */
65 static void flush_events(int waitTime)
67 MSG msg;
68 int diff = waitTime;
69 DWORD time = GetTickCount() + waitTime;
71 while (diff > 0)
73 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break;
74 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
75 diff = time - GetTickCount();
79 static int CD_Stages;
80 static LRESULT CD_Result;
81 static HWND g_hwnd;
83 #define TEST_CDDS_PREPAINT 0x00000001
84 #define TEST_CDDS_POSTPAINT 0x00000002
85 #define TEST_CDDS_PREERASE 0x00000004
86 #define TEST_CDDS_POSTERASE 0x00000008
87 #define TEST_CDDS_ITEMPREPAINT 0x00000010
88 #define TEST_CDDS_ITEMPOSTPAINT 0x00000020
89 #define TEST_CDDS_ITEMPREERASE 0x00000040
90 #define TEST_CDDS_ITEMPOSTERASE 0x00000080
91 #define TEST_CDDS_SUBITEM 0x00000100
93 static LRESULT CALLBACK CustomDrawWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
95 switch(msg) {
97 case WM_DESTROY:
98 PostQuitMessage(0);
99 break;
101 case WM_NOTIFY:
102 if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) {
103 NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam;
104 ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n",
105 ttcd->nmcd.hdr.hwndFrom, g_hwnd);
106 ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom);
108 switch (ttcd->nmcd.dwDrawStage) {
109 case CDDS_PREPAINT : CD_Stages |= TEST_CDDS_PREPAINT; break;
110 case CDDS_POSTPAINT : CD_Stages |= TEST_CDDS_POSTPAINT; break;
111 case CDDS_PREERASE : CD_Stages |= TEST_CDDS_PREERASE; break;
112 case CDDS_POSTERASE : CD_Stages |= TEST_CDDS_POSTERASE; break;
113 case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break;
114 case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break;
115 case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break;
116 case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break;
117 case CDDS_SUBITEM : CD_Stages |= TEST_CDDS_SUBITEM; break;
118 default: CD_Stages = -1;
121 if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
123 /* drop through */
125 default:
126 return DefWindowProcA(hWnd, msg, wParam, lParam);
129 return 0L;
132 static void test_customdraw(void) {
133 static struct {
134 LRESULT FirstReturnValue;
135 int ExpectedCalls;
136 } expectedResults[] = {
137 /* Valid notification responses */
138 {CDRF_DODEFAULT, TEST_CDDS_PREPAINT},
139 {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT},
140 {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT},
142 /* Invalid notification responses */
143 {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
144 {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
145 {CDRF_NOTIFYSUBITEMDRAW, TEST_CDDS_PREPAINT},
146 {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
149 int iterationNumber;
150 WNDCLASSA wc;
151 LRESULT lResult;
153 /* Create a class to use the custom draw wndproc */
154 wc.style = CS_HREDRAW | CS_VREDRAW;
155 wc.cbClsExtra = 0;
156 wc.cbWndExtra = 0;
157 wc.hInstance = GetModuleHandleA(NULL);
158 wc.hIcon = NULL;
159 wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
160 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
161 wc.lpszMenuName = NULL;
162 wc.lpszClassName = "CustomDrawClass";
163 wc.lpfnWndProc = CustomDrawWndProc;
164 RegisterClass(&wc);
166 for (iterationNumber = 0;
167 iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]);
168 iterationNumber++) {
170 HWND parent, hwndTip;
171 TOOLINFO toolInfo = { 0 };
173 /* Create a main window */
174 parent = CreateWindowEx(0, "CustomDrawClass", NULL,
175 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
176 WS_MAXIMIZEBOX | WS_VISIBLE,
177 50, 50,
178 300, 300,
179 NULL, NULL, NULL, 0);
180 ok(parent != NULL, "Creation of main window failed\n");
182 /* Make it show */
183 ShowWindow(parent, SW_SHOWNORMAL);
184 flush_events(100);
186 /* Create Tooltip */
187 hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS,
188 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
189 CW_USEDEFAULT, CW_USEDEFAULT,
190 CW_USEDEFAULT, CW_USEDEFAULT,
191 parent, NULL, GetModuleHandleA(NULL), 0);
192 ok(hwndTip != NULL, "Creation of tooltip window failed\n");
194 /* Set up parms for the wndproc to handle */
195 CD_Stages = 0;
196 CD_Result = expectedResults[iterationNumber].FirstReturnValue;
197 g_hwnd = hwndTip;
199 /* Make it topmost, as per the MSDN */
200 SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
201 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
203 /* Create a tool */
204 toolInfo.cbSize = sizeof(TOOLINFO);
205 toolInfo.hwnd = parent;
206 toolInfo.hinst = GetModuleHandleA(NULL);
207 toolInfo.uFlags = TTF_SUBCLASS;
208 toolInfo.uId = 0x1234ABCD;
209 toolInfo.lpszText = (LPSTR)"This is a test tooltip";
210 toolInfo.lParam = 0xdeadbeef;
211 GetClientRect (parent, &toolInfo.rect);
212 lResult = SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
213 ok(lResult, "Adding the tool to the tooltip failed\n");
215 /* Make tooltip appear quickly */
216 SendMessage(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
218 /* Put cursor inside window, tooltip will appear immediately */
219 SetCursorPos(100, 100);
220 flush_events(200);
222 /* Check CustomDraw results */
223 ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls,
224 "CustomDraw run %d stages %x, expected %x\n", iterationNumber, CD_Stages,
225 expectedResults[iterationNumber].ExpectedCalls);
227 /* Clean up */
228 DestroyWindow(hwndTip);
229 DestroyWindow(parent);
235 static const CHAR testcallbackA[] = "callback";
237 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
239 if (message == WM_NOTIFY && lParam)
241 NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
243 if (ttnmdi->hdr.code == TTN_GETDISPINFOA)
244 lstrcpy(ttnmdi->lpszText, testcallbackA);
247 return DefWindowProcA(hwnd, message, wParam, lParam);
250 static BOOL register_parent_wnd_class(void)
252 WNDCLASSA cls;
254 cls.style = 0;
255 cls.lpfnWndProc = parent_wnd_proc;
256 cls.cbClsExtra = 0;
257 cls.cbWndExtra = 0;
258 cls.hInstance = GetModuleHandleA(NULL);
259 cls.hIcon = 0;
260 cls.hCursor = LoadCursorA(0, IDC_ARROW);
261 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
262 cls.lpszMenuName = NULL;
263 cls.lpszClassName = "Tooltips test parent class";
264 return RegisterClassA(&cls);
267 static HWND create_parent_window(void)
269 if (!register_parent_wnd_class())
270 return NULL;
272 return CreateWindowEx(0, "Tooltips test parent class",
273 "Tooltips test parent window",
274 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
275 WS_MAXIMIZEBOX | WS_VISIBLE,
276 0, 0, 100, 100,
277 GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
280 static void test_gettext(void)
282 HWND hwnd, notify;
283 TTTOOLINFOA toolinfoA;
284 TTTOOLINFOW toolinfoW;
285 LRESULT r;
286 CHAR bufA[10] = "";
287 WCHAR bufW[10] = { 0 };
288 static const CHAR testtipA[] = "testtip";
290 notify = create_parent_window();
291 ok(notify != NULL, "Expected notification window to be created\n");
293 /* For bug 14790 - lpszText is NULL */
294 hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
295 10, 10, 300, 100,
296 NULL, NULL, NULL, 0);
297 assert(hwnd);
299 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
300 toolinfoA.hwnd = NULL;
301 toolinfoA.hinst = GetModuleHandleA(NULL);
302 toolinfoA.uFlags = 0;
303 toolinfoA.uId = 0x1234ABCD;
304 toolinfoA.lpszText = NULL;
305 toolinfoA.lParam = 0xdeadbeef;
306 GetClientRect(hwnd, &toolinfoA.rect);
307 r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
308 ok(r, "Adding the tool to the tooltip failed\n");
309 if (r)
311 toolinfoA.hwnd = NULL;
312 toolinfoA.uId = 0x1234ABCD;
313 toolinfoA.lpszText = bufA;
314 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
315 ok(strcmp(toolinfoA.lpszText, "") == 0, "lpszText should be an empty string\n");
318 /* add another tool with text */
319 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
320 toolinfoA.hwnd = NULL;
321 toolinfoA.hinst = GetModuleHandleA(NULL);
322 toolinfoA.uFlags = 0;
323 toolinfoA.uId = 0x1235ABCD;
324 strcpy(bufA, testtipA);
325 toolinfoA.lpszText = bufA;
326 toolinfoA.lParam = 0xdeadbeef;
327 GetClientRect(hwnd, &toolinfoA.rect);
328 r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
329 ok(r, "Adding the tool to the tooltip failed\n");
330 if (r)
332 DWORD length;
334 length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
335 ok(length == 0, "Expected 0, got %d\n", length);
337 toolinfoA.hwnd = NULL;
338 toolinfoA.uId = 0x1235ABCD;
339 toolinfoA.lpszText = bufA;
340 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
341 ok(strcmp(toolinfoA.lpszText, testtipA) == 0, "lpszText should be an empty string\n");
343 length = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0);
344 ok(length == 0, "Expected 0, got %d\n", length);
347 /* add another with callback text */
348 toolinfoA.cbSize = sizeof(TTTOOLINFOA);
349 toolinfoA.hwnd = notify;
350 toolinfoA.hinst = GetModuleHandleA(NULL);
351 toolinfoA.uFlags = 0;
352 toolinfoA.uId = 0x1236ABCD;
353 toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
354 toolinfoA.lParam = 0xdeadbeef;
355 GetClientRect(hwnd, &toolinfoA.rect);
356 r = SendMessageA(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoA);
357 ok(r, "Adding the tool to the tooltip failed\n");
358 if (r)
360 toolinfoA.hwnd = notify;
361 toolinfoA.uId = 0x1236ABCD;
362 toolinfoA.lpszText = bufA;
363 SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
364 ok(strcmp(toolinfoA.lpszText, testcallbackA) == 0,
365 "lpszText should be an (%s) string\n", testcallbackA);
368 DestroyWindow(hwnd);
369 DestroyWindow(notify);
371 SetLastError(0xdeadbeef);
372 hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
373 10, 10, 300, 100,
374 NULL, NULL, NULL, 0);
376 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
377 win_skip("CreateWindowExW is not implemented\n");
378 return;
381 assert(hwnd);
383 toolinfoW.cbSize = sizeof(TTTOOLINFOW);
384 toolinfoW.hwnd = NULL;
385 toolinfoW.hinst = GetModuleHandleA(NULL);
386 toolinfoW.uFlags = 0;
387 toolinfoW.uId = 0x1234ABCD;
388 toolinfoW.lpszText = NULL;
389 toolinfoW.lParam = 0xdeadbeef;
390 GetClientRect(hwnd, &toolinfoW.rect);
391 r = SendMessageW(hwnd, TTM_ADDTOOL, 0, (LPARAM)&toolinfoW);
392 ok(r, "Adding the tool to the tooltip failed\n");
394 if (0) /* crashes on NT4 */
396 toolinfoW.hwnd = NULL;
397 toolinfoW.uId = 0x1234ABCD;
398 toolinfoW.lpszText = bufW;
399 SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
400 ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n");
403 DestroyWindow(hwnd);
406 START_TEST(tooltips)
408 InitCommonControls();
410 test_create_tooltip();
411 test_customdraw();
412 test_gettext();