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