Release 980927
[wine] / dlls / comctl32 / tooltips.c
1 /*
2  * Tool tip control
3  *
4  * Copyright 1998 Eric Kohl
5  *
6  * TODO:
7  *   - Tracking tooltips (under construction).
8  *   - TTS_ALWAYSTIP (undefined).
9  *   - Unicode support.
10  *   - Custom draw support.
11  *   - The "lParam" variable from NMTTDISPINFO32A is not handled
12  *     in TOOLTIPS_GetTipText.
13  *
14  * Testing:
15  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
16  *     The second cdrom (chapter 3) contains executables activate.exe,
17  *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
18  *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
19  */
20
21 #include "windows.h"
22 #include "commctrl.h"
23 #include "tooltips.h"
24 #include "win.h"
25 #include "debug.h"
26
27
28 #define ID_TIMER1  1    /* show delay timer */
29 #define ID_TIMER2  2    /* auto pop timer */
30 #define ID_TIMER3  3    /* tool leave timer */
31
32 /* property name of tooltip window handle */
33 #define TT_SUBCLASS_PROP "CC32SubclassInfo"
34
35 #define TOOLTIPS_GetInfoPtr(wndPtr) ((TOOLTIPS_INFO *)wndPtr->wExtra[0])
36
37
38 LRESULT CALLBACK
39 TOOLTIPS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam);
40
41
42 static VOID
43 TOOLTIPS_Refresh (WND *wndPtr, HDC32 hdc)
44 {
45     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
46     RECT32 rc;
47     INT32 oldBkMode;
48     HFONT32 hOldFont;
49     UINT32 uFlags = DT_EXTERNALLEADING;
50
51     if (infoPtr->nMaxTipWidth > -1)
52         uFlags |= DT_WORDBREAK;
53     if (wndPtr->dwStyle & TTS_NOPREFIX)
54         uFlags |= DT_NOPREFIX;
55     GetClientRect32 (wndPtr->hwndSelf, &rc);
56     rc.left   += (2 + infoPtr->rcMargin.left);
57     rc.top    += (2 + infoPtr->rcMargin.top);
58     rc.right  -= (2 + infoPtr->rcMargin.right);
59     rc.bottom -= (2 + infoPtr->rcMargin.bottom);
60     oldBkMode = SetBkMode32 (hdc, TRANSPARENT);
61     SetTextColor32 (hdc, infoPtr->clrText);
62     hOldFont = SelectObject32 (hdc, infoPtr->hFont);
63     DrawText32A (hdc, infoPtr->szTipText, -1, &rc, uFlags);
64     SelectObject32 (hdc, hOldFont);
65     if (oldBkMode != TRANSPARENT)
66         SetBkMode32 (hdc, oldBkMode);
67 }
68
69
70 static VOID
71 TOOLTIPS_GetTipText (WND *wndPtr, TOOLTIPS_INFO *infoPtr)
72 {
73     TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
74
75     if (toolPtr->hinst) {
76         TRACE (tooltips, "get res string %x %x\n",
77                toolPtr->hinst, (int)toolPtr->lpszText);
78         LoadString32A (toolPtr->hinst, (UINT32)toolPtr->lpszText,
79                        infoPtr->szTipText, INFOTIPSIZE);
80     }
81     else if (toolPtr->lpszText) {
82         if (toolPtr->lpszText == LPSTR_TEXTCALLBACK32A) {
83             NMTTDISPINFO32A ttnmdi;
84
85             /* fill NMHDR struct */
86             ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFO32A));
87             ttnmdi.hdr.hwndFrom = wndPtr->hwndSelf;
88             ttnmdi.hdr.idFrom = toolPtr->uId;
89             ttnmdi.hdr.code = TTN_GETDISPINFO32A;
90             ttnmdi.uFlags = toolPtr->uFlags;
91             ttnmdi.lpszText = infoPtr->szTipText;
92
93             TRACE (tooltips, "hdr.idFrom = %x\n", ttnmdi.hdr.idFrom);
94             SendMessage32A (toolPtr->hwnd, WM_NOTIFY,
95                             (WPARAM32)toolPtr->uId, (LPARAM)&ttnmdi);
96
97             if (ttnmdi.hinst) {
98                 LoadString32A (ttnmdi.hinst, (UINT32)ttnmdi.szText,
99                                infoPtr->szTipText, INFOTIPSIZE);
100                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
101                     toolPtr->hinst = ttnmdi.hinst;
102                     toolPtr->lpszText = ttnmdi.szText;
103                 }
104             }
105             else if (ttnmdi.szText[0]) {
106                 lstrcpyn32A (infoPtr->szTipText, ttnmdi.szText, 80);
107                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
108                     INT32 len = lstrlen32A (ttnmdi.szText) + 1;
109                     toolPtr->hinst = 0;
110                     toolPtr->lpszText = COMCTL32_Alloc (len);
111                     lstrcpy32A (toolPtr->lpszText, ttnmdi.szText);
112                 }
113             }
114             else if (ttnmdi.lpszText == 0) {
115                 /* no text available */
116                 infoPtr->szTipText[0] = '\0';
117             }
118             else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACK32A) {
119                 if (ttnmdi.lpszText != infoPtr->szTipText)
120                     lstrcpyn32A (infoPtr->szTipText, ttnmdi.lpszText,
121                                  INFOTIPSIZE);
122                 if (ttnmdi.uFlags & TTF_DI_SETITEM) {
123                     INT32 len = lstrlen32A (ttnmdi.lpszText) + 1;
124                     toolPtr->hinst = 0;
125                     toolPtr->lpszText = COMCTL32_Alloc (len);
126                     lstrcpy32A (toolPtr->lpszText, ttnmdi.lpszText);
127                 }
128             }
129             else
130                 ERR (tooltips, "recursive text callback!\n");
131         }
132         else
133             lstrcpyn32A (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
134     }
135     else
136         /* no text available */
137         infoPtr->szTipText[0] = '\0';
138
139     TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
140 }
141
142
143 static VOID
144 TOOLTIPS_CalcTipSize (WND *wndPtr, TOOLTIPS_INFO *infoPtr, LPSIZE32 lpSize)
145 {
146     HDC32 hdc;
147     HFONT32 hOldFont;
148     UINT32 uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
149     RECT32 rc = {0, 0, 0, 0};
150
151     if (infoPtr->nMaxTipWidth > -1) {
152         rc.right = infoPtr->nMaxTipWidth;
153         uFlags |= DT_WORDBREAK;
154     }
155     if (wndPtr->dwStyle & TTS_NOPREFIX)
156         uFlags |= DT_NOPREFIX;
157     TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
158
159     hdc = GetDC32 (wndPtr->hwndSelf);
160     hOldFont = SelectObject32 (hdc, infoPtr->hFont);
161     DrawText32A (hdc, infoPtr->szTipText, -1, &rc, uFlags);
162     GetTextExtentPoint32A (hdc, infoPtr->szTipText, lstrlen32A(infoPtr->szTipText), lpSize);
163     SelectObject32 (hdc, hOldFont);
164     ReleaseDC32 (wndPtr->hwndSelf, hdc);
165
166     lpSize->cx = rc.right - rc.left + 4 + 
167                  infoPtr->rcMargin.left + infoPtr->rcMargin.right;
168     lpSize->cy = rc.bottom - rc.top + 4 +
169                  infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
170 }
171
172
173 static VOID
174 TOOLTIPS_Show (WND *wndPtr, TOOLTIPS_INFO *infoPtr)
175 {
176     TTTOOL_INFO *toolPtr;
177     RECT32 rect;
178     SIZE32 size;
179     NMHDR hdr;
180
181     if (infoPtr->nTool == -1) {
182         TRACE (tooltips, "invalid tool (-1)!\n");
183         return;
184     }
185
186     infoPtr->nCurrentTool = infoPtr->nTool;
187
188     TRACE (tooltips, "Show tooltip pre %d!\n", infoPtr->nTool);
189
190     TOOLTIPS_GetTipText (wndPtr, infoPtr);
191
192     if (infoPtr->szTipText[0] == '\0') {
193         infoPtr->nCurrentTool = -1;
194         return;
195     }
196
197     TRACE (tooltips, "Show tooltip %d!\n", infoPtr->nCurrentTool);
198     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
199
200     hdr.hwndFrom = wndPtr->hwndSelf;
201     hdr.idFrom = toolPtr->uId;
202     hdr.code = TTN_SHOW;
203     SendMessage32A (toolPtr->hwnd, WM_NOTIFY,
204                     (WPARAM32)toolPtr->uId, (LPARAM)&hdr);
205
206     TRACE (tooltips, "\"%s\"\n", infoPtr->szTipText);
207
208     TOOLTIPS_CalcTipSize (wndPtr, infoPtr, &size);
209     TRACE (tooltips, "size %d - %d\n", size.cx, size.cy);
210
211     if ((toolPtr->uFlags & TTF_TRACK) && (toolPtr->uFlags & TTF_ABSOLUTE)) {
212         rect.left = infoPtr->xTrackPos;
213         rect.top  = infoPtr->yTrackPos;
214     }
215     else if (toolPtr->uFlags & TTF_CENTERTIP) {
216         RECT32 rc;
217
218         if (toolPtr->uFlags & TTF_IDISHWND)
219             GetWindowRect32 ((HWND32)toolPtr->uId, &rc);
220         else {
221             rc = toolPtr->rect;
222             MapWindowPoints32 (toolPtr->hwnd, (HWND32)0, (LPPOINT32)&rc, 2);
223         }
224         rect.left = (rc.left + rc.right - size.cx) / 2;
225         rect.top  = rc.bottom + 2;
226     }
227     else {
228         GetCursorPos32 ((LPPOINT32)&rect);
229         rect.top += 20;
230     }
231
232     TRACE (tooltips, "pos %d - %d\n", rect.left, rect.top);
233
234     rect.right = rect.left + size.cx;
235     rect.bottom = rect.top + size.cy;
236
237     AdjustWindowRectEx32 (&rect, wndPtr->dwStyle, FALSE, wndPtr->dwExStyle);
238
239 //    SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 1, 1,
240     SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, rect.left, rect.top,
241                     rect.right - rect.left, rect.bottom - rect.top,
242                     SWP_SHOWWINDOW);
243
244     SetTimer32 (wndPtr->hwndSelf, ID_TIMER2, infoPtr->nAutoPopTime, 0);
245 }
246
247
248 static VOID
249 TOOLTIPS_Hide (WND *wndPtr, TOOLTIPS_INFO *infoPtr)
250 {
251     TTTOOL_INFO *toolPtr;
252     NMHDR hdr;
253
254     if (infoPtr->nCurrentTool == -1)
255         return;
256
257     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
258     TRACE (tooltips, "Hide tooltip %d!\n", infoPtr->nCurrentTool);
259     KillTimer32 (wndPtr->hwndSelf, ID_TIMER2);
260
261     hdr.hwndFrom = wndPtr->hwndSelf;
262     hdr.idFrom = toolPtr->uId;
263     hdr.code = TTN_POP;
264     SendMessage32A (toolPtr->hwnd, WM_NOTIFY,
265                     (WPARAM32)toolPtr->uId, (LPARAM)&hdr);
266
267     infoPtr->nCurrentTool = -1;
268
269     SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
270                     SWP_NOZORDER | SWP_HIDEWINDOW);
271 }
272
273
274 static INT32
275 TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFO32A lpToolInfo)
276 {
277     TTTOOL_INFO *toolPtr;
278     INT32 nTool;
279
280     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
281         toolPtr = &infoPtr->tools[nTool];
282
283         if (!(toolPtr->uFlags & TTF_IDISHWND) && 
284             (lpToolInfo->hwnd == toolPtr->hwnd) &&
285             (lpToolInfo->uId == toolPtr->uId))
286             return nTool;
287     }
288
289     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
290         toolPtr = &infoPtr->tools[nTool];
291
292         if ((toolPtr->uFlags & TTF_IDISHWND) &&
293             (lpToolInfo->uId == toolPtr->uId))
294             return nTool;
295     }
296
297     return -1;
298 }
299
300
301 static INT32
302 TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND32 hwnd, LPPOINT32 lpPt)
303 {
304     TTTOOL_INFO *toolPtr;
305     INT32  nTool;
306
307     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
308         toolPtr = &infoPtr->tools[nTool];
309
310         if (!(toolPtr->uFlags & TTF_IDISHWND)) {
311             if (hwnd != toolPtr->hwnd)
312                 continue;
313             if (!PtInRect32 (&toolPtr->rect, *lpPt))
314                 continue;
315             return nTool;
316         }
317     }
318
319     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
320         toolPtr = &infoPtr->tools[nTool];
321
322         if (toolPtr->uFlags & TTF_IDISHWND) {
323             if ((HWND32)toolPtr->uId == hwnd)
324                 return nTool;
325         }
326     }
327
328     return -1;
329 }
330
331
332 static INT32
333 TOOLTIPS_GetToolFromMessage (TOOLTIPS_INFO *infoPtr, HWND32 hwndTool)
334 {
335     DWORD   dwPos;
336     POINT32 pt;
337
338     dwPos = GetMessagePos ();
339     pt.x = (INT32)LOWORD(dwPos);
340     pt.y = (INT32)HIWORD(dwPos);
341     ScreenToClient32 (hwndTool, &pt);
342
343     return TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
344 }
345
346
347 static INT32
348 TOOLTIPS_CheckTool (WND *wndPtr, BOOL32 bShowTest)
349 {
350     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
351     POINT32 pt;
352     HWND32 hwndTool;
353     INT32 nTool;
354
355     GetCursorPos32 (&pt);
356     hwndTool =
357         SendMessage32A (wndPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
358     if (hwndTool == 0)
359         return -1;
360
361     ScreenToClient32 (hwndTool, &pt);
362     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
363     if (nTool == -1)
364         return -1;
365
366 #if 0
367     if (!(wndPtr->dwStyle & TTS_ALWAYSTIP) && bShowTest) {
368         if (!IsWindowEnabled32 (infoPtr->tools[infoPtr->nTool].hwnd))
369             return -1;
370     }
371 #endif
372
373     TRACE (tooltips, "tool %d\n", nTool);
374
375     return nTool;
376 }
377
378
379 static LRESULT
380 TOOLTIPS_Activate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
381 {
382     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
383
384     infoPtr->bActive = (BOOL32)wParam;
385
386     if (infoPtr->bActive)
387         TRACE (tooltips, "activate!\n");
388
389     if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1)) 
390             TOOLTIPS_Hide (wndPtr, infoPtr);
391
392     return 0;
393 }
394
395
396 static LRESULT
397 TOOLTIPS_AddTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
398 {
399     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
400     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
401     TTTOOL_INFO *toolPtr;
402
403     if (lpToolInfo == NULL)
404         return FALSE;
405     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
406         return FALSE;
407
408     TRACE (tooltips, "add tool (%x) %x %d%s!\n",
409            wndPtr->hwndSelf, lpToolInfo->hwnd, lpToolInfo->uId,
410            (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
411
412     if (infoPtr->uNumTools == 0) {
413         infoPtr->tools = COMCTL32_Alloc (sizeof(TTTOOL_INFO));
414         toolPtr = infoPtr->tools;
415     }
416     else {
417         TTTOOL_INFO *oldTools = infoPtr->tools;
418         infoPtr->tools =
419             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
420         memcpy (infoPtr->tools, oldTools,
421                 infoPtr->uNumTools * sizeof(TTTOOL_INFO));
422         COMCTL32_Free (oldTools);
423         toolPtr = &infoPtr->tools[infoPtr->uNumTools];
424     }
425
426     infoPtr->uNumTools++;
427
428     /* copy tool data */
429     toolPtr->uFlags = lpToolInfo->uFlags;
430     toolPtr->hwnd   = lpToolInfo->hwnd;
431     toolPtr->uId    = lpToolInfo->uId;
432     toolPtr->rect   = lpToolInfo->rect;
433     toolPtr->hinst  = lpToolInfo->hinst;
434
435     if (lpToolInfo->hinst) {
436         TRACE (tooltips, "add string id %x!\n", (int)lpToolInfo->lpszText);
437         toolPtr->lpszText = lpToolInfo->lpszText;
438     }
439     else if (lpToolInfo->lpszText) {
440         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A) {
441             TRACE (tooltips, "add CALLBACK!\n");
442             toolPtr->lpszText = lpToolInfo->lpszText;
443         }
444         else {
445             INT32 len = lstrlen32A (lpToolInfo->lpszText);
446             TRACE (tooltips, "add text \"%s\"!\n", lpToolInfo->lpszText);
447             toolPtr->lpszText = COMCTL32_Alloc (len + 1);
448             lstrcpy32A (toolPtr->lpszText, lpToolInfo->lpszText);
449         }
450     }
451
452     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
453         toolPtr->lParam = lpToolInfo->lParam;
454
455     /* install subclassing hook */
456     if (toolPtr->uFlags & TTF_SUBCLASS) {
457         if (toolPtr->uFlags & TTF_IDISHWND) {
458             LPTT_SUBCLASS_INFO lpttsi =
459                 (LPTT_SUBCLASS_INFO)GetProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
460             if (lpttsi == NULL) {
461                 lpttsi =
462                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
463                 lpttsi->wpOrigProc = 
464                     (WNDPROC32)SetWindowLong32A ((HWND32)toolPtr->uId,
465                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
466                 lpttsi->hwndToolTip = wndPtr->hwndSelf;
467                 lpttsi->uRefCount++;
468                 SetProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP,
469                             (HANDLE32)lpttsi);
470             }
471             else
472                 WARN (tooltips, "A window tool must only be listed once!\n");
473         }
474         else {
475             LPTT_SUBCLASS_INFO lpttsi =
476                 (LPTT_SUBCLASS_INFO)GetProp32A (toolPtr->hwnd, TT_SUBCLASS_PROP);
477             if (lpttsi == NULL) {
478                 lpttsi =
479                     (LPTT_SUBCLASS_INFO)COMCTL32_Alloc (sizeof(TT_SUBCLASS_INFO));
480                 lpttsi->wpOrigProc = 
481                     (WNDPROC32)SetWindowLong32A (toolPtr->hwnd,
482                     GWL_WNDPROC,(LONG)TOOLTIPS_SubclassProc);
483                 lpttsi->hwndToolTip = wndPtr->hwndSelf;
484                 lpttsi->uRefCount++;
485                 SetProp32A (toolPtr->hwnd, TT_SUBCLASS_PROP, (HANDLE32)lpttsi);
486             }
487             else
488                 lpttsi->uRefCount++;
489         }
490         TRACE (tooltips, "subclassing installed!\n");
491     }
492
493     return TRUE;
494 }
495
496
497 // << TOOLTIPS_AddTool32W >>
498
499
500 static LRESULT
501 TOOLTIPS_DelTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
502 {
503     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
504     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
505     TTTOOL_INFO *toolPtr;
506     INT32 nTool;
507
508     if (lpToolInfo == NULL)
509         return 0;
510     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
511         return 0;
512     if (infoPtr->uNumTools == 0)
513         return 0;
514
515     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
516     if (nTool == -1) return 0;
517
518     TRACE (tooltips, "tool %d\n", nTool);
519
520     /* delete text string */
521     toolPtr = &infoPtr->tools[nTool]; 
522     if ((toolPtr->hinst) && (toolPtr->lpszText)) {
523         if (toolPtr->lpszText != LPSTR_TEXTCALLBACK32A)
524             COMCTL32_Free (toolPtr->lpszText);
525     }
526
527     /* remove subclassing */
528     if (toolPtr->uFlags & TTF_SUBCLASS) {
529         if (toolPtr->uFlags & TTF_IDISHWND) {
530             LPTT_SUBCLASS_INFO lpttsi =
531                 (LPTT_SUBCLASS_INFO)GetProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
532             if (lpttsi) {
533                 SetWindowLong32A ((HWND32)toolPtr->uId, GWL_WNDPROC,
534                                   (LONG)lpttsi->wpOrigProc);
535                 RemoveProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
536                 COMCTL32_Free (&lpttsi);
537             }
538             else
539                 ERR (tooltips, "Invalid data handle!\n");
540         }
541         else {
542             LPTT_SUBCLASS_INFO lpttsi =
543                 (LPTT_SUBCLASS_INFO)GetProp32A (toolPtr->hwnd, TT_SUBCLASS_PROP);
544             if (lpttsi) {
545                 if (lpttsi->uRefCount == 1) {
546                     SetWindowLong32A ((HWND32)toolPtr->uId, GWL_WNDPROC,
547                                       (LONG)lpttsi->wpOrigProc);
548                     RemoveProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
549                     COMCTL32_Free (&lpttsi);
550                 }
551                 else
552                     lpttsi->uRefCount--;
553             }
554             else
555                 ERR (tooltips, "Invalid data handle!\n");
556         }
557     }
558
559     /* delete tool from tool list */
560     if (infoPtr->uNumTools == 1) {
561         COMCTL32_Free (infoPtr->tools);
562         infoPtr->tools = NULL;
563     }
564     else {
565         TTTOOL_INFO *oldTools = infoPtr->tools;
566         infoPtr->tools =
567             COMCTL32_Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
568
569         if (nTool > 0)
570             memcpy (&infoPtr->tools[0], &oldTools[0],
571                     nTool * sizeof(TTTOOL_INFO));
572
573         if (nTool < infoPtr->uNumTools - 1)
574             memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
575                     (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
576
577         COMCTL32_Free (oldTools);
578     }
579
580     infoPtr->uNumTools--;
581
582     return 0;
583 }
584
585
586 // << TOOLTIPS_DelTool32W >>
587
588
589 static LRESULT
590 TOOLTIPS_EnumTools32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
591 {
592     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
593     UINT32 uIndex = (UINT32)wParam;
594     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
595     TTTOOL_INFO *toolPtr;
596
597     if (lpToolInfo == NULL)
598         return FALSE;
599     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
600         return FALSE;
601     if (uIndex >= infoPtr->uNumTools)
602         return FALSE;
603
604     TRACE (tooltips, "index=%u\n", uIndex);
605
606     toolPtr = &infoPtr->tools[uIndex];
607
608     /* copy tool data */
609     lpToolInfo->uFlags   = toolPtr->uFlags;
610     lpToolInfo->hwnd     = toolPtr->hwnd;
611     lpToolInfo->uId      = toolPtr->uId;
612     lpToolInfo->rect     = toolPtr->rect;
613     lpToolInfo->hinst    = toolPtr->hinst;
614     lpToolInfo->lpszText = toolPtr->lpszText;
615
616     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
617         lpToolInfo->lParam = toolPtr->lParam;
618
619     return TRUE;
620 }
621
622
623 // << TOOLTIPS_EnumTools32W >>
624
625
626 static LRESULT
627 TOOLTIPS_GetCurrentTool32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
628 {
629     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
630     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
631     TTTOOL_INFO *toolPtr;
632
633     if (lpToolInfo == NULL)
634         return FALSE;
635     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
636         return FALSE;
637
638     if (lpToolInfo) {
639         if (infoPtr->nCurrentTool > -1) {
640             toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
641
642             /* copy tool data */
643             lpToolInfo->uFlags   = toolPtr->uFlags;
644             lpToolInfo->rect     = toolPtr->rect;
645             lpToolInfo->hinst    = toolPtr->hinst;
646             lpToolInfo->lpszText = toolPtr->lpszText;
647
648             if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
649                 lpToolInfo->lParam = toolPtr->lParam;
650
651             return TRUE;
652         }
653         else
654             return FALSE;
655     }
656     else
657         return (infoPtr->nCurrentTool != -1);
658
659     return FALSE;
660 }
661
662
663 // << TOOLTIPS_GetCurrentTool32W >>
664
665
666 static LRESULT
667 TOOLTIPS_GetDelayTime (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
668 {
669     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
670
671     switch (wParam) {
672         case TTDT_AUTOMATIC:
673             return infoPtr->nAutomaticTime;
674
675         case TTDT_RESHOW:
676             return infoPtr->nReshowTime;
677
678         case TTDT_AUTOPOP:
679             return infoPtr->nAutoPopTime;
680
681         case TTDT_INITIAL:
682             return infoPtr->nInitialTime;
683     }
684
685     return 0;
686 }
687
688
689 static LRESULT
690 TOOLTIPS_GetMargin (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
691 {
692     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
693     LPRECT32 lpRect = (LPRECT32)lParam;
694
695     lpRect->left   = infoPtr->rcMargin.left;
696     lpRect->right  = infoPtr->rcMargin.right;
697     lpRect->bottom = infoPtr->rcMargin.bottom;
698     lpRect->top    = infoPtr->rcMargin.top;
699
700     return 0;
701 }
702
703
704 __inline__ static LRESULT
705 TOOLTIPS_GetMaxTipWidth (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
706 {
707     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
708
709     return infoPtr->nMaxTipWidth;
710 }
711
712
713 static LRESULT
714 TOOLTIPS_GetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
715 {
716     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
717     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
718     INT32 nTool;
719
720     if (lpToolInfo == NULL)
721         return 0;
722     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
723         return 0;
724
725     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
726     if (nTool == -1) return 0;
727
728     lstrcpy32A (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText);
729
730     return 0;
731 }
732
733
734 // << TOOLTIPS_GetText32W >>
735
736
737 __inline__ static LRESULT
738 TOOLTIPS_GetTipBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
739 {
740     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
741     return infoPtr->clrBk;
742 }
743
744
745 __inline__ static LRESULT
746 TOOLTIPS_GetTipTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
747 {
748     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
749     return infoPtr->clrText;
750 }
751
752
753 __inline__ static LRESULT
754 TOOLTIPS_GetToolCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
755 {
756     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
757     return infoPtr->uNumTools;
758 }
759
760
761 static LRESULT
762 TOOLTIPS_GetToolInfo32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
763 {
764     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
765     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
766     TTTOOL_INFO *toolPtr;
767     INT32 nTool;
768
769     if (lpToolInfo == NULL)
770         return FALSE;
771     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
772         return FALSE;
773     if (infoPtr->uNumTools == 0)
774         return FALSE;
775
776     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
777     if (nTool == -1) return FALSE;
778
779     TRACE (tooltips, "tool %d\n", nTool);
780
781     toolPtr = &infoPtr->tools[nTool];
782
783     /* copy tool data */
784     lpToolInfo->uFlags   = toolPtr->uFlags;
785     lpToolInfo->rect     = toolPtr->rect;
786     lpToolInfo->hinst    = toolPtr->hinst;
787     lpToolInfo->lpszText = toolPtr->lpszText;
788
789     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
790         lpToolInfo->lParam = toolPtr->lParam;
791
792     return TRUE;
793 }
794
795
796 // << TOOLTIPS_GetToolInfo32W >>
797
798
799 static LRESULT
800 TOOLTIPS_HitTest32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
801 {
802     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
803     LPTTHITTESTINFO32A lptthit = (LPTTHITTESTINFO32A)lParam;
804     TTTOOL_INFO *toolPtr;
805     INT32 nTool;
806
807     if (lptthit == 0)
808         return FALSE;
809
810     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
811     if (nTool == -1)
812         return FALSE;
813
814     TRACE (tooltips, "tool %d!\n", nTool);
815
816     /* copy tool data */
817     toolPtr = &infoPtr->tools[nTool];
818     lptthit->ti.cbSize   = sizeof(TTTOOLINFO32A);
819     lptthit->ti.uFlags   = toolPtr->uFlags;
820     lptthit->ti.hwnd     = toolPtr->hwnd;
821     lptthit->ti.uId      = toolPtr->uId;
822     lptthit->ti.rect     = toolPtr->rect;
823     lptthit->ti.hinst    = toolPtr->hinst;
824     lptthit->ti.lpszText = toolPtr->lpszText;
825     lptthit->ti.lParam   = toolPtr->lParam;
826
827     return TRUE;
828 }
829
830
831 // << TOOLTIPS_HitTest32W >>
832
833
834 static LRESULT
835 TOOLTIPS_NewToolRect32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
836 {
837     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
838     LPTTTOOLINFO32A lpti = (LPTTTOOLINFO32A)lParam;
839     INT32 nTool;
840
841     if (lpti == NULL)
842         return 0;
843     if (lpti->cbSize < TTTOOLINFO_V1_SIZE32A)
844         return FALSE;
845
846     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
847     if (nTool == -1) return 0;
848
849     infoPtr->tools[nTool].rect = lpti->rect;
850
851     return 0;
852 }
853
854
855 // << TOOLTIPS_NewToolRect32W >>
856
857
858 __inline__ static LRESULT
859 TOOLTIPS_Pop (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
860 {
861     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
862
863     TOOLTIPS_Hide (wndPtr, infoPtr);
864
865     return 0;
866 }
867
868
869 static LRESULT
870 TOOLTIPS_RelayEvent (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
871 {
872     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
873     LPMSG32 lpMsg = (LPMSG32)lParam;
874     POINT32 pt;
875
876     if (lParam == 0) {
877         ERR (tooltips, "lpMsg == NULL!\n");
878         return 0;
879     }
880
881     switch (lpMsg->message) {
882         case WM_LBUTTONDOWN:
883         case WM_LBUTTONUP:
884         case WM_MBUTTONDOWN:
885         case WM_MBUTTONUP:
886         case WM_RBUTTONDOWN:
887         case WM_RBUTTONUP:
888             pt = lpMsg->pt;
889             ScreenToClient32 (lpMsg->hwnd, &pt);
890             infoPtr->nOldTool = infoPtr->nTool;
891             infoPtr->nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lpMsg->hwnd, &pt);
892             TRACE (tooltips, "tool (%x) %d %d\n",
893                    wndPtr->hwndSelf, infoPtr->nOldTool, infoPtr->nTool);
894             TOOLTIPS_Hide (wndPtr, infoPtr);
895             break;
896
897         case WM_MOUSEMOVE:
898             pt = lpMsg->pt;
899             ScreenToClient32 (lpMsg->hwnd, &pt);
900             infoPtr->nOldTool = infoPtr->nTool;
901             infoPtr->nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lpMsg->hwnd, &pt);
902             TRACE (tooltips, "tool (%x) %d %d\n",
903                    wndPtr->hwndSelf, infoPtr->nOldTool, infoPtr->nTool);
904             TRACE (tooltips, "WM_MOUSEMOVE (%04x %d %d)\n",
905                    wndPtr->hwndSelf, pt.x, pt.y);
906             if ((infoPtr->bActive) && (infoPtr->nTool != infoPtr->nOldTool)) {
907                 if (infoPtr->nOldTool == -1) {
908                     SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
909                                 infoPtr->nInitialTime, 0);
910                     TRACE (tooltips, "timer 1 started!\n");
911                 }
912                 else {
913                     TOOLTIPS_Hide (wndPtr, infoPtr);
914                     SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
915                                 infoPtr->nReshowTime, 0);
916                     TRACE (tooltips, "timer 2 started!\n");
917                 }
918             }
919             if (infoPtr->nCurrentTool != -1) {
920                 SetTimer32 (wndPtr->hwndSelf, ID_TIMER3, 100, 0);
921                 TRACE (tooltips, "timer 3 started!\n");
922             }
923             break;
924     }
925
926     return 0;
927 }
928
929
930 static LRESULT
931 TOOLTIPS_SetDelayTime (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
932 {
933     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
934     INT32 nTime = (INT32)LOWORD(lParam);
935
936     switch (wParam) {
937         case TTDT_AUTOMATIC:
938             if (nTime == 0) {
939                 infoPtr->nAutomaticTime = 500;
940                 infoPtr->nReshowTime    = 100;
941                 infoPtr->nAutoPopTime   = 5000;
942                 infoPtr->nInitialTime   = 500;
943             }
944             else {
945                 infoPtr->nAutomaticTime = nTime;
946                 infoPtr->nReshowTime    = nTime / 5;
947                 infoPtr->nAutoPopTime   = nTime * 10;
948                 infoPtr->nInitialTime   = nTime;
949             }
950             break;
951
952         case TTDT_RESHOW:
953             infoPtr->nReshowTime = nTime;
954             break;
955
956         case TTDT_AUTOPOP:
957             infoPtr->nAutoPopTime = nTime;
958             break;
959
960         case TTDT_INITIAL:
961             infoPtr->nInitialTime = nTime;
962             break;
963     }
964
965     return 0;
966 }
967
968
969 static LRESULT
970 TOOLTIPS_SetMargin (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
971 {
972     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
973     LPRECT32 lpRect = (LPRECT32)lParam;
974
975     infoPtr->rcMargin.left   = lpRect->left;
976     infoPtr->rcMargin.right  = lpRect->right;
977     infoPtr->rcMargin.bottom = lpRect->bottom;
978     infoPtr->rcMargin.top    = lpRect->top;
979
980     return 0;
981 }
982
983
984 __inline__ static LRESULT
985 TOOLTIPS_SetMaxTipWidth (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
986 {
987     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
988     INT32 nTemp = infoPtr->nMaxTipWidth;
989
990     infoPtr->nMaxTipWidth = (INT32)lParam;
991
992     return nTemp;
993 }
994
995
996 __inline__ static LRESULT
997 TOOLTIPS_SetTipBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
998 {
999     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1000
1001     infoPtr->clrBk = (COLORREF)wParam;
1002
1003     return 0;
1004 }
1005
1006
1007 __inline__ static LRESULT
1008 TOOLTIPS_SetTipTextColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1009 {
1010     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1011
1012     infoPtr->clrText = (COLORREF)wParam;
1013
1014     return 0;
1015 }
1016
1017
1018 static LRESULT
1019 TOOLTIPS_SetToolInfo32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1020 {
1021     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1022     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
1023     TTTOOL_INFO *toolPtr;
1024     INT32 nTool;
1025
1026     if (lpToolInfo == NULL)
1027         return 0;
1028     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
1029         return 0;
1030
1031     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1032     if (nTool == -1) return 0;
1033
1034     TRACE (tooltips, "tool %d\n", nTool);
1035
1036     toolPtr = &infoPtr->tools[nTool];
1037
1038     /* copy tool data */
1039     toolPtr->uFlags = lpToolInfo->uFlags;
1040     toolPtr->hwnd   = lpToolInfo->hwnd;
1041     toolPtr->uId    = lpToolInfo->uId;
1042     toolPtr->rect   = lpToolInfo->rect;
1043     toolPtr->hinst  = lpToolInfo->hinst;
1044
1045     if (lpToolInfo->hinst) {
1046         toolPtr->lpszText = lpToolInfo->lpszText;
1047     }
1048     else if (lpToolInfo->lpszText) {
1049         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A)
1050             toolPtr->lpszText = lpToolInfo->lpszText;
1051         else {
1052             INT32 len = lstrlen32A (lpToolInfo->lpszText);
1053             COMCTL32_Free (toolPtr->lpszText);
1054             toolPtr->lpszText = COMCTL32_Alloc (len + 1);
1055             lstrcpy32A (toolPtr->lpszText, lpToolInfo->lpszText);
1056         }
1057     }
1058
1059     if (lpToolInfo->cbSize >= sizeof(TTTOOLINFO32A))
1060         toolPtr->lParam = lpToolInfo->lParam;
1061
1062     return 0;
1063 }
1064
1065
1066 // << TOOLTIPS_SetToolInfo32W >>
1067
1068
1069 static LRESULT
1070 TOOLTIPS_TrackActivate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1071 {
1072     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1073     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
1074
1075     if (lpToolInfo == NULL)
1076         return 0;
1077     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
1078         return FALSE;
1079
1080     if ((BOOL32)wParam) {
1081         /* activate */
1082         infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1083         if (infoPtr->nTrackTool != -1) {
1084             infoPtr->bTrackActive = TRUE;
1085
1086             /* FIXME : show tool tip ??? */
1087         }
1088     }
1089     else {
1090         /* deactivate */
1091         /* FIXME : hide tool tip ??? */
1092
1093         infoPtr->bTrackActive = FALSE;
1094         infoPtr->nTrackTool = -1;
1095     }
1096
1097     return 0;
1098 }
1099
1100
1101 static LRESULT
1102 TOOLTIPS_TrackPosition (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1103 {
1104     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1105
1106     infoPtr->xTrackPos = (INT32)LOWORD(lParam);
1107     infoPtr->yTrackPos = (INT32)HIWORD(lParam);
1108
1109     if (infoPtr->bTrackActive) {
1110
1111         FIXME (tooltips, "set position!\n");
1112     }
1113
1114     return 0;
1115 }
1116
1117
1118 static LRESULT
1119 TOOLTIPS_Update (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1120 {
1121     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1122
1123     if (infoPtr->nCurrentTool != -1)
1124         UpdateWindow32 (wndPtr->hwndSelf);
1125
1126     return 0;
1127 }
1128
1129
1130 static LRESULT
1131 TOOLTIPS_UpdateTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1132 {
1133     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1134     LPTTTOOLINFO32A lpToolInfo = (LPTTTOOLINFO32A)lParam;
1135     TTTOOL_INFO *toolPtr;
1136     INT32 nTool;
1137
1138     if (lpToolInfo == NULL)
1139         return 0;
1140     if (lpToolInfo->cbSize < TTTOOLINFO_V1_SIZE32A)
1141         return FALSE;
1142
1143     nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1144     if (nTool == -1) return 0;
1145
1146     TRACE (tooltips, "tool %d\n", nTool);
1147
1148     toolPtr = &infoPtr->tools[nTool];
1149
1150     /* copy tool text */
1151     toolPtr->hinst  = lpToolInfo->hinst;
1152
1153     if (lpToolInfo->hinst) {
1154         toolPtr->lpszText = lpToolInfo->lpszText;
1155     }
1156     else if (lpToolInfo->lpszText) {
1157         if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACK32A)
1158             toolPtr->lpszText = lpToolInfo->lpszText;
1159         else {
1160             INT32 len = lstrlen32A (lpToolInfo->lpszText);
1161             COMCTL32_Free (toolPtr->lpszText);
1162             toolPtr->lpszText = COMCTL32_Alloc (len + 1);
1163             lstrcpy32A (toolPtr->lpszText, lpToolInfo->lpszText);
1164         }
1165     }
1166
1167     return 0;
1168 }
1169
1170
1171 // << TOOLTIPS_UpdateTipText32W >>
1172
1173
1174 static LRESULT
1175 TOOLTIPS_WindowFromPoint (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1176 {
1177     return WindowFromPoint32 (*((LPPOINT32)lParam));
1178 }
1179
1180
1181
1182 static LRESULT
1183 TOOLTIPS_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1184 {
1185     TOOLTIPS_INFO *infoPtr;
1186     NONCLIENTMETRICS32A nclm;
1187
1188     /* allocate memory for info structure */
1189     infoPtr = (TOOLTIPS_INFO *)COMCTL32_Alloc (sizeof(TOOLTIPS_INFO));
1190     wndPtr->wExtra[0] = (DWORD)infoPtr;
1191
1192     if (infoPtr == NULL) {
1193         ERR (tooltips, "could not allocate info memory!\n");
1194         return 0;
1195     }
1196
1197     /* initialize info structure */
1198     infoPtr->bActive = TRUE;
1199     infoPtr->bTrackActive = FALSE;
1200     infoPtr->clrBk   = GetSysColor32 (COLOR_INFOBK);
1201     infoPtr->clrText = GetSysColor32 (COLOR_INFOTEXT);
1202
1203     nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
1204     SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
1205     infoPtr->hFont = CreateFontIndirect32A (&nclm.lfStatusFont);
1206
1207     infoPtr->nMaxTipWidth = -1;
1208     infoPtr->nTool = -1;
1209     infoPtr->nOldTool = -1;
1210     infoPtr->nCurrentTool = -1;
1211     infoPtr->nTrackTool = -1;
1212
1213     infoPtr->nAutomaticTime = 500;
1214     infoPtr->nReshowTime    = 100;
1215     infoPtr->nAutoPopTime   = 5000;
1216     infoPtr->nInitialTime   = 500;
1217
1218     SetWindowPos32 (wndPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
1219                     SWP_NOZORDER | SWP_HIDEWINDOW);
1220
1221     return 0;
1222 }
1223
1224
1225 static LRESULT
1226 TOOLTIPS_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1227 {
1228     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1229     TTTOOL_INFO *toolPtr;
1230     INT32 i;
1231
1232     /* free tools */
1233     if (infoPtr->tools) {
1234         for (i = 0; i < infoPtr->uNumTools; i++) {
1235             toolPtr = &infoPtr->tools[i];
1236             if ((toolPtr->hinst) && (toolPtr->lpszText)) {
1237                 if (toolPtr->lpszText != LPSTR_TEXTCALLBACK32A)
1238                     COMCTL32_Free (toolPtr->lpszText);
1239             }
1240
1241             /* remove subclassing */
1242             if (toolPtr->uFlags & TTF_SUBCLASS) {
1243                 LPTT_SUBCLASS_INFO lpttsi;
1244
1245                 if (toolPtr->uFlags & TTF_IDISHWND)
1246                     lpttsi = (LPTT_SUBCLASS_INFO)GetProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
1247                 else
1248                     lpttsi = (LPTT_SUBCLASS_INFO)GetProp32A (toolPtr->hwnd, TT_SUBCLASS_PROP);
1249
1250                 if (lpttsi) {
1251                     SetWindowLong32A ((HWND32)toolPtr->uId, GWL_WNDPROC,
1252                                       (LONG)lpttsi->wpOrigProc);
1253                     RemoveProp32A ((HWND32)toolPtr->uId, TT_SUBCLASS_PROP);
1254                     COMCTL32_Free (&lpttsi);
1255                 }
1256             }
1257         }
1258         COMCTL32_Free (infoPtr->tools);
1259     }
1260
1261     /* delete font */
1262     DeleteObject32 (infoPtr->hFont);
1263
1264     /* free tool tips info data */
1265     COMCTL32_Free (infoPtr);
1266
1267     return 0;
1268 }
1269
1270
1271 static LRESULT
1272 TOOLTIPS_EraseBackground (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1273 {
1274     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1275     RECT32 rect;
1276     HBRUSH32 hBrush;
1277
1278     hBrush = CreateSolidBrush32 (infoPtr->clrBk);
1279     GetClientRect32 (wndPtr->hwndSelf, &rect);
1280     FillRect32 ((HDC32)wParam, &rect, hBrush);
1281     DeleteObject32 (hBrush);
1282
1283     return FALSE;
1284 }
1285
1286
1287 static LRESULT
1288 TOOLTIPS_GetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1289 {
1290     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1291
1292     return infoPtr->hFont;
1293 }
1294
1295
1296 static LRESULT
1297 TOOLTIPS_MouseMove (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1298 {
1299     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1300     TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nTool];
1301
1302     if (toolPtr->uFlags & TTF_TRANSPARENT) {
1303 #if 0
1304         POINT32 pt;
1305         RECT32  rc;
1306
1307         pt.x = (INT32)LOWORD(lParam);
1308         pt.y = (INT32)HIWORD(lParam);
1309
1310         GetClientRect32 (toolPtr->hwnd, &rc);
1311         ScreenToClient32 (toolPtr->hwnd, &pt);
1312         if (PtInRect32 (&rc, pt))
1313             SendMessage32A (toolPtr->hwnd, WM_MOUSEMOVE, wParam, lParam);
1314 #endif
1315     }
1316     else
1317         TOOLTIPS_Hide (wndPtr, infoPtr);
1318
1319     return 0;
1320 }
1321
1322
1323 static LRESULT
1324 TOOLTIPS_NcCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1325 {
1326     wndPtr->dwStyle &= 0x0000FFFF;
1327     wndPtr->dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
1328
1329 //    FIXME (tooltips, "style 0x%08x\n", wndPtr->dwStyle);
1330 //    SetParent32 (wndPtr->hwndSelf, NULL);
1331
1332     return TRUE;
1333 }
1334
1335
1336 static LRESULT
1337 TOOLTIPS_Paint (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1338 {
1339     HDC32 hdc;
1340     PAINTSTRUCT32 ps;
1341
1342     hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1343     TOOLTIPS_Refresh (wndPtr, hdc);
1344     if (!wParam)
1345         EndPaint32 (wndPtr->hwndSelf, &ps);
1346     return 0;
1347 }
1348
1349
1350 static LRESULT
1351 TOOLTIPS_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1352 {
1353     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1354
1355     infoPtr->hFont = (HFONT32)wParam;
1356
1357     if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
1358         FIXME (tooltips, "full redraw needed!\n");
1359     }
1360
1361     return 0;
1362 }
1363
1364
1365 static LRESULT
1366 TOOLTIPS_Timer (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1367 {
1368     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1369
1370     TRACE (tooltips, "timer %d (%x) expired!\n", wParam, wndPtr->hwndSelf);
1371
1372     switch (wParam)
1373     {
1374         case ID_TIMER1:
1375             KillTimer32 (wndPtr->hwndSelf, ID_TIMER1);
1376             if (TOOLTIPS_CheckTool (wndPtr, TRUE) == infoPtr->nTool)
1377                 TOOLTIPS_Show (wndPtr, infoPtr);
1378             break;
1379
1380         case ID_TIMER2:
1381             TOOLTIPS_Hide (wndPtr, infoPtr);
1382             break;
1383
1384         case ID_TIMER3:
1385             KillTimer32 (wndPtr->hwndSelf, ID_TIMER3);
1386             if (TOOLTIPS_CheckTool (wndPtr, FALSE) == -1) {
1387                 infoPtr->nTool = -1;
1388                 infoPtr->nOldTool = -1;
1389                 TOOLTIPS_Hide (wndPtr, infoPtr);
1390             }
1391             break;
1392     }
1393     return 0;
1394 }
1395
1396
1397 static LRESULT
1398 TOOLTIPS_WinIniChange (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1399 {
1400     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1401     NONCLIENTMETRICS32A nclm;
1402
1403     infoPtr->clrBk   = GetSysColor32 (COLOR_INFOBK);
1404     infoPtr->clrText = GetSysColor32 (COLOR_INFOTEXT);
1405
1406     DeleteObject32 (infoPtr->hFont);
1407     nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
1408     SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
1409     infoPtr->hFont = CreateFontIndirect32A (&nclm.lfStatusFont);
1410
1411     return 0;
1412 }
1413
1414
1415 LRESULT CALLBACK
1416 TOOLTIPS_SubclassProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1417 {
1418     LPTT_SUBCLASS_INFO lpttsi =
1419         (LPTT_SUBCLASS_INFO)GetProp32A (hwnd, TT_SUBCLASS_PROP);
1420     WND *wndPtr;
1421     TOOLTIPS_INFO *infoPtr;
1422     UINT32 nTool;
1423
1424     switch (uMsg) {
1425         case WM_LBUTTONDOWN:
1426         case WM_LBUTTONUP:
1427         case WM_MBUTTONDOWN:
1428         case WM_MBUTTONUP:
1429         case WM_RBUTTONDOWN:
1430         case WM_RBUTTONUP:
1431             {
1432                 wndPtr = WIN_FindWndPtr(lpttsi->hwndToolTip);
1433                 infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1434                 nTool = TOOLTIPS_GetToolFromMessage (infoPtr, hwnd);
1435
1436                 TRACE (tooltips, "subclassed mouse message %04x\n", uMsg);
1437                 infoPtr->nOldTool = infoPtr->nTool;
1438                 infoPtr->nTool = nTool;
1439                 TOOLTIPS_Hide (wndPtr, infoPtr);
1440             }
1441             break;
1442
1443         case WM_MOUSEMOVE:
1444             {
1445                 wndPtr = WIN_FindWndPtr(lpttsi->hwndToolTip);
1446                 infoPtr = TOOLTIPS_GetInfoPtr(wndPtr);
1447                 nTool = TOOLTIPS_GetToolFromMessage (infoPtr, hwnd);
1448
1449                 TRACE (tooltips, "subclassed WM_MOUSEMOVE\n");
1450                 infoPtr->nOldTool = infoPtr->nTool;
1451                 infoPtr->nTool = nTool;
1452
1453                 if ((infoPtr->bActive) &&
1454                     (infoPtr->nTool != infoPtr->nOldTool)) {
1455                     if (infoPtr->nOldTool == -1) {
1456                         SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
1457                                     infoPtr->nInitialTime, 0);
1458                         TRACE (tooltips, "timer 1 started!\n");
1459                     }
1460                     else {
1461                         TOOLTIPS_Hide (wndPtr, infoPtr);
1462                         SetTimer32 (wndPtr->hwndSelf, ID_TIMER1,
1463                                 infoPtr->nReshowTime, 0);
1464                         TRACE (tooltips, "timer 2 started!\n");
1465                     }
1466                 }
1467                 if (infoPtr->nCurrentTool != -1) {
1468                     SetTimer32 (wndPtr->hwndSelf, ID_TIMER3, 100, 0);
1469                     TRACE (tooltips, "timer 3 started!\n");
1470                 }
1471             }
1472             break;
1473     }
1474
1475     return CallWindowProc32A (lpttsi->wpOrigProc, hwnd, uMsg, wParam, lParam);
1476 }
1477
1478
1479 LRESULT CALLBACK
1480 TOOLTIPS_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
1481 {
1482     WND *wndPtr = WIN_FindWndPtr(hwnd);
1483
1484     switch (uMsg)
1485     {
1486         case TTM_ACTIVATE:
1487             return TOOLTIPS_Activate (wndPtr, wParam, lParam);
1488
1489         case TTM_ADDTOOL32A:
1490             return TOOLTIPS_AddTool32A (wndPtr, wParam, lParam);
1491
1492 //      case TTM_ADDTOOL32W:
1493
1494         case TTM_DELTOOL32A:
1495             return TOOLTIPS_DelTool32A (wndPtr, wParam, lParam);
1496
1497 //      case TTM_DELTOOL32W:
1498
1499         case TTM_ENUMTOOLS32A:
1500             return TOOLTIPS_EnumTools32A (wndPtr, wParam, lParam);
1501
1502 //      case TTM_ENUMTOOLS32W:
1503
1504         case TTM_GETCURRENTTOOL32A:
1505             return TOOLTIPS_GetCurrentTool32A (wndPtr, wParam, lParam);
1506
1507 //      case TTM_GETCURRENTTOOL32W:
1508
1509         case TTM_GETDELAYTIME:
1510             return TOOLTIPS_GetDelayTime (wndPtr, wParam, lParam);
1511
1512         case TTM_GETMARGIN:
1513             return TOOLTIPS_GetMargin (wndPtr, wParam, lParam);
1514
1515         case TTM_GETMAXTIPWIDTH:
1516             return TOOLTIPS_GetMaxTipWidth (wndPtr, wParam, lParam);
1517
1518         case TTM_GETTEXT32A:
1519             return TOOLTIPS_GetText32A (wndPtr, wParam, lParam);
1520
1521 //      case TTM_GETTEXT32W:
1522
1523         case TTM_GETTIPBKCOLOR:
1524             return TOOLTIPS_GetTipBkColor (wndPtr, wParam, lParam);
1525
1526         case TTM_GETTIPTEXTCOLOR:
1527             return TOOLTIPS_GetTipTextColor (wndPtr, wParam, lParam);
1528
1529         case TTM_GETTOOLCOUNT:
1530             return TOOLTIPS_GetToolCount (wndPtr, wParam, lParam);
1531
1532         case TTM_GETTOOLINFO32A:
1533             return TOOLTIPS_GetToolInfo32A (wndPtr, wParam, lParam);
1534
1535 //      case TTM_GETTOOLINFO32W:
1536
1537         case TTM_HITTEST32A:
1538             return TOOLTIPS_HitTest32A (wndPtr, wParam, lParam);
1539
1540 //      case TTM_HITTEST32W:
1541
1542         case TTM_NEWTOOLRECT32A:
1543             return TOOLTIPS_NewToolRect32A (wndPtr, wParam, lParam);
1544
1545 //      case TTM_NEWTOOLRECT32W:
1546
1547         case TTM_POP:
1548             return TOOLTIPS_Pop (wndPtr, wParam, lParam);
1549
1550         case TTM_RELAYEVENT:
1551             return TOOLTIPS_RelayEvent (wndPtr, wParam, lParam);
1552
1553         case TTM_SETDELAYTIME:
1554             return TOOLTIPS_SetDelayTime (wndPtr, wParam, lParam);
1555
1556         case TTM_SETMARGIN:
1557             return TOOLTIPS_SetMargin (wndPtr, wParam, lParam);
1558
1559         case TTM_SETMAXTIPWIDTH:
1560             return TOOLTIPS_SetMaxTipWidth (wndPtr, wParam, lParam);
1561
1562         case TTM_SETTIPBKCOLOR:
1563             return TOOLTIPS_SetTipBkColor (wndPtr, wParam, lParam);
1564
1565         case TTM_SETTIPTEXTCOLOR:
1566             return TOOLTIPS_SetTipTextColor (wndPtr, wParam, lParam);
1567
1568         case TTM_SETTOOLINFO32A:
1569             return TOOLTIPS_SetToolInfo32A (wndPtr, wParam, lParam);
1570
1571 //      case TTM_SETTOOLINFO32W:
1572
1573         case TTM_TRACKACTIVATE:
1574             return TOOLTIPS_TrackActivate (wndPtr, wParam, lParam);
1575
1576         case TTM_TRACKPOSITION:
1577             return TOOLTIPS_TrackPosition (wndPtr, wParam, lParam);
1578
1579         case TTM_UPDATE:
1580             return TOOLTIPS_Update (wndPtr, wParam, lParam);
1581
1582         case TTM_UPDATETIPTEXT32A:
1583             return TOOLTIPS_UpdateTipText32A (wndPtr, wParam, lParam);
1584
1585 //      case TTM_UPDATETIPTEXT32W:
1586
1587         case TTM_WINDOWFROMPOINT:
1588             return TOOLTIPS_WindowFromPoint (wndPtr, wParam, lParam);
1589
1590
1591         case WM_CREATE:
1592             return TOOLTIPS_Create (wndPtr, wParam, lParam);
1593
1594         case WM_DESTROY:
1595             return TOOLTIPS_Destroy (wndPtr, wParam, lParam);
1596
1597         case WM_ERASEBKGND:
1598             return TOOLTIPS_EraseBackground (wndPtr, wParam, lParam);
1599
1600         case WM_GETFONT:
1601             return TOOLTIPS_GetFont (wndPtr, wParam, lParam);
1602
1603 //      case WM_GETTEXT:
1604 //      case WM_GETTEXTLENGTH:
1605 //      case WM_LBUTTONDOWN:
1606 //      case WM_MBUTTONDOWN:
1607
1608         case WM_MOUSEMOVE:
1609             return TOOLTIPS_MouseMove (wndPtr, wParam, lParam);
1610
1611         case WM_NCCREATE:
1612             return TOOLTIPS_NcCreate (wndPtr, wParam, lParam);
1613
1614 //      case WM_NCHITTEST:
1615 //      case WM_NOTIFYFORMAT:
1616
1617         case WM_PAINT:
1618             return TOOLTIPS_Paint (wndPtr, wParam, lParam);
1619
1620 //      case WM_PRINTCLIENT:
1621 //      case WM_RBUTTONDOWN:
1622
1623         case WM_SETFONT:
1624             return TOOLTIPS_SetFont (wndPtr, wParam, lParam);
1625
1626 //      case WM_STYLECHANGED:
1627
1628         case WM_TIMER:
1629             return TOOLTIPS_Timer (wndPtr, wParam, lParam);
1630
1631         case WM_WININICHANGE:
1632             return TOOLTIPS_WinIniChange (wndPtr, wParam, lParam);
1633
1634         default:
1635             if (uMsg >= WM_USER)
1636                 ERR (tooltips, "unknown msg %04x wp=%08x lp=%08lx\n",
1637                      uMsg, wParam, lParam);
1638             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
1639     }
1640     return 0;
1641 }
1642
1643
1644 void
1645 TOOLTIPS_Register (void)
1646 {
1647     WNDCLASS32A wndClass;
1648
1649     if (GlobalFindAtom32A (TOOLTIPS_CLASS32A)) return;
1650
1651     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1652     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1653     wndClass.lpfnWndProc   = (WNDPROC32)TOOLTIPS_WindowProc;
1654     wndClass.cbClsExtra    = 0;
1655     wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
1656     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
1657     wndClass.hbrBackground = 0;
1658     wndClass.lpszClassName = TOOLTIPS_CLASS32A;
1659  
1660     RegisterClass32A (&wndClass);
1661 }