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