tooltips.c 63.7 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


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

    TTTOOL_INFO *tools;
} TOOLTIPS_INFO;
151

152 153 154
#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
155

156

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

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

Robert Shearman's avatar
Robert Shearman committed
169 170 171 172 173
#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

174
#define MAX_TEXT_SIZE_A 80 /* maximum retrieving text size by ANSI message */
175

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


180 181 182 183 184 185 186 187
static inline BOOL TOOLTIPS_IsCallbackString(LPCWSTR str, BOOL isW)
{
    if (isW)
      return str == LPSTR_TEXTCALLBACKW;
    else
      return (LPCSTR)str == LPSTR_TEXTCALLBACKA;
}

188
static inline UINT_PTR
Robert Shearman's avatar
Robert Shearman committed
189
TOOLTIPS_GetTitleIconIndex(HICON hIcon)
Robert Shearman's avatar
Robert Shearman committed
190 191 192 193 194 195 196 197 198 199 200 201 202
{
    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;

203 204
    infoPtr->clrBk   = comctl32_color.clrInfoBk;
    infoPtr->clrText = comctl32_color.clrInfoText;
Robert Shearman's avatar
Robert Shearman committed
205 206 207

    DeleteObject (infoPtr->hFont);
    nclm.cbSize = sizeof(nclm);
208
    SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
Robert Shearman's avatar
Robert Shearman committed
209 210 211 212 213 214 215
    infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont);

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

216 217
/* Custom draw routines */
static void
218
TOOLTIPS_customdraw_fill(const TOOLTIPS_INFO *infoPtr, NMTTCUSTOMDRAW *lpnmttcd,
219 220 221 222
                         HDC hdc, const RECT *rcBounds, UINT uFlags)
{
    ZeroMemory(lpnmttcd, sizeof(NMTTCUSTOMDRAW));
    lpnmttcd->uDrawFlags = uFlags;
223
    lpnmttcd->nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    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
251
static void
252
TOOLTIPS_Refresh (const TOOLTIPS_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
253
{
254 255 256 257 258
    RECT rc;
    INT oldBkMode;
    HFONT hOldFont;
    HBRUSH hBrush;
    UINT uFlags = DT_EXTERNALLEADING;
259
    HRGN hRgn = NULL;
260
    DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
261 262
    NMTTCUSTOMDRAW nmttcd;
    DWORD cdmode;
Alexandre Julliard's avatar
Alexandre Julliard committed
263

Alexandre Julliard's avatar
Alexandre Julliard committed
264 265
    if (infoPtr->nMaxTipWidth > -1)
	uFlags |= DT_WORDBREAK;
266
    if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_NOPREFIX)
Alexandre Julliard's avatar
Alexandre Julliard committed
267
	uFlags |= DT_NOPREFIX;
268
    GetClientRect (infoPtr->hwndSelf, &rc);
269

270
    hBrush = CreateSolidBrush(infoPtr->clrBk);
271

Robert Shearman's avatar
Robert Shearman committed
272 273
    oldBkMode = SetBkMode (hdc, TRANSPARENT);
    SetTextColor (hdc, infoPtr->clrText);
274 275 276 277
    hOldFont = SelectObject (hdc, infoPtr->hFont);

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

282 283 284 285
    if (dwStyle & TTS_BALLOON)
    {
        /* create a region to store result into */
        hRgn = CreateRectRgn(0, 0, 0, 0);
286

287
        GetWindowRgn(infoPtr->hwndSelf, hRgn);
288 289 290 291 292

        /* fill the background */
        FillRgn(hdc, hRgn, hBrush);
        DeleteObject(hBrush);
        hBrush = NULL;
Robert Shearman's avatar
Robert Shearman committed
293 294 295 296 297 298 299 300
    }
    else
    {
        /* fill the background */
        FillRect(hdc, &rc, hBrush);
        DeleteObject(hBrush);
        hBrush = NULL;
    }
301

Robert Shearman's avatar
Robert Shearman committed
302 303
    if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle)
    {
304 305 306 307 308
        /* 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);
309
        if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT;
Robert Shearman's avatar
Robert Shearman committed
310 311 312 313 314 315

        if (infoPtr->pszTitle)
        {
            RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom};
            int height;
            BOOL icon_present;
316
            HFONT prevFont;
Robert Shearman's avatar
Robert Shearman committed
317 318 319 320 321 322 323 324 325 326 327

            /* 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 */
328
            prevFont = SelectObject (hdc, infoPtr->hTitleFont);
Robert Shearman's avatar
Robert Shearman committed
329
            height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX);
330
            SelectObject (hdc, prevFont);
Robert Shearman's avatar
Robert Shearman committed
331 332
            rc.top += height + BALLOON_TITLE_TEXT_SPACING;
        }
333 334 335 336 337 338 339 340 341 342 343
    }
    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 */
344
    DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
345 346 347 348 349 350

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

351
    /* be polite and reset the things we changed in the dc */
352
    SelectObject (hdc, hOldFont);
353 354 355 356 357 358 359 360 361 362 363 364 365 366
    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
367 368
}

369
static void TOOLTIPS_GetDispInfoA(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer)
370 371 372 373 374
{
    NMTTDISPINFOA ttnmdi;

    /* fill NMHDR struct */
    ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
375
    ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf;
376
    ttnmdi.hdr.idFrom = toolPtr->uId;
377
    ttnmdi.hdr.code = TTN_GETDISPINFOA; /* == TTN_NEEDTEXTA */
378
    ttnmdi.lpszText = ttnmdi.szText;
379 380 381
    ttnmdi.uFlags = toolPtr->uFlags;
    ttnmdi.lParam = toolPtr->lParam;

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

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

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

413
        SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
414 415 416

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

425
static void TOOLTIPS_GetDispInfoW(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer)
426 427 428 429 430
{
    NMTTDISPINFOW ttnmdi;

    /* fill NMHDR struct */
    ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW));
431
    ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf;
432
    ttnmdi.hdr.idFrom = toolPtr->uId;
433
    ttnmdi.hdr.code = TTN_GETDISPINFOW; /* == TTN_NEEDTEXTW */
434
    ttnmdi.lpszText = ttnmdi.szText;
435 436 437
    ttnmdi.uFlags = toolPtr->uFlags;
    ttnmdi.lParam = toolPtr->lParam;

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

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

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

469
        SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
470 471 472

        if (IS_INTRESOURCE(ttnmdi.lpszText)) {
            LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
473
                   buffer, INFOTIPSIZE);
474 475
        } else if (ttnmdi.lpszText &&
                   ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
476
            Str_GetPtrW(ttnmdi.lpszText, buffer, INFOTIPSIZE);
477 478 479
        }
    }

480
}
Alexandre Julliard's avatar
Alexandre Julliard committed
481

Robert Shearman's avatar
Robert Shearman committed
482
static void
483
TOOLTIPS_GetTipText (const TOOLTIPS_INFO *infoPtr, INT nTool, WCHAR *buffer)
Alexandre Julliard's avatar
Alexandre Julliard committed
484
{
485
    TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
Alexandre Julliard's avatar
Alexandre Julliard committed
486

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

511
    TRACE("%s\n", debugstr_w(buffer));
Alexandre Julliard's avatar
Alexandre Julliard committed
512 513 514
}


Robert Shearman's avatar
Robert Shearman committed
515
static void
516
TOOLTIPS_CalcTipSize (const TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
517
{
518 519
    HDC hdc;
    HFONT hOldFont;
520
    DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
521 522
    UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
    RECT rc = {0, 0, 0, 0};
Robert Shearman's avatar
Robert Shearman committed
523
    SIZE title = {0, 0};
Alexandre Julliard's avatar
Alexandre Julliard committed
524 525 526 527 528

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

533
    hdc = GetDC (infoPtr->hwndSelf);
Robert Shearman's avatar
Robert Shearman committed
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
    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);
    }
