b4e85d951c3673fe2df4462b1ca4d7c7ad86aab2
[reactos.git] / base / shell / explorer / trayclock.cpp
1 /*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 * Copyright 2018 Ged Murphy <gedmurphy@reactos.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "precomp.h"
23
24 /*
25 * TrayClockWnd
26 */
27
28 const struct
29 {
30 BOOL IsTime;
31 DWORD dwFormatFlags;
32 LPCWSTR lpFormat;
33 } ClockWndFormats[] = {
34 { TRUE, 0, NULL },
35 { FALSE, 0, L"dddd" },
36 { FALSE, DATE_SHORTDATE, NULL }
37 };
38 const UINT ClockWndFormatsCount = _ARRAYSIZE(ClockWndFormats);
39
40 #define CLOCKWND_FORMAT_COUNT ClockWndFormatsCount
41
42 extern const WCHAR szTrayClockWndClass[];
43
44 class CTrayClockWnd :
45 public CComCoClass<CTrayClockWnd>,
46 public CComObjectRootEx<CComMultiThreadModelNoCS>,
47 public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits >,
48 public IOleWindow
49 {
50 HFONT hFont;
51 COLORREF textColor;
52 RECT rcText;
53 SYSTEMTIME LocalTime;
54
55 union
56 {
57 DWORD dwFlags;
58 struct
59 {
60 DWORD IsTimerEnabled : 1;
61 DWORD IsInitTimerEnabled : 1;
62 DWORD LinesMeasured : 1;
63 DWORD IsHorizontal : 1;
64 };
65 };
66 DWORD LineSpacing;
67 SIZE CurrentSize;
68 WORD VisibleLines;
69 SIZE LineSizes[CLOCKWND_FORMAT_COUNT];
70 WCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
71
72 public:
73 CTrayClockWnd();
74 virtual ~CTrayClockWnd();
75
76 private:
77 LRESULT OnThemeChanged();
78 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
79
80 BOOL MeasureLines();
81 WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize);
82 VOID UpdateWnd();
83 VOID Update();
84 UINT CalculateDueTime();
85 BOOL ResetTime();
86 VOID CalibrateTimer();
87 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
88 LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
89 VOID SetFont(IN HFONT hNewFont, IN BOOL bRedraw);
90 LRESULT DrawBackground(HDC hdc);
91 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
92 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
93 LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
94 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
95 LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
96 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
97 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
98 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
99 LRESULT OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
100
101 public:
102
103 HRESULT WINAPI GetWindow(HWND* phwnd)
104 {
105 if (!phwnd)
106 return E_INVALIDARG;
107 *phwnd = m_hWnd;
108 return S_OK;
109 }
110
111 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
112 {
113 return E_NOTIMPL;
114 }
115
116 DECLARE_NOT_AGGREGATABLE(CTrayClockWnd)
117
118 DECLARE_PROTECT_FINAL_CONSTRUCT()
119 BEGIN_COM_MAP(CTrayClockWnd)
120 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
121 END_COM_MAP()
122
123 DECLARE_WND_CLASS_EX(szTrayClockWndClass, CS_DBLCLKS, COLOR_3DFACE)
124
125 BEGIN_MSG_MAP(CTrayClockWnd)
126 MESSAGE_HANDLER(WM_CREATE, OnCreate)
127 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
128 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
129 MESSAGE_HANDLER(WM_SIZE, OnSize)
130 MESSAGE_HANDLER(WM_PAINT, OnPaint)
131 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
132 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
133 MESSAGE_HANDLER(WM_TIMER, OnTimer)
134 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
135 MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
136 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize)
137 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
138 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick)
139 END_MSG_MAP()
140
141 HRESULT Initialize(IN HWND hWndParent);
142 };
143
144 const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
145
146 #define ID_TRAYCLOCK_TIMER 0
147 #define ID_TRAYCLOCK_TIMER_INIT 1
148
149 #define TRAY_CLOCK_WND_SPACING_X 5
150 #define TRAY_CLOCK_WND_SPACING_Y 0
151
152 CTrayClockWnd::CTrayClockWnd() :
153 hFont(NULL),
154 dwFlags(0),
155 LineSpacing(0),
156 VisibleLines(0)
157 {
158 ZeroMemory(&textColor, sizeof(textColor));
159 ZeroMemory(&rcText, sizeof(rcText));
160 ZeroMemory(&LocalTime, sizeof(LocalTime));
161 ZeroMemory(&CurrentSize, sizeof(CurrentSize));
162 ZeroMemory(LineSizes, sizeof(LineSizes));
163 ZeroMemory(szLines, sizeof(szLines));
164 }
165 CTrayClockWnd::~CTrayClockWnd() { }
166
167 LRESULT CTrayClockWnd::OnThemeChanged()
168 {
169 LOGFONTW clockFont;
170 HTHEME clockTheme;
171 HFONT hFont;
172
173 clockTheme = OpenThemeData(m_hWnd, L"Clock");
174
175 if (clockTheme)
176 {
177 GetThemeFont(clockTheme,
178 NULL,
179 CLP_TIME,
180 0,
181 TMT_FONT,
182 &clockFont);
183
184 hFont = CreateFontIndirectW(&clockFont);
185
186 GetThemeColor(clockTheme,
187 CLP_TIME,
188 0,
189 TMT_TEXTCOLOR,
190 &textColor);
191
192 if (this->hFont != NULL)
193 DeleteObject(this->hFont);
194
195 SetFont(hFont, FALSE);
196 }
197 else
198 {
199 /* We don't need to set a font here, our parent will use
200 * WM_SETFONT to set the right one when themes are not enabled. */
201 textColor = RGB(0, 0, 0);
202 }
203
204 CloseThemeData(clockTheme);
205
206 return TRUE;
207 }
208
209 LRESULT CTrayClockWnd::OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
210 {
211 return OnThemeChanged();
212 }
213
214 BOOL CTrayClockWnd::MeasureLines()
215 {
216 HDC hDC;
217 HFONT hPrevFont;
218 UINT c, i;
219 BOOL bRet = TRUE;
220
221 hDC = GetDC();
222 if (hDC != NULL)
223 {
224 if (hFont)
225 hPrevFont = (HFONT) SelectObject(hDC, hFont);
226
227 for (i = 0; i < CLOCKWND_FORMAT_COUNT && bRet; i++)
228 {
229 if (szLines[i][0] != L'\0' &&
230 !GetTextExtentPointW(hDC, szLines[i], wcslen(szLines[i]),
231 &LineSizes[i]))
232 {
233 bRet = FALSE;
234 break;
235 }
236 }
237
238 if (hFont)
239 SelectObject(hDC, hPrevFont);
240
241 ReleaseDC(hDC);
242
243 if (bRet)
244 {
245 LineSpacing = 0;
246
247 /* calculate the line spacing */
248 for (i = 0, c = 0; i < CLOCKWND_FORMAT_COUNT; i++)
249 {
250 if (LineSizes[i].cx > 0)
251 {
252 LineSpacing += LineSizes[i].cy;
253 c++;
254 }
255 }
256
257 if (c > 0)
258 {
259 /* We want a spacing of 1/2 line */
260 LineSpacing = (LineSpacing / c) / 2;
261 }
262
263 return TRUE;
264 }
265 }
266
267 return FALSE;
268 }
269
270 WORD CTrayClockWnd::GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
271 {
272 WORD iLinesVisible = 0;
273 UINT i;
274 SIZE szMax = { 0, 0 };
275
276 if (!LinesMeasured)
277 LinesMeasured = MeasureLines();
278
279 if (!LinesMeasured)
280 return 0;
281
282 for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
283 {
284 if (LineSizes[i].cx != 0)
285 {
286 if (iLinesVisible > 0)
287 {
288 if (Horizontal)
289 {
290 if (szMax.cy + LineSizes[i].cy + (LONG) LineSpacing >
291 pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y))
292 {
293 break;
294 }
295 }
296 else
297 {
298 if (LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X))
299 break;
300 }
301
302 /* Add line spacing */
303 szMax.cy += LineSpacing;
304 }
305
306 iLinesVisible++;
307
308 /* Increase maximum rectangle */
309 szMax.cy += LineSizes[i].cy;
310 if (LineSizes[i].cx > szMax.cx)
311 szMax.cx = LineSizes[i].cx;
312 }
313 }
314
315 szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X;
316 szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y;
317
318 *pSize = szMax;
319
320 return iLinesVisible;
321 }
322
323 VOID CTrayClockWnd::UpdateWnd()
324 {
325 SIZE szPrevCurrent;
326 UINT BufSize, i;
327 INT iRet;
328 RECT rcClient;
329
330 ZeroMemory(LineSizes, sizeof(LineSizes));
331
332 szPrevCurrent = CurrentSize;
333
334 for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
335 {
336 szLines[i][0] = L'\0';
337 BufSize = _countof(szLines[0]);
338
339 if (ClockWndFormats[i].IsTime)
340 {
341 iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
342 g_TaskbarSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
343 &LocalTime,
344 ClockWndFormats[i].lpFormat,
345 szLines[i],
346 BufSize);
347 }
348 else
349 {
350 iRet = GetDateFormat(LOCALE_USER_DEFAULT,
351 ClockWndFormats[i].dwFormatFlags,
352 &LocalTime,
353 ClockWndFormats[i].lpFormat,
354 szLines[i],
355 BufSize);
356 }
357
358 if (iRet != 0 && i == 0)
359 {
360 /* Set the window text to the time only */
361 SetWindowText(szLines[i]);
362 }
363 }
364
365 LinesMeasured = MeasureLines();
366
367 if (LinesMeasured &&
368 GetClientRect(&rcClient))
369 {
370 SIZE szWnd;
371
372 szWnd.cx = rcClient.right;
373 szWnd.cy = rcClient.bottom;
374
375 VisibleLines = GetMinimumSize(IsHorizontal, &szWnd);
376 CurrentSize = szWnd;
377 }
378
379 if (IsWindowVisible())
380 {
381 InvalidateRect(NULL, TRUE);
382
383 if (szPrevCurrent.cx != CurrentSize.cx ||
384 szPrevCurrent.cy != CurrentSize.cy)
385 {
386 /* Ask the parent to resize */
387 NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
388 GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
389 }
390 }
391 }
392
393 VOID CTrayClockWnd::Update()
394 {
395 GetLocalTime(&LocalTime);
396 UpdateWnd();
397 }
398
399 UINT CTrayClockWnd::CalculateDueTime()
400 {
401 UINT uiDueTime;
402
403 /* Calculate the due time */
404 GetLocalTime(&LocalTime);
405 uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
406 if (g_TaskbarSettings.bShowSeconds)
407 uiDueTime += (UINT) LocalTime.wSecond * 100;
408 else
409 uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
410
411 if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM)
412 uiDueTime = 1000;
413 else
414 {
415 /* Add an artificial delay of 0.05 seconds to make sure the timer
416 doesn't fire too early*/
417 uiDueTime += 50;
418 }
419
420 return uiDueTime;
421 }
422
423 BOOL CTrayClockWnd::ResetTime()
424 {
425 UINT uiDueTime;
426 BOOL Ret;
427
428 /* Disable all timers */
429 if (IsTimerEnabled)
430 {
431 KillTimer(ID_TRAYCLOCK_TIMER);
432 IsTimerEnabled = FALSE;
433 }
434
435 if (IsInitTimerEnabled)
436 {
437 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
438 }
439
440 uiDueTime = CalculateDueTime();
441
442 /* Set the new timer */
443 Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0;
444 IsInitTimerEnabled = Ret;
445
446 /* Update the time */
447 Update();
448
449 return Ret;
450 }
451
452 VOID CTrayClockWnd::CalibrateTimer()
453 {
454 UINT uiDueTime;
455 BOOL Ret;
456 UINT uiWait1, uiWait2;
457
458 /* Kill the initialization timer */
459 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
460 IsInitTimerEnabled = FALSE;
461
462 uiDueTime = CalculateDueTime();
463
464 if (g_TaskbarSettings.bShowSeconds)
465 {
466 uiWait1 = 1000 - 200;
467 uiWait2 = 1000;
468 }
469 else
470 {
471 uiWait1 = 60 * 1000 - 200;
472 uiWait2 = 60 * 1000;
473 }
474
475 if (uiDueTime > uiWait1)
476 {
477 /* The update of the clock will be up to 200 ms late, but that's
478 acceptable. We're going to setup a timer that fires depending
479 uiWait2. */
480 Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0;
481 IsTimerEnabled = Ret;
482
483 /* Update the time */
484 Update();
485 }
486 else
487 {
488 /* Recalibrate the timer and recalculate again when the current
489 minute/second ends. */
490 ResetTime();
491 }
492 }
493
494 LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
495 {
496 /* Disable all timers */
497 if (IsTimerEnabled)
498 {
499 KillTimer(ID_TRAYCLOCK_TIMER);
500 }
501
502 if (IsInitTimerEnabled)
503 {
504 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
505 }
506
507 return TRUE;
508 }
509
510 LRESULT CTrayClockWnd::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
511 {
512 RECT rcClient;
513 HFONT hPrevFont;
514 INT iPrevBkMode;
515 UINT i, line;
516
517 PAINTSTRUCT ps;
518 HDC hDC = (HDC) wParam;
519
520 if (wParam == 0)
521 {
522 hDC = BeginPaint(&ps);
523 }
524
525 if (hDC == NULL)
526 return FALSE;
527
528 if (LinesMeasured &&
529 GetClientRect(&rcClient))
530 {
531 iPrevBkMode = SetBkMode(hDC, TRANSPARENT);
532
533 SetTextColor(hDC, textColor);
534
535 hPrevFont = (HFONT) SelectObject(hDC, hFont);
536
537 rcClient.top = (rcClient.bottom - CurrentSize.cy) / 2;
538 rcClient.bottom = rcClient.top + CurrentSize.cy;
539
540 for (i = 0, line = 0;
541 i < CLOCKWND_FORMAT_COUNT && line < VisibleLines;
542 i++)
543 {
544 if (LineSizes[i].cx != 0)
545 {
546 TextOut(hDC,
547 (rcClient.right - LineSizes[i].cx) / 2,
548 rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
549 szLines[i],
550 wcslen(szLines[i]));
551
552 rcClient.top += LineSizes[i].cy + LineSpacing;
553 line++;
554 }
555 }
556
557 SelectObject(hDC, hPrevFont);
558
559 SetBkMode(hDC, iPrevBkMode);
560 }
561
562 if (wParam == 0)
563 {
564 EndPaint(&ps);
565 }
566
567 return TRUE;
568 }
569
570 VOID CTrayClockWnd::SetFont(IN HFONT hNewFont, IN BOOL bRedraw)
571 {
572 hFont = hNewFont;
573 LinesMeasured = MeasureLines();
574 if (bRedraw)
575 {
576 InvalidateRect(NULL, TRUE);
577 }
578 }
579
580 LRESULT CTrayClockWnd::DrawBackground(HDC hdc)
581 {
582 RECT rect;
583
584 GetClientRect(&rect);
585 DrawThemeParentBackground(m_hWnd, hdc, &rect);
586
587 return TRUE;
588 }
589
590 LRESULT CTrayClockWnd::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
591 {
592 HDC hdc = (HDC) wParam;
593
594 if (!IsAppThemed())
595 {
596 bHandled = FALSE;
597 return 0;
598 }
599
600 return DrawBackground(hdc);
601 }
602
603 LRESULT CTrayClockWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
604 {
605 switch (wParam)
606 {
607 case ID_TRAYCLOCK_TIMER:
608 Update();
609 break;
610
611 case ID_TRAYCLOCK_TIMER_INIT:
612 CalibrateTimer();
613 break;
614 }
615 return TRUE;
616 }
617
618 LRESULT CTrayClockWnd::OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
619 {
620 IsHorizontal = (BOOL) wParam;
621
622 return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam) != 0;
623 }
624
625 LRESULT CTrayClockWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
626 {
627 return HTTRANSPARENT;
628 }
629
630 LRESULT CTrayClockWnd::OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
631 {
632 SetFont((HFONT) wParam, (BOOL) LOWORD(lParam));
633 return TRUE;
634 }
635
636 LRESULT CTrayClockWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
637 {
638 ResetTime();
639 return TRUE;
640 }
641
642 LRESULT CTrayClockWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
643 {
644 SIZE szClient;
645
646 szClient.cx = LOWORD(lParam);
647 szClient.cy = HIWORD(lParam);
648
649 VisibleLines = GetMinimumSize(IsHorizontal, &szClient);
650 CurrentSize = szClient;
651
652 InvalidateRect(NULL, TRUE);
653 return TRUE;
654 }
655
656 LRESULT CTrayClockWnd::OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
657 {
658 BOOL bRealign = FALSE;
659
660 TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
661 if (newSettings->bShowSeconds != g_TaskbarSettings.bShowSeconds)
662 {
663 g_TaskbarSettings.bShowSeconds = newSettings->bShowSeconds;
664 bRealign = TRUE;
665 }
666
667 if (newSettings->sr.HideClock != g_TaskbarSettings.sr.HideClock)
668 {
669 g_TaskbarSettings.sr.HideClock = newSettings->sr.HideClock;
670 ShowWindow(g_TaskbarSettings.sr.HideClock ? SW_HIDE : SW_SHOW);
671 bRealign = TRUE;
672 }
673
674 if (bRealign)
675 {
676 /* Ask the parent to resize */
677 NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
678 GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
679 Update();
680 }
681 return 0;
682 }
683
684 LRESULT CTrayClockWnd::OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
685 {
686 if (IsWindowVisible())
687 {
688 /* We get all WM_NCLBUTTONDBLCLK for the taskbar so we need to check if it is on the clock*/
689 RECT rcClock;
690 if (GetWindowRect(&rcClock))
691 {
692 POINT ptClick;
693 ptClick.x = MAKEPOINTS(lParam).x;
694 ptClick.y = MAKEPOINTS(lParam).y;
695 if (PtInRect(&rcClock, ptClick))
696 {
697 //FIXME: use SHRunControlPanel
698 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
699 }
700 }
701 }
702 return TRUE;
703 }
704
705 HRESULT CTrayClockWnd::Initialize(IN HWND hWndParent)
706 {
707 IsHorizontal = TRUE;
708
709 /* Create the window. The tray window is going to move it to the correct
710 position and resize it as needed. */
711 DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
712 if (!g_TaskbarSettings.sr.HideClock)
713 dwStyle |= WS_VISIBLE;
714
715 Create(hWndParent, 0, NULL, dwStyle);
716 if (!m_hWnd)
717 return E_FAIL;
718
719 SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
720
721 return S_OK;
722
723 };
724
725 HRESULT CTrayClockWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv)
726 {
727 return ShellObjectCreatorInit<CTrayClockWnd>(hwndParent, riid, ppv);
728 }