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