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

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


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

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

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

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

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

214 215
/* Custom draw routines */
static void
216
TOOLTIPS_customdraw_fill(const TOOLTIPS_INFO *infoPtr, NMTTCUSTOMDRAW *lpnmttcd,
217 218 219 220
                         HDC hdc, const RECT *rcBounds, UINT uFlags)
{
    ZeroMemory(lpnmttcd, sizeof(NMTTCUSTOMDRAW));
    lpnmttcd->uDrawFlags = uFlags;
221
    lpnmttcd->nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
222 223 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
    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
249
static void
250
TOOLTIPS_Refresh (const TOOLTIPS_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
251
{
252 253 254 255 256
    RECT rc;
    INT oldBkMode;
    HFONT hOldFont;
    HBRUSH hBrush;
    UINT uFlags = DT_EXTERNALLEADING;
257
    HRGN hRgn = NULL;
258
    DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
259 260
    NMTTCUSTOMDRAW nmttcd;
    DWORD cdmode;
Alexandre Julliard's avatar
Alexandre Julliard committed
261

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

268
    hBrush = CreateSolidBrush(infoPtr->clrBk);
269

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

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

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

285
        GetWindowRgn(infoPtr->hwndSelf, hRgn);
286 287 288 289 290

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

478
}
Alexandre Julliard's avatar
Alexandre Julliard committed
479

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

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

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


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

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

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

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


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

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

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

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

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

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

612 613 614 615
    if (!track_activate)
        infoPtr->nCurrentTool = infoPtr->nTool;

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

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

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

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

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

633 634 635 636 637
        if (toolPtr->uFlags & TTF_CENTERTIP)
        {
            rect.left -= (size.cx / 2);
            if (!(style & TTS_BALLOON))
                rect.top  -= (size.cy / 2);
638
        }
639 640 641
        infoPtr->bToolBelow = TRUE;

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

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

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

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

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

732
    /* check position */
733 734 735 736 737 738 739 740

    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;
741
    }
742 743 744
    if (rect.left < mon_info.rcWork.left) rect.left = mon_info.rcWork.left;

    if( rect.bottom > mon_info.rcWork.bottom ) {
745 746 747 748 749 750
        RECT rc;

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

757 758
    AdjustWindowRectEx (&rect, GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE),
			FALSE, GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE));
Alexandre Julliard's avatar
Alexandre Julliard committed
759

760
    if (style & TTS_BALLOON)
761 762
    {
        HRGN hRgn;
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
        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);
804

805 806
        CombineRgn(hRgn, hRgn, hrStem, RGN_OR);
        DeleteObject(hrStem);
807

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

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

817
    /* repaint the tooltip */
818 819
    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
    UpdateWindow(infoPtr->hwndSelf);
820

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


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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
839 840 841
    if (infoPtr->nCurrentTool == -1)
	return;

Alexandre Julliard's avatar
Alexandre Julliard committed
842
    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
843
    KillTimer (infoPtr->hwndSelf, ID_TIMERPOP);
Alexandre Julliard's avatar
Alexandre Julliard committed
844

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

Alexandre Julliard's avatar
Alexandre Julliard committed
850
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
851

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


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


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

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

872 873 874 875 876
    if (infoPtr->nTrackTool == -1)
	return;

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

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

882
    SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
883
		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
884 885
}

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

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

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


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

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

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

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
942 943
    return -1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
944

Alexandre Julliard's avatar
Alexandre Julliard committed
945

946 947
static BOOL
TOOLTIPS_IsWindowActive (HWND hwnd)
948
{
949
    HWND hwndActive = GetActiveWindow ();
950 951 952 953
    if (!hwndActive)
	return FALSE;
    if (hwndActive == hwnd)
	return TRUE;
954
    return IsChild (hwndActive, hwnd);
955 956 957
}


958
static INT
959
TOOLTIPS_CheckTool (const TOOLTIPS_INFO *infoPtr, BOOL bShowTest)
Alexandre Julliard's avatar
Alexandre Julliard committed
960
{
961 962 963
    POINT pt;
    HWND hwndTool;
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
964

965
    GetCursorPos (&pt);
966
    hwndTool = (HWND)SendMessageW (infoPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
967
    if (hwndTool == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
968
	return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
969

970
    ScreenToClient (hwndTool, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
971
    nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
972 973 974
    if (nTool == -1)
	return -1;

975 976
    if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) {
	if (!TOOLTIPS_IsWindowActive (GetWindow (infoPtr->hwndSelf, GW_OWNER)))
Alexandre Julliard's avatar
Alexandre Julliard committed
977 978 979
	    return -1;
    }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
982
    return nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
983 984 985
}


Alexandre Julliard's avatar
Alexandre Julliard committed
986
static LRESULT
987
TOOLTIPS_Activate (TOOLTIPS_INFO *infoPtr, BOOL activate)
Alexandre Julliard's avatar
Alexandre Julliard committed
988
{
989
    infoPtr->bActive = activate;
Alexandre Julliard's avatar
Alexandre Julliard committed
990

Alexandre Julliard's avatar
Alexandre Julliard committed
991
    if (infoPtr->bActive)
992
	TRACE("activate!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
993

994
    if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
995
	TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
996 997 998 999 1000 1001

    return 0;
}


static LRESULT
1002
TOOLTIPS_AddToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1003 1004
{
    TTTOOL_INFO *toolPtr;
1005
    INT nResult;
Alexandre Julliard's avatar
Alexandre Julliard committed
1006

1007
    if (!ti) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1008

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1013
    if (infoPtr->uNumTools == 0) {
1014
	infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1015 1016 1017 1018 1019
	toolPtr = infoPtr->tools;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1020
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1021 1022
	memcpy (infoPtr->tools, oldTools,
		infoPtr->uNumTools * sizeof(TTTOOL_INFO));
1023
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1024 1025 1026 1027 1028 1029
	toolPtr = &infoPtr->tools[infoPtr->uNumTools];
    }

    infoPtr->uNumTools++;

    /* copy tool data */
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
    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)) {
1042
	    TRACE("add CALLBACK!\n");
1043
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
Alexandre Julliard's avatar
Alexandre Julliard committed
1044
	}
1045 1046 1047 1048 1049 1050
	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
1051
	else {
1052 1053
	    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, NULL, 0);
	    TRACE("add text \"%s\"!\n", (LPSTR)ti->lpszText);
1054
	    toolPtr->lpszText =	Alloc (len * sizeof(WCHAR));
1055
	    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, toolPtr->lpszText, len);
Alexandre Julliard's avatar
Alexandre Julliard committed
1056 1057 1058
	}
    }

