tooltips.c 76.9 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Tool tip control
 *
4
 * Copyright 1998, 1999 Eric Kohl
Robert Shearman's avatar
Robert Shearman committed
5
 * Copyright 2004 Robert Shearman
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
 *
21 22
 * NOTES
 *
Robert Shearman's avatar
Robert Shearman committed
23 24 25 26 27 28 29
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features or bugs please note them below.
 * 
Alexandre Julliard's avatar
Alexandre Julliard committed
30
 * TODO:
Alexandre Julliard's avatar
Alexandre Julliard committed
31
 *   - Custom draw support.
Robert Shearman's avatar
Robert Shearman committed
32 33 34 35 36 37 38 39 40 41 42
 *   - Animation.
 *   - Links.
 *   - Messages:
 *     o TTM_ADJUSTRECT
 *     o TTM_GETTITLEA
 *     o TTM_GETTTILEW
 *     o TTM_POPUP
 *   - Styles:
 *     o TTS_NOANIMATE
 *     o TTS_NOFADE
 *     o TTS_CLOSE
Alexandre Julliard's avatar
Alexandre Julliard committed
43 44 45
 *
 * Testing:
 *   - Run tests using Waite Group Windows95 API Bible Volume 2.
Alexandre Julliard's avatar
Alexandre Julliard committed
46 47 48
 *     The second cdrom (chapter 3) contains executables activate.exe,
 *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
 *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
 *
 *   Timer logic.
 *
 * One important point to remember is that tools don't necessarily get
 * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when
 * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because
 * here WM_MOUSEMOVEs only get sent when the cursor is inside the
 * client area.  Therefore the only reliable way to know that the
 * cursor has left a tool is to keep a timer running and check the
 * position every time it expires.  This is the role of timer
 * ID_TIMERLEAVE.
 *
 *
 * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start
 * ID_TIMERSHOW, if this times out and we're still in the tool we show
 * the tip.  On showing a tip we start both ID_TIMERPOP and
 * ID_TIMERLEAVE.  On hiding a tooltip we kill ID_TIMERPOP.
 * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE.  If
 * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed.
 * ID_TIMERLEAVE remains running - this is important as we need to
 * determine when the cursor leaves the tool.
 *
 * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're
 * still in the tool do nothing (apart from restart ID_TIMERPOP if
 * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running).  If we've
 * left the tool and entered another one then hide the tip and start
 * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE.  If we're
 * outside all tools hide the tip and kill ID_TIMERLEAVE.  On Relayed
 * mouse button messages hide the tip but leave ID_TIMERLEAVE running,
 * this again will let us keep track of when the cursor leaves the
 * tool.
 *
 *
 * infoPtr->nTool is the tool the mouse was on on the last relayed MM
 * or timer expiry or -1 if the mouse was not on a tool.
84
 *
85 86 87 88 89
 * infoPtr->nCurrentTool is the tool for which the tip is currently
 * displaying text for or -1 if the tip is not shown.  Actually this
 * will only ever be infoPtr-nTool or -1, so it could be changed to a
 * BOOL.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
90
 */
91

92 93


94
#include <stdarg.h>
95
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
96

97
#include "windef.h"
98
#include "winbase.h"
99
#include "wine/unicode.h"
100 101 102
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
103
#include "commctrl.h"
104
#include "comctl32.h"
105
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
106

107
WINE_DEFAULT_DEBUG_CHANNEL(tooltips);
108

Robert Shearman's avatar
Robert Shearman committed
109 110
static HICON hTooltipIcons[TTI_ERROR+1];

111 112 113 114
typedef struct
{
    UINT      uFlags;
    HWND      hwnd;
115
    BOOL      bNotifyUnicode;
Frank Richter's avatar
Frank Richter committed
116
    UINT_PTR  uId;
117 118 119 120
    RECT      rect;
    HINSTANCE hinst;
    LPWSTR      lpszText;
    LPARAM      lParam;
121
} TTTOOL_INFO;
122 123 124 125 126 127 128 129 130 131 132


typedef struct
{
    WCHAR      szTipText[INFOTIPSIZE];
    BOOL     bActive;
    BOOL     bTrackActive;
    UINT     uNumTools;
    COLORREF   clrBk;
    COLORREF   clrText;
    HFONT    hFont;
Robert Shearman's avatar
Robert Shearman committed
133
    HFONT    hTitleFont;
134 135 136
    INT      xTrackPos;
    INT      yTrackPos;
    INT      nMaxTipWidth;
137
    INT      nTool; /* tool that mouse was on on last relayed mouse move */
138 139 140 141 142 143
    INT      nCurrentTool;
    INT      nTrackTool;
    INT      nReshowTime;
    INT      nAutoPopTime;
    INT      nInitialTime;
    RECT     rcMargin;
144
    BOOL     bToolBelow;
Robert Shearman's avatar
Robert Shearman committed
145 146
    LPWSTR   pszTitle;
    HICON    hTitleIcon;
147 148 149

    TTTOOL_INFO *tools;
} TOOLTIPS_INFO;
150

151 152 153
#define ID_TIMERSHOW   1    /* show delay timer */
#define ID_TIMERPOP    2    /* auto pop timer */
#define ID_TIMERLEAVE  3    /* tool leave timer */
Alexandre Julliard's avatar
Alexandre Julliard committed
154

155

156
#define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0))
Alexandre Julliard's avatar
Alexandre Julliard committed
157

158 159
/* offsets from window edge to start of text */
#define NORMAL_TEXT_MARGIN 2
160
#define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8)
161 162 163
/* value used for CreateRoundRectRgn that specifies how much
 * each corner is curved */
#define BALLOON_ROUNDEDNESS 20
164 165 166
#define BALLOON_STEMHEIGHT 13
#define BALLOON_STEMWIDTH 10
#define BALLOON_STEMINDENT 20
Alexandre Julliard's avatar
Alexandre Julliard committed
167

Robert Shearman's avatar
Robert Shearman committed
168 169 170 171 172
#define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */
#define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */
#define ICON_HEIGHT 16
#define ICON_WIDTH  16

Robert Shearman's avatar
Robert Shearman committed
173
static LRESULT CALLBACK
174
TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef);
Alexandre Julliard's avatar
Alexandre Julliard committed
175 176


177
static inline UINT_PTR
Robert Shearman's avatar
Robert Shearman committed
178
TOOLTIPS_GetTitleIconIndex(HICON hIcon)
Robert Shearman's avatar
Robert Shearman committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
{
    UINT i;
    for (i = 0; i <= TTI_ERROR; i++)
        if (hTooltipIcons[i] == hIcon)
            return i;
    return (UINT_PTR)hIcon;
}

static void
TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr)
{
    NONCLIENTMETRICSW nclm;

    infoPtr->clrBk   = GetSysColor (COLOR_INFOBK);
    infoPtr->clrText = GetSysColor (COLOR_INFOTEXT);

    DeleteObject (infoPtr->hFont);
    nclm.cbSize = sizeof(nclm);
197
    SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
Robert Shearman's avatar
Robert Shearman committed
198 199 200 201 202 203 204
    infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont);

    DeleteObject (infoPtr->hTitleFont);
    nclm.lfStatusFont.lfWeight = FW_BOLD;
    infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont);
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
/* Custom draw routines */
static void
TOOLTIPS_customdraw_fill(NMTTCUSTOMDRAW *lpnmttcd,
                         const HWND hwnd,
                         HDC hdc, const RECT *rcBounds, UINT uFlags)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd);

    ZeroMemory(lpnmttcd, sizeof(NMTTCUSTOMDRAW));
    lpnmttcd->uDrawFlags = uFlags;
    lpnmttcd->nmcd.hdr.hwndFrom = hwnd;
    lpnmttcd->nmcd.hdr.code     = NM_CUSTOMDRAW;
    if (infoPtr->nCurrentTool != -1) {
        TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
        lpnmttcd->nmcd.hdr.idFrom = toolPtr->uId;
    }
    lpnmttcd->nmcd.hdc = hdc;
    lpnmttcd->nmcd.rc = *rcBounds;
    /* FIXME - dwItemSpec, uItemState, lItemlParam */
}

static inline DWORD
TOOLTIPS_notify_customdraw (DWORD dwDrawStage, NMTTCUSTOMDRAW *lpnmttcd)
{
    LRESULT result = CDRF_DODEFAULT;
    lpnmttcd->nmcd.dwDrawStage = dwDrawStage;

    TRACE("Notifying stage %d, flags %x, id %x\n", lpnmttcd->nmcd.dwDrawStage,
          lpnmttcd->uDrawFlags, lpnmttcd->nmcd.hdr.code);

    result = SendMessageW(GetParent(lpnmttcd->nmcd.hdr.hwndFrom), WM_NOTIFY,
                          0, (LPARAM)lpnmttcd);

    TRACE("Notify result %x\n", (unsigned int)result);

    return result;
}

Robert Shearman's avatar
Robert Shearman committed
243
static void
244
TOOLTIPS_Refresh (HWND hwnd, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
245
{
246
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd);
247 248 249 250 251
    RECT rc;
    INT oldBkMode;
    HFONT hOldFont;
    HBRUSH hBrush;
    UINT uFlags = DT_EXTERNALLEADING;
252 253
    HRGN hRgn = NULL;
    DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
254 255
    NMTTCUSTOMDRAW nmttcd;
    DWORD cdmode;
Alexandre Julliard's avatar
Alexandre Julliard committed
256

Alexandre Julliard's avatar
Alexandre Julliard committed
257 258
    if (infoPtr->nMaxTipWidth > -1)
	uFlags |= DT_WORDBREAK;
259
    if (GetWindowLongW (hwnd, GWL_STYLE) & TTS_NOPREFIX)
Alexandre Julliard's avatar
Alexandre Julliard committed
260
	uFlags |= DT_NOPREFIX;
261
    GetClientRect (hwnd, &rc);
262

263
    hBrush = CreateSolidBrush(infoPtr->clrBk);
264

Robert Shearman's avatar
Robert Shearman committed
265 266
    oldBkMode = SetBkMode (hdc, TRANSPARENT);
    SetTextColor (hdc, infoPtr->clrText);
267 268 269 270 271 272 273
    hOldFont = SelectObject (hdc, infoPtr->hFont);

    /* Custom draw - Call PrePaint once initial properties set up     */
    /* Note: Contrary to MSDN, CDRF_SKIPDEFAULT still draws a tooltip */
    TOOLTIPS_customdraw_fill(&nmttcd, hwnd, hdc, &rc, uFlags);
    cdmode = TOOLTIPS_notify_customdraw(CDDS_PREPAINT, &nmttcd);
    uFlags = nmttcd.uDrawFlags;
Robert Shearman's avatar
Robert Shearman committed
274

275 276 277 278
    if (dwStyle & TTS_BALLOON)
    {
        /* create a region to store result into */
        hRgn = CreateRectRgn(0, 0, 0, 0);
279

280 281 282 283 284 285
        GetWindowRgn(hwnd, hRgn);

        /* fill the background */
        FillRgn(hdc, hRgn, hBrush);
        DeleteObject(hBrush);
        hBrush = NULL;
Robert Shearman's avatar
Robert Shearman committed
286 287 288 289 290 291 292 293
    }
    else
    {
        /* fill the background */
        FillRect(hdc, &rc, hBrush);
        DeleteObject(hBrush);
        hBrush = NULL;
    }
294

Robert Shearman's avatar
Robert Shearman committed
295 296
    if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle)
    {
297 298 299 300 301
        /* calculate text rectangle */
        rc.left   += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left);
        rc.top    += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top);
        rc.right  -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right);
        rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom);
302
        if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT;
