xref: /reactos/dll/win32/comctl32/tooltips.c (revision b3fb8555)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Tool tip control
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 1998, 1999 Eric Kohl
5c2c66affSColin Finck  * Copyright 2004 Robert Shearman
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
8c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
9c2c66affSColin Finck  * License as published by the Free Software Foundation; either
10c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
13c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c2c66affSColin Finck  * Lesser General Public License for more details.
16c2c66affSColin Finck  *
17c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
18c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
19c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20c2c66affSColin Finck  *
21c2c66affSColin Finck  * NOTES
22c2c66affSColin Finck  *
23c2c66affSColin Finck  * This code was audited for completeness against the documented features
24c2c66affSColin Finck  * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman.
25c2c66affSColin Finck  *
26c2c66affSColin Finck  * Unless otherwise noted, we believe this code to be complete, as per
27c2c66affSColin Finck  * the specification mentioned above.
28c2c66affSColin Finck  * If you discover missing features or bugs please note them below.
29c2c66affSColin Finck  *
30c2c66affSColin Finck  * TODO:
31c2c66affSColin Finck  *   - Custom draw support.
32c2c66affSColin Finck  *   - Animation.
33c2c66affSColin Finck  *   - Links.
34c2c66affSColin Finck  *   - Messages:
35c2c66affSColin Finck  *     o TTM_ADJUSTRECT
36c2c66affSColin Finck  *     o TTM_GETTITLEA
37c2c66affSColin Finck  *     o TTM_GETTTILEW
38c2c66affSColin Finck  *     o TTM_POPUP
39c2c66affSColin Finck  *   - Styles:
40c2c66affSColin Finck  *     o TTS_NOANIMATE
41c2c66affSColin Finck  *     o TTS_NOFADE
42c2c66affSColin Finck  *     o TTS_CLOSE
43c2c66affSColin Finck  *
44c2c66affSColin Finck  * Testing:
45c2c66affSColin Finck  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
46c2c66affSColin Finck  *     The second cdrom (chapter 3) contains executables activate.exe,
47c2c66affSColin Finck  *     curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe,
48c2c66affSColin Finck  *     hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe.
49c2c66affSColin Finck  *
50c2c66affSColin Finck  *   Timer logic.
51c2c66affSColin Finck  *
52c2c66affSColin Finck  * One important point to remember is that tools don't necessarily get
53c2c66affSColin Finck  * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when
54c2c66affSColin Finck  * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because
55c2c66affSColin Finck  * here WM_MOUSEMOVEs only get sent when the cursor is inside the
56c2c66affSColin Finck  * client area.  Therefore the only reliable way to know that the
57c2c66affSColin Finck  * cursor has left a tool is to keep a timer running and check the
58c2c66affSColin Finck  * position every time it expires.  This is the role of timer
59c2c66affSColin Finck  * ID_TIMERLEAVE.
60c2c66affSColin Finck  *
61c2c66affSColin Finck  *
62c2c66affSColin Finck  * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start
63c2c66affSColin Finck  * ID_TIMERSHOW, if this times out and we're still in the tool we show
64c2c66affSColin Finck  * the tip.  On showing a tip we start both ID_TIMERPOP and
65c2c66affSColin Finck  * ID_TIMERLEAVE.  On hiding a tooltip we kill ID_TIMERPOP.
66c2c66affSColin Finck  * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE.  If
67c2c66affSColin Finck  * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed.
68c2c66affSColin Finck  * ID_TIMERLEAVE remains running - this is important as we need to
69c2c66affSColin Finck  * determine when the cursor leaves the tool.
70c2c66affSColin Finck  *
71c2c66affSColin Finck  * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're
72c2c66affSColin Finck  * still in the tool do nothing (apart from restart ID_TIMERPOP if
73c2c66affSColin Finck  * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running).  If we've
74c2c66affSColin Finck  * left the tool and entered another one then hide the tip and start
75c2c66affSColin Finck  * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE.  If we're
76c2c66affSColin Finck  * outside all tools hide the tip and kill ID_TIMERLEAVE.  On Relayed
77c2c66affSColin Finck  * mouse button messages hide the tip but leave ID_TIMERLEAVE running,
78c2c66affSColin Finck  * this again will let us keep track of when the cursor leaves the
79c2c66affSColin Finck  * tool.
80c2c66affSColin Finck  *
81c2c66affSColin Finck  *
82c2c66affSColin Finck  * infoPtr->nTool is the tool the mouse was on on the last relayed MM
83c2c66affSColin Finck  * or timer expiry or -1 if the mouse was not on a tool.
84c2c66affSColin Finck  *
85c2c66affSColin Finck  * infoPtr->nCurrentTool is the tool for which the tip is currently
86c2c66affSColin Finck  * displaying text for or -1 if the tip is not shown.  Actually this
87c2c66affSColin Finck  * will only ever be infoPtr-nTool or -1, so it could be changed to a
88c2c66affSColin Finck  * BOOL.
89c2c66affSColin Finck  *
90c2c66affSColin Finck  */
91c2c66affSColin Finck 
92c2c66affSColin Finck 
93*b3fb8555SGiannis Adamopoulos 
94*b3fb8555SGiannis Adamopoulos #include <stdarg.h>
95*b3fb8555SGiannis Adamopoulos #include <string.h>
96*b3fb8555SGiannis Adamopoulos 
97*b3fb8555SGiannis Adamopoulos #include "windef.h"
98*b3fb8555SGiannis Adamopoulos #include "winbase.h"
99*b3fb8555SGiannis Adamopoulos #include "wine/unicode.h"
100*b3fb8555SGiannis Adamopoulos #include "wingdi.h"
101*b3fb8555SGiannis Adamopoulos #include "winuser.h"
102*b3fb8555SGiannis Adamopoulos #include "winnls.h"
103*b3fb8555SGiannis Adamopoulos #include "commctrl.h"
104*b3fb8555SGiannis Adamopoulos #include "comctl32.h"
105*b3fb8555SGiannis Adamopoulos #include "wine/debug.h"
106c2c66affSColin Finck 
107c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(tooltips);
108c2c66affSColin Finck 
109c2c66affSColin Finck static HICON hTooltipIcons[TTI_ERROR+1];
110c2c66affSColin Finck 
111c2c66affSColin Finck typedef struct
112c2c66affSColin Finck {
113c2c66affSColin Finck     UINT      uFlags;
114c2c66affSColin Finck     UINT      uInternalFlags;
115c2c66affSColin Finck     HWND      hwnd;
116c2c66affSColin Finck     BOOL      bNotifyUnicode;
117c2c66affSColin Finck     UINT_PTR  uId;
118c2c66affSColin Finck     RECT      rect;
119c2c66affSColin Finck     HINSTANCE hinst;
120c2c66affSColin Finck     LPWSTR      lpszText;
121c2c66affSColin Finck     LPARAM      lParam;
122c2c66affSColin Finck } TTTOOL_INFO;
123c2c66affSColin Finck 
124c2c66affSColin Finck 
125c2c66affSColin Finck typedef struct
126c2c66affSColin Finck {
127c2c66affSColin Finck     HWND     hwndSelf;
128c2c66affSColin Finck     WCHAR      szTipText[INFOTIPSIZE];
129c2c66affSColin Finck     BOOL     bActive;
130c2c66affSColin Finck     BOOL     bTrackActive;
131c2c66affSColin Finck     UINT     uNumTools;
132c2c66affSColin Finck     COLORREF   clrBk;
133c2c66affSColin Finck     COLORREF   clrText;
134c2c66affSColin Finck     HFONT    hFont;
135c2c66affSColin Finck     HFONT    hTitleFont;
136c2c66affSColin Finck     INT      xTrackPos;
137c2c66affSColin Finck     INT      yTrackPos;
138c2c66affSColin Finck     INT      nMaxTipWidth;
139c2c66affSColin Finck     INT      nTool; /* tool that mouse was on on last relayed mouse move */
140c2c66affSColin Finck     INT      nCurrentTool;
141c2c66affSColin Finck     INT      nTrackTool;
142c2c66affSColin Finck     INT      nReshowTime;
143c2c66affSColin Finck     INT      nAutoPopTime;
144c2c66affSColin Finck     INT      nInitialTime;
145c2c66affSColin Finck     RECT     rcMargin;
146c2c66affSColin Finck     BOOL     bToolBelow;
147c2c66affSColin Finck     LPWSTR   pszTitle;
148c2c66affSColin Finck     HICON    hTitleIcon;
149c2c66affSColin Finck 
150c2c66affSColin Finck     TTTOOL_INFO *tools;
151c2c66affSColin Finck } TOOLTIPS_INFO;
152c2c66affSColin Finck 
153c2c66affSColin Finck #define ID_TIMERSHOW   1    /* show delay timer */
154c2c66affSColin Finck #define ID_TIMERPOP    2    /* auto pop timer */
155c2c66affSColin Finck #define ID_TIMERLEAVE  3    /* tool leave timer */
156c2c66affSColin Finck 
157c2c66affSColin Finck 
158c2c66affSColin Finck #define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0))
159c2c66affSColin Finck 
160c2c66affSColin Finck /* offsets from window edge to start of text */
161c2c66affSColin Finck #define NORMAL_TEXT_MARGIN 2
162c2c66affSColin Finck #define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8)
163c2c66affSColin Finck /* value used for CreateRoundRectRgn that specifies how much
164c2c66affSColin Finck  * each corner is curved */
165c2c66affSColin Finck #define BALLOON_ROUNDEDNESS 20
166c2c66affSColin Finck #define BALLOON_STEMHEIGHT 13
167c2c66affSColin Finck #define BALLOON_STEMWIDTH 10
168c2c66affSColin Finck #define BALLOON_STEMINDENT 20
169c2c66affSColin Finck 
170c2c66affSColin Finck #define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */
171c2c66affSColin Finck #define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */
172c2c66affSColin Finck #define ICON_HEIGHT 16
173c2c66affSColin Finck #define ICON_WIDTH  16
174c2c66affSColin Finck 
175c2c66affSColin Finck #define MAX_TEXT_SIZE_A 80 /* maximum retrieving text size by ANSI message */
176c2c66affSColin Finck 
177c2c66affSColin Finck static LRESULT CALLBACK
178c2c66affSColin Finck TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef);
179c2c66affSColin Finck 
180c2c66affSColin Finck 
181c2c66affSColin Finck static inline BOOL TOOLTIPS_IsCallbackString(LPCWSTR str, BOOL isW)
182c2c66affSColin Finck {
183c2c66affSColin Finck     if (isW)
184c2c66affSColin Finck       return str == LPSTR_TEXTCALLBACKW;
185c2c66affSColin Finck     else
186c2c66affSColin Finck       return (LPCSTR)str == LPSTR_TEXTCALLBACKA;
187c2c66affSColin Finck }
188c2c66affSColin Finck 
189c2c66affSColin Finck static inline UINT_PTR
190c2c66affSColin Finck TOOLTIPS_GetTitleIconIndex(HICON hIcon)
191c2c66affSColin Finck {
192c2c66affSColin Finck     UINT i;
193c2c66affSColin Finck     for (i = 0; i <= TTI_ERROR; i++)
194c2c66affSColin Finck         if (hTooltipIcons[i] == hIcon)
195c2c66affSColin Finck             return i;
196c2c66affSColin Finck     return (UINT_PTR)hIcon;
197c2c66affSColin Finck }
198c2c66affSColin Finck 
199c2c66affSColin Finck static void
200c2c66affSColin Finck TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr)
201c2c66affSColin Finck {
202c2c66affSColin Finck     NONCLIENTMETRICSW nclm;
203c2c66affSColin Finck 
204c2c66affSColin Finck     infoPtr->clrBk   = comctl32_color.clrInfoBk;
205c2c66affSColin Finck     infoPtr->clrText = comctl32_color.clrInfoText;
206c2c66affSColin Finck 
207c2c66affSColin Finck     DeleteObject (infoPtr->hFont);
208c2c66affSColin Finck     nclm.cbSize = sizeof(nclm);
209c2c66affSColin Finck     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0);
210c2c66affSColin Finck     infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont);
211c2c66affSColin Finck 
212c2c66affSColin Finck     DeleteObject (infoPtr->hTitleFont);
213c2c66affSColin Finck     nclm.lfStatusFont.lfWeight = FW_BOLD;
214c2c66affSColin Finck     infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont);
215c2c66affSColin Finck }
216c2c66affSColin Finck 
217c2c66affSColin Finck /* Custom draw routines */
218c2c66affSColin Finck static void
219c2c66affSColin Finck TOOLTIPS_customdraw_fill(const TOOLTIPS_INFO *infoPtr, NMTTCUSTOMDRAW *lpnmttcd,
220c2c66affSColin Finck                          HDC hdc, const RECT *rcBounds, UINT uFlags)
221c2c66affSColin Finck {
222c2c66affSColin Finck     ZeroMemory(lpnmttcd, sizeof(NMTTCUSTOMDRAW));
223c2c66affSColin Finck     lpnmttcd->uDrawFlags = uFlags;
224c2c66affSColin Finck     lpnmttcd->nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
225c2c66affSColin Finck     lpnmttcd->nmcd.hdr.code     = NM_CUSTOMDRAW;
226c2c66affSColin Finck     if (infoPtr->nCurrentTool != -1) {
227c2c66affSColin Finck         TTTOOL_INFO *toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
228c2c66affSColin Finck         lpnmttcd->nmcd.hdr.idFrom = toolPtr->uId;
229c2c66affSColin Finck     }
230c2c66affSColin Finck     lpnmttcd->nmcd.hdc = hdc;
231c2c66affSColin Finck     lpnmttcd->nmcd.rc = *rcBounds;
232c2c66affSColin Finck     /* FIXME - dwItemSpec, uItemState, lItemlParam */
233c2c66affSColin Finck }
234c2c66affSColin Finck 
235c2c66affSColin Finck static inline DWORD
236c2c66affSColin Finck TOOLTIPS_notify_customdraw (DWORD dwDrawStage, NMTTCUSTOMDRAW *lpnmttcd)
237c2c66affSColin Finck {
238c2c66affSColin Finck     LRESULT result;
239c2c66affSColin Finck     lpnmttcd->nmcd.dwDrawStage = dwDrawStage;
240c2c66affSColin Finck 
241c2c66affSColin Finck     TRACE("Notifying stage %d, flags %x, id %x\n", lpnmttcd->nmcd.dwDrawStage,
242c2c66affSColin Finck           lpnmttcd->uDrawFlags, lpnmttcd->nmcd.hdr.code);
243c2c66affSColin Finck 
244c2c66affSColin Finck     result = SendMessageW(GetParent(lpnmttcd->nmcd.hdr.hwndFrom), WM_NOTIFY,
245c2c66affSColin Finck                           0, (LPARAM)lpnmttcd);
246c2c66affSColin Finck 
247c2c66affSColin Finck     TRACE("Notify result %x\n", (unsigned int)result);
248c2c66affSColin Finck 
249c2c66affSColin Finck     return result;
250c2c66affSColin Finck }
251c2c66affSColin Finck 
252c2c66affSColin Finck static void
253c2c66affSColin Finck TOOLTIPS_Refresh (const TOOLTIPS_INFO *infoPtr, HDC hdc)
254c2c66affSColin Finck {
255c2c66affSColin Finck     RECT rc;
256c2c66affSColin Finck     INT oldBkMode;
257c2c66affSColin Finck     HFONT hOldFont;
258c2c66affSColin Finck     HBRUSH hBrush;
259c2c66affSColin Finck     UINT uFlags = DT_EXTERNALLEADING;
260c2c66affSColin Finck     HRGN hRgn = NULL;
261c2c66affSColin Finck     DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
262c2c66affSColin Finck     NMTTCUSTOMDRAW nmttcd;
263c2c66affSColin Finck     DWORD cdmode;
264c2c66affSColin Finck 
265c2c66affSColin Finck     if (infoPtr->nMaxTipWidth > -1)
266c2c66affSColin Finck 	uFlags |= DT_WORDBREAK;
267c2c66affSColin Finck     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_NOPREFIX)
268c2c66affSColin Finck 	uFlags |= DT_NOPREFIX;
269c2c66affSColin Finck     GetClientRect (infoPtr->hwndSelf, &rc);
270c2c66affSColin Finck 
271c2c66affSColin Finck     hBrush = CreateSolidBrush(infoPtr->clrBk);
272c2c66affSColin Finck 
273c2c66affSColin Finck     oldBkMode = SetBkMode (hdc, TRANSPARENT);
274c2c66affSColin Finck     SetTextColor (hdc, infoPtr->clrText);
275c2c66affSColin Finck     hOldFont = SelectObject (hdc, infoPtr->hFont);
276c2c66affSColin Finck 
277c2c66affSColin Finck     /* Custom draw - Call PrePaint once initial properties set up     */
278c2c66affSColin Finck     /* Note: Contrary to MSDN, CDRF_SKIPDEFAULT still draws a tooltip */
279c2c66affSColin Finck     TOOLTIPS_customdraw_fill(infoPtr, &nmttcd, hdc, &rc, uFlags);
280c2c66affSColin Finck     cdmode = TOOLTIPS_notify_customdraw(CDDS_PREPAINT, &nmttcd);
281c2c66affSColin Finck     uFlags = nmttcd.uDrawFlags;
282c2c66affSColin Finck 
283c2c66affSColin Finck     if (dwStyle & TTS_BALLOON)
284c2c66affSColin Finck     {
285c2c66affSColin Finck         /* create a region to store result into */
286c2c66affSColin Finck         hRgn = CreateRectRgn(0, 0, 0, 0);
287c2c66affSColin Finck 
288c2c66affSColin Finck         GetWindowRgn(infoPtr->hwndSelf, hRgn);
289c2c66affSColin Finck 
290c2c66affSColin Finck         /* fill the background */
291c2c66affSColin Finck         FillRgn(hdc, hRgn, hBrush);
292c2c66affSColin Finck         DeleteObject(hBrush);
293c2c66affSColin Finck         hBrush = NULL;
294c2c66affSColin Finck     }
295c2c66affSColin Finck     else
296c2c66affSColin Finck     {
297c2c66affSColin Finck         /* fill the background */
298c2c66affSColin Finck         FillRect(hdc, &rc, hBrush);
299c2c66affSColin Finck         DeleteObject(hBrush);
300c2c66affSColin Finck         hBrush = NULL;
301c2c66affSColin Finck     }
302c2c66affSColin Finck 
303c2c66affSColin Finck     if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle)
304c2c66affSColin Finck     {
305c2c66affSColin Finck         /* calculate text rectangle */
306c2c66affSColin Finck         rc.left   += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left);
307c2c66affSColin Finck         rc.top    += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top);
308c2c66affSColin Finck         rc.right  -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right);
309c2c66affSColin Finck         rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom);
310c2c66affSColin Finck         if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT;
311c2c66affSColin Finck 
312c2c66affSColin Finck         if (infoPtr->pszTitle)
313c2c66affSColin Finck         {
314c2c66affSColin Finck             RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom};
315c2c66affSColin Finck             int height;
316c2c66affSColin Finck             BOOL icon_present;
317c2c66affSColin Finck             HFONT prevFont;
318c2c66affSColin Finck 
319c2c66affSColin Finck             /* draw icon */
320c2c66affSColin Finck             icon_present = infoPtr->hTitleIcon &&
321c2c66affSColin Finck                 DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon,
322c2c66affSColin Finck                            ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL);
323c2c66affSColin Finck             if (icon_present)
324c2c66affSColin Finck                 rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING;
325c2c66affSColin Finck 
326c2c66affSColin Finck             rcTitle.bottom = rc.top + ICON_HEIGHT;
327c2c66affSColin Finck 
328c2c66affSColin Finck             /* draw title text */
329c2c66affSColin Finck             prevFont = SelectObject (hdc, infoPtr->hTitleFont);
330c2c66affSColin Finck             height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX);
331c2c66affSColin Finck             SelectObject (hdc, prevFont);
332c2c66affSColin Finck             rc.top += height + BALLOON_TITLE_TEXT_SPACING;
333c2c66affSColin Finck         }
334c2c66affSColin Finck     }
335c2c66affSColin Finck     else
336c2c66affSColin Finck     {
337c2c66affSColin Finck         /* calculate text rectangle */
338c2c66affSColin Finck         rc.left   += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left);
339c2c66affSColin Finck         rc.top    += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top);
340c2c66affSColin Finck         rc.right  -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right);
341c2c66affSColin Finck         rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom);
342c2c66affSColin Finck     }
343c2c66affSColin Finck 
344c2c66affSColin Finck     /* draw text */
345c2c66affSColin Finck     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
346c2c66affSColin Finck 
347c2c66affSColin Finck     /* Custom draw - Call PostPaint after drawing */
348c2c66affSColin Finck     if (cdmode & CDRF_NOTIFYPOSTPAINT) {
349c2c66affSColin Finck         TOOLTIPS_notify_customdraw(CDDS_POSTPAINT, &nmttcd);
350c2c66affSColin Finck     }
351c2c66affSColin Finck 
352c2c66affSColin Finck     /* be polite and reset the things we changed in the dc */
353c2c66affSColin Finck     SelectObject (hdc, hOldFont);
354c2c66affSColin Finck     SetBkMode (hdc, oldBkMode);
355c2c66affSColin Finck 
356c2c66affSColin Finck     if (dwStyle & TTS_BALLOON)
357c2c66affSColin Finck     {
358c2c66affSColin Finck         /* frame region because default window proc doesn't do it */
359c2c66affSColin Finck         INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
360c2c66affSColin Finck         INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
361c2c66affSColin Finck 
362c2c66affSColin Finck         hBrush = GetSysColorBrush(COLOR_WINDOWFRAME);
363c2c66affSColin Finck         FrameRgn(hdc, hRgn, hBrush, width, height);
364c2c66affSColin Finck     }
365c2c66affSColin Finck 
366c2c66affSColin Finck     if (hRgn)
367c2c66affSColin Finck         DeleteObject(hRgn);
368c2c66affSColin Finck }
369c2c66affSColin Finck 
370c2c66affSColin Finck static void TOOLTIPS_GetDispInfoA(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer)
371c2c66affSColin Finck {
372c2c66affSColin Finck     NMTTDISPINFOA ttnmdi;
373c2c66affSColin Finck 
374c2c66affSColin Finck     /* fill NMHDR struct */
375c2c66affSColin Finck     ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA));
376c2c66affSColin Finck     ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf;
377c2c66affSColin Finck     ttnmdi.hdr.idFrom = toolPtr->uId;
378c2c66affSColin Finck     ttnmdi.hdr.code = TTN_GETDISPINFOA; /* == TTN_NEEDTEXTA */
379c2c66affSColin Finck     ttnmdi.lpszText = ttnmdi.szText;
380c2c66affSColin Finck     ttnmdi.uFlags = toolPtr->uFlags;
381c2c66affSColin Finck     ttnmdi.lParam = toolPtr->lParam;
382c2c66affSColin Finck 
383c2c66affSColin Finck     TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom);
384c2c66affSColin Finck     SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
385c2c66affSColin Finck 
386c2c66affSColin Finck     if (IS_INTRESOURCE(ttnmdi.lpszText)) {
387c2c66affSColin Finck         LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
388c2c66affSColin Finck                buffer, INFOTIPSIZE);
389c2c66affSColin Finck         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
390c2c66affSColin Finck             toolPtr->hinst = ttnmdi.hinst;
391c2c66affSColin Finck             toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText;
392c2c66affSColin Finck         }
393c2c66affSColin Finck     }
394c2c66affSColin Finck     else if (ttnmdi.lpszText == 0) {
395c2c66affSColin Finck         buffer[0] = '\0';
396c2c66affSColin Finck     }
397c2c66affSColin Finck     else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
398c2c66affSColin Finck         Str_GetPtrAtoW(ttnmdi.lpszText, buffer, INFOTIPSIZE);
399c2c66affSColin Finck         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
400c2c66affSColin Finck             toolPtr->hinst = 0;
401c2c66affSColin Finck             toolPtr->lpszText = NULL;
402c2c66affSColin Finck             Str_SetPtrW(&toolPtr->lpszText, buffer);
403c2c66affSColin Finck         }
404c2c66affSColin Finck     }
405c2c66affSColin Finck     else {
406edd99e8cSAmine Khaldi         ERR("recursive text callback\n");
407c2c66affSColin Finck         buffer[0] = '\0';
408c2c66affSColin Finck     }
409c2c66affSColin Finck 
410c2c66affSColin Finck     /* no text available - try calling parent instead as per native */
411c2c66affSColin Finck     /* FIXME: Unsure if SETITEM should save the value or not        */
412c2c66affSColin Finck     if (buffer[0] == 0x00) {
413c2c66affSColin Finck 
414c2c66affSColin Finck         SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
415c2c66affSColin Finck 
416c2c66affSColin Finck         if (IS_INTRESOURCE(ttnmdi.lpszText)) {
417c2c66affSColin Finck             LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
418c2c66affSColin Finck                    buffer, INFOTIPSIZE);
419c2c66affSColin Finck         } else if (ttnmdi.lpszText &&
420c2c66affSColin Finck                    ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) {
421c2c66affSColin Finck             Str_GetPtrAtoW(ttnmdi.lpszText, buffer, INFOTIPSIZE);
422c2c66affSColin Finck         }
423c2c66affSColin Finck     }
424c2c66affSColin Finck }
425c2c66affSColin Finck 
426c2c66affSColin Finck static void TOOLTIPS_GetDispInfoW(const TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr, WCHAR *buffer)
427c2c66affSColin Finck {
428c2c66affSColin Finck     NMTTDISPINFOW ttnmdi;
429c2c66affSColin Finck 
430c2c66affSColin Finck     /* fill NMHDR struct */
431c2c66affSColin Finck     ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW));
432c2c66affSColin Finck     ttnmdi.hdr.hwndFrom = infoPtr->hwndSelf;
433c2c66affSColin Finck     ttnmdi.hdr.idFrom = toolPtr->uId;
434c2c66affSColin Finck     ttnmdi.hdr.code = TTN_GETDISPINFOW; /* == TTN_NEEDTEXTW */
435c2c66affSColin Finck     ttnmdi.lpszText = ttnmdi.szText;
436c2c66affSColin Finck     ttnmdi.uFlags = toolPtr->uFlags;
437c2c66affSColin Finck     ttnmdi.lParam = toolPtr->lParam;
438c2c66affSColin Finck 
439c2c66affSColin Finck     TRACE("hdr.idFrom = %lx\n", ttnmdi.hdr.idFrom);
440c2c66affSColin Finck     SendMessageW(toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
441c2c66affSColin Finck 
442c2c66affSColin Finck     if (IS_INTRESOURCE(ttnmdi.lpszText)) {
443c2c66affSColin Finck         LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
444c2c66affSColin Finck                buffer, INFOTIPSIZE);
445c2c66affSColin Finck         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
446c2c66affSColin Finck             toolPtr->hinst = ttnmdi.hinst;
447c2c66affSColin Finck             toolPtr->lpszText = ttnmdi.lpszText;
448c2c66affSColin Finck         }
449c2c66affSColin Finck     }
450c2c66affSColin Finck     else if (ttnmdi.lpszText == 0) {
451c2c66affSColin Finck         buffer[0] = '\0';
452c2c66affSColin Finck     }
453c2c66affSColin Finck     else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
454c2c66affSColin Finck         Str_GetPtrW(ttnmdi.lpszText, buffer, INFOTIPSIZE);
455c2c66affSColin Finck         if (ttnmdi.uFlags & TTF_DI_SETITEM) {
456c2c66affSColin Finck             toolPtr->hinst = 0;
457c2c66affSColin Finck             toolPtr->lpszText = NULL;
458c2c66affSColin Finck             Str_SetPtrW(&toolPtr->lpszText, buffer);
459c2c66affSColin Finck         }
460c2c66affSColin Finck     }
461c2c66affSColin Finck     else {
462edd99e8cSAmine Khaldi         ERR("recursive text callback\n");
463c2c66affSColin Finck         buffer[0] = '\0';
464c2c66affSColin Finck     }
465c2c66affSColin Finck 
466c2c66affSColin Finck     /* no text available - try calling parent instead as per native */
467c2c66affSColin Finck     /* FIXME: Unsure if SETITEM should save the value or not        */
468c2c66affSColin Finck     if (buffer[0] == 0x00) {
469c2c66affSColin Finck 
470c2c66affSColin Finck         SendMessageW(GetParent(toolPtr->hwnd), WM_NOTIFY, toolPtr->uId, (LPARAM)&ttnmdi);
471c2c66affSColin Finck 
472c2c66affSColin Finck         if (IS_INTRESOURCE(ttnmdi.lpszText)) {
473c2c66affSColin Finck             LoadStringW(ttnmdi.hinst, LOWORD(ttnmdi.lpszText),
474c2c66affSColin Finck                    buffer, INFOTIPSIZE);
475c2c66affSColin Finck         } else if (ttnmdi.lpszText &&
476c2c66affSColin Finck                    ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) {
477c2c66affSColin Finck             Str_GetPtrW(ttnmdi.lpszText, buffer, INFOTIPSIZE);
478c2c66affSColin Finck         }
479c2c66affSColin Finck     }
480c2c66affSColin Finck 
481c2c66affSColin Finck }
482c2c66affSColin Finck 
483c2c66affSColin Finck static void
484c2c66affSColin Finck TOOLTIPS_GetTipText (const TOOLTIPS_INFO *infoPtr, INT nTool, WCHAR *buffer)
485c2c66affSColin Finck {
486c2c66affSColin Finck     TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool];
487c2c66affSColin Finck 
488c2c66affSColin Finck     if (IS_INTRESOURCE(toolPtr->lpszText)) {
489c2c66affSColin Finck 	/* load a resource */
490c2c66affSColin Finck 	TRACE("load res string %p %x\n",
491c2c66affSColin Finck 	       toolPtr->hinst, LOWORD(toolPtr->lpszText));
492c2c66affSColin Finck 	if (!LoadStringW (toolPtr->hinst, LOWORD(toolPtr->lpszText), buffer, INFOTIPSIZE))
493c2c66affSColin Finck 	    buffer[0] = '\0';
494c2c66affSColin Finck     }
495c2c66affSColin Finck     else if (toolPtr->lpszText) {
496c2c66affSColin Finck 	if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) {
497c2c66affSColin Finck 	    if (toolPtr->bNotifyUnicode)
498c2c66affSColin Finck 		TOOLTIPS_GetDispInfoW(infoPtr, toolPtr, buffer);
499c2c66affSColin Finck 	    else
500c2c66affSColin Finck 		TOOLTIPS_GetDispInfoA(infoPtr, toolPtr, buffer);
501c2c66affSColin Finck 	}
502c2c66affSColin Finck 	else {
503c2c66affSColin Finck 	    /* the item is a usual (unicode) text */
504c2c66affSColin Finck 	    lstrcpynW (buffer, toolPtr->lpszText, INFOTIPSIZE);
505c2c66affSColin Finck 	}
506c2c66affSColin Finck     }
507c2c66affSColin Finck     else {
508c2c66affSColin Finck 	/* no text available */
509c2c66affSColin Finck         buffer[0] = '\0';
510c2c66affSColin Finck     }
511c2c66affSColin Finck 
512c2c66affSColin Finck     if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & TTS_NOPREFIX)) {
513c2c66affSColin Finck         WCHAR *ptrW;
514c2c66affSColin Finck         if ((ptrW = strchrW(buffer, '\t')))
515c2c66affSColin Finck             *ptrW = 0;
516c2c66affSColin Finck     }
517c2c66affSColin Finck 
518c2c66affSColin Finck     TRACE("%s\n", debugstr_w(buffer));
519c2c66affSColin Finck }
520c2c66affSColin Finck 
521c2c66affSColin Finck 
522c2c66affSColin Finck static void
523c2c66affSColin Finck TOOLTIPS_CalcTipSize (const TOOLTIPS_INFO *infoPtr, LPSIZE lpSize)
524c2c66affSColin Finck {
525c2c66affSColin Finck     HDC hdc;
526c2c66affSColin Finck     HFONT hOldFont;
527c2c66affSColin Finck     DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
528c2c66affSColin Finck     UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT;
529c2c66affSColin Finck     RECT rc = {0, 0, 0, 0};
530c2c66affSColin Finck     SIZE title = {0, 0};
531c2c66affSColin Finck 
532c2c66affSColin Finck     if (infoPtr->nMaxTipWidth > -1) {
533c2c66affSColin Finck 	rc.right = infoPtr->nMaxTipWidth;
534c2c66affSColin Finck 	uFlags |= DT_WORDBREAK;
535c2c66affSColin Finck     }
536c2c66affSColin Finck     if (style & TTS_NOPREFIX)
537c2c66affSColin Finck 	uFlags |= DT_NOPREFIX;
538c2c66affSColin Finck     TRACE("%s\n", debugstr_w(infoPtr->szTipText));
539c2c66affSColin Finck 
540c2c66affSColin Finck     hdc = GetDC (infoPtr->hwndSelf);
541c2c66affSColin Finck     if (infoPtr->pszTitle)
542c2c66affSColin Finck     {
543c2c66affSColin Finck         RECT rcTitle = {0, 0, 0, 0};
544c2c66affSColin Finck         TRACE("title %s\n", debugstr_w(infoPtr->pszTitle));
545c2c66affSColin Finck         if (infoPtr->hTitleIcon)
546c2c66affSColin Finck         {
547c2c66affSColin Finck             title.cx = ICON_WIDTH;
548c2c66affSColin Finck             title.cy = ICON_HEIGHT;
549c2c66affSColin Finck         }
550c2c66affSColin Finck         if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING;
551c2c66affSColin Finck         hOldFont = SelectObject (hdc, infoPtr->hTitleFont);
552c2c66affSColin Finck         DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT);
553c2c66affSColin Finck         SelectObject (hdc, hOldFont);
554c2c66affSColin Finck         title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING;
555c2c66affSColin Finck         title.cx += (rcTitle.right - rcTitle.left);
556c2c66affSColin Finck     }
557c2c66affSColin Finck     hOldFont = SelectObject (hdc, infoPtr->hFont);
558c2c66affSColin Finck     DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags);
559c2c66affSColin Finck     SelectObject (hdc, hOldFont);
560c2c66affSColin Finck     ReleaseDC (infoPtr->hwndSelf, hdc);
561c2c66affSColin Finck 
562c2c66affSColin Finck     if ((style & TTS_BALLOON) || infoPtr->pszTitle)
563c2c66affSColin Finck     {
564c2c66affSColin Finck         lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN +
565c2c66affSColin Finck                        infoPtr->rcMargin.left + infoPtr->rcMargin.right;
566c2c66affSColin Finck         lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN +
567c2c66affSColin Finck                        infoPtr->rcMargin.bottom + infoPtr->rcMargin.top +
568c2c66affSColin Finck                        BALLOON_STEMHEIGHT;
569c2c66affSColin Finck     }
570c2c66affSColin Finck     else
571c2c66affSColin Finck     {
572c2c66affSColin Finck         lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN +
573c2c66affSColin Finck                        infoPtr->rcMargin.left + infoPtr->rcMargin.right;
574c2c66affSColin Finck         lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN +
575c2c66affSColin Finck                        infoPtr->rcMargin.bottom + infoPtr->rcMargin.top;
576c2c66affSColin Finck     }
577c2c66affSColin Finck }
578c2c66affSColin Finck 
579c2c66affSColin Finck 
580c2c66affSColin Finck static void
581c2c66affSColin Finck TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate)
582c2c66affSColin Finck {
583c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
584c2c66affSColin Finck     HMONITOR monitor;
585c2c66affSColin Finck     MONITORINFO mon_info;
586c2c66affSColin Finck     RECT rect;
587c2c66affSColin Finck     SIZE size;
588c2c66affSColin Finck     NMHDR  hdr;
589c2c66affSColin Finck     int ptfx = 0;
590c2c66affSColin Finck     DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE);
591edd99e8cSAmine Khaldi     INT nTool, current;
592c2c66affSColin Finck 
593c2c66affSColin Finck     if (track_activate)
594c2c66affSColin Finck     {
595c2c66affSColin Finck         if (infoPtr->nTrackTool == -1)
596c2c66affSColin Finck         {
597edd99e8cSAmine Khaldi             TRACE("invalid tracking tool %d\n", infoPtr->nTrackTool);
598c2c66affSColin Finck             return;
599c2c66affSColin Finck         }
600c2c66affSColin Finck         nTool = infoPtr->nTrackTool;
601c2c66affSColin Finck     }
602c2c66affSColin Finck     else
603c2c66affSColin Finck     {
604c2c66affSColin Finck         if (infoPtr->nTool == -1)
605c2c66affSColin Finck         {
606edd99e8cSAmine Khaldi             TRACE("invalid tool %d\n", infoPtr->nTool);
607c2c66affSColin Finck             return;
608c2c66affSColin Finck         }
609c2c66affSColin Finck         nTool = infoPtr->nTool;
610c2c66affSColin Finck     }
611c2c66affSColin Finck 
612edd99e8cSAmine Khaldi     TRACE("Show tooltip pre %d, %p\n", nTool, infoPtr->hwndSelf);
613edd99e8cSAmine Khaldi 
614edd99e8cSAmine Khaldi     current = infoPtr->nCurrentTool;
615edd99e8cSAmine Khaldi     if (!track_activate)
616edd99e8cSAmine Khaldi         infoPtr->nCurrentTool = infoPtr->nTool;
617c2c66affSColin Finck 
618c2c66affSColin Finck     TOOLTIPS_GetTipText (infoPtr, nTool, infoPtr->szTipText);
619c2c66affSColin Finck 
620c2c66affSColin Finck     if (infoPtr->szTipText[0] == '\0')
621edd99e8cSAmine Khaldi     {
622edd99e8cSAmine Khaldi         infoPtr->nCurrentTool = current;
623c2c66affSColin Finck         return;
624edd99e8cSAmine Khaldi     }
625c2c66affSColin Finck 
626c2c66affSColin Finck     toolPtr = &infoPtr->tools[nTool];
627c2c66affSColin Finck     TOOLTIPS_CalcTipSize (infoPtr, &size);
628*b3fb8555SGiannis Adamopoulos 
629*b3fb8555SGiannis Adamopoulos     TRACE("Show tooltip %d, %s, size %d x %d\n", nTool, debugstr_w(infoPtr->szTipText),
630*b3fb8555SGiannis Adamopoulos         size.cx, size.cy);
631c2c66affSColin Finck 
632c2c66affSColin Finck     if (track_activate && (toolPtr->uFlags & TTF_TRACK))
633c2c66affSColin Finck     {
634c2c66affSColin Finck         rect.left = infoPtr->xTrackPos;
635c2c66affSColin Finck         rect.top  = infoPtr->yTrackPos;
636c2c66affSColin Finck         ptfx = rect.left;
637c2c66affSColin Finck 
638c2c66affSColin Finck         if (toolPtr->uFlags & TTF_CENTERTIP)
639c2c66affSColin Finck         {
640c2c66affSColin Finck             rect.left -= (size.cx / 2);
641c2c66affSColin Finck             if (!(style & TTS_BALLOON))
642c2c66affSColin Finck                 rect.top  -= (size.cy / 2);
643c2c66affSColin Finck         }
644c2c66affSColin Finck         if (!(infoPtr->bToolBelow = (infoPtr->yTrackPos + size.cy <= GetSystemMetrics(SM_CYSCREEN))))
645c2c66affSColin Finck             rect.top -= size.cy;
646c2c66affSColin Finck 
647c2c66affSColin Finck         if (!(toolPtr->uFlags & TTF_ABSOLUTE))
648c2c66affSColin Finck         {
649c2c66affSColin Finck             if (style & TTS_BALLOON)
650c2c66affSColin Finck                 rect.left -= BALLOON_STEMINDENT;
651c2c66affSColin Finck             else
652c2c66affSColin Finck             {
653c2c66affSColin Finck                 RECT rcTool;
654c2c66affSColin Finck 
655c2c66affSColin Finck                 if (toolPtr->uFlags & TTF_IDISHWND)
656c2c66affSColin Finck                     GetWindowRect ((HWND)toolPtr->uId, &rcTool);
657c2c66affSColin Finck                 else
658c2c66affSColin Finck                 {
659c2c66affSColin Finck                     rcTool = toolPtr->rect;
660c2c66affSColin Finck                     MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2);
661c2c66affSColin Finck                 }
662c2c66affSColin Finck 
663c2c66affSColin Finck                 /* smart placement */
664c2c66affSColin Finck                 if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) &&
665c2c66affSColin Finck                     (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom))
666c2c66affSColin Finck                     rect.left = rcTool.right;
667c2c66affSColin Finck             }
668c2c66affSColin Finck         }
669c2c66affSColin Finck     }
670c2c66affSColin Finck     else
671c2c66affSColin Finck     {
672c2c66affSColin Finck         if (toolPtr->uFlags & TTF_CENTERTIP)
673c2c66affSColin Finck         {
674c2c66affSColin Finck 		RECT rc;
675c2c66affSColin Finck 
676c2c66affSColin Finck             if (toolPtr->uFlags & TTF_IDISHWND)
677c2c66affSColin Finck                 GetWindowRect ((HWND)toolPtr->uId, &rc);
678c2c66affSColin Finck             else {
679c2c66affSColin Finck                 rc = toolPtr->rect;
680c2c66affSColin Finck                 MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
681c2c66affSColin Finck             }
682c2c66affSColin Finck             rect.left = (rc.left + rc.right - size.cx) / 2;
683c2c66affSColin Finck             if (style & TTS_BALLOON)
684c2c66affSColin Finck             {
685c2c66affSColin Finck                 ptfx = rc.left + ((rc.right - rc.left) / 2);
686c2c66affSColin Finck 
687c2c66affSColin Finck                 /* CENTERTIP ballon tooltips default to below the field
688c2c66affSColin Finck                  * if they fit on the screen */
689c2c66affSColin Finck                 if (rc.bottom + size.cy > GetSystemMetrics(SM_CYSCREEN))
690c2c66affSColin Finck                 {
691c2c66affSColin Finck                     rect.top = rc.top - size.cy;
692c2c66affSColin Finck                     infoPtr->bToolBelow = FALSE;
693c2c66affSColin Finck                 }
694c2c66affSColin Finck                 else
695c2c66affSColin Finck                 {
696c2c66affSColin Finck                     infoPtr->bToolBelow = TRUE;
697c2c66affSColin Finck                     rect.top = rc.bottom;
698c2c66affSColin Finck                 }
699c2c66affSColin Finck                 rect.left = max(0, rect.left - BALLOON_STEMINDENT);
700c2c66affSColin Finck             }
701c2c66affSColin Finck             else
702c2c66affSColin Finck             {
703c2c66affSColin Finck                 rect.top  = rc.bottom + 2;
704c2c66affSColin Finck                 infoPtr->bToolBelow = TRUE;
705c2c66affSColin Finck             }
706c2c66affSColin Finck         }
707c2c66affSColin Finck         else
708c2c66affSColin Finck         {
709c2c66affSColin Finck             GetCursorPos ((LPPOINT)&rect);
710c2c66affSColin Finck             if (style & TTS_BALLOON)
711c2c66affSColin Finck             {
712c2c66affSColin Finck                 ptfx = rect.left;
713c2c66affSColin Finck                 if(rect.top - size.cy >= 0)
714c2c66affSColin Finck                 {
715c2c66affSColin Finck                     rect.top -= size.cy;
716c2c66affSColin Finck                     infoPtr->bToolBelow = FALSE;
717c2c66affSColin Finck                 }
718c2c66affSColin Finck                 else
719c2c66affSColin Finck                 {
720c2c66affSColin Finck                     infoPtr->bToolBelow = TRUE;
721c2c66affSColin Finck                     rect.top += 20;
722c2c66affSColin Finck                 }
723c2c66affSColin Finck                 rect.left = max(0, rect.left - BALLOON_STEMINDENT);
724c2c66affSColin Finck             }
725c2c66affSColin Finck             else
726c2c66affSColin Finck             {
727c2c66affSColin Finck 		    rect.top += 20;
728c2c66affSColin Finck 		    infoPtr->bToolBelow = TRUE;
729c2c66affSColin Finck             }
730c2c66affSColin Finck         }
731c2c66affSColin Finck     }
732c2c66affSColin Finck 
733c2c66affSColin Finck     TRACE("pos %d - %d\n", rect.left, rect.top);
734c2c66affSColin Finck 
735c2c66affSColin Finck     rect.right = rect.left + size.cx;
736c2c66affSColin Finck     rect.bottom = rect.top + size.cy;
737c2c66affSColin Finck 
738c2c66affSColin Finck     /* check position */
739c2c66affSColin Finck 
740c2c66affSColin Finck     monitor = MonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY );
741c2c66affSColin Finck     mon_info.cbSize = sizeof(mon_info);
742c2c66affSColin Finck     GetMonitorInfoW( monitor, &mon_info );
743c2c66affSColin Finck 
744c2c66affSColin Finck     if( rect.right > mon_info.rcWork.right ) {
745c2c66affSColin Finck         rect.left -= rect.right - mon_info.rcWork.right + 2;
746c2c66affSColin Finck         rect.right = mon_info.rcWork.right - 2;
747c2c66affSColin Finck     }
748c2c66affSColin Finck     if (rect.left < mon_info.rcWork.left) rect.left = mon_info.rcWork.left;
749c2c66affSColin Finck 
750c2c66affSColin Finck     if( rect.bottom > mon_info.rcWork.bottom ) {
751c2c66affSColin Finck         RECT rc;
752c2c66affSColin Finck 
753c2c66affSColin Finck 	if (toolPtr->uFlags & TTF_IDISHWND)
754c2c66affSColin Finck 	    GetWindowRect ((HWND)toolPtr->uId, &rc);
755c2c66affSColin Finck 	else {
756c2c66affSColin Finck 	    rc = toolPtr->rect;
757c2c66affSColin Finck 	    MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2);
758c2c66affSColin Finck 	}
759c2c66affSColin Finck 	rect.bottom = rc.top - 2;
760c2c66affSColin Finck     	rect.top = rect.bottom - size.cy;
761c2c66affSColin Finck     }
762c2c66affSColin Finck 
763c2c66affSColin Finck     AdjustWindowRectEx (&rect, GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE),
764c2c66affSColin Finck 			FALSE, GetWindowLongW (infoPtr->hwndSelf, GWL_EXSTYLE));
765c2c66affSColin Finck 
766c2c66affSColin Finck     if (style & TTS_BALLOON)
767c2c66affSColin Finck     {
768c2c66affSColin Finck         HRGN hRgn;
769c2c66affSColin Finck         HRGN hrStem;
770c2c66affSColin Finck         POINT pts[3];
771c2c66affSColin Finck 
772c2c66affSColin Finck         ptfx -= rect.left;
773c2c66affSColin Finck 
774c2c66affSColin Finck         if(infoPtr->bToolBelow)
775c2c66affSColin Finck         {
776c2c66affSColin Finck           pts[0].x = ptfx;
777c2c66affSColin Finck           pts[0].y = 0;
778c2c66affSColin Finck           pts[1].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2));
779c2c66affSColin Finck           pts[1].y = BALLOON_STEMHEIGHT;
780c2c66affSColin Finck           pts[2].x = pts[1].x + BALLOON_STEMWIDTH;
781c2c66affSColin Finck           pts[2].y = pts[1].y;
782c2c66affSColin Finck           if(pts[2].x > (rect.right - rect.left) - BALLOON_STEMINDENT)
783c2c66affSColin Finck           {
784c2c66affSColin Finck             pts[2].x = (rect.right - rect.left) - BALLOON_STEMINDENT;
785c2c66affSColin Finck             pts[1].x = pts[2].x - BALLOON_STEMWIDTH;
786c2c66affSColin Finck           }
787c2c66affSColin Finck         }
788c2c66affSColin Finck         else
789c2c66affSColin Finck         {
790c2c66affSColin Finck           pts[0].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2));
791c2c66affSColin Finck           pts[0].y = (rect.bottom - rect.top) - BALLOON_STEMHEIGHT;
792c2c66affSColin Finck           pts[1].x = pts[0].x + BALLOON_STEMWIDTH;
793c2c66affSColin Finck           pts[1].y = pts[0].y;
794c2c66affSColin Finck           pts[2].x = ptfx;
795c2c66affSColin Finck           pts[2].y = (rect.bottom - rect.top);
796c2c66affSColin Finck           if(pts[1].x > (rect.right - rect.left) - BALLOON_STEMINDENT)
797c2c66affSColin Finck           {
798c2c66affSColin Finck             pts[1].x = (rect.right - rect.left) - BALLOON_STEMINDENT;
799c2c66affSColin Finck             pts[0].x = pts[1].x - BALLOON_STEMWIDTH;
800c2c66affSColin Finck           }
801c2c66affSColin Finck         }
802c2c66affSColin Finck 
803*b3fb8555SGiannis Adamopoulos         hrStem = CreatePolygonRgn(pts, ARRAY_SIZE(pts), ALTERNATE);
804c2c66affSColin Finck 
805c2c66affSColin Finck         hRgn = CreateRoundRectRgn(0,
806c2c66affSColin Finck                                   (infoPtr->bToolBelow ? BALLOON_STEMHEIGHT : 0),
807c2c66affSColin Finck                                   rect.right - rect.left,
808c2c66affSColin Finck                                   (infoPtr->bToolBelow ? rect.bottom - rect.top : rect.bottom - rect.top - BALLOON_STEMHEIGHT),
809c2c66affSColin Finck                                   BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS);
810c2c66affSColin Finck 
811c2c66affSColin Finck         CombineRgn(hRgn, hRgn, hrStem, RGN_OR);
812c2c66affSColin Finck         DeleteObject(hrStem);
813c2c66affSColin Finck 
814c2c66affSColin Finck         SetWindowRgn(infoPtr->hwndSelf, hRgn, FALSE);
815c2c66affSColin Finck         /* we don't free the region handle as the system deletes it when
816c2c66affSColin Finck          * it is no longer needed */
817c2c66affSColin Finck     }
818c2c66affSColin Finck 
819*b3fb8555SGiannis Adamopoulos     SetWindowPos (infoPtr->hwndSelf, NULL, rect.left, rect.top,
820*b3fb8555SGiannis Adamopoulos         rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
821*b3fb8555SGiannis Adamopoulos 
822*b3fb8555SGiannis Adamopoulos     hdr.hwndFrom = infoPtr->hwndSelf;
823*b3fb8555SGiannis Adamopoulos     hdr.idFrom = toolPtr->uId;
824*b3fb8555SGiannis Adamopoulos     hdr.code = TTN_SHOW;
825*b3fb8555SGiannis Adamopoulos     SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
826*b3fb8555SGiannis Adamopoulos 
827*b3fb8555SGiannis Adamopoulos     SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, 0, 0, 0, 0,
828*b3fb8555SGiannis Adamopoulos         SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
829c2c66affSColin Finck 
830c2c66affSColin Finck     /* repaint the tooltip */
831c2c66affSColin Finck     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
832c2c66affSColin Finck     UpdateWindow(infoPtr->hwndSelf);
833c2c66affSColin Finck 
834c2c66affSColin Finck     if (!track_activate)
835c2c66affSColin Finck     {
836c2c66affSColin Finck         SetTimer (infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
837edd99e8cSAmine Khaldi         TRACE("timer 2 started\n");
838c2c66affSColin Finck         SetTimer (infoPtr->hwndSelf, ID_TIMERLEAVE, infoPtr->nReshowTime, 0);
839edd99e8cSAmine Khaldi         TRACE("timer 3 started\n");
840c2c66affSColin Finck     }
841c2c66affSColin Finck }
842c2c66affSColin Finck 
843c2c66affSColin Finck 
844c2c66affSColin Finck static void
845c2c66affSColin Finck TOOLTIPS_Hide (TOOLTIPS_INFO *infoPtr)
846c2c66affSColin Finck {
847c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
848c2c66affSColin Finck     NMHDR hdr;
849c2c66affSColin Finck 
850edd99e8cSAmine Khaldi     TRACE("Hide tooltip %d, %p.\n", infoPtr->nCurrentTool, infoPtr->hwndSelf);
851c2c66affSColin Finck 
852c2c66affSColin Finck     if (infoPtr->nCurrentTool == -1)
853c2c66affSColin Finck 	return;
854c2c66affSColin Finck 
855c2c66affSColin Finck     toolPtr = &infoPtr->tools[infoPtr->nCurrentTool];
856c2c66affSColin Finck     KillTimer (infoPtr->hwndSelf, ID_TIMERPOP);
857c2c66affSColin Finck 
858c2c66affSColin Finck     hdr.hwndFrom = infoPtr->hwndSelf;
859c2c66affSColin Finck     hdr.idFrom = toolPtr->uId;
860c2c66affSColin Finck     hdr.code = TTN_POP;
861c2c66affSColin Finck     SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
862c2c66affSColin Finck 
863c2c66affSColin Finck     infoPtr->nCurrentTool = -1;
864c2c66affSColin Finck 
865c2c66affSColin Finck     SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
866c2c66affSColin Finck 		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
867c2c66affSColin Finck }
868c2c66affSColin Finck 
869c2c66affSColin Finck 
870c2c66affSColin Finck static void
871c2c66affSColin Finck TOOLTIPS_TrackShow (TOOLTIPS_INFO *infoPtr)
872c2c66affSColin Finck {
873c2c66affSColin Finck     TOOLTIPS_Show(infoPtr, TRUE);
874c2c66affSColin Finck }
875c2c66affSColin Finck 
876c2c66affSColin Finck 
877c2c66affSColin Finck static void
878c2c66affSColin Finck TOOLTIPS_TrackHide (const TOOLTIPS_INFO *infoPtr)
879c2c66affSColin Finck {
880c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
881c2c66affSColin Finck     NMHDR hdr;
882c2c66affSColin Finck 
883c2c66affSColin Finck     TRACE("hide tracking tooltip %d\n", infoPtr->nTrackTool);
884c2c66affSColin Finck 
885c2c66affSColin Finck     if (infoPtr->nTrackTool == -1)
886c2c66affSColin Finck 	return;
887c2c66affSColin Finck 
888c2c66affSColin Finck     toolPtr = &infoPtr->tools[infoPtr->nTrackTool];
889c2c66affSColin Finck 
890c2c66affSColin Finck     hdr.hwndFrom = infoPtr->hwndSelf;
891c2c66affSColin Finck     hdr.idFrom = toolPtr->uId;
892c2c66affSColin Finck     hdr.code = TTN_POP;
893c2c66affSColin Finck     SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr);
894c2c66affSColin Finck 
895c2c66affSColin Finck     SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, 0, 0,
896c2c66affSColin Finck 		    SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
897c2c66affSColin Finck }
898c2c66affSColin Finck 
899c2c66affSColin Finck /* Structure layout is the same for TTTOOLINFOW and TTTOOLINFOA,
900c2c66affSColin Finck    this helper is used in both cases. */
901c2c66affSColin Finck static INT
902c2c66affSColin Finck TOOLTIPS_GetToolFromInfoT (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
903c2c66affSColin Finck {
904c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
905c2c66affSColin Finck     UINT nTool;
906c2c66affSColin Finck 
907c2c66affSColin Finck     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
908c2c66affSColin Finck 	toolPtr = &infoPtr->tools[nTool];
909c2c66affSColin Finck 
910c2c66affSColin Finck 	if (!(toolPtr->uFlags & TTF_IDISHWND) &&
911c2c66affSColin Finck 	    (lpToolInfo->hwnd == toolPtr->hwnd) &&
912c2c66affSColin Finck 	    (lpToolInfo->uId == toolPtr->uId))
913c2c66affSColin Finck 	    return nTool;
914c2c66affSColin Finck     }
915c2c66affSColin Finck 
916c2c66affSColin Finck     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
917c2c66affSColin Finck 	toolPtr = &infoPtr->tools[nTool];
918c2c66affSColin Finck 
919c2c66affSColin Finck 	if ((toolPtr->uFlags & TTF_IDISHWND) &&
920c2c66affSColin Finck 	    (lpToolInfo->uId == toolPtr->uId))
921c2c66affSColin Finck 	    return nTool;
922c2c66affSColin Finck     }
923c2c66affSColin Finck 
924c2c66affSColin Finck     return -1;
925c2c66affSColin Finck }
926c2c66affSColin Finck 
927c2c66affSColin Finck 
928c2c66affSColin Finck static INT
929c2c66affSColin Finck TOOLTIPS_GetToolFromPoint (const TOOLTIPS_INFO *infoPtr, HWND hwnd, const POINT *lpPt)
930c2c66affSColin Finck {
931c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
932c2c66affSColin Finck     UINT nTool;
933c2c66affSColin Finck 
934c2c66affSColin Finck     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
935c2c66affSColin Finck 	toolPtr = &infoPtr->tools[nTool];
936c2c66affSColin Finck 
937c2c66affSColin Finck 	if (!(toolPtr->uFlags & TTF_IDISHWND)) {
938c2c66affSColin Finck 	    if (hwnd != toolPtr->hwnd)
939c2c66affSColin Finck 		continue;
940c2c66affSColin Finck 	    if (!PtInRect (&toolPtr->rect, *lpPt))
941c2c66affSColin Finck 		continue;
942c2c66affSColin Finck 	    return nTool;
943c2c66affSColin Finck 	}
944c2c66affSColin Finck     }
945c2c66affSColin Finck 
946c2c66affSColin Finck     for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) {
947c2c66affSColin Finck 	toolPtr = &infoPtr->tools[nTool];
948c2c66affSColin Finck 
949c2c66affSColin Finck 	if (toolPtr->uFlags & TTF_IDISHWND) {
950c2c66affSColin Finck 	    if ((HWND)toolPtr->uId == hwnd)
951c2c66affSColin Finck 		return nTool;
952c2c66affSColin Finck 	}
953c2c66affSColin Finck     }
954c2c66affSColin Finck 
955c2c66affSColin Finck     return -1;
956c2c66affSColin Finck }
957c2c66affSColin Finck 
958c2c66affSColin Finck static inline void
959edd99e8cSAmine Khaldi TOOLTIPS_CopyInfoT (const TOOLTIPS_INFO *infoPtr, INT index, TTTOOLINFOW *ti, BOOL isW)
960c2c66affSColin Finck {
961edd99e8cSAmine Khaldi     const TTTOOL_INFO *toolPtr = &infoPtr->tools[index];
962edd99e8cSAmine Khaldi 
963edd99e8cSAmine Khaldi     ti->uFlags = toolPtr->uFlags;
964edd99e8cSAmine Khaldi     ti->hwnd   = toolPtr->hwnd;
965edd99e8cSAmine Khaldi     ti->uId    = toolPtr->uId;
966edd99e8cSAmine Khaldi     ti->rect   = toolPtr->rect;
967edd99e8cSAmine Khaldi     ti->hinst  = toolPtr->hinst;
968edd99e8cSAmine Khaldi 
969c2c66affSColin Finck     if (ti->lpszText) {
970c2c66affSColin Finck         if (toolPtr->lpszText == NULL ||
971c2c66affSColin Finck             IS_INTRESOURCE(toolPtr->lpszText) ||
972c2c66affSColin Finck             toolPtr->lpszText == LPSTR_TEXTCALLBACKW)
973c2c66affSColin Finck             ti->lpszText = toolPtr->lpszText;
974c2c66affSColin Finck         else if (isW)
975c2c66affSColin Finck             strcpyW (ti->lpszText, toolPtr->lpszText);
976c2c66affSColin Finck         else
977c2c66affSColin Finck             /* ANSI version, the buffer is maximum 80 bytes without null. */
978c2c66affSColin Finck             WideCharToMultiByte(CP_ACP, 0, toolPtr->lpszText, -1,
979c2c66affSColin Finck                                 (LPSTR)ti->lpszText, MAX_TEXT_SIZE_A, NULL, NULL);
980c2c66affSColin Finck     }
981edd99e8cSAmine Khaldi 
982edd99e8cSAmine Khaldi     if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
983edd99e8cSAmine Khaldi         ti->lParam = toolPtr->lParam;
984edd99e8cSAmine Khaldi 
985edd99e8cSAmine Khaldi     /* lpReserved is intentionally not set. */
986c2c66affSColin Finck }
987c2c66affSColin Finck 
988c2c66affSColin Finck static BOOL
989c2c66affSColin Finck TOOLTIPS_IsWindowActive (HWND hwnd)
990c2c66affSColin Finck {
991c2c66affSColin Finck     HWND hwndActive = GetActiveWindow ();
992c2c66affSColin Finck     if (!hwndActive)
993c2c66affSColin Finck 	return FALSE;
994c2c66affSColin Finck     if (hwndActive == hwnd)
995c2c66affSColin Finck 	return TRUE;
996c2c66affSColin Finck     return IsChild (hwndActive, hwnd);
997c2c66affSColin Finck }
998c2c66affSColin Finck 
999c2c66affSColin Finck 
1000c2c66affSColin Finck static INT
1001c2c66affSColin Finck TOOLTIPS_CheckTool (const TOOLTIPS_INFO *infoPtr, BOOL bShowTest)
1002c2c66affSColin Finck {
1003c2c66affSColin Finck     POINT pt;
1004c2c66affSColin Finck     HWND hwndTool;
1005c2c66affSColin Finck     INT nTool;
1006c2c66affSColin Finck 
1007c2c66affSColin Finck     GetCursorPos (&pt);
1008c2c66affSColin Finck     hwndTool = (HWND)SendMessageW (infoPtr->hwndSelf, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt);
1009c2c66affSColin Finck     if (hwndTool == 0)
1010c2c66affSColin Finck 	return -1;
1011c2c66affSColin Finck 
1012c2c66affSColin Finck     ScreenToClient (hwndTool, &pt);
1013c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt);
1014c2c66affSColin Finck     if (nTool == -1)
1015c2c66affSColin Finck 	return -1;
1016c2c66affSColin Finck 
1017c2c66affSColin Finck     if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest)
1018c2c66affSColin Finck     {
1019c2c66affSColin Finck         TTTOOL_INFO *ti = &infoPtr->tools[nTool];
1020c2c66affSColin Finck         HWND hwnd = (ti->uFlags & TTF_IDISHWND) ? (HWND)ti->uId : ti->hwnd;
1021c2c66affSColin Finck 
1022c2c66affSColin Finck         if (!TOOLTIPS_IsWindowActive(hwnd))
1023c2c66affSColin Finck         {
1024c2c66affSColin Finck             TRACE("not active: hwnd %p, parent %p, active %p\n",
1025c2c66affSColin Finck                   hwnd, GetParent(hwnd), GetActiveWindow());
1026c2c66affSColin Finck             return -1;
1027c2c66affSColin Finck         }
1028c2c66affSColin Finck     }
1029c2c66affSColin Finck 
1030c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1031c2c66affSColin Finck 
1032c2c66affSColin Finck     return nTool;
1033c2c66affSColin Finck }
1034c2c66affSColin Finck 
1035c2c66affSColin Finck 
1036c2c66affSColin Finck static LRESULT
1037c2c66affSColin Finck TOOLTIPS_Activate (TOOLTIPS_INFO *infoPtr, BOOL activate)
1038c2c66affSColin Finck {
1039c2c66affSColin Finck     infoPtr->bActive = activate;
1040c2c66affSColin Finck 
1041edd99e8cSAmine Khaldi     TRACE("activate %d\n", activate);
1042c2c66affSColin Finck 
1043c2c66affSColin Finck     if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1))
1044c2c66affSColin Finck 	TOOLTIPS_Hide (infoPtr);
1045c2c66affSColin Finck 
1046c2c66affSColin Finck     return 0;
1047c2c66affSColin Finck }
1048c2c66affSColin Finck 
1049c2c66affSColin Finck 
1050c2c66affSColin Finck static LRESULT
1051c2c66affSColin Finck TOOLTIPS_AddToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1052c2c66affSColin Finck {
1053c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
1054c2c66affSColin Finck     INT nResult;
1055c2c66affSColin Finck 
1056c2c66affSColin Finck     if (!ti) return FALSE;
1057c2c66affSColin Finck 
1058edd99e8cSAmine Khaldi     TRACE("add tool (%p) %p %ld%s\n", infoPtr->hwndSelf, ti->hwnd, ti->uId,
1059c2c66affSColin Finck         (ti->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : "");
1060c2c66affSColin Finck 
1061*b3fb8555SGiannis Adamopoulos     if (ti->cbSize > TTTOOLINFOW_V3_SIZE && isW)
1062c2c66affSColin Finck         return FALSE;
1063c2c66affSColin Finck 
1064c2c66affSColin Finck     if (infoPtr->uNumTools == 0) {
1065c2c66affSColin Finck 	infoPtr->tools = Alloc (sizeof(TTTOOL_INFO));
1066c2c66affSColin Finck 	toolPtr = infoPtr->tools;
1067c2c66affSColin Finck     }
1068c2c66affSColin Finck     else {
1069c2c66affSColin Finck 	TTTOOL_INFO *oldTools = infoPtr->tools;
1070c2c66affSColin Finck 	infoPtr->tools =
1071c2c66affSColin Finck 	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1));
1072c2c66affSColin Finck 	memcpy (infoPtr->tools, oldTools,
1073c2c66affSColin Finck 		infoPtr->uNumTools * sizeof(TTTOOL_INFO));
1074c2c66affSColin Finck 	Free (oldTools);
1075c2c66affSColin Finck 	toolPtr = &infoPtr->tools[infoPtr->uNumTools];
1076c2c66affSColin Finck     }
1077c2c66affSColin Finck 
1078c2c66affSColin Finck     infoPtr->uNumTools++;
1079c2c66affSColin Finck 
1080c2c66affSColin Finck     /* copy tool data */
1081c2c66affSColin Finck     toolPtr->uFlags         = ti->uFlags;
1082c2c66affSColin Finck     toolPtr->uInternalFlags = (ti->uFlags & (TTF_SUBCLASS | TTF_IDISHWND));
1083c2c66affSColin Finck     toolPtr->hwnd           = ti->hwnd;
1084c2c66affSColin Finck     toolPtr->uId            = ti->uId;
1085c2c66affSColin Finck     toolPtr->rect           = ti->rect;
1086c2c66affSColin Finck     toolPtr->hinst          = ti->hinst;
1087c2c66affSColin Finck 
1088c2c66affSColin Finck     if (ti->cbSize >= TTTOOLINFOW_V1_SIZE) {
1089c2c66affSColin Finck         if (IS_INTRESOURCE(ti->lpszText)) {
1090c2c66affSColin Finck             TRACE("add string id %x\n", LOWORD(ti->lpszText));
1091c2c66affSColin Finck             toolPtr->lpszText = ti->lpszText;
1092c2c66affSColin Finck         }
1093c2c66affSColin Finck         else if (ti->lpszText) {
1094c2c66affSColin Finck             if (TOOLTIPS_IsCallbackString(ti->lpszText, isW)) {
1095edd99e8cSAmine Khaldi                 TRACE("add CALLBACK\n");
1096c2c66affSColin Finck                 toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1097c2c66affSColin Finck             }
1098c2c66affSColin Finck             else if (isW) {
1099c2c66affSColin Finck                 INT len = lstrlenW (ti->lpszText);
1100edd99e8cSAmine Khaldi                 TRACE("add text %s\n", debugstr_w(ti->lpszText));
1101c2c66affSColin Finck                 toolPtr->lpszText =	Alloc ((len + 1)*sizeof(WCHAR));
1102c2c66affSColin Finck                 strcpyW (toolPtr->lpszText, ti->lpszText);
1103c2c66affSColin Finck             }
1104c2c66affSColin Finck             else {
1105c2c66affSColin Finck                 INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, NULL, 0);
1106edd99e8cSAmine Khaldi                 TRACE("add text \"%s\"\n", debugstr_a((char *)ti->lpszText));
1107c2c66affSColin Finck                 toolPtr->lpszText =	Alloc (len * sizeof(WCHAR));
1108c2c66affSColin Finck                 MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1, toolPtr->lpszText, len);
1109c2c66affSColin Finck             }
1110c2c66affSColin Finck         }
1111c2c66affSColin Finck     }
1112c2c66affSColin Finck 
1113c2c66affSColin Finck     if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
1114c2c66affSColin Finck 	toolPtr->lParam = ti->lParam;
1115c2c66affSColin Finck 
1116c2c66affSColin Finck     /* install subclassing hook */
1117c2c66affSColin Finck     if (toolPtr->uInternalFlags & TTF_SUBCLASS) {
1118c2c66affSColin Finck 	if (toolPtr->uInternalFlags & TTF_IDISHWND) {
1119c2c66affSColin Finck 	    SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1,
1120c2c66affSColin Finck 			      (DWORD_PTR)infoPtr->hwndSelf);
1121c2c66affSColin Finck 	}
1122c2c66affSColin Finck 	else {
1123c2c66affSColin Finck 	    SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1,
1124c2c66affSColin Finck 			      (DWORD_PTR)infoPtr->hwndSelf);
1125c2c66affSColin Finck 	}
1126edd99e8cSAmine Khaldi 	TRACE("subclassing installed\n");
1127c2c66affSColin Finck     }
1128c2c66affSColin Finck 
1129c2c66affSColin Finck     nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
1130c2c66affSColin Finck                             (WPARAM)infoPtr->hwndSelf, NF_QUERY);
1131c2c66affSColin Finck     if (nResult == NFR_ANSI) {
1132c2c66affSColin Finck         toolPtr->bNotifyUnicode = FALSE;
1133c2c66affSColin Finck 	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
1134c2c66affSColin Finck     } else if (nResult == NFR_UNICODE) {
1135c2c66affSColin Finck         toolPtr->bNotifyUnicode = TRUE;
1136c2c66affSColin Finck 	TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
1137c2c66affSColin Finck     } else {
1138edd99e8cSAmine Khaldi         TRACE (" -- WM_NOTIFYFORMAT returns: %d\n", nResult);
1139c2c66affSColin Finck     }
1140c2c66affSColin Finck 
1141c2c66affSColin Finck     return TRUE;
1142c2c66affSColin Finck }
1143c2c66affSColin Finck 
1144edd99e8cSAmine Khaldi static void TOOLTIPS_ResetSubclass (const TTTOOL_INFO *toolPtr)
1145edd99e8cSAmine Khaldi {
1146edd99e8cSAmine Khaldi     /* Reset subclassing data. */
1147edd99e8cSAmine Khaldi     if (toolPtr->uInternalFlags & TTF_SUBCLASS)
1148edd99e8cSAmine Khaldi         SetWindowSubclass(toolPtr->uInternalFlags & TTF_IDISHWND ? (HWND)toolPtr->uId : toolPtr->hwnd,
1149edd99e8cSAmine Khaldi             TOOLTIPS_SubclassProc, 1, 0);
1150edd99e8cSAmine Khaldi }
1151c2c66affSColin Finck 
1152c2c66affSColin Finck static LRESULT
1153c2c66affSColin Finck TOOLTIPS_DelToolT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1154c2c66affSColin Finck {
1155c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
1156c2c66affSColin Finck     INT nTool;
1157c2c66affSColin Finck 
1158c2c66affSColin Finck     if (!ti) return 0;
1159c2c66affSColin Finck     if (isW && ti->cbSize > TTTOOLINFOW_V2_SIZE &&
1160c2c66affSColin Finck                ti->cbSize != TTTOOLINFOW_V3_SIZE)
1161c2c66affSColin Finck 	return 0;
1162c2c66affSColin Finck     if (infoPtr->uNumTools == 0)
1163c2c66affSColin Finck 	return 0;
1164c2c66affSColin Finck 
1165c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1166c2c66affSColin Finck 
1167c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1168c2c66affSColin Finck 
1169c2c66affSColin Finck     if (nTool == -1)
1170c2c66affSColin Finck         return 0;
1171c2c66affSColin Finck 
1172c2c66affSColin Finck     /* make sure the tooltip has disappeared before deleting it */
1173c2c66affSColin Finck     TOOLTIPS_Hide(infoPtr);
1174c2c66affSColin Finck 
1175c2c66affSColin Finck     /* delete text string */
1176c2c66affSColin Finck     toolPtr = &infoPtr->tools[nTool];
1177c2c66affSColin Finck     if (toolPtr->lpszText) {
1178c2c66affSColin Finck 	if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
1179c2c66affSColin Finck 	     !IS_INTRESOURCE(toolPtr->lpszText) )
1180c2c66affSColin Finck 	    Free (toolPtr->lpszText);
1181c2c66affSColin Finck     }
1182c2c66affSColin Finck 
1183edd99e8cSAmine Khaldi     TOOLTIPS_ResetSubclass (toolPtr);
1184c2c66affSColin Finck 
1185c2c66affSColin Finck     /* delete tool from tool list */
1186c2c66affSColin Finck     if (infoPtr->uNumTools == 1) {
1187c2c66affSColin Finck 	Free (infoPtr->tools);
1188c2c66affSColin Finck 	infoPtr->tools = NULL;
1189c2c66affSColin Finck     }
1190c2c66affSColin Finck     else {
1191c2c66affSColin Finck 	TTTOOL_INFO *oldTools = infoPtr->tools;
1192c2c66affSColin Finck 	infoPtr->tools =
1193c2c66affSColin Finck 	    Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1));
1194c2c66affSColin Finck 
1195c2c66affSColin Finck 	if (nTool > 0)
1196c2c66affSColin Finck 	    memcpy (&infoPtr->tools[0], &oldTools[0],
1197c2c66affSColin Finck 		    nTool * sizeof(TTTOOL_INFO));
1198c2c66affSColin Finck 
1199c2c66affSColin Finck 	if (nTool < infoPtr->uNumTools - 1)
1200c2c66affSColin Finck 	    memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1],
1201c2c66affSColin Finck 		    (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO));
1202c2c66affSColin Finck 
1203c2c66affSColin Finck 	Free (oldTools);
1204c2c66affSColin Finck     }
1205c2c66affSColin Finck 
1206c2c66affSColin Finck     /* update any indices affected by delete */
1207c2c66affSColin Finck 
1208c2c66affSColin Finck     /* destroying tool that mouse was on on last relayed mouse move */
1209c2c66affSColin Finck     if (infoPtr->nTool == nTool)
1210c2c66affSColin Finck         /* -1 means no current tool (0 means first tool) */
1211c2c66affSColin Finck         infoPtr->nTool = -1;
1212c2c66affSColin Finck     else if (infoPtr->nTool > nTool)
1213c2c66affSColin Finck         infoPtr->nTool--;
1214c2c66affSColin Finck 
1215c2c66affSColin Finck     if (infoPtr->nTrackTool == nTool)
1216c2c66affSColin Finck         /* -1 means no current tool (0 means first tool) */
1217c2c66affSColin Finck         infoPtr->nTrackTool = -1;
1218c2c66affSColin Finck     else if (infoPtr->nTrackTool > nTool)
1219c2c66affSColin Finck         infoPtr->nTrackTool--;
1220c2c66affSColin Finck 
1221c2c66affSColin Finck     if (infoPtr->nCurrentTool == nTool)
1222c2c66affSColin Finck         /* -1 means no current tool (0 means first tool) */
1223c2c66affSColin Finck         infoPtr->nCurrentTool = -1;
1224c2c66affSColin Finck     else if (infoPtr->nCurrentTool > nTool)
1225c2c66affSColin Finck         infoPtr->nCurrentTool--;
1226c2c66affSColin Finck 
1227c2c66affSColin Finck     infoPtr->uNumTools--;
1228c2c66affSColin Finck 
1229c2c66affSColin Finck     return 0;
1230c2c66affSColin Finck }
1231c2c66affSColin Finck 
1232c2c66affSColin Finck static LRESULT
1233c2c66affSColin Finck TOOLTIPS_EnumToolsT (const TOOLTIPS_INFO *infoPtr, UINT uIndex, TTTOOLINFOW *ti,
1234c2c66affSColin Finck                      BOOL isW)
1235c2c66affSColin Finck {
1236edd99e8cSAmine Khaldi     if (!ti || ti->cbSize < TTTOOLINFOW_V1_SIZE)
1237c2c66affSColin Finck 	return FALSE;
1238c2c66affSColin Finck     if (uIndex >= infoPtr->uNumTools)
1239c2c66affSColin Finck 	return FALSE;
1240c2c66affSColin Finck 
1241c2c66affSColin Finck     TRACE("index=%u\n", uIndex);
1242c2c66affSColin Finck 
1243edd99e8cSAmine Khaldi     TOOLTIPS_CopyInfoT (infoPtr, uIndex, ti, isW);
1244c2c66affSColin Finck 
1245c2c66affSColin Finck     return TRUE;
1246c2c66affSColin Finck }
1247c2c66affSColin Finck 
1248c2c66affSColin Finck static LRESULT
1249c2c66affSColin Finck TOOLTIPS_GetBubbleSize (const TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *lpToolInfo)
1250c2c66affSColin Finck {
1251c2c66affSColin Finck     INT nTool;
1252c2c66affSColin Finck     SIZE size;
1253c2c66affSColin Finck 
1254c2c66affSColin Finck     if (lpToolInfo == NULL)
1255c2c66affSColin Finck 	return FALSE;
1256c2c66affSColin Finck     if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE)
1257c2c66affSColin Finck 	return FALSE;
1258c2c66affSColin Finck 
1259c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, lpToolInfo);
1260c2c66affSColin Finck     if (nTool == -1) return 0;
1261c2c66affSColin Finck 
1262c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1263c2c66affSColin Finck 
1264c2c66affSColin Finck     TOOLTIPS_CalcTipSize (infoPtr, &size);
1265c2c66affSColin Finck     TRACE("size %d x %d\n", size.cx, size.cy);
1266c2c66affSColin Finck 
1267c2c66affSColin Finck     return MAKELRESULT(size.cx, size.cy);
1268c2c66affSColin Finck }
1269c2c66affSColin Finck 
1270c2c66affSColin Finck static LRESULT
1271c2c66affSColin Finck TOOLTIPS_GetCurrentToolT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1272c2c66affSColin Finck {
1273c2c66affSColin Finck     if (ti) {
1274c2c66affSColin Finck         if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1275c2c66affSColin Finck             return FALSE;
1276c2c66affSColin Finck 
1277edd99e8cSAmine Khaldi         if (infoPtr->nCurrentTool != -1)
1278edd99e8cSAmine Khaldi             TOOLTIPS_CopyInfoT (infoPtr, infoPtr->nCurrentTool, ti, isW);
1279c2c66affSColin Finck     }
1280edd99e8cSAmine Khaldi 
1281edd99e8cSAmine Khaldi     return infoPtr->nCurrentTool != -1;
1282c2c66affSColin Finck }
1283c2c66affSColin Finck 
1284c2c66affSColin Finck 
1285c2c66affSColin Finck static LRESULT
1286c2c66affSColin Finck TOOLTIPS_GetDelayTime (const TOOLTIPS_INFO *infoPtr, DWORD duration)
1287c2c66affSColin Finck {
1288c2c66affSColin Finck     switch (duration) {
1289c2c66affSColin Finck     case TTDT_RESHOW:
1290c2c66affSColin Finck         return infoPtr->nReshowTime;
1291c2c66affSColin Finck 
1292c2c66affSColin Finck     case TTDT_AUTOPOP:
1293c2c66affSColin Finck         return infoPtr->nAutoPopTime;
1294c2c66affSColin Finck 
1295c2c66affSColin Finck     case TTDT_INITIAL:
1296c2c66affSColin Finck     case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */
1297c2c66affSColin Finck         return infoPtr->nInitialTime;
1298c2c66affSColin Finck 
1299c2c66affSColin Finck     default:
1300c2c66affSColin Finck         WARN("Invalid duration flag %x\n", duration);
1301c2c66affSColin Finck 	break;
1302c2c66affSColin Finck     }
1303c2c66affSColin Finck 
1304c2c66affSColin Finck     return -1;
1305c2c66affSColin Finck }
1306c2c66affSColin Finck 
1307c2c66affSColin Finck 
1308c2c66affSColin Finck static LRESULT
1309c2c66affSColin Finck TOOLTIPS_GetMargin (const TOOLTIPS_INFO *infoPtr, RECT *rect)
1310c2c66affSColin Finck {
1311c2c66affSColin Finck     if (rect)
1312c2c66affSColin Finck         *rect = infoPtr->rcMargin;
1313c2c66affSColin Finck 
1314c2c66affSColin Finck     return 0;
1315c2c66affSColin Finck }
1316c2c66affSColin Finck 
1317c2c66affSColin Finck 
1318c2c66affSColin Finck static inline LRESULT
1319c2c66affSColin Finck TOOLTIPS_GetMaxTipWidth (const TOOLTIPS_INFO *infoPtr)
1320c2c66affSColin Finck {
1321c2c66affSColin Finck     return infoPtr->nMaxTipWidth;
1322c2c66affSColin Finck }
1323c2c66affSColin Finck 
1324c2c66affSColin Finck 
1325c2c66affSColin Finck static LRESULT
1326c2c66affSColin Finck TOOLTIPS_GetTextT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1327c2c66affSColin Finck {
1328c2c66affSColin Finck     INT nTool;
1329c2c66affSColin Finck 
1330c2c66affSColin Finck     if (!ti) return 0;
1331c2c66affSColin Finck     if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1332c2c66affSColin Finck 	return 0;
1333c2c66affSColin Finck 
1334c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1335c2c66affSColin Finck     if (nTool == -1) return 0;
1336c2c66affSColin Finck 
1337c2c66affSColin Finck     if (infoPtr->tools[nTool].lpszText == NULL)
1338c2c66affSColin Finck 	return 0;
1339c2c66affSColin Finck 
1340c2c66affSColin Finck     if (isW) {
1341c2c66affSColin Finck         ti->lpszText[0] = '\0';
1342c2c66affSColin Finck         TOOLTIPS_GetTipText(infoPtr, nTool, ti->lpszText);
1343c2c66affSColin Finck     }
1344c2c66affSColin Finck     else {
1345c2c66affSColin Finck         WCHAR buffer[INFOTIPSIZE];
1346c2c66affSColin Finck 
1347c2c66affSColin Finck         /* NB this API is broken, there is no way for the app to determine
1348c2c66affSColin Finck            what size buffer it requires nor a way to specify how long the
1349c2c66affSColin Finck            one it supplies is.  According to the test result, it's up to
1350c2c66affSColin Finck            80 bytes by the ANSI version. */
1351c2c66affSColin Finck 
1352c2c66affSColin Finck         buffer[0] = '\0';
1353c2c66affSColin Finck         TOOLTIPS_GetTipText(infoPtr, nTool, buffer);
1354c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, buffer, -1, (LPSTR)ti->lpszText,
1355c2c66affSColin Finck                                                    MAX_TEXT_SIZE_A, NULL, NULL);
1356c2c66affSColin Finck     }
1357c2c66affSColin Finck 
1358c2c66affSColin Finck     return 0;
1359c2c66affSColin Finck }
1360c2c66affSColin Finck 
1361c2c66affSColin Finck 
1362c2c66affSColin Finck static inline LRESULT
1363c2c66affSColin Finck TOOLTIPS_GetTipBkColor (const TOOLTIPS_INFO *infoPtr)
1364c2c66affSColin Finck {
1365c2c66affSColin Finck     return infoPtr->clrBk;
1366c2c66affSColin Finck }
1367c2c66affSColin Finck 
1368c2c66affSColin Finck 
1369c2c66affSColin Finck static inline LRESULT
1370c2c66affSColin Finck TOOLTIPS_GetTipTextColor (const TOOLTIPS_INFO *infoPtr)
1371c2c66affSColin Finck {
1372c2c66affSColin Finck     return infoPtr->clrText;
1373c2c66affSColin Finck }
1374c2c66affSColin Finck 
1375c2c66affSColin Finck 
1376c2c66affSColin Finck static inline LRESULT
1377c2c66affSColin Finck TOOLTIPS_GetToolCount (const TOOLTIPS_INFO *infoPtr)
1378c2c66affSColin Finck {
1379c2c66affSColin Finck     return infoPtr->uNumTools;
1380c2c66affSColin Finck }
1381c2c66affSColin Finck 
1382c2c66affSColin Finck 
1383c2c66affSColin Finck static LRESULT
1384c2c66affSColin Finck TOOLTIPS_GetToolInfoT (const TOOLTIPS_INFO *infoPtr, TTTOOLINFOW *ti, BOOL isW)
1385c2c66affSColin Finck {
1386c2c66affSColin Finck     INT nTool;
1387edd99e8cSAmine Khaldi     HWND hwnd;
1388c2c66affSColin Finck 
1389c2c66affSColin Finck     if (!ti) return FALSE;
1390c2c66affSColin Finck     if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1391c2c66affSColin Finck 	return FALSE;
1392c2c66affSColin Finck     if (infoPtr->uNumTools == 0)
1393c2c66affSColin Finck 	return FALSE;
1394c2c66affSColin Finck 
1395c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1396c2c66affSColin Finck     if (nTool == -1)
1397c2c66affSColin Finck 	return FALSE;
1398c2c66affSColin Finck 
1399c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1400c2c66affSColin Finck 
1401edd99e8cSAmine Khaldi     hwnd = ti->hwnd;
1402edd99e8cSAmine Khaldi     TOOLTIPS_CopyInfoT (infoPtr, nTool, ti, isW);
1403edd99e8cSAmine Khaldi     ti->hwnd = hwnd;
1404c2c66affSColin Finck 
1405c2c66affSColin Finck     return TRUE;
1406c2c66affSColin Finck }
1407c2c66affSColin Finck 
1408c2c66affSColin Finck 
1409c2c66affSColin Finck static LRESULT
1410c2c66affSColin Finck TOOLTIPS_HitTestT (const TOOLTIPS_INFO *infoPtr, LPTTHITTESTINFOW lptthit,
1411c2c66affSColin Finck                    BOOL isW)
1412c2c66affSColin Finck {
1413c2c66affSColin Finck     INT nTool;
1414c2c66affSColin Finck 
1415c2c66affSColin Finck     if (lptthit == 0)
1416c2c66affSColin Finck 	return FALSE;
1417c2c66affSColin Finck 
1418c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt);
1419c2c66affSColin Finck     if (nTool == -1)
1420c2c66affSColin Finck 	return FALSE;
1421c2c66affSColin Finck 
1422edd99e8cSAmine Khaldi     TRACE("tool %d\n", nTool);
1423c2c66affSColin Finck 
1424c2c66affSColin Finck     /* copy tool data */
1425edd99e8cSAmine Khaldi     if (lptthit->ti.cbSize >= TTTOOLINFOW_V1_SIZE)
1426edd99e8cSAmine Khaldi         TOOLTIPS_CopyInfoT (infoPtr, nTool, &lptthit->ti, isW);
1427c2c66affSColin Finck 
1428c2c66affSColin Finck     return TRUE;
1429c2c66affSColin Finck }
1430c2c66affSColin Finck 
1431c2c66affSColin Finck 
1432c2c66affSColin Finck static LRESULT
1433c2c66affSColin Finck TOOLTIPS_NewToolRectT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti)
1434c2c66affSColin Finck {
1435c2c66affSColin Finck     INT nTool;
1436c2c66affSColin Finck 
1437c2c66affSColin Finck     if (!ti) return 0;
1438c2c66affSColin Finck     if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1439c2c66affSColin Finck 	return FALSE;
1440c2c66affSColin Finck 
1441c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1442c2c66affSColin Finck 
1443c2c66affSColin Finck     TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&ti->rect));
1444c2c66affSColin Finck 
1445c2c66affSColin Finck     if (nTool == -1) return 0;
1446c2c66affSColin Finck 
1447c2c66affSColin Finck     infoPtr->tools[nTool].rect = ti->rect;
1448c2c66affSColin Finck 
1449c2c66affSColin Finck     return 0;
1450c2c66affSColin Finck }
1451c2c66affSColin Finck 
1452c2c66affSColin Finck 
1453c2c66affSColin Finck static inline LRESULT
1454c2c66affSColin Finck TOOLTIPS_Pop (TOOLTIPS_INFO *infoPtr)
1455c2c66affSColin Finck {
1456c2c66affSColin Finck     TOOLTIPS_Hide (infoPtr);
1457c2c66affSColin Finck 
1458c2c66affSColin Finck     return 0;
1459c2c66affSColin Finck }
1460c2c66affSColin Finck 
1461c2c66affSColin Finck 
1462c2c66affSColin Finck static LRESULT
1463c2c66affSColin Finck TOOLTIPS_RelayEvent (TOOLTIPS_INFO *infoPtr, LPMSG lpMsg)
1464c2c66affSColin Finck {
1465c2c66affSColin Finck     POINT pt;
1466c2c66affSColin Finck     INT nOldTool;
1467c2c66affSColin Finck 
1468c2c66affSColin Finck     if (!lpMsg) {
1469edd99e8cSAmine Khaldi 	ERR("lpMsg == NULL\n");
1470c2c66affSColin Finck 	return 0;
1471c2c66affSColin Finck     }
1472c2c66affSColin Finck 
1473c2c66affSColin Finck     switch (lpMsg->message) {
1474c2c66affSColin Finck 	case WM_LBUTTONDOWN:
1475c2c66affSColin Finck 	case WM_LBUTTONUP:
1476c2c66affSColin Finck 	case WM_MBUTTONDOWN:
1477c2c66affSColin Finck 	case WM_MBUTTONUP:
1478c2c66affSColin Finck 	case WM_RBUTTONDOWN:
1479c2c66affSColin Finck 	case WM_RBUTTONUP:
1480c2c66affSColin Finck 	    TOOLTIPS_Hide (infoPtr);
1481c2c66affSColin Finck 	    break;
1482c2c66affSColin Finck 
1483c2c66affSColin Finck 	case WM_MOUSEMOVE:
1484c2c66affSColin Finck 	    pt.x = (short)LOWORD(lpMsg->lParam);
1485c2c66affSColin Finck 	    pt.y = (short)HIWORD(lpMsg->lParam);
1486c2c66affSColin Finck 	    nOldTool = infoPtr->nTool;
1487c2c66affSColin Finck 	    infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd,
1488c2c66affSColin Finck 						       &pt);
1489c2c66affSColin Finck 	    TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool,
1490c2c66affSColin Finck 		  infoPtr->nTool, infoPtr->nCurrentTool);
1491c2c66affSColin Finck             TRACE("WM_MOUSEMOVE (%p %s)\n", infoPtr->hwndSelf, wine_dbgstr_point(&pt));
1492c2c66affSColin Finck 
1493c2c66affSColin Finck 	    if (infoPtr->nTool != nOldTool) {
1494c2c66affSColin Finck 	        if(infoPtr->nTool == -1) { /* Moved out of all tools */
1495c2c66affSColin Finck 		    TOOLTIPS_Hide(infoPtr);
1496c2c66affSColin Finck 		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1497c2c66affSColin Finck 		} else if (nOldTool == -1) { /* Moved from outside */
1498c2c66affSColin Finck 		    if(infoPtr->bActive) {
1499c2c66affSColin Finck 		        SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1500edd99e8cSAmine Khaldi                         TRACE("timer 1 started\n");
1501c2c66affSColin Finck 		    }
1502c2c66affSColin Finck 		} else { /* Moved from one to another */
1503c2c66affSColin Finck 		    TOOLTIPS_Hide (infoPtr);
1504c2c66affSColin Finck 		    KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
1505c2c66affSColin Finck 		    if(infoPtr->bActive) {
1506c2c66affSColin Finck 		        SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
1507edd99e8cSAmine Khaldi                         TRACE("timer 1 started\n");
1508c2c66affSColin Finck 		    }
1509c2c66affSColin Finck 		}
1510c2c66affSColin Finck 	    } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */
1511c2c66affSColin Finck 	        KillTimer(infoPtr->hwndSelf, ID_TIMERPOP);
1512c2c66affSColin Finck 		SetTimer(infoPtr->hwndSelf, ID_TIMERPOP, infoPtr->nAutoPopTime, 0);
1513c2c66affSColin Finck 		TRACE("timer 2 restarted\n");
1514c2c66affSColin Finck 	    } else if(infoPtr->nTool != -1 && infoPtr->bActive) {
1515c2c66affSColin Finck                 /* previous show attempt didn't result in tooltip so try again */
1516c2c66affSColin Finck 		SetTimer(infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nInitialTime, 0);
1517edd99e8cSAmine Khaldi                 TRACE("timer 1 started\n");
1518c2c66affSColin Finck 	    }
1519c2c66affSColin Finck 	    break;
1520c2c66affSColin Finck     }
1521c2c66affSColin Finck 
1522c2c66affSColin Finck     return 0;
1523c2c66affSColin Finck }
1524c2c66affSColin Finck 
1525c2c66affSColin Finck 
1526c2c66affSColin Finck static LRESULT
1527c2c66affSColin Finck TOOLTIPS_SetDelayTime (TOOLTIPS_INFO *infoPtr, DWORD duration, INT nTime)
1528c2c66affSColin Finck {
1529c2c66affSColin Finck     switch (duration) {
1530c2c66affSColin Finck     case TTDT_AUTOMATIC:
1531c2c66affSColin Finck         if (nTime <= 0)
1532c2c66affSColin Finck 	    nTime = GetDoubleClickTime();
1533c2c66affSColin Finck 	infoPtr->nReshowTime    = nTime / 5;
1534c2c66affSColin Finck 	infoPtr->nAutoPopTime   = nTime * 10;
1535c2c66affSColin Finck 	infoPtr->nInitialTime   = nTime;
1536c2c66affSColin Finck 	break;
1537c2c66affSColin Finck 
1538c2c66affSColin Finck     case TTDT_RESHOW:
1539c2c66affSColin Finck         if(nTime < 0)
1540c2c66affSColin Finck 	    nTime = GetDoubleClickTime() / 5;
1541c2c66affSColin Finck 	infoPtr->nReshowTime = nTime;
1542c2c66affSColin Finck 	break;
1543c2c66affSColin Finck 
1544c2c66affSColin Finck     case TTDT_AUTOPOP:
1545c2c66affSColin Finck         if(nTime < 0)
1546c2c66affSColin Finck 	    nTime = GetDoubleClickTime() * 10;
1547c2c66affSColin Finck 	infoPtr->nAutoPopTime = nTime;
1548c2c66affSColin Finck 	break;
1549c2c66affSColin Finck 
1550c2c66affSColin Finck     case TTDT_INITIAL:
1551c2c66affSColin Finck         if(nTime < 0)
1552c2c66affSColin Finck 	    nTime = GetDoubleClickTime();
1553c2c66affSColin Finck 	infoPtr->nInitialTime = nTime;
1554c2c66affSColin Finck 	    break;
1555c2c66affSColin Finck 
1556c2c66affSColin Finck     default:
1557c2c66affSColin Finck         WARN("Invalid duration flag %x\n", duration);
1558c2c66affSColin Finck 	break;
1559c2c66affSColin Finck     }
1560c2c66affSColin Finck 
1561c2c66affSColin Finck     return 0;
1562c2c66affSColin Finck }
1563c2c66affSColin Finck 
1564c2c66affSColin Finck 
1565c2c66affSColin Finck static LRESULT
1566c2c66affSColin Finck TOOLTIPS_SetMargin (TOOLTIPS_INFO *infoPtr, const RECT *rect)
1567c2c66affSColin Finck {
1568c2c66affSColin Finck     if (rect)
1569c2c66affSColin Finck         infoPtr->rcMargin = *rect;
1570c2c66affSColin Finck 
1571c2c66affSColin Finck     return 0;
1572c2c66affSColin Finck }
1573c2c66affSColin Finck 
1574c2c66affSColin Finck 
1575c2c66affSColin Finck static inline LRESULT
1576c2c66affSColin Finck TOOLTIPS_SetMaxTipWidth (TOOLTIPS_INFO *infoPtr, INT MaxWidth)
1577c2c66affSColin Finck {
1578c2c66affSColin Finck     INT nTemp = infoPtr->nMaxTipWidth;
1579c2c66affSColin Finck 
1580c2c66affSColin Finck     infoPtr->nMaxTipWidth = MaxWidth;
1581c2c66affSColin Finck 
1582c2c66affSColin Finck     return nTemp;
1583c2c66affSColin Finck }
1584c2c66affSColin Finck 
1585c2c66affSColin Finck 
1586c2c66affSColin Finck static inline LRESULT
1587c2c66affSColin Finck TOOLTIPS_SetTipBkColor (TOOLTIPS_INFO *infoPtr, COLORREF clrBk)
1588c2c66affSColin Finck {
1589c2c66affSColin Finck     infoPtr->clrBk = clrBk;
1590c2c66affSColin Finck 
1591c2c66affSColin Finck     return 0;
1592c2c66affSColin Finck }
1593c2c66affSColin Finck 
1594c2c66affSColin Finck 
1595c2c66affSColin Finck static inline LRESULT
1596c2c66affSColin Finck TOOLTIPS_SetTipTextColor (TOOLTIPS_INFO *infoPtr, COLORREF clrText)
1597c2c66affSColin Finck {
1598c2c66affSColin Finck     infoPtr->clrText = clrText;
1599c2c66affSColin Finck 
1600c2c66affSColin Finck     return 0;
1601c2c66affSColin Finck }
1602c2c66affSColin Finck 
1603c2c66affSColin Finck 
1604c2c66affSColin Finck static LRESULT
1605c2c66affSColin Finck TOOLTIPS_SetTitleT (TOOLTIPS_INFO *infoPtr, UINT_PTR uTitleIcon, LPCWSTR pszTitle,
1606c2c66affSColin Finck                     BOOL isW)
1607c2c66affSColin Finck {
1608c2c66affSColin Finck     UINT size;
1609c2c66affSColin Finck 
1610c2c66affSColin Finck     TRACE("hwnd = %p, title = %s, icon = %p\n", infoPtr->hwndSelf, debugstr_w(pszTitle),
1611c2c66affSColin Finck         (void*)uTitleIcon);
1612c2c66affSColin Finck 
1613c2c66affSColin Finck     Free(infoPtr->pszTitle);
1614c2c66affSColin Finck 
1615c2c66affSColin Finck     if (pszTitle)
1616c2c66affSColin Finck     {
1617c2c66affSColin Finck         if (isW)
1618c2c66affSColin Finck         {
1619c2c66affSColin Finck             size = (strlenW(pszTitle)+1)*sizeof(WCHAR);
1620c2c66affSColin Finck             infoPtr->pszTitle = Alloc(size);
1621c2c66affSColin Finck             if (!infoPtr->pszTitle)
1622c2c66affSColin Finck                 return FALSE;
1623c2c66affSColin Finck             memcpy(infoPtr->pszTitle, pszTitle, size);
1624c2c66affSColin Finck         }
1625c2c66affSColin Finck         else
1626c2c66affSColin Finck         {
1627c2c66affSColin Finck             size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, NULL, 0);
1628c2c66affSColin Finck             infoPtr->pszTitle = Alloc(size);
1629c2c66affSColin Finck             if (!infoPtr->pszTitle)
1630c2c66affSColin Finck                 return FALSE;
1631c2c66affSColin Finck             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR));
1632c2c66affSColin Finck         }
1633c2c66affSColin Finck     }
1634c2c66affSColin Finck     else
1635c2c66affSColin Finck         infoPtr->pszTitle = NULL;
1636c2c66affSColin Finck 
1637c2c66affSColin Finck     if (uTitleIcon <= TTI_ERROR)
1638c2c66affSColin Finck         infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon];
1639c2c66affSColin Finck     else
1640c2c66affSColin Finck         infoPtr->hTitleIcon = CopyIcon((HICON)uTitleIcon);
1641c2c66affSColin Finck 
1642c2c66affSColin Finck     TRACE("icon = %p\n", infoPtr->hTitleIcon);
1643c2c66affSColin Finck 
1644c2c66affSColin Finck     return TRUE;
1645c2c66affSColin Finck }
1646c2c66affSColin Finck 
1647c2c66affSColin Finck 
1648c2c66affSColin Finck static LRESULT
1649c2c66affSColin Finck TOOLTIPS_SetToolInfoT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1650c2c66affSColin Finck {
1651c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
1652c2c66affSColin Finck     INT nTool;
1653c2c66affSColin Finck 
1654c2c66affSColin Finck     if (!ti) return 0;
1655c2c66affSColin Finck     if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1656c2c66affSColin Finck 	return 0;
1657c2c66affSColin Finck 
1658c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1659c2c66affSColin Finck     if (nTool == -1) return 0;
1660c2c66affSColin Finck 
1661c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1662c2c66affSColin Finck 
1663c2c66affSColin Finck     toolPtr = &infoPtr->tools[nTool];
1664c2c66affSColin Finck 
1665c2c66affSColin Finck     /* copy tool data */
1666c2c66affSColin Finck     toolPtr->uFlags = ti->uFlags;
1667c2c66affSColin Finck     toolPtr->hwnd   = ti->hwnd;
1668c2c66affSColin Finck     toolPtr->uId    = ti->uId;
1669c2c66affSColin Finck     toolPtr->rect   = ti->rect;
1670c2c66affSColin Finck     toolPtr->hinst  = ti->hinst;
1671c2c66affSColin Finck 
1672c2c66affSColin Finck     if (IS_INTRESOURCE(ti->lpszText)) {
1673edd99e8cSAmine Khaldi 	TRACE("set string id %x\n", LOWORD(ti->lpszText));
1674c2c66affSColin Finck 	toolPtr->lpszText = ti->lpszText;
1675c2c66affSColin Finck     }
1676c2c66affSColin Finck     else {
1677c2c66affSColin Finck 	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1678c2c66affSColin Finck 	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1679c2c66affSColin Finck 	else {
1680c2c66affSColin Finck 	    if ( (toolPtr->lpszText) &&
1681c2c66affSColin Finck 		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1682c2c66affSColin Finck 		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
1683c2c66affSColin Finck                     Free (toolPtr->lpszText);
1684c2c66affSColin Finck 		toolPtr->lpszText = NULL;
1685c2c66affSColin Finck 	    }
1686c2c66affSColin Finck 	    if (ti->lpszText) {
1687c2c66affSColin Finck 		if (isW) {
1688c2c66affSColin Finck 		    INT len = lstrlenW (ti->lpszText);
1689c2c66affSColin Finck 		    toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
1690c2c66affSColin Finck 		    strcpyW (toolPtr->lpszText, ti->lpszText);
1691c2c66affSColin Finck 		}
1692c2c66affSColin Finck 		else {
1693c2c66affSColin Finck 		    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText,
1694c2c66affSColin Finck 					      -1, NULL, 0);
1695c2c66affSColin Finck 		    toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
1696c2c66affSColin Finck 		    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1,
1697c2c66affSColin Finck 					toolPtr->lpszText, len);
1698c2c66affSColin Finck 		}
1699c2c66affSColin Finck 	    }
1700c2c66affSColin Finck 	}
1701c2c66affSColin Finck     }
1702c2c66affSColin Finck 
1703c2c66affSColin Finck     if (ti->cbSize >= TTTOOLINFOW_V2_SIZE)
1704c2c66affSColin Finck 	toolPtr->lParam = ti->lParam;
1705c2c66affSColin Finck 
1706c2c66affSColin Finck     if (infoPtr->nCurrentTool == nTool)
1707c2c66affSColin Finck     {
1708c2c66affSColin Finck         TOOLTIPS_GetTipText (infoPtr, infoPtr->nCurrentTool, infoPtr->szTipText);
1709c2c66affSColin Finck 
1710c2c66affSColin Finck         if (infoPtr->szTipText[0] == 0)
1711c2c66affSColin Finck             TOOLTIPS_Hide(infoPtr);
1712c2c66affSColin Finck         else
1713c2c66affSColin Finck             TOOLTIPS_Show (infoPtr, FALSE);
1714c2c66affSColin Finck     }
1715c2c66affSColin Finck 
1716c2c66affSColin Finck     return 0;
1717c2c66affSColin Finck }
1718c2c66affSColin Finck 
1719c2c66affSColin Finck 
1720c2c66affSColin Finck static LRESULT
1721c2c66affSColin Finck TOOLTIPS_TrackActivate (TOOLTIPS_INFO *infoPtr, BOOL track_activate, const TTTOOLINFOA *ti)
1722c2c66affSColin Finck {
1723c2c66affSColin Finck     if (track_activate) {
1724c2c66affSColin Finck 
1725c2c66affSColin Finck 	if (!ti) return 0;
1726c2c66affSColin Finck 	if (ti->cbSize < TTTOOLINFOA_V1_SIZE)
1727c2c66affSColin Finck 	    return FALSE;
1728c2c66affSColin Finck 
1729c2c66affSColin Finck 	/* activate */
1730c2c66affSColin Finck 	infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoT (infoPtr, (const TTTOOLINFOW*)ti);
1731c2c66affSColin Finck 	if (infoPtr->nTrackTool != -1) {
1732edd99e8cSAmine Khaldi 	    TRACE("activated\n");
1733c2c66affSColin Finck 	    infoPtr->bTrackActive = TRUE;
1734c2c66affSColin Finck 	    TOOLTIPS_TrackShow (infoPtr);
1735c2c66affSColin Finck 	}
1736c2c66affSColin Finck     }
1737c2c66affSColin Finck     else {
1738c2c66affSColin Finck 	/* deactivate */
1739c2c66affSColin Finck 	TOOLTIPS_TrackHide (infoPtr);
1740c2c66affSColin Finck 
1741c2c66affSColin Finck 	infoPtr->bTrackActive = FALSE;
1742c2c66affSColin Finck 	infoPtr->nTrackTool = -1;
1743c2c66affSColin Finck 
1744edd99e8cSAmine Khaldi         TRACE("deactivated\n");
1745c2c66affSColin Finck     }
1746c2c66affSColin Finck 
1747c2c66affSColin Finck     return 0;
1748c2c66affSColin Finck }
1749c2c66affSColin Finck 
1750c2c66affSColin Finck 
1751c2c66affSColin Finck static LRESULT
1752c2c66affSColin Finck TOOLTIPS_TrackPosition (TOOLTIPS_INFO *infoPtr, LPARAM coord)
1753c2c66affSColin Finck {
1754c2c66affSColin Finck     infoPtr->xTrackPos = (INT)LOWORD(coord);
1755c2c66affSColin Finck     infoPtr->yTrackPos = (INT)HIWORD(coord);
1756c2c66affSColin Finck 
1757c2c66affSColin Finck     if (infoPtr->bTrackActive) {
1758c2c66affSColin Finck 	TRACE("[%d %d]\n",
1759c2c66affSColin Finck 	       infoPtr->xTrackPos, infoPtr->yTrackPos);
1760c2c66affSColin Finck 
1761c2c66affSColin Finck 	TOOLTIPS_TrackShow (infoPtr);
1762c2c66affSColin Finck     }
1763c2c66affSColin Finck 
1764c2c66affSColin Finck     return 0;
1765c2c66affSColin Finck }
1766c2c66affSColin Finck 
1767c2c66affSColin Finck 
1768c2c66affSColin Finck static LRESULT
1769c2c66affSColin Finck TOOLTIPS_Update (TOOLTIPS_INFO *infoPtr)
1770c2c66affSColin Finck {
1771c2c66affSColin Finck     if (infoPtr->nCurrentTool != -1)
1772c2c66affSColin Finck 	UpdateWindow (infoPtr->hwndSelf);
1773c2c66affSColin Finck 
1774c2c66affSColin Finck     return 0;
1775c2c66affSColin Finck }
1776c2c66affSColin Finck 
1777c2c66affSColin Finck 
1778c2c66affSColin Finck static LRESULT
1779c2c66affSColin Finck TOOLTIPS_UpdateTipTextT (TOOLTIPS_INFO *infoPtr, const TTTOOLINFOW *ti, BOOL isW)
1780c2c66affSColin Finck {
1781c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
1782c2c66affSColin Finck     INT nTool;
1783c2c66affSColin Finck 
1784c2c66affSColin Finck     if (!ti) return 0;
1785c2c66affSColin Finck     if (ti->cbSize < TTTOOLINFOW_V1_SIZE)
1786c2c66affSColin Finck 	return FALSE;
1787c2c66affSColin Finck 
1788c2c66affSColin Finck     nTool = TOOLTIPS_GetToolFromInfoT (infoPtr, ti);
1789c2c66affSColin Finck     if (nTool == -1)
1790c2c66affSColin Finck 	return 0;
1791c2c66affSColin Finck 
1792c2c66affSColin Finck     TRACE("tool %d\n", nTool);
1793c2c66affSColin Finck 
1794c2c66affSColin Finck     toolPtr = &infoPtr->tools[nTool];
1795c2c66affSColin Finck 
1796c2c66affSColin Finck     /* copy tool text */
1797c2c66affSColin Finck     toolPtr->hinst  = ti->hinst;
1798c2c66affSColin Finck 
1799c2c66affSColin Finck     if (IS_INTRESOURCE(ti->lpszText)){
1800c2c66affSColin Finck 	toolPtr->lpszText = ti->lpszText;
1801c2c66affSColin Finck     }
1802c2c66affSColin Finck     else if (ti->lpszText) {
1803c2c66affSColin Finck 	if (TOOLTIPS_IsCallbackString(ti->lpszText, isW))
1804c2c66affSColin Finck 	    toolPtr->lpszText = LPSTR_TEXTCALLBACKW;
1805c2c66affSColin Finck 	else {
1806c2c66affSColin Finck 	    if ( (toolPtr->lpszText)  &&
1807c2c66affSColin Finck 		 !IS_INTRESOURCE(toolPtr->lpszText) ) {
1808c2c66affSColin Finck 		if( toolPtr->lpszText != LPSTR_TEXTCALLBACKW)
1809c2c66affSColin Finck                     Free (toolPtr->lpszText);
1810c2c66affSColin Finck 		toolPtr->lpszText = NULL;
1811c2c66affSColin Finck 	    }
1812c2c66affSColin Finck 	    if (ti->lpszText) {
1813c2c66affSColin Finck 		if (isW) {
1814c2c66affSColin Finck 		    INT len = lstrlenW (ti->lpszText);
1815c2c66affSColin Finck 		    toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR));
1816c2c66affSColin Finck 		    strcpyW (toolPtr->lpszText, ti->lpszText);
1817c2c66affSColin Finck 		}
1818c2c66affSColin Finck 		else {
1819c2c66affSColin Finck 		    INT len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText,
1820c2c66affSColin Finck 						-1, NULL, 0);
1821c2c66affSColin Finck 		    toolPtr->lpszText = Alloc (len * sizeof(WCHAR));
1822c2c66affSColin Finck 		    MultiByteToWideChar(CP_ACP, 0, (LPSTR)ti->lpszText, -1,
1823c2c66affSColin Finck 					toolPtr->lpszText, len);
1824c2c66affSColin Finck 	        }
1825c2c66affSColin Finck 	    }
1826c2c66affSColin Finck 	}
1827c2c66affSColin Finck     }
1828c2c66affSColin Finck 
1829c2c66affSColin Finck     if(infoPtr->nCurrentTool == -1) return 0;
1830c2c66affSColin Finck     /* force repaint */
1831c2c66affSColin Finck     if (infoPtr->bActive)
1832c2c66affSColin Finck 	TOOLTIPS_Show (infoPtr, FALSE);
1833c2c66affSColin Finck     else if (infoPtr->bTrackActive)
1834c2c66affSColin Finck 	TOOLTIPS_Show (infoPtr, TRUE);
1835c2c66affSColin Finck 
1836c2c66affSColin Finck     return 0;
1837c2c66affSColin Finck }
1838c2c66affSColin Finck 
1839c2c66affSColin Finck 
1840c2c66affSColin Finck static LRESULT
1841c2c66affSColin Finck TOOLTIPS_Create (HWND hwnd)
1842c2c66affSColin Finck {
1843c2c66affSColin Finck     TOOLTIPS_INFO *infoPtr;
1844c2c66affSColin Finck 
1845c2c66affSColin Finck     /* allocate memory for info structure */
1846c2c66affSColin Finck     infoPtr = Alloc (sizeof(TOOLTIPS_INFO));
1847c2c66affSColin Finck     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
1848c2c66affSColin Finck 
1849c2c66affSColin Finck     /* initialize info structure */
1850c2c66affSColin Finck     infoPtr->bActive = TRUE;
1851c2c66affSColin Finck     infoPtr->bTrackActive = FALSE;
1852c2c66affSColin Finck 
1853c2c66affSColin Finck     infoPtr->nMaxTipWidth = -1;
1854c2c66affSColin Finck     infoPtr->nTool = -1;
1855c2c66affSColin Finck     infoPtr->nCurrentTool = -1;
1856c2c66affSColin Finck     infoPtr->nTrackTool = -1;
1857c2c66affSColin Finck     infoPtr->hwndSelf = hwnd;
1858c2c66affSColin Finck 
1859c2c66affSColin Finck     /* initialize colours and fonts */
1860c2c66affSColin Finck     TOOLTIPS_InitSystemSettings(infoPtr);
1861c2c66affSColin Finck 
1862c2c66affSColin Finck     TOOLTIPS_SetDelayTime(infoPtr, TTDT_AUTOMATIC, 0);
1863c2c66affSColin Finck 
1864c2c66affSColin Finck     SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE);
1865c2c66affSColin Finck 
1866c2c66affSColin Finck     return 0;
1867c2c66affSColin Finck }
1868c2c66affSColin Finck 
1869c2c66affSColin Finck 
1870c2c66affSColin Finck static LRESULT
1871c2c66affSColin Finck TOOLTIPS_Destroy (TOOLTIPS_INFO *infoPtr)
1872c2c66affSColin Finck {
1873c2c66affSColin Finck     TTTOOL_INFO *toolPtr;
1874c2c66affSColin Finck     UINT i;
1875c2c66affSColin Finck 
1876c2c66affSColin Finck     /* free tools */
1877c2c66affSColin Finck     if (infoPtr->tools) {
1878c2c66affSColin Finck 	for (i = 0; i < infoPtr->uNumTools; i++) {
1879c2c66affSColin Finck 	    toolPtr = &infoPtr->tools[i];
1880c2c66affSColin Finck 	    if (toolPtr->lpszText) {
1881c2c66affSColin Finck 		if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) &&
1882c2c66affSColin Finck 		     !IS_INTRESOURCE(toolPtr->lpszText) )
1883c2c66affSColin Finck 		{
1884c2c66affSColin Finck 		    Free (toolPtr->lpszText);
1885c2c66affSColin Finck 		    toolPtr->lpszText = NULL;
1886c2c66affSColin Finck 		}
1887c2c66affSColin Finck 	    }
1888c2c66affSColin Finck 
1889edd99e8cSAmine Khaldi             TOOLTIPS_ResetSubclass (toolPtr);
1890c2c66affSColin Finck         }
1891edd99e8cSAmine Khaldi 
1892c2c66affSColin Finck 	Free (infoPtr->tools);
1893c2c66affSColin Finck     }
1894c2c66affSColin Finck 
1895c2c66affSColin Finck     /* free title string */
1896c2c66affSColin Finck     Free (infoPtr->pszTitle);
1897c2c66affSColin Finck     /* free title icon if not a standard one */
1898c2c66affSColin Finck     if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR)
1899c2c66affSColin Finck         DeleteObject(infoPtr->hTitleIcon);
1900c2c66affSColin Finck 
1901c2c66affSColin Finck     /* delete fonts */
1902c2c66affSColin Finck     DeleteObject (infoPtr->hFont);
1903c2c66affSColin Finck     DeleteObject (infoPtr->hTitleFont);
1904c2c66affSColin Finck 
1905c2c66affSColin Finck     /* free tool tips info data */
1906c2c66affSColin Finck     SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0);
1907c2c66affSColin Finck     Free (infoPtr);
1908c2c66affSColin Finck 
1909c2c66affSColin Finck     return 0;
1910c2c66affSColin Finck }
1911c2c66affSColin Finck 
1912c2c66affSColin Finck 
1913c2c66affSColin Finck static inline LRESULT
1914c2c66affSColin Finck TOOLTIPS_GetFont (const TOOLTIPS_INFO *infoPtr)
1915c2c66affSColin Finck {
1916c2c66affSColin Finck     return (LRESULT)infoPtr->hFont;
1917c2c66affSColin Finck }
1918c2c66affSColin Finck 
1919c2c66affSColin Finck 
1920c2c66affSColin Finck static LRESULT
1921c2c66affSColin Finck TOOLTIPS_MouseMessage (TOOLTIPS_INFO *infoPtr)
1922c2c66affSColin Finck {
1923c2c66affSColin Finck     TOOLTIPS_Hide (infoPtr);
1924c2c66affSColin Finck 
1925c2c66affSColin Finck     return 0;
1926c2c66affSColin Finck }
1927c2c66affSColin Finck 
1928c2c66affSColin Finck 
1929c2c66affSColin Finck static LRESULT
1930c2c66affSColin Finck TOOLTIPS_NCCreate (HWND hwnd)
1931c2c66affSColin Finck {
1932c2c66affSColin Finck     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
1933c2c66affSColin Finck     DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
1934c2c66affSColin Finck 
1935c2c66affSColin Finck     dwStyle &= ~(WS_CHILD | /*WS_MAXIMIZE |*/ WS_BORDER | WS_DLGFRAME);
1936c2c66affSColin Finck     dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS);
1937c2c66affSColin Finck 
1938c2c66affSColin Finck     /* WS_BORDER only draws a border round the window rect, not the
1939c2c66affSColin Finck      * window region, therefore it is useless to us in balloon mode */
1940c2c66affSColin Finck     if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER;
1941c2c66affSColin Finck 
1942c2c66affSColin Finck     SetWindowLongW (hwnd, GWL_STYLE, dwStyle);
1943c2c66affSColin Finck 
1944c2c66affSColin Finck     dwExStyle |= WS_EX_TOOLWINDOW;
1945c2c66affSColin Finck     SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
1946c2c66affSColin Finck 
1947c2c66affSColin Finck     return TRUE;
1948c2c66affSColin Finck }
1949c2c66affSColin Finck 
1950c2c66affSColin Finck 
1951c2c66affSColin Finck static LRESULT
1952c2c66affSColin Finck TOOLTIPS_NCHitTest (const TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1953c2c66affSColin Finck {
1954c2c66affSColin Finck     INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool;
1955c2c66affSColin Finck 
1956c2c66affSColin Finck     TRACE(" nTool=%d\n", nTool);
1957c2c66affSColin Finck 
1958c2c66affSColin Finck     if ((nTool > -1) && (nTool < infoPtr->uNumTools)) {
1959c2c66affSColin Finck 	if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) {
1960edd99e8cSAmine Khaldi 	    TRACE("-- in transparent mode\n");
1961c2c66affSColin Finck 	    return HTTRANSPARENT;
1962c2c66affSColin Finck 	}
1963c2c66affSColin Finck     }
1964c2c66affSColin Finck 
1965c2c66affSColin Finck     return DefWindowProcW (infoPtr->hwndSelf, WM_NCHITTEST, wParam, lParam);
1966c2c66affSColin Finck }
1967c2c66affSColin Finck 
1968c2c66affSColin Finck 
1969c2c66affSColin Finck static LRESULT
1970c2c66affSColin Finck TOOLTIPS_NotifyFormat (TOOLTIPS_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
1971c2c66affSColin Finck {
1972c2c66affSColin Finck #ifdef __REACTOS__
1973c2c66affSColin Finck     TTTOOL_INFO *toolPtr = infoPtr->tools;
1974c2c66affSColin Finck     LRESULT nResult;
1975c2c66affSColin Finck 
1976c2c66affSColin Finck     TRACE("infoPtr=%p wParam=%lx lParam=%p\n", infoPtr, wParam, (PVOID)lParam);
1977c2c66affSColin Finck 
1978c2c66affSColin Finck     if (lParam == NF_QUERY) {
1979c2c66affSColin Finck         if (toolPtr->bNotifyUnicode) {
1980c2c66affSColin Finck             return NFR_UNICODE;
1981c2c66affSColin Finck         } else {
1982c2c66affSColin Finck             return NFR_ANSI;
1983c2c66affSColin Finck         }
1984c2c66affSColin Finck     }
1985c2c66affSColin Finck     else if (lParam == NF_REQUERY) {
1986c2c66affSColin Finck         nResult = SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT,
1987c2c66affSColin Finck                     (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
1988c2c66affSColin Finck         if (nResult == NFR_ANSI) {
1989c2c66affSColin Finck             toolPtr->bNotifyUnicode = FALSE;
1990c2c66affSColin Finck             TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n");
1991c2c66affSColin Finck         } else if (nResult == NFR_UNICODE) {
1992c2c66affSColin Finck             toolPtr->bNotifyUnicode = TRUE;
1993c2c66affSColin Finck             TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n");
1994c2c66affSColin Finck         } else {
1995c2c66affSColin Finck             TRACE (" -- WM_NOTIFYFORMAT returns: error!\n");
1996c2c66affSColin Finck         }
1997c2c66affSColin Finck         return nResult;
1998c2c66affSColin Finck     }
1999c2c66affSColin Finck #else
2000c2c66affSColin Finck     FIXME ("hwnd=%p wParam=%lx lParam=%lx\n", infoPtr->hwndSelf, wParam, lParam);
2001c2c66affSColin Finck #endif
2002c2c66affSColin Finck 
2003c2c66affSColin Finck     return 0;
2004c2c66affSColin Finck }
2005c2c66affSColin Finck 
2006c2c66affSColin Finck 
2007c2c66affSColin Finck static LRESULT
2008c2c66affSColin Finck TOOLTIPS_Paint (const TOOLTIPS_INFO *infoPtr, HDC hDC)
2009c2c66affSColin Finck {
2010c2c66affSColin Finck     HDC hdc;
2011c2c66affSColin Finck     PAINTSTRUCT ps;
2012c2c66affSColin Finck 
2013c2c66affSColin Finck     hdc = (hDC == NULL) ? BeginPaint (infoPtr->hwndSelf, &ps) : hDC;
2014c2c66affSColin Finck     TOOLTIPS_Refresh (infoPtr, hdc);
2015c2c66affSColin Finck     if (!hDC)
2016c2c66affSColin Finck 	EndPaint (infoPtr->hwndSelf, &ps);
2017c2c66affSColin Finck     return 0;
2018c2c66affSColin Finck }
2019c2c66affSColin Finck 
2020c2c66affSColin Finck 
2021c2c66affSColin Finck static LRESULT
2022c2c66affSColin Finck TOOLTIPS_SetFont (TOOLTIPS_INFO *infoPtr, HFONT hFont, BOOL redraw)
2023c2c66affSColin Finck {
2024c2c66affSColin Finck     LOGFONTW lf;
2025c2c66affSColin Finck 
2026c2c66affSColin Finck     if(!GetObjectW(hFont, sizeof(lf), &lf))
2027c2c66affSColin Finck         return 0;
2028c2c66affSColin Finck 
2029c2c66affSColin Finck     DeleteObject (infoPtr->hFont);
2030c2c66affSColin Finck     infoPtr->hFont = CreateFontIndirectW(&lf);
2031c2c66affSColin Finck 
2032c2c66affSColin Finck     DeleteObject (infoPtr->hTitleFont);
2033c2c66affSColin Finck     lf.lfWeight = FW_BOLD;
2034c2c66affSColin Finck     infoPtr->hTitleFont = CreateFontIndirectW(&lf);
2035c2c66affSColin Finck 
2036edd99e8cSAmine Khaldi     if (redraw && infoPtr->nCurrentTool != -1)
2037edd99e8cSAmine Khaldi         FIXME("full redraw needed\n");
2038c2c66affSColin Finck 
2039c2c66affSColin Finck     return 0;
2040c2c66affSColin Finck }
2041c2c66affSColin Finck 
2042c2c66affSColin Finck /******************************************************************
2043c2c66affSColin Finck  * TOOLTIPS_GetTextLength
2044c2c66affSColin Finck  *
2045c2c66affSColin Finck  * This function is called when the tooltip receive a
2046c2c66affSColin Finck  * WM_GETTEXTLENGTH message.
2047c2c66affSColin Finck  *
2048c2c66affSColin Finck  * returns the length, in characters, of the tip text
2049c2c66affSColin Finck  */
2050c2c66affSColin Finck static inline LRESULT
2051c2c66affSColin Finck TOOLTIPS_GetTextLength(const TOOLTIPS_INFO *infoPtr)
2052c2c66affSColin Finck {
2053c2c66affSColin Finck     return strlenW(infoPtr->szTipText);
2054c2c66affSColin Finck }
2055c2c66affSColin Finck 
2056c2c66affSColin Finck /******************************************************************
2057c2c66affSColin Finck  * TOOLTIPS_OnWMGetText
2058c2c66affSColin Finck  *
2059c2c66affSColin Finck  * This function is called when the tooltip receive a
2060c2c66affSColin Finck  * WM_GETTEXT message.
2061c2c66affSColin Finck  * wParam : specifies the maximum number of characters to be copied
2062c2c66affSColin Finck  * lParam : is the pointer to the buffer that will receive
2063c2c66affSColin Finck  *          the tip text
2064c2c66affSColin Finck  *
2065c2c66affSColin Finck  * returns the number of characters copied
2066c2c66affSColin Finck  */
2067c2c66affSColin Finck static LRESULT
2068c2c66affSColin Finck TOOLTIPS_OnWMGetText (const TOOLTIPS_INFO *infoPtr, WPARAM size, LPWSTR pszText)
2069c2c66affSColin Finck {
2070c2c66affSColin Finck     LRESULT res;
2071c2c66affSColin Finck 
2072c2c66affSColin Finck     if(!size)
2073c2c66affSColin Finck         return 0;
2074c2c66affSColin Finck 
2075c2c66affSColin Finck     res = min(strlenW(infoPtr->szTipText)+1, size);
2076c2c66affSColin Finck     memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR));
2077c2c66affSColin Finck     pszText[res-1] = '\0';
2078c2c66affSColin Finck     return res-1;
2079c2c66affSColin Finck }
2080c2c66affSColin Finck 
2081c2c66affSColin Finck static LRESULT
2082c2c66affSColin Finck TOOLTIPS_Timer (TOOLTIPS_INFO *infoPtr, INT iTimer)
2083c2c66affSColin Finck {
2084c2c66affSColin Finck     INT nOldTool;
2085c2c66affSColin Finck 
2086edd99e8cSAmine Khaldi     TRACE("timer %d (%p) expired\n", iTimer, infoPtr->hwndSelf);
2087c2c66affSColin Finck 
2088c2c66affSColin Finck     switch (iTimer) {
2089c2c66affSColin Finck     case ID_TIMERSHOW:
2090c2c66affSColin Finck         KillTimer (infoPtr->hwndSelf, ID_TIMERSHOW);
2091c2c66affSColin Finck 	nOldTool = infoPtr->nTool;
2092c2c66affSColin Finck 	if ((infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, TRUE)) == nOldTool)
2093c2c66affSColin Finck 	    TOOLTIPS_Show (infoPtr, FALSE);
2094c2c66affSColin Finck 	break;
2095c2c66affSColin Finck 
2096c2c66affSColin Finck     case ID_TIMERPOP:
2097c2c66affSColin Finck         TOOLTIPS_Hide (infoPtr);
2098c2c66affSColin Finck 	break;
2099c2c66affSColin Finck 
2100c2c66affSColin Finck     case ID_TIMERLEAVE:
2101c2c66affSColin Finck         nOldTool = infoPtr->nTool;
2102c2c66affSColin Finck 	infoPtr->nTool = TOOLTIPS_CheckTool (infoPtr, FALSE);
2103c2c66affSColin Finck 	TRACE("tool (%p) %d %d %d\n", infoPtr->hwndSelf, nOldTool,
2104c2c66affSColin Finck 	      infoPtr->nTool, infoPtr->nCurrentTool);
2105c2c66affSColin Finck 	if (infoPtr->nTool != nOldTool) {
2106c2c66affSColin Finck 	    if(infoPtr->nTool == -1) { /* Moved out of all tools */
2107c2c66affSColin Finck 	        TOOLTIPS_Hide(infoPtr);
2108c2c66affSColin Finck 		KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
2109c2c66affSColin Finck 	    } else if (nOldTool == -1) { /* Moved from outside */
2110c2c66affSColin Finck 	        ERR("How did this happen?\n");
2111c2c66affSColin Finck 	    } else { /* Moved from one to another */
2112c2c66affSColin Finck 	        TOOLTIPS_Hide (infoPtr);
2113c2c66affSColin Finck 		KillTimer(infoPtr->hwndSelf, ID_TIMERLEAVE);
2114c2c66affSColin Finck 		if(infoPtr->bActive) {
2115c2c66affSColin Finck 		    SetTimer (infoPtr->hwndSelf, ID_TIMERSHOW, infoPtr->nReshowTime, 0);
2116c2c66affSColin Finck 		    TRACE("timer 1 started!\n");
2117c2c66affSColin Finck 		}
2118c2c66affSColin Finck 	    }
2119c2c66affSColin Finck 	}
2120c2c66affSColin Finck 	break;
2121c2c66affSColin Finck 
2122c2c66affSColin Finck     default:
2123c2c66affSColin Finck         ERR("Unknown timer id %d\n", iTimer);
2124c2c66affSColin Finck 	break;
2125c2c66affSColin Finck     }
2126c2c66affSColin Finck     return 0;
2127c2c66affSColin Finck }
2128c2c66affSColin Finck 
2129c2c66affSColin Finck 
2130c2c66affSColin Finck static LRESULT
2131c2c66affSColin Finck TOOLTIPS_WinIniChange (TOOLTIPS_INFO *infoPtr)
2132c2c66affSColin Finck {
2133c2c66affSColin Finck     TOOLTIPS_InitSystemSettings (infoPtr);
2134c2c66affSColin Finck 
2135c2c66affSColin Finck     return 0;
2136c2c66affSColin Finck }
2137c2c66affSColin Finck 
2138c2c66affSColin Finck 
2139c2c66affSColin Finck static LRESULT CALLBACK
2140edd99e8cSAmine Khaldi TOOLTIPS_SubclassProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
2141c2c66affSColin Finck {
2142c2c66affSColin Finck     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr ((HWND)dwRef);
2143c2c66affSColin Finck     MSG msg;
2144c2c66affSColin Finck 
2145edd99e8cSAmine Khaldi     switch (message)
2146edd99e8cSAmine Khaldi     {
2147c2c66affSColin Finck     case WM_MOUSEMOVE:
2148c2c66affSColin Finck     case WM_LBUTTONDOWN:
2149c2c66affSColin Finck     case WM_LBUTTONUP:
2150c2c66affSColin Finck     case WM_MBUTTONDOWN:
2151c2c66affSColin Finck     case WM_MBUTTONUP:
2152c2c66affSColin Finck     case WM_RBUTTONDOWN:
2153c2c66affSColin Finck     case WM_RBUTTONUP:
2154edd99e8cSAmine Khaldi         if (infoPtr)
2155edd99e8cSAmine Khaldi         {
2156c2c66affSColin Finck             msg.hwnd = hwnd;
2157edd99e8cSAmine Khaldi             msg.message = message;
2158c2c66affSColin Finck             msg.wParam = wParam;
2159c2c66affSColin Finck             msg.lParam = lParam;
2160c2c66affSColin Finck             TOOLTIPS_RelayEvent(infoPtr, &msg);
2161edd99e8cSAmine Khaldi         }
2162c2c66affSColin Finck         break;
2163edd99e8cSAmine Khaldi     case WM_NCDESTROY:
2164edd99e8cSAmine Khaldi         RemoveWindowSubclass(hwnd, TOOLTIPS_SubclassProc, 1);
2165edd99e8cSAmine Khaldi         break;
2166c2c66affSColin Finck     default:
2167c2c66affSColin Finck         break;
2168c2c66affSColin Finck     }
2169edd99e8cSAmine Khaldi 
2170edd99e8cSAmine Khaldi     return DefSubclassProc(hwnd, message, wParam, lParam);
2171c2c66affSColin Finck }
2172c2c66affSColin Finck 
2173c2c66affSColin Finck 
2174c2c66affSColin Finck static LRESULT CALLBACK
2175c2c66affSColin Finck TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2176c2c66affSColin Finck {
2177c2c66affSColin Finck     TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
2178c2c66affSColin Finck 
2179c2c66affSColin Finck     TRACE("hwnd=%p msg=%x wparam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
2180c2c66affSColin Finck     if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE))
2181c2c66affSColin Finck         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2182c2c66affSColin Finck     switch (uMsg)
2183c2c66affSColin Finck     {
2184c2c66affSColin Finck 	case TTM_ACTIVATE:
2185c2c66affSColin Finck 	    return TOOLTIPS_Activate (infoPtr, (BOOL)wParam);
2186c2c66affSColin Finck 
2187c2c66affSColin Finck 	case TTM_ADDTOOLA:
2188c2c66affSColin Finck 	case TTM_ADDTOOLW:
2189c2c66affSColin Finck 	    return TOOLTIPS_AddToolT (infoPtr, (LPTTTOOLINFOW)lParam, uMsg == TTM_ADDTOOLW);
2190c2c66affSColin Finck 
2191c2c66affSColin Finck 	case TTM_DELTOOLA:
2192c2c66affSColin Finck 	case TTM_DELTOOLW:
2193c2c66affSColin Finck 	    return TOOLTIPS_DelToolT (infoPtr, (LPTOOLINFOW)lParam,
2194c2c66affSColin Finck                                       uMsg == TTM_DELTOOLW);
2195c2c66affSColin Finck 	case TTM_ENUMTOOLSA:
2196c2c66affSColin Finck 	case TTM_ENUMTOOLSW:
2197c2c66affSColin Finck 	    return TOOLTIPS_EnumToolsT (infoPtr, (UINT)wParam, (LPTTTOOLINFOW)lParam,
2198c2c66affSColin Finck                                         uMsg == TTM_ENUMTOOLSW);
2199c2c66affSColin Finck 	case TTM_GETBUBBLESIZE:
2200c2c66affSColin Finck 	    return TOOLTIPS_GetBubbleSize (infoPtr, (LPTTTOOLINFOW)lParam);
2201c2c66affSColin Finck 
2202c2c66affSColin Finck 	case TTM_GETCURRENTTOOLA:
2203c2c66affSColin Finck 	case TTM_GETCURRENTTOOLW:
2204c2c66affSColin Finck 	    return TOOLTIPS_GetCurrentToolT (infoPtr, (LPTTTOOLINFOW)lParam,
2205c2c66affSColin Finck                                              uMsg == TTM_GETCURRENTTOOLW);
2206c2c66affSColin Finck 
2207c2c66affSColin Finck 	case TTM_GETDELAYTIME:
2208c2c66affSColin Finck 	    return TOOLTIPS_GetDelayTime (infoPtr, (DWORD)wParam);
2209c2c66affSColin Finck 
2210c2c66affSColin Finck 	case TTM_GETMARGIN:
2211c2c66affSColin Finck 	    return TOOLTIPS_GetMargin (infoPtr, (LPRECT)lParam);
2212c2c66affSColin Finck 
2213c2c66affSColin Finck 	case TTM_GETMAXTIPWIDTH:
2214c2c66affSColin Finck 	    return TOOLTIPS_GetMaxTipWidth (infoPtr);
2215c2c66affSColin Finck 
2216c2c66affSColin Finck 	case TTM_GETTEXTA:
2217c2c66affSColin Finck 	case TTM_GETTEXTW:
2218c2c66affSColin Finck 	    return TOOLTIPS_GetTextT (infoPtr, (LPTTTOOLINFOW)lParam,
2219c2c66affSColin Finck                                       uMsg == TTM_GETTEXTW);
2220c2c66affSColin Finck 
2221c2c66affSColin Finck 	case TTM_GETTIPBKCOLOR:
2222c2c66affSColin Finck 	    return TOOLTIPS_GetTipBkColor (infoPtr);
2223c2c66affSColin Finck 
2224c2c66affSColin Finck 	case TTM_GETTIPTEXTCOLOR:
2225c2c66affSColin Finck 	    return TOOLTIPS_GetTipTextColor (infoPtr);
2226c2c66affSColin Finck 
2227c2c66affSColin Finck 	case TTM_GETTOOLCOUNT:
2228c2c66affSColin Finck 	    return TOOLTIPS_GetToolCount (infoPtr);
2229c2c66affSColin Finck 
2230c2c66affSColin Finck 	case TTM_GETTOOLINFOA:
2231c2c66affSColin Finck 	case TTM_GETTOOLINFOW:
2232c2c66affSColin Finck 	    return TOOLTIPS_GetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
2233c2c66affSColin Finck                                           uMsg == TTM_GETTOOLINFOW);
2234c2c66affSColin Finck 
2235c2c66affSColin Finck 	case TTM_HITTESTA:
2236c2c66affSColin Finck 	case TTM_HITTESTW:
2237c2c66affSColin Finck 	    return TOOLTIPS_HitTestT (infoPtr, (LPTTHITTESTINFOW)lParam,
2238c2c66affSColin Finck                                       uMsg == TTM_HITTESTW);
2239c2c66affSColin Finck 	case TTM_NEWTOOLRECTA:
2240c2c66affSColin Finck 	case TTM_NEWTOOLRECTW:
2241c2c66affSColin Finck 	    return TOOLTIPS_NewToolRectT (infoPtr, (LPTTTOOLINFOW)lParam);
2242c2c66affSColin Finck 
2243c2c66affSColin Finck 	case TTM_POP:
2244c2c66affSColin Finck 	    return TOOLTIPS_Pop (infoPtr);
2245c2c66affSColin Finck 
2246c2c66affSColin Finck 	case TTM_RELAYEVENT:
2247c2c66affSColin Finck 	    return TOOLTIPS_RelayEvent (infoPtr, (LPMSG)lParam);
2248c2c66affSColin Finck 
2249c2c66affSColin Finck 	case TTM_SETDELAYTIME:
2250c2c66affSColin Finck 	    return TOOLTIPS_SetDelayTime (infoPtr, (DWORD)wParam, (INT)LOWORD(lParam));
2251c2c66affSColin Finck 
2252c2c66affSColin Finck 	case TTM_SETMARGIN:
2253c2c66affSColin Finck 	    return TOOLTIPS_SetMargin (infoPtr, (LPRECT)lParam);
2254c2c66affSColin Finck 
2255c2c66affSColin Finck 	case TTM_SETMAXTIPWIDTH:
2256c2c66affSColin Finck 	    return TOOLTIPS_SetMaxTipWidth (infoPtr, (INT)lParam);
2257c2c66affSColin Finck 
2258c2c66affSColin Finck 	case TTM_SETTIPBKCOLOR:
2259c2c66affSColin Finck 	    return TOOLTIPS_SetTipBkColor (infoPtr, (COLORREF)wParam);
2260c2c66affSColin Finck 
2261c2c66affSColin Finck 	case TTM_SETTIPTEXTCOLOR:
2262c2c66affSColin Finck 	    return TOOLTIPS_SetTipTextColor (infoPtr, (COLORREF)wParam);
2263c2c66affSColin Finck 
2264c2c66affSColin Finck 	case TTM_SETTITLEA:
2265c2c66affSColin Finck 	case TTM_SETTITLEW:
2266c2c66affSColin Finck 	    return TOOLTIPS_SetTitleT (infoPtr, (UINT_PTR)wParam, (LPCWSTR)lParam,
2267c2c66affSColin Finck                                        uMsg == TTM_SETTITLEW);
2268c2c66affSColin Finck 
2269c2c66affSColin Finck 	case TTM_SETTOOLINFOA:
2270c2c66affSColin Finck 	case TTM_SETTOOLINFOW:
2271c2c66affSColin Finck 	    return TOOLTIPS_SetToolInfoT (infoPtr, (LPTTTOOLINFOW)lParam,
2272c2c66affSColin Finck                                           uMsg == TTM_SETTOOLINFOW);
2273c2c66affSColin Finck 
2274c2c66affSColin Finck 	case TTM_TRACKACTIVATE:
2275c2c66affSColin Finck 	    return TOOLTIPS_TrackActivate (infoPtr, (BOOL)wParam, (LPTTTOOLINFOA)lParam);
2276c2c66affSColin Finck 
2277c2c66affSColin Finck 	case TTM_TRACKPOSITION:
2278c2c66affSColin Finck 	    return TOOLTIPS_TrackPosition (infoPtr, lParam);
2279c2c66affSColin Finck 
2280c2c66affSColin Finck 	case TTM_UPDATE:
2281c2c66affSColin Finck 	    return TOOLTIPS_Update (infoPtr);
2282c2c66affSColin Finck 
2283c2c66affSColin Finck 	case TTM_UPDATETIPTEXTA:
2284c2c66affSColin Finck 	case TTM_UPDATETIPTEXTW:
2285c2c66affSColin Finck 	    return TOOLTIPS_UpdateTipTextT (infoPtr, (LPTTTOOLINFOW)lParam,
2286c2c66affSColin Finck                                             uMsg == TTM_UPDATETIPTEXTW);
2287c2c66affSColin Finck 
2288c2c66affSColin Finck 	case TTM_WINDOWFROMPOINT:
2289c2c66affSColin Finck 	    return (LRESULT)WindowFromPoint (*((LPPOINT)lParam));
2290c2c66affSColin Finck 
2291c2c66affSColin Finck 	case WM_CREATE:
2292c2c66affSColin Finck 	    return TOOLTIPS_Create (hwnd);
2293c2c66affSColin Finck 
2294c2c66affSColin Finck 	case WM_DESTROY:
2295c2c66affSColin Finck 	    return TOOLTIPS_Destroy (infoPtr);
2296c2c66affSColin Finck 
2297c2c66affSColin Finck 	case WM_ERASEBKGND:
2298c2c66affSColin Finck 	    /* we draw the background in WM_PAINT */
2299c2c66affSColin Finck 	    return 0;
2300c2c66affSColin Finck 
2301c2c66affSColin Finck 	case WM_GETFONT:
2302c2c66affSColin Finck 	    return TOOLTIPS_GetFont (infoPtr);
2303c2c66affSColin Finck 
2304c2c66affSColin Finck 	case WM_GETTEXT:
2305c2c66affSColin Finck 	    return TOOLTIPS_OnWMGetText (infoPtr, wParam, (LPWSTR)lParam);
2306c2c66affSColin Finck 
2307c2c66affSColin Finck 	case WM_GETTEXTLENGTH:
2308c2c66affSColin Finck 	    return TOOLTIPS_GetTextLength (infoPtr);
2309c2c66affSColin Finck 
2310c2c66affSColin Finck 	case WM_LBUTTONDOWN:
2311c2c66affSColin Finck 	case WM_LBUTTONUP:
2312c2c66affSColin Finck 	case WM_MBUTTONDOWN:
2313c2c66affSColin Finck 	case WM_MBUTTONUP:
2314c2c66affSColin Finck 	case WM_RBUTTONDOWN:
2315c2c66affSColin Finck 	case WM_RBUTTONUP:
2316c2c66affSColin Finck 	case WM_MOUSEMOVE:
2317c2c66affSColin Finck 	    return TOOLTIPS_MouseMessage (infoPtr);
2318c2c66affSColin Finck 
2319c2c66affSColin Finck 	case WM_NCCREATE:
2320c2c66affSColin Finck 	    return TOOLTIPS_NCCreate (hwnd);
2321c2c66affSColin Finck 
2322c2c66affSColin Finck 	case WM_NCHITTEST:
2323c2c66affSColin Finck 	    return TOOLTIPS_NCHitTest (infoPtr, wParam, lParam);
2324c2c66affSColin Finck 
2325c2c66affSColin Finck 	case WM_NOTIFYFORMAT:
2326c2c66affSColin Finck 	    return TOOLTIPS_NotifyFormat (infoPtr, wParam, lParam);
2327c2c66affSColin Finck 
2328c2c66affSColin Finck 	case WM_PRINTCLIENT:
2329c2c66affSColin Finck 	case WM_PAINT:
2330c2c66affSColin Finck 	    return TOOLTIPS_Paint (infoPtr, (HDC)wParam);
2331c2c66affSColin Finck 
2332c2c66affSColin Finck 	case WM_SETFONT:
2333c2c66affSColin Finck 	    return TOOLTIPS_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam));
2334c2c66affSColin Finck 
2335c2c66affSColin Finck 	case WM_SYSCOLORCHANGE:
2336c2c66affSColin Finck 	    COMCTL32_RefreshSysColors();
2337c2c66affSColin Finck 	    return 0;
2338c2c66affSColin Finck 
2339c2c66affSColin Finck 	case WM_TIMER:
2340c2c66affSColin Finck 	    return TOOLTIPS_Timer (infoPtr, (INT)wParam);
2341c2c66affSColin Finck 
2342c2c66affSColin Finck 	case WM_WININICHANGE:
2343c2c66affSColin Finck 	    return TOOLTIPS_WinIniChange (infoPtr);
2344c2c66affSColin Finck 
2345c2c66affSColin Finck 	default:
2346c2c66affSColin Finck 	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2347c2c66affSColin Finck 		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
2348c2c66affSColin Finck 		     uMsg, wParam, lParam);
2349c2c66affSColin Finck 	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
2350c2c66affSColin Finck     }
2351c2c66affSColin Finck }
2352c2c66affSColin Finck 
2353c2c66affSColin Finck 
2354c2c66affSColin Finck VOID
2355c2c66affSColin Finck TOOLTIPS_Register (void)
2356c2c66affSColin Finck {
2357c2c66affSColin Finck     WNDCLASSW wndClass;
2358c2c66affSColin Finck 
2359c2c66affSColin Finck     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
2360c2c66affSColin Finck     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
2361c2c66affSColin Finck     wndClass.lpfnWndProc   = TOOLTIPS_WindowProc;
2362c2c66affSColin Finck     wndClass.cbClsExtra    = 0;
2363c2c66affSColin Finck     wndClass.cbWndExtra    = sizeof(TOOLTIPS_INFO *);
2364c2c66affSColin Finck     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2365c2c66affSColin Finck     wndClass.hbrBackground = 0;
2366c2c66affSColin Finck     wndClass.lpszClassName = TOOLTIPS_CLASSW;
2367c2c66affSColin Finck 
2368c2c66affSColin Finck     RegisterClassW (&wndClass);
2369c2c66affSColin Finck 
2370c2c66affSColin Finck     hTooltipIcons[TTI_NONE] = NULL;
2371c2c66affSColin Finck     hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule,
2372c2c66affSColin Finck         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0);
2373c2c66affSColin Finck     hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule,
2374c2c66affSColin Finck         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0);
2375c2c66affSColin Finck     hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule,
2376c2c66affSColin Finck         (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0);
2377c2c66affSColin Finck }
2378c2c66affSColin Finck 
2379c2c66affSColin Finck 
2380c2c66affSColin Finck VOID
2381c2c66affSColin Finck TOOLTIPS_Unregister (void)
2382c2c66affSColin Finck {
2383c2c66affSColin Finck     int i;
2384c2c66affSColin Finck     for (i = TTI_INFO; i <= TTI_ERROR; i++)
2385c2c66affSColin Finck         DestroyIcon(hTooltipIcons[i]);
2386c2c66affSColin Finck     UnregisterClassW (TOOLTIPS_CLASSW, NULL);
2387c2c66affSColin Finck }
2388