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