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