Correct errors with move to kernel time functions.
[wine/multimedia.git] / dlls / comctl32 / tooltips.c
blobd2118272fc1b54e882af20de5b0b03b74b2c58e4
1 /*
2 * Tool tip control
4 * Copyright 1998, 1999 Eric Kohl
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * TODO:
21 * - Unicode support (started).
22 * - Custom draw support.
24 * Testing:
25 * - Run tests using Waite Group Windows95 API Bible Volume 2.
26 * The second cdrom (chapter 3) contains executables activate.exe,
27 * curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
28 * hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
30 * Timer logic.
32 * One important point to remember is that tools don't necessarily get
33 * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when
34 * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because
35 * here WM_MOUSEMOVEs only get sent when the cursor is inside the
36 * client area. Therefore the only reliable way to know that the
37 * cursor has left a tool is to keep a timer running and check the
38 * position every time it expires. This is the role of timer
39 * ID_TIMERLEAVE.
42 * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start
43 * ID_TIMERSHOW, if this times out and we're still in the tool we show
44 * the tip. On showing a tip we start both ID_TIMERPOP and
45 * ID_TIMERLEAVE. On hiding a tooltip we kill ID_TIMERPOP.
46 * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE. If
47 * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed.
48 * ID_TIMERLEAVE remains running - this is important as we need to
49 * determine when the cursor leaves the tool.
51 * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're
52 * still in the tool do nothing (apart from restart ID_TIMERPOP if
53 * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running). If we've
54 * left the tool and entered another one then hide the tip and start
55 * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE. If we're
56 * outside all tools hide the tip and kill ID_TIMERLEAVE. On Relayed
57 * mouse button messages hide the tip but leave ID_TIMERLEAVE running,
58 * this again will let us keep track of when the cursor leaves the
59 * tool.
62 * infoPtr->nTool is the tool the mouse was on on the last relayed MM
63 * or timer expiry or -1 if the mouse was not on a tool.
65 * infoPtr->nCurrentTool is the tool for which the tip is currently
66 * displaying text for or -1 if the tip is not shown. Actually this
67 * will only ever be infoPtr-nTool or -1, so it could be changed to a
68 * BOOL.
74 #include <stdarg.h>
75 #include <string.h>
77 #include "windef.h"
78 #include "winbase.h"
79 #include "wine/unicode.h"
80 #include "wingdi.h"
81 #include "winuser.h"
82 #include "winnls.h"
83 #include "commctrl.h"
84 #include "comctl32.h"
85 #include "wine/debug.h"
87 WINE_DEFAULT_DEBUG_CHANNEL(tooltips);
89 typedef struct
91 UINT uFlags;
92 HWND hwnd;
93 BOOL bNotifyUnicode;
94 UINT uId;
95 RECT rect;
96 HINSTANCE hinst;
97 LPWSTR lpszText;
98 LPARAM lParam;
99 } TTTOOL_INFO;
102 typedef struct
104 WCHAR szTipText[INFOTIPSIZE];
105 BOOL bActive;
106 BOOL bTrackActive;
107 UINT uNumTools;
108 COLORREF clrBk;
109 COLORREF clrText;
110 HFONT hFont;
111 INT xTrackPos;
112 INT yTrackPos;
113 INT nMaxTipWidth;
114 INT nTool;
115 INT nCurrentTool;
116 INT nTrackTool;
117 INT nReshowTime;
118 INT nAutoPopTime;
119 INT nInitialTime;
120 RECT rcMargin;
122 TTTOOL_INFO *tools;
123 } TOOLTIPS_INFO;
125 #define ID_TIMERSHOW 1 /* show delay timer */
126 #define ID_TIMERPOP 2 /* auto pop timer */
127 #define ID_TIMERLEAVE 3 /* tool leave timer */
130 #define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongA (hWindow, 0))
133 LRESULT CALLBACK
134 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef);
137 static VOID
138 TOOLTIPS_Refresh (HWND hwnd, HDC hdc)
140 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd);
141 RECT rc;
142 INT oldBkMode;
143 HFONT hOldFont;
144 HBRUSH hBrush;
145 UINT uFlags = DT_EXTERNALLEADING;
147 if (infoPtr->nMaxTipWidth > -1)
148 uFlags |= DT_WORDBREAK;
149 if (GetWindowLongA (hwnd, GWL_STYLE) & TTS_NOPREFIX)
150 uFlags |= DT_NOPREFIX;
151 GetClientRect (hwnd, &rc);
153 /* fill the background */
154 hBrush = CreateSolidBrush (infoPtr->clrBk);
155 FillRect (hdc, &rc, hBrush);
156 DeleteObject (hBrush);
158 /* calculate text rectangle */
159 rc.left += (2 + infoPtr->rcMargin.left);
160 rc.top += (2 + infoPtr->rcMargin.top);
161 rc.right -= (2 + infoPtr->rcMargin.right);
162 rc.bottom -= (2 + infoPtr->rcMargin.bottom);
164 /* draw text */
165 oldBkMode = SetBkMode (hdc, TRANSPARENT);
166 SetTextColor (hdc, infoPtr->clrText);
167 hOldFont = SelectObject (hdc, infoPtr->hFont);
168 DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
169 SelectObject (hdc, hOldFont);
170 if (oldBkMode != TRANSPARENT)
171 SetBkMode (hdc, oldBkMode);
174 static void TOOLTIPS_GetDispInfoA(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
176 NMTTDISPINFOA ttnmdi;
178 /* fill NMHDR struct */
179 ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
180 ttnmdi.hdr.hwndFrom = hwnd;
181 ttnmdi.hdr.idFrom = toolPtr->uId;
182 ttnmdi.hdr.code = TTN_GETDISPINFOA;
183 ttnmdi.lpszText = (LPSTR)&ttnmdi.szText;
184 ttnmdi.uFlags = toolPtr->uFlags;
185 ttnmdi.lParam = toolPtr->lParam;
187 TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
188 SendMessageA(toolPtr->hwnd, WM_NOTIFY,
189 (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi);
191 if (HIWORD((UINT)ttnmdi.lpszText) == 0) {
192 LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText,
193 infoPtr->szTipText, INFOTIPSIZE);
194 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
195 toolPtr->hinst = ttnmdi.hinst;
196 toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText;
199 else if (ttnmdi.lpszText == 0) {
200 /* no text available */
201 infoPtr->szTipText[0] = '\0';
203 else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
204 INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ?
205 sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : -1;
206 MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, max_len,
207 infoPtr->szTipText, INFOTIPSIZE);
208 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
209 INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText,
210 max_len, NULL, 0);
211 toolPtr->hinst = 0;
212 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
213 MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1,
214 toolPtr->lpszText, len);
217 else {
218 ERR("recursive text callback!\n");
219 infoPtr->szTipText[0] = '\0';
223 static void TOOLTIPS_GetDispInfoW(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
225 NMTTDISPINFOW ttnmdi;
227 /* fill NMHDR struct */
228 ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW));
229 ttnmdi.hdr.hwndFrom = hwnd;
230 ttnmdi.hdr.idFrom = toolPtr->uId;
231 ttnmdi.hdr.code = TTN_GETDISPINFOW;
232 ttnmdi.lpszText = (LPWSTR)&ttnmdi.szText;
233 ttnmdi.uFlags = toolPtr->uFlags;
234 ttnmdi.lParam = toolPtr->lParam;
236 TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
237 SendMessageW(toolPtr->hwnd, WM_NOTIFY,
238 (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi);
240 if (HIWORD((UINT)ttnmdi.lpszText) == 0) {
241 LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText,
242 infoPtr->szTipText, INFOTIPSIZE);
243 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
244 toolPtr->hinst = ttnmdi.hinst;
245 toolPtr->lpszText = ttnmdi.lpszText;
248 else if (ttnmdi.lpszText == 0) {
249 /* no text available */
250 infoPtr->szTipText[0] = '\0';
252 else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
253 INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ?
254 sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : INFOTIPSIZE-1;
255 strncpyW(infoPtr->szTipText, ttnmdi.lpszText, max_len);
256 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
257 INT len = max(strlenW(ttnmdi.lpszText), max_len);
258 toolPtr->hinst = 0;
259 toolPtr->lpszText = Alloc ((len+1) * sizeof(WCHAR));
260 memcpy(toolPtr->lpszText, ttnmdi.lpszText, (len+1) * sizeof(WCHAR));
263 else {
264 ERR("recursive text callback!\n");
265 infoPtr->szTipText[0] = '\0';
269 static VOID
270 TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool)
272 TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
274 if (HIWORD((UINT)toolPtr->lpszText) == 0) {
275 /* load a resource */
276 TRACE("load res string %p %x\n",
277 toolPtr->hinst, (int)toolPtr->lpszText);
278 LoadStringW (toolPtr->hinst, (UINT)toolPtr->lpszText,
279 infoPtr->szTipText, INFOTIPSIZE);
281 else if (toolPtr->lpszText) {
282 if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) {
283 if (toolPtr->bNotifyUnicode)
284 TOOLTIPS_GetDispInfoW(hwnd, infoPtr, toolPtr);
285 else
286 TOOLTIPS_GetDispInfoA(hwnd, infoPtr, toolPtr);
288 else {
289 /* the item is a usual (unicode) text */
290 lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
293 else {
294 /* no text available */
295 infoPtr->szTipText[0] = L'\0';
298 TRACE("%s\n", debugstr_w(infoPtr->szTipText));
302 static VOID
303 TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
305 HDC hdc;
306 HFONT hOldFont;
307 UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
308 RECT rc = {0, 0, 0, 0};
310 if (infoPtr->nMaxTipWidth > -1) {
311 rc.right = infoPtr->nMaxTipWidth;
312 uFlags |= DT_WORDBREAK;
314 if (GetWindowLongA (hwnd, GWL_STYLE) & TTS_NOPREFIX)
315 uFlags |= DT_NOPREFIX;
316 TRACE("%s\n", debugstr_w(infoPtr->szTipText));
318 hdc = GetDC (hwnd);
319 hOldFont = SelectObject (hdc, infoPtr->hFont);
320 DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
321 SelectObject (hdc, hOldFont);
322 ReleaseDC (hwnd, hdc);
324 lpSize->cx = rc.right - rc.left + 4 +
325 infoPtr->rcMargin.left + infoPtr->rcMargin.right;
326 lpSize->cy = rc.bottom - rc.top + 4 +
327 infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
331 static VOID
332 TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr)
334 TTTOOL_INFO *toolPtr;
335 RECT rect, wndrect;
336 SIZE size;
337 NMHDR hdr;
339 if (infoPtr->nTool == -1) {
340 TRACE("invalid tool (-1)!\n");
341 return;
344 infoPtr->nCurrentTool = infoPtr->nTool;
346 TRACE("Show tooltip pre %d! (%p)\n", infoPtr->nTool, hwnd);
348 TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool);
350 if (infoPtr->szTipText[0] == L'\0') {
351 infoPtr->nCurrentTool = -1;
352 return;
355 TRACE("Show tooltip %d!\n", infoPtr->nCurrentTool);
356 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
358 hdr.hwndFrom = hwnd;
359 hdr.idFrom = toolPtr->uId;
360 hdr.code = TTN_SHOW;
361 SendMessageA (toolPtr->hwnd, WM_NOTIFY,
362 (WPARAM)toolPtr->uId, (LPARAM)&hdr);
364 TRACE("%s\n", debugstr_w(infoPtr->szTipText));
366 TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
367 TRACE("size %ld x %ld\n", size.cx, size.cy);
369 if (toolPtr->uFlags & TTF_CENTERTIP) {
370 RECT rc;
372 if (toolPtr->uFlags & TTF_IDISHWND)
373 GetWindowRect ((HWND)toolPtr->uId, &rc);
374 else {
375 rc = toolPtr->rect;
376 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
378 rect.left = (rc.left + rc.right - size.cx) / 2;
379 rect.top = rc.bottom + 2;
381 else {
382 GetCursorPos ((LPPOINT)&rect);
383 rect.top += 20;
386 TRACE("pos %ld - %ld\n", rect.left, rect.top);
388 rect.right = rect.left + size.cx;
389 rect.bottom = rect.top + size.cy;
391 /* check position */
392 wndrect.right = GetSystemMetrics( SM_CXSCREEN );
393 if( rect.right > wndrect.right ) {
394 rect.left -= rect.right - wndrect.right + 2;
395 rect.right = wndrect.right - 2;
397 wndrect.bottom = GetSystemMetrics( SM_CYSCREEN );
398 if( rect.bottom > wndrect.bottom ) {
399 RECT rc;
401 if (toolPtr->uFlags & TTF_IDISHWND)
402 GetWindowRect ((HWND)toolPtr->uId, &rc);
403 else {
404 rc = toolPtr->rect;
405 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
407 rect.bottom = rc.top - 2;
408 rect.top = rect.bottom - size.cy;
411 AdjustWindowRectEx (&rect, GetWindowLongA (hwnd, GWL_STYLE),
412 FALSE, GetWindowLongA (hwnd, GWL_EXSTYLE));
414 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
415 rect.right - rect.left, rect.bottom - rect.top,
416 SWP_SHOWWINDOW | SWP_NOACTIVATE);
418 /* repaint the tooltip */
419 InvalidateRect(hwnd, NULL, TRUE);
420 UpdateWindow(hwnd);
422 SetTimer (hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
423 TRACE("timer 2 started!\n");
424 SetTimer (hwnd, ID_TIMERLEAVE, infoPtr->nReshowTime, 0);
425 TRACE("timer 3 started!\n");
429 static VOID
430 TOOLTIPS_Hide (HWND hwnd, TOOLTIPS_INFO *infoPtr)
432 TTTOOL_INFO *toolPtr;
433 NMHDR hdr;
435 TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, hwnd);
437 if (infoPtr->nCurrentTool == -1)
438 return;
440 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
441 KillTimer (hwnd, ID_TIMERPOP);
443 hdr.hwndFrom = hwnd;
444 hdr.idFrom = toolPtr->uId;
445 hdr.code = TTN_POP;
446 SendMessageA (toolPtr->hwnd, WM_NOTIFY,
447 (WPARAM)toolPtr->uId, (LPARAM)&hdr);
449 infoPtr->nCurrentTool = -1;
451 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
452 SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
456 static VOID
457 TOOLTIPS_TrackShow (HWND hwnd, TOOLTIPS_INFO *infoPtr)
459 TTTOOL_INFO *toolPtr;
460 RECT rect;
461 SIZE size;
462 NMHDR hdr;
464 if (infoPtr->nTrackTool == -1) {
465 TRACE("invalid tracking tool (-1)!\n");
466 return;
469 TRACE("show tracking tooltip pre %d!\n", infoPtr->nTrackTool);
471 TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nTrackTool);
473 if (infoPtr->szTipText[0] == L'\0') {
474 infoPtr->nTrackTool = -1;
475 return;
478 TRACE("show tracking tooltip %d!\n", infoPtr->nTrackTool);
479 toolPtr = &infoPtr->tools[infoPtr->nTrackTool];
481 hdr.hwndFrom = hwnd;
482 hdr.idFrom = toolPtr->uId;
483 hdr.code = TTN_SHOW;
484 SendMessageA (toolPtr->hwnd, WM_NOTIFY,
485 (WPARAM)toolPtr->uId, (LPARAM)&hdr);
487 TRACE("%s\n", debugstr_w(infoPtr->szTipText));
489 TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
490 TRACE("size %ld x %ld\n", size.cx, size.cy);
492 if (toolPtr->uFlags & TTF_ABSOLUTE) {
493 rect.left = infoPtr->xTrackPos;
494 rect.top = infoPtr->yTrackPos;
496 if (toolPtr->uFlags & TTF_CENTERTIP) {
497 rect.left -= (size.cx / 2);
498 rect.top -= (size.cy / 2);
501 else {
502 RECT rcTool;
504 if (toolPtr->uFlags & TTF_IDISHWND)
505 GetWindowRect ((HWND)toolPtr->uId, &rcTool);
506 else {
507 rcTool = toolPtr->rect;
508 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2);
511 GetCursorPos ((LPPOINT)&rect);
512 rect.top += 20;
514 if (toolPtr->uFlags & TTF_CENTERTIP) {
515 rect.left -= (size.cx / 2);
516 rect.top -= (size.cy / 2);
519 /* smart placement */
520 if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) &&
521 (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom))
522 rect.left = rcTool.right;
525 TRACE("pos %ld - %ld\n", rect.left, rect.top);
527 rect.right = rect.left + size.cx;
528 rect.bottom = rect.top + size.cy;
530 AdjustWindowRectEx (&rect, GetWindowLongA (hwnd, GWL_STYLE),
531 FALSE, GetWindowLongA (hwnd, GWL_EXSTYLE));
533 SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
534 rect.right - rect.left, rect.bottom - rect.top,
535 SWP_SHOWWINDOW | SWP_NOACTIVATE );
537 InvalidateRect(hwnd, NULL, TRUE);
538 UpdateWindow(hwnd);
542 static VOID
543 TOOLTIPS_TrackHide (HWND hwnd, TOOLTIPS_INFO *infoPtr)
545 TTTOOL_INFO *toolPtr;
546 NMHDR hdr;
548 if (infoPtr->nTrackTool == -1)
549 return;
551 toolPtr = &infoPtr->tools[infoPtr->nTrackTool];
552 TRACE("hide tracking tooltip %d!\n", infoPtr->nTrackTool);
554 hdr.hwndFrom = hwnd;
555 hdr.idFrom = toolPtr->uId;
556 hdr.code = TTN_POP;
557 SendMessageA (toolPtr->hwnd, WM_NOTIFY,
558 (WPARAM)toolPtr->uId, (LPARAM)&hdr);
560 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
561 SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
565 static INT
566 TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA lpToolInfo)
568 TTTOOL_INFO *toolPtr;
569 INT nTool;
571 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
572 toolPtr = &infoPtr->tools[nTool];
574 if (!(toolPtr->uFlags & TTF_IDISHWND) &&
575 (lpToolInfo->hwnd == toolPtr->hwnd) &&
576 (lpToolInfo->uId == toolPtr->uId))
577 return nTool;
580 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
581 toolPtr = &infoPtr->tools[nTool];
583 if ((toolPtr->uFlags & TTF_IDISHWND) &&
584 (lpToolInfo->uId == toolPtr->uId))
585 return nTool;
588 return -1;
592 static INT
593 TOOLTIPS_GetToolFromInfoW (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOW lpToolInfo)
595 TTTOOL_INFO *toolPtr;
596 INT nTool;
598 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
599 toolPtr = &infoPtr->tools[nTool];
601 if (!(toolPtr->uFlags & TTF_IDISHWND) &&
602 (lpToolInfo->hwnd == toolPtr->hwnd) &&
603 (lpToolInfo->uId == toolPtr->uId))
604 return nTool;
607 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
608 toolPtr = &infoPtr->tools[nTool];
610 if ((toolPtr->uFlags & TTF_IDISHWND) &&
611 (lpToolInfo->uId == toolPtr->uId))
612 return nTool;
615 return -1;
619 static INT
620 TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND hwnd, LPPOINT lpPt)
622 TTTOOL_INFO *toolPtr;
623 INT nTool;
625 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
626 toolPtr = &infoPtr->tools[nTool];
628 if (!(toolPtr->uFlags & TTF_IDISHWND)) {
629 if (hwnd != toolPtr->hwnd)
630 continue;
631 if (!PtInRect (&toolPtr->rect, *lpPt))
632 continue;
633 return nTool;
637 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
638 toolPtr = &infoPtr->tools[nTool];
640 if (toolPtr->uFlags & TTF_IDISHWND) {
641 if ((HWND)toolPtr->uId == hwnd)
642 return nTool;
646 return -1;
650 static BOOL
651 TOOLTIPS_IsWindowActive (HWND hwnd)
653 HWND hwndActive = GetActiveWindow ();
654 if (!hwndActive)
655 return FALSE;
656 if (hwndActive == hwnd)
657 return TRUE;
658 return IsChild (hwndActive, hwnd);
662 static INT
663 TOOLTIPS_CheckTool (HWND hwnd, BOOL bShowTest)
665 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
666 POINT pt;
667 HWND hwndTool;
668 INT nTool;
670 GetCursorPos (&pt);
671 hwndTool = (HWND)SendMessageA (hwnd, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
672 if (hwndTool == 0)
673 return -1;
675 ScreenToClient (hwndTool, &pt);
676 nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
677 if (nTool == -1)
678 return -1;
680 if (!(GetWindowLongA (hwnd, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) {
681 if (!TOOLTIPS_IsWindowActive (GetWindow (hwnd, GW_OWNER)))
682 return -1;
685 TRACE("tool %d\n", nTool);
687 return nTool;
691 static LRESULT
692 TOOLTIPS_Activate (HWND hwnd, WPARAM wParam, LPARAM lParam)
694 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
696 infoPtr->bActive = (BOOL)wParam;
698 if (infoPtr->bActive)
699 TRACE("activate!\n");
701 if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
702 TOOLTIPS_Hide (hwnd, infoPtr);
704 return 0;
708 static LRESULT
709 TOOLTIPS_AddToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
711 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
712 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
713 TTTOOL_INFO *toolPtr;
714 INT nResult;
716 if (lpToolInfo == NULL)
717 return FALSE;
718 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
719 return FALSE;
721 TRACE("add tool (%p) %p %d%s!\n",
722 hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
723 (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
725 if (infoPtr->uNumTools == 0) {
726 infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
727 toolPtr = infoPtr->tools;
729 else {
730 TTTOOL_INFO *oldTools = infoPtr->tools;
731 infoPtr->tools =
732 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
733 memcpy (infoPtr->tools, oldTools,
734 infoPtr->uNumTools * sizeof(TTTOOL_INFO));
735 Free (oldTools);
736 toolPtr = &infoPtr->tools[infoPtr->uNumTools];
739 infoPtr->uNumTools++;
741 /* copy tool data */
742 toolPtr->uFlags = lpToolInfo->uFlags;
743 toolPtr->hwnd = lpToolInfo->hwnd;
744 toolPtr->uId = lpToolInfo->uId;
745 toolPtr->rect = lpToolInfo->rect;
746 toolPtr->hinst = lpToolInfo->hinst;
748 if (HIWORD(lpToolInfo->lpszText) == 0) {
749 TRACE("add string id %x!\n", (int)lpToolInfo->lpszText);
750 toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
752 else if (lpToolInfo->lpszText) {
753 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) {
754 TRACE("add CALLBACK!\n");
755 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
757 else {
758 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
759 NULL, 0);
760 TRACE("add text \"%s\"!\n", lpToolInfo->lpszText);
761 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
762 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
763 toolPtr->lpszText, len);
767 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
768 toolPtr->lParam = lpToolInfo->lParam;
770 /* install subclassing hook */
771 if (toolPtr->uFlags & TTF_SUBCLASS) {
772 if (toolPtr->uFlags & TTF_IDISHWND) {
773 SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
774 (DWORD_PTR)hwnd);
776 else {
777 SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
778 (DWORD_PTR)hwnd);
780 TRACE("subclassing installed!\n");
783 nResult = (INT) SendMessageA (toolPtr->hwnd, WM_NOTIFYFORMAT,
784 (WPARAM)hwnd, (LPARAM)NF_QUERY);
785 if (nResult == NFR_ANSI) {
786 toolPtr->bNotifyUnicode = FALSE;
787 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
788 } else if (nResult == NFR_UNICODE) {
789 toolPtr->bNotifyUnicode = TRUE;
790 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
791 } else {
792 TRACE (" -- WM_NOTIFYFORMAT returns: error!\n");
795 return TRUE;
799 static LRESULT
800 TOOLTIPS_AddToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
802 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
803 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
804 TTTOOL_INFO *toolPtr;
805 INT nResult;
807 if (lpToolInfo == NULL)
808 return FALSE;
809 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
810 return FALSE;
812 TRACE("add tool (%p) %p %d%s!\n",
813 hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
814 (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
816 if (infoPtr->uNumTools == 0) {
817 infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
818 toolPtr = infoPtr->tools;
820 else {
821 TTTOOL_INFO *oldTools = infoPtr->tools;
822 infoPtr->tools =
823 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
824 memcpy (infoPtr->tools, oldTools,
825 infoPtr->uNumTools * sizeof(TTTOOL_INFO));
826 Free (oldTools);
827 toolPtr = &infoPtr->tools[infoPtr->uNumTools];
830 infoPtr->uNumTools++;
832 /* copy tool data */
833 toolPtr->uFlags = lpToolInfo->uFlags;
834 toolPtr->hwnd = lpToolInfo->hwnd;
835 toolPtr->uId = lpToolInfo->uId;
836 toolPtr->rect = lpToolInfo->rect;
837 toolPtr->hinst = lpToolInfo->hinst;
839 if (HIWORD(lpToolInfo->lpszText) == 0) {
840 TRACE("add string id %x!\n", (int)lpToolInfo->lpszText);
841 toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
843 else if (lpToolInfo->lpszText) {
844 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) {
845 TRACE("add CALLBACK!\n");
846 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
848 else {
849 INT len = lstrlenW (lpToolInfo->lpszText);
850 TRACE("add text %s!\n",
851 debugstr_w(lpToolInfo->lpszText));
852 toolPtr->lpszText = Alloc ((len + 1)*sizeof(WCHAR));
853 strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
857 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
858 toolPtr->lParam = lpToolInfo->lParam;
860 /* install subclassing hook */
861 if (toolPtr->uFlags & TTF_SUBCLASS) {
862 if (toolPtr->uFlags & TTF_IDISHWND) {
863 SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
864 (DWORD_PTR)hwnd);
866 else {
867 SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
868 (DWORD_PTR)hwnd);
870 TRACE("subclassing installed!\n");
873 nResult = (INT) SendMessageA (toolPtr->hwnd, WM_NOTIFYFORMAT,
874 (WPARAM)hwnd, (LPARAM)NF_QUERY);
875 if (nResult == NFR_ANSI) {
876 toolPtr->bNotifyUnicode = FALSE;
877 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
878 } else if (nResult == NFR_UNICODE) {
879 toolPtr->bNotifyUnicode = TRUE;
880 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
881 } else {
882 TRACE (" -- WM_NOTIFYFORMAT returns: error!\n");
885 return TRUE;
889 static LRESULT
890 TOOLTIPS_DelToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
892 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
893 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
894 TTTOOL_INFO *toolPtr;
895 INT nTool;
897 if (lpToolInfo == NULL)
898 return 0;
899 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
900 return 0;
901 if (infoPtr->uNumTools == 0)
902 return 0;
904 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
905 if (nTool == -1) return 0;
907 TRACE("tool %d\n", nTool);
909 /* make sure the tooltip has disappeared before deleting it */
910 TOOLTIPS_Hide(hwnd, infoPtr);
912 /* delete text string */
913 toolPtr = &infoPtr->tools[nTool];
914 if (toolPtr->lpszText) {
915 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
916 (HIWORD((INT)toolPtr->lpszText) != 0) )
917 Free (toolPtr->lpszText);
920 /* remove subclassing */
921 if (toolPtr->uFlags & TTF_SUBCLASS) {
922 if (toolPtr->uFlags & TTF_IDISHWND) {
923 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
925 else {
926 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
930 /* delete tool from tool list */
931 if (infoPtr->uNumTools == 1) {
932 Free (infoPtr->tools);
933 infoPtr->tools = NULL;
935 else {
936 TTTOOL_INFO *oldTools = infoPtr->tools;
937 infoPtr->tools =
938 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
940 if (nTool > 0)
941 memcpy (&infoPtr->tools[0], &oldTools[0],
942 nTool * sizeof(TTTOOL_INFO));
944 if (nTool < infoPtr->uNumTools - 1)
945 memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
946 (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
948 Free (oldTools);
951 /* destroying tool that mouse was on on last relayed mouse move */
952 if (infoPtr->nTool == nTool)
954 /* no current tool (0 means first tool) */
955 infoPtr->nTool = -1;
958 infoPtr->uNumTools--;
960 return 0;
964 static LRESULT
965 TOOLTIPS_DelToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
967 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
968 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
969 TTTOOL_INFO *toolPtr;
970 INT nTool;
972 if (lpToolInfo == NULL)
973 return 0;
974 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
975 return 0;
976 if (infoPtr->uNumTools == 0)
977 return 0;
979 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
980 if (nTool == -1) return 0;
982 TRACE("tool %d\n", nTool);
984 /* make sure the tooltip has disappeared before deleting it */
985 TOOLTIPS_Hide(hwnd, infoPtr);
987 /* delete text string */
988 toolPtr = &infoPtr->tools[nTool];
989 if (toolPtr->lpszText) {
990 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
991 (HIWORD((INT)toolPtr->lpszText) != 0) )
992 Free (toolPtr->lpszText);
995 /* remove subclassing */
996 if (toolPtr->uFlags & TTF_SUBCLASS) {
997 if (toolPtr->uFlags & TTF_IDISHWND) {
998 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
1000 else {
1001 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
1005 /* delete tool from tool list */
1006 if (infoPtr->uNumTools == 1) {
1007 Free (infoPtr->tools);
1008 infoPtr->tools = NULL;
1010 else {
1011 TTTOOL_INFO *oldTools = infoPtr->tools;
1012 infoPtr->tools =
1013 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
1015 if (nTool > 0)
1016 memcpy (&infoPtr->tools[0], &oldTools[0],
1017 nTool * sizeof(TTTOOL_INFO));
1019 if (nTool < infoPtr->uNumTools - 1)
1020 memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
1021 (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
1023 Free (oldTools);
1026 /* destroying tool that mouse was on on last relayed mouse move */
1027 if (infoPtr->nTool == nTool)
1029 /* no current tool (0 means first tool) */
1030 infoPtr->nTool = -1;
1033 infoPtr->uNumTools--;
1035 return 0;
1039 static LRESULT
1040 TOOLTIPS_EnumToolsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1042 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1043 UINT uIndex = (UINT)wParam;
1044 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1045 TTTOOL_INFO *toolPtr;
1047 if (lpToolInfo == NULL)
1048 return FALSE;
1049 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1050 return FALSE;
1051 if (uIndex >= infoPtr->uNumTools)
1052 return FALSE;
1054 TRACE("index=%u\n", uIndex);
1056 toolPtr = &infoPtr->tools[uIndex];
1058 /* copy tool data */
1059 lpToolInfo->uFlags = toolPtr->uFlags;
1060 lpToolInfo->hwnd = toolPtr->hwnd;
1061 lpToolInfo->uId = toolPtr->uId;
1062 lpToolInfo->rect = toolPtr->rect;
1063 lpToolInfo->hinst = toolPtr->hinst;
1064 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1065 lpToolInfo->lpszText = NULL; /* FIXME */
1067 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1068 lpToolInfo->lParam = toolPtr->lParam;
1070 return TRUE;
1074 static LRESULT
1075 TOOLTIPS_EnumToolsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1077 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1078 UINT uIndex = (UINT)wParam;
1079 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1080 TTTOOL_INFO *toolPtr;
1082 if (lpToolInfo == NULL)
1083 return FALSE;
1084 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1085 return FALSE;
1086 if (uIndex >= infoPtr->uNumTools)
1087 return FALSE;
1089 TRACE("index=%u\n", uIndex);
1091 toolPtr = &infoPtr->tools[uIndex];
1093 /* copy tool data */
1094 lpToolInfo->uFlags = toolPtr->uFlags;
1095 lpToolInfo->hwnd = toolPtr->hwnd;
1096 lpToolInfo->uId = toolPtr->uId;
1097 lpToolInfo->rect = toolPtr->rect;
1098 lpToolInfo->hinst = toolPtr->hinst;
1099 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1100 lpToolInfo->lpszText = NULL; /* FIXME */
1102 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1103 lpToolInfo->lParam = toolPtr->lParam;
1105 return TRUE;
1108 static LRESULT
1109 TOOLTIPS_GetBubbleSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
1111 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1112 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1113 INT nTool;
1114 SIZE size;
1116 if (lpToolInfo == NULL)
1117 return FALSE;
1118 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1119 return FALSE;
1121 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1122 if (nTool == -1) return 0;
1124 TRACE("tool %d\n", nTool);
1126 TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
1127 TRACE("size %ld x %ld\n", size.cx, size.cy);
1129 return MAKELRESULT(size.cx, size.cy);
1132 static LRESULT
1133 TOOLTIPS_GetCurrentToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1135 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1136 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1137 TTTOOL_INFO *toolPtr;
1139 if (lpToolInfo == NULL)
1140 return FALSE;
1141 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1142 return FALSE;
1144 if (lpToolInfo) {
1145 if (infoPtr->nCurrentTool > -1) {
1146 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1148 /* copy tool data */
1149 lpToolInfo->uFlags = toolPtr->uFlags;
1150 lpToolInfo->rect = toolPtr->rect;
1151 lpToolInfo->hinst = toolPtr->hinst;
1152 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1153 lpToolInfo->lpszText = NULL; /* FIXME */
1155 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1156 lpToolInfo->lParam = toolPtr->lParam;
1158 return TRUE;
1160 else
1161 return FALSE;
1163 else
1164 return (infoPtr->nCurrentTool != -1);
1166 return FALSE;
1170 static LRESULT
1171 TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1173 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1174 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1175 TTTOOL_INFO *toolPtr;
1177 if (lpToolInfo == NULL)
1178 return FALSE;
1179 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1180 return FALSE;
1182 if (lpToolInfo) {
1183 if (infoPtr->nCurrentTool > -1) {
1184 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1186 /* copy tool data */
1187 lpToolInfo->uFlags = toolPtr->uFlags;
1188 lpToolInfo->rect = toolPtr->rect;
1189 lpToolInfo->hinst = toolPtr->hinst;
1190 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1191 lpToolInfo->lpszText = NULL; /* FIXME */
1193 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1194 lpToolInfo->lParam = toolPtr->lParam;
1196 return TRUE;
1198 else
1199 return FALSE;
1201 else
1202 return (infoPtr->nCurrentTool != -1);
1204 return FALSE;
1208 static LRESULT
1209 TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1211 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1213 switch (wParam) {
1214 case TTDT_RESHOW:
1215 return infoPtr->nReshowTime;
1217 case TTDT_AUTOPOP:
1218 return infoPtr->nAutoPopTime;
1220 case TTDT_INITIAL:
1221 case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
1222 return infoPtr->nInitialTime;
1224 default:
1225 WARN("Invalid wParam %x\n", wParam);
1226 break;
1229 return -1;
1233 static LRESULT
1234 TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1236 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1237 LPRECT lpRect = (LPRECT)lParam;
1239 lpRect->left = infoPtr->rcMargin.left;
1240 lpRect->right = infoPtr->rcMargin.right;
1241 lpRect->bottom = infoPtr->rcMargin.bottom;
1242 lpRect->top = infoPtr->rcMargin.top;
1244 return 0;
1248 inline static LRESULT
1249 TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1251 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1253 return infoPtr->nMaxTipWidth;
1257 static LRESULT
1258 TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1260 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1261 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1262 INT nTool;
1264 if (lpToolInfo == NULL)
1265 return 0;
1266 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1267 return 0;
1269 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1270 if (nTool == -1) return 0;
1272 /* NB this API is broken, there is no way for the app to determine
1273 what size buffer it requires nor a way to specify how long the
1274 one it supplies is. We'll assume it's upto INFOTIPSIZE */
1276 WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1,
1277 lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL);
1279 return 0;
1283 static LRESULT
1284 TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1286 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1287 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1288 INT nTool;
1290 if (lpToolInfo == NULL)
1291 return 0;
1292 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1293 return 0;
1295 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1296 if (nTool == -1) return 0;
1298 strcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText);
1300 return 0;
1304 inline static LRESULT
1305 TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1307 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1308 return infoPtr->clrBk;
1312 inline static LRESULT
1313 TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1315 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1316 return infoPtr->clrText;
1320 inline static LRESULT
1321 TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1323 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1324 return infoPtr->uNumTools;
1328 static LRESULT
1329 TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1331 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1332 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1333 TTTOOL_INFO *toolPtr;
1334 INT nTool;
1336 if (lpToolInfo == NULL)
1337 return FALSE;
1338 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1339 return FALSE;
1340 if (infoPtr->uNumTools == 0)
1341 return FALSE;
1343 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1344 if (nTool == -1)
1345 return FALSE;
1347 TRACE("tool %d\n", nTool);
1349 toolPtr = &infoPtr->tools[nTool];
1351 /* copy tool data */
1352 lpToolInfo->uFlags = toolPtr->uFlags;
1353 lpToolInfo->rect = toolPtr->rect;
1354 lpToolInfo->hinst = toolPtr->hinst;
1355 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1356 lpToolInfo->lpszText = NULL; /* FIXME */
1358 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1359 lpToolInfo->lParam = toolPtr->lParam;
1361 return TRUE;
1365 static LRESULT
1366 TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1368 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1369 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1370 TTTOOL_INFO *toolPtr;
1371 INT nTool;
1373 if (lpToolInfo == NULL)
1374 return FALSE;
1375 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1376 return FALSE;
1377 if (infoPtr->uNumTools == 0)
1378 return FALSE;
1380 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1381 if (nTool == -1)
1382 return FALSE;
1384 TRACE("tool %d\n", nTool);
1386 toolPtr = &infoPtr->tools[nTool];
1388 /* copy tool data */
1389 lpToolInfo->uFlags = toolPtr->uFlags;
1390 lpToolInfo->rect = toolPtr->rect;
1391 lpToolInfo->hinst = toolPtr->hinst;
1392 /* lpToolInfo->lpszText = toolPtr->lpszText; */
1393 lpToolInfo->lpszText = NULL; /* FIXME */
1395 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1396 lpToolInfo->lParam = toolPtr->lParam;
1398 return TRUE;
1402 static LRESULT
1403 TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1405 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1406 LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam;
1407 TTTOOL_INFO *toolPtr;
1408 INT nTool;
1410 if (lptthit == 0)
1411 return FALSE;
1413 nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1414 if (nTool == -1)
1415 return FALSE;
1417 TRACE("tool %d!\n", nTool);
1419 /* copy tool data */
1420 if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) {
1421 toolPtr = &infoPtr->tools[nTool];
1423 lptthit->ti.uFlags = toolPtr->uFlags;
1424 lptthit->ti.hwnd = toolPtr->hwnd;
1425 lptthit->ti.uId = toolPtr->uId;
1426 lptthit->ti.rect = toolPtr->rect;
1427 lptthit->ti.hinst = toolPtr->hinst;
1428 /* lptthit->ti.lpszText = toolPtr->lpszText; */
1429 lptthit->ti.lpszText = NULL; /* FIXME */
1430 lptthit->ti.lParam = toolPtr->lParam;
1433 return TRUE;
1437 static LRESULT
1438 TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1440 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1441 LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam;
1442 TTTOOL_INFO *toolPtr;
1443 INT nTool;
1445 if (lptthit == 0)
1446 return FALSE;
1448 nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1449 if (nTool == -1)
1450 return FALSE;
1452 TRACE("tool %d!\n", nTool);
1454 /* copy tool data */
1455 if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) {
1456 toolPtr = &infoPtr->tools[nTool];
1458 lptthit->ti.uFlags = toolPtr->uFlags;
1459 lptthit->ti.hwnd = toolPtr->hwnd;
1460 lptthit->ti.uId = toolPtr->uId;
1461 lptthit->ti.rect = toolPtr->rect;
1462 lptthit->ti.hinst = toolPtr->hinst;
1463 /* lptthit->ti.lpszText = toolPtr->lpszText; */
1464 lptthit->ti.lpszText = NULL; /* FIXME */
1465 lptthit->ti.lParam = toolPtr->lParam;
1468 return TRUE;
1472 static LRESULT
1473 TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1475 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1476 LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
1477 INT nTool;
1479 if (lpti == NULL)
1480 return 0;
1481 if (lpti->cbSize < TTTOOLINFOA_V1_SIZE)
1482 return FALSE;
1484 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
1485 if (nTool == -1) return 0;
1487 infoPtr->tools[nTool].rect = lpti->rect;
1489 return 0;
1493 static LRESULT
1494 TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1496 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1497 LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam;
1498 INT nTool;
1500 if (lpti == NULL)
1501 return 0;
1502 if (lpti->cbSize < TTTOOLINFOW_V1_SIZE)
1503 return FALSE;
1505 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti);
1506 if (nTool == -1) return 0;
1508 infoPtr->tools[nTool].rect = lpti->rect;
1510 return 0;
1514 inline static LRESULT
1515 TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam)
1517 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1518 TOOLTIPS_Hide (hwnd, infoPtr);
1520 return 0;
1524 static LRESULT
1525 TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam)
1527 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1528 LPMSG lpMsg = (LPMSG)lParam;
1529 POINT pt;
1530 INT nOldTool;
1532 if (lParam == 0) {
1533 ERR("lpMsg == NULL!\n");
1534 return 0;
1537 switch (lpMsg->message) {
1538 case WM_LBUTTONDOWN:
1539 case WM_LBUTTONUP:
1540 case WM_MBUTTONDOWN:
1541 case WM_MBUTTONUP:
1542 case WM_RBUTTONDOWN:
1543 case WM_RBUTTONUP:
1544 TOOLTIPS_Hide (hwnd, infoPtr);
1545 break;
1547 case WM_MOUSEMOVE:
1548 pt.x = LOWORD(lpMsg->lParam);
1549 pt.y = HIWORD(lpMsg->lParam);
1550 nOldTool = infoPtr->nTool;
1551 infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
1552 &pt);
1553 TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
1554 infoPtr->nTool, infoPtr->nCurrentTool);
1555 TRACE("WM_MOUSEMOVE (%p %ld %ld)\n", hwnd, pt.x, pt.y);
1557 if (infoPtr->nTool != nOldTool) {
1558 if(infoPtr->nTool == -1) { /* Moved out of all tools */
1559 TOOLTIPS_Hide(hwnd, infoPtr);
1560 KillTimer(hwnd, ID_TIMERLEAVE);
1561 } else if (nOldTool == -1) { /* Moved from outside */
1562 if(infoPtr->bActive) {
1563 SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1564 TRACE("timer 1 started!\n");
1566 } else { /* Moved from one to another */
1567 TOOLTIPS_Hide (hwnd, infoPtr);
1568 KillTimer(hwnd, ID_TIMERLEAVE);
1569 if(infoPtr->bActive) {
1570 SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1571 TRACE("timer 1 started!\n");
1574 } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1575 KillTimer(hwnd, ID_TIMERPOP);
1576 SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1577 TRACE("timer 2 restarted\n");
1579 break;
1582 return 0;
1586 static LRESULT
1587 TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1589 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1590 INT nTime = (INT)LOWORD(lParam);
1592 switch (wParam) {
1593 case TTDT_AUTOMATIC:
1594 if (nTime <= 0)
1595 nTime = GetDoubleClickTime();
1596 infoPtr->nReshowTime = nTime / 5;
1597 infoPtr->nAutoPopTime = nTime * 10;
1598 infoPtr->nInitialTime = nTime;
1599 break;
1601 case TTDT_RESHOW:
1602 if(nTime < 0)
1603 nTime = GetDoubleClickTime() / 5;
1604 infoPtr->nReshowTime = nTime;
1605 break;
1607 case TTDT_AUTOPOP:
1608 if(nTime < 0)
1609 nTime = GetDoubleClickTime() * 10;
1610 infoPtr->nAutoPopTime = nTime;
1611 break;
1613 case TTDT_INITIAL:
1614 if(nTime < 0)
1615 nTime = GetDoubleClickTime();
1616 infoPtr->nInitialTime = nTime;
1617 break;
1619 default:
1620 WARN("Invalid wParam %x\n", wParam);
1621 break;
1624 return 0;
1628 static LRESULT
1629 TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1631 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1632 LPRECT lpRect = (LPRECT)lParam;
1634 infoPtr->rcMargin.left = lpRect->left;
1635 infoPtr->rcMargin.right = lpRect->right;
1636 infoPtr->rcMargin.bottom = lpRect->bottom;
1637 infoPtr->rcMargin.top = lpRect->top;
1639 return 0;
1643 inline static LRESULT
1644 TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1646 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1647 INT nTemp = infoPtr->nMaxTipWidth;
1649 infoPtr->nMaxTipWidth = (INT)lParam;
1651 return nTemp;
1655 inline static LRESULT
1656 TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1658 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1660 infoPtr->clrBk = (COLORREF)wParam;
1662 return 0;
1666 inline static LRESULT
1667 TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1669 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1671 infoPtr->clrText = (COLORREF)wParam;
1673 return 0;
1677 static LRESULT
1678 TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1680 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1681 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1682 TTTOOL_INFO *toolPtr;
1683 INT nTool;
1685 if (lpToolInfo == NULL)
1686 return 0;
1687 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1688 return 0;
1690 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1691 if (nTool == -1) return 0;
1693 TRACE("tool %d\n", nTool);
1695 toolPtr = &infoPtr->tools[nTool];
1697 /* copy tool data */
1698 toolPtr->uFlags = lpToolInfo->uFlags;
1699 toolPtr->hwnd = lpToolInfo->hwnd;
1700 toolPtr->uId = lpToolInfo->uId;
1701 toolPtr->rect = lpToolInfo->rect;
1702 toolPtr->hinst = lpToolInfo->hinst;
1704 if (HIWORD(lpToolInfo->lpszText) == 0) {
1705 TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
1706 toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
1708 else if (lpToolInfo->lpszText) {
1709 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
1710 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1711 else {
1712 if ( (toolPtr->lpszText) &&
1713 (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1714 Free (toolPtr->lpszText);
1715 toolPtr->lpszText = NULL;
1717 if (lpToolInfo->lpszText) {
1718 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
1719 -1, NULL, 0);
1720 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
1721 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
1722 toolPtr->lpszText, len);
1727 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1728 toolPtr->lParam = lpToolInfo->lParam;
1730 return 0;
1734 static LRESULT
1735 TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1737 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1738 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1739 TTTOOL_INFO *toolPtr;
1740 INT nTool;
1742 if (lpToolInfo == NULL)
1743 return 0;
1744 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1745 return 0;
1747 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1748 if (nTool == -1) return 0;
1750 TRACE("tool %d\n", nTool);
1752 toolPtr = &infoPtr->tools[nTool];
1754 /* copy tool data */
1755 toolPtr->uFlags = lpToolInfo->uFlags;
1756 toolPtr->hwnd = lpToolInfo->hwnd;
1757 toolPtr->uId = lpToolInfo->uId;
1758 toolPtr->rect = lpToolInfo->rect;
1759 toolPtr->hinst = lpToolInfo->hinst;
1761 if (HIWORD(lpToolInfo->lpszText) == 0) {
1762 TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
1763 toolPtr->lpszText = lpToolInfo->lpszText;
1765 else if (lpToolInfo->lpszText) {
1766 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
1767 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1768 else {
1769 if ( (toolPtr->lpszText) &&
1770 (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1771 Free (toolPtr->lpszText);
1772 toolPtr->lpszText = NULL;
1774 if (lpToolInfo->lpszText) {
1775 INT len = lstrlenW (lpToolInfo->lpszText);
1776 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
1777 strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
1782 if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1783 toolPtr->lParam = lpToolInfo->lParam;
1785 return 0;
1789 static LRESULT
1790 TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
1792 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1793 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1795 if (lpToolInfo == NULL)
1796 return 0;
1797 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1798 return FALSE;
1800 if ((BOOL)wParam) {
1801 /* activate */
1802 infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1803 if (infoPtr->nTrackTool != -1) {
1804 TRACE("activated!\n");
1805 infoPtr->bTrackActive = TRUE;
1806 TOOLTIPS_TrackShow (hwnd, infoPtr);
1809 else {
1810 /* deactivate */
1811 TOOLTIPS_TrackHide (hwnd, infoPtr);
1813 infoPtr->bTrackActive = FALSE;
1814 infoPtr->nTrackTool = -1;
1816 TRACE("deactivated!\n");
1819 return 0;
1823 static LRESULT
1824 TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam)
1826 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1828 infoPtr->xTrackPos = (INT)LOWORD(lParam);
1829 infoPtr->yTrackPos = (INT)HIWORD(lParam);
1831 if (infoPtr->bTrackActive) {
1832 TRACE("[%d %d]\n",
1833 infoPtr->xTrackPos, infoPtr->yTrackPos);
1835 TOOLTIPS_TrackShow (hwnd, infoPtr);
1838 return 0;
1842 static LRESULT
1843 TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam)
1845 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1847 if (infoPtr->nCurrentTool != -1)
1848 UpdateWindow (hwnd);
1850 return 0;
1854 static LRESULT
1855 TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1857 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1858 LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1859 TTTOOL_INFO *toolPtr;
1860 INT nTool;
1862 if (lpToolInfo == NULL)
1863 return 0;
1864 if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1865 return FALSE;
1867 nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1868 if (nTool == -1) return 0;
1870 TRACE("tool %d\n", nTool);
1872 toolPtr = &infoPtr->tools[nTool];
1874 /* copy tool text */
1875 toolPtr->hinst = lpToolInfo->hinst;
1877 if (HIWORD(lpToolInfo->lpszText) == 0){
1878 toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
1880 else if (lpToolInfo->lpszText) {
1881 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
1882 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1883 else {
1884 if ( (toolPtr->lpszText) &&
1885 (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1886 Free (toolPtr->lpszText);
1887 toolPtr->lpszText = NULL;
1889 if (lpToolInfo->lpszText) {
1890 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
1891 -1, NULL, 0);
1892 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
1893 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
1894 toolPtr->lpszText, len);
1899 if(infoPtr->nCurrentTool == -1) return 0;
1900 /* force repaint */
1901 if (infoPtr->bActive)
1902 TOOLTIPS_Show (hwnd, infoPtr);
1903 else if (infoPtr->bTrackActive)
1904 TOOLTIPS_TrackShow (hwnd, infoPtr);
1906 return 0;
1910 static LRESULT
1911 TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1913 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1914 LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1915 TTTOOL_INFO *toolPtr;
1916 INT nTool;
1918 if (lpToolInfo == NULL)
1919 return 0;
1920 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1921 return FALSE;
1923 nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1924 if (nTool == -1)
1925 return 0;
1927 TRACE("tool %d\n", nTool);
1929 toolPtr = &infoPtr->tools[nTool];
1931 /* copy tool text */
1932 toolPtr->hinst = lpToolInfo->hinst;
1934 if (HIWORD(lpToolInfo->lpszText) == 0){
1935 toolPtr->lpszText = lpToolInfo->lpszText;
1937 else if (lpToolInfo->lpszText) {
1938 if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
1939 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1940 else {
1941 if ( (toolPtr->lpszText) &&
1942 (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1943 Free (toolPtr->lpszText);
1944 toolPtr->lpszText = NULL;
1946 if (lpToolInfo->lpszText) {
1947 INT len = lstrlenW (lpToolInfo->lpszText);
1948 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
1949 strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
1954 if(infoPtr->nCurrentTool == -1) return 0;
1955 /* force repaint */
1956 if (infoPtr->bActive)
1957 TOOLTIPS_Show (hwnd, infoPtr);
1958 else if (infoPtr->bTrackActive)
1959 TOOLTIPS_TrackShow (hwnd, infoPtr);
1961 return 0;
1965 static LRESULT
1966 TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam)
1968 return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
1973 static LRESULT
1974 TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
1976 TOOLTIPS_INFO *infoPtr;
1977 NONCLIENTMETRICSA nclm;
1979 /* allocate memory for info structure */
1980 infoPtr = (TOOLTIPS_INFO *)Alloc (sizeof(TOOLTIPS_INFO));
1981 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1983 /* initialize info structure */
1984 infoPtr->bActive = TRUE;
1985 infoPtr->bTrackActive = FALSE;
1986 infoPtr->clrBk = GetSysColor (COLOR_INFOBK);
1987 infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);
1989 nclm.cbSize = sizeof(NONCLIENTMETRICSA);
1990 SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
1991 infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont);
1993 infoPtr->nMaxTipWidth = -1;
1994 infoPtr->nTool = -1;
1995 infoPtr->nCurrentTool = -1;
1996 infoPtr->nTrackTool = -1;
1998 TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L);
2000 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
2002 return 0;
2006 static LRESULT
2007 TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
2009 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2010 TTTOOL_INFO *toolPtr;
2011 INT i;
2013 /* free tools */
2014 if (infoPtr->tools) {
2015 for (i = 0; i < infoPtr->uNumTools; i++) {
2016 toolPtr = &infoPtr->tools[i];
2017 if (toolPtr->lpszText) {
2018 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
2019 (HIWORD((INT)toolPtr->lpszText) != 0) )
2021 Free (toolPtr->lpszText);
2022 toolPtr->lpszText = NULL;
2026 /* remove subclassing */
2027 if (toolPtr->uFlags & TTF_SUBCLASS) {
2028 if (toolPtr->uFlags & TTF_IDISHWND) {
2029 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
2031 else {
2032 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
2036 Free (infoPtr->tools);
2039 /* delete font */
2040 DeleteObject (infoPtr->hFont);
2042 /* free tool tips info data */
2043 Free (infoPtr);
2044 SetWindowLongA(hwnd, 0, 0);
2045 return 0;
2049 static LRESULT
2050 TOOLTIPS_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2052 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2053 RECT rect;
2054 HBRUSH hBrush;
2056 hBrush = CreateSolidBrush (infoPtr->clrBk);
2057 GetClientRect (hwnd, &rect);
2058 FillRect ((HDC)wParam, &rect, hBrush);
2059 DeleteObject (hBrush);
2061 return FALSE;
2065 static LRESULT
2066 TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2068 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2070 return (LRESULT)infoPtr->hFont;
2074 static LRESULT
2075 TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2077 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2079 TOOLTIPS_Hide (hwnd, infoPtr);
2081 return 0;
2085 static LRESULT
2086 TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
2088 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2089 DWORD dwExStyle = GetWindowLongA (hwnd, GWL_EXSTYLE);
2091 dwStyle &= 0x0000FFFF;
2092 dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
2093 SetWindowLongA (hwnd, GWL_STYLE, dwStyle);
2095 dwExStyle |= WS_EX_TOOLWINDOW;
2096 SetWindowLongA (hwnd, GWL_EXSTYLE, dwExStyle);
2098 return TRUE;
2102 static LRESULT
2103 TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
2105 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2106 INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
2108 TRACE(" nTool=%d\n", nTool);
2110 if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
2111 if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
2112 TRACE("-- in transparent mode!\n");
2113 return HTTRANSPARENT;
2117 return DefWindowProcA (hwnd, WM_NCHITTEST, wParam, lParam);
2121 static LRESULT
2122 TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
2124 FIXME ("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2126 return 0;
2130 static LRESULT
2131 TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2133 HDC hdc;
2134 PAINTSTRUCT ps;
2136 hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2137 TOOLTIPS_Refresh (hwnd, hdc);
2138 if (!wParam)
2139 EndPaint (hwnd, &ps);
2140 return 0;
2144 static LRESULT
2145 TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2147 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2148 LOGFONTW lf;
2150 if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf))
2151 return 0;
2153 if(infoPtr->hFont) DeleteObject (infoPtr->hFont);
2154 infoPtr->hFont = CreateFontIndirectW(&lf);
2156 if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
2157 FIXME("full redraw needed!\n");
2160 return 0;
2162 /******************************************************************
2163 * TOOLTIPS_OnWMGetTextLength
2165 * This function is called when the tooltip receive a
2166 * WM_GETTEXTLENGTH message.
2167 * wParam : not used
2168 * lParam : not used
2170 * returns the length, in characters, of the tip text
2171 ******************************************************************/
2172 static LRESULT
2173 TOOLTIPS_OnWMGetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam)
2175 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2176 return lstrlenW(infoPtr->szTipText);
2179 /******************************************************************
2180 * TOOLTIPS_OnWMGetText
2182 * This function is called when the tooltip receive a
2183 * WM_GETTEXT message.
2184 * wParam : specifies the maximum number of characters to be copied
2185 * lParam : is the pointer to the buffer that will receive
2186 * the tip text
2188 * returns the number of characters copied
2189 ******************************************************************/
2190 static LRESULT
2191 TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
2193 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2195 if(!infoPtr || !(infoPtr->szTipText))
2196 return 0;
2198 return WideCharToMultiByte(CP_ACP, 0, infoPtr->szTipText, -1,
2199 (LPSTR)lParam, wParam, NULL, NULL);
2202 static LRESULT
2203 TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
2205 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2206 INT nOldTool;
2208 TRACE("timer %d (%p) expired!\n", wParam, hwnd);
2210 switch (wParam) {
2211 case ID_TIMERSHOW:
2212 KillTimer (hwnd, ID_TIMERSHOW);
2213 nOldTool = infoPtr->nTool;
2214 if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool)
2215 TOOLTIPS_Show (hwnd, infoPtr);
2216 break;
2218 case ID_TIMERPOP:
2219 TOOLTIPS_Hide (hwnd, infoPtr);
2220 break;
2222 case ID_TIMERLEAVE:
2223 nOldTool = infoPtr->nTool;
2224 infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE);
2225 TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
2226 infoPtr->nTool, infoPtr->nCurrentTool);
2227 if (infoPtr->nTool != nOldTool) {
2228 if(infoPtr->nTool == -1) { /* Moved out of all tools */
2229 TOOLTIPS_Hide(hwnd, infoPtr);
2230 KillTimer(hwnd, ID_TIMERLEAVE);
2231 } else if (nOldTool == -1) { /* Moved from outside */
2232 ERR("How did this happen?\n");
2233 } else { /* Moved from one to another */
2234 TOOLTIPS_Hide (hwnd, infoPtr);
2235 KillTimer(hwnd, ID_TIMERLEAVE);
2236 if(infoPtr->bActive) {
2237 SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
2238 TRACE("timer 1 started!\n");
2242 break;
2244 default:
2245 ERR("Unknown timer id %d\n", wParam);
2246 break;
2248 return 0;
2252 static LRESULT
2253 TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam)
2255 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2256 NONCLIENTMETRICSA nclm;
2258 infoPtr->clrBk = GetSysColor (COLOR_INFOBK);
2259 infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);
2261 DeleteObject (infoPtr->hFont);
2262 nclm.cbSize = sizeof(NONCLIENTMETRICSA);
2263 SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
2264 infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont);
2266 return 0;
2270 LRESULT CALLBACK
2271 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
2273 MSG msg;
2275 switch(uMsg) {
2276 case WM_MOUSEMOVE:
2277 case WM_LBUTTONDOWN:
2278 case WM_LBUTTONUP:
2279 case WM_MBUTTONDOWN:
2280 case WM_MBUTTONUP:
2281 case WM_RBUTTONDOWN:
2282 case WM_RBUTTONUP:
2283 msg.hwnd = hwnd;
2284 msg.message = uMsg;
2285 msg.wParam = wParam;
2286 msg.lParam = lParam;
2287 TOOLTIPS_RelayEvent((HWND)dwRef, 0, (LPARAM)&msg);
2288 break;
2290 default:
2291 break;
2293 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
2297 static LRESULT CALLBACK
2298 TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2300 TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2301 if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2302 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2303 switch (uMsg)
2305 case TTM_ACTIVATE:
2306 return TOOLTIPS_Activate (hwnd, wParam, lParam);
2308 case TTM_ADDTOOLA:
2309 return TOOLTIPS_AddToolA (hwnd, wParam, lParam);
2311 case TTM_ADDTOOLW:
2312 return TOOLTIPS_AddToolW (hwnd, wParam, lParam);
2314 case TTM_DELTOOLA:
2315 return TOOLTIPS_DelToolA (hwnd, wParam, lParam);
2317 case TTM_DELTOOLW:
2318 return TOOLTIPS_DelToolW (hwnd, wParam, lParam);
2320 case TTM_ENUMTOOLSA:
2321 return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam);
2323 case TTM_ENUMTOOLSW:
2324 return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam);
2326 case TTM_GETBUBBLESIZE:
2327 return TOOLTIPS_GetBubbleSize (hwnd, wParam, lParam);
2329 case TTM_GETCURRENTTOOLA:
2330 return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam);
2332 case TTM_GETCURRENTTOOLW:
2333 return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam);
2335 case TTM_GETDELAYTIME:
2336 return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam);
2338 case TTM_GETMARGIN:
2339 return TOOLTIPS_GetMargin (hwnd, wParam, lParam);
2341 case TTM_GETMAXTIPWIDTH:
2342 return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam);
2344 case TTM_GETTEXTA:
2345 return TOOLTIPS_GetTextA (hwnd, wParam, lParam);
2347 case TTM_GETTEXTW:
2348 return TOOLTIPS_GetTextW (hwnd, wParam, lParam);
2350 case TTM_GETTIPBKCOLOR:
2351 return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam);
2353 case TTM_GETTIPTEXTCOLOR:
2354 return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam);
2356 case TTM_GETTOOLCOUNT:
2357 return TOOLTIPS_GetToolCount (hwnd, wParam, lParam);
2359 case TTM_GETTOOLINFOA:
2360 return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam);
2362 case TTM_GETTOOLINFOW:
2363 return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam);
2365 case TTM_HITTESTA:
2366 return TOOLTIPS_HitTestA (hwnd, wParam, lParam);
2368 case TTM_HITTESTW:
2369 return TOOLTIPS_HitTestW (hwnd, wParam, lParam);
2371 case TTM_NEWTOOLRECTA:
2372 return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam);
2374 case TTM_NEWTOOLRECTW:
2375 return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam);
2377 case TTM_POP:
2378 return TOOLTIPS_Pop (hwnd, wParam, lParam);
2380 case TTM_RELAYEVENT:
2381 return TOOLTIPS_RelayEvent (hwnd, wParam, lParam);
2383 case TTM_SETDELAYTIME:
2384 return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam);
2386 case TTM_SETMARGIN:
2387 return TOOLTIPS_SetMargin (hwnd, wParam, lParam);
2389 case TTM_SETMAXTIPWIDTH:
2390 return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam);
2392 case TTM_SETTIPBKCOLOR:
2393 return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam);
2395 case TTM_SETTIPTEXTCOLOR:
2396 return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam);
2398 case TTM_SETTOOLINFOA:
2399 return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam);
2401 case TTM_SETTOOLINFOW:
2402 return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam);
2404 case TTM_TRACKACTIVATE:
2405 return TOOLTIPS_TrackActivate (hwnd, wParam, lParam);
2407 case TTM_TRACKPOSITION:
2408 return TOOLTIPS_TrackPosition (hwnd, wParam, lParam);
2410 case TTM_UPDATE:
2411 return TOOLTIPS_Update (hwnd, wParam, lParam);
2413 case TTM_UPDATETIPTEXTA:
2414 return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam);
2416 case TTM_UPDATETIPTEXTW:
2417 return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam);
2419 case TTM_WINDOWFROMPOINT:
2420 return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam);
2423 case WM_CREATE:
2424 return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam);
2426 case WM_DESTROY:
2427 return TOOLTIPS_Destroy (hwnd, wParam, lParam);
2429 case WM_ERASEBKGND:
2430 return TOOLTIPS_EraseBackground (hwnd, wParam, lParam);
2432 case WM_GETFONT:
2433 return TOOLTIPS_GetFont (hwnd, wParam, lParam);
2435 case WM_GETTEXT:
2436 return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam);
2438 case WM_GETTEXTLENGTH:
2439 return TOOLTIPS_OnWMGetTextLength (hwnd, wParam, lParam);
2442 case WM_LBUTTONDOWN:
2443 case WM_LBUTTONUP:
2444 case WM_MBUTTONDOWN:
2445 case WM_MBUTTONUP:
2446 case WM_RBUTTONDOWN:
2447 case WM_RBUTTONUP:
2448 case WM_MOUSEMOVE:
2449 return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam);
2451 case WM_NCCREATE:
2452 return TOOLTIPS_NCCreate (hwnd, wParam, lParam);
2454 case WM_NCHITTEST:
2455 return TOOLTIPS_NCHitTest (hwnd, wParam, lParam);
2457 case WM_NOTIFYFORMAT:
2458 return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam);
2460 case WM_PAINT:
2461 return TOOLTIPS_Paint (hwnd, wParam, lParam);
2463 case WM_SETFONT:
2464 return TOOLTIPS_SetFont (hwnd, wParam, lParam);
2466 case WM_TIMER:
2467 return TOOLTIPS_Timer (hwnd, wParam, lParam);
2469 case WM_WININICHANGE:
2470 return TOOLTIPS_WinIniChange (hwnd, wParam, lParam);
2472 default:
2473 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
2474 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
2475 uMsg, wParam, lParam);
2476 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2478 return 0;
2482 VOID
2483 TOOLTIPS_Register (void)
2485 WNDCLASSA wndClass;
2487 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
2488 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2489 wndClass.lpfnWndProc = (WNDPROC)TOOLTIPS_WindowProc;
2490 wndClass.cbClsExtra = 0;
2491 wndClass.cbWndExtra = sizeof(TOOLTIPS_INFO *);
2492 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
2493 wndClass.hbrBackground = 0;
2494 wndClass.lpszClassName = TOOLTIPS_CLASSA;
2496 RegisterClassA (&wndClass);
2500 VOID
2501 TOOLTIPS_Unregister (void)
2503 UnregisterClassA (TOOLTIPS_CLASSA, NULL);