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