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