1059 1060
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	toolPtr->lParam = ti->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1061

Alexandre Julliard's avatar
Alexandre Julliard committed
1062
    /* install subclassing hook */
Alexandre Julliard's avatar
Alexandre Julliard committed
1063 1064
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1065
	    SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
1066
			      (DWORD_PTR)infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1067 1068
	}
	else {
1069
	    SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
1070
			      (DWORD_PTR)infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1071
	}
1072
	TRACE("subclassing installed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1073 1074
    }

1075 1076
    nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
                            (WPARAM)infoPtr->hwndSelf, NF_QUERY);
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
    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
1087 1088 1089 1090
    return TRUE;
}


1091
static LRESULT
1092
TOOLTIPS_DelToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1093 1094
{
    TTTOOL_INFO *toolPtr;
1095
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096

1097 1098 1099 1100 1101 1102
    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
1103

1104
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1105

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

1108
    if (nTool == -1)
1109
        return 0;
1110

1111
    /* make sure the tooltip has disappeared before deleting it */
1112
    TOOLTIPS_Hide(infoPtr);
1113

Alexandre Julliard's avatar
Alexandre Julliard committed
1114
    /* delete text string */
1115
    toolPtr = &infoPtr->tools[nTool];
1116
    if (toolPtr->lpszText) {
1117
	if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
1118
	     !IS_INTRESOURCE(toolPtr->lpszText) )
1119
	    Free (toolPtr->lpszText);
Alexandre Julliard's avatar
Alexandre Julliard committed
1120 1121
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1122 1123 1124
    /* remove subclassing */
    if (toolPtr->uFlags & TTF_SUBCLASS) {
	if (toolPtr->uFlags & TTF_IDISHWND) {
1125
	    RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1126 1127
	}
	else {
1128
	    RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1129 1130 1131
	}
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133
    /* delete tool from tool list */
    if (infoPtr->uNumTools == 1) {
1134
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1135 1136 1137 1138 1139
	infoPtr->tools = NULL;
    }
    else {
	TTTOOL_INFO *oldTools = infoPtr->tools;
	infoPtr->tools =
1140
	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
Alexandre Julliard's avatar
Alexandre Julliard committed
1141

Alexandre Julliard's avatar
Alexandre Julliard committed
1142
	if (nTool > 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1143
	    memcpy (&infoPtr->tools[0], &oldTools[0],
Alexandre Julliard's avatar
Alexandre Julliard committed
1144
		    nTool * sizeof(TTTOOL_INFO));
Alexandre Julliard's avatar
Alexandre Julliard committed
1145

Alexandre Julliard's avatar
Alexandre Julliard committed
1146 1147 1148
	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
1149

1150
	Free (oldTools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1151 1152
    }

1153 1154
    /* update any indices affected by delete */

1155 1156
    /* destroying tool that mouse was on on last relayed mouse move */
    if (infoPtr->nTool == nTool)
1157
        /* -1 means no current tool (0 means first tool) */
1158
        infoPtr->nTool = -1;
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
    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--;
1173

Alexandre Julliard's avatar
Alexandre Julliard committed
1174
    infoPtr->uNumTools--;
1175

1176 1177
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1178 1179

static LRESULT
1180 1181
TOOLTIPS_EnumToolsT (const TOOLTIPS_INFO *infoPtr, UINT uIndex, TTTOOLINFOW *ti,
                     BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1182 1183 1184
{
    TTTOOL_INFO *toolPtr;

1185 1186
    if (!ti) return FALSE;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1187 1188 1189
	return FALSE;
    if (uIndex >= infoPtr->uNumTools)
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1190

1191
    TRACE("index=%u\n", uIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
1192 1193 1194 1195

    toolPtr = &infoPtr->tools[uIndex];

    /* copy tool data */
1196 1197 1198 1199 1200 1201 1202
    ti->uFlags   = toolPtr->uFlags;
    ti->hwnd     = toolPtr->hwnd;
    ti->uId      = toolPtr->uId;
    ti->rect     = toolPtr->rect;
    ti->hinst    = toolPtr->hinst;
/*    ti->lpszText = toolPtr->lpszText; */
    ti->lpszText = NULL;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1203

1204 1205
    if (ti->cbSize >= TTTOOLINFOA_V2_SIZE)
	ti->lParam = toolPtr->lParam;
1206 1207 1208

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

1210
static LRESULT
1211
TOOLTIPS_GetBubbleSize (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
1212 1213 1214 1215 1216 1217
{
    INT nTool;
    SIZE size;

    if (lpToolInfo == NULL)
	return FALSE;
1218
    if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1219 1220
	return FALSE;

1221
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, lpToolInfo);
1222 1223 1224 1225
    if (nTool == -1) return 0;

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

1226
    TOOLTIPS_CalcTipSize (infoPtr, &size);
1227
    TRACE("size %d x %d\n", size.cx, size.cy);
1228 1229 1230

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

static LRESULT
1233
TOOLTIPS_GetCurrentToolT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1234 1235 1236
{
    TTTOOL_INFO *toolPtr;

1237 1238
    if (ti) {
        if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1239 1240
            return FALSE;

1241 1242 1243 1244
	if (infoPtr->nCurrentTool > -1) {
	    toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];

	    /* copy tool data */
1245 1246 1247 1248 1249
	    ti->uFlags   = toolPtr->uFlags;
	    ti->rect     = toolPtr->rect;
	    ti->hinst    = toolPtr->hinst;
/*	    ti->lpszText = toolPtr->lpszText; */
	    ti->lpszText = NULL;  /* FIXME */
1250

1251 1252
	    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
		ti->lParam = toolPtr->lParam;
1253 1254 1255 1256 1257 1258 1259 1260 1261

	    return TRUE;
	}
	else
	    return FALSE;
    }
    else
	return (infoPtr->nCurrentTool != -1);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1262 1263 1264


static LRESULT
1265
TOOLTIPS_GetDelayTime (const TOOLTIPS_INFO *infoPtr, DWORD duration)
Alexandre Julliard's avatar
Alexandre Julliard committed
1266
{
1267
    switch (duration) {
1268 1269
    case TTDT_RESHOW:
        return infoPtr->nReshowTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1270

1271 1272
    case TTDT_AUTOPOP:
        return infoPtr->nAutoPopTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1273

1274 1275 1276
    case TTDT_INITIAL:
    case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
        return infoPtr->nInitialTime;
Alexandre Julliard's avatar
Alexandre Julliard committed
1277

1278
    default:
1279
        WARN("Invalid duration flag %x\n", duration);
1280
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1281 1282
    }

1283
    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1284 1285 1286 1287
}


static LRESULT
1288
TOOLTIPS_GetMargin (const TOOLTIPS_INFO *infoPtr, LPRECT lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1289 1290 1291 1292 1293 1294 1295 1296
{
    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
1297 1298


1299
static inline LRESULT
1300
TOOLTIPS_GetMaxTipWidth (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1301
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1302
    return infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1303 1304 1305 1306
}


static LRESULT
1307
TOOLTIPS_GetTextT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1308
{
1309
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1310

1311 1312
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1313
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1314

1315
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1316
    if (nTool == -1) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1317

1318
    if (infoPtr->tools[nTool].lpszText == NULL)
1319 1320
	return 0;

1321 1322 1323 1324 1325 1326
    if (isW) {
        ti->lpszText[0] = '\0';
        TOOLTIPS_GetTipText(infoPtr, nTool, ti->lpszText);
    }
    else {
        WCHAR buffer[INFOTIPSIZE];
1327

1328 1329 1330
        /* 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
           one it supplies is.  We'll assume it's up to INFOTIPSIZE */
1331

1332 1333 1334 1335 1336
        buffer[0] = '\0';
        TOOLTIPS_GetTipText(infoPtr, nTool, buffer);
        WideCharToMultiByte(CP_ACP, 0, buffer, -1, (LPSTR)ti->lpszText,
                                                   INFOTIPSIZE, NULL, NULL);
    }
1337 1338 1339

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1340 1341


1342
static inline LRESULT
1343
TOOLTIPS_GetTipBkColor (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1344 1345 1346 1347 1348
{
    return infoPtr->clrBk;
}


1349
static inline LRESULT
1350
TOOLTIPS_GetTipTextColor (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1351 1352 1353 1354 1355
{
    return infoPtr->clrText;
}


1356
static inline LRESULT
1357
TOOLTIPS_GetToolCount (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1358 1359 1360 1361 1362 1363
{
    return infoPtr->uNumTools;
}


static LRESULT
1364
TOOLTIPS_GetToolInfoT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1365 1366
{
    TTTOOL_INFO *toolPtr;
1367
    INT nTool;
1368

1369 1370
    if (!ti) return FALSE;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1371 1372 1373 1374
	return FALSE;
    if (infoPtr->uNumTools == 0)
	return FALSE;

1375
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1376 1377 1378
    if (nTool == -1)
	return FALSE;

1379
    TRACE("tool %d\n", nTool);
1380 1381 1382 1383

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
1384 1385 1386
    ti->uFlags   = toolPtr->uFlags;
    ti->rect     = toolPtr->rect;
    ti->hinst    = toolPtr->hinst;
1387
/*    lpToolInfo->lpszText = toolPtr->lpszText; */
1388
    ti->lpszText = NULL;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1389

1390 1391
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	ti->lParam = toolPtr->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393 1394 1395 1396

    return TRUE;
}


1397
static LRESULT
1398 1399
TOOLTIPS_HitTestT (const TOOLTIPS_INFO *infoPtr, LPTTHITTESTINFOW lptthit,
                   BOOL isW)
1400 1401
{
    TTTOOL_INFO *toolPtr;
1402
    INT nTool;
1403 1404 1405 1406 1407 1408 1409 1410

    if (lptthit == 0)
	return FALSE;

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

1411
    TRACE("tool %d!\n", nTool);
1412 1413

    /* copy tool data */
1414
    if (lptthit->ti.cbSize >= TTTOOLINFOW_V1_SIZE) {
1415 1416 1417 1418 1419 1420 1421
	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;
1422
/*	lptthit->ti.lpszText = toolPtr->lpszText; */
1423
	lptthit->ti.lpszText = NULL;  /* FIXME */
1424 1425
	if (lptthit->ti.cbSize >= TTTOOLINFOW_V2_SIZE)
	    lptthit->ti.lParam   = toolPtr->lParam;
1426 1427 1428 1429
    }

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1430 1431 1432


static LRESULT
1433
TOOLTIPS_NewToolRectT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1434
{
1435
    INT nTool;
1436

1437 1438
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1439 1440
	return FALSE;

1441
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1442

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

1445 1446
    if (nTool == -1) return 0;

1447
    infoPtr->tools[nTool].rect = ti->rect;
1448 1449 1450

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1451 1452


1453
static inline LRESULT
1454
TOOLTIPS_Pop (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1455
{
1456
    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1457 1458 1459

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1460 1461 1462


static LRESULT
1463
TOOLTIPS_RelayEvent (TOOLTIPS_INFO *infoPtr, LPMSG lpMsg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1464
{
1465
    POINT pt;
1466
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1467

1468
    if (!lpMsg) {
1469
	ERR("lpMsg == NULL!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1470 1471
	return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1472

Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474 1475 1476 1477 1478 1479
    switch (lpMsg->message) {
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
1480
	    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1481 1482 1483
	    break;

	case WM_MOUSEMOVE:
1484 1485
	    pt.x = (short)LOWORD(lpMsg->lParam);
	    pt.y = (short)HIWORD(lpMsg->lParam);
1486 1487 1488
	    nOldTool = infoPtr->nTool;
	    infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
						       &pt);
1489
	    TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool,
1490
		  infoPtr->nTool, infoPtr->nCurrentTool);
1491
            TRACE("WM_MOUSEMOVE (%p %d %d)\n", infoPtr->hwndSelf, pt.x, pt.y);
1492 1493 1494

	    if (infoPtr->nTool != nOldTool) {
	        if(infoPtr->nTool == -1) { /* Moved out of all tools */
1495 1496
		    TOOLTIPS_Hide(infoPtr);
		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1497 1498
		} else if (nOldTool == -1) { /* Moved from outside */
		    if(infoPtr->bActive) {
1499
		        SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1500 1501 1502
			TRACE("timer 1 started!\n");
		    }
		} else { /* Moved from one to another */
1503 1504
		    TOOLTIPS_Hide (infoPtr);
		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1505
		    if(infoPtr->bActive) {
1506
		        SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1507 1508
			TRACE("timer 1 started!\n");
		    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1509
		}
1510
	    } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1511 1512
	        KillTimer(infoPtr->hwndSelf, ID_TIMERPOP);
		SetTimer(infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1513
		TRACE("timer 2 restarted\n");
1514 1515
	    } else if(infoPtr->nTool != -1 && infoPtr->bActive) {
                /* previous show attempt didn't result in tooltip so try again */
1516
		SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1517
		TRACE("timer 1 started!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1518 1519
	    }
	    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1520 1521
    }

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


static LRESULT
1527
TOOLTIPS_SetDelayTime (TOOLTIPS_INFO *infoPtr, DWORD duration, INT nTime)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
{
1529
    switch (duration) {
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
    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
1554 1555
	    break;

1556
    default:
1557
        WARN("Invalid duration flag %x\n", duration);
1558
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1559
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561 1562 1563 1564

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1565
static LRESULT
1566
TOOLTIPS_SetMargin (TOOLTIPS_INFO *infoPtr, const RECT *lpRect)
Alexandre Julliard's avatar
Alexandre Julliard committed
1567 1568 1569 1570 1571 1572 1573 1574
{
    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
1575 1576


1577
static inline LRESULT
1578
TOOLTIPS_SetMaxTipWidth (TOOLTIPS_INFO *infoPtr, INT MaxWidth)
Alexandre Julliard's avatar
Alexandre Julliard committed
1579
{
1580
    INT nTemp = infoPtr->nMaxTipWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1581

1582
    infoPtr->nMaxTipWidth = MaxWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
1583

Alexandre Julliard's avatar
Alexandre Julliard committed
1584
    return nTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1585 1586 1587
}


1588
static inline LRESULT
1589
TOOLTIPS_SetTipBkColor (TOOLTIPS_INFO *infoPtr, COLORREF clrBk)
Alexandre Julliard's avatar
Alexandre Julliard committed
1590
{
1591
    infoPtr->clrBk = clrBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
1592 1593 1594 1595 1596

    return 0;
}


1597
static inline LRESULT
1598
TOOLTIPS_SetTipTextColor (TOOLTIPS_INFO *infoPtr, COLORREF clrText)
Alexandre Julliard's avatar
Alexandre Julliard committed
1599
{
1600
    infoPtr->clrText = clrText;
Alexandre Julliard's avatar
Alexandre Julliard committed
1601 1602 1603 1604 1605

    return 0;
}


Robert Shearman's avatar
Robert Shearman committed
1606
static LRESULT
1607 1608
TOOLTIPS_SetTitleT (TOOLTIPS_INFO *infoPtr, UINT_PTR uTitleIcon, LPCWSTR pszTitle,
                    BOOL isW)
Robert Shearman's avatar
Robert Shearman committed
1609 1610 1611
{
    UINT size;

1612
    TRACE("hwnd = %p, title = %s, icon = %p\n", infoPtr->hwndSelf, debugstr_w(pszTitle),
1613 1614 1615 1616 1617 1618
        (void*)uTitleIcon);

    Free(infoPtr->pszTitle);

    if (pszTitle)
    {
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
        if (isW)
        {
            size = (strlenW(pszTitle)+1)*sizeof(WCHAR);
            infoPtr->pszTitle = Alloc(size);
            if (!infoPtr->pszTitle)
                return FALSE;
            memcpy(infoPtr->pszTitle, pszTitle, size);
        }
        else
        {
            size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, (LPSTR)pszTitle, -1, NULL, 0);
            infoPtr->pszTitle = Alloc(size);
            if (!infoPtr->pszTitle)
                return FALSE;
            MultiByteToWideChar(CP_ACP, 0, (LPSTR)pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR));
        }
1635 1636 1637
    }
    else
        infoPtr->pszTitle = NULL;
Robert Shearman's avatar
Robert Shearman committed
1638 1639 1640 1641

    if (uTitleIcon <= TTI_ERROR)
        infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
    else
1642
        infoPtr->hTitleIcon = CopyIcon((HICON)uTitleIcon);
Robert Shearman's avatar
Robert Shearman committed
1643 1644 1645 1646 1647 1648 1649

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

    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1650
static LRESULT
1651
TOOLTIPS_SetToolInfoT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1652 1653
{
    TTTOOL_INFO *toolPtr;
1654
    INT nTool;
1655

1656 1657
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1658 1659
	return 0;

1660
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1661 1662
    if (nTool == -1) return 0;

1663
    TRACE("tool %d\n", nTool);
1664 1665 1666 1667

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool data */
1668 1669 1670 1671 1672
    toolPtr->uFlags = ti->uFlags;
    toolPtr->hwnd   = ti->hwnd;
    toolPtr->uId    = ti->uId;
    toolPtr->rect   = ti->rect;
    toolPtr->hinst  = ti->hinst;
1673

1674 1675 1676
    if (IS_INTRESOURCE(ti->lpszText)) {
	TRACE("set string id %x!\n", LOWORD(ti->lpszText));
	toolPtr->lpszText = ti->lpszText;
1677
    }
1678
    else {
1679
	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1680
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1681
	else {
1682
	    if ( (toolPtr->lpszText) &&
Frank Richter's avatar
Frank Richter committed
1683
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1684 1685
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
1686 1687
		toolPtr->lpszText = NULL;
	    }
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
	    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);
		}
1701 1702 1703 1704
	    }
	}
    }

1705 1706
    if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
	toolPtr->lParam = ti->lParam;
1707

1708 1709
    if (infoPtr->nCurrentTool == nTool)
    {
1710
        TOOLTIPS_GetTipText (infoPtr, infoPtr->nCurrentTool, infoPtr->szTipText);
1711 1712

        if (infoPtr->szTipText[0] == 0)
1713
            TOOLTIPS_Hide(infoPtr);
1714
        else
1715
            TOOLTIPS_Show (infoPtr, FALSE);
1716 1717
    }

1718 1719
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1720 1721 1722


static LRESULT
1723
TOOLTIPS_TrackActivate (TOOLTIPS_INFO *infoPtr, BOOL track_activate, const TTTOOLINFOA *ti)
Alexandre Julliard's avatar
Alexandre Julliard committed
1724
{
1725
    if (track_activate) {
1726

1727 1728
	if (!ti) return 0;
	if (ti->cbSize < TTTOOLINFOA_V1_SIZE)
1729 1730
	    return FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1731
	/* activate */
1732
	infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoT (infoPtr, (TTTOOLINFOW*)ti);
Alexandre Julliard's avatar
Alexandre Julliard committed
1733
	if (infoPtr->nTrackTool != -1) {
1734
	    TRACE("activated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1735
	    infoPtr->bTrackActive = TRUE;
1736
	    TOOLTIPS_TrackShow (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1737 1738 1739 1740
	}
    }
    else {
	/* deactivate */
1741
	TOOLTIPS_TrackHide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1742 1743 1744

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

1746
	TRACE("deactivated!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1747 1748 1749 1750 1751 1752 1753
    }

    return 0;
}


static LRESULT
1754
TOOLTIPS_TrackPosition (TOOLTIPS_INFO *infoPtr, LPARAM coord)
Alexandre Julliard's avatar
Alexandre Julliard committed
1755
{
1756 1757
    infoPtr->xTrackPos = (INT)LOWORD(coord);
    infoPtr->yTrackPos = (INT)HIWORD(coord);
Alexandre Julliard's avatar
Alexandre Julliard committed
1758 1759

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

1763
	TOOLTIPS_TrackShow (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1764 1765 1766 1767 1768 1769 1770
    }

    return 0;
}


static LRESULT
1771
TOOLTIPS_Update (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1772 1773
{
    if (infoPtr->nCurrentTool != -1)
1774
	UpdateWindow (infoPtr->hwndSelf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1775 1776 1777 1778 1779 1780

    return 0;
}


static LRESULT
1781
TOOLTIPS_UpdateTipTextT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
Alexandre Julliard's avatar
Alexandre Julliard committed
1782 1783
{
    TTTOOL_INFO *toolPtr;
1784
    INT nTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
1785

1786 1787
    if (!ti) return 0;
    if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1788
	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1789

1790
    nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1791 1792 1793
    if (nTool == -1)
	return 0;

1794
    TRACE("tool %d\n", nTool);
1795 1796 1797 1798

    toolPtr = &infoPtr->tools[nTool];

    /* copy tool text */
1799
    toolPtr->hinst  = ti->hinst;
1800

1801 1802
    if (IS_INTRESOURCE(ti->lpszText)){
	toolPtr->lpszText = ti->lpszText;
1803
    }
1804 1805
    else if (ti->lpszText) {
	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1806
	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1807
	else {
1808
	    if ( (toolPtr->lpszText)  &&
Frank Richter's avatar
Frank Richter committed
1809
		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1810 1811
		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
                    Free (toolPtr->lpszText);
1812 1813
		toolPtr->lpszText = NULL;
	    }
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
	    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);
	        }
1827 1828 1829 1830
	    }
	}
    }

1831
    if(infoPtr->nCurrentTool == -1) return 0;
1832 1833
    /* force repaint */
    if (infoPtr->bActive)
1834
	TOOLTIPS_Show (infoPtr, FALSE);
1835
    else if (infoPtr->bTrackActive)
1836
	TOOLTIPS_Show (infoPtr, TRUE);
1837

1838 1839
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1840 1841 1842


static LRESULT
1843
TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1844
{
1845
    return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1846 1847
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1848 1849 1850


static LRESULT
1851
TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1852 1853 1854 1855
{
    TOOLTIPS_INFO *infoPtr;

    /* allocate memory for info structure */
1856
    infoPtr = Alloc (sizeof(TOOLTIPS_INFO));
1857
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1858 1859 1860

    /* initialize info structure */
    infoPtr->bActive = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1861
    infoPtr->bTrackActive = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1862 1863 1864 1865

    infoPtr->nMaxTipWidth = -1;
    infoPtr->nTool = -1;
    infoPtr->nCurrentTool = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1866
    infoPtr->nTrackTool = -1;
1867
    infoPtr->hwndSelf = hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1868

Robert Shearman's avatar
Robert Shearman committed
1869 1870 1871
    /* initialize colours and fonts */
    TOOLTIPS_InitSystemSettings(infoPtr);

1872
    TOOLTIPS_SetDelayTime(infoPtr, TTDT_AUTOMATIC, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1873

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1876 1877 1878 1879 1880
    return 0;
}


static LRESULT
1881
TOOLTIPS_Destroy (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1882
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1883
    TTTOOL_INFO *toolPtr;
1884
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
1885 1886 1887 1888

    /* free tools */
    if (infoPtr->tools) {
	for (i = 0; i < infoPtr->uNumTools; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1889
	    toolPtr = &infoPtr->tools[i];
1890
	    if (toolPtr->lpszText) {
1891
		if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
Frank Richter's avatar
Frank Richter committed
1892
		     !IS_INTRESOURCE(toolPtr->lpszText) )
1893
		{
1894
		    Free (toolPtr->lpszText);
1895 1896
		    toolPtr->lpszText = NULL;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
1897 1898 1899
	    }

	    /* remove subclassing */
1900 1901
        if (toolPtr->uFlags & TTF_SUBCLASS) {
            if (toolPtr->uFlags & TTF_IDISHWND) {
1902
                RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1);
1903 1904
            }
            else {
1905
                RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1);
1906 1907 1908
            }
        }
    }
1909
	Free (infoPtr->tools);
Alexandre Julliard's avatar
Alexandre Julliard committed
1910 1911
    }

Robert Shearman's avatar
Robert Shearman committed
1912 1913 1914 1915 1916 1917 1918
    /* 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 */
1919
    DeleteObject (infoPtr->hFont);
Robert Shearman's avatar
Robert Shearman committed
1920
    DeleteObject (infoPtr->hTitleFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
1921

Alexandre Julliard's avatar
Alexandre Julliard committed
1922
    /* free tool tips info data */
1923
    SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
1924
    Free (infoPtr);
1925

Alexandre Julliard's avatar
Alexandre Julliard committed
1926 1927 1928 1929
    return 0;
}


1930 1931
static inline LRESULT
TOOLTIPS_GetFont (const TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1932
{
1933
    return (LRESULT)infoPtr->hFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
1934 1935 1936
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1937
static LRESULT
1938
TOOLTIPS_MouseMessage (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1939
{
1940
    TOOLTIPS_Hide (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1941 1942 1943 1944 1945 1946

    return 0;
}


static LRESULT
1947
TOOLTIPS_NCCreate (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1948
{
1949 1950
    DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
    DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
1951

1952
    dwStyle &= ~(WS_CHILD | /*WS_MAXIMIZE |*/ WS_BORDER | WS_DLGFRAME);
1953
    dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
1954 1955 1956 1957 1958

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

1959
    SetWindowLongW (hwnd, GWL_STYLE, dwStyle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1960

1961
    dwExStyle |= WS_EX_TOOLWINDOW;
1962
    SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
1963

Alexandre Julliard's avatar
Alexandre Julliard committed
1964 1965 1966 1967
    return TRUE;
}


1968
static LRESULT
1969
TOOLTIPS_NCHitTest (const TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1970
{
1971
    INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
1972

1973
    TRACE(" nTool=%d\n", nTool);
1974 1975 1976

    if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
	if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
1977
	    TRACE("-- in transparent mode!\n");
1978 1979 1980 1981
	    return HTTRANSPARENT;
	}
    }

1982
    return DefWindowProcW (infoPtr->hwndSelf, WM_NCHITTEST, wParam, lParam);
1983 1984 1985
}


1986
static LRESULT
1987
TOOLTIPS_NotifyFormat (TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1988
{
1989
    FIXME ("hwnd=%p wParam=%lx lParam=%lx\n", infoPtr->hwndSelf, wParam, lParam);
1990 1991 1992 1993 1994

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1995
static LRESULT
1996
TOOLTIPS_Paint (const TOOLTIPS_INFO *infoPtr, HDC hDC)
Alexandre Julliard's avatar
Alexandre Julliard committed
1997
{
1998 1999
    HDC hdc;
    PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
2000

2001
    hdc = (hDC == NULL) ? BeginPaint (infoPtr->hwndSelf, &ps) : hDC;
2002
    TOOLTIPS_Refresh (infoPtr, hdc);
2003
    if (!hDC)
2004
	EndPaint (infoPtr->hwndSelf, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
2005 2006
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2007 2008 2009


static LRESULT
2010
TOOLTIPS_SetFont (TOOLTIPS_INFO *infoPtr, HFONT hFont, BOOL redraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
2011
{
2012
    LOGFONTW lf;
Alexandre Julliard's avatar
Alexandre Julliard committed
2013

2014
    if(!GetObjectW(hFont, sizeof(lf), &lf))
2015
        return 0;
2016

Robert Shearman's avatar
Robert Shearman committed
2017
    DeleteObject (infoPtr->hFont);
2018
    infoPtr->hFont = CreateFontIndirectW(&lf);
Alexandre Julliard's avatar
Alexandre Julliard committed
2019

Robert Shearman's avatar
Robert Shearman committed
2020 2021 2022 2023
    DeleteObject (infoPtr->hTitleFont);
    lf.lfWeight = FW_BOLD;
    infoPtr->hTitleFont = CreateFontIndirectW(&lf);

2024
    if (redraw & (infoPtr->nCurrentTool != -1)) {
2025
	FIXME("full redraw needed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2026 2027 2028 2029
    }

    return 0;
}
2030

2031
/******************************************************************
2032
 * TOOLTIPS_GetTextLength
2033 2034 2035 2036 2037
 *
 * This function is called when the tooltip receive a
 * WM_GETTEXTLENGTH message.
 *
 * returns the length, in characters, of the tip text
2038
 */
2039 2040
static inline LRESULT
TOOLTIPS_GetTextLength(const TOOLTIPS_INFO *infoPtr)
2041
{
2042
    return strlenW(infoPtr->szTipText);
2043
}
2044

2045 2046 2047 2048 2049 2050 2051 2052 2053 2054
/******************************************************************
 * 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
2055
 */
2056
static LRESULT
2057
TOOLTIPS_OnWMGetText (const TOOLTIPS_INFO *infoPtr, WPARAM size, LPWSTR pszText)
2058
{
2059
    LRESULT res;
2060

2061
    if(!infoPtr->szTipText || !size)
2062 2063
        return 0;

2064
    res = min(strlenW(infoPtr->szTipText)+1, size);
2065 2066 2067
    memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR));
    pszText[res-1] = '\0';
    return res-1;
2068
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2069

Alexandre Julliard's avatar
Alexandre Julliard committed
2070
static LRESULT
2071
TOOLTIPS_Timer (TOOLTIPS_INFO *infoPtr, INT iTimer)
Alexandre Julliard's avatar
Alexandre Julliard committed
2072
{
2073
    INT nOldTool;
Alexandre Julliard's avatar
Alexandre Julliard committed
2074

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

2077
    switch (iTimer) {
2078
    case ID_TIMERSHOW:
2079
        KillTimer (infoPtr->hwndSelf, ID_TIMERSHOW);
2080
	nOldTool = infoPtr->nTool;
2081 2082
	if ((infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, TRUE)) == nOldTool)
	    TOOLTIPS_Show (infoPtr, FALSE);
2083 2084 2085
	break;

    case ID_TIMERPOP:
2086
        TOOLTIPS_Hide (infoPtr);
2087 2088 2089 2090
	break;

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

    default:
2112
        ERR("Unknown timer id %d\n", iTimer);
2113
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2114 2115 2116 2117 2118
    }
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2119
static LRESULT
2120
TOOLTIPS_WinIniChange (TOOLTIPS_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2121
{
Robert Shearman's avatar
Robert Shearman committed
2122
    TOOLTIPS_InitSystemSettings (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2123 2124 2125

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2126 2127


Robert Shearman's avatar
Robert Shearman committed
2128
static LRESULT CALLBACK
2129
TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
Alexandre Julliard's avatar
Alexandre Julliard committed
2130
{
2131
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr ((HWND)dwRef);
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145
    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;
2146
	TOOLTIPS_RelayEvent(infoPtr, &msg);
2147 2148 2149 2150
	break;

    default:
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
2151
    }
2152
    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2153 2154 2155
}


2156
static LRESULT CALLBACK
2157
TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2158
{
2159 2160
    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);

2161
    TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2162
    if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2163
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2164 2165 2166
    switch (uMsg)
    {
	case TTM_ACTIVATE:
2167
	    return TOOLTIPS_Activate (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2168

2169 2170
	case TTM_ADDTOOLA:
	case TTM_ADDTOOLW:
2171
	    return TOOLTIPS_AddToolT (infoPtr, (LPTTTOOLINFOW)lParam, uMsg == TTM_ADDTOOLW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2172

2173 2174
	case TTM_DELTOOLA:
	case TTM_DELTOOLW:
2175 2176
	    return TOOLTIPS_DelToolT (infoPtr, (LPTOOLINFOW)lParam,
                                      uMsg == TTM_DELTOOLW);
2177 2178
	case TTM_ENUMTOOLSA:
	case TTM_ENUMTOOLSW:
2179 2180
	    return TOOLTIPS_EnumToolsT (infoPtr, (UINT)wParam, (LPTTTOOLINFOW)lParam,
                                        uMsg == TTM_ENUMTOOLSW);
2181
	case TTM_GETBUBBLESIZE:
2182
	    return TOOLTIPS_GetBubbleSize (infoPtr, (LPTTTOOLINFOW)lParam);
2183

2184 2185
	case TTM_GETCURRENTTOOLA:
	case TTM_GETCURRENTTOOLW:
2186 2187
	    return TOOLTIPS_GetCurrentToolT (infoPtr, (LPTTTOOLINFOW)lParam,
                                             uMsg == TTM_GETCURRENTTOOLW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2188 2189

	case TTM_GETDELAYTIME:
2190
	    return TOOLTIPS_GetDelayTime (infoPtr, (DWORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2191 2192

	case TTM_GETMARGIN:
2193
	    return TOOLTIPS_GetMargin (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2194 2195

	case TTM_GETMAXTIPWIDTH:
2196
	    return TOOLTIPS_GetMaxTipWidth (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2197

2198 2199
	case TTM_GETTEXTA:
	case TTM_GETTEXTW:
2200 2201
	    return TOOLTIPS_GetTextT (infoPtr, (LPTTTOOLINFOW)lParam,
                                      uMsg == TTM_GETTEXTW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2202 2203

	case TTM_GETTIPBKCOLOR:
2204
	    return TOOLTIPS_GetTipBkColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2205 2206

	case TTM_GETTIPTEXTCOLOR:
2207
	    return TOOLTIPS_GetTipTextColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2208 2209

	case TTM_GETTOOLCOUNT:
2210
	    return TOOLTIPS_GetToolCount (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2211

2212 2213
	case TTM_GETTOOLINFOA:
	case TTM_GETTOOLINFOW:
2214 2215
	    return TOOLTIPS_GetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
                                          uMsg == TTM_GETTOOLINFOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2216

2217 2218
	case TTM_HITTESTA:
	case TTM_HITTESTW:
2219 2220
	    return TOOLTIPS_HitTestT (infoPtr, (LPTTHITTESTINFOW)lParam,
                                      uMsg == TTM_HITTESTW);
2221 2222
	case TTM_NEWTOOLRECTA:
	case TTM_NEWTOOLRECTW:
2223 2224
	    return TOOLTIPS_NewToolRectT (infoPtr, (LPTTTOOLINFOW)lParam,
                                          uMsg == TTM_NEWTOOLRECTW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2225
	case TTM_POP:
2226
	    return TOOLTIPS_Pop (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2227 2228

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

Alexandre Julliard's avatar
Alexandre Julliard committed
2231
	case TTM_SETDELAYTIME:
2232
	    return TOOLTIPS_SetDelayTime (infoPtr, (DWORD)wParam, (INT)LOWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2233 2234

	case TTM_SETMARGIN:
2235
	    return TOOLTIPS_SetMargin (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2236 2237

	case TTM_SETMAXTIPWIDTH:
2238
	    return TOOLTIPS_SetMaxTipWidth (infoPtr, (INT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2239 2240

	case TTM_SETTIPBKCOLOR:
2241
	    return TOOLTIPS_SetTipBkColor (infoPtr, (COLORREF)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2242 2243

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

Robert Shearman's avatar
Robert Shearman committed
2246 2247
	case TTM_SETTITLEA:
	case TTM_SETTITLEW:
2248 2249
	    return TOOLTIPS_SetTitleT (infoPtr, (UINT_PTR)wParam, (LPCWSTR)lParam,
                                       uMsg == TTM_SETTITLEW);
Robert Shearman's avatar
Robert Shearman committed
2250

2251 2252
	case TTM_SETTOOLINFOA:
	case TTM_SETTOOLINFOW:
2253 2254
	    return TOOLTIPS_SetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
                                          uMsg == TTM_SETTOOLINFOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2255 2256

	case TTM_TRACKACTIVATE:
2257
	    return TOOLTIPS_TrackActivate (infoPtr, (BOOL)wParam, (LPTTTOOLINFOA)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2258 2259

	case TTM_TRACKPOSITION:
2260
	    return TOOLTIPS_TrackPosition (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2261 2262

	case TTM_UPDATE:
2263
	    return TOOLTIPS_Update (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2264

2265 2266
	case TTM_UPDATETIPTEXTA:
	case TTM_UPDATETIPTEXTW:
2267 2268
	    return TOOLTIPS_UpdateTipTextT (infoPtr, (LPTTTOOLINFOW)lParam,
                                            uMsg == TTM_UPDATETIPTEXTW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2269 2270

	case TTM_WINDOWFROMPOINT:
2271
	    return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2272 2273 2274


	case WM_CREATE:
2275
	    return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2276 2277

	case WM_DESTROY:
2278
	    return TOOLTIPS_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2279

Alexandre Julliard's avatar
Alexandre Julliard committed
2280
	case WM_ERASEBKGND:
2281 2282
	    /* we draw the background in WM_PAINT */
	    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2283

Alexandre Julliard's avatar
Alexandre Julliard committed
2284
	case WM_GETFONT:
2285
	    return TOOLTIPS_GetFont (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2286

Robert Shearman's avatar
Robert Shearman committed
2287
	case WM_GETTEXT:
2288
	    return TOOLTIPS_OnWMGetText (infoPtr, wParam, (LPWSTR)lParam);
2289

Robert Shearman's avatar
Robert Shearman committed
2290
	case WM_GETTEXTLENGTH:
2291
	    return TOOLTIPS_GetTextLength (infoPtr);
2292

2293 2294 2295 2296 2297 2298
	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
2299
	case WM_MOUSEMOVE:
2300
	    return TOOLTIPS_MouseMessage (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2301 2302

	case WM_NCCREATE:
2303
	    return TOOLTIPS_NCCreate (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2304

2305
	case WM_NCHITTEST:
2306
	    return TOOLTIPS_NCHitTest (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2307

2308
	case WM_NOTIFYFORMAT:
2309
	    return TOOLTIPS_NotifyFormat (infoPtr, wParam, lParam);
2310

2311
	case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
2312
	case WM_PAINT:
2313
	    return TOOLTIPS_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2314 2315

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

2318 2319 2320 2321
	case WM_SYSCOLORCHANGE:
	    COMCTL32_RefreshSysColors();
	    return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
2322
	case WM_TIMER:
2323
	    return TOOLTIPS_Timer (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2324

Alexandre Julliard's avatar
Alexandre Julliard committed
2325
	case WM_WININICHANGE:
2326
	    return TOOLTIPS_WinIniChange (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2327 2328

	default:
2329
	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2330
		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
2331
		     uMsg, wParam, lParam);
2332
	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2333 2334 2335 2336
    }
}


2337
VOID
2338
TOOLTIPS_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2339
{
2340
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2341

2342
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2343
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2344
    wndClass.lpfnWndProc   = TOOLTIPS_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2345 2346
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2347
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
Alexandre Julliard's avatar
Alexandre Julliard committed
2348
    wndClass.hbrBackground = 0;
2349
    wndClass.lpszClassName = TOOLTIPS_CLASSW;
2350

2351
    RegisterClassW (&wndClass);
Robert Shearman's avatar
Robert Shearman committed
2352 2353 2354 2355 2356 2357 2358 2359

    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
2360
}
2361 2362 2363


VOID
2364
TOOLTIPS_Unregister (void)
2365
{
Robert Shearman's avatar
Robert Shearman committed
2366
    int i;
2367 2368
    for (i = TTI_INFO; i <= TTI_ERROR; i++)
        DestroyIcon(hTooltipIcons[i]);
2369
    UnregisterClassW (TOOLTIPS_CLASSW, NULL);
2370
}