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