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