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 if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM) 433 uiDueTime = 1000; 434 else 435 { 436 /* Add an artificial delay of 0.05 seconds to make sure the timer 437 doesn't fire too early*/ 438 uiDueTime += 50; 439 } 440 441 return uiDueTime; 442 } 443 444 BOOL CTrayClockWnd::ResetTime() 445 { 446 UINT uiDueTime; 447 BOOL Ret; 448 449 /* Disable all timers */ 450 if (IsTimerEnabled) 451 { 452 KillTimer(ID_TRAYCLOCK_TIMER); 453 IsTimerEnabled = FALSE; 454 } 455 else if (IsInitTimerEnabled) 456 { 457 KillTimer(ID_TRAYCLOCK_TIMER_INIT); 458 } 459 460 uiDueTime = CalculateDueTime(); 461 462 /* Set the new timer */ 463 Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0; 464 IsInitTimerEnabled = Ret; 465 466 return Ret; 467 } 468 469 VOID CTrayClockWnd::CalibrateTimer() 470 { 471 UINT uiDueTime; 472 BOOL Ret; 473 UINT uiWait1, uiWait2; 474 475 /* Kill the initialization timer */ 476 KillTimer(ID_TRAYCLOCK_TIMER_INIT); 477 IsInitTimerEnabled = FALSE; 478 479 uiDueTime = CalculateDueTime(); 480 481 if (g_TaskbarSettings.bShowSeconds) 482 { 483 uiWait1 = 1000 - 200; 484 uiWait2 = 1000; 485 } 486 else 487 { 488 uiWait1 = 60 * 1000 - 200; 489 uiWait2 = 60 * 1000; 490 } 491 492 if (uiDueTime > uiWait1) 493 { 494 /* The update of the clock will be up to 200 ms late, but that's 495 acceptable. We're going to setup a timer that fires depending 496 uiWait2. */ 497 Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0; 498 IsTimerEnabled = Ret; 499 } 500 else 501 { 502 /* Recalibrate the timer and recalculate again when the current 503 minute/second ends. */ 504 ResetTime(); 505 } 506 507 /* Update the time */ 508 Update(); 509 } 510 511 LRESULT CTrayClockWnd::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 512 { 513 /* Disable all timers */ 514 if (IsTimerEnabled) 515 { 516 KillTimer(ID_TRAYCLOCK_TIMER); 517 } 518 else if (IsInitTimerEnabled) 519 { 520 KillTimer(ID_TRAYCLOCK_TIMER_INIT); 521 } 522 523 return TRUE; 524 } 525 526 LRESULT CTrayClockWnd::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 527 { 528 RECT rcClient; 529 HFONT hPrevFont; 530 INT iPrevBkMode; 531 UINT i, line; 532 533 PAINTSTRUCT ps; 534 HDC hDC = (HDC) wParam; 535 536 if (wParam == 0) 537 { 538 hDC = BeginPaint(&ps); 539 } 540 541 if (hDC == NULL) 542 return FALSE; 543 544 if (LinesMeasured && 545 GetClientRect(&rcClient)) 546 { 547 iPrevBkMode = SetBkMode(hDC, TRANSPARENT); 548 549 SetTextColor(hDC, textColor); 550 551 hPrevFont = (HFONT) SelectObject(hDC, hFont); 552 553 rcClient.top = (rcClient.bottom - CurrentSize.cy) / 2; 554 rcClient.bottom = rcClient.top + CurrentSize.cy; 555 556 for (i = 0, line = 0; 557 i < CLOCKWND_FORMAT_COUNT && line < VisibleLines; 558 i++) 559 { 560 if (LineSizes[i].cx != 0) 561 { 562 TextOut(hDC, 563 (rcClient.right - LineSizes[i].cx) / 2, 564 rcClient.top + TRAY_CLOCK_WND_SPACING_Y, 565 szLines[i], 566 wcslen(szLines[i])); 567 568 rcClient.top += LineSizes[i].cy + LineSpacing; 569 line++; 570 } 571 } 572 573 SelectObject(hDC, hPrevFont); 574 575 SetBkMode(hDC, iPrevBkMode); 576 } 577 578 if (wParam == 0) 579 { 580 EndPaint(&ps); 581 } 582 583 return TRUE; 584 } 585 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 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 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 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 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 641 LRESULT CTrayClockWnd::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 642 { 643 return GetParent().SendMessage(uMsg, wParam, lParam); 644 } 645 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 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 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 InvalidateRect(NULL, TRUE); 688 return TRUE; 689 } 690 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 (bRealign) 734 { 735 /* Ask the parent to resize */ 736 NMHDR nmh = {GetParent(), 0, NTNWM_REALIGN}; 737 GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh); 738 Update(); 739 } 740 return 0; 741 } 742 743 LRESULT CTrayClockWnd::OnLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 744 { 745 if (IsWindowVisible()) 746 { 747 //FIXME: use SHRunControlPanel 748 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL); 749 } 750 return TRUE; 751 } 752 753 HRESULT CTrayClockWnd::Initialize(IN HWND hWndParent) 754 { 755 IsHorizontal = TRUE; 756 757 /* Create the window. The tray window is going to move it to the correct 758 position and resize it as needed. */ 759 DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS; 760 if (!g_TaskbarSettings.sr.HideClock) 761 dwStyle |= WS_VISIBLE; 762 763 Create(hWndParent, 0, NULL, dwStyle); 764 if (!m_hWnd) 765 return E_FAIL; 766 767 SetWindowTheme(m_hWnd, L"TrayNotify", NULL); 768 769 return S_OK; 770 771 }; 772 773 HRESULT CTrayClockWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv) 774 { 775 return ShellObjectCreatorInit<CTrayClockWnd>(hwndParent, riid, ppv); 776 } 777