Robert Shearman's avatar
Robert Shearman committed
303 304 305 306 307 308

        if (infoPtr->pszTitle)
        {
            RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom};
            int height;
            BOOL icon_present;
309
            HFONT prevFont;
Robert Shearman's avatar
Robert Shearman committed
310 311 312 313 314 315 316 317 318 319 320

            /* draw icon */
            icon_present = infoPtr->hTitleIcon && 
                DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon,
                           ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL);
            if (icon_present)
                rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING;

            rcTitle.bottom = rc.top + ICON_HEIGHT;

            /* draw title text */
321
            prevFont = SelectObject (hdc, infoPtr->hTitleFont);
Robert Shearman's avatar
Robert Shearman committed
322
            height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX);
323
            SelectObject (hdc, prevFont);
Robert Shearman's avatar
Robert Shearman committed
324 325
            rc.top += height + BALLOON_TITLE_TEXT_SPACING;
        }
326 327 328 329 330 331 332 333 334 335 336
    }
    else
    {
        /* calculate text rectangle */
        rc.left   += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left);
        rc.top    += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top);
        rc.right  -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right);
        rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom);
    }

    /* draw text */
337
    DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
338 339 340 341 342 343

    /* Custom draw - Call PostPaint after drawing */
    if (cdmode & CDRF_NOTIFYPOSTPAINT) {
        TOOLTIPS_notify_customdraw(CDDS_POSTPAINT, &nmttcd);
    }

344
    /* be polite and reset the things we changed in the dc */
345
    SelectObject (hdc, hOldFont);
346 347 348 349 350 351 352 353 354 355 356 357 358 359
    SetBkMode (hdc, oldBkMode);

    if (dwStyle & TTS_BALLOON)
    {
        /* frame region because default window proc doesn't do it */
        INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
        INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);

        hBrush = GetSysColorBrush(COLOR_WINDOWFRAME);
        FrameRgn(hdc, hRgn, hBrush, width, height);
    }

    if (hRgn)
        DeleteObject(hRgn);
Alexandre Julliard's avatar
Alexandre Julliard committed
360 361
}

362 363 364 365 366 367 368 369
static void TOOLTIPS_GetDispInfoA(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
{
    NMTTDISPINFOA ttnmdi;

    /* fill NMHDR struct */
    ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
    ttnmdi.hdr.hwndFrom = hwnd;
    ttnmdi.hdr.idFrom = toolPtr->uId;
370
    ttnmdi.hdr.code = TTN_GETDISPINFOA; /* == TTN_NEEDTEXTA */
371
    ttnmdi.lpszText = (LPSTR)ttnmdi.szText;
372 373 374
    ttnmdi.uFlags = toolPtr->uFlags;
    ttnmdi.lParam = toolPtr->lParam;

375
    TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom);
376
    SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
377

Frank Richter's avatar
Frank Richter committed
378 379
    if (IS_INTRESOURCE(ttnmdi.lpszText)) {
        LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
380 381 382 383 384 385 386 387 388 389
               infoPtr->szTipText, INFOTIPSIZE);
        if (ttnmdi.uFlags & TTF_DI_SETITEM) {
            toolPtr->hinst = ttnmdi.hinst;
            toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText;
        }
    }
    else if (ttnmdi.lpszText == 0) {
        infoPtr->szTipText[0] = '\0';
    }
    else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
390
        Str_GetPtrAtoW(ttnmdi.lpszText, infoPtr->szTipText, INFOTIPSIZE);
391 392
        if (ttnmdi.uFlags & TTF_DI_SETITEM) {
            toolPtr->hinst = 0;
393 394
            toolPtr->lpszText = NULL;
            Str_SetPtrW(&toolPtr->lpszText, infoPtr->szTipText);
395 396 397 398 399 400
        }
    }
    else {
        ERR("recursive text callback!\n");
        infoPtr->szTipText[0] = '\0';
    }
401 402 403 404 405

    /* no text available - try calling parent instead as per native */
    /* FIXME: Unsure if SETITEM should save the value or not        */
    if (infoPtr->szTipText[0] == 0x00) {

406
        SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
407 408 409 410 411 412 413 414 415

        if (IS_INTRESOURCE(ttnmdi.lpszText)) {
            LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
                   infoPtr->szTipText, INFOTIPSIZE);
        } else if (ttnmdi.lpszText &&
                   ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
            Str_GetPtrAtoW(ttnmdi.lpszText, infoPtr->szTipText, INFOTIPSIZE);
        }
    }
416 417 418 419 420 421 422 423 424 425
}

static void TOOLTIPS_GetDispInfoW(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr)
{
    NMTTDISPINFOW ttnmdi;

    /* fill NMHDR struct */
    ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW));
    ttnmdi.hdr.hwndFrom = hwnd;
    ttnmdi.hdr.idFrom = toolPtr->uId;
426
    ttnmdi.hdr.code = TTN_GETDISPINFOW; /* == TTN_NEEDTEXTW */
427
    ttnmdi.lpszText = (LPWSTR)ttnmdi.szText;
428 429 430
    ttnmdi.uFlags = toolPtr->uFlags;
    ttnmdi.lParam = toolPtr->lParam;

431
    TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom);
432
    SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
433

Frank Richter's avatar
Frank Richter committed
434 435
    if (IS_INTRESOURCE(ttnmdi.lpszText)) {
        LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
436 437 438 439 440 441 442 443 444 445
               infoPtr->szTipText, INFOTIPSIZE);
        if (ttnmdi.uFlags & TTF_DI_SETITEM) {
            toolPtr->hinst = ttnmdi.hinst;
            toolPtr->lpszText = ttnmdi.lpszText;
        }
    }
    else if (ttnmdi.lpszText == 0) {
        infoPtr->szTipText[0] = '\0';
    }
    else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
446
        Str_GetPtrW(ttnmdi.lpszText, infoPtr->szTipText, INFOTIPSIZE);
447 448
        if (ttnmdi.uFlags & TTF_DI_SETITEM) {
            toolPtr->hinst = 0;
449 450
            toolPtr->lpszText = NULL;
            Str_SetPtrW(&toolPtr->lpszText, infoPtr->szTipText);
451 452 453 454 455 456
        }
    }
    else {
        ERR("recursive text callback!\n");
        infoPtr->szTipText[0] = '\0';
    }
457 458 459 460 461

    /* no text available - try calling parent instead as per native */
    /* FIXME: Unsure if SETITEM should save the value or not        */
    if (infoPtr->szTipText[0] == 0x00) {

462
        SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
463 464 465 466 467 468 469 470 471 472

        if (IS_INTRESOURCE(ttnmdi.lpszText)) {
            LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
                   infoPtr->szTipText, INFOTIPSIZE);
        } else if (ttnmdi.lpszText &&
                   ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
            Str_GetPtrW(ttnmdi.lpszText, infoPtr->szTipText, INFOTIPSIZE);
        }
    }

473
}
Alexandre Julliard's avatar
Alexandre Julliard committed
474

