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 / 2) - (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 } 729