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
24 #include "wine/test.h"
26 static void test_create_tooltip(void)
29 DWORD style
, exp_style
;
31 parent
= CreateWindowEx(0, "static", NULL
, WS_POPUP
,
36 hwnd
= CreateWindowEx(0, TOOLTIPS_CLASS
, NULL
, 0x7fffffff | WS_POPUP
,
38 parent
, NULL
, NULL
, 0);
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
|| broken(style
== (exp_style
| WS_BORDER
)), /* nt4 */
46 "wrong style %08x/%08x\n", style
, exp_style
);
50 hwnd
= CreateWindowEx(0, TOOLTIPS_CLASS
, NULL
, 0,
52 parent
, NULL
, NULL
, 0);
55 style
= GetWindowLong(hwnd
, GWL_STYLE
);
56 trace("style = %08x\n", style
);
57 ok(style
== (WS_POPUP
| WS_CLIPSIBLINGS
| WS_BORDER
),
58 "wrong style %08x\n", style
);
62 DestroyWindow(parent
);
65 /* try to make sure pending X events have been processed before continuing */
66 static void flush_events(int waitTime
)
70 DWORD time
= GetTickCount() + waitTime
;
74 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min(100,diff
), QS_ALLEVENTS
) == WAIT_TIMEOUT
) break;
75 while (PeekMessage( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessage( &msg
);
76 diff
= time
- GetTickCount();
81 static LRESULT CD_Result
;
84 #define TEST_CDDS_PREPAINT 0x00000001
85 #define TEST_CDDS_POSTPAINT 0x00000002
86 #define TEST_CDDS_PREERASE 0x00000004
87 #define TEST_CDDS_POSTERASE 0x00000008
88 #define TEST_CDDS_ITEMPREPAINT 0x00000010
89 #define TEST_CDDS_ITEMPOSTPAINT 0x00000020
90 #define TEST_CDDS_ITEMPREERASE 0x00000040
91 #define TEST_CDDS_ITEMPOSTERASE 0x00000080
92 #define TEST_CDDS_SUBITEM 0x00000100
94 static LRESULT CALLBACK
CustomDrawWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
103 if (((NMHDR
*)lParam
)->code
== NM_CUSTOMDRAW
) {
104 NMTTCUSTOMDRAW
*ttcd
= (NMTTCUSTOMDRAW
*) lParam
;
105 ok(ttcd
->nmcd
.hdr
.hwndFrom
== g_hwnd
, "Unexpected hwnd source %p (%p)\n",
106 ttcd
->nmcd
.hdr
.hwndFrom
, g_hwnd
);
107 ok(ttcd
->nmcd
.hdr
.idFrom
== 0x1234ABCD, "Unexpected id %x\n", (int)ttcd
->nmcd
.hdr
.idFrom
);
109 switch (ttcd
->nmcd
.dwDrawStage
) {
110 case CDDS_PREPAINT
: CD_Stages
|= TEST_CDDS_PREPAINT
; break;
111 case CDDS_POSTPAINT
: CD_Stages
|= TEST_CDDS_POSTPAINT
; break;
112 case CDDS_PREERASE
: CD_Stages
|= TEST_CDDS_PREERASE
; break;
113 case CDDS_POSTERASE
: CD_Stages
|= TEST_CDDS_POSTERASE
; break;
114 case CDDS_ITEMPREPAINT
: CD_Stages
|= TEST_CDDS_ITEMPREPAINT
; break;
115 case CDDS_ITEMPOSTPAINT
: CD_Stages
|= TEST_CDDS_ITEMPOSTPAINT
; break;
116 case CDDS_ITEMPREERASE
: CD_Stages
|= TEST_CDDS_ITEMPREERASE
; break;
117 case CDDS_ITEMPOSTERASE
: CD_Stages
|= TEST_CDDS_ITEMPOSTERASE
; break;
118 case CDDS_SUBITEM
: CD_Stages
|= TEST_CDDS_SUBITEM
; break;
119 default: CD_Stages
= -1;
122 if (ttcd
->nmcd
.dwDrawStage
== CDDS_PREPAINT
) return CD_Result
;
127 return DefWindowProcA(hWnd
, msg
, wParam
, lParam
);
133 static void test_customdraw(void) {
135 LRESULT FirstReturnValue
;
137 } expectedResults
[] = {
138 /* Valid notification responses */
139 {CDRF_DODEFAULT
, TEST_CDDS_PREPAINT
},
140 {CDRF_SKIPDEFAULT
, TEST_CDDS_PREPAINT
},
141 {CDRF_NOTIFYPOSTPAINT
, TEST_CDDS_PREPAINT
| TEST_CDDS_POSTPAINT
},
143 /* Invalid notification responses */
144 {CDRF_NOTIFYITEMDRAW
, TEST_CDDS_PREPAINT
},
145 {CDRF_NOTIFYPOSTERASE
, TEST_CDDS_PREPAINT
},
146 {CDRF_NEWFONT
, TEST_CDDS_PREPAINT
}
153 /* Create a class to use the custom draw wndproc */
154 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
157 wc
.hInstance
= GetModuleHandleA(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
;
166 for (iterationNumber
= 0;
167 iterationNumber
< sizeof(expectedResults
)/sizeof(expectedResults
[0]);
170 HWND parent
, hwndTip
;
172 TOOLINFO toolInfo
= { 0 };
174 /* Create a main window */
175 parent
= CreateWindowEx(0, "CustomDrawClass", NULL
,
176 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
177 WS_MAXIMIZEBOX
| WS_VISIBLE
,
180 NULL
, NULL
, NULL
, 0);
181 ok(parent
!= NULL
, "Creation of main window failed\n");
184 ShowWindow(parent
, SW_SHOWNORMAL
);
188 hwndTip
= CreateWindowEx(WS_EX_TOPMOST
, TOOLTIPS_CLASS
,
189 NULL
, TTS_NOPREFIX
| TTS_ALWAYSTIP
,
190 CW_USEDEFAULT
, CW_USEDEFAULT
,
191 CW_USEDEFAULT
, CW_USEDEFAULT
,
192 parent
, NULL
, GetModuleHandleA(NULL
), 0);
193 ok(hwndTip
!= NULL
, "Creation of tooltip window failed\n");
195 /* Set up parms for the wndproc to handle */
197 CD_Result
= expectedResults
[iterationNumber
].FirstReturnValue
;
200 /* Make it topmost, as per the MSDN */
201 SetWindowPos(hwndTip
, HWND_TOPMOST
, 0, 0, 0, 0,
202 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
205 toolInfo
.cbSize
= TTTOOLINFO_V1_SIZE
;
206 toolInfo
.hwnd
= parent
;
207 toolInfo
.hinst
= GetModuleHandleA(NULL
);
208 toolInfo
.uFlags
= TTF_SUBCLASS
;
209 toolInfo
.uId
= 0x1234ABCD;
210 toolInfo
.lpszText
= (LPSTR
)"This is a test tooltip";
211 toolInfo
.lParam
= 0xdeadbeef;
212 GetClientRect (parent
, &toolInfo
.rect
);
213 lResult
= SendMessage(hwndTip
, TTM_ADDTOOL
, 0, (LPARAM
)&toolInfo
);
214 ok(lResult
, "Adding the tool to the tooltip failed\n");
216 /* Make tooltip appear quickly */
217 SendMessage(hwndTip
, TTM_SETDELAYTIME
, TTDT_INITIAL
, MAKELPARAM(1,0));
219 /* Put cursor inside window, tooltip will appear immediately */
220 GetWindowRect( parent
, &rect
);
221 SetCursorPos( (rect
.left
+ rect
.right
) / 2, (rect
.top
+ rect
.bottom
) / 2 );
226 /* Check CustomDraw results */
227 ok(CD_Stages
== expectedResults
[iterationNumber
].ExpectedCalls
||
228 broken(CD_Stages
== (expectedResults
[iterationNumber
].ExpectedCalls
& ~TEST_CDDS_POSTPAINT
)), /* nt4 */
229 "CustomDraw run %d stages %x, expected %x\n", iterationNumber
, CD_Stages
,
230 expectedResults
[iterationNumber
].ExpectedCalls
);
234 DestroyWindow(hwndTip
);
235 DestroyWindow(parent
);
241 static const CHAR testcallbackA
[] = "callback";
243 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
245 if (message
== WM_NOTIFY
&& lParam
)
247 NMTTDISPINFOA
*ttnmdi
= (NMTTDISPINFOA
*)lParam
;
249 if (ttnmdi
->hdr
.code
== TTN_GETDISPINFOA
)
250 lstrcpy(ttnmdi
->lpszText
, testcallbackA
);
253 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
256 static BOOL
register_parent_wnd_class(void)
261 cls
.lpfnWndProc
= parent_wnd_proc
;
264 cls
.hInstance
= GetModuleHandleA(NULL
);
266 cls
.hCursor
= LoadCursorA(0, IDC_ARROW
);
267 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
268 cls
.lpszMenuName
= NULL
;
269 cls
.lpszClassName
= "Tooltips test parent class";
270 return RegisterClassA(&cls
);
273 static HWND
create_parent_window(void)
275 if (!register_parent_wnd_class())
278 return CreateWindowEx(0, "Tooltips test parent class",
279 "Tooltips test parent window",
280 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
281 WS_MAXIMIZEBOX
| WS_VISIBLE
,
283 GetDesktopWindow(), NULL
, GetModuleHandleA(NULL
), NULL
);
286 static void test_gettext(void)
289 TTTOOLINFOA toolinfoA
;
290 TTTOOLINFOW toolinfoW
;
293 WCHAR bufW
[10] = { 0 };
294 static const CHAR testtipA
[] = "testtip";
296 notify
= create_parent_window();
297 ok(notify
!= NULL
, "Expected notification window to be created\n");
299 /* For bug 14790 - lpszText is NULL */
300 hwnd
= CreateWindowExA(0, TOOLTIPS_CLASSA
, NULL
, 0,
302 NULL
, NULL
, NULL
, 0);
305 /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
306 /* otherwise it crashes on the NULL lpszText */
307 toolinfoA
.cbSize
= sizeof(TTTOOLINFOA
);
308 toolinfoA
.hwnd
= NULL
;
309 toolinfoA
.hinst
= GetModuleHandleA(NULL
);
310 toolinfoA
.uFlags
= 0;
311 toolinfoA
.uId
= 0x1234ABCD;
312 toolinfoA
.lpszText
= NULL
;
313 toolinfoA
.lParam
= 0xdeadbeef;
314 GetClientRect(hwnd
, &toolinfoA
.rect
);
315 r
= SendMessageA(hwnd
, TTM_ADDTOOL
, 0, (LPARAM
)&toolinfoA
);
318 toolinfoA
.hwnd
= NULL
;
319 toolinfoA
.uId
= 0x1234ABCD;
320 toolinfoA
.lpszText
= bufA
;
321 SendMessageA(hwnd
, TTM_GETTEXTA
, 0, (LPARAM
)&toolinfoA
);
322 ok(strcmp(toolinfoA
.lpszText
, "") == 0, "lpszText should be an empty string\n");
326 win_skip( "Old comctl32, not testing NULL text\n" );
327 DestroyWindow( hwnd
);
331 /* add another tool with text */
332 toolinfoA
.cbSize
= sizeof(TTTOOLINFOA
);
333 toolinfoA
.hwnd
= NULL
;
334 toolinfoA
.hinst
= GetModuleHandleA(NULL
);
335 toolinfoA
.uFlags
= 0;
336 toolinfoA
.uId
= 0x1235ABCD;
337 strcpy(bufA
, testtipA
);
338 toolinfoA
.lpszText
= bufA
;
339 toolinfoA
.lParam
= 0xdeadbeef;
340 GetClientRect(hwnd
, &toolinfoA
.rect
);
341 r
= SendMessageA(hwnd
, TTM_ADDTOOL
, 0, (LPARAM
)&toolinfoA
);
342 ok(r
, "Adding the tool to the tooltip failed\n");
347 length
= SendMessage(hwnd
, WM_GETTEXTLENGTH
, 0, 0);
348 ok(length
== 0, "Expected 0, got %d\n", length
);
350 toolinfoA
.hwnd
= NULL
;
351 toolinfoA
.uId
= 0x1235ABCD;
352 toolinfoA
.lpszText
= bufA
;
353 SendMessageA(hwnd
, TTM_GETTEXTA
, 0, (LPARAM
)&toolinfoA
);
354 ok(strcmp(toolinfoA
.lpszText
, testtipA
) == 0, "lpszText should be an empty string\n");
356 length
= SendMessage(hwnd
, WM_GETTEXTLENGTH
, 0, 0);
357 ok(length
== 0, "Expected 0, got %d\n", length
);
360 /* add another with callback text */
361 toolinfoA
.cbSize
= sizeof(TTTOOLINFOA
);
362 toolinfoA
.hwnd
= notify
;
363 toolinfoA
.hinst
= GetModuleHandleA(NULL
);
364 toolinfoA
.uFlags
= 0;
365 toolinfoA
.uId
= 0x1236ABCD;
366 toolinfoA
.lpszText
= LPSTR_TEXTCALLBACKA
;
367 toolinfoA
.lParam
= 0xdeadbeef;
368 GetClientRect(hwnd
, &toolinfoA
.rect
);
369 r
= SendMessageA(hwnd
, TTM_ADDTOOL
, 0, (LPARAM
)&toolinfoA
);
370 ok(r
, "Adding the tool to the tooltip failed\n");
373 toolinfoA
.hwnd
= notify
;
374 toolinfoA
.uId
= 0x1236ABCD;
375 toolinfoA
.lpszText
= bufA
;
376 SendMessageA(hwnd
, TTM_GETTEXTA
, 0, (LPARAM
)&toolinfoA
);
377 ok(strcmp(toolinfoA
.lpszText
, testcallbackA
) == 0,
378 "lpszText should be an (%s) string\n", testcallbackA
);
382 DestroyWindow(notify
);
384 SetLastError(0xdeadbeef);
385 hwnd
= CreateWindowExW(0, TOOLTIPS_CLASSW
, NULL
, 0,
387 NULL
, NULL
, NULL
, 0);
389 if (!hwnd
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
) {
390 win_skip("CreateWindowExW is not implemented\n");
396 toolinfoW
.cbSize
= sizeof(TTTOOLINFOW
);
397 toolinfoW
.hwnd
= NULL
;
398 toolinfoW
.hinst
= GetModuleHandleA(NULL
);
399 toolinfoW
.uFlags
= 0;
400 toolinfoW
.uId
= 0x1234ABCD;
401 toolinfoW
.lpszText
= NULL
;
402 toolinfoW
.lParam
= 0xdeadbeef;
403 GetClientRect(hwnd
, &toolinfoW
.rect
);
404 r
= SendMessageW(hwnd
, TTM_ADDTOOL
, 0, (LPARAM
)&toolinfoW
);
405 ok(r
, "Adding the tool to the tooltip failed\n");
407 if (0) /* crashes on NT4 */
409 toolinfoW
.hwnd
= NULL
;
410 toolinfoW
.uId
= 0x1234ABCD;
411 toolinfoW
.lpszText
= bufW
;
412 SendMessageW(hwnd
, TTM_GETTEXTW
, 0, (LPARAM
)&toolinfoW
);
413 ok(toolinfoW
.lpszText
[0] == 0, "lpszText should be an empty string\n");
421 InitCommonControls();
423 test_create_tooltip();