When unsubclassing tools, use toolPtr->hwnd instead of toolPtr->uId if
[wine] / dlls / comctl32 / tooltips.c
1 /*
2  * Tool tip control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  *
6  * TODO:
7  *   - Unicode support (started).
8  *   - Custom draw support.
9  *
10  * Testing:
11  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
12  *     The second cdrom (chapter 3) contains executables activate.exe,
13  *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
14  *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
15  *
16  *   Timer logic.
17  *
18  * One important point to remember is that tools don't necessarily get
19  * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when
20  * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because
21  * here WM_MOUSEMOVEs only get sent when the cursor is inside the
22  * client area.  Therefore the only reliable way to know that the
23  * cursor has left a tool is to keep a timer running and check the
24  * position every time it expires.  This is the role of timer
25  * ID_TIMERLEAVE.
26  *
27  *
28  * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start
29  * ID_TIMERSHOW, if this times out and we're still in the tool we show
30  * the tip.  On showing a tip we start both ID_TIMERPOP and
31  * ID_TIMERLEAVE.  On hiding a tooltip we kill ID_TIMERPOP.
32  * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE.  If
33  * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed.
34  * ID_TIMERLEAVE remains running - this is important as we need to
35  * determine when the cursor leaves the tool.
36  *
37  * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're
38  * still in the tool do nothing (apart from restart ID_TIMERPOP if
39  * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running).  If we've
40  * left the tool and entered another one then hide the tip and start
41  * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE.  If we're
42  * outside all tools hide the tip and kill ID_TIMERLEAVE.  On Relayed
43  * mouse button messages hide the tip but leave ID_TIMERLEAVE running,
44  * this again will let us keep track of when the cursor leaves the
45  * tool.
46  *
47  *
48  * infoPtr->nTool is the tool the mouse was on on the last relayed MM
49  * or timer expiry or -1 if the mouse was not on a tool.
50  * 
51  * infoPtr->nCurrentTool is the tool for which the tip is currently
52  * displaying text for or -1 if the tip is not shown.  Actually this
53  * will only ever be infoPtr-nTool or -1, so it could be changed to a
54  * BOOL.
55  *
56  */
57
58
59
60 #include <string.h>
61
62 #include "winbase.h"
63 #include "commctrl.h"
64 #include "tooltips.h"
65 #include "debugtools.h"
66
67 DEFAULT_DEBUG_CHANNEL(tooltips)
68
69 #define ID_TIMERSHOW   1    /* show delay timer */
70 #define ID_TIMERPOP    2    /* auto pop timer */
71 #define ID_TIMERLEAVE  3    /* tool leave timer */
72
73
74 extern LPSTR COMCTL32_aSubclass; /* global subclassing atom */
75
76 /* property name of tooltip window handle */
77 /*#define TT_SUBCLASS_PROP "CC32SubclassInfo" */
78
79 #define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongA (hWindow, 0))
80
81
82 LRESULT CALLBACK
83 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
84
85
86 static VOID
87 TOOLTIPS_Refresh (HWND hwnd, HDC hdc)
88 {
89     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd);
90     RECT rc;
91     INT oldBkMode;
92     HFONT hOldFont;
93     HBRUSH hBrush;
94     UINT uFlags = DT_EXTERNALLEADING;
95
96     if (infoPtr->nMaxTipWidth > -1)
97         uFlags |= DT_WORDBREAK;
98     if (GetWindowLongA (hwnd, GWL_STYLE) & TTS_NOPREFIX)
99         uFlags |= DT_NOPREFIX;
100     GetClientRect (hwnd, &rc);
101
102     /* fill the background */
103     hBrush = CreateSolidBrush (infoPtr->clrBk);
104     FillRect (hdc, &rc, hBrush);
105     DeleteObject (hBrush);
106
107     /* calculate text rectangle */
108     rc.left   += (2 + infoPtr->rcMargin.left);
109     rc.top    += (2 + infoPtr->rcMargin.top);
110     rc.right  -= (2 + infoPtr->rcMargin.right);
111     rc.bottom -= (2 + infoPtr->rcMargin.bottom);
112
113     /* draw text */
114     oldBkMode = SetBkMode (hdc, TRANSPARENT);
115     SetTextColor (hdc, infoPtr->clrText);
116     hOldFont = SelectObject (hdc, infoPtr->hFont);
117     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
118     SelectObject (hdc, hOldFont);
119     if (oldBkMode != TRANSPARENT)
120         SetBkMode (hdc, oldBkMode);
121 }
122
123
124 static VOID
125 TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool)
126 {
127     TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
128
129     if ((toolPtr->hinst) && (HIWORD((UINT)toolPtr->lpszText) == 0)) {
130         /* load a resource */
131         TRACE("load res string %x %x\n",
132                toolPtr->hinst, (int)toolPtr->lpszText);
133         LoadStringW (toolPtr->hinst, (UINT)toolPtr->lpszText,
134                        infoPtr->szTipText, INFOTIPSIZE);
135     }
136     else if (toolPtr->lpszText) {
137         if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) {
138             NMTTDISPINFOA ttnmdi;
139
140             /* fill NMHDR struct */
141             ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
142             ttnmdi.hdr.hwndFrom = hwnd;
143             ttnmdi.hdr.idFrom = toolPtr->uId;
144             ttnmdi.hdr.code = TTN_GETDISPINFOA;
145             ttnmdi.lpszText = (LPSTR)&ttnmdi.szText;
146             ttnmdi.uFlags = toolPtr->uFlags;
147             ttnmdi.lParam = toolPtr->lParam;
148
149             TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
150             SendMessageA (toolPtr->hwnd, WM_NOTIFY,
151                             (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi);
152
153             if ((ttnmdi.hinst) && (HIWORD((UINT)ttnmdi.lpszText) == 0)) {
154                 LoadStringW (ttnmdi.hinst, (UINT)ttnmdi.lpszText,
155                                infoPtr->szTipText, INFOTIPSIZE);
156                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
157                     toolPtr->hinst = ttnmdi.hinst;
158                     toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText;
159                 }
160             }
161             else if (ttnmdi.szText[0]) {
162                 MultiByteToWideChar(CP_ACP, 0, ttnmdi.szText, 80,
163                                     infoPtr->szTipText, INFOTIPSIZE);
164                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
165                     INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.szText,
166                                                   80, NULL, 0);
167                     toolPtr->hinst = 0;
168                     toolPtr->lpszText = COMCTL32_Alloc (len * sizeof(WCHAR));
169                     MultiByteToWideChar(CP_ACP, 0, ttnmdi.szText, 80,
170                                         toolPtr->lpszText, len);
171                 }
172             }
173             else if (ttnmdi.lpszText == 0) {
174                 /* no text available */
175                 infoPtr->szTipText[0] = L'\0';
176             }
177             else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
178                 MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1,
179                                     infoPtr->szTipText, INFOTIPSIZE);
180                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
181                     INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText,
182                                                   -1, NULL, 0);
183                     toolPtr->hinst = 0;
184                     toolPtr->lpszText = COMCTL32_Alloc (len * sizeof(WCHAR));
185                     MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1,
186                                         toolPtr->lpszText, len);
187                 }
188             }
189             else {
190                 ERR("recursive text callback!\n");
191                 infoPtr->szTipText[0] = '\0';
192             }
193         }
194         else {
195             /* the item is a usual (unicode) text */
196             lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
197         }
198     }
199     else {
200         /* no text available */
201         infoPtr->szTipText[0] = L'\0';
202     }
203
204     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
205 }
206
207
208 static VOID
209 TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
210 {
211     HDC hdc;
212     HFONT hOldFont;
213     UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
214     RECT rc = {0, 0, 0, 0};
215
216     if (infoPtr->nMaxTipWidth > -1) {
217         rc.right = infoPtr->nMaxTipWidth;
218         uFlags |= DT_WORDBREAK;
219     }
220     if (GetWindowLongA (hwnd, GWL_STYLE) & TTS_NOPREFIX)
221         uFlags |= DT_NOPREFIX;
222     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
223
224     hdc = GetDC (hwnd);
225     hOldFont = SelectObject (hdc, infoPtr->hFont);
226     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
227     SelectObject (hdc, hOldFont);
228     ReleaseDC (hwnd, hdc);
229
230     lpSize->cx = rc.right - rc.left + 4 + 
231                  infoPtr->rcMargin.left + infoPtr->rcMargin.right;
232     lpSize->cy = rc.bottom - rc.top + 4 +
233                  infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
234 }
235
236
237 static VOID
238 TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr)
239 {
240     TTTOOL_INFO *toolPtr;
241     RECT rect, wndrect;
242     SIZE size;
243     NMHDR  hdr;
244
245     if (infoPtr->nTool == -1) {
246         TRACE("invalid tool (-1)!\n");
247         return;
248     }
249
250     infoPtr->nCurrentTool = infoPtr->nTool;
251
252     TRACE("Show tooltip pre %d! (%04x)\n", infoPtr->nTool, hwnd);
253
254     TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool);
255
256     if (infoPtr->szTipText[0] == L'\0') {
257         infoPtr->nCurrentTool = -1;
258         return;
259     }
260
261     TRACE("Show tooltip %d!\n", infoPtr->nCurrentTool);
262     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
263
264     hdr.hwndFrom = hwnd;
265     hdr.idFrom = toolPtr->uId;
266     hdr.code = TTN_SHOW;
267     SendMessageA (toolPtr->hwnd, WM_NOTIFY,
268                     (WPARAM)toolPtr->uId, (LPARAM)&hdr);
269
270     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
271
272     TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
273     TRACE("size %d - %d\n", size.cx, size.cy);
274
275     if (toolPtr->uFlags & TTF_CENTERTIP) {
276         RECT rc;
277
278         if (toolPtr->uFlags & TTF_IDISHWND)
279             GetWindowRect ((HWND)toolPtr->uId, &rc);
280         else {
281             rc = toolPtr->rect;
282             MapWindowPoints (toolPtr->hwnd, (HWND)0, (LPPOINT)&rc, 2);
283         }
284         rect.left = (rc.left + rc.right - size.cx) / 2;
285         rect.top  = rc.bottom + 2;
286     }
287     else {
288         GetCursorPos ((LPPOINT)&rect);
289         rect.top += 20;
290     }
291
292     TRACE("pos %d - %d\n", rect.left, rect.top);
293
294     rect.right = rect.left + size.cx;
295     rect.bottom = rect.top + size.cy;
296
297     /* check position */
298     wndrect.right = GetSystemMetrics( SM_CXSCREEN );
299     if( rect.right > wndrect.right ) {
300            rect.left -= rect.right - wndrect.right + 2;
301            rect.right = wndrect.right - 2;
302     }
303     wndrect.bottom = GetSystemMetrics( SM_CYSCREEN );
304     if( rect.bottom > wndrect.bottom ) {
305         RECT rc;
306
307         if (toolPtr->uFlags & TTF_IDISHWND)
308             GetWindowRect ((HWND)toolPtr->uId, &rc);
309         else {
310             rc = toolPtr->rect;
311             MapWindowPoints (toolPtr->hwnd, (HWND)0, (LPPOINT)&rc, 2);
312         }   
313         rect.bottom = rc.top - 2;
314         rect.top = rect.bottom - size.cy;
315     }
316
317     AdjustWindowRectEx (&rect, GetWindowLongA (hwnd, GWL_STYLE),
318                         FALSE, GetWindowLongA (hwnd, GWL_EXSTYLE));
319
320     SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
321                     rect.right - rect.left, rect.bottom - rect.top,
322                     SWP_SHOWWINDOW | SWP_NOACTIVATE);
323
324     /* repaint the tooltip */
325     InvalidateRect(hwnd, NULL, TRUE);
326     UpdateWindow(hwnd);
327
328     SetTimer (hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
329     TRACE("timer 2 started!\n");
330     SetTimer (hwnd, ID_TIMERLEAVE, infoPtr->nReshowTime, 0);
331     TRACE("timer 3 started!\n");
332 }
333
334
335 static VOID
336 TOOLTIPS_Hide (HWND hwnd, TOOLTIPS_INFO *infoPtr)
337 {
338     TTTOOL_INFO *toolPtr;
339     NMHDR hdr;
340
341     TRACE("Hide tooltip %d! (%04x)\n", infoPtr->nCurrentTool, hwnd);
342
343     if (infoPtr->nCurrentTool == -1)
344         return;
345
346     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
347     KillTimer (hwnd, ID_TIMERPOP);
348
349     hdr.hwndFrom = hwnd;
350     hdr.idFrom = toolPtr->uId;
351     hdr.code = TTN_POP;
352     SendMessageA (toolPtr->hwnd, WM_NOTIFY,
353                     (WPARAM)toolPtr->uId, (LPARAM)&hdr);
354
355     infoPtr->nCurrentTool = -1;
356
357     SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
358                     SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
359 }
360
361
362 static VOID
363 TOOLTIPS_TrackShow (HWND hwnd, TOOLTIPS_INFO *infoPtr)
364 {
365     TTTOOL_INFO *toolPtr;
366     RECT rect;
367     SIZE size;
368     NMHDR hdr;
369
370     if (infoPtr->nTrackTool == -1) {
371         TRACE("invalid tracking tool (-1)!\n");
372         return;
373     }
374
375     TRACE("show tracking tooltip pre %d!\n", infoPtr->nTrackTool);
376
377     TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nTrackTool);
378
379     if (infoPtr->szTipText[0] == L'\0') {
380         infoPtr->nTrackTool = -1;
381         return;
382     }
383
384     TRACE("show tracking tooltip %d!\n", infoPtr->nTrackTool);
385     toolPtr = &infoPtr->tools[infoPtr->nTrackTool];
386
387     hdr.hwndFrom = hwnd;
388     hdr.idFrom = toolPtr->uId;
389     hdr.code = TTN_SHOW;
390     SendMessageA (toolPtr->hwnd, WM_NOTIFY,
391                     (WPARAM)toolPtr->uId, (LPARAM)&hdr);
392
393     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
394
395     TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
396     TRACE("size %d - %d\n", size.cx, size.cy);
397
398     if (toolPtr->uFlags & TTF_ABSOLUTE) {
399         rect.left = infoPtr->xTrackPos;
400         rect.top  = infoPtr->yTrackPos;
401
402         if (toolPtr->uFlags & TTF_CENTERTIP) {
403             rect.left -= (size.cx / 2);
404             rect.top  -= (size.cy / 2);
405         }
406     }
407     else {
408         RECT rcTool;
409
410         if (toolPtr->uFlags & TTF_IDISHWND)
411             GetWindowRect ((HWND)toolPtr->uId, &rcTool);
412         else {
413             rcTool = toolPtr->rect;
414             MapWindowPoints (toolPtr->hwnd, (HWND)0, (LPPOINT)&rcTool, 2);
415         }
416
417         GetCursorPos ((LPPOINT)&rect);
418         rect.top += 20;
419
420         if (toolPtr->uFlags & TTF_CENTERTIP) {
421             rect.left -= (size.cx / 2);
422             rect.top  -= (size.cy / 2);
423         }
424
425         /* smart placement */
426         if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) &&
427             (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom))
428             rect.left = rcTool.right;
429     }
430
431     TRACE("pos %d - %d\n", rect.left, rect.top);
432
433     rect.right = rect.left + size.cx;
434     rect.bottom = rect.top + size.cy;
435
436     AdjustWindowRectEx (&rect, GetWindowLongA (hwnd, GWL_STYLE),
437                         FALSE, GetWindowLongA (hwnd, GWL_EXSTYLE));
438
439     SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top,
440                     rect.right - rect.left, rect.bottom - rect.top,
441                     SWP_SHOWWINDOW | SWP_NOACTIVATE );
442
443     InvalidateRect(hwnd, NULL, TRUE);
444     UpdateWindow(hwnd);
445 }
446
447
448 static VOID
449 TOOLTIPS_TrackHide (HWND hwnd, TOOLTIPS_INFO *infoPtr)
450 {
451     TTTOOL_INFO *toolPtr;
452     NMHDR hdr;
453
454     if (infoPtr->nTrackTool == -1)
455         return;
456
457     toolPtr = &infoPtr->tools[infoPtr->nTrackTool];
458     TRACE("hide tracking tooltip %d!\n", infoPtr->nTrackTool);
459
460     hdr.hwndFrom = hwnd;
461     hdr.idFrom = toolPtr->uId;
462     hdr.code = TTN_POP;
463     SendMessageA (toolPtr->hwnd, WM_NOTIFY,
464                     (WPARAM)toolPtr->uId, (LPARAM)&hdr);
465
466     SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
467                     SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
468 }
469
470
471 static INT
472 TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA lpToolInfo)
473 {
474     TTTOOL_INFO *toolPtr;
475     INT nTool;
476
477     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
478         toolPtr = &infoPtr->tools[nTool];
479
480         if (!(toolPtr->uFlags & TTF_IDISHWND) && 
481             (lpToolInfo->hwnd == toolPtr->hwnd) &&
482             (lpToolInfo->uId == toolPtr->uId))
483             return nTool;
484     }
485
486     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
487         toolPtr = &infoPtr->tools[nTool];
488
489         if ((toolPtr->uFlags & TTF_IDISHWND) &&
490             (lpToolInfo->uId == toolPtr->uId))
491             return nTool;
492     }
493
494     return -1;
495 }
496
497
498 static INT
499 TOOLTIPS_GetToolFromInfoW (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOW lpToolInfo)
500 {
501     TTTOOL_INFO *toolPtr;
502     INT nTool;
503
504     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
505         toolPtr = &infoPtr->tools[nTool];
506
507         if (!(toolPtr->uFlags & TTF_IDISHWND) && 
508             (lpToolInfo->hwnd == toolPtr->hwnd) &&
509             (lpToolInfo->uId == toolPtr->uId))
510             return nTool;
511     }
512
513     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
514         toolPtr = &infoPtr->tools[nTool];
515
516         if ((toolPtr->uFlags & TTF_IDISHWND) &&
517             (lpToolInfo->uId == toolPtr->uId))
518             return nTool;
519     }
520
521     return -1;
522 }
523
524
525 static INT
526 TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND hwnd, LPPOINT lpPt)
527 {
528     TTTOOL_INFO *toolPtr;
529     INT  nTool;
530
531     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
532         toolPtr = &infoPtr->tools[nTool];
533
534         if (!(toolPtr->uFlags & TTF_IDISHWND)) {
535             if (hwnd != toolPtr->hwnd)
536                 continue;
537             if (!PtInRect (&toolPtr->rect, *lpPt))
538                 continue;
539             return nTool;
540         }
541     }
542
543     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
544         toolPtr = &infoPtr->tools[nTool];
545
546         if (toolPtr->uFlags & TTF_IDISHWND) {
547             if ((HWND)toolPtr->uId == hwnd)
548                 return nTool;
549         }
550     }
551
552     return -1;
553 }
554
555
556 static BOOL
557 TOOLTIPS_IsWindowActive (HWND hwnd)
558 {
559     HWND hwndActive = GetActiveWindow ();
560     if (!hwndActive)
561         return FALSE;
562     if (hwndActive == hwnd)
563         return TRUE;
564     return IsChild (hwndActive, hwnd);
565 }
566
567
568 static INT
569 TOOLTIPS_CheckTool (HWND hwnd, BOOL bShowTest)
570 {
571     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
572     POINT pt;
573     HWND hwndTool;
574     INT nTool;
575
576     GetCursorPos (&pt);
577     hwndTool = SendMessageA (hwnd, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
578     if (hwndTool == 0)
579         return -1;
580
581     ScreenToClient (hwndTool, &pt);
582     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
583     if (nTool == -1)
584         return -1;
585
586     if (!(GetWindowLongA (hwnd, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) {
587         if (!TOOLTIPS_IsWindowActive (GetWindow (hwnd, GW_OWNER)))
588             return -1;
589     }
590
591     TRACE("tool %d\n", nTool);
592
593     return nTool;
594 }
595
596
597 static LRESULT
598 TOOLTIPS_Activate (HWND hwnd, WPARAM wParam, LPARAM lParam)
599 {
600     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
601
602     infoPtr->bActive = (BOOL)wParam;
603
604     if (infoPtr->bActive)
605         TRACE("activate!\n");
606
607     if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
608         TOOLTIPS_Hide (hwnd, infoPtr);
609
610     return 0;
611 }
612
613
614 static LRESULT
615 TOOLTIPS_AddToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
616 {
617     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
618     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
619     TTTOOL_INFO *toolPtr;
620
621     if (lpToolInfo == NULL)
622         return FALSE;
623     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
624         return FALSE;
625
626     TRACE("add tool (%x) %x %d%s!\n",
627            hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
628            (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
629
630     if (infoPtr->uNumTools == 0) {
631         infoPtr->tools = COMCTL32_Alloc (sizeof(TTTOOL_INFO));
632         toolPtr = infoPtr->tools;
633     }
634     else {
635         TTTOOL_INFO *oldTools = infoPtr->tools;
636         infoPtr->tools =
637             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
638         memcpy (infoPtr->tools, oldTools,
639                 infoPtr->uNumTools * sizeof(TTTOOL_INFO));
640         COMCTL32_Free (oldTools);
641         toolPtr = &infoPtr->tools[infoPtr->uNumTools];
642     }
643
644     infoPtr->uNumTools++;
645
646     /* copy tool data */
647     toolPtr->uFlags = lpToolInfo->uFlags;
648     toolPtr->hwnd   = lpToolInfo->hwnd;
649     toolPtr->uId    = lpToolInfo->uId;
650     toolPtr->rect   = lpToolInfo->rect;
651     toolPtr->hinst  = lpToolInfo->hinst;
652
653     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)) {
654         TRACE("add string id %x!\n", (int)lpToolInfo->lpszText);
655         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
656     }
657     else if (lpToolInfo->lpszText) {
658         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) {
659             TRACE("add CALLBACK!\n");
660             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
661         }
662         else {
663             INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
664                                           NULL, 0);
665             TRACE("add text \"%s\"!\n", lpToolInfo->lpszText);
666             toolPtr->lpszText = COMCTL32_Alloc (len * sizeof(WCHAR));
667             MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
668                                 toolPtr->lpszText, len);
669         }
670     }
671
672     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
673         toolPtr->lParam = lpToolInfo->lParam;
674
675     /* install subclassing hook */
676     if (toolPtr->uFlags & TTF_SUBCLASS) {
677         if (toolPtr->uFlags & TTF_IDISHWND) {
678             LPTT_SUBCLASS_INFO lpttsi =
679                 (LPTT_SUBCLASS_INFO)GetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
680             if (lpttsi == NULL) {
681                 lpttsi =
682                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
683                 lpttsi->wpOrigProc = 
684                     (WNDPROC)SetWindowLongA ((HWND)toolPtr->uId,
685                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
686                 lpttsi->hwndToolTip = hwnd;
687                 lpttsi->uRefCount++;
688                 SetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass,
689                             (HANDLE)lpttsi);
690             }
691             else
692                 WARN("A window tool must only be listed once!\n");
693         }
694         else {
695             LPTT_SUBCLASS_INFO lpttsi =
696                 (LPTT_SUBCLASS_INFO)GetPropA (toolPtr->hwnd, COMCTL32_aSubclass);
697             if (lpttsi == NULL) {
698                 lpttsi =
699                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
700                 lpttsi->wpOrigProc = 
701                     (WNDPROC)SetWindowLongA (toolPtr->hwnd,
702                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
703                 lpttsi->hwndToolTip = hwnd;
704                 lpttsi->uRefCount++;
705                 SetPropA (toolPtr->hwnd, COMCTL32_aSubclass, (HANDLE)lpttsi);
706             }
707             else
708                 lpttsi->uRefCount++;
709         }
710         TRACE("subclassing installed!\n");
711     }
712
713     return TRUE;
714 }
715
716
717 static LRESULT
718 TOOLTIPS_AddToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
719 {
720     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
721     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
722     TTTOOL_INFO *toolPtr;
723
724     if (lpToolInfo == NULL)
725         return FALSE;
726     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
727         return FALSE;
728
729     TRACE("add tool (%x) %x %d%s!\n",
730            hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
731            (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
732
733     if (infoPtr->uNumTools == 0) {
734         infoPtr->tools = COMCTL32_Alloc (sizeof(TTTOOL_INFO));
735         toolPtr = infoPtr->tools;
736     }
737     else {
738         TTTOOL_INFO *oldTools = infoPtr->tools;
739         infoPtr->tools =
740             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
741         memcpy (infoPtr->tools, oldTools,
742                 infoPtr->uNumTools * sizeof(TTTOOL_INFO));
743         COMCTL32_Free (oldTools);
744         toolPtr = &infoPtr->tools[infoPtr->uNumTools];
745     }
746
747     infoPtr->uNumTools++;
748
749     /* copy tool data */
750     toolPtr->uFlags = lpToolInfo->uFlags;
751     toolPtr->hwnd   = lpToolInfo->hwnd;
752     toolPtr->uId    = lpToolInfo->uId;
753     toolPtr->rect   = lpToolInfo->rect;
754     toolPtr->hinst  = lpToolInfo->hinst;
755
756     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)) {
757         TRACE("add string id %x!\n", (int)lpToolInfo->lpszText);
758         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
759     }
760     else if (lpToolInfo->lpszText) {
761         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) {
762             TRACE("add CALLBACK!\n");
763             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
764         }
765         else {
766             INT len = lstrlenW (lpToolInfo->lpszText);
767             TRACE("add text %s!\n",
768                    debugstr_w(lpToolInfo->lpszText));
769             toolPtr->lpszText = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
770             lstrcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
771         }
772     }
773
774     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
775         toolPtr->lParam = lpToolInfo->lParam;
776
777     /* install subclassing hook */
778     if (toolPtr->uFlags & TTF_SUBCLASS) {
779         if (toolPtr->uFlags & TTF_IDISHWND) {
780             LPTT_SUBCLASS_INFO lpttsi =
781                 (LPTT_SUBCLASS_INFO)GetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
782             if (lpttsi == NULL) {
783                 lpttsi =
784                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
785                 lpttsi->wpOrigProc = 
786                     (WNDPROC)SetWindowLongA ((HWND)toolPtr->uId,
787                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
788                 lpttsi->hwndToolTip = hwnd;
789                 lpttsi->uRefCount++;
790                 SetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass,
791                             (HANDLE)lpttsi);
792             }
793             else
794                 WARN("A window tool must only be listed once!\n");
795         }
796         else {
797             LPTT_SUBCLASS_INFO lpttsi =
798                 (LPTT_SUBCLASS_INFO)GetPropA (toolPtr->hwnd, COMCTL32_aSubclass);
799             if (lpttsi == NULL) {
800                 lpttsi =
801                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
802                 lpttsi->wpOrigProc = 
803                     (WNDPROC)SetWindowLongA (toolPtr->hwnd,
804                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
805                 lpttsi->hwndToolTip = hwnd;
806                 lpttsi->uRefCount++;
807                 SetPropA (toolPtr->hwnd, COMCTL32_aSubclass, (HANDLE)lpttsi);
808             }
809             else
810                 lpttsi->uRefCount++;
811         }
812         TRACE("subclassing installed!\n");
813     }
814
815     return TRUE;
816 }
817
818
819 static LRESULT
820 TOOLTIPS_DelToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
821 {
822     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
823     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
824     TTTOOL_INFO *toolPtr;
825     INT nTool;
826
827     if (lpToolInfo == NULL)
828         return 0;
829     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
830         return 0;
831     if (infoPtr->uNumTools == 0)
832         return 0;
833
834     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
835     if (nTool == -1) return 0;
836
837     TRACE("tool %d\n", nTool);
838
839     /* delete text string */
840     toolPtr = &infoPtr->tools[nTool]; 
841     if ((toolPtr->hinst) && (toolPtr->lpszText)) {
842         if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
843              (HIWORD((INT)toolPtr->lpszText) != 0) )
844             COMCTL32_Free (toolPtr->lpszText);
845     }
846
847     /* remove subclassing */
848     if (toolPtr->uFlags & TTF_SUBCLASS) {
849         if (toolPtr->uFlags & TTF_IDISHWND) {
850             LPTT_SUBCLASS_INFO lpttsi =
851                 (LPTT_SUBCLASS_INFO)GetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
852             if (lpttsi) {
853                 SetWindowLongA ((HWND)toolPtr->uId, GWL_WNDPROC,
854                                   (LONG)lpttsi->wpOrigProc);
855                 RemovePropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
856                 COMCTL32_Free (&lpttsi);
857             }
858             else
859                 ERR("Invalid data handle!\n");
860         }
861         else {
862             LPTT_SUBCLASS_INFO lpttsi =
863                 (LPTT_SUBCLASS_INFO)GetPropA (toolPtr->hwnd, COMCTL32_aSubclass);
864             if (lpttsi) {
865                 if (lpttsi->uRefCount == 1) {
866                     SetWindowLongA ((HWND)toolPtr->hwnd, GWL_WNDPROC,
867                                       (LONG)lpttsi->wpOrigProc);
868                     RemovePropA ((HWND)toolPtr->hwnd, COMCTL32_aSubclass);
869                     COMCTL32_Free (&lpttsi);
870                 }
871                 else
872                     lpttsi->uRefCount--;
873             }
874             else
875                 ERR("Invalid data handle!\n");
876         }
877     }
878
879     /* delete tool from tool list */
880     if (infoPtr->uNumTools == 1) {
881         COMCTL32_Free (infoPtr->tools);
882         infoPtr->tools = NULL;
883     }
884     else {
885         TTTOOL_INFO *oldTools = infoPtr->tools;
886         infoPtr->tools =
887             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
888
889         if (nTool > 0)
890             memcpy (&infoPtr->tools[0], &oldTools[0],
891                     nTool * sizeof(TTTOOL_INFO));
892
893         if (nTool < infoPtr->uNumTools - 1)
894             memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
895                     (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
896
897         COMCTL32_Free (oldTools);
898     }
899
900     infoPtr->uNumTools--;
901
902     return 0;
903 }
904
905
906 static LRESULT
907 TOOLTIPS_DelToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
908 {
909     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
910     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
911     TTTOOL_INFO *toolPtr;
912     INT nTool;
913
914     if (lpToolInfo == NULL)
915         return 0;
916     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
917         return 0;
918     if (infoPtr->uNumTools == 0)
919         return 0;
920
921     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
922     if (nTool == -1) return 0;
923
924     TRACE("tool %d\n", nTool);
925
926     /* delete text string */
927     toolPtr = &infoPtr->tools[nTool]; 
928     if ((toolPtr->hinst) && (toolPtr->lpszText)) {
929         if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
930              (HIWORD((INT)toolPtr->lpszText) != 0) )
931             COMCTL32_Free (toolPtr->lpszText);
932     }
933
934     /* remove subclassing */
935     if (toolPtr->uFlags & TTF_SUBCLASS) {
936         if (toolPtr->uFlags & TTF_IDISHWND) {
937             LPTT_SUBCLASS_INFO lpttsi =
938                 (LPTT_SUBCLASS_INFO)GetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
939             if (lpttsi) {
940                 SetWindowLongA ((HWND)toolPtr->uId, GWL_WNDPROC,
941                                   (LONG)lpttsi->wpOrigProc);
942                 RemovePropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
943                 COMCTL32_Free (&lpttsi);
944             }
945             else
946                 ERR("Invalid data handle!\n");
947         }
948         else {
949             LPTT_SUBCLASS_INFO lpttsi =
950                 (LPTT_SUBCLASS_INFO)GetPropA (toolPtr->hwnd, COMCTL32_aSubclass);
951             if (lpttsi) {
952                 if (lpttsi->uRefCount == 1) {
953                     SetWindowLongA ((HWND)toolPtr->hwnd, GWL_WNDPROC,
954                                       (LONG)lpttsi->wpOrigProc);
955                     RemovePropA ((HWND)toolPtr->hwnd, COMCTL32_aSubclass);
956                     COMCTL32_Free (&lpttsi);
957                 }
958                 else
959                     lpttsi->uRefCount--;
960             }
961             else
962                 ERR("Invalid data handle!\n");
963         }
964     }
965
966     /* delete tool from tool list */
967     if (infoPtr->uNumTools == 1) {
968         COMCTL32_Free (infoPtr->tools);
969         infoPtr->tools = NULL;
970     }
971     else {
972         TTTOOL_INFO *oldTools = infoPtr->tools;
973         infoPtr->tools =
974             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
975
976         if (nTool > 0)
977             memcpy (&infoPtr->tools[0], &oldTools[0],
978                     nTool * sizeof(TTTOOL_INFO));
979
980         if (nTool < infoPtr->uNumTools - 1)
981             memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
982                     (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
983
984         COMCTL32_Free (oldTools);
985     }
986
987     infoPtr->uNumTools--;
988
989     return 0;
990 }
991
992
993 static LRESULT
994 TOOLTIPS_EnumToolsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
995 {
996     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
997     UINT uIndex = (UINT)wParam;
998     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
999     TTTOOL_INFO *toolPtr;
1000
1001     if (lpToolInfo == NULL)
1002         return FALSE;
1003     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1004         return FALSE;
1005     if (uIndex >= infoPtr->uNumTools)
1006         return FALSE;
1007
1008     TRACE("index=%u\n", uIndex);
1009
1010     toolPtr = &infoPtr->tools[uIndex];
1011
1012     /* copy tool data */
1013     lpToolInfo->uFlags   = toolPtr->uFlags;
1014     lpToolInfo->hwnd     = toolPtr->hwnd;
1015     lpToolInfo->uId      = toolPtr->uId;
1016     lpToolInfo->rect     = toolPtr->rect;
1017     lpToolInfo->hinst    = toolPtr->hinst;
1018 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1019     lpToolInfo->lpszText = NULL;  /* FIXME */
1020
1021     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1022         lpToolInfo->lParam = toolPtr->lParam;
1023
1024     return TRUE;
1025 }
1026
1027
1028 static LRESULT
1029 TOOLTIPS_EnumToolsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1030 {
1031     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1032     UINT uIndex = (UINT)wParam;
1033     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1034     TTTOOL_INFO *toolPtr;
1035
1036     if (lpToolInfo == NULL)
1037         return FALSE;
1038     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1039         return FALSE;
1040     if (uIndex >= infoPtr->uNumTools)
1041         return FALSE;
1042
1043     TRACE("index=%u\n", uIndex);
1044
1045     toolPtr = &infoPtr->tools[uIndex];
1046
1047     /* copy tool data */
1048     lpToolInfo->uFlags   = toolPtr->uFlags;
1049     lpToolInfo->hwnd     = toolPtr->hwnd;
1050     lpToolInfo->uId      = toolPtr->uId;
1051     lpToolInfo->rect     = toolPtr->rect;
1052     lpToolInfo->hinst    = toolPtr->hinst;
1053 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1054     lpToolInfo->lpszText = NULL;  /* FIXME */
1055
1056     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1057         lpToolInfo->lParam = toolPtr->lParam;
1058
1059     return TRUE;
1060 }
1061
1062
1063 static LRESULT
1064 TOOLTIPS_GetCurrentToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1065 {
1066     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1067     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1068     TTTOOL_INFO *toolPtr;
1069
1070     if (lpToolInfo == NULL)
1071         return FALSE;
1072     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1073         return FALSE;
1074
1075     if (lpToolInfo) {
1076         if (infoPtr->nCurrentTool > -1) {
1077             toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1078
1079             /* copy tool data */
1080             lpToolInfo->uFlags   = toolPtr->uFlags;
1081             lpToolInfo->rect     = toolPtr->rect;
1082             lpToolInfo->hinst    = toolPtr->hinst;
1083 /*          lpToolInfo->lpszText = toolPtr->lpszText; */
1084             lpToolInfo->lpszText = NULL;  /* FIXME */
1085
1086             if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1087                 lpToolInfo->lParam = toolPtr->lParam;
1088
1089             return TRUE;
1090         }
1091         else
1092             return FALSE;
1093     }
1094     else
1095         return (infoPtr->nCurrentTool != -1);
1096
1097     return FALSE;
1098 }
1099
1100
1101 static LRESULT
1102 TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1103 {
1104     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1105     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1106     TTTOOL_INFO *toolPtr;
1107
1108     if (lpToolInfo == NULL)
1109         return FALSE;
1110     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1111         return FALSE;
1112
1113     if (lpToolInfo) {
1114         if (infoPtr->nCurrentTool > -1) {
1115             toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1116
1117             /* copy tool data */
1118             lpToolInfo->uFlags   = toolPtr->uFlags;
1119             lpToolInfo->rect     = toolPtr->rect;
1120             lpToolInfo->hinst    = toolPtr->hinst;
1121 /*          lpToolInfo->lpszText = toolPtr->lpszText; */
1122             lpToolInfo->lpszText = NULL;  /* FIXME */
1123
1124             if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1125                 lpToolInfo->lParam = toolPtr->lParam;
1126
1127             return TRUE;
1128         }
1129         else
1130             return FALSE;
1131     }
1132     else
1133         return (infoPtr->nCurrentTool != -1);
1134
1135     return FALSE;
1136 }
1137
1138
1139 static LRESULT
1140 TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1141 {
1142     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1143
1144     switch (wParam) {
1145     case TTDT_RESHOW:
1146         return infoPtr->nReshowTime;
1147
1148     case TTDT_AUTOPOP:
1149         return infoPtr->nAutoPopTime;
1150
1151     case TTDT_INITIAL:
1152     case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
1153         return infoPtr->nInitialTime;
1154
1155     default:
1156         WARN("Invalid wParam %x\n", wParam);
1157         break;
1158     }
1159
1160     return -1;
1161 }
1162
1163
1164 static LRESULT
1165 TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1166 {
1167     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1168     LPRECT lpRect = (LPRECT)lParam;
1169
1170     lpRect->left   = infoPtr->rcMargin.left;
1171     lpRect->right  = infoPtr->rcMargin.right;
1172     lpRect->bottom = infoPtr->rcMargin.bottom;
1173     lpRect->top    = infoPtr->rcMargin.top;
1174
1175     return 0;
1176 }
1177
1178
1179 inline static LRESULT
1180 TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1181 {
1182     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1183
1184     return infoPtr->nMaxTipWidth;
1185 }
1186
1187
1188 static LRESULT
1189 TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1190 {
1191     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1192     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1193     INT nTool;
1194
1195     if (lpToolInfo == NULL)
1196         return 0;
1197     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1198         return 0;
1199
1200     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1201     if (nTool == -1) return 0;
1202
1203     /* NB this API is broken, there is no way for the app to determine
1204        what size buffer it requires nor a way to specify how long the
1205        one it supplies is.  We'll assume it's upto INFOTIPSIZE */
1206
1207     WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1,
1208                         lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL);
1209
1210     return 0;
1211 }
1212
1213
1214 static LRESULT
1215 TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1216 {
1217     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1218     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1219     INT nTool;
1220
1221     if (lpToolInfo == NULL)
1222         return 0;
1223     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1224         return 0;
1225
1226     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1227     if (nTool == -1) return 0;
1228
1229     lstrcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText);
1230
1231     return 0;
1232 }
1233
1234
1235 inline static LRESULT
1236 TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1237 {
1238     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1239     return infoPtr->clrBk;
1240 }
1241
1242
1243 inline static LRESULT
1244 TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1245 {
1246     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1247     return infoPtr->clrText;
1248 }
1249
1250
1251 inline static LRESULT
1252 TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1253 {
1254     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1255     return infoPtr->uNumTools;
1256 }
1257
1258
1259 static LRESULT
1260 TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1261 {
1262     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1263     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1264     TTTOOL_INFO *toolPtr;
1265     INT nTool;
1266
1267     if (lpToolInfo == NULL)
1268         return FALSE;
1269     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1270         return FALSE;
1271     if (infoPtr->uNumTools == 0)
1272         return FALSE;
1273
1274     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1275     if (nTool == -1)
1276         return FALSE;
1277
1278     TRACE("tool %d\n", nTool);
1279
1280     toolPtr = &infoPtr->tools[nTool];
1281
1282     /* copy tool data */
1283     lpToolInfo->uFlags   = toolPtr->uFlags;
1284     lpToolInfo->rect     = toolPtr->rect;
1285     lpToolInfo->hinst    = toolPtr->hinst;
1286 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1287     lpToolInfo->lpszText = NULL;  /* FIXME */
1288
1289     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1290         lpToolInfo->lParam = toolPtr->lParam;
1291
1292     return TRUE;
1293 }
1294
1295
1296 static LRESULT
1297 TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1298 {
1299     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1300     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1301     TTTOOL_INFO *toolPtr;
1302     INT nTool;
1303
1304     if (lpToolInfo == NULL)
1305         return FALSE;
1306     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1307         return FALSE;
1308     if (infoPtr->uNumTools == 0)
1309         return FALSE;
1310
1311     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1312     if (nTool == -1)
1313         return FALSE;
1314
1315     TRACE("tool %d\n", nTool);
1316
1317     toolPtr = &infoPtr->tools[nTool];
1318
1319     /* copy tool data */
1320     lpToolInfo->uFlags   = toolPtr->uFlags;
1321     lpToolInfo->rect     = toolPtr->rect;
1322     lpToolInfo->hinst    = toolPtr->hinst;
1323 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1324     lpToolInfo->lpszText = NULL;  /* FIXME */
1325
1326     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1327         lpToolInfo->lParam = toolPtr->lParam;
1328
1329     return TRUE;
1330 }
1331
1332
1333 static LRESULT
1334 TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1335 {
1336     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1337     LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam;
1338     TTTOOL_INFO *toolPtr;
1339     INT nTool;
1340
1341     if (lptthit == 0)
1342         return FALSE;
1343
1344     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1345     if (nTool == -1)
1346         return FALSE;
1347
1348     TRACE("tool %d!\n", nTool);
1349
1350     /* copy tool data */
1351     if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) {
1352         toolPtr = &infoPtr->tools[nTool];
1353
1354         lptthit->ti.uFlags   = toolPtr->uFlags;
1355         lptthit->ti.hwnd     = toolPtr->hwnd;
1356         lptthit->ti.uId      = toolPtr->uId;
1357         lptthit->ti.rect     = toolPtr->rect;
1358         lptthit->ti.hinst    = toolPtr->hinst;
1359 /*      lptthit->ti.lpszText = toolPtr->lpszText; */
1360         lptthit->ti.lpszText = NULL;  /* FIXME */
1361         lptthit->ti.lParam   = toolPtr->lParam;
1362     }
1363
1364     return TRUE;
1365 }
1366
1367
1368 static LRESULT
1369 TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1370 {
1371     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1372     LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam;
1373     TTTOOL_INFO *toolPtr;
1374     INT nTool;
1375
1376     if (lptthit == 0)
1377         return FALSE;
1378
1379     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1380     if (nTool == -1)
1381         return FALSE;
1382
1383     TRACE("tool %d!\n", nTool);
1384
1385     /* copy tool data */
1386     if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) {
1387         toolPtr = &infoPtr->tools[nTool];
1388
1389         lptthit->ti.uFlags   = toolPtr->uFlags;
1390         lptthit->ti.hwnd     = toolPtr->hwnd;
1391         lptthit->ti.uId      = toolPtr->uId;
1392         lptthit->ti.rect     = toolPtr->rect;
1393         lptthit->ti.hinst    = toolPtr->hinst;
1394 /*      lptthit->ti.lpszText = toolPtr->lpszText; */
1395         lptthit->ti.lpszText = NULL;  /* FIXME */
1396         lptthit->ti.lParam   = toolPtr->lParam;
1397     }
1398
1399     return TRUE;
1400 }
1401
1402
1403 static LRESULT
1404 TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1405 {
1406     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1407     LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
1408     INT nTool;
1409
1410     if (lpti == NULL)
1411         return 0;
1412     if (lpti->cbSize < TTTOOLINFO_V1_SIZEA)
1413         return FALSE;
1414
1415     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
1416     if (nTool == -1) return 0;
1417
1418     infoPtr->tools[nTool].rect = lpti->rect;
1419
1420     return 0;
1421 }
1422
1423
1424 static LRESULT
1425 TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1426 {
1427     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1428     LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam;
1429     INT nTool;
1430
1431     if (lpti == NULL)
1432         return 0;
1433     if (lpti->cbSize < TTTOOLINFO_V1_SIZEW)
1434         return FALSE;
1435
1436     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti);
1437     if (nTool == -1) return 0;
1438
1439     infoPtr->tools[nTool].rect = lpti->rect;
1440
1441     return 0;
1442 }
1443
1444
1445 inline static LRESULT
1446 TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam)
1447 {
1448     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1449     TOOLTIPS_Hide (hwnd, infoPtr);
1450
1451     return 0;
1452 }
1453
1454
1455 static LRESULT
1456 TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam)
1457 {
1458     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1459     LPMSG lpMsg = (LPMSG)lParam;
1460     POINT pt;
1461     INT nOldTool;
1462
1463     if (lParam == 0) {
1464         ERR("lpMsg == NULL!\n");
1465         return 0;
1466     }
1467
1468     switch (lpMsg->message) {
1469         case WM_LBUTTONDOWN:
1470         case WM_LBUTTONUP:
1471         case WM_MBUTTONDOWN:
1472         case WM_MBUTTONUP:
1473         case WM_RBUTTONDOWN:
1474         case WM_RBUTTONUP:
1475             pt.x = LOWORD(lParam);
1476             pt.y = HIWORD(lParam);
1477             infoPtr->nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lpMsg->hwnd, &pt);
1478             TRACE("tool (%x) %d %d\n",
1479                    hwnd, infoPtr->nTool, infoPtr->nCurrentTool);
1480             TOOLTIPS_Hide (hwnd, infoPtr);
1481             break;
1482
1483         case WM_MOUSEMOVE:
1484             pt.x = LOWORD(lpMsg->lParam);
1485             pt.y = HIWORD(lpMsg->lParam);
1486             nOldTool = infoPtr->nTool;
1487             infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
1488                                                        &pt);
1489             TRACE("tool (%x) %d %d %d\n", hwnd, nOldTool,
1490                   infoPtr->nTool, infoPtr->nCurrentTool);
1491             TRACE("WM_MOUSEMOVE (%04x %ld %ld)\n", hwnd, pt.x, pt.y);
1492
1493             if (infoPtr->nTool != nOldTool) {
1494                 if(infoPtr->nTool == -1) { /* Moved out of all tools */
1495                     TOOLTIPS_Hide(hwnd, infoPtr);
1496                     KillTimer(hwnd, ID_TIMERLEAVE);
1497                 } else if (nOldTool == -1) { /* Moved from outside */
1498                     if(infoPtr->bActive) {
1499                         SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1500                         TRACE("timer 1 started!\n");
1501                     }
1502                 } else { /* Moved from one to another */
1503                     TOOLTIPS_Hide (hwnd, infoPtr);
1504                     KillTimer(hwnd, ID_TIMERLEAVE);
1505                     if(infoPtr->bActive) {
1506                         SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1507                         TRACE("timer 1 started!\n");
1508                     }
1509                 }
1510             } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1511                 KillTimer(hwnd, ID_TIMERPOP);
1512                 SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1513                 TRACE("timer 2 restarted\n");
1514             }
1515             break;
1516     }
1517
1518     return 0;
1519 }
1520
1521
1522 static LRESULT
1523 TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1524 {
1525     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1526     INT nTime = (INT)LOWORD(lParam);
1527
1528     switch (wParam) {
1529     case TTDT_AUTOMATIC:
1530         if (nTime <= 0)
1531             nTime = GetDoubleClickTime();
1532         infoPtr->nReshowTime    = nTime / 5;
1533         infoPtr->nAutoPopTime   = nTime * 10;
1534         infoPtr->nInitialTime   = nTime;
1535         break;
1536
1537     case TTDT_RESHOW:
1538         if(nTime < 0)
1539             nTime = GetDoubleClickTime() / 5;
1540         infoPtr->nReshowTime = nTime;
1541         break;
1542
1543     case TTDT_AUTOPOP:
1544         if(nTime < 0)
1545             nTime = GetDoubleClickTime() * 10;
1546         infoPtr->nAutoPopTime = nTime;
1547         break;
1548
1549     case TTDT_INITIAL:
1550         if(nTime < 0)
1551             nTime = GetDoubleClickTime();
1552         infoPtr->nInitialTime = nTime;
1553             break;
1554
1555     default:
1556         WARN("Invalid wParam %x\n", wParam);
1557         break;
1558     }
1559
1560     return 0;
1561 }
1562
1563
1564 static LRESULT
1565 TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1566 {
1567     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1568     LPRECT lpRect = (LPRECT)lParam;
1569
1570     infoPtr->rcMargin.left   = lpRect->left;
1571     infoPtr->rcMargin.right  = lpRect->right;
1572     infoPtr->rcMargin.bottom = lpRect->bottom;
1573     infoPtr->rcMargin.top    = lpRect->top;
1574
1575     return 0;
1576 }
1577
1578
1579 inline static LRESULT
1580 TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1581 {
1582     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1583     INT nTemp = infoPtr->nMaxTipWidth;
1584
1585     infoPtr->nMaxTipWidth = (INT)lParam;
1586
1587     return nTemp;
1588 }
1589
1590
1591 inline static LRESULT
1592 TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1593 {
1594     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1595
1596     infoPtr->clrBk = (COLORREF)wParam;
1597
1598     return 0;
1599 }
1600
1601
1602 inline static LRESULT
1603 TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1604 {
1605     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1606
1607     infoPtr->clrText = (COLORREF)wParam;
1608
1609     return 0;
1610 }
1611
1612
1613 static LRESULT
1614 TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1615 {
1616     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1617     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1618     TTTOOL_INFO *toolPtr;
1619     INT nTool;
1620
1621     if (lpToolInfo == NULL)
1622         return 0;
1623     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1624         return 0;
1625
1626     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1627     if (nTool == -1) return 0;
1628
1629     TRACE("tool %d\n", nTool);
1630
1631     toolPtr = &infoPtr->tools[nTool];
1632
1633     /* copy tool data */
1634     toolPtr->uFlags = lpToolInfo->uFlags;
1635     toolPtr->hwnd   = lpToolInfo->hwnd;
1636     toolPtr->uId    = lpToolInfo->uId;
1637     toolPtr->rect   = lpToolInfo->rect;
1638     toolPtr->hinst  = lpToolInfo->hinst;
1639
1640     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)) {
1641         TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
1642         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
1643     }
1644     else if (lpToolInfo->lpszText) {
1645         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
1646             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1647         else {
1648             if ( (toolPtr->lpszText) &&
1649                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1650                 COMCTL32_Free (toolPtr->lpszText);
1651                 toolPtr->lpszText = NULL;
1652             }
1653             if (lpToolInfo->lpszText) {
1654                 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
1655                                               -1, NULL, 0);
1656                 toolPtr->lpszText = COMCTL32_Alloc (len * sizeof(WCHAR));
1657                 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
1658                                     toolPtr->lpszText, len);
1659             }
1660         }
1661     }
1662
1663     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1664         toolPtr->lParam = lpToolInfo->lParam;
1665
1666     return 0;
1667 }
1668
1669
1670 static LRESULT
1671 TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1672 {
1673     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1674     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1675     TTTOOL_INFO *toolPtr;
1676     INT nTool;
1677
1678     if (lpToolInfo == NULL)
1679         return 0;
1680     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1681         return 0;
1682
1683     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1684     if (nTool == -1) return 0;
1685
1686     TRACE("tool %d\n", nTool);
1687
1688     toolPtr = &infoPtr->tools[nTool];
1689
1690     /* copy tool data */
1691     toolPtr->uFlags = lpToolInfo->uFlags;
1692     toolPtr->hwnd   = lpToolInfo->hwnd;
1693     toolPtr->uId    = lpToolInfo->uId;
1694     toolPtr->rect   = lpToolInfo->rect;
1695     toolPtr->hinst  = lpToolInfo->hinst;
1696
1697     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)) {
1698         TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
1699         toolPtr->lpszText = lpToolInfo->lpszText;
1700     }
1701     else if (lpToolInfo->lpszText) {
1702         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
1703             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1704         else {
1705             if ( (toolPtr->lpszText) &&
1706                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1707                 COMCTL32_Free (toolPtr->lpszText);
1708                 toolPtr->lpszText = NULL;
1709             }
1710             if (lpToolInfo->lpszText) {
1711                 INT len = lstrlenW (lpToolInfo->lpszText);
1712                 toolPtr->lpszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1713                 lstrcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
1714             }
1715         }
1716     }
1717
1718     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1719         toolPtr->lParam = lpToolInfo->lParam;
1720
1721     return 0;
1722 }
1723
1724
1725 static LRESULT
1726 TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
1727 {
1728     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1729     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1730
1731     if (lpToolInfo == NULL)
1732         return 0;
1733     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1734         return FALSE;
1735
1736     if ((BOOL)wParam) {
1737         /* activate */
1738         infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1739         if (infoPtr->nTrackTool != -1) {
1740             TRACE("activated!\n");
1741             infoPtr->bTrackActive = TRUE;
1742             TOOLTIPS_TrackShow (hwnd, infoPtr);
1743         }
1744     }
1745     else {
1746         /* deactivate */
1747         TOOLTIPS_TrackHide (hwnd, infoPtr);
1748
1749         infoPtr->bTrackActive = FALSE;
1750         infoPtr->nTrackTool = -1;
1751
1752         TRACE("deactivated!\n");
1753     }
1754
1755     return 0;
1756 }
1757
1758
1759 static LRESULT
1760 TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam)
1761 {
1762     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1763
1764     infoPtr->xTrackPos = (INT)LOWORD(lParam);
1765     infoPtr->yTrackPos = (INT)HIWORD(lParam);
1766
1767     if (infoPtr->bTrackActive) {
1768         TRACE("[%d %d]\n",
1769                infoPtr->xTrackPos, infoPtr->yTrackPos);
1770
1771         TOOLTIPS_TrackShow (hwnd, infoPtr);
1772     }
1773
1774     return 0;
1775 }
1776
1777
1778 static LRESULT
1779 TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam)
1780 {
1781     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1782
1783     if (infoPtr->nCurrentTool != -1)
1784         UpdateWindow (hwnd);
1785
1786     return 0;
1787 }
1788
1789
1790 static LRESULT
1791 TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1792 {
1793     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1794     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1795     TTTOOL_INFO *toolPtr;
1796     INT nTool;
1797
1798     if (lpToolInfo == NULL)
1799         return 0;
1800     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEA)
1801         return FALSE;
1802
1803     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1804     if (nTool == -1) return 0;
1805
1806     TRACE("tool %d\n", nTool);
1807
1808     toolPtr = &infoPtr->tools[nTool];
1809
1810     /* copy tool text */
1811     toolPtr->hinst  = lpToolInfo->hinst;
1812
1813     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)){
1814         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
1815     }
1816     else if (lpToolInfo->lpszText) {
1817         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
1818             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1819         else {
1820             if ( (toolPtr->lpszText) &&
1821                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1822                 COMCTL32_Free (toolPtr->lpszText);
1823                 toolPtr->lpszText = NULL;
1824             }
1825             if (lpToolInfo->lpszText) {
1826                 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
1827                                               -1, NULL, 0);
1828                 toolPtr->lpszText = COMCTL32_Alloc (len * sizeof(WCHAR));
1829                 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
1830                                     toolPtr->lpszText, len);
1831             }
1832         }
1833     }
1834
1835     /* force repaint */
1836     if (infoPtr->bActive)
1837         TOOLTIPS_Show (hwnd, infoPtr);
1838     else if (infoPtr->bTrackActive)
1839         TOOLTIPS_TrackShow (hwnd, infoPtr);
1840
1841     return 0;
1842 }
1843
1844
1845 static LRESULT
1846 TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1847 {
1848     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1849     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1850     TTTOOL_INFO *toolPtr;
1851     INT nTool;
1852
1853     if (lpToolInfo == NULL)
1854         return 0;
1855     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZEW)
1856         return FALSE;
1857
1858     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1859     if (nTool == -1)
1860         return 0;
1861
1862     TRACE("tool %d\n", nTool);
1863
1864     toolPtr = &infoPtr->tools[nTool];
1865
1866     /* copy tool text */
1867     toolPtr->hinst  = lpToolInfo->hinst;
1868
1869     if ((lpToolInfo->hinst) && (HIWORD((INT)lpToolInfo->lpszText) == 0)){
1870         toolPtr->lpszText = lpToolInfo->lpszText;
1871     }
1872     else if (lpToolInfo->lpszText) {
1873         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
1874             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1875         else {
1876             if ( (toolPtr->lpszText)  &&
1877                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
1878                 COMCTL32_Free (toolPtr->lpszText);
1879                 toolPtr->lpszText = NULL;
1880             }
1881             if (lpToolInfo->lpszText) {
1882                 INT len = lstrlenW (lpToolInfo->lpszText);
1883                 toolPtr->lpszText = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1884                 lstrcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
1885             }
1886         }
1887     }
1888
1889     /* force repaint */
1890     if (infoPtr->bActive)
1891         TOOLTIPS_Show (hwnd, infoPtr);
1892     else if (infoPtr->bTrackActive)
1893         TOOLTIPS_TrackShow (hwnd, infoPtr);
1894
1895     return 0;
1896 }
1897
1898
1899 static LRESULT
1900 TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam)
1901 {
1902     return WindowFromPoint (*((LPPOINT)lParam));
1903 }
1904
1905
1906
1907 static LRESULT
1908 TOOLTIPS_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1909 {
1910     TOOLTIPS_INFO *infoPtr;
1911     NONCLIENTMETRICSA nclm;
1912     INT nResult;
1913
1914     /* allocate memory for info structure */
1915     infoPtr = (TOOLTIPS_INFO *)COMCTL32_Alloc (sizeof(TOOLTIPS_INFO));
1916     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
1917
1918     /* initialize info structure */
1919     infoPtr->bActive = TRUE;
1920     infoPtr->bTrackActive = FALSE;
1921     infoPtr->clrBk   = GetSysColor (COLOR_INFOBK);
1922     infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);
1923
1924     nclm.cbSize = sizeof(NONCLIENTMETRICSA);
1925     SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
1926     infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont);
1927
1928     infoPtr->nMaxTipWidth = -1;
1929     infoPtr->nTool = -1;
1930     infoPtr->nCurrentTool = -1;
1931     infoPtr->nTrackTool = -1;
1932
1933     TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L);
1934
1935     nResult = (INT) SendMessageA (GetParent (hwnd), WM_NOTIFYFORMAT,
1936                                   (WPARAM)hwnd, (LPARAM)NF_QUERY);
1937     if (nResult == NFR_ANSI) {
1938         infoPtr->bNotifyUnicode = FALSE;
1939         TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
1940     }
1941     else if (nResult == NFR_UNICODE) {
1942         infoPtr->bNotifyUnicode = TRUE;
1943         TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
1944     }
1945     else {
1946         ERR (" -- WM_NOTIFYFORMAT returns: error!\n");
1947     }
1948
1949     SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
1950
1951     return 0;
1952 }
1953
1954
1955 static LRESULT
1956 TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1957 {
1958     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1959     TTTOOL_INFO *toolPtr;
1960     INT i;
1961
1962     /* free tools */
1963     if (infoPtr->tools) {
1964         for (i = 0; i < infoPtr->uNumTools; i++) {
1965             toolPtr = &infoPtr->tools[i];
1966             if ((toolPtr->hinst) && (toolPtr->lpszText)) {
1967                 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
1968                      (HIWORD((INT)toolPtr->lpszText) != 0) ) 
1969                 {
1970                     COMCTL32_Free (toolPtr->lpszText);
1971                     toolPtr->lpszText = NULL;
1972                 }
1973             }
1974
1975             /* remove subclassing */
1976         if (toolPtr->uFlags & TTF_SUBCLASS) {
1977             LPTT_SUBCLASS_INFO lpttsi;
1978     
1979             if (toolPtr->uFlags & TTF_IDISHWND) {
1980                 lpttsi = (LPTT_SUBCLASS_INFO)GetPropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
1981                 if (lpttsi) {
1982                     SetWindowLongA ((HWND)toolPtr->uId, GWL_WNDPROC,
1983                               (LONG)lpttsi->wpOrigProc);
1984                     RemovePropA ((HWND)toolPtr->uId, COMCTL32_aSubclass);
1985                     COMCTL32_Free (&lpttsi);
1986                 }
1987             }
1988             else {
1989                 lpttsi = (LPTT_SUBCLASS_INFO)GetPropA (toolPtr->hwnd, COMCTL32_aSubclass);
1990                 if (lpttsi) {
1991                     SetWindowLongA ((HWND)toolPtr->hwnd, GWL_WNDPROC,
1992                                (LONG)lpttsi->wpOrigProc);
1993                     RemovePropA ((HWND)toolPtr->hwnd, COMCTL32_aSubclass);
1994                     COMCTL32_Free (&lpttsi);
1995                 }
1996             }
1997         }
1998     }
1999         COMCTL32_Free (infoPtr->tools);
2000     }
2001
2002     /* delete font */
2003     DeleteObject (infoPtr->hFont);
2004
2005     /* free tool tips info data */
2006     COMCTL32_Free (infoPtr);
2007     SetWindowLongA(hwnd, 0, 0);
2008     return 0;
2009 }
2010
2011
2012 static LRESULT
2013 TOOLTIPS_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
2014 {
2015     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2016     RECT rect;
2017     HBRUSH hBrush;
2018
2019     hBrush = CreateSolidBrush (infoPtr->clrBk);
2020     GetClientRect (hwnd, &rect);
2021     FillRect ((HDC)wParam, &rect, hBrush);
2022     DeleteObject (hBrush);
2023
2024     return FALSE;
2025 }
2026
2027
2028 static LRESULT
2029 TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2030 {
2031     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2032
2033     return infoPtr->hFont;
2034 }
2035
2036
2037 static LRESULT
2038 TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2039 {
2040     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2041
2042     TOOLTIPS_Hide (hwnd, infoPtr);
2043
2044     return 0;
2045 }
2046
2047
2048 static LRESULT
2049 TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
2050 {
2051     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2052
2053     dwStyle &= 0x0000FFFF;
2054     dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
2055     SetWindowLongA (hwnd, GWL_STYLE, dwStyle);
2056
2057     return TRUE;
2058 }
2059
2060
2061 static LRESULT
2062 TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
2063 {
2064     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2065     INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
2066
2067     TRACE(" nTool=%d\n", nTool);
2068
2069     if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
2070         if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
2071             TRACE("-- in transparent mode!\n");
2072             return HTTRANSPARENT;
2073         }
2074     }
2075
2076     return DefWindowProcA (hwnd, WM_NCHITTEST, wParam, lParam);
2077 }
2078
2079
2080 static LRESULT
2081 TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
2082 {
2083     FIXME ("hwnd=%x wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2084
2085     return 0;
2086 }
2087
2088
2089 static LRESULT
2090 TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2091 {
2092     HDC hdc;
2093     PAINTSTRUCT ps;
2094
2095     hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2096     TOOLTIPS_Refresh (hwnd, hdc);
2097     if (!wParam)
2098         EndPaint (hwnd, &ps);
2099     return 0;
2100 }
2101
2102
2103 static LRESULT
2104 TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2105 {
2106     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2107
2108     infoPtr->hFont = (HFONT)wParam;
2109
2110     if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
2111         FIXME("full redraw needed!\n");
2112     }
2113
2114     return 0;
2115 }
2116 /******************************************************************
2117  * TOOLTIPS_OnWMGetTextLength
2118  *
2119  * This function is called when the tooltip receive a
2120  * WM_GETTEXTLENGTH message.
2121  * wParam : not used
2122  * lParam : not used
2123  *
2124  * returns the length, in characters, of the tip text
2125  ******************************************************************/
2126 static LRESULT
2127 TOOLTIPS_OnWMGetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam)
2128 {
2129     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2130     return lstrlenW(infoPtr->szTipText);
2131 }
2132
2133 /******************************************************************
2134  * TOOLTIPS_OnWMGetText
2135  *
2136  * This function is called when the tooltip receive a
2137  * WM_GETTEXT message.
2138  * wParam : specifies the maximum number of characters to be copied
2139  * lParam : is the pointer to the buffer that will receive
2140  *          the tip text
2141  *
2142  * returns the number of characters copied
2143  ******************************************************************/
2144 static LRESULT
2145 TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
2146 {
2147     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2148
2149     if(!infoPtr || !(infoPtr->szTipText))
2150         return 0;
2151
2152     return WideCharToMultiByte(CP_ACP, 0, infoPtr->szTipText, -1,
2153                                (LPSTR)lParam, wParam, NULL, NULL);
2154 }
2155
2156 static LRESULT
2157 TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
2158 {
2159     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2160     INT nOldTool;
2161
2162     TRACE("timer %d (%x) expired!\n", wParam, hwnd);
2163
2164     switch (wParam) {
2165     case ID_TIMERSHOW:
2166         KillTimer (hwnd, ID_TIMERSHOW);
2167         nOldTool = infoPtr->nTool;
2168         if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool)
2169             TOOLTIPS_Show (hwnd, infoPtr);
2170         break;
2171
2172     case ID_TIMERPOP:
2173         TOOLTIPS_Hide (hwnd, infoPtr);
2174         break;
2175
2176     case ID_TIMERLEAVE:
2177         nOldTool = infoPtr->nTool;
2178         infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE);
2179         TRACE("tool (%x) %d %d %d\n", hwnd, nOldTool,
2180               infoPtr->nTool, infoPtr->nCurrentTool);
2181         if (infoPtr->nTool != nOldTool) {
2182             if(infoPtr->nTool == -1) { /* Moved out of all tools */
2183                 TOOLTIPS_Hide(hwnd, infoPtr);
2184                 KillTimer(hwnd, ID_TIMERLEAVE);
2185             } else if (nOldTool == -1) { /* Moved from outside */
2186                 ERR("How did this happen?\n");
2187             } else { /* Moved from one to another */
2188                 TOOLTIPS_Hide (hwnd, infoPtr);
2189                 KillTimer(hwnd, ID_TIMERLEAVE);
2190                 if(infoPtr->bActive) {
2191                     SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
2192                     TRACE("timer 1 started!\n");
2193                 }
2194             }
2195         }
2196         break;
2197
2198     default:
2199         ERR("Unknown timer id %d\n", wParam);
2200         break;
2201     }
2202     return 0;
2203 }
2204
2205
2206 static LRESULT
2207 TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam)
2208 {
2209     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2210     NONCLIENTMETRICSA nclm;
2211
2212     infoPtr->clrBk   = GetSysColor (COLOR_INFOBK);
2213     infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);
2214
2215     DeleteObject (infoPtr->hFont);
2216     nclm.cbSize = sizeof(NONCLIENTMETRICSA);
2217     SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
2218     infoPtr->hFont = CreateFontIndirectA (&nclm.lfStatusFont);
2219
2220     return 0;
2221 }
2222
2223
2224 LRESULT CALLBACK
2225 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2226 {
2227     LPTT_SUBCLASS_INFO lpttsi =
2228         (LPTT_SUBCLASS_INFO)GetPropA (hwnd, COMCTL32_aSubclass);
2229     MSG msg;
2230
2231     switch(uMsg) {
2232     case WM_MOUSEMOVE:
2233     case WM_LBUTTONDOWN:
2234     case WM_LBUTTONUP:
2235     case WM_MBUTTONDOWN:
2236     case WM_MBUTTONUP:
2237     case WM_RBUTTONDOWN:
2238     case WM_RBUTTONUP:
2239         msg.hwnd = hwnd;
2240         msg.message = uMsg;
2241         msg.wParam = wParam;
2242         msg.lParam = lParam;
2243         TOOLTIPS_RelayEvent(lpttsi->hwndToolTip, 0, (LPARAM)&msg);
2244         break;
2245
2246     default:
2247         break;
2248     }
2249     return CallWindowProcA (lpttsi->wpOrigProc, hwnd, uMsg, wParam, lParam);
2250 }
2251
2252
2253 static LRESULT CALLBACK
2254 TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2255 {
2256     TRACE("hwnd=%x msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2257     if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2258         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2259     switch (uMsg)
2260     {
2261         case TTM_ACTIVATE:
2262             return TOOLTIPS_Activate (hwnd, wParam, lParam);
2263
2264         case TTM_ADDTOOLA:
2265             return TOOLTIPS_AddToolA (hwnd, wParam, lParam);
2266
2267         case TTM_ADDTOOLW:
2268             return TOOLTIPS_AddToolW (hwnd, wParam, lParam);
2269
2270         case TTM_DELTOOLA:
2271             return TOOLTIPS_DelToolA (hwnd, wParam, lParam);
2272
2273         case TTM_DELTOOLW:
2274             return TOOLTIPS_DelToolW (hwnd, wParam, lParam);
2275
2276         case TTM_ENUMTOOLSA:
2277             return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam);
2278
2279         case TTM_ENUMTOOLSW:
2280             return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam);
2281
2282         case TTM_GETCURRENTTOOLA:
2283             return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam);
2284
2285         case TTM_GETCURRENTTOOLW:
2286             return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam);
2287
2288         case TTM_GETDELAYTIME:
2289             return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam);
2290
2291         case TTM_GETMARGIN:
2292             return TOOLTIPS_GetMargin (hwnd, wParam, lParam);
2293
2294         case TTM_GETMAXTIPWIDTH:
2295             return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam);
2296
2297         case TTM_GETTEXTA:
2298             return TOOLTIPS_GetTextA (hwnd, wParam, lParam);
2299
2300         case TTM_GETTEXTW:
2301             return TOOLTIPS_GetTextW (hwnd, wParam, lParam);
2302
2303         case TTM_GETTIPBKCOLOR:
2304             return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam);
2305
2306         case TTM_GETTIPTEXTCOLOR:
2307             return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam);
2308
2309         case TTM_GETTOOLCOUNT:
2310             return TOOLTIPS_GetToolCount (hwnd, wParam, lParam);
2311
2312         case TTM_GETTOOLINFOA:
2313             return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam);
2314
2315         case TTM_GETTOOLINFOW:
2316             return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam);
2317
2318         case TTM_HITTESTA:
2319             return TOOLTIPS_HitTestA (hwnd, wParam, lParam);
2320
2321         case TTM_HITTESTW:
2322             return TOOLTIPS_HitTestW (hwnd, wParam, lParam);
2323
2324         case TTM_NEWTOOLRECTA:
2325             return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam);
2326
2327         case TTM_NEWTOOLRECTW:
2328             return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam);
2329
2330         case TTM_POP:
2331             return TOOLTIPS_Pop (hwnd, wParam, lParam);
2332
2333         case TTM_RELAYEVENT:
2334             return TOOLTIPS_RelayEvent (hwnd, wParam, lParam);
2335
2336         case TTM_SETDELAYTIME:
2337             return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam);
2338
2339         case TTM_SETMARGIN:
2340             return TOOLTIPS_SetMargin (hwnd, wParam, lParam);
2341
2342         case TTM_SETMAXTIPWIDTH:
2343             return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam);
2344
2345         case TTM_SETTIPBKCOLOR:
2346             return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam);
2347
2348         case TTM_SETTIPTEXTCOLOR:
2349             return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam);
2350
2351         case TTM_SETTOOLINFOA:
2352             return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam);
2353
2354         case TTM_SETTOOLINFOW:
2355             return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam);
2356
2357         case TTM_TRACKACTIVATE:
2358             return TOOLTIPS_TrackActivate (hwnd, wParam, lParam);
2359
2360         case TTM_TRACKPOSITION:
2361             return TOOLTIPS_TrackPosition (hwnd, wParam, lParam);
2362
2363         case TTM_UPDATE:
2364             return TOOLTIPS_Update (hwnd, wParam, lParam);
2365
2366         case TTM_UPDATETIPTEXTA:
2367             return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam);
2368
2369         case TTM_UPDATETIPTEXTW:
2370             return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam);
2371
2372         case TTM_WINDOWFROMPOINT:
2373             return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam);
2374
2375
2376         case WM_CREATE:
2377             return TOOLTIPS_Create (hwnd, wParam, lParam);
2378
2379         case WM_DESTROY:
2380             return TOOLTIPS_Destroy (hwnd, wParam, lParam);
2381
2382         case WM_ERASEBKGND:
2383             return TOOLTIPS_EraseBackground (hwnd, wParam, lParam);
2384
2385         case WM_GETFONT:
2386             return TOOLTIPS_GetFont (hwnd, wParam, lParam);
2387
2388         case WM_GETTEXT:
2389             return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam);
2390         
2391         case WM_GETTEXTLENGTH:
2392             return TOOLTIPS_OnWMGetTextLength (hwnd, wParam, lParam);
2393  
2394
2395         case WM_LBUTTONDOWN:
2396         case WM_LBUTTONUP:
2397         case WM_MBUTTONDOWN:
2398         case WM_MBUTTONUP:
2399         case WM_RBUTTONDOWN:
2400         case WM_RBUTTONUP:
2401         case WM_MOUSEMOVE:
2402             return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam);
2403
2404         case WM_NCCREATE:
2405             return TOOLTIPS_NCCreate (hwnd, wParam, lParam);
2406
2407         case WM_NCHITTEST:
2408             return TOOLTIPS_NCHitTest (hwnd, wParam, lParam);
2409
2410         case WM_NOTIFYFORMAT:
2411             return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam);
2412
2413         case WM_PAINT:
2414             return TOOLTIPS_Paint (hwnd, wParam, lParam);
2415
2416         case WM_SETFONT:
2417             return TOOLTIPS_SetFont (hwnd, wParam, lParam);
2418
2419         case WM_TIMER:
2420             return TOOLTIPS_Timer (hwnd, wParam, lParam);
2421
2422         case WM_WININICHANGE:
2423             return TOOLTIPS_WinIniChange (hwnd, wParam, lParam);
2424
2425         default:
2426             if (uMsg >= WM_USER)
2427                 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
2428                      uMsg, wParam, lParam);
2429             return DefWindowProcA (hwnd, uMsg, wParam, lParam);
2430     }
2431     return 0;
2432 }
2433
2434
2435 VOID
2436 TOOLTIPS_Register (void)
2437 {
2438     WNDCLASSA wndClass;
2439
2440     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
2441     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2442     wndClass.lpfnWndProc   = (WNDPROC)TOOLTIPS_WindowProc;
2443     wndClass.cbClsExtra    = 0;
2444     wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2445     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
2446     wndClass.hbrBackground = 0;
2447     wndClass.lpszClassName = TOOLTIPS_CLASSA;
2448  
2449     RegisterClassA (&wndClass);
2450 }
2451
2452
2453 VOID
2454 TOOLTIPS_Unregister (void)
2455 {
2456     UnregisterClassA (TOOLTIPS_CLASSA, (HINSTANCE)NULL);
2457 }
2458