Removed W->A from DEFWND_ImmIsUIMessageW.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * This code was audited for completeness against the documented features
22  * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman.
23  * 
24  * Unless otherwise noted, we believe this code to be complete, as per
25  * the specification mentioned above.
26  * If you discover missing features or bugs please note them below.
27  * 
28  * TODO:
29  *   - Custom draw support.
30  *   - Animation.
31  *   - Links.
32  *   - Messages:
33  *     o TTM_ADJUSTRECT
34  *     o TTM_GETTITLEA
35  *     o TTM_GETTTILEW
36  *     o TTM_POPUP
37  *   - Styles:
38  *     o TTS_NOANIMATE
39  *     o TTS_NOFADE
40  *     o TTS_CLOSE
41  *
42  * Testing:
43  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
44  *     The second cdrom (chapter 3) contains executables activate.exe,
45  *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
46  *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
47  *
48  *   Timer logic.
49  *
50  * One important point to remember is that tools don't necessarily get
51  * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when
52  * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because
53  * here WM_MOUSEMOVEs only get sent when the cursor is inside the
54  * client area.  Therefore the only reliable way to know that the
55  * cursor has left a tool is to keep a timer running and check the
56  * position every time it expires.  This is the role of timer
57  * ID_TIMERLEAVE.
58  *
59  *
60  * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start
61  * ID_TIMERSHOW, if this times out and we're still in the tool we show
62  * the tip.  On showing a tip we start both ID_TIMERPOP and
63  * ID_TIMERLEAVE.  On hiding a tooltip we kill ID_TIMERPOP.
64  * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE.  If
65  * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed.
66  * ID_TIMERLEAVE remains running - this is important as we need to
67  * determine when the cursor leaves the tool.
68  *
69  * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're
70  * still in the tool do nothing (apart from restart ID_TIMERPOP if
71  * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running).  If we've
72  * left the tool and entered another one then hide the tip and start
73  * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE.  If we're
74  * outside all tools hide the tip and kill ID_TIMERLEAVE.  On Relayed
75  * mouse button messages hide the tip but leave ID_TIMERLEAVE running,
76  * this again will let us keep track of when the cursor leaves the
77  * tool.
78  *
79  *
80  * infoPtr->nTool is the tool the mouse was on on the last relayed MM
81  * or timer expiry or -1 if the mouse was not on a tool.
82  *
83  * infoPtr->nCurrentTool is the tool for which the tip is currently
84  * displaying text for or -1 if the tip is not shown.  Actually this
85  * will only ever be infoPtr-nTool or -1, so it could be changed to a
86  * BOOL.
87  *
88  */
89
90
91
92 #include <stdarg.h>
93 #include <string.h>
94
95 #include "windef.h"
96 #include "winbase.h"
97 #include "wine/unicode.h"
98 #include "wingdi.h"
99 #include "winuser.h"
100 #include "winnls.h"
101 #include "commctrl.h"
102 #include "comctl32.h"
103 #include "wine/debug.h"
104
105 WINE_DEFAULT_DEBUG_CHANNEL(tooltips);
106
107 static HICON hTooltipIcons[TTI_ERROR+1];
108
109 typedef struct
110 {
111     UINT      uFlags;
112     HWND      hwnd;
113     BOOL      bNotifyUnicode;
114     UINT      uId;
115     RECT      rect;
116     HINSTANCE hinst;
117     LPWSTR      lpszText;
118     LPARAM      lParam;
119 } TTTOOL_INFO;
120
121
122 typedef struct
123 {
124     WCHAR      szTipText[INFOTIPSIZE];
125     BOOL     bActive;
126     BOOL     bTrackActive;
127     UINT     uNumTools;
128     COLORREF   clrBk;
129     COLORREF   clrText;
130     HFONT    hFont;
131     HFONT    hTitleFont;
132     INT      xTrackPos;
133     INT      yTrackPos;
134     INT      nMaxTipWidth;
135     INT      nTool; /* tool that mouse was on on last relayed mouse move */
136     INT      nCurrentTool;
137     INT      nTrackTool;
138     INT      nReshowTime;
139     INT      nAutoPopTime;
140     INT      nInitialTime;
141     RECT     rcMargin;
142     BOOL     bToolBelow;
143     LPWSTR   pszTitle;
144     HICON    hTitleIcon;
145
146     TTTOOL_INFO *tools;
147 } TOOLTIPS_INFO;
148
149 #define ID_TIMERSHOW   1    /* show delay timer */
150 #define ID_TIMERPOP    2    /* auto pop timer */
151 #define ID_TIMERLEAVE  3    /* tool leave timer */
152
153
154 #define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0))
155
156 /* offsets from window edge to start of text */
157 #define NORMAL_TEXT_MARGIN 2
158 #define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8)
159 /* value used for CreateRoundRectRgn that specifies how much
160  * each corner is curved */
161 #define BALLOON_ROUNDEDNESS 20
162 #define BALLOON_STEMHEIGHT 13
163 #define BALLOON_STEMWIDTH 10
164 #define BALLOON_STEMINDENT 20
165
166 #define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */
167 #define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */
168 #define ICON_HEIGHT 16
169 #define ICON_WIDTH  16
170
171 static LRESULT CALLBACK
172 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef);
173
174
175 inline static UINT_PTR
176 TOOLTIPS_GetTitleIconIndex(HICON hIcon)
177 {
178     UINT i;
179     for (i = 0; i <= TTI_ERROR; i++)
180         if (hTooltipIcons[i] == hIcon)
181             return i;
182     return (UINT_PTR)hIcon;
183 }
184
185 static void
186 TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr)
187 {
188     NONCLIENTMETRICSW nclm;
189
190     infoPtr->clrBk   = GetSysColor (COLOR_INFOBK);
191     infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);
192
193     DeleteObject (infoPtr->hFont);
194     nclm.cbSize = sizeof(nclm);
195     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
196     infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont);
197
198     DeleteObject (infoPtr->hTitleFont);
199     nclm.lfStatusFont.lfWeight = FW_BOLD;
200     infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont);
201 }
202
203 static void
204 TOOLTIPS_Refresh (HWND hwnd, HDC hdc)
205 {
206     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd);
207     RECT rc;
208     INT oldBkMode;
209     HFONT hOldFont;
210     HBRUSH hBrush;
211     UINT uFlags = DT_EXTERNALLEADING;
212     HRGN hRgn = NULL;
213     DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
214
215     if (infoPtr->nMaxTipWidth > -1)
216         uFlags |= DT_WORDBREAK;
217     if (GetWindowLongA (hwnd, GWL_STYLE) & TTS_NOPREFIX)
218         uFlags |= DT_NOPREFIX;
219     GetClientRect (hwnd, &rc);
220
221     hBrush = CreateSolidBrush(infoPtr->clrBk);
222
223     oldBkMode = SetBkMode (hdc, TRANSPARENT);
224     SetTextColor (hdc, infoPtr->clrText);
225
226     if (dwStyle & TTS_BALLOON)
227     {
228         /* create a region to store result into */
229         hRgn = CreateRectRgn(0, 0, 0, 0);
230
231         GetWindowRgn(hwnd, hRgn);
232
233         /* fill the background */
234         FillRgn(hdc, hRgn, hBrush);
235         DeleteObject(hBrush);
236         hBrush = NULL;
237     }
238     else
239     {
240         /* fill the background */
241         FillRect(hdc, &rc, hBrush);
242         DeleteObject(hBrush);
243         hBrush = NULL;
244     }
245
246     if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle)
247     {
248         /* calculate text rectangle */
249         rc.left   += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left);
250         rc.top    += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top);
251         rc.right  -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right);
252         rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom);
253         if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT;
254
255         if (infoPtr->pszTitle)
256         {
257             RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom};
258             int height;
259             BOOL icon_present;
260
261             /* draw icon */
262             icon_present = infoPtr->hTitleIcon && 
263                 DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon,
264                            ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL);
265             if (icon_present)
266                 rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING;
267
268             rcTitle.bottom = rc.top + ICON_HEIGHT;
269
270             /* draw title text */
271             hOldFont = SelectObject (hdc, infoPtr->hTitleFont);
272             height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX);
273             SelectObject (hdc, hOldFont);
274             rc.top += height + BALLOON_TITLE_TEXT_SPACING;
275         }
276     }
277     else
278     {
279         /* calculate text rectangle */
280         rc.left   += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left);
281         rc.top    += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top);
282         rc.right  -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right);
283         rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom);
284     }
285
286     /* draw text */
287     hOldFont = SelectObject (hdc, infoPtr->hFont);
288     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
289     /* be polite and reset the things we changed in the dc */
290     SelectObject (hdc, hOldFont);
291     SetBkMode (hdc, oldBkMode);
292
293     if (dwStyle & TTS_BALLOON)
294     {
295         /* frame region because default window proc doesn't do it */
296         INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
297         INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
298
299         hBrush = GetSysColorBrush(COLOR_WINDOWFRAME);
300         FrameRgn(hdc, hRgn, hBrush, width, height);
301     }
302
303     if (hRgn)
304         DeleteObject(hRgn);
305 }
306
307 static void TOOLTIPS_GetDispInfoA(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
308 {
309     NMTTDISPINFOA ttnmdi;
310
311     /* fill NMHDR struct */
312     ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
313     ttnmdi.hdr.hwndFrom = hwnd;
314     ttnmdi.hdr.idFrom = toolPtr->uId;
315     ttnmdi.hdr.code = TTN_GETDISPINFOA;
316     ttnmdi.lpszText = (LPSTR)&ttnmdi.szText;
317     ttnmdi.uFlags = toolPtr->uFlags;
318     ttnmdi.lParam = toolPtr->lParam;
319
320     TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
321     SendMessageW(toolPtr->hwnd, WM_NOTIFY,
322                  (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi);
323
324     if (HIWORD((UINT)ttnmdi.lpszText) == 0) {
325         LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText,
326                infoPtr->szTipText, INFOTIPSIZE);
327         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
328             toolPtr->hinst = ttnmdi.hinst;
329             toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText;
330         }
331     }
332     else if (ttnmdi.lpszText == 0) {
333         /* no text available */
334         infoPtr->szTipText[0] = '\0';
335     }
336     else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
337         INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? 
338                 sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : -1;
339         MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, max_len,
340                             infoPtr->szTipText, INFOTIPSIZE);
341         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
342             INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText,
343                                           max_len, NULL, 0);
344             toolPtr->hinst = 0;
345             toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
346             MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1,
347                                 toolPtr->lpszText, len);
348         }
349     }
350     else {
351         ERR("recursive text callback!\n");
352         infoPtr->szTipText[0] = '\0';
353     }
354 }
355
356 static void TOOLTIPS_GetDispInfoW(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
357 {
358     NMTTDISPINFOW ttnmdi;
359
360     /* fill NMHDR struct */
361     ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW));
362     ttnmdi.hdr.hwndFrom = hwnd;
363     ttnmdi.hdr.idFrom = toolPtr->uId;
364     ttnmdi.hdr.code = TTN_GETDISPINFOW;
365     ttnmdi.lpszText = (LPWSTR)&ttnmdi.szText;
366     ttnmdi.uFlags = toolPtr->uFlags;
367     ttnmdi.lParam = toolPtr->lParam;
368
369     TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
370     SendMessageW(toolPtr->hwnd, WM_NOTIFY,
371                  (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi);
372
373     if (HIWORD((UINT)ttnmdi.lpszText) == 0) {
374         LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText,
375                infoPtr->szTipText, INFOTIPSIZE);
376         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
377             toolPtr->hinst = ttnmdi.hinst;
378             toolPtr->lpszText = ttnmdi.lpszText;
379         }
380     }
381     else if (ttnmdi.lpszText == 0) {
382         /* no text available */
383         infoPtr->szTipText[0] = '\0';
384     }
385     else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
386         INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? 
387                 sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : INFOTIPSIZE-1;
388         strncpyW(infoPtr->szTipText, ttnmdi.lpszText, max_len);
389         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
390             INT len = max(strlenW(ttnmdi.lpszText), max_len);
391             toolPtr->hinst = 0;
392             toolPtr->lpszText = Alloc ((len+1) * sizeof(WCHAR));
393             memcpy(toolPtr->lpszText, ttnmdi.lpszText, (len+1) * sizeof(WCHAR));
394         }
395     }
396     else {
397         ERR("recursive text callback!\n");
398         infoPtr->szTipText[0] = '\0';
399     }
400 }
401
402 static void
403 TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool)
404 {
405     TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
406
407     if (HIWORD((UINT)toolPtr->lpszText) == 0 && toolPtr->hinst) {
408         /* load a resource */
409         TRACE("load res string %p %x\n",
410                toolPtr->hinst, (int)toolPtr->lpszText);
411         LoadStringW (toolPtr->hinst, (UINT)toolPtr->lpszText,
412                        infoPtr->szTipText, INFOTIPSIZE);
413     }
414     else if (toolPtr->lpszText) {
415         if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) {
416             if (toolPtr->bNotifyUnicode)
417                 TOOLTIPS_GetDispInfoW(hwnd, infoPtr, toolPtr);
418             else
419                 TOOLTIPS_GetDispInfoA(hwnd, infoPtr, toolPtr);
420         }
421         else {
422             /* the item is a usual (unicode) text */
423             lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
424         }
425     }
426     else {
427         /* no text available */
428         infoPtr->szTipText[0] = L'\0';
429     }
430
431     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
432 }
433
434
435 static void
436 TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
437 {
438     HDC hdc;
439     HFONT hOldFont;
440     DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
441     UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
442     RECT rc = {0, 0, 0, 0};
443     SIZE title = {0, 0};
444
445     if (infoPtr->nMaxTipWidth > -1) {
446         rc.right = infoPtr->nMaxTipWidth;
447         uFlags |= DT_WORDBREAK;
448     }
449     if (style & TTS_NOPREFIX)
450         uFlags |= DT_NOPREFIX;
451     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
452
453     hdc = GetDC (hwnd);
454     if (infoPtr->pszTitle)
455     {
456         RECT rcTitle = {0, 0, 0, 0};
457         TRACE("title %s\n", debugstr_w(infoPtr->pszTitle));
458         if (infoPtr->hTitleIcon)
459         {
460             title.cx = ICON_WIDTH;
461             title.cy = ICON_HEIGHT;
462         }
463         if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING;
464         hOldFont = SelectObject (hdc, infoPtr->hTitleFont);
465         DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
466         SelectObject (hdc, hOldFont);
467         title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING;
468         title.cx += (rcTitle.right - rcTitle.left);
469     }
470     hOldFont = SelectObject (hdc, infoPtr->hFont);
471     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
472     SelectObject (hdc, hOldFont);
473     ReleaseDC (hwnd, hdc);
474
475     if ((style & TTS_BALLOON) || infoPtr->pszTitle)
476     {
477         lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN +
478                        infoPtr->rcMargin.left + infoPtr->rcMargin.right;
479         lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN +
480                        infoPtr->rcMargin.bottom + infoPtr->rcMargin.top +
481                        BALLOON_STEMHEIGHT;
482     }
483     else
484     {
485         lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN +
486                        infoPtr->rcMargin.left + infoPtr->rcMargin.right;
487         lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN +
488                        infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
489     }
490 }
491
492
493 static void
494 TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr)
495 {
496     TTTOOL_INFO *toolPtr;
497     RECT rect, wndrect;
498     SIZE size;
499     NMHDR  hdr;
500     int ptfx = 0;
501     DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
502
503     if (infoPtr->nTool == -1) {
504         TRACE("invalid tool (-1)!\n");
505         return;
506     }
507
508     infoPtr->nCurrentTool = infoPtr->nTool;
509
510     TRACE("Show tooltip pre %d! (%p)\n", infoPtr->nTool, hwnd);
511
512     TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool);
513
514     if (infoPtr->szTipText[0] == L'\0') {
515         infoPtr->nCurrentTool = -1;
516         return;
517     }
518
519     TRACE("Show tooltip %d!\n", infoPtr->nCurrentTool);
520     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
521
522     hdr.hwndFrom = hwnd;
523     hdr.idFrom = toolPtr->uId;
524     hdr.code = TTN_SHOW;
525     SendMessageW (toolPtr->hwnd, WM_NOTIFY,
526                     (WPARAM)toolPtr->uId, (LPARAM)&hdr);
527
528     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
529
530     TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
531     TRACE("size %ld x %ld\n", size.cx, size.cy);
532
533     if (toolPtr->uFlags & TTF_CENTERTIP) {
534         RECT rc;
535
536         if (toolPtr->uFlags & TTF_IDISHWND)
537             GetWindowRect ((HWND)toolPtr->uId, &rc);
538         else {
539             rc = toolPtr->rect;
540             MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
541         }
542         rect.left = (rc.left + rc.right - size.cx) / 2;
543         if (style & TTS_BALLOON)
544         {
545           ptfx = rc.left + ((rc.right - rc.left) / 2);
546           if(rect.top - size.cy >= 0)
547           {
548             rect.top -= size.cy;
549             infoPtr->bToolBelow = FALSE;
550           }
551           else
552           {
553             infoPtr->bToolBelow = TRUE;
554             rect.top += 20;
555           }
556           rect.left = max(0, rect.left - BALLOON_STEMINDENT);
557         }
558         else
559         {
560           rect.top  = rc.bottom + 2;
561           infoPtr->bToolBelow = TRUE;
562         }
563     }
564     else {
565         GetCursorPos ((LPPOINT)&rect);
566         if (style & TTS_BALLOON)
567         {
568             ptfx = rect.left;
569             if(rect.top - size.cy >= 0)
570             {
571               rect.top -= size.cy;
572               infoPtr->bToolBelow = FALSE;
573             }
574             else
575             {
576               infoPtr->bToolBelow = TRUE;
577               rect.top += 20;
578             }
579             rect.left = max(0, rect.left - BALLOON_STEMINDENT);
580         }
581         else
582         {
583             rect.top += 20;
584             infoPtr->bToolBelow = TRUE;
585         }
586     }
587
588     TRACE("pos %ld - %ld\n", rect.left, rect.top);
589
590     rect.right = rect.left + size.cx;
591     rect.bottom = rect.top + size.cy;
592
593     /* check position */
594     wndrect.right = GetSystemMetrics( SM_CXSCREEN );
595     if( rect.right > wndrect.right ) {
596            rect.left -= rect.right - wndrect.right + 2;
597            rect.right = wndrect.right - 2;
598     }
599     wndrect.bottom = GetSystemMetrics( SM_CYSCREEN );
600     if( rect.bottom > wndrect.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, GetWindowLongA (hwnd, GWL_STYLE),
614                         FALSE, GetWindowLongA (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] == L'\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 %ld x %ld\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 %ld - %ld\n", rect.left, rect.top);
781
782     rect.right = rect.left + size.cx;
783     rect.bottom = rect.top + size.cy;
784
785     AdjustWindowRectEx (&rect, GetWindowLongA (hwnd, GWL_STYLE),
786                         FALSE, GetWindowLongA (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, 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 (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA 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 (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOW 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 (TOOLTIPS_INFO *infoPtr, HWND hwnd, LPPOINT 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 (!(GetWindowLongA (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 %d%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 (HIWORD(lpToolInfo->lpszText) == 0) {
1017         TRACE("add string id %x!\n", (int)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 %d%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 (HIWORD(lpToolInfo->lpszText) == 0) {
1108         TRACE("add string id %x!\n", (int)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              (HIWORD((INT)toolPtr->lpszText) != 0) )
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 %ld x %ld\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 == NULL)
1378         return FALSE;
1379     if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1380         return FALSE;
1381
1382     if (lpToolInfo) {
1383         if (infoPtr->nCurrentTool > -1) {
1384             toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1385
1386             /* copy tool data */
1387             lpToolInfo->uFlags   = toolPtr->uFlags;
1388             lpToolInfo->rect     = toolPtr->rect;
1389             lpToolInfo->hinst    = toolPtr->hinst;
1390 /*          lpToolInfo->lpszText = toolPtr->lpszText; */
1391             lpToolInfo->lpszText = NULL;  /* FIXME */
1392
1393             if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1394                 lpToolInfo->lParam = toolPtr->lParam;
1395
1396             return TRUE;
1397         }
1398         else
1399             return FALSE;
1400     }
1401     else
1402         return (infoPtr->nCurrentTool != -1);
1403
1404     return FALSE;
1405 }
1406
1407
1408 static LRESULT
1409 TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1410 {
1411     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1412     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1413     TTTOOL_INFO *toolPtr;
1414
1415     if (lpToolInfo == NULL)
1416         return FALSE;
1417     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1418         return FALSE;
1419
1420     if (lpToolInfo) {
1421         if (infoPtr->nCurrentTool > -1) {
1422             toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
1423
1424             /* copy tool data */
1425             lpToolInfo->uFlags   = toolPtr->uFlags;
1426             lpToolInfo->rect     = toolPtr->rect;
1427             lpToolInfo->hinst    = toolPtr->hinst;
1428 /*          lpToolInfo->lpszText = toolPtr->lpszText; */
1429             lpToolInfo->lpszText = NULL;  /* FIXME */
1430
1431             if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1432                 lpToolInfo->lParam = toolPtr->lParam;
1433
1434             return TRUE;
1435         }
1436         else
1437             return FALSE;
1438     }
1439     else
1440         return (infoPtr->nCurrentTool != -1);
1441
1442     return FALSE;
1443 }
1444
1445
1446 static LRESULT
1447 TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1448 {
1449     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1450
1451     switch (wParam) {
1452     case TTDT_RESHOW:
1453         return infoPtr->nReshowTime;
1454
1455     case TTDT_AUTOPOP:
1456         return infoPtr->nAutoPopTime;
1457
1458     case TTDT_INITIAL:
1459     case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
1460         return infoPtr->nInitialTime;
1461
1462     default:
1463         WARN("Invalid wParam %x\n", wParam);
1464         break;
1465     }
1466
1467     return -1;
1468 }
1469
1470
1471 static LRESULT
1472 TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1473 {
1474     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1475     LPRECT lpRect = (LPRECT)lParam;
1476
1477     lpRect->left   = infoPtr->rcMargin.left;
1478     lpRect->right  = infoPtr->rcMargin.right;
1479     lpRect->bottom = infoPtr->rcMargin.bottom;
1480     lpRect->top    = infoPtr->rcMargin.top;
1481
1482     return 0;
1483 }
1484
1485
1486 inline static LRESULT
1487 TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1488 {
1489     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1490
1491     return infoPtr->nMaxTipWidth;
1492 }
1493
1494
1495 static LRESULT
1496 TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1497 {
1498     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1499     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1500     INT nTool;
1501
1502     if (lpToolInfo == NULL)
1503         return 0;
1504     if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1505         return 0;
1506
1507     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1508     if (nTool == -1) return 0;
1509
1510     /* NB this API is broken, there is no way for the app to determine
1511        what size buffer it requires nor a way to specify how long the
1512        one it supplies is.  We'll assume it's upto INFOTIPSIZE */
1513
1514     WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1,
1515                         lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL);
1516
1517     return 0;
1518 }
1519
1520
1521 static LRESULT
1522 TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1523 {
1524     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1525     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1526     INT nTool;
1527
1528     if (lpToolInfo == NULL)
1529         return 0;
1530     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1531         return 0;
1532
1533     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1534     if (nTool == -1) return 0;
1535
1536     strcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText);
1537
1538     return 0;
1539 }
1540
1541
1542 inline static LRESULT
1543 TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1544 {
1545     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1546     return infoPtr->clrBk;
1547 }
1548
1549
1550 inline static LRESULT
1551 TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1552 {
1553     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1554     return infoPtr->clrText;
1555 }
1556
1557
1558 inline static LRESULT
1559 TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1560 {
1561     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1562     return infoPtr->uNumTools;
1563 }
1564
1565
1566 static LRESULT
1567 TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1568 {
1569     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1570     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1571     TTTOOL_INFO *toolPtr;
1572     INT nTool;
1573
1574     if (lpToolInfo == NULL)
1575         return FALSE;
1576     if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
1577         return FALSE;
1578     if (infoPtr->uNumTools == 0)
1579         return FALSE;
1580
1581     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1582     if (nTool == -1)
1583         return FALSE;
1584
1585     TRACE("tool %d\n", nTool);
1586
1587     toolPtr = &infoPtr->tools[nTool];
1588
1589     /* copy tool data */
1590     lpToolInfo->uFlags   = toolPtr->uFlags;
1591     lpToolInfo->rect     = toolPtr->rect;
1592     lpToolInfo->hinst    = toolPtr->hinst;
1593 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1594     lpToolInfo->lpszText = NULL;  /* FIXME */
1595
1596     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
1597         lpToolInfo->lParam = toolPtr->lParam;
1598
1599     return TRUE;
1600 }
1601
1602
1603 static LRESULT
1604 TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1605 {
1606     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1607     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1608     TTTOOL_INFO *toolPtr;
1609     INT nTool;
1610
1611     if (lpToolInfo == NULL)
1612         return FALSE;
1613     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1614         return FALSE;
1615     if (infoPtr->uNumTools == 0)
1616         return FALSE;
1617
1618     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
1619     if (nTool == -1)
1620         return FALSE;
1621
1622     TRACE("tool %d\n", nTool);
1623
1624     toolPtr = &infoPtr->tools[nTool];
1625
1626     /* copy tool data */
1627     lpToolInfo->uFlags   = toolPtr->uFlags;
1628     lpToolInfo->rect     = toolPtr->rect;
1629     lpToolInfo->hinst    = toolPtr->hinst;
1630 /*    lpToolInfo->lpszText = toolPtr->lpszText; */
1631     lpToolInfo->lpszText = NULL;  /* FIXME */
1632
1633     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1634         lpToolInfo->lParam = toolPtr->lParam;
1635
1636     return TRUE;
1637 }
1638
1639
1640 static LRESULT
1641 TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1642 {
1643     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1644     LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam;
1645     TTTOOL_INFO *toolPtr;
1646     INT nTool;
1647
1648     if (lptthit == 0)
1649         return FALSE;
1650
1651     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1652     if (nTool == -1)
1653         return FALSE;
1654
1655     TRACE("tool %d!\n", nTool);
1656
1657     /* copy tool data */
1658     if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) {
1659         toolPtr = &infoPtr->tools[nTool];
1660
1661         lptthit->ti.uFlags   = toolPtr->uFlags;
1662         lptthit->ti.hwnd     = toolPtr->hwnd;
1663         lptthit->ti.uId      = toolPtr->uId;
1664         lptthit->ti.rect     = toolPtr->rect;
1665         lptthit->ti.hinst    = toolPtr->hinst;
1666 /*      lptthit->ti.lpszText = toolPtr->lpszText; */
1667         lptthit->ti.lpszText = NULL;  /* FIXME */
1668         lptthit->ti.lParam   = toolPtr->lParam;
1669     }
1670
1671     return TRUE;
1672 }
1673
1674
1675 static LRESULT
1676 TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1677 {
1678     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1679     LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam;
1680     TTTOOL_INFO *toolPtr;
1681     INT nTool;
1682
1683     if (lptthit == 0)
1684         return FALSE;
1685
1686     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1687     if (nTool == -1)
1688         return FALSE;
1689
1690     TRACE("tool %d!\n", nTool);
1691
1692     /* copy tool data */
1693     if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) {
1694         toolPtr = &infoPtr->tools[nTool];
1695
1696         lptthit->ti.uFlags   = toolPtr->uFlags;
1697         lptthit->ti.hwnd     = toolPtr->hwnd;
1698         lptthit->ti.uId      = toolPtr->uId;
1699         lptthit->ti.rect     = toolPtr->rect;
1700         lptthit->ti.hinst    = toolPtr->hinst;
1701 /*      lptthit->ti.lpszText = toolPtr->lpszText; */
1702         lptthit->ti.lpszText = NULL;  /* FIXME */
1703         lptthit->ti.lParam   = toolPtr->lParam;
1704     }
1705
1706     return TRUE;
1707 }
1708
1709
1710 static LRESULT
1711 TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1712 {
1713     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1714     LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
1715     INT nTool;
1716
1717     if (lpti == NULL)
1718         return 0;
1719     if (lpti->cbSize < TTTOOLINFOA_V1_SIZE)
1720         return FALSE;
1721
1722     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
1723
1724     TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect));
1725
1726     if (nTool == -1) return 0;
1727
1728     infoPtr->tools[nTool].rect = lpti->rect;
1729
1730     return 0;
1731 }
1732
1733
1734 static LRESULT
1735 TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1736 {
1737     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1738     LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam;
1739     INT nTool;
1740
1741     if (lpti == NULL)
1742         return 0;
1743     if (lpti->cbSize < TTTOOLINFOW_V1_SIZE)
1744         return FALSE;
1745
1746     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti);
1747
1748     TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect));
1749
1750     if (nTool == -1) return 0;
1751
1752     infoPtr->tools[nTool].rect = lpti->rect;
1753
1754     return 0;
1755 }
1756
1757
1758 inline static LRESULT
1759 TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam)
1760 {
1761     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1762     TOOLTIPS_Hide (hwnd, infoPtr);
1763
1764     return 0;
1765 }
1766
1767
1768 static LRESULT
1769 TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam)
1770 {
1771     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1772     LPMSG lpMsg = (LPMSG)lParam;
1773     POINT pt;
1774     INT nOldTool;
1775
1776     if (lParam == 0) {
1777         ERR("lpMsg == NULL!\n");
1778         return 0;
1779     }
1780
1781     switch (lpMsg->message) {
1782         case WM_LBUTTONDOWN:
1783         case WM_LBUTTONUP:
1784         case WM_MBUTTONDOWN:
1785         case WM_MBUTTONUP:
1786         case WM_RBUTTONDOWN:
1787         case WM_RBUTTONUP:
1788             TOOLTIPS_Hide (hwnd, infoPtr);
1789             break;
1790
1791         case WM_MOUSEMOVE:
1792             pt.x = LOWORD(lpMsg->lParam);
1793             pt.y = HIWORD(lpMsg->lParam);
1794             nOldTool = infoPtr->nTool;
1795             infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
1796                                                        &pt);
1797             TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
1798                   infoPtr->nTool, infoPtr->nCurrentTool);
1799             TRACE("WM_MOUSEMOVE (%p %ld %ld)\n", hwnd, pt.x, pt.y);
1800
1801             if (infoPtr->nTool != nOldTool) {
1802                 if(infoPtr->nTool == -1) { /* Moved out of all tools */
1803                     TOOLTIPS_Hide(hwnd, infoPtr);
1804                     KillTimer(hwnd, ID_TIMERLEAVE);
1805                 } else if (nOldTool == -1) { /* Moved from outside */
1806                     if(infoPtr->bActive) {
1807                         SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1808                         TRACE("timer 1 started!\n");
1809                     }
1810                 } else { /* Moved from one to another */
1811                     TOOLTIPS_Hide (hwnd, infoPtr);
1812                     KillTimer(hwnd, ID_TIMERLEAVE);
1813                     if(infoPtr->bActive) {
1814                         SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1815                         TRACE("timer 1 started!\n");
1816                     }
1817                 }
1818             } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1819                 KillTimer(hwnd, ID_TIMERPOP);
1820                 SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1821                 TRACE("timer 2 restarted\n");
1822             } else if(infoPtr->nTool != -1 && infoPtr->bActive) {
1823                 /* previous show attempt didn't result in tooltip so try again */
1824                 SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1825                 TRACE("timer 1 started!\n");
1826             }
1827             break;
1828     }
1829
1830     return 0;
1831 }
1832
1833
1834 static LRESULT
1835 TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
1836 {
1837     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1838     INT nTime = (INT)LOWORD(lParam);
1839
1840     switch (wParam) {
1841     case TTDT_AUTOMATIC:
1842         if (nTime <= 0)
1843             nTime = GetDoubleClickTime();
1844         infoPtr->nReshowTime    = nTime / 5;
1845         infoPtr->nAutoPopTime   = nTime * 10;
1846         infoPtr->nInitialTime   = nTime;
1847         break;
1848
1849     case TTDT_RESHOW:
1850         if(nTime < 0)
1851             nTime = GetDoubleClickTime() / 5;
1852         infoPtr->nReshowTime = nTime;
1853         break;
1854
1855     case TTDT_AUTOPOP:
1856         if(nTime < 0)
1857             nTime = GetDoubleClickTime() * 10;
1858         infoPtr->nAutoPopTime = nTime;
1859         break;
1860
1861     case TTDT_INITIAL:
1862         if(nTime < 0)
1863             nTime = GetDoubleClickTime();
1864         infoPtr->nInitialTime = nTime;
1865             break;
1866
1867     default:
1868         WARN("Invalid wParam %x\n", wParam);
1869         break;
1870     }
1871
1872     return 0;
1873 }
1874
1875
1876 static LRESULT
1877 TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
1878 {
1879     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1880     LPRECT lpRect = (LPRECT)lParam;
1881
1882     infoPtr->rcMargin.left   = lpRect->left;
1883     infoPtr->rcMargin.right  = lpRect->right;
1884     infoPtr->rcMargin.bottom = lpRect->bottom;
1885     infoPtr->rcMargin.top    = lpRect->top;
1886
1887     return 0;
1888 }
1889
1890
1891 inline static LRESULT
1892 TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
1893 {
1894     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1895     INT nTemp = infoPtr->nMaxTipWidth;
1896
1897     infoPtr->nMaxTipWidth = (INT)lParam;
1898
1899     return nTemp;
1900 }
1901
1902
1903 inline static LRESULT
1904 TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1905 {
1906     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1907
1908     infoPtr->clrBk = (COLORREF)wParam;
1909
1910     return 0;
1911 }
1912
1913
1914 inline static LRESULT
1915 TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
1916 {
1917     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1918
1919     infoPtr->clrText = (COLORREF)wParam;
1920
1921     return 0;
1922 }
1923
1924
1925 static LRESULT
1926 TOOLTIPS_SetTitleA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1927 {
1928     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1929     LPCSTR pszTitle = (LPCSTR)lParam;
1930     UINT_PTR uTitleIcon = (UINT_PTR)wParam;
1931     UINT size;
1932
1933     TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_a(pszTitle),
1934         (void*)uTitleIcon);
1935
1936     Free(infoPtr->pszTitle);
1937
1938     if (pszTitle)
1939     {
1940         size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, NULL, 0);
1941         infoPtr->pszTitle = Alloc(size);
1942         if (!infoPtr->pszTitle)
1943             return FALSE;
1944         MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR));
1945     }
1946     else
1947         infoPtr->pszTitle = NULL;
1948
1949     if (uTitleIcon <= TTI_ERROR)
1950         infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
1951     else
1952         infoPtr->hTitleIcon = CopyIcon((HICON)wParam);
1953
1954     return TRUE;
1955 }
1956
1957
1958 static LRESULT
1959 TOOLTIPS_SetTitleW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1960 {
1961     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1962     LPCWSTR pszTitle = (LPCWSTR)lParam;
1963     UINT_PTR uTitleIcon = (UINT_PTR)wParam;
1964     UINT size;
1965
1966     TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_w(pszTitle),
1967         (void*)uTitleIcon);
1968
1969     Free(infoPtr->pszTitle);
1970
1971     if (pszTitle)
1972     {
1973         size = (strlenW(pszTitle)+1)*sizeof(WCHAR);
1974         infoPtr->pszTitle = Alloc(size);
1975         if (!infoPtr->pszTitle)
1976             return FALSE;
1977         memcpy(infoPtr->pszTitle, pszTitle, size);
1978     }
1979     else
1980         infoPtr->pszTitle = NULL;
1981
1982     if (uTitleIcon <= TTI_ERROR)
1983         infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
1984     else
1985         infoPtr->hTitleIcon = CopyIcon((HICON)wParam);
1986
1987     TRACE("icon = %p\n", infoPtr->hTitleIcon);
1988
1989     return TRUE;
1990 }
1991
1992
1993 static LRESULT
1994 TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1995 {
1996     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1997     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
1998     TTTOOL_INFO *toolPtr;
1999     INT nTool;
2000
2001     if (lpToolInfo == NULL)
2002         return 0;
2003     if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
2004         return 0;
2005
2006     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
2007     if (nTool == -1) return 0;
2008
2009     TRACE("tool %d\n", nTool);
2010
2011     toolPtr = &infoPtr->tools[nTool];
2012
2013     /* copy tool data */
2014     toolPtr->uFlags = lpToolInfo->uFlags;
2015     toolPtr->hwnd   = lpToolInfo->hwnd;
2016     toolPtr->uId    = lpToolInfo->uId;
2017     toolPtr->rect   = lpToolInfo->rect;
2018     toolPtr->hinst  = lpToolInfo->hinst;
2019
2020     if (HIWORD(lpToolInfo->lpszText) == 0) {
2021         TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
2022         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
2023     }
2024     else if (lpToolInfo->lpszText) {
2025         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
2026             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2027         else {
2028             if ( (toolPtr->lpszText) &&
2029                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
2030                 Free (toolPtr->lpszText);
2031                 toolPtr->lpszText = NULL;
2032             }
2033             if (lpToolInfo->lpszText) {
2034                 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
2035                                               -1, NULL, 0);
2036                 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
2037                 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
2038                                     toolPtr->lpszText, len);
2039             }
2040         }
2041     }
2042
2043     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
2044         toolPtr->lParam = lpToolInfo->lParam;
2045
2046     return 0;
2047 }
2048
2049
2050 static LRESULT
2051 TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2052 {
2053     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2054     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
2055     TTTOOL_INFO *toolPtr;
2056     INT nTool;
2057
2058     if (lpToolInfo == NULL)
2059         return 0;
2060     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
2061         return 0;
2062
2063     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
2064     if (nTool == -1) return 0;
2065
2066     TRACE("tool %d\n", nTool);
2067
2068     toolPtr = &infoPtr->tools[nTool];
2069
2070     /* copy tool data */
2071     toolPtr->uFlags = lpToolInfo->uFlags;
2072     toolPtr->hwnd   = lpToolInfo->hwnd;
2073     toolPtr->uId    = lpToolInfo->uId;
2074     toolPtr->rect   = lpToolInfo->rect;
2075     toolPtr->hinst  = lpToolInfo->hinst;
2076
2077     if (HIWORD(lpToolInfo->lpszText) == 0) {
2078         TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText);
2079         toolPtr->lpszText = lpToolInfo->lpszText;
2080     }
2081     else {
2082         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
2083             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2084         else {
2085             if ( (toolPtr->lpszText) &&
2086                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
2087                 Free (toolPtr->lpszText);
2088                 toolPtr->lpszText = NULL;
2089             }
2090             if (lpToolInfo->lpszText) {
2091                 INT len = lstrlenW (lpToolInfo->lpszText);
2092                 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
2093                 strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
2094             }
2095         }
2096     }
2097
2098     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
2099         toolPtr->lParam = lpToolInfo->lParam;
2100
2101     if (infoPtr->nCurrentTool == nTool)
2102     {
2103         TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool);
2104
2105         if (infoPtr->szTipText[0] == 0)
2106             TOOLTIPS_Hide(hwnd, infoPtr);
2107         else
2108             TOOLTIPS_Show (hwnd, infoPtr);
2109     }
2110
2111     return 0;
2112 }
2113
2114
2115 static LRESULT
2116 TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
2117 {
2118     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2119
2120     if ((BOOL)wParam) {
2121         LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
2122
2123         if (lpToolInfo == NULL)
2124             return 0;
2125         if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
2126             return FALSE;
2127
2128         /* activate */
2129         infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
2130         if (infoPtr->nTrackTool != -1) {
2131             TRACE("activated!\n");
2132             infoPtr->bTrackActive = TRUE;
2133             TOOLTIPS_TrackShow (hwnd, infoPtr);
2134         }
2135     }
2136     else {
2137         /* deactivate */
2138         TOOLTIPS_TrackHide (hwnd, infoPtr);
2139
2140         infoPtr->bTrackActive = FALSE;
2141         infoPtr->nTrackTool = -1;
2142
2143         TRACE("deactivated!\n");
2144     }
2145
2146     return 0;
2147 }
2148
2149
2150 static LRESULT
2151 TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam)
2152 {
2153     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2154
2155     infoPtr->xTrackPos = (INT)LOWORD(lParam);
2156     infoPtr->yTrackPos = (INT)HIWORD(lParam);
2157
2158     if (infoPtr->bTrackActive) {
2159         TRACE("[%d %d]\n",
2160                infoPtr->xTrackPos, infoPtr->yTrackPos);
2161
2162         TOOLTIPS_TrackShow (hwnd, infoPtr);
2163     }
2164
2165     return 0;
2166 }
2167
2168
2169 static LRESULT
2170 TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam)
2171 {
2172     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2173
2174     if (infoPtr->nCurrentTool != -1)
2175         UpdateWindow (hwnd);
2176
2177     return 0;
2178 }
2179
2180
2181 static LRESULT
2182 TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2183 {
2184     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2185     LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
2186     TTTOOL_INFO *toolPtr;
2187     INT nTool;
2188
2189     if (lpToolInfo == NULL)
2190         return 0;
2191     if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
2192         return FALSE;
2193
2194     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
2195     if (nTool == -1) return 0;
2196
2197     TRACE("tool %d\n", nTool);
2198
2199     toolPtr = &infoPtr->tools[nTool];
2200
2201     /* copy tool text */
2202     toolPtr->hinst  = lpToolInfo->hinst;
2203
2204     if (HIWORD(lpToolInfo->lpszText) == 0){
2205         toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
2206     }
2207     else if (lpToolInfo->lpszText) {
2208         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
2209             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2210         else {
2211             if ( (toolPtr->lpszText) &&
2212                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
2213                 Free (toolPtr->lpszText);
2214                 toolPtr->lpszText = NULL;
2215             }
2216             if (lpToolInfo->lpszText) {
2217                 INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
2218                                               -1, NULL, 0);
2219                 toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
2220                 MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
2221                                     toolPtr->lpszText, len);
2222             }
2223         }
2224     }
2225
2226     if(infoPtr->nCurrentTool == -1) return 0;
2227     /* force repaint */
2228     if (infoPtr->bActive)
2229         TOOLTIPS_Show (hwnd, infoPtr);
2230     else if (infoPtr->bTrackActive)
2231         TOOLTIPS_TrackShow (hwnd, infoPtr);
2232
2233     return 0;
2234 }
2235
2236
2237 static LRESULT
2238 TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2239 {
2240     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2241     LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
2242     TTTOOL_INFO *toolPtr;
2243     INT nTool;
2244
2245     if (lpToolInfo == NULL)
2246         return 0;
2247     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
2248         return FALSE;
2249
2250     nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
2251     if (nTool == -1)
2252         return 0;
2253
2254     TRACE("tool %d\n", nTool);
2255
2256     toolPtr = &infoPtr->tools[nTool];
2257
2258     /* copy tool text */
2259     toolPtr->hinst  = lpToolInfo->hinst;
2260
2261     if (HIWORD(lpToolInfo->lpszText) == 0){
2262         toolPtr->lpszText = lpToolInfo->lpszText;
2263     }
2264     else if (lpToolInfo->lpszText) {
2265         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
2266             toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2267         else {
2268             if ( (toolPtr->lpszText)  &&
2269                  (HIWORD((INT)toolPtr->lpszText) != 0) ) {
2270                 Free (toolPtr->lpszText);
2271                 toolPtr->lpszText = NULL;
2272             }
2273             if (lpToolInfo->lpszText) {
2274                 INT len = lstrlenW (lpToolInfo->lpszText);
2275                 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
2276                 strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
2277             }
2278         }
2279     }
2280
2281     if(infoPtr->nCurrentTool == -1) return 0;
2282     /* force repaint */
2283     if (infoPtr->bActive)
2284         TOOLTIPS_Show (hwnd, infoPtr);
2285     else if (infoPtr->bTrackActive)
2286         TOOLTIPS_TrackShow (hwnd, infoPtr);
2287
2288     return 0;
2289 }
2290
2291
2292 static LRESULT
2293 TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2294 {
2295     return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
2296 }
2297
2298
2299
2300 static LRESULT
2301 TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
2302 {
2303     TOOLTIPS_INFO *infoPtr;
2304
2305     /* allocate memory for info structure */
2306     infoPtr = (TOOLTIPS_INFO *)Alloc (sizeof(TOOLTIPS_INFO));
2307     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
2308
2309     /* initialize info structure */
2310     infoPtr->bActive = TRUE;
2311     infoPtr->bTrackActive = FALSE;
2312
2313     infoPtr->nMaxTipWidth = -1;
2314     infoPtr->nTool = -1;
2315     infoPtr->nCurrentTool = -1;
2316     infoPtr->nTrackTool = -1;
2317
2318     /* initialize colours and fonts */
2319     TOOLTIPS_InitSystemSettings(infoPtr);
2320
2321     TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L);
2322
2323     SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
2324
2325     return 0;
2326 }
2327
2328
2329 static LRESULT
2330 TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
2331 {
2332     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2333     TTTOOL_INFO *toolPtr;
2334     UINT i;
2335
2336     /* free tools */
2337     if (infoPtr->tools) {
2338         for (i = 0; i < infoPtr->uNumTools; i++) {
2339             toolPtr = &infoPtr->tools[i];
2340             if (toolPtr->lpszText) {
2341                 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
2342                      (HIWORD((INT)toolPtr->lpszText) != 0) )
2343                 {
2344                     Free (toolPtr->lpszText);
2345                     toolPtr->lpszText = NULL;
2346                 }
2347             }
2348
2349             /* remove subclassing */
2350         if (toolPtr->uFlags & TTF_SUBCLASS) {
2351             if (toolPtr->uFlags & TTF_IDISHWND) {
2352                 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
2353             }
2354             else {
2355                 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
2356             }
2357         }
2358     }
2359         Free (infoPtr->tools);
2360     }
2361
2362     /* free title string */
2363     Free (infoPtr->pszTitle);
2364     /* free title icon if not a standard one */
2365     if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR)
2366         DeleteObject(infoPtr->hTitleIcon);
2367
2368     /* delete fonts */
2369     DeleteObject (infoPtr->hFont);
2370     DeleteObject (infoPtr->hTitleFont);
2371
2372     /* free tool tips info data */
2373     Free (infoPtr);
2374     SetWindowLongPtrW(hwnd, 0, 0);
2375     return 0;
2376 }
2377
2378
2379 static LRESULT
2380 TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2381 {
2382     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2383
2384     return (LRESULT)infoPtr->hFont;
2385 }
2386
2387
2388 static LRESULT
2389 TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2390 {
2391     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2392
2393     TOOLTIPS_Hide (hwnd, infoPtr);
2394
2395     return 0;
2396 }
2397
2398
2399 static LRESULT
2400 TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
2401 {
2402     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2403     DWORD dwExStyle = GetWindowLongA (hwnd, GWL_EXSTYLE);
2404
2405     dwStyle &= 0x0000FFFF;
2406     dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
2407
2408     /* WS_BORDER only draws a border round the window rect, not the
2409      * window region, therefore it is useless to us in balloon mode */
2410     if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER;
2411
2412     SetWindowLongA (hwnd, GWL_STYLE, dwStyle);
2413
2414     dwExStyle |= WS_EX_TOOLWINDOW;
2415     SetWindowLongA (hwnd, GWL_EXSTYLE, dwExStyle);
2416
2417     return TRUE;
2418 }
2419
2420
2421 static LRESULT
2422 TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
2423 {
2424     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2425     INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
2426
2427     TRACE(" nTool=%d\n", nTool);
2428
2429     if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
2430         if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
2431             TRACE("-- in transparent mode!\n");
2432             return HTTRANSPARENT;
2433         }
2434     }
2435
2436     return DefWindowProcW (hwnd, WM_NCHITTEST, wParam, lParam);
2437 }
2438
2439
2440 static LRESULT
2441 TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
2442 {
2443     FIXME ("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2444
2445     return 0;
2446 }
2447
2448
2449 static LRESULT
2450 TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
2451 {
2452     HDC hdc;
2453     PAINTSTRUCT ps;
2454
2455     hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam;
2456     TOOLTIPS_Refresh (hwnd, hdc);
2457     if (!wParam)
2458         EndPaint (hwnd, &ps);
2459     return 0;
2460 }
2461
2462
2463 static LRESULT
2464 TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
2465 {
2466     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2467     LOGFONTW lf;
2468
2469     if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf))
2470         return 0;
2471
2472     DeleteObject (infoPtr->hFont);
2473     infoPtr->hFont = CreateFontIndirectW(&lf);
2474
2475     DeleteObject (infoPtr->hTitleFont);
2476     lf.lfWeight = FW_BOLD;
2477     infoPtr->hTitleFont = CreateFontIndirectW(&lf);
2478
2479     if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
2480         FIXME("full redraw needed!\n");
2481     }
2482
2483     return 0;
2484 }
2485
2486 /******************************************************************
2487  * TOOLTIPS_GetTextLength
2488  *
2489  * This function is called when the tooltip receive a
2490  * WM_GETTEXTLENGTH message.
2491  * wParam : not used
2492  * lParam : not used
2493  *
2494  * returns the length, in characters, of the tip text
2495  */
2496 static LRESULT
2497 TOOLTIPS_GetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam)
2498 {
2499     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2500     return strlenW(infoPtr->szTipText);
2501 }
2502
2503 /******************************************************************
2504  * TOOLTIPS_OnWMGetText
2505  *
2506  * This function is called when the tooltip receive a
2507  * WM_GETTEXT message.
2508  * wParam : specifies the maximum number of characters to be copied
2509  * lParam : is the pointer to the buffer that will receive
2510  *          the tip text
2511  *
2512  * returns the number of characters copied
2513  */
2514 static LRESULT
2515 TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
2516 {
2517     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2518     LRESULT res;
2519     LPWSTR pszText = (LPWSTR)lParam;
2520
2521     if(!infoPtr->szTipText || !wParam)
2522         return 0;
2523
2524     res = min(strlenW(infoPtr->szTipText)+1, wParam);
2525     memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR));
2526     pszText[res-1] = '\0';
2527     return res-1;
2528 }
2529
2530 static LRESULT
2531 TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
2532 {
2533     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2534     INT nOldTool;
2535
2536     TRACE("timer %d (%p) expired!\n", wParam, hwnd);
2537
2538     switch (wParam) {
2539     case ID_TIMERSHOW:
2540         KillTimer (hwnd, ID_TIMERSHOW);
2541         nOldTool = infoPtr->nTool;
2542         if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool)
2543             TOOLTIPS_Show (hwnd, infoPtr);
2544         break;
2545
2546     case ID_TIMERPOP:
2547         TOOLTIPS_Hide (hwnd, infoPtr);
2548         break;
2549
2550     case ID_TIMERLEAVE:
2551         nOldTool = infoPtr->nTool;
2552         infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE);
2553         TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
2554               infoPtr->nTool, infoPtr->nCurrentTool);
2555         if (infoPtr->nTool != nOldTool) {
2556             if(infoPtr->nTool == -1) { /* Moved out of all tools */
2557                 TOOLTIPS_Hide(hwnd, infoPtr);
2558                 KillTimer(hwnd, ID_TIMERLEAVE);
2559             } else if (nOldTool == -1) { /* Moved from outside */
2560                 ERR("How did this happen?\n");
2561             } else { /* Moved from one to another */
2562                 TOOLTIPS_Hide (hwnd, infoPtr);
2563                 KillTimer(hwnd, ID_TIMERLEAVE);
2564                 if(infoPtr->bActive) {
2565                     SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
2566                     TRACE("timer 1 started!\n");
2567                 }
2568             }
2569         }
2570         break;
2571
2572     default:
2573         ERR("Unknown timer id %d\n", wParam);
2574         break;
2575     }
2576     return 0;
2577 }
2578
2579
2580 static LRESULT
2581 TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam)
2582 {
2583     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2584
2585     TOOLTIPS_InitSystemSettings (infoPtr);
2586
2587     return 0;
2588 }
2589
2590
2591 static LRESULT CALLBACK
2592 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
2593 {
2594     MSG msg;
2595
2596     switch(uMsg) {
2597     case WM_MOUSEMOVE:
2598     case WM_LBUTTONDOWN:
2599     case WM_LBUTTONUP:
2600     case WM_MBUTTONDOWN:
2601     case WM_MBUTTONUP:
2602     case WM_RBUTTONDOWN:
2603     case WM_RBUTTONUP:
2604         msg.hwnd = hwnd;
2605         msg.message = uMsg;
2606         msg.wParam = wParam;
2607         msg.lParam = lParam;
2608         TOOLTIPS_RelayEvent((HWND)dwRef, 0, (LPARAM)&msg);
2609         break;
2610
2611     default:
2612         break;
2613     }
2614     return DefSubclassProc(hwnd, uMsg, wParam, lParam);
2615 }
2616
2617
2618 static LRESULT CALLBACK
2619 TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2620 {
2621     TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2622     if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2623         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2624     switch (uMsg)
2625     {
2626         case TTM_ACTIVATE:
2627             return TOOLTIPS_Activate (hwnd, wParam, lParam);
2628
2629         case TTM_ADDTOOLA:
2630             return TOOLTIPS_AddToolA (hwnd, wParam, lParam);
2631
2632         case TTM_ADDTOOLW:
2633             return TOOLTIPS_AddToolW (hwnd, wParam, lParam);
2634
2635         case TTM_DELTOOLA:
2636             return TOOLTIPS_DelToolA (hwnd, wParam, lParam);
2637
2638         case TTM_DELTOOLW:
2639             return TOOLTIPS_DelToolW (hwnd, wParam, lParam);
2640
2641         case TTM_ENUMTOOLSA:
2642             return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam);
2643
2644         case TTM_ENUMTOOLSW:
2645             return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam);
2646
2647         case TTM_GETBUBBLESIZE:
2648             return TOOLTIPS_GetBubbleSize (hwnd, wParam, lParam);
2649
2650         case TTM_GETCURRENTTOOLA:
2651             return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam);
2652
2653         case TTM_GETCURRENTTOOLW:
2654             return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam);
2655
2656         case TTM_GETDELAYTIME:
2657             return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam);
2658
2659         case TTM_GETMARGIN:
2660             return TOOLTIPS_GetMargin (hwnd, wParam, lParam);
2661
2662         case TTM_GETMAXTIPWIDTH:
2663             return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam);
2664
2665         case TTM_GETTEXTA:
2666             return TOOLTIPS_GetTextA (hwnd, wParam, lParam);
2667
2668         case TTM_GETTEXTW:
2669             return TOOLTIPS_GetTextW (hwnd, wParam, lParam);
2670
2671         case TTM_GETTIPBKCOLOR:
2672             return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam);
2673
2674         case TTM_GETTIPTEXTCOLOR:
2675             return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam);
2676
2677         case TTM_GETTOOLCOUNT:
2678             return TOOLTIPS_GetToolCount (hwnd, wParam, lParam);
2679
2680         case TTM_GETTOOLINFOA:
2681             return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam);
2682
2683         case TTM_GETTOOLINFOW:
2684             return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam);
2685
2686         case TTM_HITTESTA:
2687             return TOOLTIPS_HitTestA (hwnd, wParam, lParam);
2688
2689         case TTM_HITTESTW:
2690             return TOOLTIPS_HitTestW (hwnd, wParam, lParam);
2691
2692         case TTM_NEWTOOLRECTA:
2693             return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam);
2694
2695         case TTM_NEWTOOLRECTW:
2696             return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam);
2697
2698         case TTM_POP:
2699             return TOOLTIPS_Pop (hwnd, wParam, lParam);
2700
2701         case TTM_RELAYEVENT:
2702             return TOOLTIPS_RelayEvent (hwnd, wParam, lParam);
2703
2704         case TTM_SETDELAYTIME:
2705             return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam);
2706
2707         case TTM_SETMARGIN:
2708             return TOOLTIPS_SetMargin (hwnd, wParam, lParam);
2709
2710         case TTM_SETMAXTIPWIDTH:
2711             return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam);
2712
2713         case TTM_SETTIPBKCOLOR:
2714             return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam);
2715
2716         case TTM_SETTIPTEXTCOLOR:
2717             return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam);
2718
2719         case TTM_SETTITLEA:
2720             return TOOLTIPS_SetTitleA (hwnd, wParam, lParam);
2721
2722         case TTM_SETTITLEW:
2723             return TOOLTIPS_SetTitleW (hwnd, wParam, lParam);
2724
2725         case TTM_SETTOOLINFOA:
2726             return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam);
2727
2728         case TTM_SETTOOLINFOW:
2729             return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam);
2730
2731         case TTM_TRACKACTIVATE:
2732             return TOOLTIPS_TrackActivate (hwnd, wParam, lParam);
2733
2734         case TTM_TRACKPOSITION:
2735             return TOOLTIPS_TrackPosition (hwnd, wParam, lParam);
2736
2737         case TTM_UPDATE:
2738             return TOOLTIPS_Update (hwnd, wParam, lParam);
2739
2740         case TTM_UPDATETIPTEXTA:
2741             return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam);
2742
2743         case TTM_UPDATETIPTEXTW:
2744             return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam);
2745
2746         case TTM_WINDOWFROMPOINT:
2747             return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam);
2748
2749
2750         case WM_CREATE:
2751             return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam);
2752
2753         case WM_DESTROY:
2754             return TOOLTIPS_Destroy (hwnd, wParam, lParam);
2755
2756         case WM_ERASEBKGND:
2757             /* we draw the background in WM_PAINT */
2758             return 0;
2759
2760         case WM_GETFONT:
2761             return TOOLTIPS_GetFont (hwnd, wParam, lParam);
2762
2763         case WM_GETTEXT:
2764             return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam);
2765
2766         case WM_GETTEXTLENGTH:
2767             return TOOLTIPS_GetTextLength (hwnd, wParam, lParam);
2768
2769         case WM_LBUTTONDOWN:
2770         case WM_LBUTTONUP:
2771         case WM_MBUTTONDOWN:
2772         case WM_MBUTTONUP:
2773         case WM_RBUTTONDOWN:
2774         case WM_RBUTTONUP:
2775         case WM_MOUSEMOVE:
2776             return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam);
2777
2778         case WM_NCCREATE:
2779             return TOOLTIPS_NCCreate (hwnd, wParam, lParam);
2780
2781         case WM_NCHITTEST:
2782             return TOOLTIPS_NCHitTest (hwnd, wParam, lParam);
2783
2784         case WM_NOTIFYFORMAT:
2785             return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam);
2786
2787         case WM_PAINT:
2788             return TOOLTIPS_Paint (hwnd, wParam, lParam);
2789
2790         case WM_SETFONT:
2791             return TOOLTIPS_SetFont (hwnd, wParam, lParam);
2792
2793         case WM_TIMER:
2794             return TOOLTIPS_Timer (hwnd, wParam, lParam);
2795
2796         case WM_WININICHANGE:
2797             return TOOLTIPS_WinIniChange (hwnd, wParam, lParam);
2798
2799         default:
2800             if ((uMsg >= WM_USER) && (uMsg < WM_APP))
2801                 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
2802                      uMsg, wParam, lParam);
2803             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2804     }
2805     return 0;
2806 }
2807
2808
2809 VOID
2810 TOOLTIPS_Register (void)
2811 {
2812     WNDCLASSW wndClass;
2813
2814     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2815     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2816     wndClass.lpfnWndProc   = TOOLTIPS_WindowProc;
2817     wndClass.cbClsExtra    = 0;
2818     wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2819     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2820     wndClass.hbrBackground = 0;
2821     wndClass.lpszClassName = TOOLTIPS_CLASSW;
2822
2823     RegisterClassW (&wndClass);
2824
2825     hTooltipIcons[TTI_NONE] = NULL;
2826     hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule,
2827         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0);
2828     hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule,
2829         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0);
2830     hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule,
2831         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0);
2832 }
2833
2834
2835 VOID
2836 TOOLTIPS_Unregister (void)
2837 {
2838     int i;
2839     for (i = 0; i < TTI_ERROR+1; i++)
2840         DeleteObject(hTooltipIcons[i]);
2841     UnregisterClassW (TOOLTIPS_CLASSW, NULL);
2842 }