Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentooltips.c
Go to the documentation of this file.
00001 /* 00002 * Tool tip control 00003 * 00004 * Copyright 1998, 1999 Eric Kohl 00005 * Copyright 2004 Robert Shearman 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * NOTES 00022 * 00023 * This code was audited for completeness against the documented features 00024 * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman. 00025 * 00026 * Unless otherwise noted, we believe this code to be complete, as per 00027 * the specification mentioned above. 00028 * If you discover missing features or bugs please note them below. 00029 * 00030 * TODO: 00031 * - Custom draw support. 00032 * - Animation. 00033 * - Links. 00034 * - Messages: 00035 * o TTM_ADJUSTRECT 00036 * o TTM_GETTITLEA 00037 * o TTM_GETTTILEW 00038 * o TTM_POPUP 00039 * - Styles: 00040 * o TTS_NOANIMATE 00041 * o TTS_NOFADE 00042 * o TTS_CLOSE 00043 * 00044 * Testing: 00045 * - Run tests using Waite Group Windows95 API Bible Volume 2. 00046 * The second cdrom (chapter 3) contains executables activate.exe, 00047 * curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe, 00048 * hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe. 00049 * 00050 * Timer logic. 00051 * 00052 * One important point to remember is that tools don't necessarily get 00053 * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when 00054 * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because 00055 * here WM_MOUSEMOVEs only get sent when the cursor is inside the 00056 * client area. Therefore the only reliable way to know that the 00057 * cursor has left a tool is to keep a timer running and check the 00058 * position every time it expires. This is the role of timer 00059 * ID_TIMERLEAVE. 00060 * 00061 * 00062 * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start 00063 * ID_TIMERSHOW, if this times out and we're still in the tool we show 00064 * the tip. On showing a tip we start both ID_TIMERPOP and 00065 * ID_TIMERLEAVE. On hiding a tooltip we kill ID_TIMERPOP. 00066 * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE. If 00067 * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed. 00068 * ID_TIMERLEAVE remains running - this is important as we need to 00069 * determine when the cursor leaves the tool. 00070 * 00071 * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're 00072 * still in the tool do nothing (apart from restart ID_TIMERPOP if 00073 * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running). If we've 00074 * left the tool and entered another one then hide the tip and start 00075 * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE. If we're 00076 * outside all tools hide the tip and kill ID_TIMERLEAVE. On Relayed 00077 * mouse button messages hide the tip but leave ID_TIMERLEAVE running, 00078 * this again will let us keep track of when the cursor leaves the 00079 * tool. 00080 * 00081 * 00082 * infoPtr->nTool is the tool the mouse was on on the last relayed MM 00083 * or timer expiry or -1 if the mouse was not on a tool. 00084 * 00085 * infoPtr->nCurrentTool is the tool for which the tip is currently 00086 * displaying text for or -1 if the tip is not shown. Actually this 00087 * will only ever be infoPtr-nTool or -1, so it could be changed to a 00088 * BOOL. 00089 * 00090 */ 00091 00092 00093 00094 #include <stdarg.h> 00095 #include <string.h> 00096 00097 #include "windef.h" 00098 #include "winbase.h" 00099 #include "wine/unicode.h" 00100 #include "wingdi.h" 00101 #include "winuser.h" 00102 #include "winnls.h" 00103 #include "commctrl.h" 00104 #include "comctl32.h" 00105 #include "wine/debug.h" 00106 00107 WINE_DEFAULT_DEBUG_CHANNEL(tooltips); 00108 00109 static HICON hTooltipIcons[TTI_ERROR+1]; 00110 00111 typedef struct 00112 { 00113 UINT uFlags; 00114 HWND hwnd; 00115 BOOL bNotifyUnicode; 00116 UINT_PTR uId; 00117 RECT rect; 00118 HINSTANCE hinst; 00119 LPWSTR lpszText; 00120 LPARAM lParam; 00121 } TTTOOL_INFO; 00122 00123 00124 typedef struct 00125 { 00126 HWND hwndSelf; 00127 WCHAR szTipText[INFOTIPSIZE]; 00128 BOOL bActive; 00129 BOOL bTrackActive; 00130 UINT uNumTools; 00131 COLORREF clrBk; 00132 COLORREF clrText; 00133 HFONT hFont; 00134 HFONT hTitleFont; 00135 INT xTrackPos; 00136 INT yTrackPos; 00137 INT nMaxTipWidth; 00138 INT nTool; /* tool that mouse was on on last relayed mouse move */ 00139 INT nCurrentTool; 00140 INT nTrackTool; 00141 INT nReshowTime; 00142 INT nAutoPopTime; 00143 INT nInitialTime; 00144 RECT rcMargin; 00145 BOOL bToolBelow; 00146 LPWSTR pszTitle; 00147 HICON hTitleIcon; 00148 00149 TTTOOL_INFO *tools; 00150 } TOOLTIPS_INFO; 00151 00152 #define ID_TIMERSHOW 1 /* show delay timer */ 00153 #define ID_TIMERPOP 2 /* auto pop timer */ 00154 #define ID_TIMERLEAVE 3 /* tool leave timer */ 00155 00156 00157 #define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0)) 00158 00159 /* offsets from window edge to start of text */ 00160 #define NORMAL_TEXT_MARGIN 2 00161 #define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8) 00162 /* value used for CreateRoundRectRgn that specifies how much 00163 * each corner is curved */ 00164 #define BALLOON_ROUNDEDNESS 20 00165 #define BALLOON_STEMHEIGHT 13 00166 #define BALLOON_STEMWIDTH 10 00167 #define BALLOON_STEMINDENT 20 00168 00169 #define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */ 00170 #define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */ 00171 #define ICON_HEIGHT 16 00172 #define ICON_WIDTH 16 00173 00174 static LRESULT CALLBACK 00175 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef); 00176 00177 00178 static inline BOOL TOOLTIPS_IsCallbackString(LPCWSTR str, BOOL isW) 00179 { 00180 if (isW) 00181 return str == LPSTR_TEXTCALLBACKW; 00182 else 00183 return (LPCSTR)str == LPSTR_TEXTCALLBACKA; 00184 } 00185 00186 static inline UINT_PTR 00187 TOOLTIPS_GetTitleIconIndex(HICON hIcon) 00188 { 00189 UINT i; 00190 for (i = 0; i <= TTI_ERROR; i++) 00191 if (hTooltipIcons[i] == hIcon) 00192 return i; 00193 return (UINT_PTR)hIcon; 00194 } 00195 00196 static void 00197 TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr) 00198 { 00199 NONCLIENTMETRICSW nclm; 00200 00201 infoPtr->clrBk = comctl32_color.clrInfoBk; 00202 infoPtr->clrText = comctl32_color.clrInfoText; 00203 00204 DeleteObject (infoPtr->hFont); 00205 nclm.cbSize = sizeof(nclm); 00206 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0); 00207 infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont); 00208 00209 DeleteObject (infoPtr->hTitleFont); 00210 nclm.lfStatusFont.lfWeight = FW_BOLD; 00211 infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont); 00212 } 00213 00214 /* Custom draw routines */ 00215 static void 00216 TOOLTIPS_customdraw_fill(const TOOLTIPS_INFO *infoPtr, NMTTCUSTOMDRAW *lpnmttcd, 00217 HDC hdc, const RECT *rcBounds, UINT uFlags) 00218 { 00219 ZeroMemory(lpnmttcd, sizeof(NMTTCUSTOMDRAW)); 00220 lpnmttcd->uDrawFlags = uFlags; 00221 lpnmttcd->nmcd.hdr.hwndFrom = infoPtr->hwndSelf; 00222 lpnmttcd->nmcd.hdr.code = NM_CUSTOMDRAW; 00223 if (infoPtr->nCurrentTool != -1) { 00224 TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; 00225 lpnmttcd->nmcd.hdr.idFrom = toolPtr->uId; 00226 } 00227 lpnmttcd->nmcd.hdc = hdc; 00228 lpnmttcd->nmcd.rc = *rcBounds; 00229 /* FIXME - dwItemSpec, uItemState, lItemlParam */ 00230 } 00231 00232 static inline DWORD 00233 TOOLTIPS_notify_customdraw (DWORD dwDrawStage, NMTTCUSTOMDRAW *lpnmttcd) 00234 { 00235 LRESULT result = CDRF_DODEFAULT; 00236 lpnmttcd->nmcd.dwDrawStage = dwDrawStage; 00237 00238 TRACE("Notifying stage %d, flags %x, id %x\n", lpnmttcd->nmcd.dwDrawStage, 00239 lpnmttcd->uDrawFlags, lpnmttcd->nmcd.hdr.code); 00240 00241 result = SendMessageW(GetParent(lpnmttcd->nmcd.hdr.hwndFrom), WM_NOTIFY, 00242 0, (LPARAM)lpnmttcd); 00243 00244 TRACE("Notify result %x\n", (unsigned int)result); 00245 00246 return result; 00247 } 00248 00249 static void 00250 TOOLTIPS_Refresh (const TOOLTIPS_INFO *infoPtr, HDC hdc) 00251 { 00252 RECT rc; 00253 INT oldBkMode; 00254 HFONT hOldFont; 00255 HBRUSH hBrush; 00256 UINT uFlags = DT_EXTERNALLEADING; 00257 HRGN hRgn = NULL; 00258 DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); 00259 NMTTCUSTOMDRAW nmttcd; 00260 DWORD cdmode; 00261 00262 if (infoPtr->nMaxTipWidth > -1) 00263 uFlags |= DT_WORDBREAK; 00264 if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_NOPREFIX) 00265 uFlags |= DT_NOPREFIX; 00266 GetClientRect (infoPtr->hwndSelf, &rc); 00267 00268 hBrush = CreateSolidBrush(infoPtr->clrBk); 00269 00270 oldBkMode = SetBkMode (hdc, TRANSPARENT); 00271 SetTextColor (hdc, infoPtr->clrText); 00272 hOldFont = SelectObject (hdc, infoPtr->hFont); 00273 00274 /* Custom draw - Call PrePaint once initial properties set up */ 00275 /* Note: Contrary to MSDN, CDRF_SKIPDEFAULT still draws a tooltip */ 00276 TOOLTIPS_customdraw_fill(infoPtr, &nmttcd, hdc, &rc, uFlags); 00277 cdmode = TOOLTIPS_notify_customdraw(CDDS_PREPAINT, &nmttcd); 00278 uFlags = nmttcd.uDrawFlags; 00279 00280 if (dwStyle & TTS_BALLOON) 00281 { 00282 /* create a region to store result into */ 00283 hRgn = CreateRectRgn(0, 0, 0, 0); 00284 00285 GetWindowRgn(infoPtr->hwndSelf, hRgn); 00286 00287 /* fill the background */ 00288 FillRgn(hdc, hRgn, hBrush); 00289 DeleteObject(hBrush); 00290 hBrush = NULL; 00291 } 00292 else 00293 { 00294 /* fill the background */ 00295 FillRect(hdc, &rc, hBrush); 00296 DeleteObject(hBrush); 00297 hBrush = NULL; 00298 } 00299 00300 if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle) 00301 { 00302 /* calculate text rectangle */ 00303 rc.left += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left); 00304 rc.top += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top); 00305 rc.right -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right); 00306 rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom); 00307 if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT; 00308 00309 if (infoPtr->pszTitle) 00310 { 00311 RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom}; 00312 int height; 00313 BOOL icon_present; 00314 HFONT prevFont; 00315 00316 /* draw icon */ 00317 icon_present = infoPtr->hTitleIcon && 00318 DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon, 00319 ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL); 00320 if (icon_present) 00321 rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING; 00322 00323 rcTitle.bottom = rc.top + ICON_HEIGHT; 00324 00325 /* draw title text */ 00326 prevFont = SelectObject (hdc, infoPtr->hTitleFont); 00327 height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX); 00328 SelectObject (hdc, prevFont); 00329 rc.top += height + BALLOON_TITLE_TEXT_SPACING; 00330 } 00331 } 00332 else 00333 { 00334 /* calculate text rectangle */ 00335 rc.left += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left); 00336 rc.top += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top); 00337 rc.right -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right); 00338 rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom); 00339 } 00340 00341 /* draw text */ 00342 DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); 00343 00344 /* Custom draw - Call PostPaint after drawing */ 00345 if (cdmode & CDRF_NOTIFYPOSTPAINT) { 00346 TOOLTIPS_notify_customdraw(CDDS_POSTPAINT, &nmttcd); 00347 } 00348 00349 /* be polite and reset the things we changed in the dc */ 00350 SelectObject (hdc, hOldFont); 00351 SetBkMode (hdc, oldBkMode); 00352 00353 if (dwStyle & TTS_BALLOON) 00354 { 00355 /* frame region because default window proc doesn't do it */ 00356 INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE); 00357 INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE); 00358 00359 hBrush = GetSysColorBrush(COLOR_WINDOWFRAME); 00360 FrameRgn(hdc, hRgn, hBrush, width, height); 00361 } 00362 00363 if (hRgn) 00364 DeleteObject(hRgn); 00365 } 00366 00367 static void TOOLTIPS_GetDispInfoA(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer) 00368 { 00369 NMTTDISPINFOA ttnmdi; 00370 00371 /* fill NMHDR struct */ 00372 ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA)); 00373 ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf; 00374 ttnmdi.hdr.idFrom = toolPtr->uId; 00375 ttnmdi.hdr.code = TTN_GETDISPINFOA; /* == TTN_NEEDTEXTA */ 00376 ttnmdi.lpszText = ttnmdi.szText; 00377 ttnmdi.uFlags = toolPtr->uFlags; 00378 ttnmdi.lParam = toolPtr->lParam; 00379 00380 TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom); 00381 SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi); 00382 00383 if (IS_INTRESOURCE(ttnmdi.lpszText)) { 00384 LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText), 00385 buffer, INFOTIPSIZE); 00386 if (ttnmdi.uFlags & TTF_DI_SETITEM) { 00387 toolPtr->hinst = ttnmdi.hinst; 00388 toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText; 00389 } 00390 } 00391 else if (ttnmdi.lpszText == 0) { 00392 buffer[0] = '\0'; 00393 } 00394 else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) { 00395 Str_GetPtrAtoW(ttnmdi.lpszText, buffer, INFOTIPSIZE); 00396 if (ttnmdi.uFlags & TTF_DI_SETITEM) { 00397 toolPtr->hinst = 0; 00398 toolPtr->lpszText = NULL; 00399 Str_SetPtrW(&toolPtr->lpszText, buffer); 00400 } 00401 } 00402 else { 00403 ERR("recursive text callback!\n"); 00404 buffer[0] = '\0'; 00405 } 00406 00407 /* no text available - try calling parent instead as per native */ 00408 /* FIXME: Unsure if SETITEM should save the value or not */ 00409 if (buffer[0] == 0x00) { 00410 00411 SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi); 00412 00413 if (IS_INTRESOURCE(ttnmdi.lpszText)) { 00414 LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText), 00415 buffer, INFOTIPSIZE); 00416 } else if (ttnmdi.lpszText && 00417 ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) { 00418 Str_GetPtrAtoW(ttnmdi.lpszText, buffer, INFOTIPSIZE); 00419 } 00420 } 00421 } 00422 00423 static void TOOLTIPS_GetDispInfoW(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer) 00424 { 00425 NMTTDISPINFOW ttnmdi; 00426 00427 /* fill NMHDR struct */ 00428 ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW)); 00429 ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf; 00430 ttnmdi.hdr.idFrom = toolPtr->uId; 00431 ttnmdi.hdr.code = TTN_GETDISPINFOW; /* == TTN_NEEDTEXTW */ 00432 ttnmdi.lpszText = ttnmdi.szText; 00433 ttnmdi.uFlags = toolPtr->uFlags; 00434 ttnmdi.lParam = toolPtr->lParam; 00435 00436 TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom); 00437 SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi); 00438 00439 if (IS_INTRESOURCE(ttnmdi.lpszText)) { 00440 LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText), 00441 buffer, INFOTIPSIZE); 00442 if (ttnmdi.uFlags & TTF_DI_SETITEM) { 00443 toolPtr->hinst = ttnmdi.hinst; 00444 toolPtr->lpszText = ttnmdi.lpszText; 00445 } 00446 } 00447 else if (ttnmdi.lpszText == 0) { 00448 buffer[0] = '\0'; 00449 } 00450 else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) { 00451 Str_GetPtrW(ttnmdi.lpszText, buffer, INFOTIPSIZE); 00452 if (ttnmdi.uFlags & TTF_DI_SETITEM) { 00453 toolPtr->hinst = 0; 00454 toolPtr->lpszText = NULL; 00455 Str_SetPtrW(&toolPtr->lpszText, buffer); 00456 } 00457 } 00458 else { 00459 ERR("recursive text callback!\n"); 00460 buffer[0] = '\0'; 00461 } 00462 00463 /* no text available - try calling parent instead as per native */ 00464 /* FIXME: Unsure if SETITEM should save the value or not */ 00465 if (buffer[0] == 0x00) { 00466 00467 SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi); 00468 00469 if (IS_INTRESOURCE(ttnmdi.lpszText)) { 00470 LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText), 00471 buffer, INFOTIPSIZE); 00472 } else if (ttnmdi.lpszText && 00473 ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) { 00474 Str_GetPtrW(ttnmdi.lpszText, buffer, INFOTIPSIZE); 00475 } 00476 } 00477 00478 } 00479 00480 static void 00481 TOOLTIPS_GetTipText (const TOOLTIPS_INFO *infoPtr, INT nTool, WCHAR *buffer) 00482 { 00483 TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool]; 00484 00485 if (IS_INTRESOURCE(toolPtr->lpszText) && toolPtr->hinst) { 00486 /* load a resource */ 00487 TRACE("load res string %p %x\n", 00488 toolPtr->hinst, LOWORD(toolPtr->lpszText)); 00489 LoadStringW (toolPtr->hinst, LOWORD(toolPtr->lpszText), 00490 buffer, INFOTIPSIZE); 00491 } 00492 else if (toolPtr->lpszText) { 00493 if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) { 00494 if (toolPtr->bNotifyUnicode) 00495 TOOLTIPS_GetDispInfoW(infoPtr, toolPtr, buffer); 00496 else 00497 TOOLTIPS_GetDispInfoA(infoPtr, toolPtr, buffer); 00498 } 00499 else { 00500 /* the item is a usual (unicode) text */ 00501 lstrcpynW (buffer, toolPtr->lpszText, INFOTIPSIZE); 00502 } 00503 } 00504 else { 00505 /* no text available */ 00506 buffer[0] = '\0'; 00507 } 00508 00509 TRACE("%s\n", debugstr_w(buffer)); 00510 } 00511 00512 00513 static void 00514 TOOLTIPS_CalcTipSize (const TOOLTIPS_INFO *infoPtr, LPSIZE lpSize) 00515 { 00516 HDC hdc; 00517 HFONT hOldFont; 00518 DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); 00519 UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT; 00520 RECT rc = {0, 0, 0, 0}; 00521 SIZE title = {0, 0}; 00522 00523 if (infoPtr->nMaxTipWidth > -1) { 00524 rc.right = infoPtr->nMaxTipWidth; 00525 uFlags |= DT_WORDBREAK; 00526 } 00527 if (style & TTS_NOPREFIX) 00528 uFlags |= DT_NOPREFIX; 00529 TRACE("%s\n", debugstr_w(infoPtr->szTipText)); 00530 00531 hdc = GetDC (infoPtr->hwndSelf); 00532 if (infoPtr->pszTitle) 00533 { 00534 RECT rcTitle = {0, 0, 0, 0}; 00535 TRACE("title %s\n", debugstr_w(infoPtr->pszTitle)); 00536 if (infoPtr->hTitleIcon) 00537 { 00538 title.cx = ICON_WIDTH; 00539 title.cy = ICON_HEIGHT; 00540 } 00541 if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING; 00542 hOldFont = SelectObject (hdc, infoPtr->hTitleFont); 00543 DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); 00544 SelectObject (hdc, hOldFont); 00545 title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING; 00546 title.cx += (rcTitle.right - rcTitle.left); 00547 } 00548 hOldFont = SelectObject (hdc, infoPtr->hFont); 00549 DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); 00550 SelectObject (hdc, hOldFont); 00551 ReleaseDC (infoPtr->hwndSelf, hdc); 00552 00553 if ((style & TTS_BALLOON) || infoPtr->pszTitle) 00554 { 00555 lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN + 00556 infoPtr->rcMargin.left + infoPtr->rcMargin.right; 00557 lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN + 00558 infoPtr->rcMargin.bottom + infoPtr->rcMargin.top + 00559 BALLOON_STEMHEIGHT; 00560 } 00561 else 00562 { 00563 lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN + 00564 infoPtr->rcMargin.left + infoPtr->rcMargin.right; 00565 lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN + 00566 infoPtr->rcMargin.bottom + infoPtr->rcMargin.top; 00567 } 00568 } 00569 00570 00571 static void 00572 TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate) 00573 { 00574 TTTOOL_INFO *toolPtr; 00575 HMONITOR monitor; 00576 MONITORINFO mon_info; 00577 RECT rect; 00578 SIZE size; 00579 NMHDR hdr; 00580 int ptfx = 0; 00581 DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); 00582 INT nTool; 00583 00584 if (track_activate) 00585 { 00586 if (infoPtr->nTrackTool == -1) 00587 { 00588 TRACE("invalid tracking tool (-1)!\n"); 00589 return; 00590 } 00591 nTool = infoPtr->nTrackTool; 00592 } 00593 else 00594 { 00595 if (infoPtr->nTool == -1) 00596 { 00597 TRACE("invalid tool (-1)!\n"); 00598 return; 00599 } 00600 nTool = infoPtr->nTool; 00601 } 00602 00603 TRACE("Show tooltip pre %d! (%p)\n", nTool, infoPtr->hwndSelf); 00604 00605 TOOLTIPS_GetTipText (infoPtr, nTool, infoPtr->szTipText); 00606 00607 if (infoPtr->szTipText[0] == '\0') 00608 return; 00609 00610 toolPtr = &infoPtr->tools[nTool]; 00611 00612 if (!track_activate) 00613 infoPtr->nCurrentTool = infoPtr->nTool; 00614 00615 TRACE("Show tooltip %d!\n", nTool); 00616 00617 hdr.hwndFrom = infoPtr->hwndSelf; 00618 hdr.idFrom = toolPtr->uId; 00619 hdr.code = TTN_SHOW; 00620 SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr); 00621 00622 TRACE("%s\n", debugstr_w(infoPtr->szTipText)); 00623 00624 TOOLTIPS_CalcTipSize (infoPtr, &size); 00625 TRACE("size %d x %d\n", size.cx, size.cy); 00626 00627 if (track_activate) 00628 { 00629 rect.left = infoPtr->xTrackPos; 00630 rect.top = infoPtr->yTrackPos; 00631 ptfx = rect.left; 00632 00633 if (toolPtr->uFlags & TTF_CENTERTIP) 00634 { 00635 rect.left -= (size.cx / 2); 00636 if (!(style & TTS_BALLOON)) 00637 rect.top -= (size.cy / 2); 00638 } 00639 if (!(infoPtr->bToolBelow = (infoPtr->yTrackPos + size.cy <= GetSystemMetrics(SM_CYSCREEN)))) 00640 rect.top -= size.cy; 00641 00642 if (!(toolPtr->uFlags & TTF_ABSOLUTE)) 00643 { 00644 if (style & TTS_BALLOON) 00645 rect.left -= BALLOON_STEMINDENT; 00646 else 00647 { 00648 RECT rcTool; 00649 00650 if (toolPtr->uFlags & TTF_IDISHWND) 00651 GetWindowRect ((HWND)toolPtr->uId, &rcTool); 00652 else 00653 { 00654 rcTool = toolPtr->rect; 00655 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2); 00656 } 00657 00658 /* smart placement */ 00659 if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) && 00660 (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom)) 00661 rect.left = rcTool.right; 00662 } 00663 } 00664 } 00665 else 00666 { 00667 if (toolPtr->uFlags & TTF_CENTERTIP) 00668 { 00669 RECT rc; 00670 00671 if (toolPtr->uFlags & TTF_IDISHWND) 00672 GetWindowRect ((HWND)toolPtr->uId, &rc); 00673 else { 00674 rc = toolPtr->rect; 00675 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); 00676 } 00677 rect.left = (rc.left + rc.right - size.cx) / 2; 00678 if (style & TTS_BALLOON) 00679 { 00680 ptfx = rc.left + ((rc.right - rc.left) / 2); 00681 00682 /* CENTERTIP ballon tooltips default to below the field 00683 * if they fit on the screen */ 00684 if (rc.bottom + size.cy > GetSystemMetrics(SM_CYSCREEN)) 00685 { 00686 rect.top = rc.top - size.cy; 00687 infoPtr->bToolBelow = FALSE; 00688 } 00689 else 00690 { 00691 infoPtr->bToolBelow = TRUE; 00692 rect.top = rc.bottom; 00693 } 00694 rect.left = max(0, rect.left - BALLOON_STEMINDENT); 00695 } 00696 else 00697 { 00698 rect.top = rc.bottom + 2; 00699 infoPtr->bToolBelow = TRUE; 00700 } 00701 } 00702 else 00703 { 00704 GetCursorPos ((LPPOINT)&rect); 00705 if (style & TTS_BALLOON) 00706 { 00707 ptfx = rect.left; 00708 if(rect.top - size.cy >= 0) 00709 { 00710 rect.top -= size.cy; 00711 infoPtr->bToolBelow = FALSE; 00712 } 00713 else 00714 { 00715 infoPtr->bToolBelow = TRUE; 00716 rect.top += 20; 00717 } 00718 rect.left = max(0, rect.left - BALLOON_STEMINDENT); 00719 } 00720 else 00721 { 00722 rect.top += 20; 00723 infoPtr->bToolBelow = TRUE; 00724 } 00725 } 00726 } 00727 00728 TRACE("pos %d - %d\n", rect.left, rect.top); 00729 00730 rect.right = rect.left + size.cx; 00731 rect.bottom = rect.top + size.cy; 00732 00733 /* check position */ 00734 00735 monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY ); 00736 mon_info.cbSize = sizeof(mon_info); 00737 GetMonitorInfoW( monitor, &mon_info ); 00738 00739 if( rect.right > mon_info.rcWork.right ) { 00740 rect.left -= rect.right - mon_info.rcWork.right + 2; 00741 rect.right = mon_info.rcWork.right - 2; 00742 } 00743 if (rect.left < mon_info.rcWork.left) rect.left = mon_info.rcWork.left; 00744 00745 if( rect.bottom > mon_info.rcWork.bottom ) { 00746 RECT rc; 00747 00748 if (toolPtr->uFlags & TTF_IDISHWND) 00749 GetWindowRect ((HWND)toolPtr->uId, &rc); 00750 else { 00751 rc = toolPtr->rect; 00752 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); 00753 } 00754 rect.bottom = rc.top - 2; 00755 rect.top = rect.bottom - size.cy; 00756 } 00757 00758 AdjustWindowRectEx (&rect, GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE), 00759 FALSE, GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE)); 00760 00761 if (style & TTS_BALLOON) 00762 { 00763 HRGN hRgn; 00764 HRGN hrStem; 00765 POINT pts[3]; 00766 00767 ptfx -= rect.left; 00768 00769 if(infoPtr->bToolBelow) 00770 { 00771 pts[0].x = ptfx; 00772 pts[0].y = 0; 00773 pts[1].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); 00774 pts[1].y = BALLOON_STEMHEIGHT; 00775 pts[2].x = pts[1].x + BALLOON_STEMWIDTH; 00776 pts[2].y = pts[1].y; 00777 if(pts[2].x > (rect.right - rect.left) - BALLOON_STEMINDENT) 00778 { 00779 pts[2].x = (rect.right - rect.left) - BALLOON_STEMINDENT; 00780 pts[1].x = pts[2].x - BALLOON_STEMWIDTH; 00781 } 00782 } 00783 else 00784 { 00785 pts[0].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); 00786 pts[0].y = (rect.bottom - rect.top) - BALLOON_STEMHEIGHT; 00787 pts[1].x = pts[0].x + BALLOON_STEMWIDTH; 00788 pts[1].y = pts[0].y; 00789 pts[2].x = ptfx; 00790 pts[2].y = (rect.bottom - rect.top); 00791 if(pts[1].x > (rect.right - rect.left) - BALLOON_STEMINDENT) 00792 { 00793 pts[1].x = (rect.right - rect.left) - BALLOON_STEMINDENT; 00794 pts[0].x = pts[1].x - BALLOON_STEMWIDTH; 00795 } 00796 } 00797 00798 hrStem = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE); 00799 00800 hRgn = CreateRoundRectRgn(0, 00801 (infoPtr->bToolBelow ? BALLOON_STEMHEIGHT : 0), 00802 rect.right - rect.left, 00803 (infoPtr->bToolBelow ? rect.bottom - rect.top : rect.bottom - rect.top - BALLOON_STEMHEIGHT), 00804 BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS); 00805 00806 CombineRgn(hRgn, hRgn, hrStem, RGN_OR); 00807 DeleteObject(hrStem); 00808 00809 SetWindowRgn(infoPtr->hwndSelf, hRgn, FALSE); 00810 /* we don't free the region handle as the system deletes it when 00811 * it is no longer needed */ 00812 } 00813 00814 SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, rect.left, rect.top, 00815 rect.right - rect.left, rect.bottom - rect.top, 00816 SWP_SHOWWINDOW | SWP_NOACTIVATE); 00817 00818 /* repaint the tooltip */ 00819 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 00820 UpdateWindow(infoPtr->hwndSelf); 00821 00822 if (!track_activate) 00823 { 00824 SetTimer (infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); 00825 TRACE("timer 2 started!\n"); 00826 SetTimer (infoPtr->hwndSelf, ID_TIMERLEAVE, infoPtr->nReshowTime, 0); 00827 TRACE("timer 3 started!\n"); 00828 } 00829 } 00830 00831 00832 static void 00833 TOOLTIPS_Hide (TOOLTIPS_INFO *infoPtr) 00834 { 00835 TTTOOL_INFO *toolPtr; 00836 NMHDR hdr; 00837 00838 TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, infoPtr->hwndSelf); 00839 00840 if (infoPtr->nCurrentTool == -1) 00841 return; 00842 00843 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; 00844 KillTimer (infoPtr->hwndSelf, ID_TIMERPOP); 00845 00846 hdr.hwndFrom = infoPtr->hwndSelf; 00847 hdr.idFrom = toolPtr->uId; 00848 hdr.code = TTN_POP; 00849 SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr); 00850 00851 infoPtr->nCurrentTool = -1; 00852 00853 SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0, 00854 SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); 00855 } 00856 00857 00858 static void 00859 TOOLTIPS_TrackShow (TOOLTIPS_INFO *infoPtr) 00860 { 00861 TOOLTIPS_Show(infoPtr, TRUE); 00862 } 00863 00864 00865 static void 00866 TOOLTIPS_TrackHide (const TOOLTIPS_INFO *infoPtr) 00867 { 00868 TTTOOL_INFO *toolPtr; 00869 NMHDR hdr; 00870 00871 TRACE("hide tracking tooltip %d\n", infoPtr->nTrackTool); 00872 00873 if (infoPtr->nTrackTool == -1) 00874 return; 00875 00876 toolPtr = &infoPtr->tools[infoPtr->nTrackTool]; 00877 00878 hdr.hwndFrom = infoPtr->hwndSelf; 00879 hdr.idFrom = toolPtr->uId; 00880 hdr.code = TTN_POP; 00881 SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr); 00882 00883 SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0, 00884 SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); 00885 } 00886 00887 /* Structure layout is the same for TTTOOLINFOW and TTTOOLINFOA, 00888 this helper is used in both cases. */ 00889 static INT 00890 TOOLTIPS_GetToolFromInfoT (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo) 00891 { 00892 TTTOOL_INFO *toolPtr; 00893 UINT nTool; 00894 00895 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { 00896 toolPtr = &infoPtr->tools[nTool]; 00897 00898 if (!(toolPtr->uFlags & TTF_IDISHWND) && 00899 (lpToolInfo->hwnd == toolPtr->hwnd) && 00900 (lpToolInfo->uId == toolPtr->uId)) 00901 return nTool; 00902 } 00903 00904 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { 00905 toolPtr = &infoPtr->tools[nTool]; 00906 00907 if ((toolPtr->uFlags & TTF_IDISHWND) && 00908 (lpToolInfo->uId == toolPtr->uId)) 00909 return nTool; 00910 } 00911 00912 return -1; 00913 } 00914 00915 00916 static INT 00917 TOOLTIPS_GetToolFromPoint (const TOOLTIPS_INFO *infoPtr, HWND hwnd, const POINT *lpPt) 00918 { 00919 TTTOOL_INFO *toolPtr; 00920 UINT nTool; 00921 00922 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { 00923 toolPtr = &infoPtr->tools[nTool]; 00924 00925 if (!(toolPtr->uFlags & TTF_IDISHWND)) { 00926 if (hwnd != toolPtr->hwnd) 00927 continue; 00928 if (!PtInRect (&toolPtr->rect, *lpPt)) 00929 continue; 00930 return nTool; 00931 } 00932 } 00933 00934 for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { 00935 toolPtr = &infoPtr->tools[nTool]; 00936 00937 if (toolPtr->uFlags & TTF_IDISHWND) { 00938 if ((HWND)toolPtr->uId == hwnd) 00939 return nTool; 00940 } 00941 } 00942 00943 return -1; 00944 } 00945 00946 00947 static BOOL 00948 TOOLTIPS_IsWindowActive (HWND hwnd) 00949 { 00950 HWND hwndActive = GetActiveWindow (); 00951 if (!hwndActive) 00952 return FALSE; 00953 if (hwndActive == hwnd) 00954 return TRUE; 00955 return IsChild (hwndActive, hwnd); 00956 } 00957 00958 00959 static INT 00960 TOOLTIPS_CheckTool (const TOOLTIPS_INFO *infoPtr, BOOL bShowTest) 00961 { 00962 POINT pt; 00963 HWND hwndTool; 00964 INT nTool; 00965 00966 GetCursorPos (&pt); 00967 hwndTool = (HWND)SendMessageW (infoPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt); 00968 if (hwndTool == 0) 00969 return -1; 00970 00971 ScreenToClient (hwndTool, &pt); 00972 nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt); 00973 if (nTool == -1) 00974 return -1; 00975 00976 if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) { 00977 if (!TOOLTIPS_IsWindowActive (GetWindow (infoPtr->hwndSelf, GW_OWNER))) 00978 return -1; 00979 } 00980 00981 TRACE("tool %d\n", nTool); 00982 00983 return nTool; 00984 } 00985 00986 00987 static LRESULT 00988 TOOLTIPS_Activate (TOOLTIPS_INFO *infoPtr, BOOL activate) 00989 { 00990 infoPtr->bActive = activate; 00991 00992 if (infoPtr->bActive) 00993 TRACE("activate!\n"); 00994 00995 if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1)) 00996 TOOLTIPS_Hide (infoPtr); 00997 00998 return 0; 00999 } 01000 01001 01002 static LRESULT 01003 TOOLTIPS_AddToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW) 01004 { 01005 TTTOOL_INFO *toolPtr; 01006 INT nResult; 01007 01008 if (!ti) return FALSE; 01009 01010 TRACE("add tool (%p) %p %ld%s!\n", 01011 infoPtr->hwndSelf, ti->hwnd, ti->uId, 01012 (ti->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : ""); 01013 01014 if (infoPtr->uNumTools == 0) { 01015 infoPtr->tools = Alloc (sizeof(TTTOOL_INFO)); 01016 toolPtr = infoPtr->tools; 01017 } 01018 else { 01019 TTTOOL_INFO *oldTools = infoPtr->tools; 01020 infoPtr->tools = 01021 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1)); 01022 memcpy (infoPtr->tools, oldTools, 01023 infoPtr->uNumTools * sizeof(TTTOOL_INFO)); 01024 Free (oldTools); 01025 toolPtr = &infoPtr->tools[infoPtr->uNumTools]; 01026 } 01027 01028 infoPtr->uNumTools++; 01029 01030 /* copy tool data */ 01031 toolPtr->uFlags = ti->uFlags; 01032 toolPtr->hwnd = ti->hwnd; 01033 toolPtr->uId = ti->uId; 01034 toolPtr->rect = ti->rect; 01035 toolPtr->hinst = ti->hinst; 01036 01037 if (IS_INTRESOURCE(ti->lpszText)) { 01038 TRACE("add string id %x\n", LOWORD(ti->lpszText)); 01039 toolPtr->lpszText = ti->lpszText; 01040 } 01041 else if (ti->lpszText) { 01042 if (TOOLTIPS_IsCallbackString(ti->lpszText, isW)) { 01043 TRACE("add CALLBACK!\n"); 01044 toolPtr->lpszText = LPSTR_TEXTCALLBACKW; 01045 } 01046 else if (isW) { 01047 INT len = lstrlenW (ti->lpszText); 01048 TRACE("add text %s!\n", debugstr_w(ti->lpszText)); 01049 toolPtr->lpszText = Alloc ((len + 1)*sizeof(WCHAR)); 01050 strcpyW (toolPtr->lpszText, ti->lpszText); 01051 } 01052 else { 01053 INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, NULL, 0); 01054 TRACE("add text \"%s\"!\n", (LPSTR)ti->lpszText); 01055 toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); 01056 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, toolPtr->lpszText, len); 01057 } 01058 } 01059 01060 if (ti->cbSize >= TTTOOLINFOW_V2_SIZE) 01061 toolPtr->lParam = ti->lParam; 01062 01063 /* install subclassing hook */ 01064 if (toolPtr->uFlags & TTF_SUBCLASS) { 01065 if (toolPtr->uFlags & TTF_IDISHWND) { 01066 SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1, 01067 (DWORD_PTR)infoPtr->hwndSelf); 01068 } 01069 else { 01070 SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1, 01071 (DWORD_PTR)infoPtr->hwndSelf); 01072 } 01073 TRACE("subclassing installed!\n"); 01074 } 01075 01076 nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, 01077 (WPARAM)infoPtr->hwndSelf, NF_QUERY); 01078 if (nResult == NFR_ANSI) { 01079 toolPtr->bNotifyUnicode = FALSE; 01080 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); 01081 } else if (nResult == NFR_UNICODE) { 01082 toolPtr->bNotifyUnicode = TRUE; 01083 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); 01084 } else { 01085 TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); 01086 } 01087 01088 return TRUE; 01089 } 01090 01091 01092 static LRESULT 01093 TOOLTIPS_DelToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW) 01094 { 01095 TTTOOL_INFO *toolPtr; 01096 INT nTool; 01097 01098 if (!ti) return 0; 01099 if (isW && ti->cbSize > TTTOOLINFOW_V2_SIZE && 01100 ti->cbSize != TTTOOLINFOW_V3_SIZE) 01101 return 0; 01102 if (infoPtr->uNumTools == 0) 01103 return 0; 01104 01105 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01106 01107 TRACE("tool %d\n", nTool); 01108 01109 if (nTool == -1) 01110 return 0; 01111 01112 /* make sure the tooltip has disappeared before deleting it */ 01113 TOOLTIPS_Hide(infoPtr); 01114 01115 /* delete text string */ 01116 toolPtr = &infoPtr->tools[nTool]; 01117 if (toolPtr->lpszText) { 01118 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && 01119 !IS_INTRESOURCE(toolPtr->lpszText) ) 01120 Free (toolPtr->lpszText); 01121 } 01122 01123 /* remove subclassing */ 01124 if (toolPtr->uFlags & TTF_SUBCLASS) { 01125 if (toolPtr->uFlags & TTF_IDISHWND) { 01126 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); 01127 } 01128 else { 01129 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); 01130 } 01131 } 01132 01133 /* delete tool from tool list */ 01134 if (infoPtr->uNumTools == 1) { 01135 Free (infoPtr->tools); 01136 infoPtr->tools = NULL; 01137 } 01138 else { 01139 TTTOOL_INFO *oldTools = infoPtr->tools; 01140 infoPtr->tools = 01141 Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1)); 01142 01143 if (nTool > 0) 01144 memcpy (&infoPtr->tools[0], &oldTools[0], 01145 nTool * sizeof(TTTOOL_INFO)); 01146 01147 if (nTool < infoPtr->uNumTools - 1) 01148 memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1], 01149 (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO)); 01150 01151 Free (oldTools); 01152 } 01153 01154 /* update any indices affected by delete */ 01155 01156 /* destroying tool that mouse was on on last relayed mouse move */ 01157 if (infoPtr->nTool == nTool) 01158 /* -1 means no current tool (0 means first tool) */ 01159 infoPtr->nTool = -1; 01160 else if (infoPtr->nTool > nTool) 01161 infoPtr->nTool--; 01162 01163 if (infoPtr->nTrackTool == nTool) 01164 /* -1 means no current tool (0 means first tool) */ 01165 infoPtr->nTrackTool = -1; 01166 else if (infoPtr->nTrackTool > nTool) 01167 infoPtr->nTrackTool--; 01168 01169 if (infoPtr->nCurrentTool == nTool) 01170 /* -1 means no current tool (0 means first tool) */ 01171 infoPtr->nCurrentTool = -1; 01172 else if (infoPtr->nCurrentTool > nTool) 01173 infoPtr->nCurrentTool--; 01174 01175 infoPtr->uNumTools--; 01176 01177 return 0; 01178 } 01179 01180 static LRESULT 01181 TOOLTIPS_EnumToolsT (const TOOLTIPS_INFO *infoPtr, UINT uIndex, TTTOOLINFOW *ti, 01182 BOOL isW) 01183 { 01184 TTTOOL_INFO *toolPtr; 01185 01186 if (!ti) return FALSE; 01187 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01188 return FALSE; 01189 if (uIndex >= infoPtr->uNumTools) 01190 return FALSE; 01191 01192 TRACE("index=%u\n", uIndex); 01193 01194 toolPtr = &infoPtr->tools[uIndex]; 01195 01196 /* copy tool data */ 01197 ti->uFlags = toolPtr->uFlags; 01198 ti->hwnd = toolPtr->hwnd; 01199 ti->uId = toolPtr->uId; 01200 ti->rect = toolPtr->rect; 01201 ti->hinst = toolPtr->hinst; 01202 /* ti->lpszText = toolPtr->lpszText; */ 01203 ti->lpszText = NULL; /* FIXME */ 01204 01205 if (ti->cbSize >= TTTOOLINFOA_V2_SIZE) 01206 ti->lParam = toolPtr->lParam; 01207 01208 return TRUE; 01209 } 01210 01211 static LRESULT 01212 TOOLTIPS_GetBubbleSize (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo) 01213 { 01214 INT nTool; 01215 SIZE size; 01216 01217 if (lpToolInfo == NULL) 01218 return FALSE; 01219 if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) 01220 return FALSE; 01221 01222 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, lpToolInfo); 01223 if (nTool == -1) return 0; 01224 01225 TRACE("tool %d\n", nTool); 01226 01227 TOOLTIPS_CalcTipSize (infoPtr, &size); 01228 TRACE("size %d x %d\n", size.cx, size.cy); 01229 01230 return MAKELRESULT(size.cx, size.cy); 01231 } 01232 01233 static LRESULT 01234 TOOLTIPS_GetCurrentToolT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW) 01235 { 01236 TTTOOL_INFO *toolPtr; 01237 01238 if (ti) { 01239 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01240 return FALSE; 01241 01242 if (infoPtr->nCurrentTool > -1) { 01243 toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; 01244 01245 /* copy tool data */ 01246 ti->uFlags = toolPtr->uFlags; 01247 ti->rect = toolPtr->rect; 01248 ti->hinst = toolPtr->hinst; 01249 /* ti->lpszText = toolPtr->lpszText; */ 01250 ti->lpszText = NULL; /* FIXME */ 01251 01252 if (ti->cbSize >= TTTOOLINFOW_V2_SIZE) 01253 ti->lParam = toolPtr->lParam; 01254 01255 return TRUE; 01256 } 01257 else 01258 return FALSE; 01259 } 01260 else 01261 return (infoPtr->nCurrentTool != -1); 01262 } 01263 01264 01265 static LRESULT 01266 TOOLTIPS_GetDelayTime (const TOOLTIPS_INFO *infoPtr, DWORD duration) 01267 { 01268 switch (duration) { 01269 case TTDT_RESHOW: 01270 return infoPtr->nReshowTime; 01271 01272 case TTDT_AUTOPOP: 01273 return infoPtr->nAutoPopTime; 01274 01275 case TTDT_INITIAL: 01276 case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */ 01277 return infoPtr->nInitialTime; 01278 01279 default: 01280 WARN("Invalid duration flag %x\n", duration); 01281 break; 01282 } 01283 01284 return -1; 01285 } 01286 01287 01288 static LRESULT 01289 TOOLTIPS_GetMargin (const TOOLTIPS_INFO *infoPtr, LPRECT lpRect) 01290 { 01291 lpRect->left = infoPtr->rcMargin.left; 01292 lpRect->right = infoPtr->rcMargin.right; 01293 lpRect->bottom = infoPtr->rcMargin.bottom; 01294 lpRect->top = infoPtr->rcMargin.top; 01295 01296 return 0; 01297 } 01298 01299 01300 static inline LRESULT 01301 TOOLTIPS_GetMaxTipWidth (const TOOLTIPS_INFO *infoPtr) 01302 { 01303 return infoPtr->nMaxTipWidth; 01304 } 01305 01306 01307 static LRESULT 01308 TOOLTIPS_GetTextT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW) 01309 { 01310 INT nTool; 01311 01312 if (!ti) return 0; 01313 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01314 return 0; 01315 01316 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01317 if (nTool == -1) return 0; 01318 01319 if (infoPtr->tools[nTool].lpszText == NULL) 01320 return 0; 01321 01322 if (isW) { 01323 ti->lpszText[0] = '\0'; 01324 TOOLTIPS_GetTipText(infoPtr, nTool, ti->lpszText); 01325 } 01326 else { 01327 WCHAR buffer[INFOTIPSIZE]; 01328 01329 /* NB this API is broken, there is no way for the app to determine 01330 what size buffer it requires nor a way to specify how long the 01331 one it supplies is. We'll assume it's up to INFOTIPSIZE */ 01332 01333 buffer[0] = '\0'; 01334 TOOLTIPS_GetTipText(infoPtr, nTool, buffer); 01335 WideCharToMultiByte(CP_ACP, 0, buffer, -1, (LPSTR)ti->lpszText, 01336 INFOTIPSIZE, NULL, NULL); 01337 } 01338 01339 return 0; 01340 } 01341 01342 01343 static inline LRESULT 01344 TOOLTIPS_GetTipBkColor (const TOOLTIPS_INFO *infoPtr) 01345 { 01346 return infoPtr->clrBk; 01347 } 01348 01349 01350 static inline LRESULT 01351 TOOLTIPS_GetTipTextColor (const TOOLTIPS_INFO *infoPtr) 01352 { 01353 return infoPtr->clrText; 01354 } 01355 01356 01357 static inline LRESULT 01358 TOOLTIPS_GetToolCount (const TOOLTIPS_INFO *infoPtr) 01359 { 01360 return infoPtr->uNumTools; 01361 } 01362 01363 01364 static LRESULT 01365 TOOLTIPS_GetToolInfoT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW) 01366 { 01367 TTTOOL_INFO *toolPtr; 01368 INT nTool; 01369 01370 if (!ti) return FALSE; 01371 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01372 return FALSE; 01373 if (infoPtr->uNumTools == 0) 01374 return FALSE; 01375 01376 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01377 if (nTool == -1) 01378 return FALSE; 01379 01380 TRACE("tool %d\n", nTool); 01381 01382 toolPtr = &infoPtr->tools[nTool]; 01383 01384 /* copy tool data */ 01385 ti->uFlags = toolPtr->uFlags; 01386 ti->rect = toolPtr->rect; 01387 ti->hinst = toolPtr->hinst; 01388 /* lpToolInfo->lpszText = toolPtr->lpszText; */ 01389 ti->lpszText = NULL; /* FIXME */ 01390 01391 if (ti->cbSize >= TTTOOLINFOW_V2_SIZE) 01392 ti->lParam = toolPtr->lParam; 01393 01394 return TRUE; 01395 } 01396 01397 01398 static LRESULT 01399 TOOLTIPS_HitTestT (const TOOLTIPS_INFO *infoPtr, LPTTHITTESTINFOW lptthit, 01400 BOOL isW) 01401 { 01402 TTTOOL_INFO *toolPtr; 01403 INT nTool; 01404 01405 if (lptthit == 0) 01406 return FALSE; 01407 01408 nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt); 01409 if (nTool == -1) 01410 return FALSE; 01411 01412 TRACE("tool %d!\n", nTool); 01413 01414 /* copy tool data */ 01415 if (lptthit->ti.cbSize >= TTTOOLINFOW_V1_SIZE) { 01416 toolPtr = &infoPtr->tools[nTool]; 01417 01418 lptthit->ti.uFlags = toolPtr->uFlags; 01419 lptthit->ti.hwnd = toolPtr->hwnd; 01420 lptthit->ti.uId = toolPtr->uId; 01421 lptthit->ti.rect = toolPtr->rect; 01422 lptthit->ti.hinst = toolPtr->hinst; 01423 /* lptthit->ti.lpszText = toolPtr->lpszText; */ 01424 lptthit->ti.lpszText = NULL; /* FIXME */ 01425 if (lptthit->ti.cbSize >= TTTOOLINFOW_V2_SIZE) 01426 lptthit->ti.lParam = toolPtr->lParam; 01427 } 01428 01429 return TRUE; 01430 } 01431 01432 01433 static LRESULT 01434 TOOLTIPS_NewToolRectT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti) 01435 { 01436 INT nTool; 01437 01438 if (!ti) return 0; 01439 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01440 return FALSE; 01441 01442 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01443 01444 TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&ti->rect)); 01445 01446 if (nTool == -1) return 0; 01447 01448 infoPtr->tools[nTool].rect = ti->rect; 01449 01450 return 0; 01451 } 01452 01453 01454 static inline LRESULT 01455 TOOLTIPS_Pop (TOOLTIPS_INFO *infoPtr) 01456 { 01457 TOOLTIPS_Hide (infoPtr); 01458 01459 return 0; 01460 } 01461 01462 01463 static LRESULT 01464 TOOLTIPS_RelayEvent (TOOLTIPS_INFO *infoPtr, LPMSG lpMsg) 01465 { 01466 POINT pt; 01467 INT nOldTool; 01468 01469 if (!lpMsg) { 01470 ERR("lpMsg == NULL!\n"); 01471 return 0; 01472 } 01473 01474 switch (lpMsg->message) { 01475 case WM_LBUTTONDOWN: 01476 case WM_LBUTTONUP: 01477 case WM_MBUTTONDOWN: 01478 case WM_MBUTTONUP: 01479 case WM_RBUTTONDOWN: 01480 case WM_RBUTTONUP: 01481 TOOLTIPS_Hide (infoPtr); 01482 break; 01483 01484 case WM_MOUSEMOVE: 01485 pt.x = (short)LOWORD(lpMsg->lParam); 01486 pt.y = (short)HIWORD(lpMsg->lParam); 01487 nOldTool = infoPtr->nTool; 01488 infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd, 01489 &pt); 01490 TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool, 01491 infoPtr->nTool, infoPtr->nCurrentTool); 01492 TRACE("WM_MOUSEMOVE (%p %d %d)\n", infoPtr->hwndSelf, pt.x, pt.y); 01493 01494 if (infoPtr->nTool != nOldTool) { 01495 if(infoPtr->nTool == -1) { /* Moved out of all tools */ 01496 TOOLTIPS_Hide(infoPtr); 01497 KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE); 01498 } else if (nOldTool == -1) { /* Moved from outside */ 01499 if(infoPtr->bActive) { 01500 SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0); 01501 TRACE("timer 1 started!\n"); 01502 } 01503 } else { /* Moved from one to another */ 01504 TOOLTIPS_Hide (infoPtr); 01505 KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE); 01506 if(infoPtr->bActive) { 01507 SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0); 01508 TRACE("timer 1 started!\n"); 01509 } 01510 } 01511 } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */ 01512 KillTimer(infoPtr->hwndSelf, ID_TIMERPOP); 01513 SetTimer(infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); 01514 TRACE("timer 2 restarted\n"); 01515 } else if(infoPtr->nTool != -1 && infoPtr->bActive) { 01516 /* previous show attempt didn't result in tooltip so try again */ 01517 SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0); 01518 TRACE("timer 1 started!\n"); 01519 } 01520 break; 01521 } 01522 01523 return 0; 01524 } 01525 01526 01527 static LRESULT 01528 TOOLTIPS_SetDelayTime (TOOLTIPS_INFO *infoPtr, DWORD duration, INT nTime) 01529 { 01530 switch (duration) { 01531 case TTDT_AUTOMATIC: 01532 if (nTime <= 0) 01533 nTime = GetDoubleClickTime(); 01534 infoPtr->nReshowTime = nTime / 5; 01535 infoPtr->nAutoPopTime = nTime * 10; 01536 infoPtr->nInitialTime = nTime; 01537 break; 01538 01539 case TTDT_RESHOW: 01540 if(nTime < 0) 01541 nTime = GetDoubleClickTime() / 5; 01542 infoPtr->nReshowTime = nTime; 01543 break; 01544 01545 case TTDT_AUTOPOP: 01546 if(nTime < 0) 01547 nTime = GetDoubleClickTime() * 10; 01548 infoPtr->nAutoPopTime = nTime; 01549 break; 01550 01551 case TTDT_INITIAL: 01552 if(nTime < 0) 01553 nTime = GetDoubleClickTime(); 01554 infoPtr->nInitialTime = nTime; 01555 break; 01556 01557 default: 01558 WARN("Invalid duration flag %x\n", duration); 01559 break; 01560 } 01561 01562 return 0; 01563 } 01564 01565 01566 static LRESULT 01567 TOOLTIPS_SetMargin (TOOLTIPS_INFO *infoPtr, const RECT *lpRect) 01568 { 01569 infoPtr->rcMargin.left = lpRect->left; 01570 infoPtr->rcMargin.right = lpRect->right; 01571 infoPtr->rcMargin.bottom = lpRect->bottom; 01572 infoPtr->rcMargin.top = lpRect->top; 01573 01574 return 0; 01575 } 01576 01577 01578 static inline LRESULT 01579 TOOLTIPS_SetMaxTipWidth (TOOLTIPS_INFO *infoPtr, INT MaxWidth) 01580 { 01581 INT nTemp = infoPtr->nMaxTipWidth; 01582 01583 infoPtr->nMaxTipWidth = MaxWidth; 01584 01585 return nTemp; 01586 } 01587 01588 01589 static inline LRESULT 01590 TOOLTIPS_SetTipBkColor (TOOLTIPS_INFO *infoPtr, COLORREF clrBk) 01591 { 01592 infoPtr->clrBk = clrBk; 01593 01594 return 0; 01595 } 01596 01597 01598 static inline LRESULT 01599 TOOLTIPS_SetTipTextColor (TOOLTIPS_INFO *infoPtr, COLORREF clrText) 01600 { 01601 infoPtr->clrText = clrText; 01602 01603 return 0; 01604 } 01605 01606 01607 static LRESULT 01608 TOOLTIPS_SetTitleT (TOOLTIPS_INFO *infoPtr, UINT_PTR uTitleIcon, LPCWSTR pszTitle, 01609 BOOL isW) 01610 { 01611 UINT size; 01612 01613 TRACE("hwnd = %p, title = %s, icon = %p\n", infoPtr->hwndSelf, debugstr_w(pszTitle), 01614 (void*)uTitleIcon); 01615 01616 Free(infoPtr->pszTitle); 01617 01618 if (pszTitle) 01619 { 01620 if (isW) 01621 { 01622 size = (strlenW(pszTitle)+1)*sizeof(WCHAR); 01623 infoPtr->pszTitle = Alloc(size); 01624 if (!infoPtr->pszTitle) 01625 return FALSE; 01626 memcpy(infoPtr->pszTitle, pszTitle, size); 01627 } 01628 else 01629 { 01630 size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, NULL, 0); 01631 infoPtr->pszTitle = Alloc(size); 01632 if (!infoPtr->pszTitle) 01633 return FALSE; 01634 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR)); 01635 } 01636 } 01637 else 01638 infoPtr->pszTitle = NULL; 01639 01640 if (uTitleIcon <= TTI_ERROR) 01641 infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; 01642 else 01643 infoPtr->hTitleIcon = CopyIcon((HICON)uTitleIcon); 01644 01645 TRACE("icon = %p\n", infoPtr->hTitleIcon); 01646 01647 return TRUE; 01648 } 01649 01650 01651 static LRESULT 01652 TOOLTIPS_SetToolInfoT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW) 01653 { 01654 TTTOOL_INFO *toolPtr; 01655 INT nTool; 01656 01657 if (!ti) return 0; 01658 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01659 return 0; 01660 01661 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01662 if (nTool == -1) return 0; 01663 01664 TRACE("tool %d\n", nTool); 01665 01666 toolPtr = &infoPtr->tools[nTool]; 01667 01668 /* copy tool data */ 01669 toolPtr->uFlags = ti->uFlags; 01670 toolPtr->hwnd = ti->hwnd; 01671 toolPtr->uId = ti->uId; 01672 toolPtr->rect = ti->rect; 01673 toolPtr->hinst = ti->hinst; 01674 01675 if (IS_INTRESOURCE(ti->lpszText)) { 01676 TRACE("set string id %x!\n", LOWORD(ti->lpszText)); 01677 toolPtr->lpszText = ti->lpszText; 01678 } 01679 else { 01680 if (TOOLTIPS_IsCallbackString(ti->lpszText, isW)) 01681 toolPtr->lpszText = LPSTR_TEXTCALLBACKW; 01682 else { 01683 if ( (toolPtr->lpszText) && 01684 !IS_INTRESOURCE(toolPtr->lpszText) ) { 01685 if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW) 01686 Free (toolPtr->lpszText); 01687 toolPtr->lpszText = NULL; 01688 } 01689 if (ti->lpszText) { 01690 if (isW) { 01691 INT len = lstrlenW (ti->lpszText); 01692 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); 01693 strcpyW (toolPtr->lpszText, ti->lpszText); 01694 } 01695 else { 01696 INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, 01697 -1, NULL, 0); 01698 toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); 01699 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, 01700 toolPtr->lpszText, len); 01701 } 01702 } 01703 } 01704 } 01705 01706 if (ti->cbSize >= TTTOOLINFOW_V2_SIZE) 01707 toolPtr->lParam = ti->lParam; 01708 01709 if (infoPtr->nCurrentTool == nTool) 01710 { 01711 TOOLTIPS_GetTipText (infoPtr, infoPtr->nCurrentTool, infoPtr->szTipText); 01712 01713 if (infoPtr->szTipText[0] == 0) 01714 TOOLTIPS_Hide(infoPtr); 01715 else 01716 TOOLTIPS_Show (infoPtr, FALSE); 01717 } 01718 01719 return 0; 01720 } 01721 01722 01723 static LRESULT 01724 TOOLTIPS_TrackActivate (TOOLTIPS_INFO *infoPtr, BOOL track_activate, const TTTOOLINFOA *ti) 01725 { 01726 if (track_activate) { 01727 01728 if (!ti) return 0; 01729 if (ti->cbSize < TTTOOLINFOA_V1_SIZE) 01730 return FALSE; 01731 01732 /* activate */ 01733 infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoT (infoPtr, (const TTTOOLINFOW*)ti); 01734 if (infoPtr->nTrackTool != -1) { 01735 TRACE("activated!\n"); 01736 infoPtr->bTrackActive = TRUE; 01737 TOOLTIPS_TrackShow (infoPtr); 01738 } 01739 } 01740 else { 01741 /* deactivate */ 01742 TOOLTIPS_TrackHide (infoPtr); 01743 01744 infoPtr->bTrackActive = FALSE; 01745 infoPtr->nTrackTool = -1; 01746 01747 TRACE("deactivated!\n"); 01748 } 01749 01750 return 0; 01751 } 01752 01753 01754 static LRESULT 01755 TOOLTIPS_TrackPosition (TOOLTIPS_INFO *infoPtr, LPARAM coord) 01756 { 01757 infoPtr->xTrackPos = (INT)LOWORD(coord); 01758 infoPtr->yTrackPos = (INT)HIWORD(coord); 01759 01760 if (infoPtr->bTrackActive) { 01761 TRACE("[%d %d]\n", 01762 infoPtr->xTrackPos, infoPtr->yTrackPos); 01763 01764 TOOLTIPS_TrackShow (infoPtr); 01765 } 01766 01767 return 0; 01768 } 01769 01770 01771 static LRESULT 01772 TOOLTIPS_Update (TOOLTIPS_INFO *infoPtr) 01773 { 01774 if (infoPtr->nCurrentTool != -1) 01775 UpdateWindow (infoPtr->hwndSelf); 01776 01777 return 0; 01778 } 01779 01780 01781 static LRESULT 01782 TOOLTIPS_UpdateTipTextT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW) 01783 { 01784 TTTOOL_INFO *toolPtr; 01785 INT nTool; 01786 01787 if (!ti) return 0; 01788 if (ti->cbSize < TTTOOLINFOW_V1_SIZE) 01789 return FALSE; 01790 01791 nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti); 01792 if (nTool == -1) 01793 return 0; 01794 01795 TRACE("tool %d\n", nTool); 01796 01797 toolPtr = &infoPtr->tools[nTool]; 01798 01799 /* copy tool text */ 01800 toolPtr->hinst = ti->hinst; 01801 01802 if (IS_INTRESOURCE(ti->lpszText)){ 01803 toolPtr->lpszText = ti->lpszText; 01804 } 01805 else if (ti->lpszText) { 01806 if (TOOLTIPS_IsCallbackString(ti->lpszText, isW)) 01807 toolPtr->lpszText = LPSTR_TEXTCALLBACKW; 01808 else { 01809 if ( (toolPtr->lpszText) && 01810 !IS_INTRESOURCE(toolPtr->lpszText) ) { 01811 if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW) 01812 Free (toolPtr->lpszText); 01813 toolPtr->lpszText = NULL; 01814 } 01815 if (ti->lpszText) { 01816 if (isW) { 01817 INT len = lstrlenW (ti->lpszText); 01818 toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); 01819 strcpyW (toolPtr->lpszText, ti->lpszText); 01820 } 01821 else { 01822 INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, 01823 -1, NULL, 0); 01824 toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); 01825 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, 01826 toolPtr->lpszText, len); 01827 } 01828 } 01829 } 01830 } 01831 01832 if(infoPtr->nCurrentTool == -1) return 0; 01833 /* force repaint */ 01834 if (infoPtr->bActive) 01835 TOOLTIPS_Show (infoPtr, FALSE); 01836 else if (infoPtr->bTrackActive) 01837 TOOLTIPS_Show (infoPtr, TRUE); 01838 01839 return 0; 01840 } 01841 01842 01843 static LRESULT 01844 TOOLTIPS_Create (HWND hwnd) 01845 { 01846 TOOLTIPS_INFO *infoPtr; 01847 01848 /* allocate memory for info structure */ 01849 infoPtr = Alloc (sizeof(TOOLTIPS_INFO)); 01850 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 01851 01852 /* initialize info structure */ 01853 infoPtr->bActive = TRUE; 01854 infoPtr->bTrackActive = FALSE; 01855 01856 infoPtr->nMaxTipWidth = -1; 01857 infoPtr->nTool = -1; 01858 infoPtr->nCurrentTool = -1; 01859 infoPtr->nTrackTool = -1; 01860 infoPtr->hwndSelf = hwnd; 01861 01862 /* initialize colours and fonts */ 01863 TOOLTIPS_InitSystemSettings(infoPtr); 01864 01865 TOOLTIPS_SetDelayTime(infoPtr, TTDT_AUTOMATIC, 0); 01866 01867 SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); 01868 01869 return 0; 01870 } 01871 01872 01873 static LRESULT 01874 TOOLTIPS_Destroy (TOOLTIPS_INFO *infoPtr) 01875 { 01876 TTTOOL_INFO *toolPtr; 01877 UINT i; 01878 01879 /* free tools */ 01880 if (infoPtr->tools) { 01881 for (i = 0; i < infoPtr->uNumTools; i++) { 01882 toolPtr = &infoPtr->tools[i]; 01883 if (toolPtr->lpszText) { 01884 if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && 01885 !IS_INTRESOURCE(toolPtr->lpszText) ) 01886 { 01887 Free (toolPtr->lpszText); 01888 toolPtr->lpszText = NULL; 01889 } 01890 } 01891 01892 /* remove subclassing */ 01893 if (toolPtr->uFlags & TTF_SUBCLASS) { 01894 if (toolPtr->uFlags & TTF_IDISHWND) { 01895 RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); 01896 } 01897 else { 01898 RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); 01899 } 01900 } 01901 } 01902 Free (infoPtr->tools); 01903 } 01904 01905 /* free title string */ 01906 Free (infoPtr->pszTitle); 01907 /* free title icon if not a standard one */ 01908 if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR) 01909 DeleteObject(infoPtr->hTitleIcon); 01910 01911 /* delete fonts */ 01912 DeleteObject (infoPtr->hFont); 01913 DeleteObject (infoPtr->hTitleFont); 01914 01915 /* free tool tips info data */ 01916 SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); 01917 Free (infoPtr); 01918 01919 return 0; 01920 } 01921 01922 01923 static inline LRESULT 01924 TOOLTIPS_GetFont (const TOOLTIPS_INFO *infoPtr) 01925 { 01926 return (LRESULT)infoPtr->hFont; 01927 } 01928 01929 01930 static LRESULT 01931 TOOLTIPS_MouseMessage (TOOLTIPS_INFO *infoPtr) 01932 { 01933 TOOLTIPS_Hide (infoPtr); 01934 01935 return 0; 01936 } 01937 01938 01939 static LRESULT 01940 TOOLTIPS_NCCreate (HWND hwnd) 01941 { 01942 DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); 01943 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); 01944 01945 dwStyle &= ~(WS_CHILD | /*WS_MAXIMIZE |*/ WS_BORDER | WS_DLGFRAME); 01946 dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS); 01947 01948 /* WS_BORDER only draws a border round the window rect, not the 01949 * window region, therefore it is useless to us in balloon mode */ 01950 if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER; 01951 01952 SetWindowLongW (hwnd, GWL_STYLE, dwStyle); 01953 01954 dwExStyle |= WS_EX_TOOLWINDOW; 01955 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); 01956 01957 return TRUE; 01958 } 01959 01960 01961 static LRESULT 01962 TOOLTIPS_NCHitTest (const TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 01963 { 01964 INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool; 01965 01966 TRACE(" nTool=%d\n", nTool); 01967 01968 if ((nTool > -1) && (nTool < infoPtr->uNumTools)) { 01969 if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) { 01970 TRACE("-- in transparent mode!\n"); 01971 return HTTRANSPARENT; 01972 } 01973 } 01974 01975 return DefWindowProcW (infoPtr->hwndSelf, WM_NCHITTEST, wParam, lParam); 01976 } 01977 01978 01979 static LRESULT 01980 TOOLTIPS_NotifyFormat (TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 01981 { 01982 TTTOOL_INFO *toolPtr = infoPtr->tools; 01983 LRESULT nResult; 01984 01985 TRACE("infoPtr=%p wParam=%lx lParam=%p\n", infoPtr, wParam, (PVOID)lParam); 01986 01987 if (lParam == NF_QUERY) { 01988 if (toolPtr->bNotifyUnicode) { 01989 return NFR_UNICODE; 01990 } else { 01991 return NFR_ANSI; 01992 } 01993 } 01994 else if (lParam == NF_REQUERY) { 01995 nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, 01996 (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY); 01997 if (nResult == NFR_ANSI) { 01998 toolPtr->bNotifyUnicode = FALSE; 01999 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); 02000 } else if (nResult == NFR_UNICODE) { 02001 toolPtr->bNotifyUnicode = TRUE; 02002 TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); 02003 } else { 02004 TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); 02005 } 02006 return nResult; 02007 } 02008 02009 return 0; 02010 } 02011 02012 02013 static LRESULT 02014 TOOLTIPS_Paint (const TOOLTIPS_INFO *infoPtr, HDC hDC) 02015 { 02016 HDC hdc; 02017 PAINTSTRUCT ps; 02018 02019 hdc = (hDC == NULL) ? BeginPaint (infoPtr->hwndSelf, &ps) : hDC; 02020 TOOLTIPS_Refresh (infoPtr, hdc); 02021 if (!hDC) 02022 EndPaint (infoPtr->hwndSelf, &ps); 02023 return 0; 02024 } 02025 02026 02027 static LRESULT 02028 TOOLTIPS_SetFont (TOOLTIPS_INFO *infoPtr, HFONT hFont, BOOL redraw) 02029 { 02030 LOGFONTW lf; 02031 02032 if(!GetObjectW(hFont, sizeof(lf), &lf)) 02033 return 0; 02034 02035 DeleteObject (infoPtr->hFont); 02036 infoPtr->hFont = CreateFontIndirectW(&lf); 02037 02038 DeleteObject (infoPtr->hTitleFont); 02039 lf.lfWeight = FW_BOLD; 02040 infoPtr->hTitleFont = CreateFontIndirectW(&lf); 02041 02042 if (redraw && infoPtr->nCurrentTool != -1) { 02043 FIXME("full redraw needed!\n"); 02044 } 02045 02046 return 0; 02047 } 02048 02049 /****************************************************************** 02050 * TOOLTIPS_GetTextLength 02051 * 02052 * This function is called when the tooltip receive a 02053 * WM_GETTEXTLENGTH message. 02054 * 02055 * returns the length, in characters, of the tip text 02056 */ 02057 static inline LRESULT 02058 TOOLTIPS_GetTextLength(const TOOLTIPS_INFO *infoPtr) 02059 { 02060 return strlenW(infoPtr->szTipText); 02061 } 02062 02063 /****************************************************************** 02064 * TOOLTIPS_OnWMGetText 02065 * 02066 * This function is called when the tooltip receive a 02067 * WM_GETTEXT message. 02068 * wParam : specifies the maximum number of characters to be copied 02069 * lParam : is the pointer to the buffer that will receive 02070 * the tip text 02071 * 02072 * returns the number of characters copied 02073 */ 02074 static LRESULT 02075 TOOLTIPS_OnWMGetText (const TOOLTIPS_INFO *infoPtr, WPARAM size, LPWSTR pszText) 02076 { 02077 LRESULT res; 02078 02079 if(!size) 02080 return 0; 02081 02082 res = min(strlenW(infoPtr->szTipText)+1, size); 02083 memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR)); 02084 pszText[res-1] = '\0'; 02085 return res-1; 02086 } 02087 02088 static LRESULT 02089 TOOLTIPS_Timer (TOOLTIPS_INFO *infoPtr, INT iTimer) 02090 { 02091 INT nOldTool; 02092 02093 TRACE("timer %d (%p) expired!\n", iTimer, infoPtr->hwndSelf); 02094 02095 switch (iTimer) { 02096 case ID_TIMERSHOW: 02097 KillTimer (infoPtr->hwndSelf, ID_TIMERSHOW); 02098 nOldTool = infoPtr->nTool; 02099 if ((infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, TRUE)) == nOldTool) 02100 TOOLTIPS_Show (infoPtr, FALSE); 02101 break; 02102 02103 case ID_TIMERPOP: 02104 TOOLTIPS_Hide (infoPtr); 02105 break; 02106 02107 case ID_TIMERLEAVE: 02108 nOldTool = infoPtr->nTool; 02109 infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, FALSE); 02110 TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool, 02111 infoPtr->nTool, infoPtr->nCurrentTool); 02112 if (infoPtr->nTool != nOldTool) { 02113 if(infoPtr->nTool == -1) { /* Moved out of all tools */ 02114 TOOLTIPS_Hide(infoPtr); 02115 KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE); 02116 } else if (nOldTool == -1) { /* Moved from outside */ 02117 ERR("How did this happen?\n"); 02118 } else { /* Moved from one to another */ 02119 TOOLTIPS_Hide (infoPtr); 02120 KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE); 02121 if(infoPtr->bActive) { 02122 SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0); 02123 TRACE("timer 1 started!\n"); 02124 } 02125 } 02126 } 02127 break; 02128 02129 default: 02130 ERR("Unknown timer id %d\n", iTimer); 02131 break; 02132 } 02133 return 0; 02134 } 02135 02136 02137 static LRESULT 02138 TOOLTIPS_WinIniChange (TOOLTIPS_INFO *infoPtr) 02139 { 02140 TOOLTIPS_InitSystemSettings (infoPtr); 02141 02142 return 0; 02143 } 02144 02145 02146 static LRESULT CALLBACK 02147 TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) 02148 { 02149 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr ((HWND)dwRef); 02150 MSG msg; 02151 02152 switch(uMsg) { 02153 case WM_MOUSEMOVE: 02154 case WM_LBUTTONDOWN: 02155 case WM_LBUTTONUP: 02156 case WM_MBUTTONDOWN: 02157 case WM_MBUTTONUP: 02158 case WM_RBUTTONDOWN: 02159 case WM_RBUTTONUP: 02160 msg.hwnd = hwnd; 02161 msg.message = uMsg; 02162 msg.wParam = wParam; 02163 msg.lParam = lParam; 02164 TOOLTIPS_RelayEvent(infoPtr, &msg); 02165 break; 02166 02167 default: 02168 break; 02169 } 02170 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 02171 } 02172 02173 02174 static LRESULT CALLBACK 02175 TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 02176 { 02177 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); 02178 02179 TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam); 02180 if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE)) 02181 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 02182 switch (uMsg) 02183 { 02184 case TTM_ACTIVATE: 02185 return TOOLTIPS_Activate (infoPtr, (BOOL)wParam); 02186 02187 case TTM_ADDTOOLA: 02188 case TTM_ADDTOOLW: 02189 return TOOLTIPS_AddToolT (infoPtr, (LPTTTOOLINFOW)lParam, uMsg == TTM_ADDTOOLW); 02190 02191 case TTM_DELTOOLA: 02192 case TTM_DELTOOLW: 02193 return TOOLTIPS_DelToolT (infoPtr, (LPTOOLINFOW)lParam, 02194 uMsg == TTM_DELTOOLW); 02195 case TTM_ENUMTOOLSA: 02196 case TTM_ENUMTOOLSW: 02197 return TOOLTIPS_EnumToolsT (infoPtr, (UINT)wParam, (LPTTTOOLINFOW)lParam, 02198 uMsg == TTM_ENUMTOOLSW); 02199 case TTM_GETBUBBLESIZE: 02200 return TOOLTIPS_GetBubbleSize (infoPtr, (LPTTTOOLINFOW)lParam); 02201 02202 case TTM_GETCURRENTTOOLA: 02203 case TTM_GETCURRENTTOOLW: 02204 return TOOLTIPS_GetCurrentToolT (infoPtr, (LPTTTOOLINFOW)lParam, 02205 uMsg == TTM_GETCURRENTTOOLW); 02206 02207 case TTM_GETDELAYTIME: 02208 return TOOLTIPS_GetDelayTime (infoPtr, (DWORD)wParam); 02209 02210 case TTM_GETMARGIN: 02211 return TOOLTIPS_GetMargin (infoPtr, (LPRECT)lParam); 02212 02213 case TTM_GETMAXTIPWIDTH: 02214 return TOOLTIPS_GetMaxTipWidth (infoPtr); 02215 02216 case TTM_GETTEXTA: 02217 case TTM_GETTEXTW: 02218 return TOOLTIPS_GetTextT (infoPtr, (LPTTTOOLINFOW)lParam, 02219 uMsg == TTM_GETTEXTW); 02220 02221 case TTM_GETTIPBKCOLOR: 02222 return TOOLTIPS_GetTipBkColor (infoPtr); 02223 02224 case TTM_GETTIPTEXTCOLOR: 02225 return TOOLTIPS_GetTipTextColor (infoPtr); 02226 02227 case TTM_GETTOOLCOUNT: 02228 return TOOLTIPS_GetToolCount (infoPtr); 02229 02230 case TTM_GETTOOLINFOA: 02231 case TTM_GETTOOLINFOW: 02232 return TOOLTIPS_GetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam, 02233 uMsg == TTM_GETTOOLINFOW); 02234 02235 case TTM_HITTESTA: 02236 case TTM_HITTESTW: 02237 return TOOLTIPS_HitTestT (infoPtr, (LPTTHITTESTINFOW)lParam, 02238 uMsg == TTM_HITTESTW); 02239 case TTM_NEWTOOLRECTA: 02240 case TTM_NEWTOOLRECTW: 02241 return TOOLTIPS_NewToolRectT (infoPtr, (LPTTTOOLINFOW)lParam); 02242 02243 case TTM_POP: 02244 return TOOLTIPS_Pop (infoPtr); 02245 02246 case TTM_RELAYEVENT: 02247 return TOOLTIPS_RelayEvent (infoPtr, (LPMSG)lParam); 02248 02249 case TTM_SETDELAYTIME: 02250 return TOOLTIPS_SetDelayTime (infoPtr, (DWORD)wParam, (INT)LOWORD(lParam)); 02251 02252 case TTM_SETMARGIN: 02253 return TOOLTIPS_SetMargin (infoPtr, (LPRECT)lParam); 02254 02255 case TTM_SETMAXTIPWIDTH: 02256 return TOOLTIPS_SetMaxTipWidth (infoPtr, (INT)lParam); 02257 02258 case TTM_SETTIPBKCOLOR: 02259 return TOOLTIPS_SetTipBkColor (infoPtr, (COLORREF)wParam); 02260 02261 case TTM_SETTIPTEXTCOLOR: 02262 return TOOLTIPS_SetTipTextColor (infoPtr, (COLORREF)wParam); 02263 02264 case TTM_SETTITLEA: 02265 case TTM_SETTITLEW: 02266 return TOOLTIPS_SetTitleT (infoPtr, (UINT_PTR)wParam, (LPCWSTR)lParam, 02267 uMsg == TTM_SETTITLEW); 02268 02269 case TTM_SETTOOLINFOA: 02270 case TTM_SETTOOLINFOW: 02271 return TOOLTIPS_SetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam, 02272 uMsg == TTM_SETTOOLINFOW); 02273 02274 case TTM_TRACKACTIVATE: 02275 return TOOLTIPS_TrackActivate (infoPtr, (BOOL)wParam, (LPTTTOOLINFOA)lParam); 02276 02277 case TTM_TRACKPOSITION: 02278 return TOOLTIPS_TrackPosition (infoPtr, lParam); 02279 02280 case TTM_UPDATE: 02281 return TOOLTIPS_Update (infoPtr); 02282 02283 case TTM_UPDATETIPTEXTA: 02284 case TTM_UPDATETIPTEXTW: 02285 return TOOLTIPS_UpdateTipTextT (infoPtr, (LPTTTOOLINFOW)lParam, 02286 uMsg == TTM_UPDATETIPTEXTW); 02287 02288 case TTM_WINDOWFROMPOINT: 02289 return (LRESULT)WindowFromPoint (*((LPPOINT)lParam)); 02290 02291 case WM_CREATE: 02292 return TOOLTIPS_Create (hwnd); 02293 02294 case WM_DESTROY: 02295 return TOOLTIPS_Destroy (infoPtr); 02296 02297 case WM_ERASEBKGND: 02298 /* we draw the background in WM_PAINT */ 02299 return 0; 02300 02301 case WM_GETFONT: 02302 return TOOLTIPS_GetFont (infoPtr); 02303 02304 case WM_GETTEXT: 02305 return TOOLTIPS_OnWMGetText (infoPtr, wParam, (LPWSTR)lParam); 02306 02307 case WM_GETTEXTLENGTH: 02308 return TOOLTIPS_GetTextLength (infoPtr); 02309 02310 case WM_LBUTTONDOWN: 02311 case WM_LBUTTONUP: 02312 case WM_MBUTTONDOWN: 02313 case WM_MBUTTONUP: 02314 case WM_RBUTTONDOWN: 02315 case WM_RBUTTONUP: 02316 case WM_MOUSEMOVE: 02317 return TOOLTIPS_MouseMessage (infoPtr); 02318 02319 case WM_NCCREATE: 02320 return TOOLTIPS_NCCreate (hwnd); 02321 02322 case WM_NCHITTEST: 02323 return TOOLTIPS_NCHitTest (infoPtr, wParam, lParam); 02324 02325 case WM_NOTIFYFORMAT: 02326 return TOOLTIPS_NotifyFormat (infoPtr, wParam, lParam); 02327 02328 case WM_PRINTCLIENT: 02329 case WM_PAINT: 02330 return TOOLTIPS_Paint (infoPtr, (HDC)wParam); 02331 02332 case WM_SETFONT: 02333 return TOOLTIPS_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); 02334 02335 case WM_SYSCOLORCHANGE: 02336 COMCTL32_RefreshSysColors(); 02337 return 0; 02338 02339 case WM_TIMER: 02340 return TOOLTIPS_Timer (infoPtr, (INT)wParam); 02341 02342 case WM_WININICHANGE: 02343 return TOOLTIPS_WinIniChange (infoPtr); 02344 02345 default: 02346 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 02347 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", 02348 uMsg, wParam, lParam); 02349 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 02350 } 02351 } 02352 02353 02354 VOID 02355 TOOLTIPS_Register (void) 02356 { 02357 WNDCLASSW wndClass; 02358 02359 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 02360 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS; 02361 wndClass.lpfnWndProc = TOOLTIPS_WindowProc; 02362 wndClass.cbClsExtra = 0; 02363 wndClass.cbWndExtra = sizeof(TOOLTIPS_INFO *); 02364 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 02365 wndClass.hbrBackground = 0; 02366 wndClass.lpszClassName = TOOLTIPS_CLASSW; 02367 02368 RegisterClassW (&wndClass); 02369 02370 hTooltipIcons[TTI_NONE] = NULL; 02371 hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule, 02372 (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0); 02373 hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule, 02374 (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0); 02375 hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule, 02376 (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0); 02377 } 02378 02379 02380 VOID 02381 TOOLTIPS_Unregister (void) 02382 { 02383 int i; 02384 for (i = TTI_INFO; i <= TTI_ERROR; i++) 02385 DestroyIcon(hTooltipIcons[i]); 02386 UnregisterClassW (TOOLTIPS_CLASSW, NULL); 02387 } Generated on Sun May 27 2012 04:23:05 for ReactOS by
1.7.6.1
|