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