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