[FREELDR] Merge boot-drive and partition functionalities together (#6760)
[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 static const WCHAR szTrayClockWndClass[] = L"TrayClockWClass";
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 CTooltips m_tooltip;
55
56 union
57 {
58 DWORD dwFlags;
59 struct
60 {
61 DWORD IsTimerEnabled : 1;
62 DWORD IsInitTimerEnabled : 1;
63 DWORD LinesMeasured : 1;
64 DWORD IsHorizontal : 1;
65 };
66 };
67 DWORD LineSpacing;
68 SIZE CurrentSize;
69 WORD VisibleLines;
70 SIZE LineSizes[CLOCKWND_FORMAT_COUNT];
71 WCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
72
73 public:
74 CTrayClockWnd();
75 virtual ~CTrayClockWnd();
76
77 private:
78 LRESULT OnThemeChanged();
79 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
80
81 BOOL MeasureLines();
82 WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize);
83 VOID UpdateWnd();
84 VOID Update();
85 UINT CalculateDueTime();
86 BOOL ResetTime();
87 VOID CalibrateTimer();
88 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
89 LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
90 VOID SetFont(IN HFONT hNewFont, IN BOOL bRedraw);
91 LRESULT DrawBackground(HDC hdc);
92 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
93 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
94 LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
95 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
96 LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
97 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
98 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
99 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
100 LRESULT OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
101
102 public:
103
104 HRESULT WINAPI GetWindow(HWND* phwnd)
105 {
106 if (!phwnd)
107 return E_INVALIDARG;
108 *phwnd = m_hWnd;
109 return S_OK;
110 }
111
112 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
113 {
114 return E_NOTIMPL;
115 }
116
117 DECLARE_NOT_AGGREGATABLE(CTrayClockWnd)
118
119 DECLARE_PROTECT_FINAL_CONSTRUCT()
120 BEGIN_COM_MAP(CTrayClockWnd)
121 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
122 END_COM_MAP()
123
124 DECLARE_WND_CLASS_EX(szTrayClockWndClass, CS_DBLCLKS, COLOR_3DFACE)
125
126 BEGIN_MSG_MAP(CTrayClockWnd)
127 MESSAGE_HANDLER(WM_CREATE, OnCreate)
128 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
129 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
130 MESSAGE_HANDLER(WM_SIZE, OnSize)
131 MESSAGE_HANDLER(WM_PAINT, OnPaint)
132 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
133 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
134 MESSAGE_HANDLER(WM_TIMER, OnTimer)
135 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
136 MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
137 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize)
138 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
139 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClick)
140 END_MSG_MAP()
141
142 HRESULT Initialize(IN HWND hWndParent);
143 };
144
145 #define ID_TRAYCLOCK_TIMER 0
146 #define ID_TRAYCLOCK_TIMER_INIT 1
147
148 #define TRAY_CLOCK_WND_SPACING_X 5
149 #define TRAY_CLOCK_WND_SPACING_Y 0
150
151 CTrayClockWnd::CTrayClockWnd() :
152 hFont(NULL),
153 dwFlags(0),
154 LineSpacing(0),
155 VisibleLines(0)
156 {
157 ZeroMemory(&textColor, sizeof(textColor));
158 ZeroMemory(&rcText, sizeof(rcText));
159 ZeroMemory(&LocalTime, sizeof(LocalTime));
160 ZeroMemory(&CurrentSize, sizeof(CurrentSize));
161 ZeroMemory(LineSizes, sizeof(LineSizes));
162 ZeroMemory(szLines, sizeof(szLines));
163 }
164 CTrayClockWnd::~CTrayClockWnd() { }
165
166 LRESULT CTrayClockWnd::OnThemeChanged()
167 {
168 LOGFONTW clockFont;
169 HTHEME clockTheme;
170 HFONT hFont;
171
172 clockTheme = OpenThemeData(m_hWnd, L"Clock");
173
174 if (clockTheme)
175 {
176 GetThemeFont(clockTheme,
177 NULL,
178 CLP_TIME,
179 0,
180 TMT_FONT,
181 &clockFont);
182
183 hFont = CreateFontIndirectW(&clockFont);
184
185 GetThemeColor(clockTheme,
186 CLP_TIME,
187 0,
188 TMT_TEXTCOLOR,
189 &textColor);
190
191 if (this->hFont != NULL)
192 DeleteObject(this->hFont);
193
194 SetFont(hFont, FALSE);
195 }
196 else
197 {
198 /* We don't need to set a font here, our parent will use
199 * WM_SETFONT to set the right one when themes are not enabled. */
200 textColor = RGB(0, 0, 0);
201 }
202
203 CloseThemeData(clockTheme);
204
205 return TRUE;
206 }
207
208 LRESULT CTrayClockWnd::OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
209 {
210 return OnThemeChanged();
211 }
212
213 BOOL CTrayClockWnd::MeasureLines()
214 {
215 HDC hDC;
216 HFONT hPrevFont;
217 UINT c, i;
218 BOOL bRet = TRUE;
219
220 hDC = GetDC();
221 if (hDC != NULL)
222 {
223 if (hFont)
224 hPrevFont = (HFONT) SelectObject(hDC, hFont);
225
226 for (i = 0; i < CLOCKWND_FORMAT_COUNT && bRet; i++)
227 {
228 if (szLines[i][0] != L'\0' &&
229 !GetTextExtentPointW(hDC, szLines[i], wcslen(szLines[i]),
230 &LineSizes[i]))
231 {
232 bRet = FALSE;
233 break;
234 }
235 }
236
237 if (hFont)
238 SelectObject(hDC, hPrevFont);
239
240 ReleaseDC(hDC);
241
242 if (bRet)
243 {
244 LineSpacing = 0;
245
246 /* calculate the line spacing */
247 for (i = 0, c = 0; i < CLOCKWND_FORMAT_COUNT; i++)
248 {
249 if (LineSizes[i].cx > 0)
250 {
251 LineSpacing += LineSizes[i].cy;
252 c++;
253 }
254 }
255
256 if (c > 0)
257 {
258 /* We want a spacing of 1/2 line */
259 LineSpacing = (LineSpacing / c) / 2;
260 }
261
262 return TRUE;
263 }
264 }
265
266 return FALSE;
267 }
268
269 WORD CTrayClockWnd::GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
270 {
271 WORD iLinesVisible = 0;
272 UINT i;
273 SIZE szMax = { 0, 0 };
274
275 if (!LinesMeasured)
276 LinesMeasured = MeasureLines();
277
278 if (!LinesMeasured)
279 return 0;
280
281 for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
282 {
283 if (LineSizes[i].cx != 0)
284 {
285 if (iLinesVisible > 0)
286 {
287 if (Horizontal)
288 {
289 if (szMax.cy + LineSizes[i].cy + (LONG) LineSpacing >
290 pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y))
291 {
292 break;
293 }
294 }
295 else
296 {
297 if (LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X))
298 break;
299 }
300
301 /* Add line spacing */
302 szMax.cy += LineSpacing;
303 }
304
305 iLinesVisible++;
306
307 /* Increase maximum rectangle */
308 szMax.cy += LineSizes[i].cy;
309 if (LineSizes[i].cx > szMax.cx)
310 szMax.cx = LineSizes[i].cx;
311 }
312 }
313
314 szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X;
315 szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y;
316
317 *pSize = szMax;
318
319 return iLinesVisible;
320 }
321
322 VOID CTrayClockWnd::UpdateWnd()
323 {
324 SIZE szPrevCurrent;
325 UINT BufSize, i;
326 INT iRet;
327 RECT rcClient;
328
329 ZeroMemory(LineSizes, sizeof(LineSizes));
330
331 szPrevCurrent = CurrentSize;
332
333 for (i = 0; i < CLOCKWND_FORMAT_COUNT; i++)
334 {
335 szLines[i][0] = L'\0';
336 BufSize = _countof(szLines[0]);
337
338 if (ClockWndFormats[i].IsTime)
339 {
340 iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
341 g_TaskbarSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
342 &LocalTime,
343 ClockWndFormats[i].lpFormat,
344 szLines[i],
345 BufSize);
346 }
347 else
348 {
349 iRet = GetDateFormat(LOCALE_USER_DEFAULT,
350 ClockWndFormats[i].dwFormatFlags,
351 &LocalTime,
352 ClockWndFormats[i].lpFormat,
353 szLines[i],
354 BufSize);
355 }
356
357 if (iRet != 0 && i == 0)
358 {
359 /* Set the window text to the time only */
360 SetWindowText(szLines[i]);
361 }
362 }
363
364 LinesMeasured = MeasureLines();
365
366 if (LinesMeasured &&
367 GetClientRect(&rcClient))
368 {
369 SIZE szWnd;
370
371 szWnd.cx = rcClient.right;
372 szWnd.cy = rcClient.bottom;
373
374 VisibleLines = GetMinimumSize(IsHorizontal, &szWnd);
375 CurrentSize = szWnd;
376 }
377
378 if (IsWindowVisible())
379 {
380 InvalidateRect(NULL, TRUE);
381
382 if (szPrevCurrent.cx != CurrentSize.cx ||
383 szPrevCurrent.cy != CurrentSize.cy)
384 {
385 /* Ask the parent to resize */
386 NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
387 GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
388 }
389 }
390
391 int iDateLength = GetDateFormat(LOCALE_USER_DEFAULT,
392 DATE_LONGDATE,
393 &LocalTime,
394 NULL,
395 NULL,
396 0);
397 if (iDateLength <= 0)
398 {
399 return;
400 }
401
402 WCHAR* szDate = new WCHAR[iDateLength];
403 if (GetDateFormat(LOCALE_USER_DEFAULT,
404 DATE_LONGDATE,
405 &LocalTime,
406 NULL,
407 szDate,
408 iDateLength) > 0)
409 {
410 m_tooltip.UpdateTipText(m_hWnd,
411 reinterpret_cast<UINT_PTR>(m_hWnd),
412 szDate);
413 }
414 delete[] szDate;
415 }
416
417 VOID CTrayClockWnd::Update()
418 {
419 GetLocalTime(&LocalTime);
420 UpdateWnd();
421 }
422
423 UINT CTrayClockWnd::CalculateDueTime()
424 {
425 UINT uiDueTime;
426
427 GetLocalTime(&LocalTime);
428 uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
429 if (!g_TaskbarSettings.bShowSeconds)
430 uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
431
432 return uiDueTime;
433 }
434
435 BOOL CTrayClockWnd::ResetTime()
436 {
437 UINT uiDueTime;
438 BOOL Ret;
439
440 /* Disable all timers */
441 if (IsTimerEnabled)
442 {
443 KillTimer(ID_TRAYCLOCK_TIMER);
444 IsTimerEnabled = FALSE;
445 }
446 else if (IsInitTimerEnabled)
447 {
448 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
449 }
450
451 uiDueTime = CalculateDueTime();
452
453 /* Set the new timer */
454 Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0;
455 IsInitTimerEnabled = Ret;
456
457 return Ret;
458 }
459
460 VOID CTrayClockWnd::CalibrateTimer()
461 {
462 UINT uiDueTime;
463 BOOL Ret;
464 UINT uiWait1, uiWait2;
465
466 /* Kill the initialization timer */
467 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
468 IsInitTimerEnabled = FALSE;
469
470 uiDueTime = CalculateDueTime();
471
472 if (g_TaskbarSettings.bShowSeconds)
473 {
474 uiWait1 = 1000 - 200;
475 uiWait2 = 1000;
476 }
477 else
478 {
479 uiWait1 = 60 * 1000 - 200;
480 uiWait2 = 60 * 1000;
481 }
482
483 if (uiDueTime > uiWait1)
484 {
485 /* The update of the clock will be up to 200 ms late, but that's
486 acceptable. We're going to setup a timer that fires depending
487 uiWait2. */
488 Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0;
489 IsTimerEnabled = Ret;
490 }
491 else
492 {
493 /* Recalibrate the timer and recalculate again when the current
494 minute/second ends. */
495 ResetTime();
496 }
497
498 /* Update the time */
499 Update();
500 }
501
502 LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
503 {
504 /* Disable all timers */
505 if (IsTimerEnabled)
506 {
507 KillTimer(ID_TRAYCLOCK_TIMER);
508 }
509 else if (IsInitTimerEnabled)
510 {
511 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
512 }
513
514 return TRUE;
515 }
516
517 LRESULT CTrayClockWnd::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
518 {
519 RECT rcClient;
520 HFONT hPrevFont;
521 INT iPrevBkMode;
522 UINT i, line;
523
524 PAINTSTRUCT ps;
525 HDC hDC = (HDC) wParam;
526
527 if (wParam == 0)
528 {
529 hDC = BeginPaint(&ps);
530 }
531
532 if (hDC == NULL)
533 return FALSE;
534
535 if (LinesMeasured &&
536 GetClientRect(&rcClient))
537 {
538 iPrevBkMode = SetBkMode(hDC, TRANSPARENT);
539
540 SetTextColor(hDC, textColor);
541
542 hPrevFont = (HFONT) SelectObject(hDC, hFont);
543
544 rcClient.top = (rcClient.bottom - CurrentSize.cy) / 2;
545 rcClient.bottom = rcClient.top + CurrentSize.cy;
546
547 for (i = 0, line = 0;
548 i < CLOCKWND_FORMAT_COUNT && line < VisibleLines;
549 i++)
550 {
551 if (LineSizes[i].cx != 0)
552 {
553 TextOut(hDC,
554 (rcClient.right - LineSizes[i].cx) / 2,
555 rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
556 szLines[i],
557 wcslen(szLines[i]));
558
559 rcClient.top += LineSizes[i].cy + LineSpacing;
560 line++;
561 }
562 }
563
564 SelectObject(hDC, hPrevFont);
565
566 SetBkMode(hDC, iPrevBkMode);
567 }
568
569 if (wParam == 0)
570 {
571 EndPaint(&ps);
572 }
573
574 return TRUE;
575 }
576
577 VOID CTrayClockWnd::SetFont(IN HFONT hNewFont, IN BOOL bRedraw)
578 {
579 hFont = hNewFont;
580 LinesMeasured = MeasureLines();
581 if (bRedraw)
582 {
583 InvalidateRect(NULL, TRUE);
584 }
585 }
586
587 LRESULT CTrayClockWnd::DrawBackground(HDC hdc)
588 {
589 RECT rect;
590
591 GetClientRect(&rect);
592 DrawThemeParentBackground(m_hWnd, hdc, &rect);
593
594 return TRUE;
595 }
596
597 LRESULT CTrayClockWnd::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
598 {
599 HDC hdc = (HDC) wParam;
600
601 if (!IsAppThemed())
602 {
603 bHandled = FALSE;
604 return 0;
605 }
606
607 return DrawBackground(hdc);
608 }
609
610 LRESULT CTrayClockWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
611 {
612 switch (wParam)
613 {
614 case ID_TRAYCLOCK_TIMER:
615 Update();
616 break;
617
618 case ID_TRAYCLOCK_TIMER_INIT:
619 CalibrateTimer();
620 break;
621 }
622 return TRUE;
623 }
624
625 LRESULT CTrayClockWnd::OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
626 {
627 IsHorizontal = (BOOL) wParam;
628
629 return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam) != 0;
630 }
631
632 LRESULT CTrayClockWnd::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
633 {
634 return GetParent().SendMessage(uMsg, wParam, lParam);
635 }
636
637 LRESULT CTrayClockWnd::OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
638 {
639 SetFont((HFONT) wParam, (BOOL) LOWORD(lParam));
640 return TRUE;
641 }
642
643 LRESULT CTrayClockWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
644 {
645 m_tooltip.Create(m_hWnd, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP);
646
647 TOOLINFOW ti = { 0 };
648 ti.cbSize = TTTOOLINFOW_V1_SIZE;
649 ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
650 ti.hwnd = m_hWnd;
651 ti.uId = reinterpret_cast<UINT_PTR>(m_hWnd);
652 ti.lpszText = NULL;
653 ti.lParam = NULL;
654
655 m_tooltip.AddTool(&ti);
656
657 if (!g_TaskbarSettings.sr.HideClock)
658 {
659 ResetTime();
660 }
661
662 /* Update the time */
663 Update();
664
665 return TRUE;
666 }
667
668 LRESULT CTrayClockWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
669 {
670 SIZE szClient;
671
672 szClient.cx = LOWORD(lParam);
673 szClient.cy = HIWORD(lParam);
674
675 VisibleLines = GetMinimumSize(IsHorizontal, &szClient);
676 CurrentSize = szClient;
677
678 InvalidateRect(NULL, TRUE);
679 return TRUE;
680 }
681
682 LRESULT CTrayClockWnd::OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
683 {
684 BOOL bRealign = FALSE;
685
686 TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
687 if (newSettings->bShowSeconds != g_TaskbarSettings.bShowSeconds)
688 {
689 g_TaskbarSettings.bShowSeconds = newSettings->bShowSeconds;
690 if (!g_TaskbarSettings.sr.HideClock)
691 {
692 bRealign = TRUE;
693
694 ResetTime();
695 }
696 }
697
698 if (newSettings->sr.HideClock != g_TaskbarSettings.sr.HideClock)
699 {
700 g_TaskbarSettings.sr.HideClock = newSettings->sr.HideClock;
701 ShowWindow(g_TaskbarSettings.sr.HideClock ? SW_HIDE : SW_SHOW);
702 bRealign = TRUE;
703
704 if (g_TaskbarSettings.sr.HideClock)
705 {
706 /* Disable all timers */
707 if (IsTimerEnabled)
708 {
709 KillTimer(ID_TRAYCLOCK_TIMER);
710 IsTimerEnabled = FALSE;
711 }
712 else if (IsInitTimerEnabled)
713 {
714 KillTimer(ID_TRAYCLOCK_TIMER_INIT);
715 IsInitTimerEnabled = FALSE;
716 }
717 }
718 else
719 {
720 ResetTime();
721 }
722 }
723
724 if (bRealign)
725 {
726 /* Ask the parent to resize */
727 NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN};
728 GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh);
729 Update();
730 }
731 return 0;
732 }
733
734 LRESULT CTrayClockWnd::OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
735 {
736 if (IsWindowVisible())
737 {
738 //FIXME: use SHRunControlPanel
739 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
740 }
741 return TRUE;
742 }
743
744 HRESULT CTrayClockWnd::Initialize(IN HWND hWndParent)
745 {
746 IsHorizontal = TRUE;
747
748 /* Create the window. The tray window is going to move it to the correct
749 position and resize it as needed. */
750 DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
751 if (!g_TaskbarSettings.sr.HideClock)
752 dwStyle |= WS_VISIBLE;
753
754 Create(hWndParent, 0, NULL, dwStyle);
755 if (!m_hWnd)
756 return E_FAIL;
757
758 SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
759
760 return S_OK;
761
762 };
763
764 HRESULT CTrayClockWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv)
765 {
766 return ShellObjectCreatorInit<CTrayClockWnd>(hwndParent, riid, ppv);
767 }