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