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