4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 * Copyright 2018 Ged Murphy <gedmurphy@reactos.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 struct InternalIconData
: NOTIFYICONDATA
26 // Must keep a separate copy since the original is unioned with uTimeout.
30 struct IconWatcherData
34 NOTIFYICONDATA IconData
;
36 IconWatcherData(CONST NOTIFYICONDATA
*iconData
) :
37 hProcess(NULL
), ProcessId(0)
39 IconData
.cbSize
= sizeof(NOTIFYICONDATA
);
40 IconData
.hWnd
= iconData
->hWnd
;
41 IconData
.uID
= iconData
->uID
;
42 IconData
.guidItem
= iconData
->guidItem
;
49 CloseHandle(hProcess
);
56 CAtlList
<IconWatcherData
*> m_WatcherList
;
57 CRITICAL_SECTION m_ListLock
;
58 HANDLE m_hWatcherThread
;
66 virtual ~CIconWatcher();
68 bool Initialize(_In_ HWND hWndParent
);
71 bool AddIconToWatcher(_In_ CONST NOTIFYICONDATA
*iconData
);
72 bool RemoveIconFromWatcher(_In_ CONST NOTIFYICONDATA
*iconData
);
74 IconWatcherData
* GetListEntry(_In_opt_ CONST NOTIFYICONDATA
*iconData
, _In_opt_ HANDLE hProcess
, _In_
bool Remove
);
78 static UINT WINAPI
WatcherThread(_In_opt_ LPVOID lpParam
);
86 static const int TimerInterval
= 2000;
87 static const int BalloonsTimerId
= 1;
88 static const int MinTimeout
= 10000;
89 static const int MaxTimeout
= 30000;
90 static const int CooldownBetweenBalloons
= 2000;
95 InternalIconData
* pSource
;
97 WCHAR szInfoTitle
[64];
101 Info(InternalIconData
* source
)
104 StringCchCopy(szInfo
, _countof(szInfo
), source
->szInfo
);
105 StringCchCopy(szInfoTitle
, _countof(szInfoTitle
), source
->szInfoTitle
);
106 uIcon
= source
->dwInfoFlags
& NIIF_ICON_MASK
;
107 if (source
->dwInfoFlags
== NIIF_USER
)
108 uIcon
= reinterpret_cast<WPARAM
>(source
->hIcon
);
109 uTimeout
= source
->uTimeout
;
115 CTooltips
* m_tooltips
;
117 CAtlList
<Info
> m_queue
;
119 CNotifyToolbar
* m_toolbar
;
121 InternalIconData
* m_current
;
122 bool m_currentClosed
;
129 void Init(HWND hwndParent
, CNotifyToolbar
* toolbar
, CTooltips
* balloons
);
132 bool OnTimer(int timerId
);
133 void UpdateInfo(InternalIconData
* notifyItem
);
134 void RemoveInfo(InternalIconData
* notifyItem
);
139 int IndexOf(InternalIconData
* pdata
);
140 void SetTimer(int length
);
141 void Show(Info
& info
);
142 void Close(IN OUT InternalIconData
* notifyItem
, IN UINT uReason
);
145 class CNotifyToolbar
:
146 public CWindowImplBaseT
< CToolbar
<InternalIconData
>, CControlWinTraits
>
148 HIMAGELIST m_ImageList
;
149 int m_VisibleButtonCount
;
151 CBalloonQueue
* m_BalloonQueue
;
155 virtual ~CNotifyToolbar();
157 int GetVisibleButtonCount();
158 int FindItem(IN HWND hWnd
, IN UINT uID
, InternalIconData
** pdata
);
159 int FindExistingSharedIcon(HICON handle
);
160 BOOL
AddButton(IN CONST NOTIFYICONDATA
*iconData
);
161 BOOL
SwitchVersion(IN CONST NOTIFYICONDATA
*iconData
);
162 BOOL
UpdateButton(IN CONST NOTIFYICONDATA
*iconData
);
163 BOOL
RemoveButton(IN CONST NOTIFYICONDATA
*iconData
);
164 VOID
ResizeImagelist();
165 bool SendNotifyCallback(InternalIconData
* notifyItem
, UINT uMsg
);
168 LRESULT
OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
169 VOID
SendMouseEvent(IN WORD wIndex
, IN UINT uMsg
, IN WPARAM wParam
);
170 LRESULT
OnMouseEvent(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
171 LRESULT
OnTooltipShow(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
);
174 BEGIN_MSG_MAP(CNotifyToolbar
)
175 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnCtxMenu
)
176 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseEvent
)
177 NOTIFY_CODE_HANDLER(TTN_SHOW
, OnTooltipShow
)
180 void Initialize(HWND hWndParent
, CBalloonQueue
* queue
);
184 static const WCHAR szSysPagerWndClass
[] = L
"SysPager";
187 public CComCoClass
<CSysPagerWnd
>,
188 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
189 public CWindowImpl
< CSysPagerWnd
, CWindow
, CControlWinTraits
>,
193 CNotifyToolbar Toolbar
;
194 CTooltips m_Balloons
;
195 CBalloonQueue m_BalloonQueue
;
199 virtual ~CSysPagerWnd();
201 LRESULT
DrawBackground(HDC hdc
);
202 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
203 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
204 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
205 LRESULT
OnGetInfoTip(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
);
206 LRESULT
OnCustomDraw(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
);
207 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
208 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
209 LRESULT
OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
210 LRESULT
OnBalloonPop(UINT uCode
, LPNMHDR hdr
, BOOL
& bHandled
);
211 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
212 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
213 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
214 LRESULT
OnGetMinimumSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
);
218 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
226 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
231 DECLARE_NOT_AGGREGATABLE(CSysPagerWnd
)
233 DECLARE_PROTECT_FINAL_CONSTRUCT()
234 BEGIN_COM_MAP(CSysPagerWnd
)
235 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
238 BOOL
NotifyIcon(DWORD dwMessage
, _In_ CONST NOTIFYICONDATA
*iconData
);
239 void GetSize(IN BOOL IsHorizontal
, IN PSIZE size
);
241 DECLARE_WND_CLASS_EX(szSysPagerWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
243 BEGIN_MSG_MAP(CSysPagerWnd
)
244 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
245 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
246 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
247 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
248 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
249 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnCtxMenu
)
250 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
251 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
252 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
253 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE
, OnGetMinimumSize
)
254 NOTIFY_CODE_HANDLER(TTN_POP
, OnBalloonPop
)
255 NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW
, OnGetInfoTip
)
256 NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW
, OnCustomDraw
)
259 HRESULT
Initialize(IN HWND hWndParent
);
266 CIconWatcher::CIconWatcher() :
267 m_hWatcherThread(NULL
),
274 CIconWatcher::~CIconWatcher()
277 DeleteCriticalSection(&m_ListLock
);
280 CloseHandle(m_WakeUpEvent
);
281 if (m_hWatcherThread
)
282 CloseHandle(m_hWatcherThread
);
285 bool CIconWatcher::Initialize(_In_ HWND hWndParent
)
287 m_hwndSysTray
= hWndParent
;
289 InitializeCriticalSection(&m_ListLock
);
290 m_WakeUpEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
291 if (m_WakeUpEvent
== NULL
)
294 m_hWatcherThread
= (HANDLE
)_beginthreadex(NULL
,
300 if (m_hWatcherThread
== NULL
)
306 void CIconWatcher::Uninitialize()
310 SetEvent(m_WakeUpEvent
);
312 EnterCriticalSection(&m_ListLock
);
315 for (size_t i
= 0; i
< m_WatcherList
.GetCount(); i
++)
317 Pos
= m_WatcherList
.FindIndex(i
);
320 IconWatcherData
*Icon
;
321 Icon
= m_WatcherList
.GetAt(Pos
);
325 m_WatcherList
.RemoveAll();
327 LeaveCriticalSection(&m_ListLock
);
330 bool CIconWatcher::AddIconToWatcher(_In_ CONST NOTIFYICONDATA
*iconData
)
333 (void)GetWindowThreadProcessId(iconData
->hWnd
, &ProcessId
);
336 hProcess
= OpenProcess(SYNCHRONIZE
, FALSE
, ProcessId
);
337 if (hProcess
== NULL
)
342 IconWatcherData
*Icon
= new IconWatcherData(iconData
);
343 Icon
->hProcess
= hProcess
;
344 Icon
->ProcessId
= ProcessId
;
347 EnterCriticalSection(&m_ListLock
);
349 // The likelyhood of someone having more than 64 icons in their tray is
350 // pretty slim. We could spin up a new thread for each multiple of 64, but
351 // it's not worth the effort, so we just won't bother watching those icons
352 if (m_WatcherList
.GetCount() < MAXIMUM_WAIT_OBJECTS
)
354 m_WatcherList
.AddTail(Icon
);
355 SetEvent(m_WakeUpEvent
);
359 LeaveCriticalSection(&m_ListLock
);
369 bool CIconWatcher::RemoveIconFromWatcher(_In_ CONST NOTIFYICONDATA
*iconData
)
371 EnterCriticalSection(&m_ListLock
);
373 IconWatcherData
*Icon
;
374 Icon
= GetListEntry(iconData
, NULL
, true);
376 SetEvent(m_WakeUpEvent
);
377 LeaveCriticalSection(&m_ListLock
);
383 IconWatcherData
* CIconWatcher::GetListEntry(_In_opt_ CONST NOTIFYICONDATA
*iconData
, _In_opt_ HANDLE hProcess
, _In_
bool Remove
)
385 IconWatcherData
*Entry
= NULL
;
386 POSITION NextPosition
= m_WatcherList
.GetHeadPosition();
390 Position
= NextPosition
;
392 Entry
= m_WatcherList
.GetNext(NextPosition
);
395 if ((iconData
&& ((Entry
->IconData
.hWnd
== iconData
->hWnd
) && (Entry
->IconData
.uID
== iconData
->uID
))) ||
396 (hProcess
&& (Entry
->hProcess
== hProcess
)))
399 m_WatcherList
.RemoveAt(Position
);
405 } while (NextPosition
!= NULL
);
410 UINT WINAPI
CIconWatcher::WatcherThread(_In_opt_ LPVOID lpParam
)
412 CIconWatcher
* This
= reinterpret_cast<CIconWatcher
*>(lpParam
);
413 HANDLE
*WatchList
= NULL
;
418 EnterCriticalSection(&This
->m_ListLock
);
421 Size
= This
->m_WatcherList
.GetCount() + 1;
422 ASSERT(Size
<= MAXIMUM_WAIT_OBJECTS
);
426 WatchList
= new HANDLE
[Size
];
427 WatchList
[0] = This
->m_WakeUpEvent
;
430 for (size_t i
= 0; i
< This
->m_WatcherList
.GetCount(); i
++)
432 Pos
= This
->m_WatcherList
.FindIndex(i
);
435 IconWatcherData
*Icon
;
436 Icon
= This
->m_WatcherList
.GetAt(Pos
);
437 WatchList
[i
+ 1] = Icon
->hProcess
;
441 LeaveCriticalSection(&This
->m_ListLock
);
444 Status
= WaitForMultipleObjects(Size
,
448 if (Status
== WAIT_OBJECT_0
)
450 // We've been kicked, we have updates to our list (or we're exiting the thread)
452 TRACE("Updating watched icon list\n");
454 else if ((Status
>= WAIT_OBJECT_0
+ 1) && (Status
< Size
))
456 IconWatcherData
*Icon
;
457 Icon
= This
->GetListEntry(NULL
, WatchList
[Status
], false);
459 TRACE("Pid %lu owns a notification icon and has stopped without deleting it. We'll cleanup on its behalf\n", Icon
->ProcessId
);
461 TRAYNOTIFYDATAW tnid
= {0};
462 tnid
.dwSignature
= NI_NOTIFY_SIG
;
463 tnid
.dwMessage
= NIM_DELETE
;
464 CopyMemory(&tnid
.nid
, &Icon
->IconData
, Icon
->IconData
.cbSize
);
468 data
.cbData
= sizeof(tnid
);
471 BOOL Success
= ::SendMessage(This
->m_hwndSysTray
, WM_COPYDATA
,
472 (WPARAM
)&Icon
->IconData
, (LPARAM
)&data
);
475 // If we failed to handle the delete message, forcibly remove it
476 This
->RemoveIconFromWatcher(&Icon
->IconData
);
481 if (Status
== WAIT_FAILED
)
483 Status
= GetLastError();
485 ERR("Failed to wait on process handles : %lu\n", Status
);
486 This
->Uninitialize();
500 CBalloonQueue::CBalloonQueue() :
505 m_currentClosed(false),
510 void CBalloonQueue::Init(HWND hwndParent
, CNotifyToolbar
* toolbar
, CTooltips
* balloons
)
512 m_hwndParent
= hwndParent
;
514 m_tooltips
= balloons
;
517 void CBalloonQueue::Deinit()
521 ::KillTimer(m_hwndParent
, m_timer
);
525 bool CBalloonQueue::OnTimer(int timerId
)
527 if (timerId
!= m_timer
)
530 ::KillTimer(m_hwndParent
, m_timer
);
533 if (m_current
&& !m_currentClosed
)
535 Close(m_current
, NIN_BALLOONTIMEOUT
);
540 m_currentClosed
= false;
541 if (!m_queue
.IsEmpty())
543 Info info
= m_queue
.RemoveHead();
551 void CBalloonQueue::UpdateInfo(InternalIconData
* notifyItem
)
554 HRESULT hr
= StringCchLength(notifyItem
->szInfo
, _countof(notifyItem
->szInfo
), &len
);
555 if (SUCCEEDED(hr
) && len
> 0)
557 Info
info(notifyItem
);
559 // If m_current == notifyItem, we want to replace the previous balloon even if there is a queue.
560 if (m_current
!= notifyItem
&& (m_current
!= NULL
|| !m_queue
.IsEmpty()))
562 m_queue
.AddTail(info
);
571 Close(notifyItem
, NIN_BALLOONHIDE
);
575 void CBalloonQueue::RemoveInfo(InternalIconData
* notifyItem
)
577 Close(notifyItem
, NIN_BALLOONHIDE
);
579 POSITION position
= m_queue
.GetHeadPosition();
580 while(position
!= NULL
)
582 Info
& info
= m_queue
.GetNext(position
);
583 if (info
.pSource
== notifyItem
)
585 m_queue
.RemoveAt(position
);
590 void CBalloonQueue::CloseCurrent()
592 if (m_current
!= NULL
)
594 Close(m_current
, NIN_BALLOONTIMEOUT
);
598 int CBalloonQueue::IndexOf(InternalIconData
* pdata
)
600 int count
= m_toolbar
->GetButtonCount();
601 for (int i
= 0; i
< count
; i
++)
603 if (m_toolbar
->GetItemData(i
) == pdata
)
609 void CBalloonQueue::SetTimer(int length
)
611 m_timer
= ::SetTimer(m_hwndParent
, BalloonsTimerId
, length
, NULL
);
614 void CBalloonQueue::Show(Info
& info
)
616 TRACE("ShowBalloonTip called for flags=%x text=%ws; title=%ws\n", info
.uIcon
, info
.szInfo
, info
.szInfoTitle
);
618 // TODO: NIF_REALTIME, NIIF_NOSOUND, other Vista+ flags
620 const int index
= IndexOf(info
.pSource
);
622 m_toolbar
->GetItemRect(index
, &rc
);
623 m_toolbar
->ClientToScreen(&rc
);
624 const WORD x
= (rc
.left
+ rc
.right
) / 2;
625 const WORD y
= (rc
.top
+ rc
.bottom
) / 2;
627 m_tooltips
->SetTitle(info
.szInfoTitle
, info
.uIcon
);
628 m_tooltips
->TrackPosition(x
, y
);
629 m_tooltips
->UpdateTipText(m_hwndParent
, reinterpret_cast<LPARAM
>(m_toolbar
->m_hWnd
), info
.szInfo
);
630 m_tooltips
->TrackActivate(m_hwndParent
, reinterpret_cast<LPARAM
>(m_toolbar
->m_hWnd
));
632 m_current
= info
.pSource
;
633 int timeout
= info
.uTimeout
;
634 if (timeout
< MinTimeout
) timeout
= MinTimeout
;
635 if (timeout
> MaxTimeout
) timeout
= MaxTimeout
;
639 m_toolbar
->SendNotifyCallback(m_current
, NIN_BALLOONSHOW
);
642 void CBalloonQueue::Close(IN OUT InternalIconData
* notifyItem
, IN UINT uReason
)
644 TRACE("HideBalloonTip called\n");
646 if (m_current
== notifyItem
&& !m_currentClosed
)
648 m_toolbar
->SendNotifyCallback(m_current
, uReason
);
651 m_currentClosed
= true;
652 m_tooltips
->TrackDeactivate();
653 SetTimer(CooldownBetweenBalloons
);
661 CNotifyToolbar::CNotifyToolbar() :
663 m_VisibleButtonCount(0),
668 CNotifyToolbar::~CNotifyToolbar()
672 int CNotifyToolbar::GetVisibleButtonCount()
674 return m_VisibleButtonCount
;
677 int CNotifyToolbar::FindItem(IN HWND hWnd
, IN UINT uID
, InternalIconData
** pdata
)
679 int count
= GetButtonCount();
681 for (int i
= 0; i
< count
; i
++)
683 InternalIconData
* data
= GetItemData(i
);
685 if (data
->hWnd
== hWnd
&&
697 int CNotifyToolbar::FindExistingSharedIcon(HICON handle
)
699 int count
= GetButtonCount();
700 for (int i
= 0; i
< count
; i
++)
702 InternalIconData
* data
= GetItemData(i
);
703 if (data
->hIcon
== handle
)
714 BOOL
CNotifyToolbar::AddButton(_In_ CONST NOTIFYICONDATA
*iconData
)
716 TBBUTTON tbBtn
= { 0 };
717 InternalIconData
* notifyItem
;
720 TRACE("Adding icon %d from hWnd %08x flags%s%s state%s%s",
721 iconData
->uID
, iconData
->hWnd
,
722 (iconData
->uFlags
& NIF_ICON
) ? " ICON" : "",
723 (iconData
->uFlags
& NIF_STATE
) ? " STATE" : "",
724 (iconData
->dwState
& NIS_HIDDEN
) ? " HIDDEN" : "",
725 (iconData
->dwState
& NIS_SHAREDICON
) ? " SHARED" : "");
727 int index
= FindItem(iconData
->hWnd
, iconData
->uID
, ¬ifyItem
);
730 TRACE("Icon %d from hWnd %08x ALREADY EXISTS!", iconData
->uID
, iconData
->hWnd
);
734 notifyItem
= new InternalIconData();
735 ZeroMemory(notifyItem
, sizeof(*notifyItem
));
737 notifyItem
->hWnd
= iconData
->hWnd
;
738 notifyItem
->uID
= iconData
->uID
;
740 tbBtn
.fsState
= TBSTATE_ENABLED
;
741 tbBtn
.fsStyle
= BTNS_NOPREFIX
;
742 tbBtn
.dwData
= (DWORD_PTR
)notifyItem
;
743 tbBtn
.iString
= (INT_PTR
) text
;
744 tbBtn
.idCommand
= GetButtonCount();
747 if (iconData
->uFlags
& NIF_STATE
)
749 notifyItem
->dwState
= iconData
->dwState
& iconData
->dwStateMask
;
752 if (iconData
->uFlags
& NIF_MESSAGE
)
754 notifyItem
->uCallbackMessage
= iconData
->uCallbackMessage
;
757 if (iconData
->uFlags
& NIF_ICON
)
759 notifyItem
->hIcon
= iconData
->hIcon
;
760 BOOL hasSharedIcon
= notifyItem
->dwState
& NIS_SHAREDICON
;
763 INT iIcon
= FindExistingSharedIcon(notifyItem
->hIcon
);
766 notifyItem
->hIcon
= NULL
;
767 TRACE("Shared icon requested, but HICON not found!!!");
769 tbBtn
.iBitmap
= iIcon
;
773 tbBtn
.iBitmap
= ImageList_AddIcon(m_ImageList
, notifyItem
->hIcon
);
777 if (iconData
->uFlags
& NIF_TIP
)
779 StringCchCopy(notifyItem
->szTip
, _countof(notifyItem
->szTip
), iconData
->szTip
);
782 if (iconData
->uFlags
& NIF_INFO
)
784 // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always.
785 StringCchCopy(notifyItem
->szInfo
, _countof(notifyItem
->szInfo
), iconData
->szInfo
);
786 StringCchCopy(notifyItem
->szInfoTitle
, _countof(notifyItem
->szInfoTitle
), iconData
->szInfoTitle
);
787 notifyItem
->dwInfoFlags
= iconData
->dwInfoFlags
;
788 notifyItem
->uTimeout
= iconData
->uTimeout
;
791 if (notifyItem
->dwState
& NIS_HIDDEN
)
793 tbBtn
.fsState
|= TBSTATE_HIDDEN
;
797 m_VisibleButtonCount
++;
800 /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
802 CToolbar::AddButton(&tbBtn
);
803 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
805 if (iconData
->uFlags
& NIF_INFO
)
807 m_BalloonQueue
->UpdateInfo(notifyItem
);
813 BOOL
CNotifyToolbar::SwitchVersion(_In_ CONST NOTIFYICONDATA
*iconData
)
815 InternalIconData
* notifyItem
;
816 int index
= FindItem(iconData
->hWnd
, iconData
->uID
, ¬ifyItem
);
819 WARN("Icon %d from hWnd %08x DOES NOT EXIST!", iconData
->uID
, iconData
->hWnd
);
823 if (iconData
->uVersion
!= 0 && iconData
->uVersion
!= NOTIFYICON_VERSION
)
825 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
);
829 // We can not store the version in the uVersion field, because it's union'd with uTimeout,
830 // which we also need to keep track of.
831 notifyItem
->uVersionCopy
= iconData
->uVersion
;
836 BOOL
CNotifyToolbar::UpdateButton(_In_ CONST NOTIFYICONDATA
*iconData
)
838 InternalIconData
* notifyItem
;
839 TBBUTTONINFO tbbi
= { 0 };
841 TRACE("Updating icon %d from hWnd %08x flags%s%s state%s%s\n",
842 iconData
->uID
, iconData
->hWnd
,
843 (iconData
->uFlags
& NIF_ICON
) ? " ICON" : "",
844 (iconData
->uFlags
& NIF_STATE
) ? " STATE" : "",
845 (iconData
->dwState
& NIS_HIDDEN
) ? " HIDDEN" : "",
846 (iconData
->dwState
& NIS_SHAREDICON
) ? " SHARED" : "");
848 int index
= FindItem(iconData
->hWnd
, iconData
->uID
, ¬ifyItem
);
851 WARN("Icon %d from hWnd %08x DOES NOT EXIST!\n", iconData
->uID
, iconData
->hWnd
);
852 return AddButton(iconData
);
856 GetButton(index
, &btn
);
857 int oldIconIndex
= btn
.iBitmap
;
859 tbbi
.cbSize
= sizeof(tbbi
);
860 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_COMMAND
;
861 tbbi
.idCommand
= index
;
863 if (iconData
->uFlags
& NIF_STATE
)
865 if (iconData
->dwStateMask
& NIS_HIDDEN
&&
866 (notifyItem
->dwState
& NIS_HIDDEN
) != (iconData
->dwState
& NIS_HIDDEN
))
868 tbbi
.dwMask
|= TBIF_STATE
;
869 if (iconData
->dwState
& NIS_HIDDEN
)
871 tbbi
.fsState
|= TBSTATE_HIDDEN
;
872 m_VisibleButtonCount
--;
876 tbbi
.fsState
&= ~TBSTATE_HIDDEN
;
877 m_VisibleButtonCount
++;
881 notifyItem
->dwState
&= ~iconData
->dwStateMask
;
882 notifyItem
->dwState
|= (iconData
->dwState
& iconData
->dwStateMask
);
885 if (iconData
->uFlags
& NIF_MESSAGE
)
887 notifyItem
->uCallbackMessage
= iconData
->uCallbackMessage
;
890 if (iconData
->uFlags
& NIF_ICON
)
892 BOOL hasSharedIcon
= notifyItem
->dwState
& NIS_SHAREDICON
;
895 INT iIcon
= FindExistingSharedIcon(iconData
->hIcon
);
898 notifyItem
->hIcon
= iconData
->hIcon
;
899 tbbi
.dwMask
|= TBIF_IMAGE
;
904 TRACE("Shared icon requested, but HICON not found!!! IGNORING!");
909 notifyItem
->hIcon
= iconData
->hIcon
;
910 tbbi
.dwMask
|= TBIF_IMAGE
;
911 tbbi
.iImage
= ImageList_ReplaceIcon(m_ImageList
, oldIconIndex
, notifyItem
->hIcon
);
915 if (iconData
->uFlags
& NIF_TIP
)
917 StringCchCopy(notifyItem
->szTip
, _countof(notifyItem
->szTip
), iconData
->szTip
);
920 if (iconData
->uFlags
& NIF_INFO
)
922 // NOTE: In Vista+, the uTimeout value is disregarded, and the accessibility settings are used always.
923 StringCchCopy(notifyItem
->szInfo
, _countof(notifyItem
->szInfo
), iconData
->szInfo
);
924 StringCchCopy(notifyItem
->szInfoTitle
, _countof(notifyItem
->szInfoTitle
), iconData
->szInfoTitle
);
925 notifyItem
->dwInfoFlags
= iconData
->dwInfoFlags
;
926 notifyItem
->uTimeout
= iconData
->uTimeout
;
929 /* TODO: support VERSION_4 (NIF_GUID, NIF_REALTIME, NIF_SHOWTIP) */
931 SetButtonInfo(index
, &tbbi
);
933 if (iconData
->uFlags
& NIF_INFO
)
935 m_BalloonQueue
->UpdateInfo(notifyItem
);
941 BOOL
CNotifyToolbar::RemoveButton(_In_ CONST NOTIFYICONDATA
*iconData
)
943 InternalIconData
* notifyItem
;
945 TRACE("Removing icon %d from hWnd %08x", iconData
->uID
, iconData
->hWnd
);
947 int index
= FindItem(iconData
->hWnd
, iconData
->uID
, ¬ifyItem
);
950 TRACE("Icon %d from hWnd %08x ALREADY MISSING!\n", iconData
->uID
, iconData
->hWnd
);
955 if (!(notifyItem
->dwState
& NIS_HIDDEN
))
957 m_VisibleButtonCount
--;
960 if (!(notifyItem
->dwState
& NIS_SHAREDICON
))
963 GetButton(index
, &btn
);
964 int oldIconIndex
= btn
.iBitmap
;
965 ImageList_Remove(m_ImageList
, oldIconIndex
);
967 // Update other icons!
968 int count
= GetButtonCount();
969 for (int i
= 0; i
< count
; i
++)
974 if (btn
.iBitmap
> oldIconIndex
)
976 TBBUTTONINFO tbbi2
= { 0 };
977 tbbi2
.cbSize
= sizeof(tbbi2
);
978 tbbi2
.dwMask
= TBIF_BYINDEX
| TBIF_IMAGE
;
979 tbbi2
.iImage
= btn
.iBitmap
-1;
980 SetButtonInfo(i
, &tbbi2
);
985 m_BalloonQueue
->RemoveInfo(notifyItem
);
994 VOID
CNotifyToolbar::ResizeImagelist()
999 if (!ImageList_GetIconSize(m_ImageList
, &cx
, &cy
))
1002 if (cx
== GetSystemMetrics(SM_CXSMICON
) && cy
== GetSystemMetrics(SM_CYSMICON
))
1005 iml
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 0, 1000);
1009 ImageList_Destroy(m_ImageList
);
1011 SetImageList(m_ImageList
);
1013 int count
= GetButtonCount();
1014 for (int i
= 0; i
< count
; i
++)
1016 InternalIconData
* data
= GetItemData(i
);
1017 BOOL hasSharedIcon
= data
->dwState
& NIS_SHAREDICON
;
1018 INT iIcon
= hasSharedIcon
? FindExistingSharedIcon(data
->hIcon
) : -1;
1020 iIcon
= ImageList_AddIcon(iml
, data
->hIcon
);
1021 TBBUTTONINFO tbbi
= { sizeof(tbbi
), TBIF_BYINDEX
| TBIF_IMAGE
, 0, iIcon
};
1022 SetButtonInfo(i
, &tbbi
);
1025 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
1028 LRESULT
CNotifyToolbar::OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1033 * WM_CONTEXTMENU message can be generated either by the mouse,
1034 * in which case lParam encodes the mouse coordinates where the
1035 * user right-clicked the mouse, or can be generated by (Shift-)F10
1036 * keyboard press, in which case lParam equals -1.
1038 INT iBtn
= GetHotItem();
1042 InternalIconData
* notifyItem
= GetItemData(iBtn
);
1044 if (!::IsWindow(notifyItem
->hWnd
))
1047 if (notifyItem
->uVersionCopy
>= NOTIFYICON_VERSION
)
1049 /* Transmit the WM_CONTEXTMENU message if the notification icon supports it */
1050 ::SendNotifyMessage(notifyItem
->hWnd
,
1051 notifyItem
->uCallbackMessage
,
1055 else if (lParam
== -1)
1058 * Otherwise, and only if the WM_CONTEXTMENU message was generated
1059 * from the keyboard, simulate right-click mouse messages. This is
1060 * not needed if the message came from the mouse because in this
1061 * case the right-click mouse messages were already sent together.
1063 ::SendNotifyMessage(notifyItem
->hWnd
,
1064 notifyItem
->uCallbackMessage
,
1067 ::SendNotifyMessage(notifyItem
->hWnd
,
1068 notifyItem
->uCallbackMessage
,
1076 bool CNotifyToolbar::SendNotifyCallback(InternalIconData
* notifyItem
, UINT uMsg
)
1078 if (!::IsWindow(notifyItem
->hWnd
))
1080 // We detect and destroy icons with invalid handles only on mouse move over systray, same as MS does.
1081 // Alternatively we could search for them periodically (would waste more resources).
1082 TRACE("Destroying icon %d with invalid handle hWnd=%08x\n", notifyItem
->uID
, notifyItem
->hWnd
);
1084 RemoveButton(notifyItem
);
1086 /* Ask the parent to resize */
1087 NMHDR nmh
= {GetParent(), 0, NTNWM_REALIGN
};
1088 GetParent().SendMessage(WM_NOTIFY
, 0, (LPARAM
) &nmh
);
1094 GetWindowThreadProcessId(notifyItem
->hWnd
, &pid
);
1096 if (pid
== GetCurrentProcessId() ||
1097 (uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
))
1099 ::PostMessage(notifyItem
->hWnd
,
1100 notifyItem
->uCallbackMessage
,
1106 ::SendMessage(notifyItem
->hWnd
,
1107 notifyItem
->uCallbackMessage
,
1114 VOID
CNotifyToolbar::SendMouseEvent(IN WORD wIndex
, IN UINT uMsg
, IN WPARAM wParam
)
1116 static LPCWSTR eventNames
[] = {
1120 L
"WM_LBUTTONDBLCLK",
1123 L
"WM_RBUTTONDBLCLK",
1126 L
"WM_MBUTTONDBLCLK",
1133 InternalIconData
* notifyItem
= GetItemData(wIndex
);
1135 if (uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
)
1137 TRACE("Sending message %S from button %d to %p (msg=%x, w=%x, l=%x)...\n",
1138 eventNames
[uMsg
- WM_MOUSEFIRST
], wIndex
,
1139 notifyItem
->hWnd
, notifyItem
->uCallbackMessage
, notifyItem
->uID
, uMsg
);
1142 SendNotifyCallback(notifyItem
, uMsg
);
1145 LRESULT
CNotifyToolbar::OnMouseEvent(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1147 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1148 INT iBtn
= HitTest(&pt
);
1152 SendMouseEvent(iBtn
, uMsg
, wParam
);
1159 static VOID
GetTooltipText(LPARAM data
, LPTSTR szTip
, DWORD cchTip
)
1161 InternalIconData
* notifyItem
= reinterpret_cast<InternalIconData
*>(data
);
1164 StringCchCopy(szTip
, cchTip
, notifyItem
->szTip
);
1168 StringCchCopy(szTip
, cchTip
, L
"");
1172 LRESULT
CNotifyToolbar::OnTooltipShow(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
1175 ::GetWindowRect(hdr
->hwndFrom
, &rcTip
);
1177 SIZE szTip
= { rcTip
.right
- rcTip
.left
, rcTip
.bottom
- rcTip
.top
};
1179 INT iBtn
= GetHotItem();
1183 MONITORINFO monInfo
= { 0 };
1184 HMONITOR hMon
= MonitorFromWindow(m_hWnd
, MONITOR_DEFAULTTONEAREST
);
1186 monInfo
.cbSize
= sizeof(monInfo
);
1189 GetMonitorInfo(hMon
, &monInfo
);
1191 ::GetWindowRect(GetDesktopWindow(), &monInfo
.rcMonitor
);
1193 GetItemRect(iBtn
, &rcItem
);
1195 POINT ptItem
= { rcItem
.left
, rcItem
.top
};
1196 SIZE szItem
= { rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
};
1197 ClientToScreen(&ptItem
);
1199 ptItem
.x
+= szItem
.cx
/ 2;
1200 ptItem
.y
-= szTip
.cy
;
1202 if (ptItem
.x
+ szTip
.cx
> monInfo
.rcMonitor
.right
)
1203 ptItem
.x
= monInfo
.rcMonitor
.right
- szTip
.cx
;
1205 if (ptItem
.y
+ szTip
.cy
> monInfo
.rcMonitor
.bottom
)
1206 ptItem
.y
= monInfo
.rcMonitor
.bottom
- szTip
.cy
;
1208 if (ptItem
.x
< monInfo
.rcMonitor
.left
)
1209 ptItem
.x
= monInfo
.rcMonitor
.left
;
1211 if (ptItem
.y
< monInfo
.rcMonitor
.top
)
1212 ptItem
.y
= monInfo
.rcMonitor
.top
;
1214 TRACE("ptItem { %d, %d }\n", ptItem
.x
, ptItem
.y
);
1216 ::SetWindowPos(hdr
->hwndFrom
, NULL
, ptItem
.x
, ptItem
.y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1225 void CNotifyToolbar::Initialize(HWND hWndParent
, CBalloonQueue
* queue
)
1227 m_BalloonQueue
= queue
;
1230 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
1231 TBSTYLE_FLAT
| TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_TRANSPARENT
|
1232 CCS_TOP
| CCS_NORESIZE
| CCS_NOPARENTALIGN
| CCS_NODIVIDER
;
1234 // HACK & FIXME: CORE-17505
1235 SubclassWindow(CToolbar::Create(hWndParent
, styles
));
1237 // Force the toolbar tooltips window to always show tooltips even if not foreground
1238 HWND tooltipsWnd
= (HWND
)SendMessageW(TB_GETTOOLTIPS
);
1241 ::SetWindowLong(tooltipsWnd
, GWL_STYLE
, ::GetWindowLong(tooltipsWnd
, GWL_STYLE
) | TTS_ALWAYSTIP
);
1244 SetWindowTheme(m_hWnd
, L
"TrayNotify", NULL
);
1246 m_ImageList
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 0, 1000);
1247 SetImageList(m_ImageList
);
1249 TBMETRICS tbm
= {sizeof(tbm
)};
1250 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
| TBMF_PAD
;
1255 tbm
.cxButtonSpacing
= 1;
1256 tbm
.cyButtonSpacing
= 1;
1259 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
1266 CSysPagerWnd::CSysPagerWnd() {}
1268 CSysPagerWnd::~CSysPagerWnd() {}
1270 LRESULT
CSysPagerWnd::OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1272 HDC hdc
= (HDC
) wParam
;
1281 GetClientRect(&rect
);
1282 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1287 LRESULT
CSysPagerWnd::OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1289 Toolbar
.Initialize(m_hWnd
, &m_BalloonQueue
);
1290 CIconWatcher::Initialize(m_hWnd
);
1292 HWND hWndTop
= GetAncestor(m_hWnd
, GA_ROOT
);
1294 m_Balloons
.Create(hWndTop
, TTS_NOPREFIX
| TTS_BALLOON
| TTS_CLOSE
);
1296 TOOLINFOW ti
= { 0 };
1297 ti
.cbSize
= TTTOOLINFOW_V1_SIZE
;
1298 ti
.uFlags
= TTF_TRACK
| TTF_IDISHWND
;
1299 ti
.uId
= reinterpret_cast<UINT_PTR
>(Toolbar
.m_hWnd
);
1304 BOOL ret
= m_Balloons
.AddTool(&ti
);
1307 WARN("AddTool failed, LastError=%d (probably meaningless unless non-zero)\n", GetLastError());
1310 m_BalloonQueue
.Init(m_hWnd
, &Toolbar
, &m_Balloons
);
1312 // Explicitly request running applications to re-register their systray icons
1313 ::SendNotifyMessageW(HWND_BROADCAST
,
1314 RegisterWindowMessageW(L
"TaskbarCreated"),
1320 LRESULT
CSysPagerWnd::OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1322 m_BalloonQueue
.Deinit();
1323 CIconWatcher::Uninitialize();
1327 BOOL
CSysPagerWnd::NotifyIcon(DWORD dwMessage
, _In_ CONST NOTIFYICONDATA
*iconData
)
1331 int VisibleButtonCount
= Toolbar
.GetVisibleButtonCount();
1333 TRACE("NotifyIcon received. Code=%d\n", dwMessage
);
1337 ret
= Toolbar
.AddButton(iconData
);
1340 (void)AddIconToWatcher(iconData
);
1345 ret
= Toolbar
.UpdateButton(iconData
);
1349 ret
= Toolbar
.RemoveButton(iconData
);
1352 (void)RemoveIconFromWatcher(iconData
);
1361 case NIM_SETVERSION
:
1362 ret
= Toolbar
.SwitchVersion(iconData
);
1366 TRACE("NotifyIcon received with unknown code %d.\n", dwMessage
);
1370 if (VisibleButtonCount
!= Toolbar
.GetVisibleButtonCount())
1372 /* Ask the parent to resize */
1373 NMHDR nmh
= {GetParent(), 0, NTNWM_REALIGN
};
1374 GetParent().SendMessage(WM_NOTIFY
, 0, (LPARAM
) &nmh
);
1380 void CSysPagerWnd::GetSize(IN BOOL IsHorizontal
, IN PSIZE size
)
1382 /* Get the ideal height or width */
1384 /* Unfortunately this doens't work correctly in ros */
1385 Toolbar
.GetIdealSize(!IsHorizontal
, size
);
1387 /* Make the reference dimension an exact multiple of the icon size */
1389 size
->cy
-= size
->cy
% GetSystemMetrics(SM_CYSMICON
);
1391 size
->cx
-= size
->cx
% GetSystemMetrics(SM_CXSMICON
);
1396 INT cyButton
= GetSystemMetrics(SM_CYSMICON
) + 2;
1397 INT cxButton
= GetSystemMetrics(SM_CXSMICON
) + 2;
1398 int VisibleButtonCount
= Toolbar
.GetVisibleButtonCount();
1402 rows
= max(size
->cy
/ cyButton
, 1);
1403 columns
= (VisibleButtonCount
+ rows
- 1) / rows
;
1407 columns
= max(size
->cx
/ cxButton
, 1);
1408 rows
= (VisibleButtonCount
+ columns
- 1) / columns
;
1410 size
->cx
= columns
* cxButton
;
1411 size
->cy
= rows
* cyButton
;
1415 LRESULT
CSysPagerWnd::OnGetInfoTip(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
1417 NMTBGETINFOTIPW
* nmtip
= (NMTBGETINFOTIPW
*) hdr
;
1418 GetTooltipText(nmtip
->lParam
, nmtip
->pszText
, nmtip
->cchTextMax
);
1422 LRESULT
CSysPagerWnd::OnCustomDraw(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
1424 NMCUSTOMDRAW
* cdraw
= (NMCUSTOMDRAW
*) hdr
;
1425 switch (cdraw
->dwDrawStage
)
1428 return CDRF_NOTIFYITEMDRAW
;
1430 case CDDS_ITEMPREPAINT
:
1431 return TBCDRF_NOBACKGROUND
| TBCDRF_NOEDGES
| TBCDRF_NOOFFSET
| TBCDRF_NOMARK
| TBCDRF_NOETCHEDEFFECT
;
1436 LRESULT
CSysPagerWnd::OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1440 /* Handles the BN_CLICKED notifications sent by the CNotifyToolbar member */
1441 if (HIWORD(wParam
) != BN_CLICKED
)
1444 INT iBtn
= LOWORD(wParam
);
1448 InternalIconData
* notifyItem
= Toolbar
.GetItemData(iBtn
);
1450 if (!::IsWindow(notifyItem
->hWnd
))
1453 // TODO: Improve keyboard handling by looking whether one presses
1454 // on ENTER, etc..., which roughly translates into "double-clicking".
1456 if (notifyItem
->uVersionCopy
>= NOTIFYICON_VERSION
)
1458 /* Use new-style notifications if the notification icon supports them */
1459 ::SendNotifyMessage(notifyItem
->hWnd
,
1460 notifyItem
->uCallbackMessage
,
1462 NIN_SELECT
); // TODO: Distinguish with NIN_KEYSELECT
1464 else if (lParam
== -1)
1467 * Otherwise, and only if the icon was selected via the keyboard,
1468 * simulate right-click mouse messages. This is not needed if the
1469 * selection was done by mouse because in this case the mouse
1470 * messages were already sent.
1472 ::SendNotifyMessage(notifyItem
->hWnd
,
1473 notifyItem
->uCallbackMessage
,
1475 WM_LBUTTONDOWN
); // TODO: Distinguish with double-click WM_LBUTTONDBLCLK
1476 ::SendNotifyMessage(notifyItem
->hWnd
,
1477 notifyItem
->uCallbackMessage
,
1485 LRESULT
CSysPagerWnd::OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1489 szClient
.cx
= LOWORD(lParam
);
1490 szClient
.cy
= HIWORD(lParam
);
1492 Ret
= DefWindowProc(uMsg
, wParam
, lParam
);
1496 Toolbar
.SetWindowPos(NULL
, 0, 0, szClient
.cx
, szClient
.cy
, SWP_NOZORDER
);
1500 Toolbar
.GetClientRect(&rc
);
1502 SIZE szBar
= { rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
1504 INT xOff
= (szClient
.cx
- szBar
.cx
) / 2;
1505 INT yOff
= (szClient
.cy
- szBar
.cy
) / 2;
1507 Toolbar
.SetWindowPos(NULL
, xOff
, yOff
, szBar
.cx
, szBar
.cy
, SWP_NOZORDER
);
1512 LRESULT
CSysPagerWnd::OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1518 LRESULT
CSysPagerWnd::OnBalloonPop(UINT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
1520 m_BalloonQueue
.CloseCurrent();
1525 LRESULT
CSysPagerWnd::OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1527 if (m_BalloonQueue
.OnTimer(wParam
))
1535 LRESULT
CSysPagerWnd::OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1537 PCOPYDATASTRUCT cpData
= (PCOPYDATASTRUCT
)lParam
;
1538 if (cpData
->dwData
== TABDMC_NOTIFY
)
1540 /* A taskbar NotifyIcon notification */
1541 PTRAYNOTIFYDATAW pData
= (PTRAYNOTIFYDATAW
)cpData
->lpData
;
1542 if (pData
->dwSignature
== NI_NOTIFY_SIG
)
1543 return NotifyIcon(pData
->dwMessage
, &pData
->nid
);
1545 else if (cpData
->dwData
== TABDMC_LOADINPROC
)
1547 FIXME("Taskbar Load In Proc\n");
1553 LRESULT
CSysPagerWnd::OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1555 if (wParam
== SPI_SETNONCLIENTMETRICS
)
1557 Toolbar
.ResizeImagelist();
1562 LRESULT
CSysPagerWnd::OnGetMinimumSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1564 GetSize((BOOL
)wParam
, (PSIZE
)lParam
);
1568 HRESULT
CSysPagerWnd::Initialize(IN HWND hWndParent
)
1570 /* Create the window. The tray window is going to move it to the correct
1571 position and resize it as needed. */
1572 DWORD dwStyle
= WS_CHILD
| WS_CLIPSIBLINGS
| WS_VISIBLE
;
1573 Create(hWndParent
, 0, NULL
, dwStyle
);
1577 SetWindowTheme(m_hWnd
, L
"TrayNotify", NULL
);
1582 HRESULT
CSysPagerWnd_CreateInstance(HWND hwndParent
, REFIID riid
, void **ppv
)
1584 return ShellObjectCreatorInit
<CSysPagerWnd
>(hwndParent
, riid
, ppv
);