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