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