ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

tooltips.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.