550 551 552
    hOldFont = SelectObject (hdc, infoPtr->hFont);
    DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
    SelectObject (hdc, hOldFont);
553
    ReleaseDC (infoPtr->hwndSelf, hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
554

Robert Shearman's avatar
Robert Shearman committed
555
    if ((style & TTS_BALLOON) || infoPtr->pszTitle)
556
    {
Robert Shearman's avatar
Robert Shearman committed
557
        lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN +
558
                       infoPtr->rcMargin.left + infoPtr->rcMargin.right;
Robert Shearman's avatar
Robert Shearman committed
559
        lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN +
560 561
                       infoPtr->rcMargin.bottom + infoPtr->rcMargin.top +
                       BALLOON_STEMHEIGHT;
562 563 564 565 566 567 568 569
    }
    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
570 571 572
}


Robert Shearman's avatar
Robert Shearman committed
573
static void
574
TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate)
Alexandre Julliard's avatar
Alexandre Julliard committed
575
{
Alexandre Julliard's avatar
Alexandre Julliard committed
576
    TTTOOL_INFO *toolPtr;
577 578 579
    HMONITOR monitor;
    MONITORINFO mon_info;
    RECT rect;
580
    SIZE size;
581
    NMHDR  hdr;
582
    int ptfx = 0;
583
    DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
584
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
585

586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
    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
603
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
604

605
    TRACE("Show tooltip pre %d! (%p)\n", nTool, infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
606

607
    TOOLTIPS_GetTipText (infoPtr, nTool, infoPtr->szTipText);
Alexandre Julliard's avatar
Alexandre Julliard committed
608

609 610
    if (infoPtr->szTipText[0] == '\0')
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
611

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

614 615 616 617
    if (!track_activate)
        infoPtr->nCurrentTool = infoPtr->nTool;

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

619
    hdr.hwndFrom = infoPtr->hwndSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
620
    hdr.idFrom = toolPtr->uId;
Alexandre Julliard's avatar
Alexandre Julliard committed
621
    hdr.code = TTN_SHOW;
622
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
623

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

626
    TOOLTIPS_CalcTipSize (infoPtr, &size);
627
    TRACE("size %d x %d\n", size.cx, size.cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
628

629 630
    if (track_activate)
    {
631 632 633
        rect.left = infoPtr->xTrackPos;
        rect.top  = infoPtr->yTrackPos;
        ptfx = rect.left;
Alexandre Julliard's avatar
Alexandre Julliard committed
634

635 636 637 638 639
        if (toolPtr->uFlags & TTF_CENTERTIP)
        {
            rect.left -= (size.cx / 2);
            if (!(style & TTS_BALLOON))
                rect.top  -= (size.cy / 2);
640
        }
641 642
        if (!(infoPtr->bToolBelow = (infoPtr->yTrackPos + size.cy <= GetSystemMetrics(SM_CYSCREEN))))
            rect.top -= size.cy;
643 644

        if (!(toolPtr->uFlags & TTF_ABSOLUTE))
645
        {
646 647 648 649 650
            if (style & TTS_BALLOON)
                rect.left -= BALLOON_STEMINDENT;
            else
            {
                RECT rcTool;
651

652 653
                if (toolPtr->uFlags & TTF_IDISHWND)
                    GetWindowRect ((HWND)toolPtr->uId, &rcTool);
654 655
                else
                {
656 657
                    rcTool = toolPtr->rect;
                    MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2);
658 659
                }

660 661 662 663
                /* 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;
664
            }
665
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
666
    }
667 668 669 670 671 672 673 674 675 676 677 678 679 680
    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)
681
            {
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
                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);
697 698 699
            }
            else
            {
700 701
                rect.top  = rc.bottom + 2;
                infoPtr->bToolBelow = TRUE;
702 703 704 705
            }
        }
        else
        {
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
            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;
            }
727
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
728 729
    }

730
    TRACE("pos %d - %d\n", rect.left, rect.top);
Alexandre Julliard's avatar
Alexandre Julliard committed
731 732 733 734

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

735
    /* check position */
736 737 738 739 740 741 742 743

    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;
744
    }
745 746 747
    if (rect.left < mon_info.rcWork.left) rect.left = mon_info.rcWork.left;

    if( rect.bottom > mon_info.rcWork.bottom ) {
748 749 750 751 752 753
        RECT rc;

	if (toolPtr->uFlags & TTF_IDISHWND)
	    GetWindowRect ((HWND)toolPtr->uId, &rc);
	else {
	    rc = toolPtr->rect;
754
	    MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
755
	}
756 757 758 759
	rect.bottom = rc.top - 2;
    	rect.top = rect.bottom - size.cy;
    }

760 761
    AdjustWindowRectEx (&rect, GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE),
			FALSE, GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE));
Alexandre Julliard's avatar
Alexandre Julliard committed
762

763
    if (style & TTS_BALLOON)
764 765
    {
        HRGN hRgn;
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 799 800 801 802 803 804 805 806
        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);
807

808 809
        CombineRgn(hRgn, hRgn, hrStem, RGN_OR);
        DeleteObject(hrStem);
810

811
        SetWindowRgn(infoPtr->hwndSelf, hRgn, FALSE);
812 813 814 815
        /* we don't free the region handle as the system deletes it when 
         * it is no longer needed */
    }

816
    SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, rect.left, rect.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
817
		    rect.right - rect.left, rect.bottom - rect.top,
818
		    SWP_SHOWWINDOW | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
819

820
    /* repaint the tooltip */
821 822
    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
    UpdateWindow(infoPtr->hwndSelf);
823

824 825
    if (!track_activate)
    {
826
        SetTimer (infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
827
        TRACE("timer 2 started!\n");
828
        SetTimer (infoPtr->hwndSelf, ID_TIMERLEAVE, infoPtr->nReshowTime, 0);
829 830
        TRACE("timer 3 started!\n");
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
831 832 833
}


Robert Shearman's avatar
Robert Shearman committed
834
static void
835
TOOLTIPS_Hide (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
836
{
Alexandre Julliard's avatar
Alexandre Julliard committed
837
    TTTOOL_INFO *toolPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
838 839
    NMHDR hdr;

840
    TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, infoPtr->hwndSelf);
841

Alexandre Julliard's avatar
Alexandre Julliard committed
842 843 844
    if (infoPtr->nCurrentTool == -1)
	return;

Alexandre Julliard's avatar
Alexandre Julliard committed
845
    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
846
    KillTimer (infoPtr->hwndSelf, ID_TIMERPOP);
Alexandre Julliard's avatar
Alexandre Julliard committed
847

848
    hdr.hwndFrom = infoPtr->hwndSelf;
Alexandre Julliard's avatar
Alexandre Julliard committed
849
    hdr.idFrom = toolPtr->uId;
Alexandre Julliard's avatar
Alexandre Julliard committed
850
    hdr.code = TTN_POP;
851
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
Alexandre Julliard's avatar
Alexandre Julliard committed
852

Alexandre Julliard's avatar
Alexandre Julliard committed
853
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
854

855
    SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
856
		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
857 858 859
}


Robert Shearman's avatar
Robert Shearman committed
860
static void
861
TOOLTIPS_TrackShow (TOOLTIPS_INFO *infoPtr)
862
{
863
    TOOLTIPS_Show(infoPtr, TRUE);
864 865 866
}


Robert Shearman's avatar
Robert Shearman committed
867
static void
868
TOOLTIPS_TrackHide (const TOOLTIPS_INFO *infoPtr)
869 870 871 872
{
    TTTOOL_INFO *toolPtr;
    NMHDR hdr;

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

875 876 877 878 879
    if (infoPtr->nTrackTool == -1)
	return;

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

880
    hdr.hwndFrom = infoPtr->hwndSelf;
881 882
    hdr.idFrom = toolPtr->uId;
    hdr.code = TTN_POP;
883
    SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
884

885
    SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
886
		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
887 888
}

889 890
/* Structure layout is the same for TTTOOLINFOW and TTTOOLINFOA,
   this helper is used in both cases. */
891
static INT
892
TOOLTIPS_GetToolFromInfoT (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
893 894
{
    TTTOOL_INFO *toolPtr;
895
    UINT nTool;
896 897 898 899

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

900
	if (!(toolPtr->uFlags & TTF_IDISHWND) &&
901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
	    (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;
}


918
static INT
919
TOOLTIPS_GetToolFromPoint (const TOOLTIPS_INFO *infoPtr, HWND hwnd, const POINT *lpPt)
Alexandre Julliard's avatar
Alexandre Julliard committed
920 921
{
    TTTOOL_INFO *toolPtr;
922
    UINT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
923

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

Alexandre Julliard's avatar
Alexandre Julliard committed
927
	if (!(toolPtr->uFlags & TTF_IDISHWND)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
928 929
	    if (hwnd != toolPtr->hwnd)
		continue;
930
	    if (!PtInRect (&toolPtr->rect, *lpPt))
Alexandre Julliard's avatar
Alexandre Julliard committed
931
		continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
932
	    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
933 934 935
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
936 937 938 939
    for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
	toolPtr = &infoPtr->tools[nTool];

	if (toolPtr->uFlags & TTF_IDISHWND) {
940
	    if ((HWND)toolPtr->uId == hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
941 942 943 944
		return nTool;
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
945 946
    return -1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
947

948 949 950 951 952 953 954 955 956 957 958
static inline void
TOOLTIPS_CopyInfoT (const TTTOOL_INFO *toolPtr, TTTOOLINFOW *ti, BOOL isW)
{
    if (ti->lpszText) {
        if (toolPtr->lpszText == NULL ||
            IS_INTRESOURCE(toolPtr->lpszText) ||
            toolPtr->lpszText == LPSTR_TEXTCALLBACKW)
            ti->lpszText = toolPtr->lpszText;
        else if (isW)
            strcpyW (ti->lpszText, toolPtr->lpszText);
        else
959
            /* ANSI version, the buffer is maximum 80 bytes without null. */
960
            WideCharToMultiByte(CP_ACP, 0, toolPtr->lpszText, -1,
961
                                (LPSTR)ti->lpszText, MAX_TEXT_SIZE_A, NULL, NULL);
962 963
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
964

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


977
static INT
978
TOOLTIPS_CheckTool (const TOOLTIPS_INFO *infoPtr, BOOL bShowTest)
Alexandre Julliard's avatar
Alexandre Julliard committed
979
{
980 981 982
    POINT pt;
    HWND hwndTool;
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
983

984
    GetCursorPos (&pt);
985
    hwndTool = (HWND)SendMessageW (infoPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
986
    if (hwndTool == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
987
	return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
988

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

994 995
    if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) {
	if (!TOOLTIPS_IsWindowActive (GetWindow (infoPtr->hwndSelf, GW_OWNER)))
Alexandre Julliard's avatar
Alexandre Julliard committed
996 997 998
	    return -1;
    }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1001
    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1002 1003 1004
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1005
static LRESULT
1006
TOOLTIPS_Activate (TOOLTIPS_INFO *infoPtr, BOOL activate)
Alexandre Julliard's avatar
Alexandre Julliard committed
1007
{
1008
    infoPtr->bActive = activate;
Alexandre Julliard's avatar
Alexandre Julliard committed
1009

Alexandre Julliard's avatar
Alexandre Julliard committed
1010
    if (infoPtr->bActive)
1011
	TRACE("activate!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1012

1013
    if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
1014
	TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1015 1016 1017 1018 1019 1020

    return 0;
}


static LRESULT
1021
TOOLTIPS_AddToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1022 1023
{
    TTTOOL_INFO *toolPtr;
1024
    INT nResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1025

1026
    if (!ti) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027

1028
    TRACE("add tool (%p) %p %ld%s!\n",
1029 1030
	   infoPtr->hwndSelf, ti->hwnd, ti->uId,
	   (ti->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
Alexandre Julliard's avatar
Alexandre Julliard committed
1031

Alexandre Julliard's avatar
Alexandre Julliard committed
1032
    if (infoPtr->uNumTools == 0) {
1033
	infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1034 1035 1036 1037 1038
	toolPtr = infoPtr->tools;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1039
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1040 1041
	memcpy (infoPtr->tools, oldTools,
		infoPtr->uNumTools * sizeof(TTTOOL_INFO));
1042
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1043 1044 1045 1046 1047 1048
	toolPtr = &infoPtr->tools[infoPtr->uNumTools];
    }

    infoPtr->uNumTools++;

    /* copy tool data */
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
    toolPtr->uFlags = ti->uFlags;
    toolPtr->hwnd   = ti->hwnd;
    toolPtr->uId    = ti->uId;
    toolPtr->rect   = ti->rect;
    toolPtr->hinst  = ti->hinst;

    if (IS_INTRESOURCE(ti->lpszText)) {
	TRACE("add string id %x\n", LOWORD(ti->lpszText));
	toolPtr->lpszText = ti->lpszText;
    }
    else if (ti->lpszText) {
	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW)) {
1061
	    TRACE("add CALLBACK!\n");
1062
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
Alexandre Julliard's avatar
Alexandre Julliard committed
1063
	}
1064 1065 1066 1067 1068 1069
	else if (isW) {
	    INT len = lstrlenW (ti->lpszText);
	    TRACE("add text %s!\n", debugstr_w(ti->lpszText));
	    toolPtr->lpszText =	Alloc ((len + 1)*sizeof(WCHAR));
	    strcpyW (toolPtr->lpszText, ti->lpszText);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1070
	else {
1071 1072
	    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, NULL, 0);
	    TRACE("add text \"%s\"!\n", (LPSTR)ti->lpszText);
1073
	    toolPtr->lpszText =	Alloc (len * sizeof(WCHAR));
1074
	    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, toolPtr->lpszText, len);
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076 1077
	}
    }

1078 1079
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	toolPtr->lParam = ti->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1080

Alexandre Julliard's avatar
Alexandre Julliard committed
1081
    /* install subclassing hook */
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1084
	    SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
1085
			      (DWORD_PTR)infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1086 1087
	}
	else {
1088
	    SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
1089
			      (DWORD_PTR)infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
	}
1091
	TRACE("subclassing installed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1092 1093
    }

1094 1095
    nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
                            (WPARAM)infoPtr->hwndSelf, NF_QUERY);
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
    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
1106 1107 1108 1109
    return TRUE;
}


1110
static LRESULT
1111
TOOLTIPS_DelToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1112 1113
{
    TTTOOL_INFO *toolPtr;
1114
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1115

1116 1117 1118 1119 1120 1121
    if (!ti) return 0;
    if (isW && ti->cbSize > TTTOOLINFOW_V2_SIZE &&
               ti->cbSize != TTTOOLINFOW_V3_SIZE)
	return 0;
    if (infoPtr->uNumTools == 0)
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1122

1123
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1124

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

1127
    if (nTool == -1)
1128
        return 0;
1129

1130
    /* make sure the tooltip has disappeared before deleting it */
1131
    TOOLTIPS_Hide(infoPtr);
1132

Alexandre Julliard's avatar
Alexandre Julliard committed
1133
    /* delete text string */
1134
    toolPtr = &infoPtr->tools[nTool];
1135
    if (toolPtr->lpszText) {
1136
	if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
1137
	     !IS_INTRESOURCE(toolPtr->lpszText) )
1138
	    Free (toolPtr->lpszText);
Alexandre Julliard's avatar
Alexandre Julliard committed
1139 1140
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1141 1142 1143
    /* remove subclassing */
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1144
	    RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1145 1146
	}
	else {
1147
	    RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1148 1149 1150
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1151 1152
    /* delete tool from tool list */
    if (infoPtr->uNumTools == 1) {
1153
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1154 1155 1156 1157 1158
	infoPtr->tools = NULL;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1159
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1160

Alexandre Julliard's avatar
Alexandre Julliard committed
1161
	if (nTool > 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1162
	    memcpy (&infoPtr->tools[0], &oldTools[0],
Alexandre Julliard's avatar
Alexandre Julliard committed
1163
		    nTool * sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1164

Alexandre Julliard's avatar
Alexandre Julliard committed
1165 1166 1167
	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
1168

1169
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1170 1171
    }

1172 1173
    /* update any indices affected by delete */

1174 1175
    /* destroying tool that mouse was on on last relayed mouse move */
    if (infoPtr->nTool == nTool)
1176
        /* -1 means no current tool (0 means first tool) */
1177
        infoPtr->nTool = -1;
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
    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--;
1192

Alexandre Julliard's avatar
Alexandre Julliard committed
1193
    infoPtr->uNumTools--;
1194

1195 1196
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1197 1198

static LRESULT
1199 1200
TOOLTIPS_EnumToolsT (const TOOLTIPS_INFO *infoPtr, UINT uIndex, TTTOOLINFOW *ti,
                     BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1201 1202 1203
{
    TTTOOL_INFO *toolPtr;

1204 1205
    if (!ti) return FALSE;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1206 1207 1208
	return FALSE;
    if (uIndex >= infoPtr->uNumTools)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1209

1210
    TRACE("index=%u\n", uIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
1211 1212 1213 1214

    toolPtr = &infoPtr->tools[uIndex];

    /* copy tool data */
1215 1216 1217 1218 1219
    ti->uFlags   = toolPtr->uFlags;
    ti->hwnd     = toolPtr->hwnd;
    ti->uId      = toolPtr->uId;
    ti->rect     = toolPtr->rect;
    ti->hinst    = toolPtr->hinst;
1220
    TOOLTIPS_CopyInfoT (toolPtr, ti, isW);
Alexandre Julliard's avatar
Alexandre Julliard committed
1221

1222 1223
    if (ti->cbSize >= TTTOOLINFOA_V2_SIZE)
	ti->lParam = toolPtr->lParam;
1224 1225 1226

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

1228
static LRESULT
1229
TOOLTIPS_GetBubbleSize (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
1230 1231 1232 1233 1234 1235
{
    INT nTool;
    SIZE size;

    if (lpToolInfo == NULL)
	return FALSE;
1236
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1237 1238
	return FALSE;

1239
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, lpToolInfo);
1240 1241 1242 1243
    if (nTool == -1) return 0;

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

1244
    TOOLTIPS_CalcTipSize (infoPtr, &size);
1245
    TRACE("size %d x %d\n", size.cx, size.cy);
1246 1247 1248

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

static LRESULT
1251
TOOLTIPS_GetCurrentToolT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1252 1253 1254
{
    TTTOOL_INFO *toolPtr;

1255 1256
    if (ti) {
        if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1257 1258
            return FALSE;

1259 1260 1261 1262
	if (infoPtr->nCurrentTool > -1) {
	    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];

	    /* copy tool data */
1263 1264 1265
	    ti->uFlags   = toolPtr->uFlags;
	    ti->rect     = toolPtr->rect;
	    ti->hinst    = toolPtr->hinst;
1266
	    TOOLTIPS_CopyInfoT (toolPtr, ti, isW);
1267

1268 1269
	    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
		ti->lParam = toolPtr->lParam;
1270 1271 1272 1273 1274 1275 1276 1277 1278

	    return TRUE;
	}
	else
	    return FALSE;
    }
    else
	return (infoPtr->nCurrentTool != -1);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1279 1280 1281


static LRESULT
1282
TOOLTIPS_GetDelayTime (const TOOLTIPS_INFO *infoPtr, DWORD duration)
Alexandre Julliard's avatar
Alexandre Julliard committed
1283
{
1284
    switch (duration) {
1285 1286
    case TTDT_RESHOW:
        return infoPtr->nReshowTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1287

1288 1289
    case TTDT_AUTOPOP:
        return infoPtr->nAutoPopTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1290

1291 1292 1293
    case TTDT_INITIAL:
    case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
        return infoPtr->nInitialTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1294

1295
    default:
1296
        WARN("Invalid duration flag %x\n", duration);
1297
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299
    }

1300
    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1301 1302 1303 1304
}


static LRESULT
1305
TOOLTIPS_GetMargin (const TOOLTIPS_INFO *infoPtr, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1306 1307 1308 1309 1310 1311 1312 1313
{
    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
1314 1315


1316
static inline LRESULT
1317
TOOLTIPS_GetMaxTipWidth (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1318
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1319
    return infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1320 1321 1322 1323
}


static LRESULT
1324
TOOLTIPS_GetTextT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1325
{
1326
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1327

1328 1329
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1330
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1331

1332
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1333
    if (nTool == -1) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1334

1335
    if (infoPtr->tools[nTool].lpszText == NULL)
1336 1337
	return 0;

1338 1339 1340 1341 1342 1343
    if (isW) {
        ti->lpszText[0] = '\0';
        TOOLTIPS_GetTipText(infoPtr, nTool, ti->lpszText);
    }
    else {
        WCHAR buffer[INFOTIPSIZE];
1344

1345 1346
        /* 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
1347 1348
           one it supplies is.  According to the test result, it's up to
           80 bytes by the ANSI version. */
1349

1350 1351 1352
        buffer[0] = '\0';
        TOOLTIPS_GetTipText(infoPtr, nTool, buffer);
        WideCharToMultiByte(CP_ACP, 0, buffer, -1, (LPSTR)ti->lpszText,
1353
                                                   MAX_TEXT_SIZE_A, NULL, NULL);
1354
    }
1355 1356 1357

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1358 1359


1360
static inline LRESULT
1361
TOOLTIPS_GetTipBkColor (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1362 1363 1364 1365 1366
{
    return infoPtr->clrBk;
}


1367
static inline LRESULT
1368
TOOLTIPS_GetTipTextColor (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370 1371 1372 1373
{
    return infoPtr->clrText;
}


1374
static inline LRESULT
1375
TOOLTIPS_GetToolCount (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1376 1377 1378 1379 1380 1381
{
    return infoPtr->uNumTools;
}


static LRESULT
1382
TOOLTIPS_GetToolInfoT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1383 1384
{
    TTTOOL_INFO *toolPtr;
1385
    INT nTool;
1386

1387 1388
    if (!ti) return FALSE;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1389 1390 1391 1392
	return FALSE;
    if (infoPtr->uNumTools == 0)
	return FALSE;

1393
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1394 1395 1396
    if (nTool == -1)
	return FALSE;

1397
    TRACE("tool %d\n", nTool);
1398 1399 1400 1401

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
1402 1403 1404
    ti->uFlags   = toolPtr->uFlags;
    ti->rect     = toolPtr->rect;
    ti->hinst    = toolPtr->hinst;
1405
    TOOLTIPS_CopyInfoT (toolPtr, ti, isW);
Alexandre Julliard's avatar
Alexandre Julliard committed
1406

1407 1408
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	ti->lParam = toolPtr->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1409 1410 1411 1412 1413

    return TRUE;
}


1414
static LRESULT
1415 1416
TOOLTIPS_HitTestT (const TOOLTIPS_INFO *infoPtr, LPTTHITTESTINFOW lptthit,
                   BOOL isW)
1417 1418
{
    TTTOOL_INFO *toolPtr;
1419
    INT nTool;
1420 1421 1422 1423 1424 1425 1426 1427

    if (lptthit == 0)
	return FALSE;

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

1428
    TRACE("tool %d!\n", nTool);
1429 1430

    /* copy tool data */
1431
    if (lptthit->ti.cbSize >= TTTOOLINFOW_V1_SIZE) {
1432 1433 1434 1435 1436 1437 1438
	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;
1439
	TOOLTIPS_CopyInfoT (toolPtr, &lptthit->ti, isW);
1440 1441
	if (lptthit->ti.cbSize >= TTTOOLINFOW_V2_SIZE)
	    lptthit->ti.lParam   = toolPtr->lParam;
1442 1443 1444 1445
    }

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1446 1447 1448


static LRESULT
1449
TOOLTIPS_NewToolRectT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti)
1450
{
1451
    INT nTool;
1452

1453 1454
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1455 1456
	return FALSE;

1457
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1458

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

1461 1462
    if (nTool == -1) return 0;

1463
    infoPtr->tools[nTool].rect = ti->rect;
1464 1465 1466

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1467 1468


1469
static inline LRESULT
1470
TOOLTIPS_Pop (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1471
{
1472
    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474 1475

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1476 1477 1478


static LRESULT
1479
TOOLTIPS_RelayEvent (TOOLTIPS_INFO *infoPtr, LPMSG lpMsg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1480
{
1481
    POINT pt;
1482
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1483

1484
    if (!lpMsg) {
1485
	ERR("lpMsg == NULL!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1486 1487
	return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1488

Alexandre Julliard's avatar
Alexandre Julliard committed
1489 1490 1491 1492 1493 1494 1495
    switch (lpMsg->message) {
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
1496
	    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1497 1498 1499
	    break;

	case WM_MOUSEMOVE:
1500 1501
	    pt.x = (short)LOWORD(lpMsg->lParam);
	    pt.y = (short)HIWORD(lpMsg->lParam);
1502 1503 1504
	    nOldTool = infoPtr->nTool;
	    infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
						       &pt);
1505
	    TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool,
1506
		  infoPtr->nTool, infoPtr->nCurrentTool);
1507
            TRACE("WM_MOUSEMOVE (%p %d %d)\n", infoPtr->hwndSelf, pt.x, pt.y);
1508 1509 1510

	    if (infoPtr->nTool != nOldTool) {
	        if(infoPtr->nTool == -1) { /* Moved out of all tools */
1511 1512
		    TOOLTIPS_Hide(infoPtr);
		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1513 1514
		} else if (nOldTool == -1) { /* Moved from outside */
		    if(infoPtr->bActive) {
1515
		        SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1516 1517 1518
			TRACE("timer 1 started!\n");
		    }
		} else { /* Moved from one to another */
1519 1520
		    TOOLTIPS_Hide (infoPtr);
		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1521
		    if(infoPtr->bActive) {
1522
		        SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1523 1524
			TRACE("timer 1 started!\n");
		    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1525
		}
1526
	    } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1527 1528
	        KillTimer(infoPtr->hwndSelf, ID_TIMERPOP);
		SetTimer(infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1529
		TRACE("timer 2 restarted\n");
1530 1531
	    } else if(infoPtr->nTool != -1 && infoPtr->bActive) {
                /* previous show attempt didn't result in tooltip so try again */
1532
		SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1533
		TRACE("timer 1 started!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1534 1535
	    }
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1536 1537
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1538 1539 1540 1541 1542
    return 0;
}


static LRESULT
1543
TOOLTIPS_SetDelayTime (TOOLTIPS_INFO *infoPtr, DWORD duration, INT nTime)
Alexandre Julliard's avatar
Alexandre Julliard committed
1544
{
1545
    switch (duration) {
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
    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
1570 1571
	    break;

1572
    default:
1573
        WARN("Invalid duration flag %x\n", duration);
1574
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1575
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1576 1577 1578 1579 1580

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1581
static LRESULT
1582
TOOLTIPS_SetMargin (TOOLTIPS_INFO *infoPtr, const RECT *lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1583 1584 1585 1586 1587 1588 1589 1590
{
    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
1591 1592


1593
static inline LRESULT
1594
TOOLTIPS_SetMaxTipWidth (TOOLTIPS_INFO *infoPtr, INT MaxWidth)
Alexandre Julliard's avatar
Alexandre Julliard committed
1595
{
1596
    INT nTemp = infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1597

1598
    infoPtr->nMaxTipWidth = MaxWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1599

Alexandre Julliard's avatar
Alexandre Julliard committed
1600
    return nTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1601 1602 1603
}


1604
static inline LRESULT
1605
TOOLTIPS_SetTipBkColor (TOOLTIPS_INFO *infoPtr, COLORREF clrBk)
Alexandre Julliard's avatar
Alexandre Julliard committed
1606
{
1607
    infoPtr->clrBk = clrBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
1608 1609 1610 1611 1612

    return 0;
}


1613
static inline LRESULT
1614
TOOLTIPS_SetTipTextColor (TOOLTIPS_INFO *infoPtr, COLORREF clrText)
Alexandre Julliard's avatar
Alexandre Julliard committed
1615
{
1616
    infoPtr->clrText = clrText;
Alexandre Julliard's avatar
Alexandre Julliard committed
1617 1618 1619 1620 1621

    return 0;
}


Robert Shearman's avatar
Robert Shearman committed
1622
static LRESULT
1623 1624
TOOLTIPS_SetTitleT (TOOLTIPS_INFO *infoPtr, UINT_PTR uTitleIcon, LPCWSTR pszTitle,
                    BOOL isW)
Robert Shearman's avatar
Robert Shearman committed
1625 1626 1627
{
    UINT size;

1628
    TRACE("hwnd = %p, title = %s, icon = %p\n", infoPtr->hwndSelf, debugstr_w(pszTitle),
1629 1630 1631 1632 1633 1634
        (void*)uTitleIcon);

    Free(infoPtr->pszTitle);

    if (pszTitle)
    {
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
        if (isW)
        {
            size = (strlenW(pszTitle)+1)*sizeof(WCHAR);
            infoPtr->pszTitle = Alloc(size);
            if (!infoPtr->pszTitle)
                return FALSE;
            memcpy(infoPtr->pszTitle, pszTitle, size);
        }
        else
        {
1645
            size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, NULL, 0);
1646 1647 1648
            infoPtr->pszTitle = Alloc(size);
            if (!infoPtr->pszTitle)
                return FALSE;
1649
            MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR));
1650
        }
1651 1652 1653
    }
    else
        infoPtr->pszTitle = NULL;
Robert Shearman's avatar
Robert Shearman committed
1654 1655 1656 1657

    if (uTitleIcon <= TTI_ERROR)
        infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
    else
1658
        infoPtr->hTitleIcon = CopyIcon((HICON)uTitleIcon);
Robert Shearman's avatar
Robert Shearman committed
1659 1660 1661 1662 1663 1664 1665

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

    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1666
static LRESULT
1667
TOOLTIPS_SetToolInfoT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1668 1669
{
    TTTOOL_INFO *toolPtr;
1670
    INT nTool;
1671

1672 1673
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1674 1675
	return 0;

1676
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1677 1678
    if (nTool == -1) return 0;

1679
    TRACE("tool %d\n", nTool);
1680 1681 1682 1683

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
1684 1685 1686 1687 1688
    toolPtr->uFlags = ti->uFlags;
    toolPtr->hwnd   = ti->hwnd;
    toolPtr->uId    = ti->uId;
    toolPtr->rect   = ti->rect;
    toolPtr->hinst  = ti->hinst;
1689

1690 1691 1692
    if (IS_INTRESOURCE(ti->lpszText)) {
	TRACE("set string id %x!\n", LOWORD(ti->lpszText));
	toolPtr->lpszText = ti->lpszText;
1693
    }
1694
    else {
1695
	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1696
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1697
	else {
1698
	    if ( (toolPtr->lpszText) &&
Frank Richter's avatar
Frank Richter committed
1699
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1700 1701
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
1702 1703
		toolPtr->lpszText = NULL;
	    }
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716
	    if (ti->lpszText) {
		if (isW) {
		    INT len = lstrlenW (ti->lpszText);
		    toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
		    strcpyW (toolPtr->lpszText, ti->lpszText);
		}
		else {
		    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText,
					      -1, NULL, 0);
		    toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
		    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1,
					toolPtr->lpszText, len);
		}
1717 1718 1719 1720
	    }
	}
    }

1721 1722
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	toolPtr->lParam = ti->lParam;
1723

1724 1725
    if (infoPtr->nCurrentTool == nTool)
    {
1726
        TOOLTIPS_GetTipText (infoPtr, infoPtr->nCurrentTool, infoPtr->szTipText);
1727 1728

        if (infoPtr->szTipText[0] == 0)
1729
            TOOLTIPS_Hide(infoPtr);
1730
        else
1731
            TOOLTIPS_Show (infoPtr, FALSE);
1732 1733
    }

1734 1735
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1736 1737 1738


static LRESULT
1739
TOOLTIPS_TrackActivate (TOOLTIPS_INFO *infoPtr, BOOL track_activate, const TTTOOLINFOA *ti)
Alexandre Julliard's avatar
Alexandre Julliard committed
1740
{
1741
    if (track_activate) {
1742

1743 1744
	if (!ti) return 0;
	if (ti->cbSize < TTTOOLINFOA_V1_SIZE)
1745 1746
	    return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1747
	/* activate */
1748
	infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoT (infoPtr, (const TTTOOLINFOW*)ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1749
	if (infoPtr->nTrackTool != -1) {
1750
	    TRACE("activated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1751
	    infoPtr->bTrackActive = TRUE;
1752
	    TOOLTIPS_TrackShow (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1753 1754 1755 1756
	}
    }
    else {
	/* deactivate */
1757
	TOOLTIPS_TrackHide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1758 1759 1760

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

1762
	TRACE("deactivated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1763 1764 1765 1766 1767 1768 1769
    }

    return 0;
}


static LRESULT
1770
TOOLTIPS_TrackPosition (TOOLTIPS_INFO *infoPtr, LPARAM coord)
Alexandre Julliard's avatar
Alexandre Julliard committed
1771
{
1772 1773
    infoPtr->xTrackPos = (INT)LOWORD(coord);
    infoPtr->yTrackPos = (INT)HIWORD(coord);
Alexandre Julliard's avatar
Alexandre Julliard committed
1774 1775

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

1779
	TOOLTIPS_TrackShow (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1780 1781 1782 1783 1784 1785 1786
    }

    return 0;
}


static LRESULT
1787
TOOLTIPS_Update (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1788 1789
{
    if (infoPtr->nCurrentTool != -1)
1790
	UpdateWindow (infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1791 1792 1793 1794 1795 1796

    return 0;
}


static LRESULT
1797
TOOLTIPS_UpdateTipTextT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1798 1799
{
    TTTOOL_INFO *toolPtr;
1800
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1801

1802 1803
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1804
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1805

1806
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1807 1808 1809
    if (nTool == -1)
	return 0;

1810
    TRACE("tool %d\n", nTool);
1811 1812 1813 1814

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool text */
1815
    toolPtr->hinst  = ti->hinst;
1816

1817 1818
    if (IS_INTRESOURCE(ti->lpszText)){
	toolPtr->lpszText = ti->lpszText;
1819
    }
1820 1821
    else if (ti->lpszText) {
	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1822
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1823
	else {
1824
	    if ( (toolPtr->lpszText)  &&
Frank Richter's avatar
Frank Richter committed
1825
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1826 1827
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
1828 1829
		toolPtr->lpszText = NULL;
	    }
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
	    if (ti->lpszText) {
		if (isW) {
		    INT len = lstrlenW (ti->lpszText);
		    toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
		    strcpyW (toolPtr->lpszText, ti->lpszText);
		}
		else {
		    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText,
						-1, NULL, 0);
		    toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
		    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1,
					toolPtr->lpszText, len);
	        }
1843 1844 1845 1846
	    }
	}
    }

1847
    if(infoPtr->nCurrentTool == -1) return 0;
1848 1849
    /* force repaint */
    if (infoPtr->bActive)
1850
	TOOLTIPS_Show (infoPtr, FALSE);
1851
    else if (infoPtr->bTrackActive)
1852
	TOOLTIPS_Show (infoPtr, TRUE);
1853

1854 1855
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1856 1857


Alexandre Julliard's avatar
Alexandre Julliard committed
1858
static LRESULT
1859
TOOLTIPS_Create (HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1860 1861 1862 1863
{
    TOOLTIPS_INFO *infoPtr;

    /* allocate memory for info structure */
1864
    infoPtr = Alloc (sizeof(TOOLTIPS_INFO));
1865
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1866 1867 1868

    /* initialize info structure */
    infoPtr->bActive = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1869
    infoPtr->bTrackActive = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1870 1871 1872 1873

    infoPtr->nMaxTipWidth = -1;
    infoPtr->nTool = -1;
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1874
    infoPtr->nTrackTool = -1;
1875
    infoPtr->hwndSelf = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1876

Robert Shearman's avatar
Robert Shearman committed
1877 1878 1879
    /* initialize colours and fonts */
    TOOLTIPS_InitSystemSettings(infoPtr);

1880
    TOOLTIPS_SetDelayTime(infoPtr, TTDT_AUTOMATIC, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1881

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1884 1885 1886 1887 1888
    return 0;
}


static LRESULT
1889
TOOLTIPS_Destroy (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1890
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1891
    TTTOOL_INFO *toolPtr;
1892
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1893 1894 1895 1896

    /* free tools */
    if (infoPtr->tools) {
	for (i = 0; i < infoPtr->uNumTools; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1897
	    toolPtr = &infoPtr->tools[i];
1898
	    if (toolPtr->lpszText) {
1899
		if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
1900
		     !IS_INTRESOURCE(toolPtr->lpszText) )
1901
		{
1902
		    Free (toolPtr->lpszText);
1903 1904
		    toolPtr->lpszText = NULL;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
1905 1906 1907
	    }

	    /* remove subclassing */
1908 1909
        if (toolPtr->uFlags & TTF_SUBCLASS) {
            if (toolPtr->uFlags & TTF_IDISHWND) {
1910
                RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
1911 1912
            }
            else {
1913
                RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
1914 1915 1916
            }
        }
    }
1917
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1918 1919
    }

Robert Shearman's avatar
Robert Shearman committed
1920 1921 1922 1923 1924 1925 1926
    /* 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 */
1927
    DeleteObject (infoPtr->hFont);
Robert Shearman's avatar
Robert Shearman committed
1928
    DeleteObject (infoPtr->hTitleFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
1929

Alexandre Julliard's avatar
Alexandre Julliard committed
1930
    /* free tool tips info data */
1931
    SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
1932
    Free (infoPtr);
1933

Alexandre Julliard's avatar
Alexandre Julliard committed
1934 1935 1936 1937
    return 0;
}


1938 1939
static inline LRESULT
TOOLTIPS_GetFont (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1940
{
1941
    return (LRESULT)infoPtr->hFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
1942 1943 1944
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1945
static LRESULT
1946
TOOLTIPS_MouseMessage (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1947
{
1948
    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1949 1950 1951 1952 1953 1954

    return 0;
}


static LRESULT
1955
TOOLTIPS_NCCreate (HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1956
{
1957 1958
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
    DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
1959

1960
    dwStyle &= ~(WS_CHILD | /*WS_MAXIMIZE |*/ WS_BORDER | WS_DLGFRAME);
1961
    dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
1962 1963 1964 1965 1966

    /* 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;

1967
    SetWindowLongW (hwnd, GWL_STYLE, dwStyle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1968

1969
    dwExStyle |= WS_EX_TOOLWINDOW;
1970
    SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
1971

Alexandre Julliard's avatar
Alexandre Julliard committed
1972 1973 1974 1975
    return TRUE;
}


1976
static LRESULT
1977
TOOLTIPS_NCHitTest (const TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1978
{
1979
    INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
1980

1981
    TRACE(" nTool=%d\n", nTool);
1982 1983 1984

    if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
	if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
1985
	    TRACE("-- in transparent mode!\n");
1986 1987 1988 1989
	    return HTTRANSPARENT;
	}
    }

1990
    return DefWindowProcW (infoPtr->hwndSelf, WM_NCHITTEST, wParam, lParam);
1991 1992 1993
}


1994
static LRESULT
1995
TOOLTIPS_NotifyFormat (TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1996
{
1997
    FIXME ("hwnd=%p wParam=%lx lParam=%lx\n", infoPtr->hwndSelf, wParam, lParam);
1998 1999 2000 2001 2002

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2003
static LRESULT
2004
TOOLTIPS_Paint (const TOOLTIPS_INFO *infoPtr, HDC hDC)
Alexandre Julliard's avatar
Alexandre Julliard committed
2005
{
2006 2007
    HDC hdc;
    PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
2008

2009
    hdc = (hDC == NULL) ? BeginPaint (infoPtr->hwndSelf, &ps) : hDC;
2010
    TOOLTIPS_Refresh (infoPtr, hdc);
2011
    if (!hDC)
2012
	EndPaint (infoPtr->hwndSelf, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
2013 2014
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2015 2016 2017


static LRESULT
2018
TOOLTIPS_SetFont (TOOLTIPS_INFO *infoPtr, HFONT hFont, BOOL redraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
2019
{
2020
    LOGFONTW lf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2021

2022
    if(!GetObjectW(hFont, sizeof(lf), &lf))
2023
        return 0;
2024

Robert Shearman's avatar
Robert Shearman committed
2025
    DeleteObject (infoPtr->hFont);
2026
    infoPtr->hFont = CreateFontIndirectW(&lf);
Alexandre Julliard's avatar
Alexandre Julliard committed
2027

Robert Shearman's avatar
Robert Shearman committed
2028 2029 2030 2031
    DeleteObject (infoPtr->hTitleFont);
    lf.lfWeight = FW_BOLD;
    infoPtr->hTitleFont = CreateFontIndirectW(&lf);

2032
    if (redraw && infoPtr->nCurrentTool != -1) {
2033
	FIXME("full redraw needed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2034 2035 2036 2037
    }

    return 0;
}
2038

2039
/******************************************************************
2040
 * TOOLTIPS_GetTextLength
2041 2042 2043 2044 2045
 *
 * This function is called when the tooltip receive a
 * WM_GETTEXTLENGTH message.
 *
 * returns the length, in characters, of the tip text
2046
 */
2047 2048
static inline LRESULT
TOOLTIPS_GetTextLength(const TOOLTIPS_INFO *infoPtr)
2049
{
2050
    return strlenW(infoPtr->szTipText);
2051
}
2052

2053 2054 2055 2056 2057 2058 2059 2060 2061 2062
/******************************************************************
 * 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
2063
 */
2064
static LRESULT
2065
TOOLTIPS_OnWMGetText (const TOOLTIPS_INFO *infoPtr, WPARAM size, LPWSTR pszText)
2066
{
2067
    LRESULT res;
2068

2069
    if(!size)
2070 2071
        return 0;

2072
    res = min(strlenW(infoPtr->szTipText)+1, size);
2073 2074 2075
    memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR));
    pszText[res-1] = '\0';
    return res-1;
2076
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2077

Alexandre Julliard's avatar
Alexandre Julliard committed
2078
static LRESULT
2079
TOOLTIPS_Timer (TOOLTIPS_INFO *infoPtr, INT iTimer)
Alexandre Julliard's avatar
Alexandre Julliard committed
2080
{
2081
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
2082

2083
    TRACE("timer %d (%p) expired!\n", iTimer, infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
2084

2085
    switch (iTimer) {
2086
    case ID_TIMERSHOW:
2087
        KillTimer (infoPtr->hwndSelf, ID_TIMERSHOW);
2088
	nOldTool = infoPtr->nTool;
2089 2090
	if ((infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, TRUE)) == nOldTool)
	    TOOLTIPS_Show (infoPtr, FALSE);
2091 2092 2093
	break;

    case ID_TIMERPOP:
2094
        TOOLTIPS_Hide (infoPtr);
2095 2096 2097 2098
	break;

    case ID_TIMERLEAVE:
        nOldTool = infoPtr->nTool;
2099 2100
	infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, FALSE);
	TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool,
2101 2102 2103
	      infoPtr->nTool, infoPtr->nCurrentTool);
	if (infoPtr->nTool != nOldTool) {
	    if(infoPtr->nTool == -1) { /* Moved out of all tools */
2104 2105
	        TOOLTIPS_Hide(infoPtr);
		KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
2106 2107 2108
	    } else if (nOldTool == -1) { /* Moved from outside */
	        ERR("How did this happen?\n");
	    } else { /* Moved from one to another */
2109 2110
	        TOOLTIPS_Hide (infoPtr);
		KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
2111
		if(infoPtr->bActive) {
2112
		    SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
2113 2114
		    TRACE("timer 1 started!\n");
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
2115
	    }
2116 2117 2118 2119
	}
	break;

    default:
2120
        ERR("Unknown timer id %d\n", iTimer);
2121
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2122 2123 2124 2125 2126
    }
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2127
static LRESULT
2128
TOOLTIPS_WinIniChange (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2129
{
Robert Shearman's avatar
Robert Shearman committed
2130
    TOOLTIPS_InitSystemSettings (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2131 2132 2133

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2134 2135


Robert Shearman's avatar
Robert Shearman committed
2136
static LRESULT CALLBACK
2137
TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
Alexandre Julliard's avatar
Alexandre Julliard committed
2138
{
2139
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr ((HWND)dwRef);
2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
    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;
2154
	TOOLTIPS_RelayEvent(infoPtr, &msg);
2155 2156 2157 2158
	break;

    default:
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2159
    }
2160
    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2161 2162 2163
}


2164
static LRESULT CALLBACK
2165
TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2166
{
2167 2168
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);

2169
    TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2170
    if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2171
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2172 2173 2174
    switch (uMsg)
    {
	case TTM_ACTIVATE:
2175
	    return TOOLTIPS_Activate (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2176

2177 2178
	case TTM_ADDTOOLA:
	case TTM_ADDTOOLW:
2179
	    return TOOLTIPS_AddToolT (infoPtr, (LPTTTOOLINFOW)lParam, uMsg == TTM_ADDTOOLW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2180

2181 2182
	case TTM_DELTOOLA:
	case TTM_DELTOOLW:
2183 2184
	    return TOOLTIPS_DelToolT (infoPtr, (LPTOOLINFOW)lParam,
                                      uMsg == TTM_DELTOOLW);
2185 2186
	case TTM_ENUMTOOLSA:
	case TTM_ENUMTOOLSW:
2187 2188
	    return TOOLTIPS_EnumToolsT (infoPtr, (UINT)wParam, (LPTTTOOLINFOW)lParam,
                                        uMsg == TTM_ENUMTOOLSW);
2189
	case TTM_GETBUBBLESIZE:
2190
	    return TOOLTIPS_GetBubbleSize (infoPtr, (LPTTTOOLINFOW)lParam);
2191

2192 2193
	case TTM_GETCURRENTTOOLA:
	case TTM_GETCURRENTTOOLW:
2194 2195
	    return TOOLTIPS_GetCurrentToolT (infoPtr, (LPTTTOOLINFOW)lParam,
                                             uMsg == TTM_GETCURRENTTOOLW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2196 2197

	case TTM_GETDELAYTIME:
2198
	    return TOOLTIPS_GetDelayTime (infoPtr, (DWORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2199 2200

	case TTM_GETMARGIN:
2201
	    return TOOLTIPS_GetMargin (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2202 2203

	case TTM_GETMAXTIPWIDTH:
2204
	    return TOOLTIPS_GetMaxTipWidth (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2205

2206 2207
	case TTM_GETTEXTA:
	case TTM_GETTEXTW:
2208 2209
	    return TOOLTIPS_GetTextT (infoPtr, (LPTTTOOLINFOW)lParam,
                                      uMsg == TTM_GETTEXTW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2210 2211

	case TTM_GETTIPBKCOLOR:
2212
	    return TOOLTIPS_GetTipBkColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2213 2214

	case TTM_GETTIPTEXTCOLOR:
2215
	    return TOOLTIPS_GetTipTextColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2216 2217

	case TTM_GETTOOLCOUNT:
2218
	    return TOOLTIPS_GetToolCount (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2219

2220 2221
	case TTM_GETTOOLINFOA:
	case TTM_GETTOOLINFOW:
2222 2223
	    return TOOLTIPS_GetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
                                          uMsg == TTM_GETTOOLINFOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2224

2225 2226
	case TTM_HITTESTA:
	case TTM_HITTESTW:
2227 2228
	    return TOOLTIPS_HitTestT (infoPtr, (LPTTHITTESTINFOW)lParam,
                                      uMsg == TTM_HITTESTW);
2229 2230
	case TTM_NEWTOOLRECTA:
	case TTM_NEWTOOLRECTW:
2231 2232
	    return TOOLTIPS_NewToolRectT (infoPtr, (LPTTTOOLINFOW)lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
2233
	case TTM_POP:
2234
	    return TOOLTIPS_Pop (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2235 2236

	case TTM_RELAYEVENT:
2237
	    return TOOLTIPS_RelayEvent (infoPtr, (LPMSG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2238

Alexandre Julliard's avatar
Alexandre Julliard committed
2239
	case TTM_SETDELAYTIME:
2240
	    return TOOLTIPS_SetDelayTime (infoPtr, (DWORD)wParam, (INT)LOWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2241 2242

	case TTM_SETMARGIN:
2243
	    return TOOLTIPS_SetMargin (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2244 2245

	case TTM_SETMAXTIPWIDTH:
2246
	    return TOOLTIPS_SetMaxTipWidth (infoPtr, (INT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2247 2248

	case TTM_SETTIPBKCOLOR:
2249
	    return TOOLTIPS_SetTipBkColor (infoPtr, (COLORREF)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2250 2251

	case TTM_SETTIPTEXTCOLOR:
2252
	    return TOOLTIPS_SetTipTextColor (infoPtr, (COLORREF)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2253

Robert Shearman's avatar
Robert Shearman committed
2254 2255
	case TTM_SETTITLEA:
	case TTM_SETTITLEW:
2256 2257
	    return TOOLTIPS_SetTitleT (infoPtr, (UINT_PTR)wParam, (LPCWSTR)lParam,
                                       uMsg == TTM_SETTITLEW);
Robert Shearman's avatar
Robert Shearman committed
2258

2259 2260
	case TTM_SETTOOLINFOA:
	case TTM_SETTOOLINFOW:
2261 2262
	    return TOOLTIPS_SetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
                                          uMsg == TTM_SETTOOLINFOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2263 2264

	case TTM_TRACKACTIVATE:
2265
	    return TOOLTIPS_TrackActivate (infoPtr, (BOOL)wParam, (LPTTTOOLINFOA)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2266 2267

	case TTM_TRACKPOSITION:
2268
	    return TOOLTIPS_TrackPosition (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2269 2270

	case TTM_UPDATE:
2271
	    return TOOLTIPS_Update (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2272

2273 2274
	case TTM_UPDATETIPTEXTA:
	case TTM_UPDATETIPTEXTW:
2275 2276
	    return TOOLTIPS_UpdateTipTextT (infoPtr, (LPTTTOOLINFOW)lParam,
                                            uMsg == TTM_UPDATETIPTEXTW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2277 2278

	case TTM_WINDOWFROMPOINT:
2279
	    return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2280 2281

	case WM_CREATE:
2282
	    return TOOLTIPS_Create (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2283 2284

	case WM_DESTROY:
2285
	    return TOOLTIPS_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2286

Alexandre Julliard's avatar
Alexandre Julliard committed
2287
	case WM_ERASEBKGND:
2288 2289
	    /* we draw the background in WM_PAINT */
	    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2290

Alexandre Julliard's avatar
Alexandre Julliard committed
2291
	case WM_GETFONT:
2292
	    return TOOLTIPS_GetFont (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2293

Robert Shearman's avatar
Robert Shearman committed
2294
	case WM_GETTEXT:
2295
	    return TOOLTIPS_OnWMGetText (infoPtr, wParam, (LPWSTR)lParam);
2296

Robert Shearman's avatar
Robert Shearman committed
2297
	case WM_GETTEXTLENGTH:
2298
	    return TOOLTIPS_GetTextLength (infoPtr);
2299

2300 2301 2302 2303 2304 2305
	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
2306
	case WM_MOUSEMOVE:
2307
	    return TOOLTIPS_MouseMessage (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2308 2309

	case WM_NCCREATE:
2310
	    return TOOLTIPS_NCCreate (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
2311

2312
	case WM_NCHITTEST:
2313
	    return TOOLTIPS_NCHitTest (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2314

2315
	case WM_NOTIFYFORMAT:
2316
	    return TOOLTIPS_NotifyFormat (infoPtr, wParam, lParam);
2317

2318
	case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
2319
	case WM_PAINT:
2320
	    return TOOLTIPS_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2321 2322

	case WM_SETFONT:
2323
	    return TOOLTIPS_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2324

2325 2326 2327 2328
	case WM_SYSCOLORCHANGE:
	    COMCTL32_RefreshSysColors();
	    return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
2329
	case WM_TIMER:
2330
	    return TOOLTIPS_Timer (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2331

Alexandre Julliard's avatar
Alexandre Julliard committed
2332
	case WM_WININICHANGE:
2333
	    return TOOLTIPS_WinIniChange (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2334 2335

	default:
2336
	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2337
		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2338
		     uMsg, wParam, lParam);
2339
	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2340 2341 2342 2343
    }
}


2344
VOID
2345
TOOLTIPS_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2346
{
2347
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2348

2349
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2350
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2351
    wndClass.lpfnWndProc   = TOOLTIPS_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2352 2353
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2354
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2355
    wndClass.hbrBackground = 0;
2356
    wndClass.lpszClassName = TOOLTIPS_CLASSW;
2357

2358
    RegisterClassW (&wndClass);
Robert Shearman's avatar
Robert Shearman committed
2359 2360 2361 2362 2363 2364 2365 2366

    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
2367
}
2368 2369 2370


VOID
2371
TOOLTIPS_Unregister (void)
2372
{
Robert Shearman's avatar
Robert Shearman committed
2373
    int i;
2374 2375
    for (i = TTI_INFO; i <= TTI_ERROR; i++)
        DestroyIcon(hTooltipIcons[i]);
2376
    UnregisterClassW (TOOLTIPS_CLASSW, NULL);
2377
}