4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 static const WCHAR szSysPagerWndClass
[] = L
"SysPager";
28 // Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
29 typedef struct _SYS_PAGER_COPY_DATA
33 NOTIFYICONDATA nicon_data
;
34 } SYS_PAGER_COPY_DATA
, *PSYS_PAGER_COPY_DATA
;
36 class CNotifyToolbar
:
37 public CWindowImplBaseT
< CToolbar
<NOTIFYICONDATA
>, CControlWinTraits
>
39 HIMAGELIST m_ImageList
;
40 int m_VisibleButtonCount
;
45 m_VisibleButtonCount(0)
53 int GetVisibleButtonCount()
55 return m_VisibleButtonCount
;
58 int FindItemByIconData(IN CONST NOTIFYICONDATA
*iconData
, NOTIFYICONDATA
** pdata
)
60 int count
= GetButtonCount();
62 for (int i
= 0; i
< count
; i
++)
64 NOTIFYICONDATA
* data
;
66 data
= GetItemData(i
);
68 if (data
->hWnd
== iconData
->hWnd
&&
69 data
->uID
== iconData
->uID
)
80 BOOL
AddButton(IN CONST NOTIFYICONDATA
*iconData
)
83 NOTIFYICONDATA
* notifyItem
;
86 int index
= FindItemByIconData(iconData
, ¬ifyItem
);
89 return UpdateButton(iconData
);
92 notifyItem
= new NOTIFYICONDATA();
93 ZeroMemory(notifyItem
, sizeof(*notifyItem
));
95 notifyItem
->hWnd
= iconData
->hWnd
;
96 notifyItem
->uID
= iconData
->uID
;
98 tbBtn
.fsState
= TBSTATE_ENABLED
;
99 tbBtn
.fsStyle
= BTNS_NOPREFIX
;
100 tbBtn
.dwData
= (DWORD_PTR
)notifyItem
;
101 tbBtn
.iString
= (INT_PTR
) text
;
102 tbBtn
.idCommand
= GetButtonCount();
104 if (iconData
->uFlags
& NIF_MESSAGE
)
106 notifyItem
->uCallbackMessage
= iconData
->uCallbackMessage
;
109 if (iconData
->uFlags
& NIF_ICON
)
111 notifyItem
->hIcon
= (HICON
)CopyImage(iconData
->hIcon
, IMAGE_ICON
, 0, 0, 0);
112 tbBtn
.iBitmap
= ImageList_AddIcon(m_ImageList
, iconData
->hIcon
);
115 if (iconData
->uFlags
& NIF_TIP
)
117 StringCchCopy(notifyItem
->szTip
, _countof(notifyItem
->szTip
), iconData
->szTip
);
120 m_VisibleButtonCount
++;
121 if (iconData
->uFlags
& NIF_STATE
)
123 notifyItem
->dwState
&= ~iconData
->dwStateMask
;
124 notifyItem
->dwState
|= (iconData
->dwState
& iconData
->dwStateMask
);
125 if (notifyItem
->dwState
& NIS_HIDDEN
)
127 tbBtn
.fsState
|= TBSTATE_HIDDEN
;
128 m_VisibleButtonCount
--;
132 /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
134 CToolbar::AddButton(&tbBtn
);
135 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
140 BOOL
UpdateButton(IN CONST NOTIFYICONDATA
*iconData
)
142 NOTIFYICONDATA
* notifyItem
;
143 TBBUTTONINFO tbbi
= { 0 };
145 int index
= FindItemByIconData(iconData
, ¬ifyItem
);
148 return AddButton(iconData
);
151 tbbi
.cbSize
= sizeof(tbbi
);
152 tbbi
.dwMask
= TBIF_BYINDEX
| TBIF_COMMAND
;
153 tbbi
.idCommand
= index
;
155 if (iconData
->uFlags
& NIF_MESSAGE
)
157 notifyItem
->uCallbackMessage
= iconData
->uCallbackMessage
;
160 if (iconData
->uFlags
& NIF_ICON
)
162 DestroyIcon(notifyItem
->hIcon
);
163 notifyItem
->hIcon
= (HICON
)CopyImage(iconData
->hIcon
, IMAGE_ICON
, 0, 0, 0);
164 tbbi
.dwMask
|= TBIF_IMAGE
;
165 tbbi
.iImage
= ImageList_ReplaceIcon(m_ImageList
, index
, iconData
->hIcon
);
168 if (iconData
->uFlags
& NIF_TIP
)
170 StringCchCopy(notifyItem
->szTip
, _countof(notifyItem
->szTip
), iconData
->szTip
);
173 if (iconData
->uFlags
& NIF_STATE
)
175 if (iconData
->dwStateMask
& NIS_HIDDEN
&&
176 (notifyItem
->dwState
& NIS_HIDDEN
) != (iconData
->dwState
& NIS_HIDDEN
))
178 tbbi
.dwMask
|= TBIF_STATE
;
179 if (iconData
->dwState
& NIS_HIDDEN
)
181 tbbi
.fsState
|= TBSTATE_HIDDEN
;
182 m_VisibleButtonCount
--;
186 tbbi
.fsState
&= ~TBSTATE_HIDDEN
;
187 m_VisibleButtonCount
++;
191 notifyItem
->dwState
&= ~iconData
->dwStateMask
;
192 notifyItem
->dwState
|= (iconData
->dwState
& iconData
->dwStateMask
);
195 /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
197 SetButtonInfo(index
, &tbbi
);
202 BOOL
RemoveButton(IN CONST NOTIFYICONDATA
*iconData
)
204 NOTIFYICONDATA
* notifyItem
;
206 int index
= FindItemByIconData(iconData
, ¬ifyItem
);
210 if (!(notifyItem
->dwState
& NIS_HIDDEN
))
212 m_VisibleButtonCount
--;
215 DestroyIcon(notifyItem
->hIcon
);
219 ImageList_Remove(m_ImageList
, index
);
221 int count
= GetButtonCount();
223 /* shift all buttons one index to the left -- starting one index right
224 from item to delete -- to preserve their correct icon and tip */
225 for (int i
= index
; i
< count
- 1; i
++)
227 notifyItem
= GetItemData(i
+ 1);
228 SetItemData(i
, notifyItem
);
229 UpdateButton(notifyItem
);
232 /* Delete the right-most, now obsolete button */
233 DeleteButton(count
- 1);
238 VOID
GetTooltipText(int index
, LPTSTR szTip
, DWORD cchTip
)
240 NOTIFYICONDATA
* notifyItem
;
241 notifyItem
= GetItemData(index
);
245 StringCchCopy(szTip
, cchTip
, notifyItem
->szTip
);
249 VOID
ResizeImagelist()
254 if (!ImageList_GetIconSize(m_ImageList
, &cx
, &cy
))
257 if (cx
== GetSystemMetrics(SM_CXSMICON
) && cy
== GetSystemMetrics(SM_CYSMICON
))
260 iml
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 0, 1000);
264 ImageList_Destroy(m_ImageList
);
266 SetImageList(m_ImageList
);
268 int count
= GetButtonCount();
269 for (int i
= 0; i
< count
; i
++)
271 NOTIFYICONDATA
* data
= GetItemData(i
);
272 INT iIcon
= ImageList_AddIcon(iml
, data
->hIcon
);
273 TBBUTTONINFO tbbi
= { sizeof(tbbi
), TBIF_BYINDEX
| TBIF_IMAGE
, 0, iIcon
};
274 SetButtonInfo(i
, &tbbi
);
277 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
282 VOID
SendMouseEvent(IN WORD wIndex
, IN UINT uMsg
, IN WPARAM wParam
)
284 static LPCWSTR eventNames
[] = {
301 NOTIFYICONDATA
* notifyItem
= GetItemData(wIndex
);
303 if (!::IsWindow(notifyItem
->hWnd
))
305 // We detect and destroy icons with invalid handles only on mouse move over systray, same as MS does.
306 // Alternatively we could search for them periodically (would waste more resources).
307 TRACE("destroying icon with invalid handle\n");
309 HWND parentHWND
= GetParent();
310 parentHWND
= ::GetParent(parentHWND
);
313 ::GetClientRect(parentHWND
, &windowRect
);
315 RemoveButton(notifyItem
);
317 SendMessage(parentHWND
,
320 MAKELONG(windowRect
.right
- windowRect
.left
,
321 windowRect
.bottom
- windowRect
.top
));
326 if (uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
)
328 TRACE("Sending message %S from button %d to %p (msg=%x, w=%x, l=%x)...\n",
329 eventNames
[uMsg
- WM_MOUSEFIRST
], wIndex
,
330 notifyItem
->hWnd
, notifyItem
->uCallbackMessage
, notifyItem
->uID
, uMsg
);
334 GetWindowThreadProcessId(notifyItem
->hWnd
, &pid
);
336 if (pid
== GetCurrentProcessId() ||
337 (uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
))
339 ::PostMessage(notifyItem
->hWnd
,
340 notifyItem
->uCallbackMessage
,
346 SendMessage(notifyItem
->hWnd
,
347 notifyItem
->uCallbackMessage
,
353 LRESULT
OnMouseEvent(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
355 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
357 INT iBtn
= HitTest(&pt
);
361 SendMouseEvent(iBtn
, uMsg
, wParam
);
368 LRESULT
OnTooltipShow(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
371 ::GetWindowRect(hdr
->hwndFrom
, &rcTip
);
373 SIZE szTip
= { rcTip
.right
- rcTip
.left
, rcTip
.bottom
- rcTip
.top
};
375 INT iBtn
= GetHotItem();
379 MONITORINFO monInfo
= { 0 };
380 HMONITOR hMon
= MonitorFromWindow(m_hWnd
, MONITOR_DEFAULTTONEAREST
);
382 monInfo
.cbSize
= sizeof(monInfo
);
385 GetMonitorInfo(hMon
, &monInfo
);
387 ::GetWindowRect(GetDesktopWindow(), &monInfo
.rcMonitor
);
389 GetItemRect(iBtn
, &rcItem
);
391 POINT ptItem
= { rcItem
.left
, rcItem
.top
};
392 SIZE szItem
= { rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
};
393 ClientToScreen(&ptItem
);
395 ptItem
.x
+= szItem
.cx
/ 2;
396 ptItem
.y
-= szTip
.cy
;
398 if (ptItem
.x
+ szTip
.cx
> monInfo
.rcMonitor
.right
)
399 ptItem
.x
= monInfo
.rcMonitor
.right
- szTip
.cx
;
401 if (ptItem
.y
+ szTip
.cy
> monInfo
.rcMonitor
.bottom
)
402 ptItem
.y
= monInfo
.rcMonitor
.bottom
- szTip
.cy
;
404 if (ptItem
.x
< monInfo
.rcMonitor
.left
)
405 ptItem
.x
= monInfo
.rcMonitor
.left
;
407 if (ptItem
.y
< monInfo
.rcMonitor
.top
)
408 ptItem
.y
= monInfo
.rcMonitor
.top
;
410 TRACE("ptItem { %d, %d }\n", ptItem
.x
, ptItem
.y
);
412 ::SetWindowPos(hdr
->hwndFrom
, NULL
, ptItem
.x
, ptItem
.y
, 0, 0, SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
423 BEGIN_MSG_MAP(CNotifyToolbar
)
424 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseEvent
)
425 NOTIFY_CODE_HANDLER(TTN_SHOW
, OnTooltipShow
)
428 void Initialize(HWND hWndParent
)
431 WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
|
432 TBSTYLE_FLAT
| TBSTYLE_TOOLTIPS
| TBSTYLE_WRAPABLE
| TBSTYLE_TRANSPARENT
|
433 CCS_TOP
| CCS_NORESIZE
| CCS_NOPARENTALIGN
| CCS_NODIVIDER
;
435 SubclassWindow(CToolbar::Create(hWndParent
, styles
));
437 SetWindowTheme(m_hWnd
, L
"TrayNotify", NULL
);
439 m_ImageList
= ImageList_Create(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), ILC_COLOR32
| ILC_MASK
, 0, 1000);
440 SetImageList(m_ImageList
);
442 TBMETRICS tbm
= {sizeof(tbm
)};
443 tbm
.dwMask
= TBMF_BARPAD
| TBMF_BUTTONSPACING
| TBMF_PAD
;
446 tbm
.cxButtonSpacing
= 1;
447 tbm
.cyButtonSpacing
= 1;
450 SetButtonSize(GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
));
455 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
456 public CWindowImpl
< CSysPagerWnd
, CWindow
, CControlWinTraits
>
458 CNotifyToolbar Toolbar
;
462 virtual ~CSysPagerWnd() {}
464 LRESULT
DrawBackground(HDC hdc
)
468 GetClientRect(&rect
);
469 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
474 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
476 HDC hdc
= (HDC
) wParam
;
484 return DrawBackground(hdc
);
487 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
489 Toolbar
.Initialize(m_hWnd
);
491 // Explicitly request running applications to re-register their systray icons
492 ::SendNotifyMessageW(HWND_BROADCAST
,
493 RegisterWindowMessageW(L
"TaskbarCreated"),
499 BOOL
NotifyIconCmd(WPARAM wParam
, LPARAM lParam
)
501 PCOPYDATASTRUCT cpData
= (PCOPYDATASTRUCT
) lParam
;
502 if (cpData
->dwData
== 1)
504 SYS_PAGER_COPY_DATA
* data
;
505 NOTIFYICONDATA
*iconData
;
509 parentHWND
= GetParent();
510 parentHWND
= ::GetParent(parentHWND
);
511 ::GetClientRect(parentHWND
, &windowRect
);
513 int VisibleButtonCount
= Toolbar
.GetVisibleButtonCount();
515 data
= (PSYS_PAGER_COPY_DATA
) cpData
->lpData
;
516 iconData
= &data
->nicon_data
;
518 TRACE("NotifyIconCmd received. Code=%d\n", data
->notify_code
);
519 switch (data
->notify_code
)
522 ret
= Toolbar
.AddButton(iconData
);
525 ret
= Toolbar
.UpdateButton(iconData
);
528 ret
= Toolbar
.RemoveButton(iconData
);
531 TRACE("NotifyIconCmd received with unknown code %d.\n", data
->notify_code
);
535 if (VisibleButtonCount
!= Toolbar
.GetVisibleButtonCount())
537 SendMessage(parentHWND
, WM_SIZE
, 0, 0);
546 void GetSize(IN BOOL IsHorizontal
, IN PSIZE size
)
548 /* Get the ideal height or width */
550 /* Unfortunately this doens't work correctly in ros */
551 Toolbar
.GetIdealSize(!IsHorizontal
, size
);
553 /* Make the reference dimension an exact multiple of the icon size */
555 size
->cy
-= size
->cy
% GetSystemMetrics(SM_CYSMICON
);
557 size
->cx
-= size
->cx
% GetSystemMetrics(SM_CXSMICON
);
562 INT cyButton
= GetSystemMetrics(SM_CYSMICON
) + 2;
563 INT cxButton
= GetSystemMetrics(SM_CXSMICON
) + 2;
564 int VisibleButtonCount
= Toolbar
.GetVisibleButtonCount();
568 rows
= max(size
->cy
/ cyButton
, 1);
569 columns
= (VisibleButtonCount
+ rows
- 1) / rows
;
573 columns
= max(size
->cx
/ cxButton
, 1);
574 rows
= (VisibleButtonCount
+ columns
- 1) / columns
;
576 size
->cx
= columns
* cxButton
;
577 size
->cy
= rows
* cyButton
;
581 LRESULT
OnGetInfoTip(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
583 NMTBGETINFOTIPW
* nmtip
= (NMTBGETINFOTIPW
*) hdr
;
584 Toolbar
.GetTooltipText(nmtip
->iItem
, nmtip
->pszText
, nmtip
->cchTextMax
);
588 LRESULT
OnCustomDraw(INT uCode
, LPNMHDR hdr
, BOOL
& bHandled
)
590 NMCUSTOMDRAW
* cdraw
= (NMCUSTOMDRAW
*) hdr
;
591 switch (cdraw
->dwDrawStage
)
594 return CDRF_NOTIFYITEMDRAW
;
596 case CDDS_ITEMPREPAINT
:
597 return TBCDRF_NOBACKGROUND
| TBCDRF_NOEDGES
| TBCDRF_NOOFFSET
| TBCDRF_NOMARK
| TBCDRF_NOETCHEDEFFECT
;
602 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
606 szClient
.cx
= LOWORD(lParam
);
607 szClient
.cy
= HIWORD(lParam
);
609 Ret
= DefWindowProc(uMsg
, wParam
, lParam
);
613 Toolbar
.SetWindowPos(NULL
, 0, 0, szClient
.cx
, szClient
.cy
, SWP_NOZORDER
);
617 Toolbar
.GetClientRect(&rc
);
619 SIZE szBar
= { rc
.right
- rc
.left
, rc
.bottom
- rc
.top
};
621 INT xOff
= (szClient
.cx
- szBar
.cx
) / 2;
622 INT yOff
= (szClient
.cy
- szBar
.cy
) / 2;
624 Toolbar
.SetWindowPos(NULL
, xOff
, yOff
, szBar
.cx
, szBar
.cy
, SWP_NOZORDER
);
629 LRESULT
OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
635 void ResizeImagelist()
637 Toolbar
.ResizeImagelist();
640 DECLARE_WND_CLASS_EX(szSysPagerWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
642 BEGIN_MSG_MAP(CSysPagerWnd
)
643 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
644 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
645 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
646 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnCtxMenu
)
647 NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW
, OnGetInfoTip
)
648 NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW
, OnCustomDraw
)
651 HWND
_Init(IN HWND hWndParent
, IN BOOL bVisible
)
655 /* Create the window. The tray window is going to move it to the correct
656 position and resize it as needed. */
657 dwStyle
= WS_CHILD
| WS_CLIPSIBLINGS
;
659 dwStyle
|= WS_VISIBLE
;
661 Create(hWndParent
, 0, NULL
, dwStyle
);
668 SetWindowTheme(m_hWnd
, L
"TrayNotify", NULL
);
678 static const WCHAR szTrayClockWndClass
[] = L
"TrayClockWClass";
680 #define ID_TRAYCLOCK_TIMER 0
681 #define ID_TRAYCLOCK_TIMER_INIT 1
688 } ClockWndFormats
[] = {
690 { FALSE
, 0, L
"dddd" },
691 { FALSE
, DATE_SHORTDATE
, NULL
}
694 #define CLOCKWND_FORMAT_COUNT (_ARRAYSIZE(ClockWndFormats))
696 #define TRAY_CLOCK_WND_SPACING_X 0
697 #define TRAY_CLOCK_WND_SPACING_Y 0
699 class CTrayClockWnd
:
700 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
701 public CWindowImpl
< CTrayClockWnd
, CWindow
, CControlWinTraits
>
707 SYSTEMTIME LocalTime
;
714 DWORD IsTimerEnabled
: 1;
715 DWORD IsInitTimerEnabled
: 1;
716 DWORD LinesMeasured
: 1;
717 DWORD IsHorizontal
: 1;
723 SIZE LineSizes
[CLOCKWND_FORMAT_COUNT
];
724 WCHAR szLines
[CLOCKWND_FORMAT_COUNT
][48];
734 ZeroMemory(&textColor
, sizeof(textColor
));
735 ZeroMemory(&rcText
, sizeof(rcText
));
736 ZeroMemory(&LocalTime
, sizeof(LocalTime
));
737 ZeroMemory(&CurrentSize
, sizeof(CurrentSize
));
738 ZeroMemory(LineSizes
, sizeof(LineSizes
));
739 ZeroMemory(szLines
, sizeof(szLines
));
741 virtual ~CTrayClockWnd() { }
743 LRESULT
OnThemeChanged()
749 clockTheme
= OpenThemeData(m_hWnd
, L
"Clock");
753 GetThemeFont(clockTheme
,
760 hFont
= CreateFontIndirectW(&clockFont
);
762 GetThemeColor(clockTheme
,
768 if (this->hFont
!= NULL
)
769 DeleteObject(this->hFont
);
771 SetFont(hFont
, FALSE
);
775 /* We don't need to set a font here, our parent will use
776 * WM_SETFONT to set the right one when themes are not enabled. */
777 textColor
= RGB(0, 0, 0);
780 CloseThemeData(clockTheme
);
785 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
787 return OnThemeChanged();
801 hPrevFont
= (HFONT
) SelectObject(hDC
, hFont
);
803 for (i
= 0; i
< CLOCKWND_FORMAT_COUNT
&& bRet
; i
++)
805 if (szLines
[i
][0] != L
'\0' &&
806 !GetTextExtentPointW(hDC
, szLines
[i
], wcslen(szLines
[i
]),
815 SelectObject(hDC
, hPrevFont
);
823 /* calculate the line spacing */
824 for (i
= 0, c
= 0; i
< CLOCKWND_FORMAT_COUNT
; i
++)
826 if (LineSizes
[i
].cx
> 0)
828 LineSpacing
+= LineSizes
[i
].cy
;
835 /* We want a spacing of 1/2 line */
836 LineSpacing
= (LineSpacing
/ c
) / 2;
846 WORD
GetMinimumSize(IN BOOL Horizontal
, IN OUT PSIZE pSize
)
848 WORD iLinesVisible
= 0;
850 SIZE szMax
= { 0, 0 };
853 LinesMeasured
= MeasureLines();
858 for (i
= 0; i
< CLOCKWND_FORMAT_COUNT
; i
++)
860 if (LineSizes
[i
].cx
!= 0)
862 if (iLinesVisible
> 0)
866 if (szMax
.cy
+ LineSizes
[i
].cy
+ (LONG
) LineSpacing
>
867 pSize
->cy
- (2 * TRAY_CLOCK_WND_SPACING_Y
))
874 if (LineSizes
[i
].cx
> pSize
->cx
- (2 * TRAY_CLOCK_WND_SPACING_X
))
878 /* Add line spacing */
879 szMax
.cy
+= LineSpacing
;
884 /* Increase maximum rectangle */
885 szMax
.cy
+= LineSizes
[i
].cy
;
886 if (LineSizes
[i
].cx
> szMax
.cx
- (2 * TRAY_CLOCK_WND_SPACING_X
))
887 szMax
.cx
= LineSizes
[i
].cx
+ (2 * TRAY_CLOCK_WND_SPACING_X
);
891 szMax
.cx
+= 2 * TRAY_CLOCK_WND_SPACING_X
;
892 szMax
.cy
+= 2 * TRAY_CLOCK_WND_SPACING_Y
;
896 return iLinesVisible
;
907 ZeroMemory(LineSizes
, sizeof(LineSizes
));
909 szPrevCurrent
= CurrentSize
;
911 for (i
= 0; i
< CLOCKWND_FORMAT_COUNT
; i
++)
913 szLines
[i
][0] = L
'\0';
914 BufSize
= _countof(szLines
[0]);
916 if (ClockWndFormats
[i
].IsTime
)
918 iRet
= GetTimeFormat(LOCALE_USER_DEFAULT
,
919 g_TaskbarSettings
.bShowSeconds
? ClockWndFormats
[i
].dwFormatFlags
: TIME_NOSECONDS
,
921 ClockWndFormats
[i
].lpFormat
,
927 iRet
= GetDateFormat(LOCALE_USER_DEFAULT
,
928 ClockWndFormats
[i
].dwFormatFlags
,
930 ClockWndFormats
[i
].lpFormat
,
935 if (iRet
!= 0 && i
== 0)
937 /* Set the window text to the time only */
938 SetWindowText(szLines
[i
]);
942 LinesMeasured
= MeasureLines();
945 GetClientRect(&rcClient
))
949 szWnd
.cx
= rcClient
.right
;
950 szWnd
.cy
= rcClient
.bottom
;
952 VisibleLines
= GetMinimumSize(IsHorizontal
, &szWnd
);
956 if (IsWindowVisible())
958 InvalidateRect(NULL
, TRUE
);
960 if (hWndNotify
!= NULL
&&
961 (szPrevCurrent
.cx
!= CurrentSize
.cx
||
962 szPrevCurrent
.cy
!= CurrentSize
.cy
))
966 nmh
.hwndFrom
= m_hWnd
;
967 nmh
.idFrom
= GetWindowLongPtr(GWLP_ID
);
968 nmh
.code
= NTNWM_REALIGN
;
970 SendMessage(hWndNotify
,
980 GetLocalTime(&LocalTime
);
984 UINT
CalculateDueTime()
988 /* Calculate the due time */
989 GetLocalTime(&LocalTime
);
990 uiDueTime
= 1000 - (UINT
) LocalTime
.wMilliseconds
;
991 if (g_TaskbarSettings
.bShowSeconds
)
992 uiDueTime
+= (UINT
) LocalTime
.wSecond
* 100;
994 uiDueTime
+= (59 - (UINT
) LocalTime
.wSecond
) * 1000;
996 if (uiDueTime
< USER_TIMER_MINIMUM
|| uiDueTime
> USER_TIMER_MAXIMUM
)
1000 /* Add an artificial delay of 0.05 seconds to make sure the timer
1001 doesn't fire too early*/
1013 /* Disable all timers */
1016 KillTimer(ID_TRAYCLOCK_TIMER
);
1017 IsTimerEnabled
= FALSE
;
1020 if (IsInitTimerEnabled
)
1022 KillTimer(ID_TRAYCLOCK_TIMER_INIT
);
1025 uiDueTime
= CalculateDueTime();
1027 /* Set the new timer */
1028 Ret
= SetTimer(ID_TRAYCLOCK_TIMER_INIT
, uiDueTime
, NULL
) != 0;
1029 IsInitTimerEnabled
= Ret
;
1031 /* Update the time */
1037 VOID
CalibrateTimer()
1041 UINT uiWait1
, uiWait2
;
1043 /* Kill the initialization timer */
1044 KillTimer(ID_TRAYCLOCK_TIMER_INIT
);
1045 IsInitTimerEnabled
= FALSE
;
1047 uiDueTime
= CalculateDueTime();
1049 if (g_TaskbarSettings
.bShowSeconds
)
1051 uiWait1
= 1000 - 200;
1056 uiWait1
= 60 * 1000 - 200;
1057 uiWait2
= 60 * 1000;
1060 if (uiDueTime
> uiWait1
)
1062 /* The update of the clock will be up to 200 ms late, but that's
1063 acceptable. We're going to setup a timer that fires depending
1065 Ret
= SetTimer(ID_TRAYCLOCK_TIMER
, uiWait2
, NULL
) != 0;
1066 IsTimerEnabled
= Ret
;
1068 /* Update the time */
1073 /* Recalibrate the timer and recalculate again when the current
1074 minute/second ends. */
1079 LRESULT
OnDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1081 /* Disable all timers */
1084 KillTimer(ID_TRAYCLOCK_TIMER
);
1087 if (IsInitTimerEnabled
)
1089 KillTimer(ID_TRAYCLOCK_TIMER_INIT
);
1095 LRESULT
OnPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1103 HDC hDC
= (HDC
) wParam
;
1107 hDC
= BeginPaint(&ps
);
1113 if (LinesMeasured
&&
1114 GetClientRect(&rcClient
))
1116 iPrevBkMode
= SetBkMode(hDC
, TRANSPARENT
);
1118 SetTextColor(hDC
, textColor
);
1120 hPrevFont
= (HFONT
) SelectObject(hDC
, hFont
);
1122 rcClient
.left
= (rcClient
.right
/ 2) - (CurrentSize
.cx
/ 2);
1123 rcClient
.top
= (rcClient
.bottom
/ 2) - (CurrentSize
.cy
/ 2);
1124 rcClient
.right
= rcClient
.left
+ CurrentSize
.cx
;
1125 rcClient
.bottom
= rcClient
.top
+ CurrentSize
.cy
;
1127 for (i
= 0, line
= 0;
1128 i
< CLOCKWND_FORMAT_COUNT
&& line
< VisibleLines
;
1131 if (LineSizes
[i
].cx
!= 0)
1134 rcClient
.left
+ (CurrentSize
.cx
/ 2) - (LineSizes
[i
].cx
/ 2) +
1135 TRAY_CLOCK_WND_SPACING_X
,
1136 rcClient
.top
+ TRAY_CLOCK_WND_SPACING_Y
,
1138 wcslen(szLines
[i
]));
1140 rcClient
.top
+= LineSizes
[i
].cy
+ LineSpacing
;
1145 SelectObject(hDC
, hPrevFont
);
1147 SetBkMode(hDC
, iPrevBkMode
);
1158 VOID
SetFont(IN HFONT hNewFont
, IN BOOL bRedraw
)
1161 LinesMeasured
= MeasureLines();
1164 InvalidateRect(NULL
, TRUE
);
1168 LRESULT
DrawBackground(HDC hdc
)
1172 GetClientRect(&rect
);
1173 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1178 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1180 HDC hdc
= (HDC
) wParam
;
1188 return DrawBackground(hdc
);
1191 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1195 case ID_TRAYCLOCK_TIMER
:
1199 case ID_TRAYCLOCK_TIMER_INIT
:
1206 LRESULT
OnGetMinimumSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1208 IsHorizontal
= (BOOL
) wParam
;
1210 return (LRESULT
) GetMinimumSize((BOOL
) wParam
, (PSIZE
) lParam
) != 0;
1213 LRESULT
OnUpdateTime(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1215 return (LRESULT
) ResetTime();
1218 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1220 return HTTRANSPARENT
;
1223 LRESULT
OnSetFont(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1225 SetFont((HFONT
) wParam
, (BOOL
) LOWORD(lParam
));
1229 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1235 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1239 szClient
.cx
= LOWORD(lParam
);
1240 szClient
.cy
= HIWORD(lParam
);
1242 VisibleLines
= GetMinimumSize(IsHorizontal
, &szClient
);
1243 CurrentSize
= szClient
;
1245 InvalidateRect(NULL
, TRUE
);
1249 DECLARE_WND_CLASS_EX(szTrayClockWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
1251 BEGIN_MSG_MAP(CTrayClockWnd
)
1252 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1253 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
1254 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1255 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1256 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
1257 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
1258 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
1259 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
1260 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
1261 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
1262 MESSAGE_HANDLER(TCWM_GETMINIMUMSIZE
, OnGetMinimumSize
)
1263 MESSAGE_HANDLER(TCWM_UPDATETIME
, OnUpdateTime
)
1267 HWND
_Init(IN HWND hWndParent
, IN BOOL bVisible
)
1269 IsHorizontal
= TRUE
;
1271 hWndNotify
= hWndParent
;
1273 /* Create the window. The tray window is going to move it to the correct
1274 position and resize it as needed. */
1275 DWORD dwStyle
= WS_CHILD
| WS_CLIPSIBLINGS
;
1277 dwStyle
|= WS_VISIBLE
;
1279 Create(hWndParent
, 0, NULL
, dwStyle
);
1282 SetWindowTheme(m_hWnd
, L
"TrayNotify", NULL
);
1293 static const WCHAR szTrayNotifyWndClass
[] = TEXT("TrayNotifyWnd");
1295 #define TRAY_NOTIFY_WND_SPACING_X 1
1296 #define TRAY_NOTIFY_WND_SPACING_Y 1
1298 class CTrayNotifyWnd
:
1299 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
1300 public CWindowImpl
< CTrayNotifyWnd
, CWindow
, CControlWinTraits
>
1304 CSysPagerWnd
* m_pager
;
1305 CTrayClockWnd
* m_clock
;
1307 CComPtr
<ITrayWindow
> TrayWindow
;
1310 SIZE szTrayClockMin
;
1312 MARGINS ContentMargin
;
1323 ZeroMemory(&szTrayClockMin
, sizeof(szTrayClockMin
));
1324 ZeroMemory(&szTrayNotify
, sizeof(szTrayNotify
));
1325 ZeroMemory(&ContentMargin
, sizeof(ContentMargin
));
1327 virtual ~CTrayNotifyWnd() { }
1329 LRESULT
OnThemeChanged()
1332 CloseThemeData(TrayTheme
);
1334 if (IsThemeActive())
1335 TrayTheme
= OpenThemeData(m_hWnd
, L
"TrayNotify");
1341 SetWindowExStyle(m_hWnd
, WS_EX_STATICEDGE
, 0);
1343 GetThemeMargins(TrayTheme
,
1353 SetWindowExStyle(m_hWnd
, WS_EX_STATICEDGE
, WS_EX_STATICEDGE
);
1355 ContentMargin
.cxLeftWidth
= 2;
1356 ContentMargin
.cxRightWidth
= 2;
1357 ContentMargin
.cyTopHeight
= 2;
1358 ContentMargin
.cyBottomHeight
= 2;
1364 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1366 return OnThemeChanged();
1369 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1371 m_clock
= new CTrayClockWnd();
1372 m_clock
->_Init(m_hWnd
, !g_TaskbarSettings
.sr
.HideClock
);
1374 m_pager
= new CSysPagerWnd();
1375 m_pager
->_Init(m_hWnd
, !g_TaskbarSettings
.sr
.HideClock
);
1380 BOOL
GetMinimumSize(IN OUT PSIZE pSize
)
1382 SIZE szClock
= { 0, 0 };
1383 SIZE szTray
= { 0, 0 };
1385 if (!g_TaskbarSettings
.sr
.HideClock
)
1389 szClock
.cy
= pSize
->cy
- 2 * TRAY_NOTIFY_WND_SPACING_Y
;
1390 if (szClock
.cy
<= 0)
1395 szClock
.cx
= pSize
->cx
- 2 * TRAY_NOTIFY_WND_SPACING_X
;
1396 if (szClock
.cx
<= 0)
1400 m_clock
->SendMessage(TCWM_GETMINIMUMSIZE
, (WPARAM
) IsHorizontal
, (LPARAM
) &szClock
);
1402 szTrayClockMin
= szClock
;
1406 szTrayClockMin
= szClock
;
1410 szTray
.cy
= pSize
->cy
- 2 * TRAY_NOTIFY_WND_SPACING_Y
;
1414 szTray
.cx
= pSize
->cx
- 2 * TRAY_NOTIFY_WND_SPACING_X
;
1417 m_pager
->GetSize(IsHorizontal
, &szTray
);
1419 szTrayNotify
= szTray
;
1423 pSize
->cx
= 2 * TRAY_NOTIFY_WND_SPACING_X
;
1425 if (!g_TaskbarSettings
.sr
.HideClock
)
1426 pSize
->cx
+= TRAY_NOTIFY_WND_SPACING_X
+ szTrayClockMin
.cx
;
1428 pSize
->cx
+= szTray
.cx
;
1432 pSize
->cy
= 2 * TRAY_NOTIFY_WND_SPACING_Y
;
1434 if (!g_TaskbarSettings
.sr
.HideClock
)
1435 pSize
->cy
+= TRAY_NOTIFY_WND_SPACING_Y
+ szTrayClockMin
.cy
;
1437 pSize
->cy
+= szTray
.cy
;
1440 pSize
->cy
+= ContentMargin
.cyTopHeight
+ ContentMargin
.cyBottomHeight
;
1441 pSize
->cx
+= ContentMargin
.cxLeftWidth
+ ContentMargin
.cxRightWidth
;
1446 VOID
Size(IN
const SIZE
*pszClient
)
1448 if (!g_TaskbarSettings
.sr
.HideClock
)
1455 ptClock
.x
= pszClient
->cx
- szTrayClockMin
.cx
- ContentMargin
.cxRightWidth
;
1456 ptClock
.y
= ContentMargin
.cyTopHeight
;
1457 szClock
.cx
= szTrayClockMin
.cx
;
1458 szClock
.cy
= pszClient
->cy
- ContentMargin
.cyTopHeight
- ContentMargin
.cyBottomHeight
;
1462 ptClock
.x
= ContentMargin
.cxLeftWidth
;
1463 ptClock
.y
= pszClient
->cy
- szTrayClockMin
.cy
;
1464 szClock
.cx
= pszClient
->cx
- ContentMargin
.cxLeftWidth
- ContentMargin
.cxRightWidth
;
1465 szClock
.cy
= szTrayClockMin
.cy
;
1468 m_clock
->SetWindowPos(
1480 ptPager
.x
= ContentMargin
.cxLeftWidth
;
1481 ptPager
.y
= (pszClient
->cy
- szTrayNotify
.cy
)/2;
1485 ptPager
.x
= (pszClient
->cx
- szTrayNotify
.cx
)/2;
1486 ptPager
.y
= ContentMargin
.cyTopHeight
;
1489 m_pager
->SetWindowPos(
1499 LRESULT
DrawBackground(HDC hdc
)
1504 GetClientRect(&rect
);
1508 if (IsThemeBackgroundPartiallyTransparent(TrayTheme
, TNP_BACKGROUND
, 0))
1510 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1513 res
= DrawThemeBackground(TrayTheme
, hdc
, TNP_BACKGROUND
, 0, &rect
, 0);
1519 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1521 HDC hdc
= (HDC
) wParam
;
1529 return DrawBackground(hdc
);
1532 BOOL
NotifyIconCmd(WPARAM wParam
, LPARAM lParam
)
1536 return m_pager
->NotifyIconCmd(wParam
, lParam
);
1542 BOOL
GetClockRect(OUT PRECT rcClock
)
1544 if (!m_clock
->IsWindowVisible())
1547 return m_clock
->GetWindowRect(rcClock
);
1550 LRESULT
OnGetMinimumSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1552 BOOL Horizontal
= (BOOL
) wParam
;
1554 if (Horizontal
!= IsHorizontal
)
1556 IsHorizontal
= Horizontal
;
1558 SetWindowTheme(m_hWnd
, L
"TrayNotifyHoriz", NULL
);
1560 SetWindowTheme(m_hWnd
, L
"TrayNotifyVert", NULL
);
1563 return (LRESULT
) GetMinimumSize((PSIZE
) lParam
);
1566 LRESULT
OnUpdateTime(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1568 if (m_clock
!= NULL
)
1570 /* Forward the message to the tray clock window procedure */
1571 return m_clock
->OnUpdateTime(uMsg
, wParam
, lParam
, bHandled
);
1576 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1580 szClient
.cx
= LOWORD(lParam
);
1581 szClient
.cy
= HIWORD(lParam
);
1588 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1590 return HTTRANSPARENT
;
1593 LRESULT
OnShowClock(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1595 BOOL PrevHidden
= g_TaskbarSettings
.sr
.HideClock
;
1596 g_TaskbarSettings
.sr
.HideClock
= (wParam
== 0);
1598 if (m_clock
!= NULL
&& PrevHidden
!= g_TaskbarSettings
.sr
.HideClock
)
1600 m_clock
->ShowWindow(g_TaskbarSettings
.sr
.HideClock
? SW_HIDE
: SW_SHOW
);
1603 return (LRESULT
) (!PrevHidden
);
1606 LRESULT
OnTaskbarSettingsChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1608 TaskbarSettings
* newSettings
= (TaskbarSettings
*)lParam
;
1609 if (newSettings
->bShowSeconds
!= g_TaskbarSettings
.bShowSeconds
)
1611 g_TaskbarSettings
.bShowSeconds
= newSettings
->bShowSeconds
;
1612 /* TODO: Toggle showing seconds */
1615 if (newSettings
->sr
.HideClock
!= g_TaskbarSettings
.sr
.HideClock
)
1617 g_TaskbarSettings
.sr
.HideClock
= newSettings
->sr
.HideClock
;
1618 /* TODO: Toggle hiding the clock */
1624 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1626 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
1628 if (nmh
->hwndFrom
== m_clock
->m_hWnd
)
1630 /* Pass down notifications */
1631 return m_clock
->SendMessage(WM_NOTIFY
, wParam
, lParam
);
1637 LRESULT
OnSetFont(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1639 if (m_clock
!= NULL
)
1641 m_clock
->SendMessageW(WM_SETFONT
, wParam
, lParam
);
1648 LRESULT
OnCtxMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1654 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1656 if (wParam
== SPI_SETNONCLIENTMETRICS
)
1658 m_pager
->ResizeImagelist();
1663 DECLARE_WND_CLASS_EX(szTrayNotifyWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
1665 BEGIN_MSG_MAP(CTrayNotifyWnd
)
1666 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1667 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
1668 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1669 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
1670 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1671 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
1672 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
1673 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
1674 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnCtxMenu
) // FIXME: This handler is not necessary in Windows
1675 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE
, OnGetMinimumSize
)
1676 MESSAGE_HANDLER(TNWM_UPDATETIME
, OnUpdateTime
)
1677 MESSAGE_HANDLER(TNWM_SHOWCLOCK
, OnShowClock
)
1678 MESSAGE_HANDLER(TWM_SETTINGSCHANGED
, OnTaskbarSettingsChanged
)
1681 HWND
_Init(IN OUT ITrayWindow
*TrayWindow
)
1683 HWND hWndTrayWindow
;
1685 hWndTrayWindow
= TrayWindow
->GetHWND();
1686 if (hWndTrayWindow
== NULL
)
1689 this->TrayWindow
= TrayWindow
;
1690 this->hWndNotify
= hWndTrayWindow
;
1692 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1693 return Create(hWndTrayWindow
, 0, NULL
, dwStyle
, WS_EX_STATICEDGE
);
1697 HWND
CreateTrayNotifyWnd(IN OUT ITrayWindow
*Tray
, CTrayNotifyWnd
** ppinstance
)
1699 CTrayNotifyWnd
* pTrayNotify
= new CTrayNotifyWnd();
1700 // TODO: Destroy after the window is destroyed
1701 *ppinstance
= pTrayNotify
;
1703 return pTrayNotify
->_Init(Tray
);
1707 TrayNotify_NotifyIconCmd(CTrayNotifyWnd
* pTrayNotify
, WPARAM wParam
, LPARAM lParam
)
1709 return pTrayNotify
->NotifyIconCmd(wParam
, lParam
);
1713 TrayNotify_GetClockRect(CTrayNotifyWnd
* pTrayNotify
, OUT PRECT rcClock
)
1715 return pTrayNotify
->GetClockRect(rcClock
);