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 } 768