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