Robert Shearman's avatar
Robert Shearman committed
475
static void
476
TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool)
Alexandre Julliard's avatar
Alexandre Julliard committed
477
{
478
    TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
479

Frank Richter's avatar
Frank Richter committed
480
    if (IS_INTRESOURCE(toolPtr->lpszText) && toolPtr->hinst) {
481
	/* load a resource */
482
	TRACE("load res string %p %x\n",
Frank Richter's avatar
Frank Richter committed
483 484
	       toolPtr->hinst, LOWORD(toolPtr->lpszText));
	LoadStringW (toolPtr->hinst, LOWORD(toolPtr->lpszText),
Alexandre Julliard's avatar
Alexandre Julliard committed
485 486 487
		       infoPtr->szTipText, INFOTIPSIZE);
    }
    else if (toolPtr->lpszText) {
488
	if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) {
489 490 491 492
	    if (toolPtr->bNotifyUnicode)
		TOOLTIPS_GetDispInfoW(hwnd, infoPtr, toolPtr);
	    else
		TOOLTIPS_GetDispInfoA(hwnd, infoPtr, toolPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
493
	}
494 495
	else {
	    /* the item is a usual (unicode) text */
496
	    lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE);
497
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
498
    }
499
    else {
Alexandre Julliard's avatar
Alexandre Julliard committed
500
	/* no text available */
501
        infoPtr->szTipText[0] = '\0';
502
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
503

504
    TRACE("%s\n", debugstr_w(infoPtr->szTipText));
Alexandre Julliard's avatar
Alexandre Julliard committed
505 506 507
}


Robert Shearman's avatar
Robert Shearman committed
508
static void
509
TOOLTIPS_CalcTipSize (HWND hwnd, const TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
510
{
511 512
    HDC hdc;
    HFONT hOldFont;
513
    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
514 515
    UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
    RECT rc = {0, 0, 0, 0};
Robert Shearman's avatar
Robert Shearman committed
516
    SIZE title = {0, 0};
Alexandre Julliard's avatar
Alexandre Julliard committed
517 518 519 520 521

    if (infoPtr->nMaxTipWidth > -1) {
	rc.right = infoPtr->nMaxTipWidth;
	uFlags |= DT_WORDBREAK;
    }
522
    if (style & TTS_NOPREFIX)
Alexandre Julliard's avatar
Alexandre Julliard committed
523
	uFlags |= DT_NOPREFIX;
524
    TRACE("%s\n", debugstr_w(infoPtr->szTipText));
Alexandre Julliard's avatar
Alexandre Julliard committed
525

526
    hdc = GetDC (hwnd);
Robert Shearman's avatar
Robert Shearman committed
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
    if (infoPtr->pszTitle)
    {
        RECT rcTitle = {0, 0, 0, 0};
        TRACE("title %s\n", debugstr_w(infoPtr->pszTitle));
        if (infoPtr->hTitleIcon)
        {
            title.cx = ICON_WIDTH;
            title.cy = ICON_HEIGHT;
        }
        if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING;
        hOldFont = SelectObject (hdc, infoPtr->hTitleFont);
        DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
        SelectObject (hdc, hOldFont);
        title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING;
        title.cx += (rcTitle.right - rcTitle.left);
    }
543 544 545
    hOldFont = SelectObject (hdc, infoPtr->hFont);
    DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
    SelectObject (hdc, hOldFont);
546
    ReleaseDC (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
547

Robert Shearman's avatar
Robert Shearman committed
548
    if ((style & TTS_BALLOON) || infoPtr->pszTitle)
549
    {
Robert Shearman's avatar
Robert Shearman committed
550
        lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN +
551
                       infoPtr->rcMargin.left + infoPtr->rcMargin.right;
Robert Shearman's avatar
Robert Shearman committed
552
        lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN +
553 554
                       infoPtr->rcMargin.bottom + infoPtr->rcMargin.top +
                       BALLOON_STEMHEIGHT;
555 556 557 558 559 560 561 562
    }
    else
    {
        lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN +
                       infoPtr->rcMargin.left + infoPtr->rcMargin.right;
        lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN +
                       infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
563 564 565
}


Robert Shearman's avatar
Robert Shearman committed
566
static void
567
TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr, BOOL track_activate)
Alexandre Julliard's avatar
Alexandre Julliard committed
568
{
Alexandre Julliard's avatar
Alexandre Julliard committed
569
    TTTOOL_INFO *toolPtr;
570 571 572
    HMONITOR monitor;
    MONITORINFO mon_info;
    RECT rect;
573
    SIZE size;
574
    NMHDR  hdr;
575 576
    int ptfx = 0;
    DWORD style = GetWindowLongW(hwnd, GWL_STYLE);
577
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
578

579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
    if (track_activate)
    {
        if (infoPtr->nTrackTool == -1)
        {
            TRACE("invalid tracking tool (-1)!\n");
            return;
        }
        nTool = infoPtr->nTrackTool;
    }
    else
    {
        if (infoPtr->nTool == -1)
        {
            TRACE("invalid tool (-1)!\n");
		return;
        }
        nTool = infoPtr->nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
596
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
597

598
    TRACE("Show tooltip pre %d! (%p)\n", nTool, hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
599

600
    TOOLTIPS_GetTipText (hwnd, infoPtr, nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
601

602 603
    if (infoPtr->szTipText[0] == '\0')
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
604

605
    toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
606

607 608 609 610
    if (!track_activate)
        infoPtr->nCurrentTool = infoPtr->nTool;

    TRACE("Show tooltip %d!\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
611

612
    hdr.hwndFrom = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
613
    hdr.idFrom = toolPtr->uId;
Alexandre Julliard's avatar
Alexandre Julliard committed
614
    hdr.code = TTN_SHOW;
615
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
616

617
    TRACE("%s\n", debugstr_w(infoPtr->szTipText));
Alexandre Julliard's avatar
Alexandre Julliard committed
618

619
    TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
620
    TRACE("size %d x %d\n", size.cx, size.cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
621

622 623
    if (track_activate)
    {
624 625 626
        rect.left = infoPtr->xTrackPos;
        rect.top  = infoPtr->yTrackPos;
        ptfx = rect.left;
Alexandre Julliard's avatar
Alexandre Julliard committed
627

628 629 630 631 632
        if (toolPtr->uFlags & TTF_CENTERTIP)
        {
            rect.left -= (size.cx / 2);
            if (!(style & TTS_BALLOON))
                rect.top  -= (size.cy / 2);
633
        }
634 635 636
        infoPtr->bToolBelow = TRUE;

        if (!(toolPtr->uFlags & TTF_ABSOLUTE))
637
        {
638 639 640 641 642
            if (style & TTS_BALLOON)
                rect.left -= BALLOON_STEMINDENT;
            else
            {
                RECT rcTool;
643

644 645
                if (toolPtr->uFlags & TTF_IDISHWND)
                    GetWindowRect ((HWND)toolPtr->uId, &rcTool);
646 647
                else
                {
648 649
                    rcTool = toolPtr->rect;
                    MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2);
650 651
                }

652 653 654 655
                /* smart placement */
                if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) &&
                    (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom))
                    rect.left = rcTool.right;
656
            }
657
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
658
    }
659 660 661 662 663 664 665 666 667 668 669 670 671 672
    else
    {
        if (toolPtr->uFlags & TTF_CENTERTIP)
        {
		RECT rc;

            if (toolPtr->uFlags & TTF_IDISHWND)
                GetWindowRect ((HWND)toolPtr->uId, &rc);
            else {
                rc = toolPtr->rect;
                MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
            }
            rect.left = (rc.left + rc.right - size.cx) / 2;
            if (style & TTS_BALLOON)
673
            {
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
                ptfx = rc.left + ((rc.right - rc.left) / 2);

                /* CENTERTIP ballon tooltips default to below the field
                 * if they fit on the screen */
                if (rc.bottom + size.cy > GetSystemMetrics(SM_CYSCREEN))
                {
                    rect.top = rc.top - size.cy;
                    infoPtr->bToolBelow = FALSE;
                }
                else
                {
                    infoPtr->bToolBelow = TRUE;
                    rect.top = rc.bottom;
                }
                rect.left = max(0, rect.left - BALLOON_STEMINDENT);
689 690 691
            }
            else
            {
692 693
                rect.top  = rc.bottom + 2;
                infoPtr->bToolBelow = TRUE;
694 695 696 697
            }
        }
        else
        {
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
            GetCursorPos ((LPPOINT)&rect);
            if (style & TTS_BALLOON)
            {
                ptfx = rect.left;
                if(rect.top - size.cy >= 0)
                {
                    rect.top -= size.cy;
                    infoPtr->bToolBelow = FALSE;
                }
                else
                {
                    infoPtr->bToolBelow = TRUE;
                    rect.top += 20;
                }
                rect.left = max(0, rect.left - BALLOON_STEMINDENT);
            }
            else
            {
		    rect.top += 20;
		    infoPtr->bToolBelow = TRUE;
            }
719
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
720 721
    }

722
    TRACE("pos %d - %d\n", rect.left, rect.top);
Alexandre Julliard's avatar
Alexandre Julliard committed
723 724 725 726

    rect.right = rect.left + size.cx;
    rect.bottom = rect.top + size.cy;

727
    /* check position */
728 729 730 731 732 733 734 735

    monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
    mon_info.cbSize = sizeof(mon_info);
    GetMonitorInfoW( monitor, &mon_info );

    if( rect.right > mon_info.rcWork.right ) {
        rect.left -= rect.right - mon_info.rcWork.right + 2;
        rect.right = mon_info.rcWork.right - 2;
736
    }
737 738 739
    if (rect.left < mon_info.rcWork.left) rect.left = mon_info.rcWork.left;

    if( rect.bottom > mon_info.rcWork.bottom ) {
740 741 742 743 744 745
        RECT rc;

	if (toolPtr->uFlags & TTF_IDISHWND)
	    GetWindowRect ((HWND)toolPtr->uId, &rc);
	else {
	    rc = toolPtr->rect;
746
	    MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
747
	}
748 749 750 751
	rect.bottom = rc.top - 2;
    	rect.top = rect.bottom - size.cy;
    }

752 753
    AdjustWindowRectEx (&rect, GetWindowLongW (hwnd, GWL_STYLE),
			FALSE, GetWindowLongW (hwnd, GWL_EXSTYLE));
Alexandre Julliard's avatar
Alexandre Julliard committed
754

755
    if (style & TTS_BALLOON)
756 757
    {
        HRGN hRgn;
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
        HRGN hrStem;
        POINT pts[3];

        ptfx -= rect.left;

        if(infoPtr->bToolBelow)
        {
          pts[0].x = ptfx;
          pts[0].y = 0;
          pts[1].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2));
          pts[1].y = BALLOON_STEMHEIGHT;
          pts[2].x = pts[1].x + BALLOON_STEMWIDTH;
          pts[2].y = pts[1].y;
          if(pts[2].x > (rect.right - rect.left) - BALLOON_STEMINDENT)
          {
            pts[2].x = (rect.right - rect.left) - BALLOON_STEMINDENT;
            pts[1].x = pts[2].x - BALLOON_STEMWIDTH;
          }
        }
        else
        {
          pts[0].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2));
          pts[0].y = (rect.bottom - rect.top) - BALLOON_STEMHEIGHT;
          pts[1].x = pts[0].x + BALLOON_STEMWIDTH;
          pts[1].y = pts[0].y;
          pts[2].x = ptfx;
          pts[2].y = (rect.bottom - rect.top);
          if(pts[1].x > (rect.right - rect.left) - BALLOON_STEMINDENT)
          {
            pts[1].x = (rect.right - rect.left) - BALLOON_STEMINDENT;
            pts[0].x = pts[1].x - BALLOON_STEMWIDTH;
          }
        }

        hrStem = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE);
        
        hRgn = CreateRoundRectRgn(0,
                                  (infoPtr->bToolBelow ? BALLOON_STEMHEIGHT : 0),
                                  rect.right - rect.left,
                                  (infoPtr->bToolBelow ? rect.bottom - rect.top : rect.bottom - rect.top - BALLOON_STEMHEIGHT),
                                  BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS);
799

800 801
        CombineRgn(hRgn, hRgn, hrStem, RGN_OR);
        DeleteObject(hrStem);
802 803 804 805 806 807

        SetWindowRgn(hwnd, hRgn, FALSE);
        /* we don't free the region handle as the system deletes it when 
         * it is no longer needed */
    }

808
    SetWindowPos (hwnd, HWND_TOPMOST, rect.left, rect.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
809
		    rect.right - rect.left, rect.bottom - rect.top,
810
		    SWP_SHOWWINDOW | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
811

812
    /* repaint the tooltip */
813 814
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
815

816 817 818 819 820 821 822
    if (!track_activate)
    {
        SetTimer (hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
        TRACE("timer 2 started!\n");
        SetTimer (hwnd, ID_TIMERLEAVE, infoPtr->nReshowTime, 0);
        TRACE("timer 3 started!\n");
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
823 824 825
}


Robert Shearman's avatar
Robert Shearman committed
826
static void
827
TOOLTIPS_Hide (HWND hwnd, TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
828
{
Alexandre Julliard's avatar
Alexandre Julliard committed
829
    TTTOOL_INFO *toolPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
830 831
    NMHDR hdr;

832
    TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, hwnd);
833

Alexandre Julliard's avatar
Alexandre Julliard committed
834 835 836
    if (infoPtr->nCurrentTool == -1)
	return;

Alexandre Julliard's avatar
Alexandre Julliard committed
837
    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
838
    KillTimer (hwnd, ID_TIMERPOP);
Alexandre Julliard's avatar
Alexandre Julliard committed
839

840
    hdr.hwndFrom = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
841
    hdr.idFrom = toolPtr->uId;
Alexandre Julliard's avatar
Alexandre Julliard committed
842
    hdr.code = TTN_POP;
843
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
844

Alexandre Julliard's avatar
Alexandre Julliard committed
845
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
846

847
    SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
848
		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
849 850 851
}


Robert Shearman's avatar
Robert Shearman committed
852
static void
853
TOOLTIPS_TrackShow (HWND hwnd, TOOLTIPS_INFO *infoPtr)
854
{
855
    TOOLTIPS_Show(hwnd, infoPtr, TRUE);
856 857 858
}


Robert Shearman's avatar
Robert Shearman committed
859
static void
860
TOOLTIPS_TrackHide (HWND hwnd, const TOOLTIPS_INFO *infoPtr)
861 862 863 864
{
    TTTOOL_INFO *toolPtr;
    NMHDR hdr;

865 866
    TRACE("hide tracking tooltip %d\n", infoPtr->nTrackTool);

867 868 869 870 871
    if (infoPtr->nTrackTool == -1)
	return;

    toolPtr = &infoPtr->tools[infoPtr->nTrackTool];

872
    hdr.hwndFrom = hwnd;
873 874
    hdr.idFrom = toolPtr->uId;
    hdr.code = TTN_POP;
875
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
876

877
    SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
878
		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
879 880 881
}


882
static INT
883
TOOLTIPS_GetToolFromInfoA (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOA *lpToolInfo)
Alexandre Julliard's avatar
Alexandre Julliard committed
884 885
{
    TTTOOL_INFO *toolPtr;
886
    UINT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
887 888 889 890

    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];

891
	if (!(toolPtr->uFlags & TTF_IDISHWND) &&
Alexandre Julliard's avatar
Alexandre Julliard committed
892 893 894 895
	    (lpToolInfo->hwnd == toolPtr->hwnd) &&
	    (lpToolInfo->uId == toolPtr->uId))
	    return nTool;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
896

Alexandre Julliard's avatar
Alexandre Julliard committed
897 898
    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
899

Alexandre Julliard's avatar
Alexandre Julliard committed
900
	if ((toolPtr->uFlags & TTF_IDISHWND) &&
Alexandre Julliard's avatar
Alexandre Julliard committed
901
	    (lpToolInfo->uId == toolPtr->uId))
Alexandre Julliard's avatar
Alexandre Julliard committed
902
	    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
903 904 905 906 907
    }

    return -1;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
908

909
static INT
910
TOOLTIPS_GetToolFromInfoW (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
911 912
{
    TTTOOL_INFO *toolPtr;
913
    UINT nTool;
914 915 916 917

    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];

918
	if (!(toolPtr->uFlags & TTF_IDISHWND) &&
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
	    (lpToolInfo->hwnd == toolPtr->hwnd) &&
	    (lpToolInfo->uId == toolPtr->uId))
	    return nTool;
    }

    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];

	if ((toolPtr->uFlags & TTF_IDISHWND) &&
	    (lpToolInfo->uId == toolPtr->uId))
	    return nTool;
    }

    return -1;
}


936
static INT
937
TOOLTIPS_GetToolFromPoint (const TOOLTIPS_INFO *infoPtr, HWND hwnd, const POINT *lpPt)
Alexandre Julliard's avatar
Alexandre Julliard committed
938 939
{
    TTTOOL_INFO *toolPtr;
940
    UINT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
941

Alexandre Julliard's avatar
Alexandre Julliard committed
942 943
    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
944

Alexandre Julliard's avatar
Alexandre Julliard committed
945
	if (!(toolPtr->uFlags & TTF_IDISHWND)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
946 947
	    if (hwnd != toolPtr->hwnd)
		continue;
948
	    if (!PtInRect (&toolPtr->rect, *lpPt))
Alexandre Julliard's avatar
Alexandre Julliard committed
949
		continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
950
	    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
951 952 953
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
954 955 956 957
    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];

	if (toolPtr->uFlags & TTF_IDISHWND) {
958
	    if ((HWND)toolPtr->uId == hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
959 960 961 962
		return nTool;
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
963 964
    return -1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
965

Alexandre Julliard's avatar
Alexandre Julliard committed
966

967 968
static BOOL
TOOLTIPS_IsWindowActive (HWND hwnd)
969
{
970
    HWND hwndActive = GetActiveWindow ();
971 972 973 974
    if (!hwndActive)
	return FALSE;
    if (hwndActive == hwnd)
	return TRUE;
975
    return IsChild (hwndActive, hwnd);
976 977 978
}


979
static INT
980
TOOLTIPS_CheckTool (HWND hwnd, BOOL bShowTest)
Alexandre Julliard's avatar
Alexandre Julliard committed
981
{
982
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
983 984 985
    POINT pt;
    HWND hwndTool;
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
986

987
    GetCursorPos (&pt);
988
    hwndTool = (HWND)SendMessageW (hwnd, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
989
    if (hwndTool == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
990
	return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
991

992
    ScreenToClient (hwndTool, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
993
    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995 996
    if (nTool == -1)
	return -1;

997
    if (!(GetWindowLongW (hwnd, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) {
998
	if (!TOOLTIPS_IsWindowActive (GetWindow (hwnd, GW_OWNER)))
Alexandre Julliard's avatar
Alexandre Julliard committed
999 1000 1001
	    return -1;
    }

1002
    TRACE("tool %d\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
1003

Alexandre Julliard's avatar
Alexandre Julliard committed
1004
    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006 1007
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1008
static LRESULT
1009
TOOLTIPS_Activate (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1010
{
1011
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1012

1013
    infoPtr->bActive = (BOOL)wParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1014

Alexandre Julliard's avatar
Alexandre Julliard committed
1015
    if (infoPtr->bActive)
1016
	TRACE("activate!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1017

1018
    if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
1019
	TOOLTIPS_Hide (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1020 1021 1022 1023 1024 1025

    return 0;
}


static LRESULT
1026
TOOLTIPS_AddToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1027
{
1028
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1029
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1030
    TTTOOL_INFO *toolPtr;
1031
    INT nResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1032

Alexandre Julliard's avatar
Alexandre Julliard committed
1033 1034
    if (lpToolInfo == NULL)
	return FALSE;
1035
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1036
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1037

1038
    TRACE("add tool (%p) %p %ld%s!\n",
1039
	   hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
Alexandre Julliard's avatar
Alexandre Julliard committed
1040 1041
	   (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");

Alexandre Julliard's avatar
Alexandre Julliard committed
1042
    if (infoPtr->uNumTools == 0) {
1043
	infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1044 1045 1046 1047 1048
	toolPtr = infoPtr->tools;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1049
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1050 1051
	memcpy (infoPtr->tools, oldTools,
		infoPtr->uNumTools * sizeof(TTTOOL_INFO));
1052
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
	toolPtr = &infoPtr->tools[infoPtr->uNumTools];
    }

    infoPtr->uNumTools++;

    /* copy tool data */
    toolPtr->uFlags = lpToolInfo->uFlags;
    toolPtr->hwnd   = lpToolInfo->hwnd;
    toolPtr->uId    = lpToolInfo->uId;
    toolPtr->rect   = lpToolInfo->rect;
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
1065 1066
    if (IS_INTRESOURCE(lpToolInfo->lpszText)) {
	TRACE("add string id %x!\n", LOWORD(lpToolInfo->lpszText));
1067
	toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
Alexandre Julliard's avatar
Alexandre Julliard committed
1068 1069
    }
    else if (lpToolInfo->lpszText) {
1070
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) {
1071
	    TRACE("add CALLBACK!\n");
1072
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
	else {
1075 1076
	    INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
					  NULL, 0);
1077
	    TRACE("add text \"%s\"!\n", lpToolInfo->lpszText);
1078
	    toolPtr->lpszText =	Alloc (len * sizeof(WCHAR));
1079 1080
	    MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
				toolPtr->lpszText, len);
Alexandre Julliard's avatar
Alexandre Julliard committed
1081 1082 1083
	}
    }

1084
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
Alexandre Julliard's avatar
Alexandre Julliard committed
1085 1086
	toolPtr->lParam = lpToolInfo->lParam;

Alexandre Julliard's avatar
Alexandre Julliard committed
1087
    /* install subclassing hook */
Alexandre Julliard's avatar
Alexandre Julliard committed
1088 1089
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1090 1091
	    SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
			       (DWORD_PTR)hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1092 1093
	}
	else {
1094 1095
	    SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
			      (DWORD_PTR)hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1096
	}
1097
	TRACE("subclassing installed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1098 1099
    }

1100
    nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
				  (WPARAM)hwnd, (LPARAM)NF_QUERY);
    if (nResult == NFR_ANSI) {
        toolPtr->bNotifyUnicode = FALSE;
	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
    } else if (nResult == NFR_UNICODE) {
        toolPtr->bNotifyUnicode = TRUE;
	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
    } else {
        TRACE (" -- WM_NOTIFYFORMAT returns: error!\n");
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1112 1113 1114 1115
    return TRUE;
}


1116
static LRESULT
1117
TOOLTIPS_AddToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1118
{
1119
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1120
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1121
    TTTOOL_INFO *toolPtr;
1122
    INT nResult;
1123 1124 1125

    if (lpToolInfo == NULL)
	return FALSE;
1126
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1127 1128
	return FALSE;

1129
    TRACE("add tool (%p) %p %ld%s!\n",
1130
	   hwnd, lpToolInfo->hwnd, lpToolInfo->uId,
1131 1132 1133
	   (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");

    if (infoPtr->uNumTools == 0) {
1134
	infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
1135 1136 1137 1138 1139
	toolPtr = infoPtr->tools;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1140
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
1141 1142
	memcpy (infoPtr->tools, oldTools,
		infoPtr->uNumTools * sizeof(TTTOOL_INFO));
1143
	Free (oldTools);
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
	toolPtr = &infoPtr->tools[infoPtr->uNumTools];
    }

    infoPtr->uNumTools++;

    /* copy tool data */
    toolPtr->uFlags = lpToolInfo->uFlags;
    toolPtr->hwnd   = lpToolInfo->hwnd;
    toolPtr->uId    = lpToolInfo->uId;
    toolPtr->rect   = lpToolInfo->rect;
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
1156 1157
    if (IS_INTRESOURCE(lpToolInfo->lpszText)) {
	TRACE("add string id %x\n", LOWORD(lpToolInfo->lpszText));
1158
	toolPtr->lpszText = lpToolInfo->lpszText;
1159 1160
    }
    else if (lpToolInfo->lpszText) {
1161
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) {
1162
	    TRACE("add CALLBACK!\n");
1163
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1164 1165
	}
	else {
1166
	    INT len = lstrlenW (lpToolInfo->lpszText);
1167
	    TRACE("add text %s!\n",
1168
		   debugstr_w(lpToolInfo->lpszText));
1169
	    toolPtr->lpszText =	Alloc ((len + 1)*sizeof(WCHAR));
1170
	    strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
1171 1172 1173
	}
    }

1174
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1175 1176 1177 1178 1179
	toolPtr->lParam = lpToolInfo->lParam;

    /* install subclassing hook */
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1180 1181
	    SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
			      (DWORD_PTR)hwnd);
1182 1183
	}
	else {
1184 1185
	    SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
			      (DWORD_PTR)hwnd);
1186
	}
1187
	TRACE("subclassing installed!\n");
1188 1189
    }

1190
    nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
				  (WPARAM)hwnd, (LPARAM)NF_QUERY);
    if (nResult == NFR_ANSI) {
        toolPtr->bNotifyUnicode = FALSE;
	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
    } else if (nResult == NFR_UNICODE) {
        toolPtr->bNotifyUnicode = TRUE;
	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
    } else {
        TRACE (" -- WM_NOTIFYFORMAT returns: error!\n");
    }

1202 1203
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1204 1205


Robert Shearman's avatar
Robert Shearman committed
1206 1207
static void
TOOLTIPS_DelToolCommon (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool)
Alexandre Julliard's avatar
Alexandre Julliard committed
1208 1209 1210
{
    TTTOOL_INFO *toolPtr;

1211
    TRACE("tool %d\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
1212

1213 1214 1215
    if (nTool == -1)
        return;

1216 1217
    /* make sure the tooltip has disappeared before deleting it */
    TOOLTIPS_Hide(hwnd, infoPtr);
1218

Alexandre Julliard's avatar
Alexandre Julliard committed
1219
    /* delete text string */
1220
    toolPtr = &infoPtr->tools[nTool];
1221
    if (toolPtr->lpszText) {
1222
	if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
1223
	     !IS_INTRESOURCE(toolPtr->lpszText) )
1224
	    Free (toolPtr->lpszText);
Alexandre Julliard's avatar
Alexandre Julliard committed
1225 1226
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1227 1228 1229
    /* remove subclassing */
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1230
	    RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1231 1232
	}
	else {
1233
	    RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1234 1235 1236
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1237 1238
    /* delete tool from tool list */
    if (infoPtr->uNumTools == 1) {
1239
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1240 1241 1242 1243 1244
	infoPtr->tools = NULL;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1245
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1246

Alexandre Julliard's avatar
Alexandre Julliard committed
1247
	if (nTool > 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1248
	    memcpy (&infoPtr->tools[0], &oldTools[0],
Alexandre Julliard's avatar
Alexandre Julliard committed
1249
		    nTool * sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1250

Alexandre Julliard's avatar
Alexandre Julliard committed
1251 1252 1253
	if (nTool < infoPtr->uNumTools - 1)
	    memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
		    (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1254

1255
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1256 1257
    }

1258 1259
    /* update any indices affected by delete */

1260 1261
    /* destroying tool that mouse was on on last relayed mouse move */
    if (infoPtr->nTool == nTool)
1262
        /* -1 means no current tool (0 means first tool) */
1263
        infoPtr->nTool = -1;
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
    else if (infoPtr->nTool > nTool)
        infoPtr->nTool--;

    if (infoPtr->nTrackTool == nTool)
        /* -1 means no current tool (0 means first tool) */
        infoPtr->nTrackTool = -1;
    else if (infoPtr->nTrackTool > nTool)
        infoPtr->nTrackTool--;

    if (infoPtr->nCurrentTool == nTool)
        /* -1 means no current tool (0 means first tool) */
        infoPtr->nCurrentTool = -1;
    else if (infoPtr->nCurrentTool > nTool)
        infoPtr->nCurrentTool--;
1278

Alexandre Julliard's avatar
Alexandre Julliard committed
1279
    infoPtr->uNumTools--;
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
}

static LRESULT
TOOLTIPS_DelToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
    INT nTool;

    if (lpToolInfo == NULL)
	return 0;
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
	return 0;
    if (infoPtr->uNumTools == 0)
	return 0;

    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);

    TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool);
1299

Alexandre Julliard's avatar
Alexandre Julliard committed
1300 1301 1302 1303
    return 0;
}


1304
static LRESULT
1305
TOOLTIPS_DelToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1306
{
1307
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1308 1309
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
    INT nTool;
1310 1311 1312

    if (lpToolInfo == NULL)
	return 0;
1313
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1314 1315 1316 1317 1318 1319
	return 0;
    if (infoPtr->uNumTools == 0)
	return 0;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);

1320
    TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool);
1321

1322 1323
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1324 1325 1326


static LRESULT
1327
TOOLTIPS_EnumToolsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1328
{
1329
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1330 1331
    UINT uIndex = (UINT)wParam;
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1332 1333
    TTTOOL_INFO *toolPtr;

Alexandre Julliard's avatar
Alexandre Julliard committed
1334 1335
    if (lpToolInfo == NULL)
	return FALSE;
1336
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1337 1338 1339
	return FALSE;
    if (uIndex >= infoPtr->uNumTools)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1340

1341
    TRACE("index=%u\n", uIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
1342 1343 1344 1345 1346 1347 1348 1349 1350

    toolPtr = &infoPtr->tools[uIndex];

    /* copy tool data */
    lpToolInfo->uFlags   = toolPtr->uFlags;
    lpToolInfo->hwnd     = toolPtr->hwnd;
    lpToolInfo->uId      = toolPtr->uId;
    lpToolInfo->rect     = toolPtr->rect;
    lpToolInfo->hinst    = toolPtr->hinst;
1351
/*    lpToolInfo->lpszText = toolPtr->lpszText; */
1352
    lpToolInfo->lpszText = NULL;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1353

1354
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
Alexandre Julliard's avatar
Alexandre Julliard committed
1355 1356 1357 1358 1359 1360
	lpToolInfo->lParam = toolPtr->lParam;

    return TRUE;
}


1361
static LRESULT
1362
TOOLTIPS_EnumToolsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1363
{
1364
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1365 1366
    UINT uIndex = (UINT)wParam;
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1367 1368 1369 1370
    TTTOOL_INFO *toolPtr;

    if (lpToolInfo == NULL)
	return FALSE;
1371
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1372 1373 1374 1375
	return FALSE;
    if (uIndex >= infoPtr->uNumTools)
	return FALSE;

1376
    TRACE("index=%u\n", uIndex);
1377 1378 1379 1380 1381 1382 1383 1384 1385

    toolPtr = &infoPtr->tools[uIndex];

    /* copy tool data */
    lpToolInfo->uFlags   = toolPtr->uFlags;
    lpToolInfo->hwnd     = toolPtr->hwnd;
    lpToolInfo->uId      = toolPtr->uId;
    lpToolInfo->rect     = toolPtr->rect;
    lpToolInfo->hinst    = toolPtr->hinst;
1386
/*    lpToolInfo->lpszText = toolPtr->lpszText; */
1387 1388
    lpToolInfo->lpszText = NULL;  /* FIXME */

1389
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1390 1391 1392 1393
	lpToolInfo->lParam = toolPtr->lParam;

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1394

1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
static LRESULT
TOOLTIPS_GetBubbleSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
    INT nTool;
    SIZE size;

    if (lpToolInfo == NULL)
	return FALSE;
1405
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1406 1407 1408 1409 1410 1411 1412 1413
	return FALSE;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
    if (nTool == -1) return 0;

    TRACE("tool %d\n", nTool);

    TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size);
1414
    TRACE("size %d x %d\n", size.cx, size.cy);
1415 1416 1417

    return MAKELRESULT(size.cx, size.cy);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1418 1419

static LRESULT
1420
TOOLTIPS_GetCurrentToolA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1421
{
1422
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1423
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1424
    TTTOOL_INFO *toolPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
1425

Alexandre Julliard's avatar
Alexandre Julliard committed
1426
    if (lpToolInfo) {
1427 1428 1429
        if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
            return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1430 1431 1432 1433
	if (infoPtr->nCurrentTool > -1) {
	    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];

	    /* copy tool data */
Alexandre Julliard's avatar
Alexandre Julliard committed
1434 1435 1436
	    lpToolInfo->uFlags   = toolPtr->uFlags;
	    lpToolInfo->rect     = toolPtr->rect;
	    lpToolInfo->hinst    = toolPtr->hinst;
1437
/*	    lpToolInfo->lpszText = toolPtr->lpszText; */
1438
	    lpToolInfo->lpszText = NULL;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1439

1440
	    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
Alexandre Julliard's avatar
Alexandre Julliard committed
1441
		lpToolInfo->lParam = toolPtr->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1442 1443 1444 1445 1446 1447 1448

	    return TRUE;
	}
	else
	    return FALSE;
    }
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
1449
	return (infoPtr->nCurrentTool != -1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1450 1451 1452
}


1453
static LRESULT
1454
TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1455
{
1456
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1457
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1458 1459 1460
    TTTOOL_INFO *toolPtr;

    if (lpToolInfo) {
1461 1462 1463
        if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
            return FALSE;

1464 1465 1466 1467 1468 1469 1470
	if (infoPtr->nCurrentTool > -1) {
	    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];

	    /* copy tool data */
	    lpToolInfo->uFlags   = toolPtr->uFlags;
	    lpToolInfo->rect     = toolPtr->rect;
	    lpToolInfo->hinst    = toolPtr->hinst;
1471
/*	    lpToolInfo->lpszText = toolPtr->lpszText; */
1472 1473
	    lpToolInfo->lpszText = NULL;  /* FIXME */

1474
	    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
		lpToolInfo->lParam = toolPtr->lParam;

	    return TRUE;
	}
	else
	    return FALSE;
    }
    else
	return (infoPtr->nCurrentTool != -1);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486 1487


static LRESULT
1488
TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1489
{
1490
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1491 1492

    switch (wParam) {
1493 1494
    case TTDT_RESHOW:
        return infoPtr->nReshowTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1495

1496 1497
    case TTDT_AUTOPOP:
        return infoPtr->nAutoPopTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1498

1499 1500 1501
    case TTDT_INITIAL:
    case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
        return infoPtr->nInitialTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1502

1503
    default:
1504
        WARN("Invalid wParam %lx\n", wParam);
1505
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507
    }

1508
    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1509 1510 1511 1512
}


static LRESULT
1513
TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1514
{
1515
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1516
    LPRECT lpRect = (LPRECT)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1517 1518 1519 1520 1521 1522 1523 1524

    lpRect->left   = infoPtr->rcMargin.left;
    lpRect->right  = infoPtr->rcMargin.right;
    lpRect->bottom = infoPtr->rcMargin.bottom;
    lpRect->top    = infoPtr->rcMargin.top;

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1525 1526


1527
static inline LRESULT
1528
TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1529
{
1530
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1531

Alexandre Julliard's avatar
Alexandre Julliard committed
1532
    return infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1533 1534 1535 1536
}


static LRESULT
1537
TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1538
{
1539
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1540 1541
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1542

Alexandre Julliard's avatar
Alexandre Julliard committed
1543 1544
    if (lpToolInfo == NULL)
	return 0;
1545
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1546
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1547

Alexandre Julliard's avatar
Alexandre Julliard committed
1548
    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
Alexandre Julliard's avatar
Alexandre Julliard committed
1549
    if (nTool == -1) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1550

1551 1552
    /* NB this API is broken, there is no way for the app to determine
       what size buffer it requires nor a way to specify how long the
1553
       one it supplies is.  We'll assume it's up to INFOTIPSIZE */
1554 1555 1556

    WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1,
			lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1557 1558 1559 1560 1561

    return 0;
}


1562
static LRESULT
1563
TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1564
{
1565
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1566 1567
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
    INT nTool;
1568 1569 1570

    if (lpToolInfo == NULL)
	return 0;
1571
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1572 1573 1574 1575 1576
	return 0;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
    if (nTool == -1) return 0;

1577 1578 1579
    if (infoPtr->tools[nTool].lpszText == NULL)
	return 0;

1580
    strcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText);
1581 1582 1583

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1584 1585


1586
static inline LRESULT
1587
TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1588
{
1589
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1590 1591 1592 1593
    return infoPtr->clrBk;
}


1594
static inline LRESULT
1595
TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1596
{
1597
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599 1600 1601
    return infoPtr->clrText;
}


1602
static inline LRESULT
1603
TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1604
{
1605
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1606 1607 1608 1609 1610
    return infoPtr->uNumTools;
}


static LRESULT
1611
TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1612
{
1613
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1614
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1615
    TTTOOL_INFO *toolPtr;
1616
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1617

Alexandre Julliard's avatar
Alexandre Julliard committed
1618 1619
    if (lpToolInfo == NULL)
	return FALSE;
1620
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1621 1622 1623
	return FALSE;
    if (infoPtr->uNumTools == 0)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1624

Alexandre Julliard's avatar
Alexandre Julliard committed
1625
    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
1626 1627
    if (nTool == -1)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1628

1629
    TRACE("tool %d\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
1630

Alexandre Julliard's avatar
Alexandre Julliard committed
1631
    toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
1632 1633 1634 1635 1636

    /* copy tool data */
    lpToolInfo->uFlags   = toolPtr->uFlags;
    lpToolInfo->rect     = toolPtr->rect;
    lpToolInfo->hinst    = toolPtr->hinst;
1637
/*    lpToolInfo->lpszText = toolPtr->lpszText; */
1638
    lpToolInfo->lpszText = NULL;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1639

1640
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
Alexandre Julliard's avatar
Alexandre Julliard committed
1641 1642 1643 1644 1645 1646
	lpToolInfo->lParam = toolPtr->lParam;

    return TRUE;
}


1647
static LRESULT
1648
TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1649
{
1650
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1651
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
1652
    TTTOOL_INFO *toolPtr;
1653
    INT nTool;
1654 1655 1656

    if (lpToolInfo == NULL)
	return FALSE;
1657
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1658 1659 1660 1661 1662 1663 1664 1665
	return FALSE;
    if (infoPtr->uNumTools == 0)
	return FALSE;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
    if (nTool == -1)
	return FALSE;

1666
    TRACE("tool %d\n", nTool);
1667 1668 1669 1670 1671 1672 1673

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
    lpToolInfo->uFlags   = toolPtr->uFlags;
    lpToolInfo->rect     = toolPtr->rect;
    lpToolInfo->hinst    = toolPtr->hinst;
1674
/*    lpToolInfo->lpszText = toolPtr->lpszText; */
1675 1676
    lpToolInfo->lpszText = NULL;  /* FIXME */

1677
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
1678 1679 1680 1681
	lpToolInfo->lParam = toolPtr->lParam;

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1682 1683 1684


static LRESULT
1685
TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1686
{
1687
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1688
    LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1689
    TTTOOL_INFO *toolPtr;
1690
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1691 1692 1693 1694

    if (lptthit == 0)
	return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1695
    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1696 1697 1698
    if (nTool == -1)
	return FALSE;

1699
    TRACE("tool %d!\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
1700 1701

    /* copy tool data */
1702
    if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) {
1703 1704 1705 1706 1707 1708 1709
	toolPtr = &infoPtr->tools[nTool];

	lptthit->ti.uFlags   = toolPtr->uFlags;
	lptthit->ti.hwnd     = toolPtr->hwnd;
	lptthit->ti.uId      = toolPtr->uId;
	lptthit->ti.rect     = toolPtr->rect;
	lptthit->ti.hinst    = toolPtr->hinst;
1710
/*	lptthit->ti.lpszText = toolPtr->lpszText; */
1711 1712 1713
	lptthit->ti.lpszText = NULL;  /* FIXME */
	lptthit->ti.lParam   = toolPtr->lParam;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1714 1715 1716 1717 1718

    return TRUE;
}


1719
static LRESULT
1720
TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1721
{
1722
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1723
    LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam;
1724
    TTTOOL_INFO *toolPtr;
1725
    INT nTool;
1726 1727 1728 1729 1730 1731 1732 1733

    if (lptthit == 0)
	return FALSE;

    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
    if (nTool == -1)
	return FALSE;

1734
    TRACE("tool %d!\n", nTool);
1735 1736

    /* copy tool data */
1737
    if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) {
1738 1739 1740 1741 1742 1743 1744
	toolPtr = &infoPtr->tools[nTool];

	lptthit->ti.uFlags   = toolPtr->uFlags;
	lptthit->ti.hwnd     = toolPtr->hwnd;
	lptthit->ti.uId      = toolPtr->uId;
	lptthit->ti.rect     = toolPtr->rect;
	lptthit->ti.hinst    = toolPtr->hinst;
1745
/*	lptthit->ti.lpszText = toolPtr->lpszText; */
1746 1747 1748 1749 1750 1751
	lptthit->ti.lpszText = NULL;  /* FIXME */
	lptthit->ti.lParam   = toolPtr->lParam;
    }

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1752 1753 1754


static LRESULT
1755
TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1756
{
1757
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1758 1759
    LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam;
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1760

Alexandre Julliard's avatar
Alexandre Julliard committed
1761 1762
    if (lpti == NULL)
	return 0;
1763
    if (lpti->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1764
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1765

Alexandre Julliard's avatar
Alexandre Julliard committed
1766
    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti);
1767 1768 1769

    TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect));

Alexandre Julliard's avatar
Alexandre Julliard committed
1770
    if (nTool == -1) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1771

Alexandre Julliard's avatar
Alexandre Julliard committed
1772
    infoPtr->tools[nTool].rect = lpti->rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1773 1774 1775 1776 1777

    return 0;
}


1778
static LRESULT
1779
TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam)
1780
{
1781
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1782 1783
    LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam;
    INT nTool;
1784 1785 1786

    if (lpti == NULL)
	return 0;
1787
    if (lpti->cbSize < TTTOOLINFOW_V1_SIZE)
1788 1789 1790
	return FALSE;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti);
1791 1792 1793

    TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect));

1794 1795 1796 1797 1798 1799
    if (nTool == -1) return 0;

    infoPtr->tools[nTool].rect = lpti->rect;

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1800 1801


1802
static inline LRESULT
1803
TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1804
{
1805 1806
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    TOOLTIPS_Hide (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1807 1808 1809

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1810 1811 1812


static LRESULT
1813
TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1814
{
1815
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1816 1817
    LPMSG lpMsg = (LPMSG)lParam;
    POINT pt;
1818
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1819

Alexandre Julliard's avatar
Alexandre Julliard committed
1820
    if (lParam == 0) {
1821
	ERR("lpMsg == NULL!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1822 1823
	return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1824

Alexandre Julliard's avatar
Alexandre Julliard committed
1825 1826 1827 1828 1829 1830 1831
    switch (lpMsg->message) {
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
1832
	    TOOLTIPS_Hide (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1833 1834 1835
	    break;

	case WM_MOUSEMOVE:
1836 1837
	    pt.x = (short)LOWORD(lpMsg->lParam);
	    pt.y = (short)HIWORD(lpMsg->lParam);
1838 1839 1840
	    nOldTool = infoPtr->nTool;
	    infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
						       &pt);
1841
	    TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
1842
		  infoPtr->nTool, infoPtr->nCurrentTool);
1843
            TRACE("WM_MOUSEMOVE (%p %d %d)\n", hwnd, pt.x, pt.y);
1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860

	    if (infoPtr->nTool != nOldTool) {
	        if(infoPtr->nTool == -1) { /* Moved out of all tools */
		    TOOLTIPS_Hide(hwnd, infoPtr);
		    KillTimer(hwnd, ID_TIMERLEAVE);
		} else if (nOldTool == -1) { /* Moved from outside */
		    if(infoPtr->bActive) {
		        SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
			TRACE("timer 1 started!\n");
		    }
		} else { /* Moved from one to another */
		    TOOLTIPS_Hide (hwnd, infoPtr);
		    KillTimer(hwnd, ID_TIMERLEAVE);
		    if(infoPtr->bActive) {
		        SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
			TRACE("timer 1 started!\n");
		    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1861
		}
1862 1863 1864 1865
	    } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
	        KillTimer(hwnd, ID_TIMERPOP);
		SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
		TRACE("timer 2 restarted\n");
1866 1867 1868 1869
	    } else if(infoPtr->nTool != -1 && infoPtr->bActive) {
                /* previous show attempt didn't result in tooltip so try again */
		SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
		TRACE("timer 1 started!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1870 1871
	    }
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1872 1873
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1874 1875 1876 1877 1878
    return 0;
}


static LRESULT
1879
TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1880
{
1881
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1882
    INT nTime = (INT)LOWORD(lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1883 1884

    switch (wParam) {
1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
    case TTDT_AUTOMATIC:
        if (nTime <= 0)
	    nTime = GetDoubleClickTime();
	infoPtr->nReshowTime    = nTime / 5;
	infoPtr->nAutoPopTime   = nTime * 10;
	infoPtr->nInitialTime   = nTime;
	break;

    case TTDT_RESHOW:
        if(nTime < 0)
	    nTime = GetDoubleClickTime() / 5;
	infoPtr->nReshowTime = nTime;
	break;

    case TTDT_AUTOPOP:
        if(nTime < 0)
	    nTime = GetDoubleClickTime() * 10;
	infoPtr->nAutoPopTime = nTime;
	break;

    case TTDT_INITIAL:
        if(nTime < 0)
	    nTime = GetDoubleClickTime();
	infoPtr->nInitialTime = nTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1909 1910
	    break;

1911
    default:
1912
        WARN("Invalid wParam %lx\n", wParam);
1913
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1914
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1915 1916 1917 1918 1919

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1920
static LRESULT
1921
TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1922
{
1923
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1924
    LPRECT lpRect = (LPRECT)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1925 1926 1927 1928 1929 1930 1931 1932

    infoPtr->rcMargin.left   = lpRect->left;
    infoPtr->rcMargin.right  = lpRect->right;
    infoPtr->rcMargin.bottom = lpRect->bottom;
    infoPtr->rcMargin.top    = lpRect->top;

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1933 1934


1935
static inline LRESULT
1936
TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1937
{
1938
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
1939
    INT nTemp = infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1940

1941
    infoPtr->nMaxTipWidth = (INT)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1942

Alexandre Julliard's avatar
Alexandre Julliard committed
1943
    return nTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1944 1945 1946
}


1947
static inline LRESULT
1948
TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1949
{
1950
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1951 1952 1953 1954 1955 1956 1957

    infoPtr->clrBk = (COLORREF)wParam;

    return 0;
}


1958
static inline LRESULT
1959
TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1960
{
1961
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1962 1963 1964 1965 1966 1967 1968

    infoPtr->clrText = (COLORREF)wParam;

    return 0;
}


Robert Shearman's avatar
Robert Shearman committed
1969 1970 1971 1972 1973
static LRESULT
TOOLTIPS_SetTitleA (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    LPCSTR pszTitle = (LPCSTR)lParam;
1974
    UINT_PTR uTitleIcon = wParam;
Robert Shearman's avatar
Robert Shearman committed
1975 1976
    UINT size;

1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
    TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_a(pszTitle),
        (void*)uTitleIcon);

    Free(infoPtr->pszTitle);

    if (pszTitle)
    {
        size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, NULL, 0);
        infoPtr->pszTitle = Alloc(size);
        if (!infoPtr->pszTitle)
            return FALSE;
        MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR));
    }
    else
        infoPtr->pszTitle = NULL;
Robert Shearman's avatar
Robert Shearman committed
1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006

    if (uTitleIcon <= TTI_ERROR)
        infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
    else
        infoPtr->hTitleIcon = CopyIcon((HICON)wParam);

    return TRUE;
}


static LRESULT
TOOLTIPS_SetTitleW (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    LPCWSTR pszTitle = (LPCWSTR)lParam;
2007
    UINT_PTR uTitleIcon = wParam;
Robert Shearman's avatar
Robert Shearman committed
2008 2009
    UINT size;

2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
    TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_w(pszTitle),
        (void*)uTitleIcon);

    Free(infoPtr->pszTitle);

    if (pszTitle)
    {
        size = (strlenW(pszTitle)+1)*sizeof(WCHAR);
        infoPtr->pszTitle = Alloc(size);
        if (!infoPtr->pszTitle)
            return FALSE;
        memcpy(infoPtr->pszTitle, pszTitle, size);
    }
    else
        infoPtr->pszTitle = NULL;
Robert Shearman's avatar
Robert Shearman committed
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036

    if (uTitleIcon <= TTI_ERROR)
        infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
    else
        infoPtr->hTitleIcon = CopyIcon((HICON)wParam);

    TRACE("icon = %p\n", infoPtr->hTitleIcon);

    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2037
static LRESULT
2038
TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2039
{
2040
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2041
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2042
    TTTOOL_INFO *toolPtr;
2043
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
2044

Alexandre Julliard's avatar
Alexandre Julliard committed
2045 2046
    if (lpToolInfo == NULL)
	return 0;
2047
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2048
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2049

Alexandre Julliard's avatar
Alexandre Julliard committed
2050 2051
    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
    if (nTool == -1) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2052

2053
    TRACE("tool %d\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
2054

Alexandre Julliard's avatar
Alexandre Julliard committed
2055
    toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
2056 2057 2058 2059 2060 2061 2062 2063

    /* copy tool data */
    toolPtr->uFlags = lpToolInfo->uFlags;
    toolPtr->hwnd   = lpToolInfo->hwnd;
    toolPtr->uId    = lpToolInfo->uId;
    toolPtr->rect   = lpToolInfo->rect;
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
2064 2065
    if (IS_INTRESOURCE(lpToolInfo->lpszText)) {
	TRACE("set string id %x\n", LOWORD(lpToolInfo->lpszText));
2066
	toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
Alexandre Julliard's avatar
Alexandre Julliard committed
2067 2068
    }
    else if (lpToolInfo->lpszText) {
2069 2070
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
Alexandre Julliard's avatar
Alexandre Julliard committed
2071
	else {
2072
	    if ( (toolPtr->lpszText) &&
Frank Richter's avatar
Frank Richter committed
2073
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
2074 2075
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
2076 2077 2078
		toolPtr->lpszText = NULL;
	    }
	    if (lpToolInfo->lpszText) {
2079 2080
		INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
					      -1, NULL, 0);
2081
		toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
2082 2083
		MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
				    toolPtr->lpszText, len);
2084
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2085 2086 2087
	}
    }

2088
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA))
Alexandre Julliard's avatar
Alexandre Julliard committed
2089 2090 2091 2092 2093 2094
	toolPtr->lParam = lpToolInfo->lParam;

    return 0;
}


2095
static LRESULT
2096
TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2097
{
2098
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2099
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
2100
    TTTOOL_INFO *toolPtr;
2101
    INT nTool;
2102 2103 2104

    if (lpToolInfo == NULL)
	return 0;
2105
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
2106 2107 2108 2109 2110
	return 0;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
    if (nTool == -1) return 0;

2111
    TRACE("tool %d\n", nTool);
2112 2113 2114 2115 2116 2117 2118 2119 2120 2121

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
    toolPtr->uFlags = lpToolInfo->uFlags;
    toolPtr->hwnd   = lpToolInfo->hwnd;
    toolPtr->uId    = lpToolInfo->uId;
    toolPtr->rect   = lpToolInfo->rect;
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
2122 2123
    if (IS_INTRESOURCE(lpToolInfo->lpszText)) {
	TRACE("set string id %x!\n", LOWORD(lpToolInfo->lpszText));
2124 2125
	toolPtr->lpszText = lpToolInfo->lpszText;
    }
2126
    else {
2127 2128
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2129
	else {
2130
	    if ( (toolPtr->lpszText) &&
Frank Richter's avatar
Frank Richter committed
2131
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
2132 2133
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
2134 2135 2136
		toolPtr->lpszText = NULL;
	    }
	    if (lpToolInfo->lpszText) {
2137
		INT len = lstrlenW (lpToolInfo->lpszText);
2138
		toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
2139
		strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
2140 2141 2142 2143
	    }
	}
    }

2144
    if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW))
2145 2146
	toolPtr->lParam = lpToolInfo->lParam;

2147 2148 2149 2150 2151 2152 2153
    if (infoPtr->nCurrentTool == nTool)
    {
        TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool);

        if (infoPtr->szTipText[0] == 0)
            TOOLTIPS_Hide(hwnd, infoPtr);
        else
2154
            TOOLTIPS_Show (hwnd, infoPtr, FALSE);
2155 2156
    }

2157 2158
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2159 2160 2161


static LRESULT
2162
TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2163
{
2164
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2165

2166
    if ((BOOL)wParam) {
2167 2168 2169 2170 2171 2172 2173
	LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;

	if (lpToolInfo == NULL)
	    return 0;
	if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
	    return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
2174 2175 2176
	/* activate */
	infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
	if (infoPtr->nTrackTool != -1) {
2177
	    TRACE("activated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2178
	    infoPtr->bTrackActive = TRUE;
2179
	    TOOLTIPS_TrackShow (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2180 2181 2182 2183
	}
    }
    else {
	/* deactivate */
2184
	TOOLTIPS_TrackHide (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2185 2186 2187

	infoPtr->bTrackActive = FALSE;
	infoPtr->nTrackTool = -1;
2188

2189
	TRACE("deactivated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2190 2191 2192 2193 2194 2195 2196
    }

    return 0;
}


static LRESULT
2197
TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2198
{
2199
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2200

2201 2202
    infoPtr->xTrackPos = (INT)LOWORD(lParam);
    infoPtr->yTrackPos = (INT)HIWORD(lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2203 2204

    if (infoPtr->bTrackActive) {
2205
	TRACE("[%d %d]\n",
2206
	       infoPtr->xTrackPos, infoPtr->yTrackPos);
Alexandre Julliard's avatar
Alexandre Julliard committed
2207

2208
	TOOLTIPS_TrackShow (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2209 2210 2211 2212 2213 2214 2215
    }

    return 0;
}


static LRESULT
2216
TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2217
{
2218
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2219 2220

    if (infoPtr->nCurrentTool != -1)
2221
	UpdateWindow (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2222 2223 2224 2225 2226 2227

    return 0;
}


static LRESULT
2228
TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2229
{
2230
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2231
    LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2232
    TTTOOL_INFO *toolPtr;
2233
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
2234

Alexandre Julliard's avatar
Alexandre Julliard committed
2235 2236
    if (lpToolInfo == NULL)
	return 0;
2237
    if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2238
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2239 2240 2241 2242

    nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo);
    if (nTool == -1) return 0;

2243
    TRACE("tool %d\n", nTool);
Alexandre Julliard's avatar
Alexandre Julliard committed
2244 2245 2246 2247 2248 2249

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool text */
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
2250
    if (IS_INTRESOURCE(lpToolInfo->lpszText)){
2251
	toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText;
Alexandre Julliard's avatar
Alexandre Julliard committed
2252 2253
    }
    else if (lpToolInfo->lpszText) {
2254 2255
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA)
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
Alexandre Julliard's avatar
Alexandre Julliard committed
2256
	else {
2257
	    if ( (toolPtr->lpszText) &&
Frank Richter's avatar
Frank Richter committed
2258
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
2259 2260
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
2261 2262 2263
		toolPtr->lpszText = NULL;
	    }
	    if (lpToolInfo->lpszText) {
2264 2265
		INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText,
					      -1, NULL, 0);
2266
		toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
2267 2268
		MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1,
				    toolPtr->lpszText, len);
2269
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2270 2271 2272
	}
    }

2273
    if(infoPtr->nCurrentTool == -1) return 0;
2274 2275
    /* force repaint */
    if (infoPtr->bActive)
2276
	TOOLTIPS_Show (hwnd, infoPtr, FALSE);
2277
    else if (infoPtr->bTrackActive)
2278
	TOOLTIPS_TrackShow (hwnd, infoPtr);
2279

Alexandre Julliard's avatar
Alexandre Julliard committed
2280 2281 2282 2283
    return 0;
}


2284
static LRESULT
2285
TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2286
{
2287
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2288
    LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam;
2289
    TTTOOL_INFO *toolPtr;
2290
    INT nTool;
2291 2292 2293

    if (lpToolInfo == NULL)
	return 0;
2294
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
2295 2296 2297 2298 2299 2300
	return FALSE;

    nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo);
    if (nTool == -1)
	return 0;

2301
    TRACE("tool %d\n", nTool);
2302 2303 2304 2305 2306 2307

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool text */
    toolPtr->hinst  = lpToolInfo->hinst;

Frank Richter's avatar
Frank Richter committed
2308
    if (IS_INTRESOURCE(lpToolInfo->lpszText)){
2309 2310 2311
	toolPtr->lpszText = lpToolInfo->lpszText;
    }
    else if (lpToolInfo->lpszText) {
2312 2313
	if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW)
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
2314
	else {
2315
	    if ( (toolPtr->lpszText)  &&
Frank Richter's avatar
Frank Richter committed
2316
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
2317 2318
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
2319 2320 2321
		toolPtr->lpszText = NULL;
	    }
	    if (lpToolInfo->lpszText) {
2322
		INT len = lstrlenW (lpToolInfo->lpszText);
2323
		toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
2324
		strcpyW (toolPtr->lpszText, lpToolInfo->lpszText);
2325 2326 2327 2328
	    }
	}
    }

2329
    if(infoPtr->nCurrentTool == -1) return 0;
2330 2331
    /* force repaint */
    if (infoPtr->bActive)
2332
	TOOLTIPS_Show (hwnd, infoPtr, FALSE);
2333
    else if (infoPtr->bTrackActive)
2334
	TOOLTIPS_Show (hwnd, infoPtr, TRUE);
2335

2336 2337
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2338 2339 2340


static LRESULT
2341
TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2342
{
2343
    return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2344 2345
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2346 2347 2348


static LRESULT
2349
TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
2350 2351 2352 2353
{
    TOOLTIPS_INFO *infoPtr;

    /* allocate memory for info structure */
2354
    infoPtr = Alloc (sizeof(TOOLTIPS_INFO));
2355
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2356 2357 2358

    /* initialize info structure */
    infoPtr->bActive = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2359
    infoPtr->bTrackActive = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2360 2361 2362 2363

    infoPtr->nMaxTipWidth = -1;
    infoPtr->nTool = -1;
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2364
    infoPtr->nTrackTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
2365

Robert Shearman's avatar
Robert Shearman committed
2366 2367 2368
    /* initialize colours and fonts */
    TOOLTIPS_InitSystemSettings(infoPtr);

2369
    TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
2370

2371
    SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2372

Alexandre Julliard's avatar
Alexandre Julliard committed
2373 2374 2375 2376 2377
    return 0;
}


static LRESULT
2378
TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2379
{
2380
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2381
    TTTOOL_INFO *toolPtr;
2382
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2383 2384 2385 2386

    /* free tools */
    if (infoPtr->tools) {
	for (i = 0; i < infoPtr->uNumTools; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2387
	    toolPtr = &infoPtr->tools[i];
2388
	    if (toolPtr->lpszText) {
2389
		if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
2390
		     !IS_INTRESOURCE(toolPtr->lpszText) )
2391
		{
2392
		    Free (toolPtr->lpszText);
2393 2394
		    toolPtr->lpszText = NULL;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
2395 2396 2397
	    }

	    /* remove subclassing */
2398 2399
        if (toolPtr->uFlags & TTF_SUBCLASS) {
            if (toolPtr->uFlags & TTF_IDISHWND) {
2400
                RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
2401 2402
            }
            else {
2403
                RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
2404 2405 2406
            }
        }
    }
2407
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
2408 2409
    }

Robert Shearman's avatar
Robert Shearman committed
2410 2411 2412 2413 2414 2415 2416
    /* free title string */
    Free (infoPtr->pszTitle);
    /* free title icon if not a standard one */
    if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR)
        DeleteObject(infoPtr->hTitleIcon);

    /* delete fonts */
2417
    DeleteObject (infoPtr->hFont);
Robert Shearman's avatar
Robert Shearman committed
2418
    DeleteObject (infoPtr->hTitleFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
2419

Alexandre Julliard's avatar
Alexandre Julliard committed
2420
    /* free tool tips info data */
2421
    Free (infoPtr);
2422
    SetWindowLongPtrW(hwnd, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2423 2424 2425 2426 2427
    return 0;
}


static LRESULT
2428
TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2429
{
2430
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2431

2432
    return (LRESULT)infoPtr->hFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
2433 2434 2435
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2436
static LRESULT
2437
TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2438
{
2439
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2440

2441
    TOOLTIPS_Hide (hwnd, infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2442 2443 2444 2445 2446 2447

    return 0;
}


static LRESULT
2448
TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2449
{
2450 2451
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
    DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
2452

2453
    dwStyle &= ~(WS_CHILD | /*WS_MAXIMIZE |*/ WS_BORDER | WS_DLGFRAME);
2454
    dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
2455 2456 2457 2458 2459

    /* WS_BORDER only draws a border round the window rect, not the
     * window region, therefore it is useless to us in balloon mode */
    if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER;

2460
    SetWindowLongW (hwnd, GWL_STYLE, dwStyle);
Alexandre Julliard's avatar
Alexandre Julliard committed
2461

2462
    dwExStyle |= WS_EX_TOOLWINDOW;
2463
    SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
2464

Alexandre Julliard's avatar
Alexandre Julliard committed
2465 2466 2467 2468
    return TRUE;
}


2469
static LRESULT
2470
TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
2471
{
2472
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2473
    INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
2474

2475
    TRACE(" nTool=%d\n", nTool);
2476 2477 2478

    if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
	if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
2479
	    TRACE("-- in transparent mode!\n");
2480 2481 2482 2483
	    return HTTRANSPARENT;
	}
    }

2484
    return DefWindowProcW (hwnd, WM_NCHITTEST, wParam, lParam);
2485 2486 2487
}


2488 2489 2490
static LRESULT
TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
2491
    FIXME ("hwnd=%p wParam=%lx lParam=%lx\n", hwnd, wParam, lParam);
2492 2493 2494 2495 2496

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2497
static LRESULT
2498
TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2499
{
2500 2501
    HDC hdc;
    PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
2502

2503 2504
    hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam;
    TOOLTIPS_Refresh (hwnd, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
2505
    if (!wParam)
2506
	EndPaint (hwnd, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
2507 2508
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2509 2510 2511


static LRESULT
2512
TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2513
{
2514
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2515
    LOGFONTW lf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2516

2517
    if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf))
2518
        return 0;
2519

Robert Shearman's avatar
Robert Shearman committed
2520
    DeleteObject (infoPtr->hFont);
2521
    infoPtr->hFont = CreateFontIndirectW(&lf);
Alexandre Julliard's avatar
Alexandre Julliard committed
2522

Robert Shearman's avatar
Robert Shearman committed
2523 2524 2525 2526
    DeleteObject (infoPtr->hTitleFont);
    lf.lfWeight = FW_BOLD;
    infoPtr->hTitleFont = CreateFontIndirectW(&lf);

Alexandre Julliard's avatar
Alexandre Julliard committed
2527
    if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) {
2528
	FIXME("full redraw needed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2529 2530 2531 2532
    }

    return 0;
}
2533

2534
/******************************************************************
2535
 * TOOLTIPS_GetTextLength
2536 2537 2538 2539 2540 2541 2542
 *
 * This function is called when the tooltip receive a
 * WM_GETTEXTLENGTH message.
 * wParam : not used
 * lParam : not used
 *
 * returns the length, in characters, of the tip text
2543
 */
2544
static LRESULT
2545
TOOLTIPS_GetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam)
2546 2547
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2548
    return strlenW(infoPtr->szTipText);
2549
}
2550

2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
/******************************************************************
 * TOOLTIPS_OnWMGetText
 *
 * This function is called when the tooltip receive a
 * WM_GETTEXT message.
 * wParam : specifies the maximum number of characters to be copied
 * lParam : is the pointer to the buffer that will receive
 *          the tip text
 *
 * returns the number of characters copied
2561
 */
2562 2563 2564 2565
static LRESULT
TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2566 2567
    LRESULT res;
    LPWSTR pszText = (LPWSTR)lParam;
2568

2569
    if(!infoPtr->szTipText || !wParam)
2570 2571
        return 0;

2572 2573 2574 2575
    res = min(strlenW(infoPtr->szTipText)+1, wParam);
    memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR));
    pszText[res-1] = '\0';
    return res-1;
2576
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2577

Alexandre Julliard's avatar
Alexandre Julliard committed
2578
static LRESULT
2579
TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2580
{
2581
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2582
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
2583

2584
    TRACE("timer %ld (%p) expired!\n", wParam, hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2585

2586 2587 2588 2589 2590
    switch (wParam) {
    case ID_TIMERSHOW:
        KillTimer (hwnd, ID_TIMERSHOW);
	nOldTool = infoPtr->nTool;
	if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool)
2591
	    TOOLTIPS_Show (hwnd, infoPtr, FALSE);
2592 2593 2594 2595 2596 2597 2598 2599 2600
	break;

    case ID_TIMERPOP:
        TOOLTIPS_Hide (hwnd, infoPtr);
	break;

    case ID_TIMERLEAVE:
        nOldTool = infoPtr->nTool;
	infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE);
2601
	TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool,
2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
	      infoPtr->nTool, infoPtr->nCurrentTool);
	if (infoPtr->nTool != nOldTool) {
	    if(infoPtr->nTool == -1) { /* Moved out of all tools */
	        TOOLTIPS_Hide(hwnd, infoPtr);
		KillTimer(hwnd, ID_TIMERLEAVE);
	    } else if (nOldTool == -1) { /* Moved from outside */
	        ERR("How did this happen?\n");
	    } else { /* Moved from one to another */
	        TOOLTIPS_Hide (hwnd, infoPtr);
		KillTimer(hwnd, ID_TIMERLEAVE);
		if(infoPtr->bActive) {
		    SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
		    TRACE("timer 1 started!\n");
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
2616
	    }
2617 2618 2619 2620
	}
	break;

    default:
2621
        ERR("Unknown timer id %ld\n", wParam);
2622
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2623 2624 2625 2626 2627
    }
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2628
static LRESULT
2629
TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2630
{
2631
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2632

Robert Shearman's avatar
Robert Shearman committed
2633
    TOOLTIPS_InitSystemSettings (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2634 2635 2636

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2637 2638


Robert Shearman's avatar
Robert Shearman committed
2639
static LRESULT CALLBACK
2640
TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
Alexandre Julliard's avatar
Alexandre Julliard committed
2641
{
2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
    MSG msg;

    switch(uMsg) {
    case WM_MOUSEMOVE:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MBUTTONDOWN:
    case WM_MBUTTONUP:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
        msg.hwnd = hwnd;
	msg.message = uMsg;
	msg.wParam = wParam;
	msg.lParam = lParam;
2656
	TOOLTIPS_RelayEvent((HWND)dwRef, 0, (LPARAM)&msg);
2657 2658 2659 2660
	break;

    default:
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2661
    }
2662
    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2663 2664 2665
}


2666
static LRESULT CALLBACK
2667
TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2668
{
2669
    TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
Chris Morgan's avatar
Chris Morgan committed
2670
    if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2671
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2672 2673 2674
    switch (uMsg)
    {
	case TTM_ACTIVATE:
2675
	    return TOOLTIPS_Activate (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2676

2677
	case TTM_ADDTOOLA:
2678
	    return TOOLTIPS_AddToolA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2679

2680
	case TTM_ADDTOOLW:
2681
	    return TOOLTIPS_AddToolW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2682

2683
	case TTM_DELTOOLA:
2684
	    return TOOLTIPS_DelToolA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2685

2686
	case TTM_DELTOOLW:
2687
	    return TOOLTIPS_DelToolW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2688

2689
	case TTM_ENUMTOOLSA:
2690
	    return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2691

2692
	case TTM_ENUMTOOLSW:
2693
	    return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2694

2695 2696 2697
	case TTM_GETBUBBLESIZE:
	    return TOOLTIPS_GetBubbleSize (hwnd, wParam, lParam);

2698
	case TTM_GETCURRENTTOOLA:
2699
	    return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2700

2701
	case TTM_GETCURRENTTOOLW:
2702
	    return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2703 2704

	case TTM_GETDELAYTIME:
2705
	    return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2706 2707

	case TTM_GETMARGIN:
2708
	    return TOOLTIPS_GetMargin (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2709 2710

	case TTM_GETMAXTIPWIDTH:
2711
	    return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2712

2713
	case TTM_GETTEXTA:
2714
	    return TOOLTIPS_GetTextA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2715

2716
	case TTM_GETTEXTW:
2717
	    return TOOLTIPS_GetTextW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2718 2719

	case TTM_GETTIPBKCOLOR:
2720
	    return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2721 2722

	case TTM_GETTIPTEXTCOLOR:
2723
	    return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2724 2725

	case TTM_GETTOOLCOUNT:
2726
	    return TOOLTIPS_GetToolCount (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2727

2728
	case TTM_GETTOOLINFOA:
2729
	    return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2730

2731
	case TTM_GETTOOLINFOW:
2732
	    return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2733

2734
	case TTM_HITTESTA:
2735
	    return TOOLTIPS_HitTestA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2736

2737
	case TTM_HITTESTW:
2738
	    return TOOLTIPS_HitTestW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2739

2740
	case TTM_NEWTOOLRECTA:
2741
	    return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2742

2743
	case TTM_NEWTOOLRECTW:
2744
	    return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2745 2746

	case TTM_POP:
2747
	    return TOOLTIPS_Pop (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2748 2749

	case TTM_RELAYEVENT:
2750
	    return TOOLTIPS_RelayEvent (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2751

Alexandre Julliard's avatar
Alexandre Julliard committed
2752
	case TTM_SETDELAYTIME:
2753
	    return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2754 2755

	case TTM_SETMARGIN:
2756
	    return TOOLTIPS_SetMargin (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2757 2758

	case TTM_SETMAXTIPWIDTH:
2759
	    return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2760 2761

	case TTM_SETTIPBKCOLOR:
2762
	    return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2763 2764

	case TTM_SETTIPTEXTCOLOR:
2765
	    return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2766

Robert Shearman's avatar
Robert Shearman committed
2767 2768 2769 2770 2771 2772
	case TTM_SETTITLEA:
	    return TOOLTIPS_SetTitleA (hwnd, wParam, lParam);

	case TTM_SETTITLEW:
	    return TOOLTIPS_SetTitleW (hwnd, wParam, lParam);

2773
	case TTM_SETTOOLINFOA:
2774
	    return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2775

2776
	case TTM_SETTOOLINFOW:
2777
	    return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2778 2779

	case TTM_TRACKACTIVATE:
2780
	    return TOOLTIPS_TrackActivate (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2781 2782

	case TTM_TRACKPOSITION:
2783
	    return TOOLTIPS_TrackPosition (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2784 2785

	case TTM_UPDATE:
2786
	    return TOOLTIPS_Update (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2787

2788
	case TTM_UPDATETIPTEXTA:
2789
	    return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2790

2791
	case TTM_UPDATETIPTEXTW:
2792
	    return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2793 2794

	case TTM_WINDOWFROMPOINT:
2795
	    return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2796 2797 2798


	case WM_CREATE:
2799
	    return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2800 2801

	case WM_DESTROY:
2802
	    return TOOLTIPS_Destroy (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2803

Alexandre Julliard's avatar
Alexandre Julliard committed
2804
	case WM_ERASEBKGND:
2805 2806
	    /* we draw the background in WM_PAINT */
	    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2807

Alexandre Julliard's avatar
Alexandre Julliard committed
2808
	case WM_GETFONT:
2809
	    return TOOLTIPS_GetFont (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2810

Robert Shearman's avatar
Robert Shearman committed
2811 2812
	case WM_GETTEXT:
	    return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam);
2813

Robert Shearman's avatar
Robert Shearman committed
2814
	case WM_GETTEXTLENGTH:
2815
	    return TOOLTIPS_GetTextLength (hwnd, wParam, lParam);
2816

2817 2818 2819 2820 2821 2822
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
Alexandre Julliard's avatar
Alexandre Julliard committed
2823
	case WM_MOUSEMOVE:
2824
	    return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2825 2826

	case WM_NCCREATE:
2827
	    return TOOLTIPS_NCCreate (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2828

2829
	case WM_NCHITTEST:
2830
	    return TOOLTIPS_NCHitTest (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2831

2832 2833
	case WM_NOTIFYFORMAT:
	    return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam);
2834

2835
	case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
2836
	case WM_PAINT:
2837
	    return TOOLTIPS_Paint (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2838 2839

	case WM_SETFONT:
2840
	    return TOOLTIPS_SetFont (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2841

Alexandre Julliard's avatar
Alexandre Julliard committed
2842
	case WM_TIMER:
2843
	    return TOOLTIPS_Timer (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2844

Alexandre Julliard's avatar
Alexandre Julliard committed
2845
	case WM_WININICHANGE:
2846
	    return TOOLTIPS_WinIniChange (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2847 2848

	default:
2849
	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2850
		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2851
		     uMsg, wParam, lParam);
2852
	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2853 2854 2855 2856
    }
}


2857
VOID
2858
TOOLTIPS_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2859
{
2860
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2861

2862
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2863
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2864
    wndClass.lpfnWndProc   = TOOLTIPS_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2865 2866
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2867
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2868
    wndClass.hbrBackground = 0;
2869
    wndClass.lpszClassName = TOOLTIPS_CLASSW;
2870

2871
    RegisterClassW (&wndClass);
Robert Shearman's avatar
Robert Shearman committed
2872 2873 2874 2875 2876 2877 2878 2879

    hTooltipIcons[TTI_NONE] = NULL;
    hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule,
        (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0);
    hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule,
        (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0);
    hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule,
        (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2880
}
2881 2882 2883


VOID
2884
TOOLTIPS_Unregister (void)
2885
{
Robert Shearman's avatar
Robert Shearman committed
2886
    int i;
2887 2888
    for (i = TTI_INFO; i <= TTI_ERROR; i++)
        DestroyIcon(hTooltipIcons[i]);
2889
    UnregisterClassW (TOOLTIPS_CLASSW, NULL);
2890
}