2018-01-24 13:41:06 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2018-01-28 12:21:45 +00:00
|
|
|
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
|
2023-07-08 22:04:45 +00:00
|
|
|
#define CLOCKWND_FORMAT_TIME 0
|
|
|
|
#define CLOCKWND_FORMAT_DAY 1
|
|
|
|
#define CLOCKWND_FORMAT_DATE 2
|
2018-01-28 12:21:45 +00:00
|
|
|
|
2019-04-22 19:25:41 +00:00
|
|
|
static const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
|
2018-01-28 12:21:45 +00:00
|
|
|
|
|
|
|
class CTrayClockWnd :
|
|
|
|
public CComCoClass<CTrayClockWnd>,
|
|
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
|
|
public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits >,
|
|
|
|
public IOleWindow
|
|
|
|
{
|
|
|
|
HFONT hFont;
|
|
|
|
COLORREF textColor;
|
|
|
|
RECT rcText;
|
|
|
|
SYSTEMTIME LocalTime;
|
2019-03-23 16:16:44 +00:00
|
|
|
CTooltips m_tooltip;
|
2018-01-28 12:21:45 +00:00
|
|
|
|
|
|
|
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);
|
2019-10-08 23:18:36 +00:00
|
|
|
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
2018-01-28 12:21:45 +00:00
|
|
|
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);
|
|
|
|
LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
2019-03-23 16:16:44 +00:00
|
|
|
LRESULT OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
2023-07-08 22:04:45 +00:00
|
|
|
VOID PaintLine(IN HDC hDC, IN OUT RECT *rcClient, IN UINT LineNumber, IN UINT szLinesIndex);
|
2018-01-28 12:21:45 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
HRESULT WINAPI GetWindow(HWND* phwnd)
|
|
|
|
{
|
|
|
|
if (!phwnd)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*phwnd = m_hWnd;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECLARE_NOT_AGGREGATABLE(CTrayClockWnd)
|
|
|
|
|
|
|
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
|
|
|
BEGIN_COM_MAP(CTrayClockWnd)
|
|
|
|
COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
|
|
|
|
END_COM_MAP()
|
|
|
|
|
|
|
|
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)
|
2019-10-08 23:18:36 +00:00
|
|
|
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
|
2018-01-28 12:21:45 +00:00
|
|
|
MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
|
|
|
|
MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize)
|
|
|
|
MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
|
2019-03-23 16:16:44 +00:00
|
|
|
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClick)
|
2018-01-28 12:21:45 +00:00
|
|
|
END_MSG_MAP()
|
|
|
|
|
|
|
|
HRESULT Initialize(IN HWND hWndParent);
|
|
|
|
};
|
|
|
|
|
2018-01-24 13:41:06 +00:00
|
|
|
#define ID_TRAYCLOCK_TIMER 0
|
|
|
|
#define ID_TRAYCLOCK_TIMER_INIT 1
|
|
|
|
|
2018-01-30 17:42:21 +00:00
|
|
|
#define TRAY_CLOCK_WND_SPACING_X 5
|
2018-01-24 13:41:06 +00:00
|
|
|
#define TRAY_CLOCK_WND_SPACING_Y 0
|
|
|
|
|
|
|
|
CTrayClockWnd::CTrayClockWnd() :
|
|
|
|
hFont(NULL),
|
2023-03-25 12:31:32 +00:00
|
|
|
textColor(0),
|
2018-01-24 13:41:06 +00:00
|
|
|
dwFlags(0),
|
|
|
|
LineSpacing(0),
|
|
|
|
VisibleLines(0)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2023-03-25 12:31:32 +00:00
|
|
|
GetThemeFont(clockTheme, NULL, CLP_TIME, 0, TMT_FONT, &clockFont);
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
hFont = CreateFontIndirectW(&clockFont);
|
|
|
|
|
2023-03-25 12:31:32 +00:00
|
|
|
GetThemeColor(clockTheme, CLP_TIME, 0, TMT_TEXTCOLOR, &textColor);
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
if (this->hFont != NULL)
|
|
|
|
DeleteObject(this->hFont);
|
|
|
|
|
|
|
|
SetFont(hFont, FALSE);
|
|
|
|
|
2023-03-25 12:31:32 +00:00
|
|
|
CloseThemeData(clockTheme);
|
|
|
|
}
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2023-08-04 11:20:19 +00:00
|
|
|
/* Prevents the date from being cut off when the day of the week is shorter than the date. */
|
|
|
|
if (VisibleLines > 1 && g_TaskbarSettings.bPreferDate)
|
|
|
|
szMax.cx = LineSizes[CLOCKWND_FORMAT_DATE].cx;
|
|
|
|
|
2018-01-24 13:41:06 +00:00
|
|
|
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;
|
2018-01-29 20:32:17 +00:00
|
|
|
if (LineSizes[i].cx > szMax.cx)
|
|
|
|
szMax.cx = LineSizes[i].cx;
|
2018-01-24 13:41:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-01-26 23:27:24 +00:00
|
|
|
if (szPrevCurrent.cx != CurrentSize.cx ||
|
|
|
|
szPrevCurrent.cy != CurrentSize.cy)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
2018-01-26 23:27:24 +00:00
|
|
|
/* Ask the parent to resize */
|
|
|
|
NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
|
|
|
|
GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
|
2018-01-24 13:41:06 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-23 16:16:44 +00:00
|
|
|
|
|
|
|
int iDateLength = GetDateFormat(LOCALE_USER_DEFAULT,
|
|
|
|
DATE_LONGDATE,
|
|
|
|
&LocalTime,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
if (iDateLength <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WCHAR* szDate = new WCHAR[iDateLength];
|
|
|
|
if (GetDateFormat(LOCALE_USER_DEFAULT,
|
|
|
|
DATE_LONGDATE,
|
|
|
|
&LocalTime,
|
|
|
|
NULL,
|
|
|
|
szDate,
|
|
|
|
iDateLength) > 0)
|
|
|
|
{
|
|
|
|
m_tooltip.UpdateTipText(m_hWnd,
|
|
|
|
reinterpret_cast<UINT_PTR>(m_hWnd),
|
|
|
|
szDate);
|
|
|
|
}
|
|
|
|
delete[] szDate;
|
2018-01-24 13:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID CTrayClockWnd::Update()
|
|
|
|
{
|
|
|
|
GetLocalTime(&LocalTime);
|
|
|
|
UpdateWnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT CTrayClockWnd::CalculateDueTime()
|
|
|
|
{
|
|
|
|
UINT uiDueTime;
|
|
|
|
|
|
|
|
GetLocalTime(&LocalTime);
|
|
|
|
uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
|
2020-01-24 03:41:00 +00:00
|
|
|
if (!g_TaskbarSettings.bShowSeconds)
|
2018-01-24 13:41:06 +00:00
|
|
|
uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
|
|
|
|
|
|
|
|
return uiDueTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CTrayClockWnd::ResetTime()
|
|
|
|
{
|
|
|
|
UINT uiDueTime;
|
|
|
|
BOOL Ret;
|
|
|
|
|
|
|
|
/* Disable all timers */
|
|
|
|
if (IsTimerEnabled)
|
|
|
|
{
|
|
|
|
KillTimer(ID_TRAYCLOCK_TIMER);
|
|
|
|
IsTimerEnabled = FALSE;
|
|
|
|
}
|
2020-01-24 13:47:58 +00:00
|
|
|
else if (IsInitTimerEnabled)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
|
|
|
KillTimer(ID_TRAYCLOCK_TIMER_INIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
uiDueTime = CalculateDueTime();
|
|
|
|
|
|
|
|
/* Set the new timer */
|
|
|
|
Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0;
|
|
|
|
IsInitTimerEnabled = Ret;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Recalibrate the timer and recalculate again when the current
|
|
|
|
minute/second ends. */
|
|
|
|
ResetTime();
|
|
|
|
}
|
2020-01-24 13:47:58 +00:00
|
|
|
|
|
|
|
/* Update the time */
|
|
|
|
Update();
|
2018-01-24 13:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
|
|
{
|
|
|
|
/* Disable all timers */
|
|
|
|
if (IsTimerEnabled)
|
|
|
|
{
|
|
|
|
KillTimer(ID_TRAYCLOCK_TIMER);
|
|
|
|
}
|
2020-01-24 13:47:58 +00:00
|
|
|
else if (IsInitTimerEnabled)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2023-03-25 12:31:32 +00:00
|
|
|
if (!IsAppThemed())
|
|
|
|
textColor = ::GetSysColor(COLOR_BTNTEXT);
|
|
|
|
|
|
|
|
::SetTextColor(hDC, textColor);
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
hPrevFont = (HFONT) SelectObject(hDC, hFont);
|
|
|
|
|
2018-08-12 13:12:13 +00:00
|
|
|
rcClient.top = (rcClient.bottom - CurrentSize.cy) / 2;
|
2018-01-24 13:41:06 +00:00
|
|
|
rcClient.bottom = rcClient.top + CurrentSize.cy;
|
|
|
|
|
2023-07-08 22:04:45 +00:00
|
|
|
if (VisibleLines == 2)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
2023-07-08 22:04:45 +00:00
|
|
|
/* Display either time and weekday (by default), or time and date (opt-in) */
|
|
|
|
PaintLine(hDC, &rcClient, 0, CLOCKWND_FORMAT_TIME);
|
|
|
|
PaintLine(hDC, &rcClient, 1,
|
|
|
|
g_TaskbarSettings.bPreferDate ? CLOCKWND_FORMAT_DATE : CLOCKWND_FORMAT_DAY);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0, line = 0;
|
|
|
|
i < CLOCKWND_FORMAT_COUNT && line < VisibleLines;
|
|
|
|
i++)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
2023-07-08 22:04:45 +00:00
|
|
|
PaintLine(hDC, &rcClient, i, i);
|
2018-01-24 13:41:06 +00:00
|
|
|
line++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SelectObject(hDC, hPrevFont);
|
|
|
|
|
|
|
|
SetBkMode(hDC, iPrevBkMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wParam == 0)
|
|
|
|
EndPaint(&ps);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2023-07-08 22:04:45 +00:00
|
|
|
VOID CTrayClockWnd::PaintLine(IN HDC hDC, IN OUT RECT *rcClient, IN UINT LineNumber, IN UINT szLinesIndex)
|
|
|
|
{
|
|
|
|
if (LineSizes[LineNumber].cx == 0)
|
|
|
|
return;
|
|
|
|
|
2023-08-04 11:20:19 +00:00
|
|
|
INT HShift = ((IsHorizontal && (VisibleLines <= 1 ||
|
2023-12-23 20:21:12 +00:00
|
|
|
g_TaskbarSettings.UseCompactTrayIcons())) ? 0 : TRAY_CLOCK_WND_SPACING_X);
|
2023-08-04 11:20:19 +00:00
|
|
|
|
2023-07-08 22:04:45 +00:00
|
|
|
TextOut(hDC,
|
2023-08-04 11:20:19 +00:00
|
|
|
((rcClient->right - LineSizes[szLinesIndex].cx) / 2) + HShift,
|
2023-07-08 22:04:45 +00:00
|
|
|
rcClient->top + TRAY_CLOCK_WND_SPACING_Y,
|
|
|
|
szLines[szLinesIndex],
|
|
|
|
wcslen(szLines[szLinesIndex]));
|
|
|
|
|
|
|
|
rcClient->top += LineSizes[LineNumber].cy + LineSpacing;
|
|
|
|
}
|
|
|
|
|
2018-01-24 13:41:06 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-08 23:18:36 +00:00
|
|
|
LRESULT CTrayClockWnd::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
2019-10-08 23:18:36 +00:00
|
|
|
return GetParent().SendMessage(uMsg, wParam, lParam);
|
2018-01-24 13:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2019-03-23 16:16:44 +00:00
|
|
|
m_tooltip.Create(m_hWnd, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP);
|
|
|
|
|
|
|
|
TOOLINFOW ti = { 0 };
|
|
|
|
ti.cbSize = TTTOOLINFOW_V1_SIZE;
|
|
|
|
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
|
|
|
|
ti.hwnd = m_hWnd;
|
|
|
|
ti.uId = reinterpret_cast<UINT_PTR>(m_hWnd);
|
|
|
|
ti.lpszText = NULL;
|
|
|
|
ti.lParam = NULL;
|
|
|
|
|
|
|
|
m_tooltip.AddTool(&ti);
|
|
|
|
|
2020-01-24 13:47:58 +00:00
|
|
|
if (!g_TaskbarSettings.sr.HideClock)
|
|
|
|
{
|
|
|
|
ResetTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the time */
|
|
|
|
Update();
|
|
|
|
|
2018-01-24 13:41:06 +00:00
|
|
|
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;
|
|
|
|
|
2023-12-23 20:21:12 +00:00
|
|
|
UpdateWnd();
|
2018-01-24 13:41:06 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-01-26 23:27:24 +00:00
|
|
|
LRESULT CTrayClockWnd::OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
2018-01-24 13:41:06 +00:00
|
|
|
{
|
2018-01-28 16:59:18 +00:00
|
|
|
BOOL bRealign = FALSE;
|
|
|
|
|
2018-01-26 23:27:24 +00:00
|
|
|
TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
|
|
|
|
if (newSettings->bShowSeconds != g_TaskbarSettings.bShowSeconds)
|
|
|
|
{
|
|
|
|
g_TaskbarSettings.bShowSeconds = newSettings->bShowSeconds;
|
2020-01-24 13:47:58 +00:00
|
|
|
if (!g_TaskbarSettings.sr.HideClock)
|
|
|
|
{
|
|
|
|
bRealign = TRUE;
|
|
|
|
|
|
|
|
ResetTime();
|
|
|
|
}
|
2018-01-26 23:27:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newSettings->sr.HideClock != g_TaskbarSettings.sr.HideClock)
|
|
|
|
{
|
|
|
|
g_TaskbarSettings.sr.HideClock = newSettings->sr.HideClock;
|
2018-01-28 16:59:18 +00:00
|
|
|
ShowWindow(g_TaskbarSettings.sr.HideClock ? SW_HIDE : SW_SHOW);
|
|
|
|
bRealign = TRUE;
|
2020-01-24 13:47:58 +00:00
|
|
|
|
|
|
|
if (g_TaskbarSettings.sr.HideClock)
|
|
|
|
{
|
|
|
|
/* Disable all timers */
|
|
|
|
if (IsTimerEnabled)
|
|
|
|
{
|
|
|
|
KillTimer(ID_TRAYCLOCK_TIMER);
|
|
|
|
IsTimerEnabled = FALSE;
|
|
|
|
}
|
|
|
|
else if (IsInitTimerEnabled)
|
|
|
|
{
|
|
|
|
KillTimer(ID_TRAYCLOCK_TIMER_INIT);
|
|
|
|
IsInitTimerEnabled = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ResetTime();
|
|
|
|
}
|
2018-01-26 23:27:24 +00:00
|
|
|
}
|
|
|
|
|
2023-07-08 22:04:45 +00:00
|
|
|
if (newSettings->bPreferDate != g_TaskbarSettings.bPreferDate)
|
|
|
|
{
|
|
|
|
g_TaskbarSettings.bPreferDate = newSettings->bPreferDate;
|
|
|
|
bRealign = TRUE;
|
|
|
|
}
|
|
|
|
|
2018-01-28 16:59:18 +00:00
|
|
|
if (bRealign)
|
|
|
|
{
|
|
|
|
/* Ask the parent to resize */
|
|
|
|
NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
|
|
|
|
GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
|
|
|
|
Update();
|
|
|
|
}
|
2018-01-26 23:27:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2018-01-24 13:41:06 +00:00
|
|
|
|
2019-03-23 16:16:44 +00:00
|
|
|
LRESULT CTrayClockWnd::OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
2018-01-26 23:27:24 +00:00
|
|
|
{
|
|
|
|
if (IsWindowVisible())
|
|
|
|
{
|
2019-03-23 16:16:44 +00:00
|
|
|
//FIXME: use SHRunControlPanel
|
|
|
|
ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
|
2018-01-26 23:27:24 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-01-28 12:21:45 +00:00
|
|
|
HRESULT CTrayClockWnd::Initialize(IN HWND hWndParent)
|
2018-01-26 23:27:24 +00:00
|
|
|
{
|
|
|
|
IsHorizontal = TRUE;
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
/* 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;
|
2018-01-26 23:27:24 +00:00
|
|
|
if (!g_TaskbarSettings.sr.HideClock)
|
2018-01-24 13:41:06 +00:00
|
|
|
dwStyle |= WS_VISIBLE;
|
|
|
|
|
|
|
|
Create(hWndParent, 0, NULL, dwStyle);
|
2018-01-28 12:21:45 +00:00
|
|
|
if (!m_hWnd)
|
|
|
|
return E_FAIL;
|
2018-01-24 13:41:06 +00:00
|
|
|
|
2018-01-28 12:21:45 +00:00
|
|
|
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
|
2018-01-24 13:41:06 +00:00
|
|
|
|
2018-01-28 12:21:45 +00:00
|
|
|
return S_OK;
|
2018-01-24 13:41:06 +00:00
|
|
|
|
|
|
|
};
|
2018-01-28 12:21:45 +00:00
|
|
|
|
|
|
|
HRESULT CTrayClockWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv)
|
|
|
|
{
|
|
|
|
return ShellObjectCreatorInit<CTrayClockWnd>(hwndParent, riid, ppv);
|
|
|
|
}
|