/* *@@sourcefile cctl_tooltip.c: * implementation for the "tooltip" common control. * See comctl.c for an overview. * * This has been extracted from comctl.c with V0.9.3 (2000-05-21) [umoeller]. * * Note: Version numbering in this file relates to XWorkplace version * numbering. * *@@header "helpers\comctl.h" *@@added V0.9.3 (2000-05-21) [umoeller]. */ /* * Copyright (C) 1997-2005 Ulrich M”ller. * This file is part of the "XWorkplace helpers" source package. * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, in version 2 as it comes in the * "COPYING" file of the XWorkplace main distribution. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define OS2EMX_PLAIN_CHAR // this is needed for "os2emx.h"; if this is defined, // emx will define PSZ as _signed_ char, otherwise // as unsigned char #define INCL_DOSEXCEPTIONS #define INCL_DOSPROCESS #define INCL_DOSSEMAPHORES #define INCL_DOSERRORS #define INCL_WINWINDOWMGR #define INCL_WINFRAMEMGR #define INCL_WINMESSAGEMGR #define INCL_WININPUT #define INCL_WINPOINTERS #define INCL_WINTRACKRECT #define INCL_WINTIMER #define INCL_WINSYS #define INCL_WINRECTANGLES /// xxx temporary #define INCL_WINMENUS #define INCL_WINSTATICS #define INCL_WINBUTTONS #define INCL_WINSTDCNR #define INCL_GPIPRIMITIVES #define INCL_GPILOGCOLORTABLE #define INCL_GPILCIDS #define INCL_GPIPATHS #define INCL_GPIREGIONS #define INCL_GPIBITMAPS // added V0.9.1 (2000-01-04) [umoeller]: needed for EMX headers #include #include #include #include #include // needed for except.h #include // needed for except.h #include "setup.h" // code generation and debugging options #include "helpers\cnrh.h" #include "helpers\except.h" // exception handling #include "helpers\gpih.h" #include "helpers\linklist.h" #include "helpers\nls.h" #include "helpers\winh.h" #include "helpers\comctl.h" #pragma hdrstop /* *@@category: Helpers\PM helpers\Window classes\Tooltips * See cctl_tooltip.c. */ /* ****************************************************************** * * Global variables * ********************************************************************/ // linked list of all tools which were subclassed for tooltip HMTX G_hmtxSubclassedTools = NULLHANDLE; LINKLIST G_llSubclassedTools; // linked list of SUBCLASSEDTOOL items /* ****************************************************************** * * "Tooltip" control * ********************************************************************/ /* *@@ ctlRegisterTooltip: * this registers the Tooltip window class (ctl_fnwpTooltip) * for an application. This is required before the tooltip * control can be used. * *@@added V0.9.0 [umoeller] */ BOOL ctlRegisterTooltip(HAB hab) { return WinRegisterClass(hab, WC_CCTL_TOOLTIP, ctl_fnwpTooltip, CS_HITTEST, // class styles; // CS_FRAME not working, // CS_CLIPSIBLINGS not working sizeof(PVOID) * 2); // addt'l bytes to reserve: // one pointer for QWL_USER, // one more for instance data } /* ****************************************************************** * * Subclassing * ********************************************************************/ /* *@@ LockSubclassedTools: * locks the global list of subclassed tools. * *@@added V0.9.12 (2001-04-28) [umoeller] */ STATIC BOOL LockSubclassedTools(VOID) { if (!G_hmtxSubclassedTools) { // first call: // initialize the list lstInit(&G_llSubclassedTools, TRUE); // auto-free // create mutex and request it right away return !DosCreateMutexSem(NULL, &G_hmtxSubclassedTools, 0, TRUE); // request! } return !DosRequestMutexSem(G_hmtxSubclassedTools, SEM_INDEFINITE_WAIT); } /* *@@ UnlockSubclassedTools: * unlocks the global list of subclassed tools. * *@@added V0.9.12 (2001-04-28) [umoeller] *@@changed V0.9.12 (2001-05-03) [umoeller]: this did nothing... fixed */ STATIC VOID UnlockSubclassedTools(VOID) { DosReleaseMutexSem(G_hmtxSubclassedTools); // was missing V0.9.12 (2001-05-03) [umoeller] } /* *@@ SUBCLASSEDTOOL: * structure created for each control which is * subclassed by the tooltip control (ctl_fnwpTooltip). * *@@added V0.9.0 [umoeller] */ typedef struct _SUBCLASSEDTOOL { HWND hwndTool; PFNWP pfnwpOrig; HWND hwndTooltip; HAB hab; } SUBCLASSEDTOOL, *PSUBCLASSEDTOOL; /* *@@ FindSubclassedTool: * returns the SUBCLASSEDTOOL struct from the * global list which matches hwndTool or NULL * if not found. * * Preconditions: Caller must hold the subclassed * tools mutex. * *@@added V0.9.12 (2001-04-28) [umoeller] */ STATIC PSUBCLASSEDTOOL FindSubclassedTool(HWND hwndTool) { PLISTNODE pNode = lstQueryFirstNode(&G_llSubclassedTools); while (pNode) { PSUBCLASSEDTOOL pstThis = (PSUBCLASSEDTOOL)pNode->pItemData; if (pstThis->hwndTool == hwndTool) return pstThis; pNode = pNode->pNext; } return NULL; } /* *@@ ctl_fnwpSubclassedTool: * window procedure for tools which were subclassed * to support tooltips. * *@@added V0.9.0 [umoeller] *@@changed V0.9.12 (2001-04-28) [umoeller]: added mutex protection *@@changed V1.0.2 (2003-07-26) [pr]: fixed tooltip moving with mouse from xcenters @@fixes 455 */ MRESULT EXPENTRY ctl_fnwpSubclassedTool(HWND hwndTool, ULONG msg, MPARAM mp1, MPARAM mp2) { MRESULT mrc = 0; PFNWP pfnwpOrig = NULL; if (LockSubclassedTools()) { PSUBCLASSEDTOOL pst; if (pst = FindSubclassedTool(hwndTool)) { pfnwpOrig = pst->pfnwpOrig; // call default switch (msg) { case WM_MOUSEMOVE: case WM_BUTTON1DOWN: case WM_BUTTON1UP: case WM_BUTTON2DOWN: case WM_BUTTON2UP: case WM_BUTTON3DOWN: case WM_BUTTON3UP: case WM_MOUSELEAVE: // V1.0.2 (2003-07-26) [pr]: @@fixes 455 { QMSG qmsg; qmsg.hwnd = hwndTool; qmsg.msg = msg; qmsg.mp1 = mp1; qmsg.mp2 = mp2; // _Pmpf((__FUNCTION__ ": sending TTM_RELAYEVENT")); WinSendMsg(pst->hwndTooltip, TTM_RELAYEVENT, (MPARAM)0, (MPARAM)&qmsg); } break; case WM_DESTROY: lstRemoveItem(&G_llSubclassedTools, pst); // this frees the item break; } } UnlockSubclassedTools(); } if (pfnwpOrig) mrc = pfnwpOrig(hwndTool, msg, mp1, mp2); return mrc; } /* *@@ SubclassTool: * this gets called from ctl_fnwpTooltip if a control * is to be subclassed to support mouse messaging * (TTF_SUBCLASS flag). * * Preconditions: Caller must hold the subclassed * tools mutex. * *@@added V0.9.0 [umoeller] *@@changed V0.9.12 (2001-04-28) [umoeller]: renamed from SubclassToolForToolInfo */ STATIC BOOL SubclassTool(HWND hwndTooltip, HWND hwndTool) { BOOL brc = FALSE; // make sure the tool is not on the list yet // V0.9.12 (2001-04-28) [umoeller] if (!FindSubclassedTool(hwndTool)) { PFNWP pfnwpOrig; if (pfnwpOrig = WinSubclassWindow(hwndTool, ctl_fnwpSubclassedTool)) { PSUBCLASSEDTOOL pst; if (pst = (PSUBCLASSEDTOOL)malloc(sizeof(SUBCLASSEDTOOL))) { pst->pfnwpOrig = pfnwpOrig; pst->hwndTooltip = hwndTooltip; pst->hwndTool = hwndTool; pst->hab = WinQueryAnchorBlock(hwndTool); brc = !!lstAppendItem(&G_llSubclassedTools, pst); } } } return brc; } /* *@@ UnSubclassTool: * un-subclasses a tool previously subclassed by * SubclassToolForToolinfo. * * Preconditions: Caller must hold the subclassed * tools mutex. * *@@added V0.9.12 (2001-04-28) [umoeller] */ STATIC BOOL UnSubclassTool(HWND hwndTool) { PSUBCLASSEDTOOL pst; if (pst = FindSubclassedTool(hwndTool)) { WinSubclassWindow(hwndTool, pst->pfnwpOrig); // orig winproc == un-subclass return lstRemoveItem(&G_llSubclassedTools, pst); // this frees the item } return FALSE; } /* ****************************************************************** * * Implementation * ********************************************************************/ /* *@@ TOOLTIPDATA: * private data structure stored in the window * words of ctl_fnwpTooltip to hold information for * a tooltip instance. * *@@added V0.9.0 [umoeller] */ typedef struct _TOOLTIPDATA { HWND hwndOwner; // from WM_CREATE HAB hab; // from WM_CREATE USHORT usTooltipID; // from WM_CREATE BOOL fIsActive; // TRUE per default; changed by TTM_ACTIVATE ULONG idTimerInitial, // if != 0, "initial" timer is running idTimerAutopop; // if != 0, "autopop" (hide) timer is running ULONG ulTimeoutInitial, // "initial" timer timeout (ms) ulTimeoutAutopop, // "autopop" (hide) timer timeout (ms) ulTimeoutReshow; // "reshow" timer timeout (ms) LINKLIST llTools; // linked list of TOOLINFO structures // containing the tools FONTMETRICS fontmetrics; // current font LONG lForeColor, // current foreground color lBackColor, // current background color l3DHiColor, // 3D border light color l3DLoColor; // 3D border dark color PSZ pszPaintText; // text to paint (new buffer) POINTL ptlPointerLast; // last mouse pointer position PTOOLINFO ptiMouseOver; // tool info over which the mouse resides BOOL fIsVisible; // TRUE if tooltip is visible // CHAR szTextBuf[256]; // static buffer for copying/loading strings } TOOLTIPDATA, *PTOOLTIPDATA; // timer IDs #define TOOLTIP_ID_TIMER_INITIAL 1 #define TOOLTIP_ID_TIMER_AUTOPOP 2 // tooltip window border (free spaces) #define TOOLTIP_CX_BORDER 5 #define TOOLTIP_CY_BORDER 3 /* *@@ UpdateTooltipPresColors: * this gets called during WM_CREATE and WM_PRESPARAMCHANGED * in ctl_fnwpTooltip to set the colors in TOOLTIPDATA according * to the control's presparams. */ STATIC VOID UpdateTooltipPresColors(HWND hwndTooltip) // in: tooltip control { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); // tooltip background color: pttd->lBackColor = winhQueryPresColor(hwndTooltip, PP_MENUBACKGROUNDCOLOR, FALSE, // no inherit SYSCLR_ENTRYFIELD); // tooltip text color: pttd->lForeColor = winhQueryPresColor(hwndTooltip, PP_MENUFOREGROUNDCOLOR, FALSE, // no inherit SYSCLR_WINDOWTEXT); // 3D border light color: pttd->l3DHiColor = winhQueryPresColor(hwndTooltip, PP_MENUHILITEFGNDCOLOR, FALSE, // no inherit SYSCLR_WINDOWTEXT); // 3D border dark color: pttd->l3DLoColor = winhQueryPresColor(hwndTooltip, PP_MENUHILITEBGNDCOLOR, FALSE, // no inherit SYSCLR_WINDOWTEXT); } /* *@@ TtmCreate: * implementation for WM_CREATE in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmCreate(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd; PCREATESTRUCT pcs = (PCREATESTRUCT)mp2; // allocate and initialize tooltip data if (pttd = (PTOOLTIPDATA)malloc(sizeof(TOOLTIPDATA))) { CHAR szFont[256]; memset(pttd, 0, sizeof(TOOLTIPDATA)); WinSetWindowPtr(hwndTooltip, 1, pttd); pttd->hwndOwner = pcs->hwndOwner; pttd->hab = WinQueryAnchorBlock(hwndTooltip); pttd->usTooltipID = pcs->id; pttd->fIsActive = TRUE; // default timeouts pttd->ulTimeoutInitial = 1000; pttd->ulTimeoutAutopop = 5000; pttd->ulTimeoutReshow = 500; // get colors from presparams/syscolors UpdateTooltipPresColors(hwndTooltip); // check if font presparam set if (WinQueryPresParam(hwndTooltip, PP_FONTNAMESIZE, 0, NULL, sizeof(szFont), szFont, QPF_NOINHERIT) == 0) { // no: set default font presparam // (we never want the System Proportional font) winhSetWindowFont(hwndTooltip, NULL); // default (WarpSans or 8.Helv) } pttd->pszPaintText = strdup("undefined"); lstInit(&pttd->llTools, TRUE); // auto-free items // override CREATESTRUCT WinSetWindowPos(hwndTooltip, HWND_TOP, 50, 50, 100, 100, SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_HIDE); return (MPARAM)FALSE; } // malloc failed: return (MPARAM)TRUE; } /* *@@ TtmTimer: * implementation for WM_TIMER in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC BOOL TtmTimer(HWND hwndTooltip, MPARAM mp1) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); USHORT usTimer = SHORT1FROMMP(mp1); switch (usTimer) { case TOOLTIP_ID_TIMER_INITIAL: // _Pmpf(("WM_TIMER: Stopping initial timer: %d", usTimer)); // _Pmpf((__FUNCTION__ ": TOOLTIP_ID_TIMER_INITIAL")); WinStopTimer(pttd->hab, hwndTooltip, usTimer); pttd->idTimerInitial = 0; if (pttd->fIsActive) // show tooltip WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)TRUE, 0); break; case TOOLTIP_ID_TIMER_AUTOPOP: // _Pmpf(("WM_TIMER: Stopping autopop timer: %d", usTimer)); WinStopTimer(pttd->hab, hwndTooltip, usTimer); pttd->idTimerAutopop = 0; WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)FALSE, 0); break; default: return FALSE; } // end switch return TRUE; } /* *@@ TtmPaint: * implementation for WM_PAINT in ctl_fnwpTooltip. * *@@added V0.9.1 (99-11-30) [umoeller] */ STATIC VOID TtmPaint(HWND hwndTooltip) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); HPS hps = WinBeginPaint(hwndTooltip, NULLHANDLE, NULL); POINTL ptl = {0, 0}; RECTL rclWindow, rclWindowBak; ULONG ulStyle = WinQueryWindowULong(hwndTooltip, QWL_STYLE); ULONG ulRounding = 0; if (ulStyle & TTS_ROUNDED) ulRounding = TT_ROUNDING; gpihSwitchToRGB(hps); // get tooltip size; this has been properly calculated // by TTM_SHOWTOOLTIPNOW earlier WinQueryWindowRect(hwndTooltip, &rclWindow); memcpy(&rclWindowBak, &rclWindow, sizeof(RECTL)); if (ulStyle & TTS_SHADOW) { // if shadows are on, the window is too large; // make rectl smaller for rest of paint rclWindow.xRight -= TT_SHADOWOFS; rclWindow.yBottom += TT_SHADOWOFS; // restore old pattern GpiSetPattern(hps, PATSYM_DEFAULT); } // draw shadow if (ulStyle & TTS_SHADOW) { GpiSetColor(hps, CLR_BLACK); GpiSetPattern(hps, PATSYM_HALFTONE); ptl.x = rclWindowBak.xLeft + TT_SHADOWOFS; ptl.y = rclWindowBak.yBottom; GpiMove(hps, &ptl); ptl.x = rclWindowBak.xRight - 1; ptl.y = rclWindowBak.yTop - TT_SHADOWOFS; GpiBox(hps, DRO_FILL, &ptl, ulRounding, ulRounding); // restore pattern GpiSetPattern(hps, PATSYM_DEFAULT); } // draw "real" rectangle ptl.x = rclWindow.xLeft; ptl.y = rclWindow.yBottom; GpiMove(hps, &ptl); ptl.x = rclWindow.xRight - 1; ptl.y = rclWindow.yTop - 1; GpiSetColor(hps, pttd->lBackColor); GpiBox(hps, DRO_FILL, &ptl, 6, 6); GpiSetColor(hps, pttd->lForeColor); GpiBox(hps, DRO_OUTLINE, &ptl, ulRounding, ulRounding); if (pttd->pszPaintText) { RECTL rclText; GpiSetColor(hps, pttd->lForeColor); GpiSetBackColor(hps, pttd->lBackColor); rclText.xLeft = rclWindow.xLeft + TOOLTIP_CX_BORDER; rclText.xRight = rclWindow.xRight - TOOLTIP_CX_BORDER; rclText.yBottom = rclWindow.yBottom + TOOLTIP_CY_BORDER; rclText.yTop = rclWindow.yTop - TOOLTIP_CY_BORDER; winhDrawFormattedText(hps, &rclText, pttd->pszPaintText, DT_LEFT | DT_TOP | DT_WORDBREAK); } WinEndPaint(hps); } /* *@@ TtmDestroy: * implementation for WM_DESTROY in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC VOID TtmDestroy(HWND hwndTooltip) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); // stop timers if (pttd->idTimerInitial) WinStopTimer(pttd->hab, hwndTooltip, pttd->idTimerInitial); if (pttd->idTimerAutopop) WinStopTimer(pttd->hab, hwndTooltip, pttd->idTimerAutopop); if (pttd->pszPaintText) free(pttd->pszPaintText); // un-subclass all tools that we subclassed // V0.9.12 (2001-04-28) [umoeller] if (LockSubclassedTools()) { PLISTNODE pNode; PSUBCLASSEDTOOL pst; for (pNode = lstQueryFirstNode(&pttd->llTools); pNode; pNode = pNode->pNext) { PTOOLINFO pti = (PTOOLINFO)pNode->pItemData; if (pst = FindSubclassedTool(pti->hwndTool)) UnSubclassTool(pti->hwndTool); } UnlockSubclassedTools(); } // end V0.9.12 (2001-04-28) [umoeller] lstClear(&pttd->llTools); free(pttd); } /* *@@ TtmAddTool: * implementation for TTM_ADDTOOL in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmAddTool(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); if (mp2) { PTOOLINFO ptiPassed = (PTOOLINFO)mp2, ptiNew = (PTOOLINFO)malloc(sizeof(TOOLINFO)); if (ptiNew) { memcpy(ptiNew, ptiPassed, sizeof(TOOLINFO)); lstAppendItem(&pttd->llTools, ptiNew); if ( (ptiPassed->ulFlags & TTF_SUBCLASS) && (LockSubclassedTools()) // V0.9.12 (2001-04-28) [umoeller] ) { // caller wants this tool to be subclassed: // well, do it then SubclassTool(hwndTooltip, ptiPassed->hwndTool); UnlockSubclassedTools(); } return ((MPARAM)TRUE); } } return (MPARAM)FALSE; } /* *@@ TtmDelTool: * implementation for TTM_DELTOOL in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] *@@changed V0.9.13 (2001-06-21) [umoeller]: fixed missing unlock *@@changed V0.9.13 (2001-06-21) [umoeller]: fixed endless loop */ STATIC VOID TtmDelTool(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PTOOLINFO ptiSearch; if (ptiSearch = (PTOOLINFO)mp2) { PLISTNODE pToolNode = lstQueryFirstNode(&pttd->llTools); while (pToolNode) { PTOOLINFO ptiThis = (PTOOLINFO)pToolNode->pItemData; if ( (ptiThis->hwndToolOwner == ptiSearch->hwndToolOwner) && (ptiThis->hwndTool == ptiSearch->hwndTool) ) { // found: // V0.9.12 (2001-04-28) [umoeller] // unsubclass if this was subclassed if (ptiThis->ulFlags & TTF_SUBCLASS) { if (LockSubclassedTools()) { UnSubclassTool(ptiSearch->hwndTool); UnlockSubclassedTools(); // was missing V0.9.13 (2001-06-21) [umoeller] } } // remove the tool from the list lstRemoveNode(&pttd->llTools, pToolNode); break; } pToolNode = pToolNode->pNext; // fixed endless loop V0.9.13 (2001-06-21) [umoeller] } } } /* *@@ TtmRelayEvent: * implementation for TTM_RELAYEVENT in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] *@@changed V0.9.19 (2002-05-14) [umoeller]: fixed bad stop timer, thanks yuri *@@changed V1.0.2 (2003-07-26) [pr]: fixed tooltip moving with mouse from xcenters @@fixes 455 */ STATIC VOID TtmRelayEvent(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PQMSG pqmsg = (PQMSG)mp2; if (pqmsg) { POINTL ptlPointer; PLISTNODE pToolNode; // moved stop timer down V0.9.19 (2002-05-14) [umoeller] WinQueryPointerPos(HWND_DESKTOP, &ptlPointer); // find TOOLINFO from mouse position pttd->ptiMouseOver = NULL; pToolNode = lstQueryFirstNode(&pttd->llTools); while (pToolNode) { PTOOLINFO pti = (PTOOLINFO)pToolNode->pItemData; if (pti->hwndTool == pqmsg->hwnd) { // _Pmpf((__FUNCTION__ ": found tool")); pttd->ptiMouseOver = pti; break; } pToolNode = pToolNode->pNext; } if ( (ptlPointer.x != pttd->ptlPointerLast.x) || (ptlPointer.y != pttd->ptlPointerLast.y) || (pqmsg->msg == WM_BUTTON1DOWN) || (pqmsg->msg == WM_BUTTON2DOWN) || (pqmsg->msg == WM_BUTTON3DOWN) || (pqmsg->msg == WM_MOUSELEAVE) // V1.0.2 (2003-07-26) [pr]: @@fixes 455 ) { // mouse pos changed: // moved stop timer here V0.9.19 (2002-05-14) [umoeller] if (pttd->idTimerInitial) { // _Pmpf(("TTM_RELAYEVENT: Stopping timer: %d", pttd->idTimerInitial)); WinStopTimer(pttd->hab, hwndTooltip, TOOLTIP_ID_TIMER_INITIAL); pttd->idTimerInitial = 0; } // hide tooltip WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)FALSE, 0); memcpy(&pttd->ptlPointerLast, &ptlPointer, sizeof(POINTL)); // _Pmpf((__FUNCTION__ ": pttd->ptiMouseOver: 0x%lX", pttd->ptiMouseOver)); // _Pmpf((__FUNCTION__ ": pttd->fIsActive: 0x%lX", pttd->fIsActive)); if ( (pttd->ptiMouseOver) && (pttd->fIsActive) && (pqmsg->msg != WM_MOUSELEAVE) // V1.0.2 (2003-07-26) [pr]: @@fixes 455 ) { // tool found and tooltip is activated: pttd->idTimerInitial = WinStartTimer(pttd->hab, hwndTooltip, TOOLTIP_ID_TIMER_INITIAL, pttd->ulTimeoutInitial); // _Pmpf(("TTM_RELAYEVENT: Started timer: %d", pttd->idTimerInitial)); } } } // end if (pqmsg) } /* *@@ TtmGetDelayTime: * implementation for TTM_GETDELAYTIME in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmGetDelayTime(HWND hwndTooltip, MPARAM mp1) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); switch ((ULONG)mp1) { case TTDT_AUTOPOP: return (MRESULT)pttd->ulTimeoutAutopop; case TTDT_INITIAL: return (MRESULT)pttd->ulTimeoutInitial; case TTDT_RESHOW: return (MRESULT)pttd->ulTimeoutReshow; } return 0; } /* *@@ TtmSetDelayTime: * implementation for TTM_SETDELAYTIME in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC VOID TtmSetDelayTime(HWND hwndTooltip, MPARAM mp1, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); ULONG iDelay = (ULONG)mp2; switch (SHORT1FROMMP(mp1)) { case TTDT_AUTOMATIC: pttd->ulTimeoutInitial = iDelay; pttd->ulTimeoutAutopop = iDelay * 5; pttd->ulTimeoutReshow = iDelay / 2; break; case TTDT_AUTOPOP: pttd->ulTimeoutAutopop = iDelay; break; case TTDT_INITIAL: pttd->ulTimeoutInitial = iDelay; break; case TTDT_RESHOW: pttd->ulTimeoutReshow = iDelay; break; } } /* *@@ TtmGetText: * implementation for TTM_GETTEXT in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC VOID TtmGetText(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PTOOLINFO pti = (PTOOLINFO)mp2; if (pti->pszText == PSZ_TEXTCALLBACK) { // TTN_NEEDTEXT notification desired: // compose values for that msg TOOLTIPTEXT ttt = {0}; ttt.hwndTooltip = hwndTooltip; ttt.hwndTool = pti->hwndTool; WinSendMsg(pti->hwndToolOwner, WM_CONTROL, MPFROM2SHORT(pttd->usTooltipID, // tooltip control wnd ID TTN_NEEDTEXT), &ttt); // in case of error: set lpszText to NULL; this // is not specified in the docs however. pti->pszText = NULL; switch (ttt.ulFormat) { case TTFMT_PSZ: if (ttt.pszText) pti->pszText = ttt.pszText; break; case TTFMT_STRINGRES: // @@todo break; } } } /* *@@ TtmEnumTools: * implementation for TTM_ENUMTOOLS in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmEnumTools(HWND hwndTooltip, MPARAM mp1, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PTOOLINFO ptiTarget; if (ptiTarget = (PTOOLINFO)mp2) { PTOOLINFO ptiFound = (PTOOLINFO)lstItemFromIndex(&pttd->llTools, SHORT1FROMMP(mp1)); if (ptiFound) { memcpy(ptiTarget, ptiFound, sizeof(TOOLINFO)); return (MRESULT)TRUE; } } return (MRESULT)FALSE; } /* *@@ TtmGetCurrentTool: * implementation for TTM_GETCURRENTTOOL in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmGetCurrentTool(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PTOOLINFO ptiTarget; if (ptiTarget = (PTOOLINFO)mp2) { if (pttd->ptiMouseOver) { memcpy(ptiTarget, pttd->ptiMouseOver, sizeof(TOOLINFO)); return (MRESULT)TRUE; } } return (MRESULT)FALSE; } /* *@@ TtmGetToolInfo: * implementation for TTM_GETTOOLINFO in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC MRESULT TtmGetToolInfo(HWND hwndTooltip, MPARAM mp2) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); PTOOLINFO ptiSearch; if (ptiSearch = (PTOOLINFO)mp2) { PLISTNODE pToolNode = lstQueryFirstNode(&pttd->llTools); while (pToolNode) { PTOOLINFO ptiThis = (PTOOLINFO)pToolNode->pItemData; if ( (ptiThis->hwndToolOwner == ptiSearch->hwndToolOwner) && (ptiThis->hwndTool == ptiSearch->hwndTool) ) { // found: memcpy(ptiSearch, ptiThis, sizeof(TOOLINFO)); return (MPARAM)TRUE; } pToolNode = pToolNode->pNext; } } return (MRESULT)FALSE; } /* *@@ FormatTooltip: * formats the tooltip window according to * its text (which is assumed to be in * pttd->pszPaintText) and positions it * on the screen. * * This does not change the visibility * of the tooltip; if it is not yet visible, * you must show it afterwards. * *@@added V0.9.13 (2001-06-21) [umoeller] *@@changed V1.0.4 (2005-10-15) [bvl]: Add 1 pixel to width of DBCS tooltip @@fixes 676 */ STATIC VOID FormatTooltip(HWND hwndTooltip, PTOOLTIPDATA pttd, PPOINTL pptlPointer) // in: current pointer pos or NULL { // find out how much space we need RECTL rcl = { 0, 0, 300, 1000 }; POINTL ptlTooltip; LONG cx, cy; ULONG ulStyle = WinQueryWindowULong(hwndTooltip, QWL_STYLE); HPS hps = WinGetPS(hwndTooltip); winhDrawFormattedText(hps, &rcl, pttd->pszPaintText, DT_LEFT | DT_TOP | DT_WORDBREAK | DT_QUERYEXTENT); WinReleasePS(hps); // calc width and height of tooltip // DBCS needs a extra pixel to show characters. cx = rcl.xRight + 2*TOOLTIP_CX_BORDER; if (nlsDBCS()) cx++; cy = (rcl.yTop - rcl.yBottom) + 2*TOOLTIP_CY_BORDER; // calc x and y pos of tooltip: // per default, use pointer pos ptlTooltip.x = pptlPointer->x - cx/2; ptlTooltip.y = pptlPointer->y - cy; // do we need the tool's position? if ( pttd->ptiMouseOver->ulFlags & (TTF_CENTER_X_ON_TOOL | TTF_POS_Y_ABOVE_TOOL | TTF_POS_Y_BELOW_TOOL) ) { // yes: SWP swpTool; POINTL ptlTool; WinQueryWindowPos(pttd->ptiMouseOver->hwndTool, &swpTool); ptlTool.x = swpTool.x; ptlTool.y = swpTool.y; // convert x, y to desktop points WinMapWindowPoints(WinQueryWindow(pttd->ptiMouseOver->hwndTool, QW_PARENT), // hwndFrom HWND_DESKTOP, // hwndTo &ptlTool, 1); // X if (pttd->ptiMouseOver->ulFlags & TTF_CENTER_X_ON_TOOL) // center X on tool: ptlTooltip.x = ptlTool.x + ((swpTool.cx - cx) / 2L); // Y if (pttd->ptiMouseOver->ulFlags & TTF_POS_Y_ABOVE_TOOL) ptlTooltip.y = ptlTool.y + swpTool.cy; else if (pttd->ptiMouseOver->ulFlags & TTF_POS_Y_BELOW_TOOL) ptlTooltip.y = ptlTool.y - cy; } // if "shy mouse" is enabled, make // sure the tool tip is not under the // mouse pointer if (ulStyle & TTF_SHYMOUSE) { // we need to subtract the current mouse // pointer's hot spot from the current // pointer position HPOINTER hptr = WinQueryPointer(HWND_DESKTOP); POINTERINFO pi; if (WinQueryPointerInfo(hptr, &pi)) { // calc bottom edge of mouse pointer rect ULONG yBottomPointer = (pptlPointer->y - pi.yHotspot); // _Pmpf(("yHotspot: %d", pi.yHotspot)); if ( (ptlTooltip.y + cy) // top edge of tool tip > yBottomPointer ) { ptlTooltip.y = pptlPointer->y - cy - pi.yHotspot; } } } // constrain to screen if (ptlTooltip.x < 0) ptlTooltip.x = 0; if (ptlTooltip.y < 0) ptlTooltip.y = 0; if (ptlTooltip.x + cx > G_cxScreen) ptlTooltip.x = G_cxScreen - cx; if (ptlTooltip.y + cy > G_cyScreen) ptlTooltip.y = G_cyScreen - cy; // if shadow is enabled, // enlarge; the shadow might by // off-screen now, but that's OK if (ulStyle & TTS_SHADOW) { cx += TT_SHADOWOFS; cy += TT_SHADOWOFS; ptlTooltip.y -= TT_SHADOWOFS; } // set tooltip position at the pos we calculated // and show tooltip WinSetWindowPos(hwndTooltip, HWND_TOP, ptlTooltip.x, ptlTooltip.y, cx, cy, SWP_MOVE | SWP_SIZE | SWP_ZORDER); } /* *@@ TtmUpdateTipText: * implementation for TTM_UPDATETIPTEXT in ctl_fnwpTooltip. * *@@added V0.9.13 (2001-06-21) [umoeller] */ STATIC VOID TtmUpdateTipText(HWND hwndTooltip, const char *pcszNewText) { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); // has text really changed? if ( ( (pttd->pszPaintText) && (pcszNewText) && (strcmp(pttd->pszPaintText, pcszNewText)) ) || (pttd->pszPaintText && !pcszNewText) || (!pttd->pszPaintText && pcszNewText) ) { // yes: if (pttd->pszPaintText) { free(pttd->pszPaintText); pttd->pszPaintText = NULL; } if (pcszNewText) pttd->pszPaintText = strdup(pcszNewText); if (pttd->fIsVisible) { // currently showing: // reformat POINTL ptlPointer; WinQueryPointerPos(HWND_DESKTOP, &ptlPointer); FormatTooltip(hwndTooltip, pttd, &ptlPointer); WinInvalidateRect(hwndTooltip, NULL, FALSE); } } } /* *@@ TtmShowTooltip: * implementation for TTM_SHOW_TOOLTIP. * * Depending on fShow, this shows or hides the * tool tip at the position specified by the * current tool or the mouse pointer (specified * by the tool's style flags). * *@@added V0.9.1 (2000-02-04) [umoeller] */ STATIC VOID TtmShowTooltip(HWND hwndTooltip, BOOL fShow) // if TRUE: show, else: HIDE { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); if (fShow) { /* * show tooltip:: * */ POINTL ptlPointer; // HPS hps; // free old text if (pttd->pszPaintText) { free(pttd->pszPaintText); pttd->pszPaintText = NULL; } WinQueryPointerPos(HWND_DESKTOP, &ptlPointer); if ( (ptlPointer.x == pttd->ptlPointerLast.x) && (ptlPointer.y == pttd->ptlPointerLast.y) ) { // mouse not moved since timer was started: // find the current TOOLINFO if (pttd->ptiMouseOver) { TOOLINFO tiTemp; memcpy(&tiTemp, pttd->ptiMouseOver, sizeof(TOOLINFO)); // get the text for the TOOLINFO WinSendMsg(hwndTooltip, TTM_GETTEXT, (MPARAM)0, (MPARAM)&tiTemp); if (tiTemp.pszText) pttd->pszPaintText = strdup(tiTemp.pszText); else pttd->pszPaintText = NULL; } if (pttd->pszPaintText) { FormatTooltip(hwndTooltip, pttd, &ptlPointer); // notify owner (TTN_SHOW) WinSendMsg(pttd->hwndOwner, WM_CONTROL, MPFROM2SHORT(pttd->usTooltipID, // tooltip control wnd ID TTN_SHOW), pttd->ptiMouseOver); WinShowWindow(hwndTooltip, TRUE); pttd->fIsVisible = TRUE; // start autopop timer pttd->idTimerAutopop = WinStartTimer(pttd->hab, hwndTooltip, TOOLTIP_ID_TIMER_AUTOPOP, pttd->ulTimeoutAutopop); } // end if (pttd->pszPaintText) } // end if ( (ptlPointer.x == pttd->ptlPointerLast.x)... } // end if (mp1) else { /* * hide tooltip:: * */ if (pttd->fIsVisible) { // notify owner (TTN_POP) WinSendMsg(pttd->hwndOwner, WM_CONTROL, MPFROM2SHORT(pttd->usTooltipID, // tooltip control wnd ID TTN_POP), pttd->ptiMouseOver); WinShowWindow(hwndTooltip, FALSE); } // stop autopop timer if (pttd->idTimerAutopop) { WinStopTimer(pttd->hab, hwndTooltip, TOOLTIP_ID_TIMER_AUTOPOP); pttd->idTimerAutopop = 0; } } // store new visibility pttd->fIsVisible = fShow; } /* *@@ ctl_fnwpTooltip: * window procedure for the "tooltip" control. This control is * largely source-code compatible to the Win32 version and has * been modelled according to the Win32 programmer's reference. * * A tooltip control is a small pop-up window that displays a * single line of descriptive text giving the purpose of "tools" * in an application. * A "tool" is either a window, such as a child window or control, * or an application-defined rectangular area within a window. * See the TTM_ADDTOOL message for details. * * To clarify: There is usually one tooltip control, which is hidden * most of the time, for many "tools" (parts of a visible window). * When the user puts the cursor on a tool and leaves it there for * approximately one-half second, the tooltip control is set up for * that tool and made visible. The tooltip control appears near the * pointer and disappears when the user clicks a mouse button or moves * the pointer off of the tool. * * The Win32 concept has been extended with this implementation to * display even longer texts, including line breaks. The tooltip * window is formatted accordingly. * * All default window styles are ignored when you create the tooltip, * but will rather be set by this window proc automatically. The * only valid window styles are the TTS_* flags (see notes below). * * Presentation parameters are fully supported. * * To create a tooltip control using comctl.c, use + ctlRegisterTooltip(hab); + hwndTooltip = WinCreateWindow(HWND_DESKTOP, // parent + WC_CCTL_TOOLTIP, // wnd class (comctl.h) + NULL, // window text + TTS_ALWAYSTIP, // window style, ignored except for TTS_* flags + 0, 0, 0, 0, // window pos and size, ignored + hwndOwner, // owner window -- important! + NULLHANDLE, // hwndInsertBehind, ignored + ulID, // window ID, optional + NULL, // control data + NULL); // presparams + * ctl_fnwpTooltip automatically sets the size, position, and visibility * of the tooltip control. The size of the tooltip window will vary * depending on the text to be displayed and on the font presentation * parameters, which are supported by this control (OS/2 only). * * Note: OS/2 normally does not destroy windows which are only owned by * another window. As a result, when the tooltip's owner is destroyed, * you must explicitly also destroy the tooltip window. * * Under both Win32 and OS/2, a tooltip control has two class-specific styles: * * -- TTS_ALWAYSTIP: the tooltip appears when the cursor is on a tool, * regardless of whether the tooltip control's owner window is active * or inactive. Without this style, the tooltip control appears when the * tool's owner window is active, but not when it is inactive. * * -- TTS_NOPREFIX: this prevents the system from stripping the ampersand (&) * character from a string. If a tooltip control does not have the TTS_NOPREFIX * style, the system automatically strips ampersand characters, allowing an * application to use the same string as both a menu item and tooltip text. * * The tooltip control can be (de)activated using the TTM_ACTIVATE message. * * To register tools with the tooltip control (to make it do anything * meaningful), send the TTM_ADDTOOL message to the tooltip control. * * This control supports the following presentation parameters (if the * PP_* value is not found, the SYSCLR_* system color is used): * -- PP_MENUBACKGROUNDCOLOR / SYSCLR_ENTRYFIELD: tooltip background color. * -- PP_MENUFOREGROUNDCOLOR / SYSCLR_WINDOWTEXT: tooltip text color. * -- PP_MENUHILITEFGNDCOLOR / SYSCLR_WINDOWTEXT: 3D border light color. * -- PP_MENUHILITEBGNDCOLOR / SYSCLR_WINDOWTEXT: 3D border dark color. * -- PP_FONTNAMESIZE: font to use for the tooltip. The default is "8.Helv" * on Warp 3 and "9.WarpSans" on Warp 4. * * So per default, if no presentation parameters are set, the control * paints the background like an entry field and the text and the border * in the same window text color (usually black). * The tooltip does _not_ inherit presentation parameters from the parent, * so unless you explicitly set presparams, the tooltip looks pretty much * like the Win32 counterpart (with the default system colors, black border * and text on yellow background). * *@@added V0.9.0 [umoeller] *@@changed V0.9.12 (2001-04-28) [umoeller]: various fixes WRT subclassing */ MRESULT EXPENTRY ctl_fnwpTooltip(HWND hwndTooltip, ULONG msg, MPARAM mp1, MPARAM mp2) { MRESULT mrc = 0; TRY_LOUD(excpt1) { switch (msg) { /* * WM_CREATE: * this message is sent to the window procedure of * the window being created, thus offering it an * opportunity to initialize that window. * * The window procedure receives this after the window * is created but before the window becomes visible. */ case WM_CREATE: mrc = TtmCreate(hwndTooltip, mp2); break; /* * WM_HITTEST: * since we have the CS_HITTEST class style set, * we get this message. We return HT_TRANSPARENT * always so the tooltip does not block mouse clicks * for the windows which lie below. */ case WM_HITTEST: // done mrc = (MPARAM)HT_TRANSPARENT; break; /* * WM_TIMER: * posted when either the "initial" timer * or the "autopop" timer times out. * We'll show or hide the tooltip then. */ case WM_TIMER: // done if (!TtmTimer(hwndTooltip, mp1)) mrc = WinDefWindowProc(hwndTooltip, msg, mp1, mp2); break; /* * WM_PAINT: * */ case WM_PAINT: // done TtmPaint(hwndTooltip); break; /* * WM_PRESPARAMCHANGED: * presentation parameter has changed. */ case WM_PRESPARAMCHANGED: switch ((LONG)mp1) // pp index { case 0: // layout palette thing dropped case PP_MENUBACKGROUNDCOLOR: case PP_MENUFOREGROUNDCOLOR: case PP_MENUHILITEFGNDCOLOR: case PP_MENUHILITEBGNDCOLOR: // re-query our presparams UpdateTooltipPresColors(hwndTooltip); } break; /* * WM_SYSCOLORCHANGE: * system color has changed. */ case WM_SYSCOLORCHANGE: UpdateTooltipPresColors(hwndTooltip); break; /* * WM_DESTROY: * clean up upon destruction. */ case WM_DESTROY: TtmDestroy(hwndTooltip); break; /* *@@ TTM_ACTIVATE: * activates or deactives the tooltip control. * * Parameters: * -- BOOL mp1: if TRUE, activate, if FALSE, deactivate. * -- mp2: always 0. * * Return value: 0 always. */ case TTM_ACTIVATE: // done { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); if (!(pttd->fIsActive = (BOOL)mp1)) // disable: hide tooltip WinPostMsg(hwndTooltip, TTM_SHOWTOOLTIPNOW, (MPARAM)FALSE, 0); } break; /* *@@ TTM_ADDTOOL: * registers a tool with a tooltip control. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: information about the tool. * * Return value: TRUE if successful or FALSE otherwise. * * A tooltip control can support any number of tools. To * support a particular tool, you must register the tool * with the tooltip control by sending the TTM_ADDTOOL * message to the tooltip control. The message includes * the address of a TOOLINFO structure, which provides * information the tooltip control needs to display text * for the tool. * * A tooltip control supports tools implemented as windows * (such as child windows or control windows) and as * rectangular areas within a window's client area. * * -- When you add a tool implemented as a rectangular * area, the "hwndToolOwner" member of TOOLINFO must * specify the handle of the window that contains the * area, and the "rect" member must specify the client * coordinates of the area's bounding rectangle. * * -- When you add a tool implemented as a window, the * "hwndTool" member of TOOLINFO must contain the * window handle of the tool. hwndToolOwner should be * the owner of the tool. * * When you add a tool to a tooltip control, the "pszText" * member of the TOOLINFO structure must specify the string * to display for the tool. You can change the text any time * after adding the tool by using the TTM_UPDATETIPTEXT message. * * If you specify the PSZ_TEXTCALLBACK value in the pszText * member, whenever the tooltip control needs the text for the * tool, it sends a WM_CONTROL message to hwndToolOwner with * the TTN_NEEDTEXT notification code. * * The message includes the address of a TOOLTIPTEXT structure, * which contains the window handle of the tool. You can then * fill the TOOLTIPTEXT structure with the tool text. * * To retrieve the text for a tool, use the TTM_GETTEXT message. * *@@todo: add tool rectangles */ case TTM_ADDTOOL: // done mrc = TtmAddTool(hwndTooltip, mp2); break; /* *@@ TTM_DELTOOL: * removes a tool from a tooltip control. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: information about the tool; * all fields except cbSize, hwndToolOwner, * and hwndTool are ignored. * * Return value: 0 always. */ case TTM_DELTOOL: // done TtmDelTool(hwndTooltip, mp2); break; /* *@@ TTM_NEWTOOLRECT: * sets a new bounding rectangle for a tool * already registered with a tooltip control. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: information about the tool; * all fields except hwnd, uID, and rect * are ignored. * * Return value: 0 always. * * If an application includes a tool implemented as a rectangular * area and the size or position of the control changes, it can * use the TTM_NEWTOOLRECT message to report the change to the * tooltip control. An application does not need to report size * and position changes for a tool implemented as a window. * Reporting that is not necessary because the tooltip control * uses the window handle of a tool to determine if the cursor * is on the tool, not the tool's bounding rectangle. */ case TTM_NEWTOOLRECT: break; /* *@@ TTM_RELAYEVENT: * passes a mouse message to a tooltip control * for further processing. * * Parameters: * -- mp1: always 0. * -- PQMSG mp2: pointer to a QMSG struct (Win95: MSG struct) * containing a mouse message. Only the above messages * are processed. * * Return value: 0 always. * * A tooltip control needs to receive mouse messages to determine * when to display the tooltip window. Because mouse messages are * sent only to the window that contains the cursor, you must * use the TTM_RELAYEVENT message to relay mouse messages to the * tooltip control. * * If a tool is implemented as a rectangular area in an * application-defined window, the window procedure receives all * mouse messages and can relay the ones listed below to the * tooltip control, using this message. * * However, if a tool is implemented as a system-defined window, * the mouse messages are sent to that window and are not readily * available to the application. There are two ways you can have * the tooltip control notified of these mouse messages: * * -- You can specify the TTF_SUBCLASS flag when adding the tool * to the tooltip control. The tooltip control will then subclass * the tool window to get mouse-related messages, and you're off. * * -- You can implement a message hook for your process and check * for your tool windows there and send TTM_RELAYEVENT to the * tooltip control. In that case, you need to intercept the * messages specified below. * * When a tooltip control receives a relayed WM_MOUSEMOVE message, * it determines whether the cursor is in the bounding rectangle of * a tool. If the cursor is there, the tooltip control sets a timer. * At the end of the time-out duration, the tooltip control checks * the position of the cursor to see whether it has moved. If the * cursor has not, the tooltip control retrieves the text for the tool, * copies the text into the tooltip window, and shows the window. * The tooltip control continues to show the window until it receives * a relayed button-up or button-down message or until a relayed * WM_MOUSEMOVE message indicates that the cursor has moved outside * the bounding rectangle of the tool. * * For the timer descriptions, see TTM_SETDELAYTIME. * * When it is about to be displayed, a tootip control sends the * TTN_SHOW notification to the owner window. A tooltip control * sends the TTN_POP notification when it is about to be hidden. * Each notification is sent in the context of a WM_NOTIFY message * (OS/2: WM_CONTROL). * * Relevant messages: * -- WM_MOUSEMOVE * -- WM_BUTTON1DOWN (Win95: WM_LBUTTONDOWN) * -- WM_BUTTON1UP (Win95: WM_LBUTTONUP) * -- WM_BUTTON2DOWN (Win95: WM_RBUTTONDOWN) * -- WM_BUTTON2UP (Win95: WM_RBUTTONUP) * -- WM_BUTTON3DOWN (Win95: WM_MBUTTONDOWN) * -- WM_BUTTON3UP (Win95: WM_MBUTTONUP) */ case TTM_RELAYEVENT: TtmRelayEvent(hwndTooltip, mp2); break; /* *@@ TTM_GETDELAYTIME: * returns the current value of the specified * timeout value. See TTM_SETDELAYTIME. * * Parameters: * * -- USHORT mp1: timer value to query. One of: * -- TTDT_AUTOPOP * -- TTDT_INITIAL * -- TTDT_RESHOW * * Returns: ULONG timeout value. * *@@added V0.9.12 (2001-04-28) [umoeller] */ case TTM_GETDELAYTIME: mrc = TtmGetDelayTime(hwndTooltip, mp1); break; /* *@@ TTM_SETDELAYTIME: * overrides a few default timeout values for the * tooltip control. * * A tooltip control actually has three time-out durations * associated with it. The initial duration is the length * of time that the cursor must remain stationary within * the bounding rectangle of a tool before the tooltip window * is displayed. The reshow duration is the length of the delay * before subsequent tooltip windows are displayed when the * cursor moves from one tool to another. The autopopup duration * is the length of time that the tooltip window remains * displayed before it is hidden. That is, if the cursor remains * stationary within the bounding rectangle after the tooltip * window is displayed, the tooltip window is automatically * hidden at the end of the autopopup duration. * * You can adjust all of the time-out durations by using this * message. * * Parameters: * -- USHORT mp1: parameter selection. One of the following: * -- TTDT_AUTOMATIC: automatically calculates the initial, * reshow, and autopopup durations based on the value of mp2. * -- TTDT_AUTOPOP: sets the length of time before the tooltip * window is hidden if the cursor remains stationary * in the tool's bounding rectangle after the tooltip window * has appeared. * -- TTDT_INITIAL: sets the length of time that the cursor must * remain stationary within the bounding rectangle of * a tool before the tooltip window is displayed. * -- TTDT_RESHOW: sets the length of the delay before subsequent * tooltip windows are displayed when the cursor is moved * from one tool to another. * -- ULONG mp2: new duration, in milliseconds. * * Return value: 0 always. */ case TTM_SETDELAYTIME: // done TtmSetDelayTime(hwndTooltip, mp1, mp2); break; /* *@@ TTM_GETTEXT: * retrieves the text for a tool in the tooltip control. * * Parameters: * -- mp1: always 0 * -- PTOOLINFO mp2: pointer to a TOOLINFO structure. * hwndTool identifies a tool. If the tooltip control * includes the tool, the pszText member receives * the pointer to the string on output. * * Return value: 0 always. * * Additional note: On input, if TOOLINFO.lpszText == PSZ_TEXTCALLBACK, * this sends the TTN_NEEDTEXT notification to TOOLINFO.hwnd. * */ case TTM_GETTEXT: // done, I think TtmGetText(hwndTooltip, mp2); break; /* *@@ TTM_UPDATETIPTEXT: * sets the current tooltip text explicitly, * no matter for what tool the tooltip is * currently being displayed. This might be * useful if you want to dynamically update * the tooltip display. * * If the tooltip is currently showing, * it is reformatted with the new text. * * Note that the change is not permanent; * if the mouse moves over a different * tool next, the change will be lost. * * Parameters: * -- PSZ mp1: new text to display. * *@@added V0.9.13 (2001-06-21) [umoeller] */ case TTM_UPDATETIPTEXT: TtmUpdateTipText(hwndTooltip, (PSZ)mp1); break; /* *@@ TTM_HITTEST: * tests a point to determine whether it is within the * bounding rectangle of the specified tool and, if the * point is within, retrieves information about the tool. * * Parameters: * -- mp1: always 0. * -- PHITTESTINFO mp2: pointer to a TTHITTESTINFO structure. * When sending the message, the "hwnd" member must specify * the handle of a tool and the "pt" member must specify the * coordinates of a point. If the return value is TRUE, the * "ti" member receives information about the tool that * occupies the point. * * Return value: returns TRUE if the tool occupies the specified * point or FALSE otherwise. */ case TTM_HITTEST: break; /* *@@ TTM_WINDOWFROMPOINT: * this message allows a subclass procedure to cause a tooltip * to display text for a window other than the one beneath the * mouse cursor. * * Parameters: * -- mp1: always 0. * -- mp2: PPOINTL lppt (Win95: (POINT FAR *)lppt): * pointer to a POINTL structure that defines the point to be checked. * * Return value: the handle to the window that contains the point, or * NULL if no window exists at the specified point. * * This message is intended to be processed by an application that * subclasses a tooltip. It is not intended to be sent by an * application. A tooltip sends this message to itself before * displaying the text for a window. By changing the coordinates * of the point specified by lppt, the subclass procedure can cause * the tooltip to display text for a window other than the one * beneath the mouse cursor. */ case TTM_WINDOWFROMPOINT: break; /* *@@ TTM_ENUMTOOLS: * this message retrieves the information that a tooltip control * maintains about a certain tool. * * Parameters: * -- USHORT mp1: zero-based index of the tool for which to * retrieve information. * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that * receives information about the tool. Before sending * this message, the cbSize member must specify the size * of the structure. * * Return value: TRUE if any tools are enumerated or FALSE otherwise. */ case TTM_ENUMTOOLS: // done mrc = TtmEnumTools(hwndTooltip, mp1, mp2); break; /* *@@ TTM_GETCURRENTTOOL: * this message retrieves the information that the * tooltip control maintains for the _current_ tool; * that is, the one for which the tooltip control * is currently displaying text. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that receives * information about the current tool. * * Return value: TRUE if successful or FALSE otherwise. */ case TTM_GETCURRENTTOOL: // done mrc = TtmGetCurrentTool(hwndTooltip, mp2); break; /* *@@ TTM_GETTOOLCOUNT: * returns the number of tools in the tooltip control. * * No parameters. */ case TTM_GETTOOLCOUNT: // done { PTOOLTIPDATA pttd = (PTOOLTIPDATA)WinQueryWindowPtr(hwndTooltip, 1); mrc = (MPARAM)lstCountItems(&pttd->llTools); } break; /* *@@ TTM_GETTOOLINFO: * this message retrieves the information that a tooltip * control maintains about a tool. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: * pointer to a TOOLINFO structure. When sending the message, * the hwnd and uId members identify a tool, and the cbSize * member must specify the size of the structure. If the * tooltip control includes the tool, the structure receives * information about the tool. * * Return value: TRUE if successful or FALSE otherwise. */ case TTM_GETTOOLINFO: // done mrc = TtmGetToolInfo(hwndTooltip, mp2); break; /* *@@ TTM_SETTOOLINFO: * this message sets the information that a tooltip control * maintains for a tool. * * Parameters: * -- mp1: always 0. * -- PTOOLINFO mp2: pointer to a TOOLINFO structure that * specifies the information to set. * * Return value: 0 always. */ case TTM_SETTOOLINFO: break; /* *@@ TTM_SHOWTOOLTIPNOW: * depending on BOOL mp1, shows or hides the tooltip. * This is required because we cannot show or hide * the window during processing of WM_MOUSEMOVE etc, * which will lead to strange PM hangs. * * This is not part of the Win95 message set but used * in the OS/2 implementation only. This calls * TtmShowTooltip in turn. */ case TTM_SHOWTOOLTIPNOW: TtmShowTooltip(hwndTooltip, (BOOL)mp1); break; default: mrc = WinDefWindowProc(hwndTooltip, msg, mp1, mp2); } } CATCH(excpt1) { mrc = 0; // XWP V1.0.4 (2005-10-09) [pr] } END_CATCH(); return mrc; }