https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bbca71c4a5604f4919d79…
commit bbca71c4a5604f4919d792c4b414ae84a05c4594
Author: David Quintana <gigaherz(a)gmail.com>
AuthorDate: Fri Jan 19 16:39:46 2018 +0100
Commit: David Quintana <gigaherz(a)gmail.com>
CommitDate: Tue Jan 23 22:13:01 2018 +0100
[EXPLORER] Implement rudimentary uVersion management, and notification balloons.
- uVersion will only be truly useful when Vista+'s V4 style notification icons are
implemented.
- Balloon notifications do not yet support queuing and auto-closing.
- Force the notification icon tooltips to always show even if the taskbar isn't
foreground.
[ROSCTRLS.H] Implement CTooltips class which manages a comctl32 tooltips window.
---
base/shell/explorer/trayntfy.cpp | 217 +++++++++++++++++++++++++++++++++----
sdk/include/reactos/rosctrls.h | 225 +++++++++++++++++++++++++++++++++++++++
2 files changed, 421 insertions(+), 21 deletions(-)
diff --git a/base/shell/explorer/trayntfy.cpp b/base/shell/explorer/trayntfy.cpp
index 1864e33e96..7e13d9f131 100644
--- a/base/shell/explorer/trayntfy.cpp
+++ b/base/shell/explorer/trayntfy.cpp
@@ -34,6 +34,12 @@ typedef struct _SYS_PAGER_COPY_DATA
NOTIFYICONDATA nicon_data;
} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
+struct InternalIconData : NOTIFYICONDATA
+{
+ // Must keep a separate copy since the original is unioned with uTimeout.
+ UINT uVersionCopy;
+};
+
struct IconWatcherData
{
@@ -310,15 +316,22 @@ private:
class CNotifyToolbar :
- public CWindowImplBaseT< CToolbar<NOTIFYICONDATA>, CControlWinTraits >
+ public CWindowImplBaseT< CToolbar<InternalIconData>, CControlWinTraits >
{
HIMAGELIST m_ImageList;
int m_VisibleButtonCount;
+ HWND m_BalloonsParent;
+ CTooltips * m_Balloons;
+ InternalIconData * m_currentTooltip;
+
public:
CNotifyToolbar() :
m_ImageList(NULL),
- m_VisibleButtonCount(0)
+ m_VisibleButtonCount(0),
+ m_BalloonsParent(NULL),
+ m_Balloons(NULL),
+ m_currentTooltip(NULL)
{
}
@@ -331,15 +344,13 @@ public:
return m_VisibleButtonCount;
}
- int FindItem(IN HWND hWnd, IN UINT uID, NOTIFYICONDATA ** pdata)
+ int FindItem(IN HWND hWnd, IN UINT uID, InternalIconData ** pdata)
{
int count = GetButtonCount();
for (int i = 0; i < count; i++)
{
- NOTIFYICONDATA * data;
-
- data = GetItemData(i);
+ InternalIconData * data = GetItemData(i);
if (data->hWnd == hWnd &&
data->uID == uID)
@@ -358,7 +369,7 @@ public:
int count = GetButtonCount();
for (int i = 0; i < count; i++)
{
- NOTIFYICONDATA * data = GetItemData(i);
+ InternalIconData * data = GetItemData(i);
if (data->hIcon == handle)
{
TBBUTTON btn;
@@ -373,7 +384,7 @@ public:
BOOL AddButton(IN CONST NOTIFYICONDATA *iconData)
{
TBBUTTON tbBtn;
- NOTIFYICONDATA * notifyItem;
+ InternalIconData * notifyItem;
WCHAR text[] = L"";
TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s",
@@ -390,7 +401,7 @@ public:
return FALSE;
}
- notifyItem = new NOTIFYICONDATA();
+ notifyItem = new InternalIconData();
ZeroMemory(notifyItem, sizeof(*notifyItem));
notifyItem->hWnd = iconData->hWnd;
@@ -437,6 +448,16 @@ public:
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip),
iconData->szTip);
}
+ if (iconData->uFlags & NIF_INFO)
+ {
+ // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility
settings are used always.
+ StrNCpy(notifyItem->szInfo, iconData->szInfo,
_countof(notifyItem->szInfo));
+ StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle,
_countof(notifyItem->szInfo));
+ notifyItem->dwInfoFlags = iconData->dwInfoFlags;
+ notifyItem->uTimeout = iconData->uTimeout;
+
+ }
+
m_VisibleButtonCount++;
if (notifyItem->dwState & NIS_HIDDEN)
{
@@ -444,17 +465,45 @@ public:
m_VisibleButtonCount--;
}
- /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+ /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
CToolbar::AddButton(&tbBtn);
SetButtonSize(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
+ if (iconData->uFlags & NIF_INFO)
+ {
+ UpdateBalloonTip(notifyItem);
+ }
+
+ return TRUE;
+ }
+
+ BOOL SwitchVersion(IN CONST NOTIFYICONDATA *iconData)
+ {
+ InternalIconData * notifyItem;
+ int index = FindItem(iconData->hWnd, iconData->uID, ¬ifyItem);
+ if (index < 0)
+ {
+ WARN("Icon %d from hWnd %08x DOES NOT EXIST!", iconData->uID,
iconData->hWnd);
+ return FALSE;
+ }
+
+ if (iconData->uVersion != 0 && iconData->uVersion !=
NOTIFYICON_VERSION)
+ {
+ WARN("Tried to set the version of icon %d from hWnd %08x, to an unknown
value %d. Vista+ program?", iconData->uID, iconData->hWnd,
iconData->uVersion);
+ return FALSE;
+ }
+
+ // We can not store the version in the uVersion field, because it's
union'd with uTimeout,
+ // which we also need to keep track of.
+ notifyItem->uVersionCopy = iconData->uVersion;
+
return TRUE;
}
BOOL UpdateButton(IN CONST NOTIFYICONDATA *iconData)
{
- NOTIFYICONDATA * notifyItem;
+ InternalIconData * notifyItem;
TBBUTTONINFO tbbi = { 0 };
TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s",
@@ -536,16 +585,30 @@ public:
StringCchCopy(notifyItem->szTip, _countof(notifyItem->szTip),
iconData->szTip);
}
- /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+ if (iconData->uFlags & NIF_INFO)
+ {
+ // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility
settings are used always.
+ StrNCpy(notifyItem->szInfo, iconData->szInfo,
_countof(notifyItem->szInfo));
+ StrNCpy(notifyItem->szInfoTitle, iconData->szInfoTitle,
_countof(notifyItem->szInfo));
+ notifyItem->dwInfoFlags = iconData->dwInfoFlags;
+ notifyItem->uTimeout = iconData->uTimeout;
+ }
+
+ /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
SetButtonInfo(index, &tbbi);
+ if (iconData->uFlags & NIF_INFO)
+ {
+ UpdateBalloonTip(notifyItem);
+ }
+
return TRUE;
}
BOOL RemoveButton(IN CONST NOTIFYICONDATA *iconData)
{
- NOTIFYICONDATA * notifyItem;
+ InternalIconData * notifyItem;
TRACE("Removing icon %d from hWnd %08x", iconData->uID,
iconData->hWnd);
@@ -587,16 +650,86 @@ public:
}
}
- delete notifyItem;
+ HideBalloonTip(notifyItem);
+
DeleteButton(index);
+ delete notifyItem;
+
return TRUE;
}
+ void UpdateBalloonTip(InternalIconData* notifyItem)
+ {
+ size_t len = 0;
+ if (SUCCEEDED(StringCchLength(notifyItem->szInfo,
_countof(notifyItem->szInfo), &len)) && len > 0)
+ {
+ ShowBalloonTip(notifyItem);
+ }
+ else
+ {
+ HideBalloonTip(notifyItem);
+ }
+ }
+
+ static WPARAM GetTitleIcon(DWORD dwFlags, HICON hIcon)
+ {
+ if (dwFlags & NIIF_USER)
+ return reinterpret_cast<WPARAM>(hIcon);
+
+ return dwFlags & 3;
+ }
+
+ BOOL ShowBalloonTip(IN OUT InternalIconData *notifyItem)
+ {
+ DbgPrint("ShowBalloonTip called for flags=%x text=%ws; title=%ws",
notifyItem->dwInfoFlags, notifyItem->szInfo, notifyItem->szInfoTitle);
+
+ // TODO: Queueing -> NIF_REALTIME? (Vista+)
+ // TODO: NIIF_NOSOUND, Vista+ flags
+
+ const WPARAM icon = GetTitleIcon(notifyItem->dwInfoFlags,
notifyItem->hIcon);
+ BOOL ret = m_Balloons->SetTitle(notifyItem->szInfoTitle, icon);
+ if (!ret)
+ DbgPrint("SetTitle failed, GetLastError=%d", GetLastError());
+
+ const int index = FindItem(notifyItem->hWnd, notifyItem->uID, NULL);
+ RECT rc;
+ GetItemRect(index, &rc);
+ ClientToScreen(&rc); // I have no idea why this is needed! >_<
+ WORD x = (rc.left + rc.right) / 2;
+ WORD y = (rc.top + rc.bottom) / 2;
+ DbgPrint("ClientToScreen returned (%d, %d, %d, %d) x=%d, y=%d",
+ rc.left, rc.top,
+ rc.right, rc.bottom, x, y);
+ m_Balloons->TrackPosition(x, y);
+ m_Balloons->UpdateTipText(m_BalloonsParent,
reinterpret_cast<LPARAM>(m_hWnd), notifyItem->szInfo);
+ m_Balloons->TrackActivate(m_BalloonsParent,
reinterpret_cast<LPARAM>(m_hWnd));
+ m_currentTooltip = notifyItem;
+
+ return TRUE;
+ }
+
+ VOID HideBalloonTip(IN OUT InternalIconData *notifyItem)
+ {
+ DbgPrint("HideBalloonTip called");
+
+ if (m_currentTooltip == notifyItem)
+ {
+ // Prevent Re-entry
+ m_currentTooltip = NULL;
+ m_Balloons->TrackDeactivate();
+ }
+ }
+
+ VOID HideCurrentBalloon()
+ {
+ if (m_currentTooltip != NULL)
+ HideBalloonTip(m_currentTooltip);
+ }
+
VOID GetTooltipText(int index, LPTSTR szTip, DWORD cchTip)
{
- NOTIFYICONDATA * notifyItem;
- notifyItem = GetItemData(index);
+ InternalIconData * notifyItem = GetItemData(index);
if (notifyItem)
{
@@ -626,7 +759,7 @@ public:
int count = GetButtonCount();
for (int i = 0; i < count; i++)
{
- NOTIFYICONDATA * data = GetItemData(i);
+ InternalIconData * data = GetItemData(i);
BOOL hasSharedIcon = data->dwState & NIS_SHAREDICON;
INT iIcon = hasSharedIcon ? FindExistingSharedIcon(data->hIcon) : -1;
if (iIcon < 0)
@@ -659,7 +792,7 @@ private:
L"WM_XBUTTONDBLCLK"
};
- NOTIFYICONDATA * notifyItem = GetItemData(wIndex);
+ InternalIconData * notifyItem = GetItemData(wIndex);
if (!::IsWindow(notifyItem->hWnd))
{
@@ -770,15 +903,17 @@ private:
return 0;
}
-
public:
BEGIN_MSG_MAP(CNotifyToolbar)
MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent)
NOTIFY_CODE_HANDLER(TTN_SHOW, OnTooltipShow)
END_MSG_MAP()
- void Initialize(HWND hWndParent)
+ void Initialize(HWND hWndParent, CTooltips * tooltips)
{
+ m_BalloonsParent = hWndParent;
+ m_Balloons = tooltips;
+
DWORD styles =
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
@@ -786,6 +921,13 @@ public:
SubclassWindow(CToolbar::Create(hWndParent, styles));
+ // Force the toolbar tooltips window to always show tooltips even if not
foreground
+ HWND tooltipsWnd = (HWND)SendMessageW(TB_GETTOOLTIPS);
+ if (tooltipsWnd)
+ {
+ ::SetWindowLong(tooltipsWnd, GWL_STYLE, ::GetWindowLong(tooltipsWnd,
GWL_STYLE) | TTS_ALWAYSTIP);
+ }
+
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 1000);
@@ -810,6 +952,8 @@ class CSysPagerWnd :
{
CNotifyToolbar Toolbar;
+ CTooltips m_Balloons;
+
public:
CSysPagerWnd() {}
virtual ~CSysPagerWnd() {}
@@ -839,9 +983,27 @@ public:
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
- Toolbar.Initialize(m_hWnd);
+ Toolbar.Initialize(m_hWnd, &m_Balloons);
CIconWatcher::Initialize(m_hWnd);
+ HWND hWndTop = GetAncestor(m_hWnd, GA_ROOT);
+
+ m_Balloons.Create(hWndTop, TTS_NOPREFIX | TTS_BALLOON | TTS_CLOSE);
+
+ TOOLINFOW ti = { 0 };
+ ti.cbSize = TTTOOLINFOW_V1_SIZE;
+ ti.uFlags = TTF_TRACK | TTF_IDISHWND;
+ ti.uId = reinterpret_cast<UINT_PTR>(Toolbar.m_hWnd);
+ ti.hwnd = m_hWnd;
+ ti.lpszText = NULL;
+ ti.lParam = NULL;
+
+ BOOL ret = m_Balloons.AddTool(&ti);
+ if (!ret)
+ {
+ DbgPrint("AddTool failed, LastError=%d (probably meaningless unless
non-zero)", GetLastError());
+ }
+
// Explicitly request running applications to re-register their systray icons
::SendNotifyMessageW(HWND_BROADCAST,
RegisterWindowMessageW(L"TaskbarCreated"),
@@ -890,6 +1052,11 @@ public:
(void)RemoveIconFromWatcher(iconData);
}
break;
+ case NIM_SETFOCUS:
+ Toolbar.SetFocus();
+ ret = TRUE;
+ case NIM_SETVERSION:
+ ret = Toolbar.SwitchVersion(iconData);
default:
TRACE("NotifyIconCmd received with unknown code %d.\n",
data->notify_code);
return FALSE;
@@ -996,6 +1163,13 @@ public:
return 0;
}
+ LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr , BOOL& bHandled)
+ {
+ Toolbar.HideCurrentBalloon();
+ bHandled = TRUE;
+ return 0;
+ }
+
void ResizeImagelist()
{
Toolbar.ResizeImagelist();
@@ -1009,6 +1183,7 @@ public:
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
+ NOTIFY_CODE_HANDLER(TTN_POP, OnBalloonPop)
NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip)
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
END_MSG_MAP()
diff --git a/sdk/include/reactos/rosctrls.h b/sdk/include/reactos/rosctrls.h
index a5976416d8..f332aca915 100644
--- a/sdk/include/reactos/rosctrls.h
+++ b/sdk/include/reactos/rosctrls.h
@@ -581,3 +581,228 @@ public:
}
};
+
+class CTooltips :
+ public CWindow
+{
+public: // Configuration methods
+
+ HWND Create(HWND hWndParent, DWORD dwStyles = WS_POPUP | TTS_NOPREFIX, DWORD
dwExStyles = WS_EX_TOPMOST)
+ {
+ RECT r = { 0 };
+ return CWindow::Create(TOOLTIPS_CLASS, hWndParent, r, L"", dwStyles,
dwExStyles);
+ }
+
+public: // Relay event
+
+ // Win7+: Can use GetMessageExtraInfo to provide the WPARAM value.
+ VOID RelayEvent(MSG * pMsg, WPARAM extraInfo = 0)
+ {
+ SendMessageW(TTM_RELAYEVENT, extraInfo, reinterpret_cast<LPARAM>(pMsg));
+ }
+
+public: // Helpers
+
+ INT GetToolCount()
+ {
+ return SendMessageW(TTM_GETTOOLCOUNT, 0, 0);
+ }
+
+ BOOL AddTool(IN CONST TTTOOLINFOW * pInfo)
+ {
+ return SendMessageW(TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ VOID DelTool(IN HWND hwndToolOwner, IN UINT uId)
+ {
+ TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
+ info.hwnd = hwndToolOwner;
+ info.uId = uId;
+ SendMessageW(TTM_DELTOOL, 0, reinterpret_cast<LPARAM>(&info));
+ }
+
+ VOID NewToolRect(IN HWND hwndToolOwner, IN UINT uId, IN RECT rect)
+ {
+ TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
+ info.hwnd = hwndToolOwner;
+ info.uId = uId;
+ info.rect = rect;
+ SendMessageW(TTM_NEWTOOLRECT, 0, reinterpret_cast<LPARAM>(&info));
+ }
+
+ BOOL GetToolInfo(IN HWND hwndToolOwner, IN UINT uId, IN OUT TTTOOLINFOW * pInfo)
+ {
+ pInfo->hwnd = hwndToolOwner;
+ pInfo->uId = uId;
+ return SendMessageW(TTM_GETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ VOID SetToolInfo(IN CONST TTTOOLINFOW * pInfo)
+ {
+ SendMessageW(TTM_SETTOOLINFO, 0, reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ BOOL HitTest(IN CONST TTHITTESTINFOW * pInfo)
+ {
+ return SendMessageW(TTM_HITTEST, 0, reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ VOID GetText(IN HWND hwndToolOwner, IN UINT uId, OUT PWSTR pBuffer, IN DWORD
cchBuffer)
+ {
+ TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
+ info.hwnd = hwndToolOwner;
+ info.uId = uId;
+ info.lpszText = pBuffer;
+ SendMessageW(TTM_GETTEXT, cchBuffer, reinterpret_cast<LPARAM>(&info));
+ }
+
+ VOID UpdateTipText(IN HWND hwndToolOwner, IN UINT uId, IN PCWSTR szText, IN HINSTANCE
hinstResourceOwner = NULL)
+ {
+ TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
+ info.hwnd = hwndToolOwner;
+ info.uId = uId;
+ info.lpszText = const_cast<PWSTR>(szText);
+ info.hinst = hinstResourceOwner;
+ SendMessageW(TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
+ }
+
+ BOOL EnumTools(IN CONST TTTOOLINFOW * pInfo)
+ {
+ return SendMessageW(TTM_ENUMTOOLS, 0, reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ BOOL GetCurrentTool(OUT OPTIONAL TTTOOLINFOW * pInfo = NULL)
+ {
+ return SendMessageW(TTM_GETCURRENTTOOL, 0,
reinterpret_cast<LPARAM>(pInfo));
+ }
+
+ VOID GetTitle(TTGETTITLE * pTitleInfo)
+ {
+ SendMessageW(TTM_GETTITLE, 0, reinterpret_cast<LPARAM>(pTitleInfo));
+ }
+
+ BOOL SetTitle(PCWSTR szTitleText, WPARAM icon = 0)
+ {
+ return SendMessageW(TTM_SETTITLE, icon,
reinterpret_cast<LPARAM>(szTitleText));
+ }
+
+ VOID TrackActivate(IN HWND hwndToolOwner, IN UINT uId)
+ {
+ TTTOOLINFOW info = { sizeof(TTTOOLINFOW), 0 };
+ info.hwnd = hwndToolOwner;
+ info.uId = uId;
+ SendMessageW(TTM_TRACKACTIVATE, TRUE,
reinterpret_cast<LPARAM>(&info));
+ }
+
+ VOID TrackDeactivate()
+ {
+ SendMessageW(TTM_TRACKACTIVATE, FALSE, NULL);
+ }
+
+ VOID TrackPosition(IN WORD x, IN WORD y)
+ {
+ SendMessageW(TTM_TRACKPOSITION, 0, MAKELPARAM(x, y));
+ }
+
+ // Opens the tooltip
+ VOID Popup()
+ {
+ SendMessageW(TTM_POPUP);
+ }
+
+ // Closes the tooltip - Pressing the [X] for a TTF_CLOSE balloon is equivalent to
calling this
+ VOID Pop()
+ {
+ SendMessageW(TTM_POP);
+ }
+
+ // Delay times for AUTOMATIC tooltips (they don't affect balloons)
+ INT GetDelayTime(UINT which)
+ {
+ return SendMessageW(TTM_GETDELAYTIME, which);
+ }
+
+ VOID SetDelayTime(UINT which, WORD time)
+ {
+ SendMessageW(TTM_SETDELAYTIME, which, MAKELPARAM(time, 0));
+ }
+
+ // Activates or deactivates the automatic tooltip display when hovering a control
+ VOID Activate(IN BOOL bActivate = TRUE)
+ {
+ SendMessageW(TTM_ACTIVATE, bActivate);
+ }
+
+ // Adjusts the position of a tooltip when used to display trimmed text
+ VOID AdjustRect(IN BOOL bTextToWindow, IN OUT RECT * pRect)
+ {
+ SendMessageW(TTM_ADJUSTRECT, bTextToWindow,
reinterpret_cast<LPARAM>(pRect));
+ }
+
+ // Useful for TTF_ABSOLUTE|TTF_TRACK tooltip positioning
+ SIZE GetBubbleSize(IN TTTOOLINFOW * pInfo)
+ {
+ DWORD ret = SendMessageW(TTM_GETBUBBLESIZE, 0,
reinterpret_cast<LPARAM>(pInfo));
+ const SIZE sz = { LOWORD(ret), HIWORD(ret) };
+ return sz;
+ }
+
+ // Fills the RECT with the margin size previously set. Default is 0 margins.
+ VOID GetMargin(OUT RECT * pRect)
+ {
+ SendMessageW(TTM_GETMARGIN, 0, reinterpret_cast<LPARAM>(pRect));
+ }
+
+ VOID SetMargin(IN RECT * pRect)
+ {
+ SendMessageW(TTM_SETMARGIN, 0, reinterpret_cast<LPARAM>(pRect));
+ }
+
+ // Gets a previously established max width. Returns -1 if no limit is set
+ INT GetMaxTipWidth()
+ {
+ return SendMessageW(TTM_GETMAXTIPWIDTH);
+ }
+
+ INT SetMaxTipWidth(IN OPTIONAL INT width = -1)
+ {
+ return SendMessageW(TTM_SETMAXTIPWIDTH, 0, width);
+ }
+
+ // Get the color of the tooltip text
+ COLORREF GetTipTextColor()
+ {
+ return SendMessageW(TTM_GETTIPTEXTCOLOR);
+ }
+
+ VOID SetTipTextColor(IN COLORREF textColor)
+ {
+ SendMessageW(TTM_SETTIPTEXTCOLOR, textColor);
+ }
+
+ COLORREF GetTipBkColor()
+ {
+ return SendMessageW(TTM_GETTIPBKCOLOR);
+ }
+
+ VOID SetTipBkColor(IN COLORREF textColor)
+ {
+ SendMessageW(TTM_SETTIPBKCOLOR, textColor);
+ }
+
+ VOID SetWindowTheme(IN PCWSTR szThemeName)
+ {
+ SendMessageW(TTM_SETWINDOWTHEME, 0,
reinterpret_cast<LPARAM>(szThemeName));
+ }
+
+ // Forces redraw
+ VOID Update()
+ {
+ SendMessageW(TTM_UPDATE);
+ }
+
+ HWND WindowFromPoint(IN POINT * pPoint)
+ {
+ return reinterpret_cast<HWND>(SendMessageW(TTM_WINDOWFROMPOINT, 0,
reinterpret_cast<LPARAM>(pPoint)));
+ }
+};