mirror of
https://github.com/reactos/reactos.git
synced 2024-06-27 16:31:30 +00:00
[EXPLORER] Split up the notification area into a few more manageable pieces.
This commit is contained in:
parent
4a910a12cc
commit
3d75cc0814
|
@ -16,9 +16,11 @@ list(APPEND SOURCE
|
|||
startmnucust.cpp
|
||||
startmnusite.cpp
|
||||
startup.cpp
|
||||
syspager.cpp
|
||||
taskband.cpp
|
||||
taskswnd.cpp
|
||||
tbsite.cpp
|
||||
trayclock.cpp
|
||||
trayntfy.cpp
|
||||
trayprop.cpp
|
||||
traywnd.cpp
|
||||
|
|
|
@ -384,4 +384,16 @@ Tray_OnStartMenuDismissed(ITrayWindow* Tray);
|
|||
HRESULT
|
||||
IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2);
|
||||
|
||||
/*
|
||||
* syspager.c
|
||||
*/
|
||||
|
||||
#include "syspager.h"
|
||||
|
||||
/*
|
||||
* trayclock.c
|
||||
*/
|
||||
|
||||
#include "trayclock.h"
|
||||
|
||||
#endif /* _EXPLORER_PRECOMP__H_ */
|
||||
|
|
1228
base/shell/explorer/syspager.cpp
Normal file
1228
base/shell/explorer/syspager.cpp
Normal file
File diff suppressed because it is too large
Load diff
203
base/shell/explorer/syspager.h
Normal file
203
base/shell/explorer/syspager.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
#pragma once
|
||||
|
||||
struct InternalIconData : NOTIFYICONDATA
|
||||
{
|
||||
// Must keep a separate copy since the original is unioned with uTimeout.
|
||||
UINT uVersionCopy;
|
||||
};
|
||||
|
||||
struct IconWatcherData
|
||||
{
|
||||
HANDLE hProcess;
|
||||
DWORD ProcessId;
|
||||
NOTIFYICONDATA IconData;
|
||||
|
||||
IconWatcherData(NOTIFYICONDATA *iconData) :
|
||||
hProcess(NULL), ProcessId(0)
|
||||
{
|
||||
IconData.cbSize = sizeof(NOTIFYICONDATA);
|
||||
IconData.hWnd = iconData->hWnd;
|
||||
IconData.uID = iconData->uID;
|
||||
IconData.guidItem = iconData->guidItem;
|
||||
}
|
||||
|
||||
~IconWatcherData()
|
||||
{
|
||||
if (hProcess)
|
||||
{
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CIconWatcher
|
||||
{
|
||||
CAtlList<IconWatcherData *> m_WatcherList;
|
||||
CRITICAL_SECTION m_ListLock;
|
||||
HANDLE m_hWatcherThread;
|
||||
HANDLE m_WakeUpEvent;
|
||||
HWND m_hwndSysTray;
|
||||
bool m_Loop;
|
||||
|
||||
public:
|
||||
CIconWatcher();
|
||||
|
||||
virtual ~CIconWatcher();
|
||||
|
||||
bool Initialize(_In_ HWND hWndParent);
|
||||
void Uninitialize();
|
||||
|
||||
bool AddIconToWatcher(_In_ NOTIFYICONDATA *iconData);
|
||||
bool RemoveIconFromWatcher(_In_ NOTIFYICONDATA *iconData);
|
||||
|
||||
IconWatcherData* GetListEntry(_In_opt_ NOTIFYICONDATA *iconData, _In_opt_ HANDLE hProcess, _In_ bool Remove);
|
||||
|
||||
private:
|
||||
|
||||
static UINT WINAPI WatcherThread(_In_opt_ LPVOID lpParam);
|
||||
};
|
||||
|
||||
class CBalloonQueue
|
||||
{
|
||||
public:
|
||||
static const int TimerInterval = 2000;
|
||||
static const int BalloonsTimerId = 1;
|
||||
static const int MinTimeout = 10000;
|
||||
static const int MaxTimeout = 30000;
|
||||
static const int CooldownBetweenBalloons = 2000;
|
||||
|
||||
private:
|
||||
struct Info
|
||||
{
|
||||
InternalIconData * pSource;
|
||||
WCHAR szInfo[256];
|
||||
WCHAR szInfoTitle[64];
|
||||
WPARAM uIcon;
|
||||
UINT uTimeout;
|
||||
|
||||
Info(InternalIconData * source)
|
||||
{
|
||||
pSource = source;
|
||||
StrNCpy(szInfo, source->szInfo, _countof(szInfo));
|
||||
StrNCpy(szInfoTitle, source->szInfoTitle, _countof(szInfoTitle));
|
||||
uIcon = source->dwInfoFlags & NIIF_ICON_MASK;
|
||||
if (source->dwInfoFlags == NIIF_USER)
|
||||
uIcon = reinterpret_cast<WPARAM>(source->hIcon);
|
||||
uTimeout = source->uTimeout;
|
||||
}
|
||||
};
|
||||
|
||||
HWND m_hwndParent;
|
||||
|
||||
CTooltips * m_tooltips;
|
||||
|
||||
CAtlList<Info> m_queue;
|
||||
|
||||
CToolbar<InternalIconData> * m_toolbar;
|
||||
|
||||
InternalIconData * m_current;
|
||||
bool m_currentClosed;
|
||||
|
||||
int m_timer;
|
||||
|
||||
public:
|
||||
CBalloonQueue();
|
||||
|
||||
void Init(HWND hwndParent, CToolbar<InternalIconData> * toolbar, CTooltips * balloons);
|
||||
void Deinit();
|
||||
|
||||
bool OnTimer(int timerId);
|
||||
void UpdateInfo(InternalIconData * notifyItem);
|
||||
void RemoveInfo(InternalIconData * notifyItem);
|
||||
void CloseCurrent();
|
||||
|
||||
private:
|
||||
|
||||
int IndexOf(InternalIconData * pdata);
|
||||
void SetTimer(int length);
|
||||
void Show(Info& info);
|
||||
void Close(IN OUT InternalIconData * notifyItem);
|
||||
};
|
||||
|
||||
class CNotifyToolbar :
|
||||
public CWindowImplBaseT< CToolbar<InternalIconData>, CControlWinTraits >
|
||||
{
|
||||
HIMAGELIST m_ImageList;
|
||||
int m_VisibleButtonCount;
|
||||
|
||||
CBalloonQueue * m_BalloonQueue;
|
||||
|
||||
public:
|
||||
CNotifyToolbar();
|
||||
virtual ~CNotifyToolbar();
|
||||
|
||||
int GetVisibleButtonCount();
|
||||
int FindItem(IN HWND hWnd, IN UINT uID, InternalIconData ** pdata);
|
||||
int FindExistingSharedIcon(HICON handle);
|
||||
BOOL AddButton(IN CONST NOTIFYICONDATA *iconData);
|
||||
BOOL SwitchVersion(IN CONST NOTIFYICONDATA *iconData);
|
||||
BOOL UpdateButton(IN CONST NOTIFYICONDATA *iconData);
|
||||
BOOL RemoveButton(IN CONST NOTIFYICONDATA *iconData);
|
||||
VOID ResizeImagelist();
|
||||
|
||||
private:
|
||||
VOID SendMouseEvent(IN WORD wIndex, IN UINT uMsg, IN WPARAM wParam);
|
||||
LRESULT OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnTooltipShow(INT uCode, LPNMHDR hdr, BOOL& bHandled);
|
||||
|
||||
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, CBalloonQueue * queue);
|
||||
};
|
||||
|
||||
extern const WCHAR szSysPagerWndClass[];
|
||||
|
||||
class CSysPagerWnd :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public CWindowImpl < CSysPagerWnd, CWindow, CControlWinTraits >,
|
||||
public CIconWatcher
|
||||
{
|
||||
CNotifyToolbar Toolbar;
|
||||
CTooltips m_Balloons;
|
||||
CBalloonQueue m_BalloonQueue;
|
||||
|
||||
public:
|
||||
CSysPagerWnd();
|
||||
virtual ~CSysPagerWnd();
|
||||
|
||||
LRESULT DrawBackground(HDC hdc);
|
||||
LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnGetInfoTip(INT uCode, LPNMHDR hdr, BOOL& bHandled);
|
||||
LRESULT OnCustomDraw(INT uCode, LPNMHDR hdr, BOOL& bHandled);
|
||||
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnBalloonPop(UINT uCode, LPNMHDR hdr, BOOL& bHandled);
|
||||
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
|
||||
public:
|
||||
BOOL NotifyIconCmd(WPARAM wParam, LPARAM lParam);
|
||||
void GetSize(IN BOOL IsHorizontal, IN PSIZE size);
|
||||
void ResizeImagelist();
|
||||
|
||||
DECLARE_WND_CLASS_EX(szSysPagerWndClass, CS_DBLCLKS, COLOR_3DFACE)
|
||||
|
||||
BEGIN_MSG_MAP(CSysPagerWnd)
|
||||
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
||||
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
|
||||
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
||||
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
||||
MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu)
|
||||
MESSAGE_HANDLER(WM_TIMER, OnTimer)
|
||||
NOTIFY_CODE_HANDLER(TTN_POP, OnBalloonPop)
|
||||
NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip)
|
||||
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
|
||||
END_MSG_MAP()
|
||||
|
||||
HWND _Init(IN HWND hWndParent, IN BOOL bVisible);
|
||||
};
|
576
base/shell/explorer/trayclock.cpp
Normal file
576
base/shell/explorer/trayclock.cpp
Normal file
|
@ -0,0 +1,576 @@
|
|||
/*
|
||||
* ReactOS Explorer
|
||||
*
|
||||
* Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
|
||||
* Copyright 2018 Ged Murphy <gedmurphy@reactos.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
/*
|
||||
* TrayClockWnd
|
||||
*/
|
||||
|
||||
const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
|
||||
|
||||
#define ID_TRAYCLOCK_TIMER 0
|
||||
#define ID_TRAYCLOCK_TIMER_INIT 1
|
||||
|
||||
#define TRAY_CLOCK_WND_SPACING_X 0
|
||||
#define TRAY_CLOCK_WND_SPACING_Y 0
|
||||
|
||||
CTrayClockWnd::CTrayClockWnd() :
|
||||
hWndNotify(NULL),
|
||||
hFont(NULL),
|
||||
dwFlags(0),
|
||||
LineSpacing(0),
|
||||
VisibleLines(0)
|
||||
{
|
||||
ZeroMemory(&textColor, sizeof(textColor));
|
||||
ZeroMemory(&rcText, sizeof(rcText));
|
||||
ZeroMemory(&LocalTime, sizeof(LocalTime));
|
||||
ZeroMemory(&CurrentSize, sizeof(CurrentSize));
|
||||
ZeroMemory(LineSizes, sizeof(LineSizes));
|
||||
ZeroMemory(szLines, sizeof(szLines));
|
||||
}
|
||||
CTrayClockWnd::~CTrayClockWnd() { }
|
||||
|
||||
LRESULT CTrayClockWnd::OnThemeChanged()
|
||||
{
|
||||
LOGFONTW clockFont;
|
||||
HTHEME clockTheme;
|
||||
HFONT hFont;
|
||||
|
||||
clockTheme = OpenThemeData(m_hWnd, L"Clock");
|
||||
|
||||
if (clockTheme)
|
||||
{
|
||||
GetThemeFont(clockTheme,
|
||||
NULL,
|
||||
CLP_TIME,
|
||||
0,
|
||||
TMT_FONT,
|
||||
&clockFont);
|
||||
|
||||
hFont = CreateFontIndirectW(&clockFont);
|
||||
|
||||
GetThemeColor(clockTheme,
|
||||
CLP_TIME,
|
||||
0,
|
||||
TMT_TEXTCOLOR,
|
||||
&textColor);
|
||||
|
||||
if (this->hFont != NULL)
|
||||
DeleteObject(this->hFont);
|
||||
|
||||
SetFont(hFont, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't need to set a font here, our parent will use
|
||||
* WM_SETFONT to set the right one when themes are not enabled. */
|
||||
textColor = RGB(0, 0, 0);
|
||||
}
|
||||
|
||||
CloseThemeData(clockTheme);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
return OnThemeChanged();
|
||||
}
|
||||
|
||||
BOOL CTrayClockWnd::MeasureLines()
|
||||
{
|
||||
HDC hDC;
|
||||
HFONT hPrevFont;
|
||||
UINT c, i;
|
||||
BOOL bRet = TRUE;
|
||||
|
||||
hDC = GetDC();
|
||||
if (hDC != NULL)
|
||||
{
|
||||
if (hFont)
|
||||
hPrevFont = (HFONT) SelectObject(hDC, hFont);
|
||||
|
||||
for (i = 0; i < CLOCKWND_FORMAT_COUNT && bRet; i++)
|
||||
{
|
||||
if (szLines[i][0] != L'\0' &&
|
||||
!GetTextExtentPointW(hDC, szLines[i], wcslen(szLines[i]),
|
||||
&LineSizes[i]))
|
||||
{
|
||||
bRet = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hFont)
|
||||
SelectObject(hDC, hPrevFont);
|
||||
|
||||
ReleaseDC(hDC);
|
||||
|
||||
if (bRet)
|
||||
{
|
||||
LineSpacing = 0;
|
||||
|
||||
/* calculate the line spacing */
|
||||
for (i = 0, c = 0; i < CLOCKWND_FORMAT_COUNT; i++)
|
||||
{
|
||||
if (LineSizes[i].cx > 0)
|
||||
{
|
||||
LineSpacing += LineSizes[i].cy;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
if (c > 0)
|
||||
{
|
||||
/* We want a spacing of 1/2 line */
|
||||
LineSpacing = (LineSpacing / c) / 2;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WORD CTrayClockWnd::GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
|
||||
{
|
||||
WORD iLinesVisible = 0;
|
||||
UINT i;
|
||||
SIZE szMax = { 0, 0 };
|
||||
|
||||
if (!LinesMeasured)
|
||||
LinesMeasured = MeasureLines();
|
||||
|
||||
if (!LinesMeasured)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
|
||||
{
|
||||
if (LineSizes[i].cx != 0)
|
||||
{
|
||||
if (iLinesVisible > 0)
|
||||
{
|
||||
if (Horizontal)
|
||||
{
|
||||
if (szMax.cy + LineSizes[i].cy + (LONG) LineSpacing >
|
||||
pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add line spacing */
|
||||
szMax.cy += LineSpacing;
|
||||
}
|
||||
|
||||
iLinesVisible++;
|
||||
|
||||
/* Increase maximum rectangle */
|
||||
szMax.cy += LineSizes[i].cy;
|
||||
if (LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X))
|
||||
szMax.cx = LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X);
|
||||
}
|
||||
}
|
||||
|
||||
szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X;
|
||||
szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y;
|
||||
|
||||
*pSize = szMax;
|
||||
|
||||
return iLinesVisible;
|
||||
}
|
||||
|
||||
VOID CTrayClockWnd::UpdateWnd()
|
||||
{
|
||||
SIZE szPrevCurrent;
|
||||
UINT BufSize, i;
|
||||
INT iRet;
|
||||
RECT rcClient;
|
||||
|
||||
ZeroMemory(LineSizes, sizeof(LineSizes));
|
||||
|
||||
szPrevCurrent = CurrentSize;
|
||||
|
||||
for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
|
||||
{
|
||||
szLines[i][0] = L'\0';
|
||||
BufSize = _countof(szLines[0]);
|
||||
|
||||
if (ClockWndFormats[i].IsTime)
|
||||
{
|
||||
iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
|
||||
g_TaskbarSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
|
||||
&LocalTime,
|
||||
ClockWndFormats[i].lpFormat,
|
||||
szLines[i],
|
||||
BufSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
iRet = GetDateFormat(LOCALE_USER_DEFAULT,
|
||||
ClockWndFormats[i].dwFormatFlags,
|
||||
&LocalTime,
|
||||
ClockWndFormats[i].lpFormat,
|
||||
szLines[i],
|
||||
BufSize);
|
||||
}
|
||||
|
||||
if (iRet != 0 && i == 0)
|
||||
{
|
||||
/* Set the window text to the time only */
|
||||
SetWindowText(szLines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
LinesMeasured = MeasureLines();
|
||||
|
||||
if (LinesMeasured &&
|
||||
GetClientRect(&rcClient))
|
||||
{
|
||||
SIZE szWnd;
|
||||
|
||||
szWnd.cx = rcClient.right;
|
||||
szWnd.cy = rcClient.bottom;
|
||||
|
||||
VisibleLines = GetMinimumSize(IsHorizontal, &szWnd);
|
||||
CurrentSize = szWnd;
|
||||
}
|
||||
|
||||
if (IsWindowVisible())
|
||||
{
|
||||
InvalidateRect(NULL, TRUE);
|
||||
|
||||
if (hWndNotify != NULL &&
|
||||
(szPrevCurrent.cx != CurrentSize.cx ||
|
||||
szPrevCurrent.cy != CurrentSize.cy))
|
||||
{
|
||||
NMHDR nmh;
|
||||
|
||||
nmh.hwndFrom = m_hWnd;
|
||||
nmh.idFrom = GetWindowLongPtr(GWLP_ID);
|
||||
nmh.code = NTNWM_REALIGN;
|
||||
|
||||
::SendMessage(hWndNotify,
|
||||
WM_NOTIFY,
|
||||
(WPARAM) nmh.idFrom,
|
||||
(LPARAM) &nmh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID CTrayClockWnd::Update()
|
||||
{
|
||||
GetLocalTime(&LocalTime);
|
||||
UpdateWnd();
|
||||
}
|
||||
|
||||
UINT CTrayClockWnd::CalculateDueTime()
|
||||
{
|
||||
UINT uiDueTime;
|
||||
|
||||
/* Calculate the due time */
|
||||
GetLocalTime(&LocalTime);
|
||||
uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
|
||||
if (g_TaskbarSettings.bShowSeconds)
|
||||
uiDueTime += (UINT) LocalTime.wSecond * 100;
|
||||
else
|
||||
uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
|
||||
|
||||
if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM)
|
||||
uiDueTime = 1000;
|
||||
else
|
||||
{
|
||||
/* Add an artificial delay of 0.05 seconds to make sure the timer
|
||||
doesn't fire too early*/
|
||||
uiDueTime += 50;
|
||||
}
|
||||
|
||||
return uiDueTime;
|
||||
}
|
||||
|
||||
BOOL CTrayClockWnd::ResetTime()
|
||||
{
|
||||
UINT uiDueTime;
|
||||
BOOL Ret;
|
||||
|
||||
/* Disable all timers */
|
||||
if (IsTimerEnabled)
|
||||
{
|
||||
KillTimer(ID_TRAYCLOCK_TIMER);
|
||||
IsTimerEnabled = FALSE;
|
||||
}
|
||||
|
||||
if (IsInitTimerEnabled)
|
||||
{
|
||||
KillTimer(ID_TRAYCLOCK_TIMER_INIT);
|
||||
}
|
||||
|
||||
uiDueTime = CalculateDueTime();
|
||||
|
||||
/* Set the new timer */
|
||||
Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0;
|
||||
IsInitTimerEnabled = Ret;
|
||||
|
||||
/* Update the time */
|
||||
Update();
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
VOID CTrayClockWnd::CalibrateTimer()
|
||||
{
|
||||
UINT uiDueTime;
|
||||
BOOL Ret;
|
||||
UINT uiWait1, uiWait2;
|
||||
|
||||
/* Kill the initialization timer */
|
||||
KillTimer(ID_TRAYCLOCK_TIMER_INIT);
|
||||
IsInitTimerEnabled = FALSE;
|
||||
|
||||
uiDueTime = CalculateDueTime();
|
||||
|
||||
if (g_TaskbarSettings.bShowSeconds)
|
||||
{
|
||||
uiWait1 = 1000 - 200;
|
||||
uiWait2 = 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
uiWait1 = 60 * 1000 - 200;
|
||||
uiWait2 = 60 * 1000;
|
||||
}
|
||||
|
||||
if (uiDueTime > uiWait1)
|
||||
{
|
||||
/* The update of the clock will be up to 200 ms late, but that's
|
||||
acceptable. We're going to setup a timer that fires depending
|
||||
uiWait2. */
|
||||
Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0;
|
||||
IsTimerEnabled = Ret;
|
||||
|
||||
/* Update the time */
|
||||
Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Recalibrate the timer and recalculate again when the current
|
||||
minute/second ends. */
|
||||
ResetTime();
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
/* Disable all timers */
|
||||
if (IsTimerEnabled)
|
||||
{
|
||||
KillTimer(ID_TRAYCLOCK_TIMER);
|
||||
}
|
||||
|
||||
if (IsInitTimerEnabled)
|
||||
{
|
||||
KillTimer(ID_TRAYCLOCK_TIMER_INIT);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
RECT rcClient;
|
||||
HFONT hPrevFont;
|
||||
INT iPrevBkMode;
|
||||
UINT i, line;
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
HDC hDC = (HDC) wParam;
|
||||
|
||||
if (wParam == 0)
|
||||
{
|
||||
hDC = BeginPaint(&ps);
|
||||
}
|
||||
|
||||
if (hDC == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (LinesMeasured &&
|
||||
GetClientRect(&rcClient))
|
||||
{
|
||||
iPrevBkMode = SetBkMode(hDC, TRANSPARENT);
|
||||
|
||||
SetTextColor(hDC, textColor);
|
||||
|
||||
hPrevFont = (HFONT) SelectObject(hDC, hFont);
|
||||
|
||||
rcClient.left = (rcClient.right / 2) - (CurrentSize.cx / 2);
|
||||
rcClient.top = (rcClient.bottom / 2) - (CurrentSize.cy / 2);
|
||||
rcClient.right = rcClient.left + CurrentSize.cx;
|
||||
rcClient.bottom = rcClient.top + CurrentSize.cy;
|
||||
|
||||
for (i = 0, line = 0;
|
||||
i < CLOCKWND_FORMAT_COUNT && line < VisibleLines;
|
||||
i++)
|
||||
{
|
||||
if (LineSizes[i].cx != 0)
|
||||
{
|
||||
TextOut(hDC,
|
||||
rcClient.left + (CurrentSize.cx / 2) - (LineSizes[i].cx / 2) +
|
||||
TRAY_CLOCK_WND_SPACING_X,
|
||||
rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
|
||||
szLines[i],
|
||||
wcslen(szLines[i]));
|
||||
|
||||
rcClient.top += LineSizes[i].cy + LineSpacing;
|
||||
line++;
|
||||
}
|
||||
}
|
||||
|
||||
SelectObject(hDC, hPrevFont);
|
||||
|
||||
SetBkMode(hDC, iPrevBkMode);
|
||||
}
|
||||
|
||||
if (wParam == 0)
|
||||
{
|
||||
EndPaint(&ps);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID CTrayClockWnd::SetFont(IN HFONT hNewFont, IN BOOL bRedraw)
|
||||
{
|
||||
hFont = hNewFont;
|
||||
LinesMeasured = MeasureLines();
|
||||
if (bRedraw)
|
||||
{
|
||||
InvalidateRect(NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::DrawBackground(HDC hdc)
|
||||
{
|
||||
RECT rect;
|
||||
|
||||
GetClientRect(&rect);
|
||||
DrawThemeParentBackground(m_hWnd, hdc, &rect);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
HDC hdc = (HDC) wParam;
|
||||
|
||||
if (!IsAppThemed())
|
||||
{
|
||||
bHandled = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DrawBackground(hdc);
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case ID_TRAYCLOCK_TIMER:
|
||||
Update();
|
||||
break;
|
||||
|
||||
case ID_TRAYCLOCK_TIMER_INIT:
|
||||
CalibrateTimer();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
IsHorizontal = (BOOL) wParam;
|
||||
|
||||
return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam) != 0;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
return (LRESULT) ResetTime();
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
SetFont((HFONT) wParam, (BOOL) LOWORD(lParam));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
ResetTime();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LRESULT CTrayClockWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
||||
{
|
||||
SIZE szClient;
|
||||
|
||||
szClient.cx = LOWORD(lParam);
|
||||
szClient.cy = HIWORD(lParam);
|
||||
|
||||
VisibleLines = GetMinimumSize(IsHorizontal, &szClient);
|
||||
CurrentSize = szClient;
|
||||
|
||||
InvalidateRect(NULL, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HWND CTrayClockWnd::_Init(IN HWND hWndParent, IN BOOL bVisible)
|
||||
{
|
||||
IsHorizontal = TRUE;
|
||||
|
||||
hWndNotify = hWndParent;
|
||||
|
||||
/* Create the window. The tray window is going to move it to the correct
|
||||
position and resize it as needed. */
|
||||
DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
|
||||
if (bVisible)
|
||||
dwStyle |= WS_VISIBLE;
|
||||
|
||||
Create(hWndParent, 0, NULL, dwStyle);
|
||||
|
||||
if (m_hWnd != NULL)
|
||||
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
|
||||
|
||||
return m_hWnd;
|
||||
|
||||
};
|
94
base/shell/explorer/trayclock.h
Normal file
94
base/shell/explorer/trayclock.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
const struct
|
||||
{
|
||||
BOOL IsTime;
|
||||
DWORD dwFormatFlags;
|
||||
LPCWSTR lpFormat;
|
||||
} ClockWndFormats[] = {
|
||||
{ TRUE, 0, NULL },
|
||||
{ FALSE, 0, L"dddd" },
|
||||
{ FALSE, DATE_SHORTDATE, NULL }
|
||||
};
|
||||
const UINT ClockWndFormatsCount = _ARRAYSIZE(ClockWndFormats);
|
||||
|
||||
#define CLOCKWND_FORMAT_COUNT ClockWndFormatsCount
|
||||
|
||||
extern const WCHAR szTrayClockWndClass[];
|
||||
class CTrayClockWnd :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits >
|
||||
{
|
||||
HWND hWndNotify;
|
||||
HFONT hFont;
|
||||
COLORREF textColor;
|
||||
RECT rcText;
|
||||
SYSTEMTIME LocalTime;
|
||||
|
||||
union
|
||||
{
|
||||
DWORD dwFlags;
|
||||
struct
|
||||
{
|
||||
DWORD IsTimerEnabled : 1;
|
||||
DWORD IsInitTimerEnabled : 1;
|
||||
DWORD LinesMeasured : 1;
|
||||
DWORD IsHorizontal : 1;
|
||||
};
|
||||
};
|
||||
DWORD LineSpacing;
|
||||
SIZE CurrentSize;
|
||||
WORD VisibleLines;
|
||||
SIZE LineSizes[CLOCKWND_FORMAT_COUNT];
|
||||
WCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
|
||||
|
||||
public:
|
||||
CTrayClockWnd();
|
||||
virtual ~CTrayClockWnd();
|
||||
|
||||
private:
|
||||
LRESULT OnThemeChanged();
|
||||
LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
|
||||
BOOL MeasureLines();
|
||||
WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize);
|
||||
VOID UpdateWnd();
|
||||
VOID Update();
|
||||
UINT CalculateDueTime();
|
||||
BOOL ResetTime();
|
||||
VOID CalibrateTimer();
|
||||
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
VOID SetFont(IN HFONT hNewFont, IN BOOL bRedraw);
|
||||
LRESULT DrawBackground(HDC hdc);
|
||||
LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
public:
|
||||
LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
||||
|
||||
public:
|
||||
DECLARE_WND_CLASS_EX(szTrayClockWndClass, CS_DBLCLKS, COLOR_3DFACE)
|
||||
|
||||
BEGIN_MSG_MAP(CTrayClockWnd)
|
||||
MESSAGE_HANDLER(WM_CREATE, OnCreate)
|
||||
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
|
||||
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
|
||||
MESSAGE_HANDLER(WM_SIZE, OnSize)
|
||||
MESSAGE_HANDLER(WM_PAINT, OnPaint)
|
||||
MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
|
||||
MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
|
||||
MESSAGE_HANDLER(WM_TIMER, OnTimer)
|
||||
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
|
||||
MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
|
||||
MESSAGE_HANDLER(TCWM_GETMINIMUMSIZE, OnGetMinimumSize)
|
||||
MESSAGE_HANDLER(TCWM_UPDATETIME, OnUpdateTime)
|
||||
|
||||
END_MSG_MAP()
|
||||
|
||||
HWND _Init(IN HWND hWndParent, IN BOOL bVisible);
|
||||
};
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue