reactos/base/shell/explorer/trayclock.cpp
Carl J. Bialorucki 77653462a9
[EXPLORER] Notification area icon improvements (#6169)
Automatically adjusts the spacing of the tray icons according to the small
or large taskbar icons setting. Also, a minor bug fix to the clock spacing
when switching between taskbar icon sizes.

CORE-19380

Update the ROS-specific CompactTrayIcons registry value from a binary
yes/no to have three states. The three states are as follows:

  0 (default) - Automatic. When small taskbar icons are used, the
  notification area will use compact tray icon spacing. When large
  taskbar icons are used, the notification area will use larger tray
  icon spacing. While no version of Windows behaves this way, I believe
  this is a smart default choice for ReactOS since users wanting large
  taskbar icons will generally expect larger tray icon spacing, while
  users with small taskbar icons may want more compact spacing.

  1 - Never Compact. Regardless of the taskbar icon size setting, the
  notification area will always use the larger spacing. This follows
  the behavior of Windows 7 and newer versions.

  2 - Always Compact. Regardless of the taskbar icon size setting, the
  notification area will always use the compact spacing. This follows
  the behavior of Windows Vista and older versions.

Fix a clock spacing bug that occurs when changing the taskbar size
before advancing to the next minute. The taskbar clock now adjusts
its spacing when the size of the taskbar changes.
2023-12-23 21:21:12 +01:00

783 lines
20 KiB
C++

/*
* 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 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
#define CLOCKWND_FORMAT_TIME 0
#define CLOCKWND_FORMAT_DAY 1
#define CLOCKWND_FORMAT_DATE 2
static const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
class CTrayClockWnd :
public CComCoClass<CTrayClockWnd>,
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits >,
public IOleWindow
{
HFONT hFont;
COLORREF textColor;
RECT rcText;
SYSTEMTIME LocalTime;
CTooltips m_tooltip;
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 OnContextMenu(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);
LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
VOID PaintLine(IN HDC hDC, IN OUT RECT *rcClient, IN UINT LineNumber, IN UINT szLinesIndex);
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)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize)
MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClick)
END_MSG_MAP()
HRESULT Initialize(IN HWND hWndParent);
};
#define ID_TRAYCLOCK_TIMER 0
#define ID_TRAYCLOCK_TIMER_INIT 1
#define TRAY_CLOCK_WND_SPACING_X 5
#define TRAY_CLOCK_WND_SPACING_Y 0
CTrayClockWnd::CTrayClockWnd() :
hFont(NULL),
textColor(0),
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)
{
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);
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;
/* 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;
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)
szMax.cx = LineSizes[i].cx;
}
}
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 (szPrevCurrent.cx != CurrentSize.cx ||
szPrevCurrent.cy != CurrentSize.cy)
{
/* Ask the parent to resize */
NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
}
}
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;
}
VOID CTrayClockWnd::Update()
{
GetLocalTime(&LocalTime);
UpdateWnd();
}
UINT CTrayClockWnd::CalculateDueTime()
{
UINT uiDueTime;
GetLocalTime(&LocalTime);
uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
if (!g_TaskbarSettings.bShowSeconds)
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;
}
else if (IsInitTimerEnabled)
{
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();
}
/* Update the time */
Update();
}
LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
/* Disable all timers */
if (IsTimerEnabled)
{
KillTimer(ID_TRAYCLOCK_TIMER);
}
else 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);
if (!IsAppThemed())
textColor = ::GetSysColor(COLOR_BTNTEXT);
::SetTextColor(hDC, textColor);
hPrevFont = (HFONT) SelectObject(hDC, hFont);
rcClient.top = (rcClient.bottom - CurrentSize.cy) / 2;
rcClient.bottom = rcClient.top + CurrentSize.cy;
if (VisibleLines == 2)
{
/* 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++)
{
PaintLine(hDC, &rcClient, i, i);
line++;
}
}
SelectObject(hDC, hPrevFont);
SetBkMode(hDC, iPrevBkMode);
}
if (wParam == 0)
EndPaint(&ps);
return TRUE;
}
VOID CTrayClockWnd::PaintLine(IN HDC hDC, IN OUT RECT *rcClient, IN UINT LineNumber, IN UINT szLinesIndex)
{
if (LineSizes[LineNumber].cx == 0)
return;
INT HShift = ((IsHorizontal && (VisibleLines <= 1 ||
g_TaskbarSettings.UseCompactTrayIcons())) ? 0 : TRAY_CLOCK_WND_SPACING_X);
TextOut(hDC,
((rcClient->right - LineSizes[szLinesIndex].cx) / 2) + HShift,
rcClient->top + TRAY_CLOCK_WND_SPACING_Y,
szLines[szLinesIndex],
wcslen(szLines[szLinesIndex]));
rcClient->top += LineSizes[LineNumber].cy + LineSpacing;
}
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::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return GetParent().SendMessage(uMsg, wParam, lParam);
}
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)
{
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);
if (!g_TaskbarSettings.sr.HideClock)
{
ResetTime();
}
/* Update the time */
Update();
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;
UpdateWnd();
return TRUE;
}
LRESULT CTrayClockWnd::OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
BOOL bRealign = FALSE;
TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
if (newSettings->bShowSeconds != g_TaskbarSettings.bShowSeconds)
{
g_TaskbarSettings.bShowSeconds = newSettings->bShowSeconds;
if (!g_TaskbarSettings.sr.HideClock)
{
bRealign = TRUE;
ResetTime();
}
}
if (newSettings->sr.HideClock != g_TaskbarSettings.sr.HideClock)
{
g_TaskbarSettings.sr.HideClock = newSettings->sr.HideClock;
ShowWindow(g_TaskbarSettings.sr.HideClock ? SW_HIDE : SW_SHOW);
bRealign = TRUE;
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();
}
}
if (newSettings->bPreferDate != g_TaskbarSettings.bPreferDate)
{
g_TaskbarSettings.bPreferDate = newSettings->bPreferDate;
bRealign = TRUE;
}
if (bRealign)
{
/* Ask the parent to resize */
NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
Update();
}
return 0;
}
LRESULT CTrayClockWnd::OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (IsWindowVisible())
{
//FIXME: use SHRunControlPanel
ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
}
return TRUE;
}
HRESULT CTrayClockWnd::Initialize(IN HWND hWndParent)
{
IsHorizontal = TRUE;
/* 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 (!g_TaskbarSettings.sr.HideClock)
dwStyle |= WS_VISIBLE;
Create(hWndParent, 0, NULL, dwStyle);
if (!m_hWnd)
return E_FAIL;
SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
return S_OK;
};
HRESULT CTrayClockWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv)
{
return ShellObjectCreatorInit<CTrayClockWnd>(hwndParent, riid, ppv);
}