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