Reactos
at master 558 lines 17 kB view raw
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#include <commoncontrols.h> 24 25static const WCHAR szTrayNotifyWndClass[] = L"TrayNotifyWnd"; 26 27#define TRAY_NOTIFY_WND_SPACING_X 1 28#define TRAY_NOTIFY_WND_SPACING_Y 1 29#define CLOCK_TEXT_HACK 4 30 31/* 32 * TrayNotifyWnd 33 */ 34 35class CTrayNotifyWnd : 36 public CComCoClass<CTrayNotifyWnd>, 37 public CComObjectRootEx<CComMultiThreadModelNoCS>, 38 public CWindowImpl < CTrayNotifyWnd, CWindow, CControlWinTraits >, 39 public IOleWindow 40{ 41 CComPtr<IUnknown> m_clock; 42 CTrayShowDesktopButton m_ShowDesktopButton; 43 CComPtr<IUnknown> m_pager; 44 45 HWND m_hwndClock; 46 HWND m_hwndShowDesktop; 47 HWND m_hwndPager; 48 49 HTHEME TrayTheme; 50 SIZE trayClockMinSize; 51 SIZE trayShowDesktopSize; 52 SIZE trayNotifySize; 53 MARGINS ContentMargin; 54 BOOL IsHorizontal; 55 56public: 57 CTrayNotifyWnd() : 58 m_hwndClock(NULL), 59 m_hwndPager(NULL), 60 TrayTheme(NULL), 61 IsHorizontal(FALSE) 62 { 63 ZeroMemory(&trayClockMinSize, sizeof(trayClockMinSize)); 64 ZeroMemory(&trayShowDesktopSize, sizeof(trayShowDesktopSize)); 65 ZeroMemory(&trayNotifySize, sizeof(trayNotifySize)); 66 ZeroMemory(&ContentMargin, sizeof(ContentMargin)); 67 } 68 ~CTrayNotifyWnd() { } 69 70 LRESULT OnThemeChanged() 71 { 72 if (TrayTheme) 73 CloseThemeData(TrayTheme); 74 75 if (IsThemeActive()) 76 TrayTheme = OpenThemeData(m_hWnd, L"TrayNotify"); 77 else 78 TrayTheme = NULL; 79 80 if (TrayTheme) 81 { 82 SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, 0); 83 84 GetThemeMargins(TrayTheme, 85 NULL, 86 TNP_BACKGROUND, 87 0, 88 TMT_CONTENTMARGINS, 89 NULL, 90 &ContentMargin); 91 } 92 else 93 { 94 SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, WS_EX_STATICEDGE); 95 96 ContentMargin.cxLeftWidth = 2; 97 ContentMargin.cxRightWidth = 2; 98 ContentMargin.cyTopHeight = 2; 99 ContentMargin.cyBottomHeight = 2; 100 } 101 102 return TRUE; 103 } 104 105 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 106 { 107 return OnThemeChanged(); 108 } 109 110 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 111 { 112 HRESULT hr; 113 114 hr = CTrayClockWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_clock)); 115 if (FAILED_UNEXPECTEDLY(hr)) 116 return FALSE; 117 118 hr = IUnknown_GetWindow(m_clock, &m_hwndClock); 119 if (FAILED_UNEXPECTEDLY(hr)) 120 return FALSE; 121 122 hr = CSysPagerWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_pager)); 123 if (FAILED_UNEXPECTEDLY(hr)) 124 return FALSE; 125 126 hr = IUnknown_GetWindow(m_pager, &m_hwndPager); 127 if (FAILED_UNEXPECTEDLY(hr)) 128 return FALSE; 129 130 /* Create the 'Show Desktop' button */ 131 m_ShowDesktopButton.DoCreate(m_hWnd); 132 m_hwndShowDesktop = m_ShowDesktopButton.m_hWnd; 133 134 return TRUE; 135 } 136 137 BOOL GetMinimumSize(IN OUT PSIZE pSize) 138 { 139 SIZE clockSize = { 0, 0 }; 140 SIZE traySize = { 0, 0 }; 141 SIZE showDesktopSize = { 0, 0 }; 142 BOOL bHideClock = GetHideClock(); 143 144 if (!bHideClock) 145 { 146 if (IsHorizontal) 147 { 148 clockSize.cy = pSize->cy; 149 if (clockSize.cy <= 0) 150 goto NoClock; 151 } 152 else 153 { 154 clockSize.cx = pSize->cx; 155 if (clockSize.cx <= 0) 156 goto NoClock; 157 } 158 159 ::SendMessage(m_hwndClock, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &clockSize); 160 161 trayClockMinSize = clockSize; 162 } 163 else 164 NoClock: 165 trayClockMinSize = clockSize; 166 167 if (IsHorizontal) 168 { 169 traySize.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; 170 } 171 else 172 { 173 traySize.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; 174 } 175 176 ::SendMessage(m_hwndPager, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &traySize); 177 178 trayNotifySize = traySize; 179 180 INT showDesktopButtonExtent = 0; 181 if (g_TaskbarSettings.bShowDesktopButton) 182 { 183 showDesktopButtonExtent = m_ShowDesktopButton.WidthOrHeight(); 184 if (IsHorizontal) 185 { 186 showDesktopSize.cx = showDesktopButtonExtent; 187 showDesktopSize.cy = pSize->cy; 188 } 189 else 190 { 191 showDesktopSize.cx = pSize->cx; 192 showDesktopSize.cy = showDesktopButtonExtent; 193 } 194 } 195 trayShowDesktopSize = showDesktopSize; 196 197 if (IsHorizontal) 198 { 199 pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X; 200 201 if (!bHideClock) 202 pSize->cx += TRAY_NOTIFY_WND_SPACING_X + trayClockMinSize.cx; 203 204 if (g_TaskbarSettings.bShowDesktopButton) 205 pSize->cx += showDesktopButtonExtent; 206 207 pSize->cx += traySize.cx; 208 pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; 209 } 210 else 211 { 212 pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y; 213 214 if (!bHideClock) 215 pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + trayClockMinSize.cy; 216 217 if (g_TaskbarSettings.bShowDesktopButton) 218 pSize->cy += showDesktopButtonExtent; 219 220 pSize->cy += traySize.cy; 221 pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; 222 } 223 224 return TRUE; 225 } 226 227 VOID Size(IN OUT SIZE *pszClient) 228 { 229 RECT rcClient = {0, 0, pszClient->cx, pszClient->cy}; 230 AlignControls(&rcClient); 231 pszClient->cx = rcClient.right - rcClient.left; 232 pszClient->cy = rcClient.bottom - rcClient.top; 233 } 234 235 VOID AlignControls(IN CONST PRECT prcClient OPTIONAL) 236 { 237 RECT rcClient; 238 if (prcClient != NULL) 239 rcClient = *prcClient; 240 else 241 GetClientRect(&rcClient); 242 243 rcClient.left += ContentMargin.cxLeftWidth; 244 rcClient.top += ContentMargin.cyTopHeight; 245 rcClient.right -= ContentMargin.cxRightWidth; 246 rcClient.bottom -= ContentMargin.cyBottomHeight; 247 248 CONST UINT swpFlags = SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOZORDER; 249 250 if (g_TaskbarSettings.bShowDesktopButton) 251 { 252 POINT ptShowDesktop = 253 { 254 rcClient.left, 255 rcClient.top 256 }; 257 SIZE showDesktopSize = 258 { 259 rcClient.right - rcClient.left, 260 rcClient.bottom - rcClient.top 261 }; 262 263 INT cxyShowDesktop = m_ShowDesktopButton.WidthOrHeight(); 264 if (IsHorizontal) 265 { 266 if (!TrayTheme) 267 { 268 ptShowDesktop.y -= ContentMargin.cyTopHeight; 269 showDesktopSize.cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; 270 } 271 272 rcClient.right -= (cxyShowDesktop - ContentMargin.cxRightWidth); 273 274 ptShowDesktop.x = rcClient.right; 275 showDesktopSize.cx = cxyShowDesktop; 276 277 // HACK: Clock has layout problems - remove this once addressed. 278 rcClient.right -= CLOCK_TEXT_HACK; 279 } 280 else 281 { 282 if (!TrayTheme) 283 { 284 ptShowDesktop.x -= ContentMargin.cxLeftWidth; 285 showDesktopSize.cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; 286 } 287 288 rcClient.bottom -= (cxyShowDesktop - ContentMargin.cyBottomHeight); 289 290 ptShowDesktop.y = rcClient.bottom; 291 showDesktopSize.cy = cxyShowDesktop; 292 293 // HACK: Clock has layout problems - remove this once addressed. 294 rcClient.bottom -= CLOCK_TEXT_HACK; 295 } 296 297 /* Resize and reposition the button */ 298 ::SetWindowPos(m_hwndShowDesktop, 299 NULL, 300 ptShowDesktop.x, 301 ptShowDesktop.y, 302 showDesktopSize.cx, 303 showDesktopSize.cy, 304 swpFlags); 305 } 306 307 if (!GetHideClock()) 308 { 309 POINT ptClock = { rcClient.left, rcClient.top }; 310 SIZE clockSize = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top }; 311 312 if (IsHorizontal) 313 { 314 rcClient.right -= trayClockMinSize.cx; 315 316 ptClock.x = rcClient.right; 317 clockSize.cx = trayClockMinSize.cx; 318 } 319 else 320 { 321 rcClient.bottom -= trayClockMinSize.cy; 322 323 ptClock.y = rcClient.bottom; 324 clockSize.cy = trayClockMinSize.cy; 325 } 326 327 ::SetWindowPos(m_hwndClock, 328 NULL, 329 ptClock.x, 330 ptClock.y, 331 clockSize.cx, 332 clockSize.cy, 333 swpFlags); 334 } 335 336 POINT ptPager; 337 if (IsHorizontal) 338 { 339 ptPager.x = ContentMargin.cxLeftWidth; 340 ptPager.y = ((rcClient.bottom - rcClient.top) - trayNotifySize.cy) / 2; 341 if (g_TaskbarSettings.UseCompactTrayIcons()) 342 ptPager.y += ContentMargin.cyTopHeight; 343 } 344 else 345 { 346 ptPager.x = ((rcClient.right - rcClient.left) - trayNotifySize.cx) / 2; 347 if (g_TaskbarSettings.UseCompactTrayIcons()) 348 ptPager.x += ContentMargin.cxLeftWidth; 349 ptPager.y = ContentMargin.cyTopHeight; 350 } 351 352 ::SetWindowPos(m_hwndPager, 353 NULL, 354 ptPager.x, 355 ptPager.y, 356 trayNotifySize.cx, 357 trayNotifySize.cy, 358 swpFlags); 359 360 if (prcClient != NULL) 361 { 362 prcClient->left = rcClient.left - ContentMargin.cxLeftWidth; 363 prcClient->top = rcClient.top - ContentMargin.cyTopHeight; 364 prcClient->right = rcClient.right + ContentMargin.cxRightWidth; 365 prcClient->bottom = rcClient.bottom + ContentMargin.cyBottomHeight; 366 } 367 } 368 369 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 370 { 371 HDC hdc = (HDC) wParam; 372 373 if (!TrayTheme) 374 { 375 bHandled = FALSE; 376 return 0; 377 } 378 379 RECT rect; 380 GetClientRect(&rect); 381 if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0)) 382 DrawThemeParentBackground(m_hWnd, hdc, &rect); 383 384 DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0); 385 386 return TRUE; 387 } 388 389 LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 390 { 391 BOOL Horizontal = (BOOL) wParam; 392 393 if (Horizontal != IsHorizontal) 394 IsHorizontal = Horizontal; 395 396 SetWindowTheme(m_hWnd, 397 IsHorizontal ? L"TrayNotifyHoriz" : L"TrayNotifyVert", 398 NULL); 399 m_ShowDesktopButton.m_bHorizontal = Horizontal; 400 401 return (LRESULT)GetMinimumSize((PSIZE)lParam); 402 } 403 404 LRESULT OnGetShowDesktopButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 405 { 406 if (wParam == NULL) 407 return 0; 408 409 CTrayShowDesktopButton** ptr = (CTrayShowDesktopButton**)wParam; 410 if (!m_ShowDesktopButton) 411 { 412 *ptr = NULL; 413 return 0; 414 } 415 416 *ptr = &m_ShowDesktopButton; 417 bHandled = TRUE; 418 return 0; 419 } 420 421 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 422 { 423 SIZE clientSize; 424 425 clientSize.cx = LOWORD(lParam); 426 clientSize.cy = HIWORD(lParam); 427 428 Size(&clientSize); 429 430 return TRUE; 431 } 432 433 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 434 { 435 POINT pt; 436 pt.x = GET_X_LPARAM(lParam); 437 pt.y = GET_Y_LPARAM(lParam); 438 439 if (m_ShowDesktopButton && m_ShowDesktopButton.PtInButton(&pt)) 440 return HTCLIENT; 441 442 return HTTRANSPARENT; 443 } 444 445 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 446 { 447 POINT pt; 448 ::GetCursorPos(&pt); 449 450 if (m_ShowDesktopButton && m_ShowDesktopButton.PtInButton(&pt)) 451 m_ShowDesktopButton.StartHovering(); 452 453 return TRUE; 454 } 455 456 LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 457 { 458 bHandled = TRUE; 459 460 if (reinterpret_cast<HWND>(wParam) == m_hwndClock) 461 return GetParent().SendMessage(uMsg, wParam, lParam); 462 else 463 return 0; 464 } 465 466 LRESULT OnClockMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 467 { 468 return SendMessageW(m_hwndClock, uMsg, wParam, lParam); 469 } 470 471 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 472 { 473 TaskbarSettings* newSettings = (TaskbarSettings*)lParam; 474 475 /* Toggle show desktop button */ 476 if (newSettings->bShowDesktopButton != g_TaskbarSettings.bShowDesktopButton) 477 { 478 g_TaskbarSettings.bShowDesktopButton = newSettings->bShowDesktopButton; 479 ::ShowWindow(m_hwndShowDesktop, g_TaskbarSettings.bShowDesktopButton ? SW_SHOW : SW_HIDE); 480 481 /* Ask the parent to resize */ 482 NMHDR nmh = {m_hWnd, 0, NTNWM_REALIGN}; 483 SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh); 484 } 485 486 g_TaskbarSettings.bHideInactiveIcons = newSettings->bHideInactiveIcons; 487 488 return OnClockMessage(uMsg, wParam, lParam, bHandled); 489 } 490 491 LRESULT OnPagerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 492 { 493 return SendMessageW(m_hwndPager, uMsg, wParam, lParam); 494 } 495 496 LRESULT OnRealign(INT uCode, LPNMHDR hdr, BOOL& bHandled) 497 { 498 hdr->hwndFrom = m_hWnd; 499 return GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM)hdr); 500 } 501 502 // *** IOleWindow methods *** 503 504 STDMETHODIMP 505 GetWindow(HWND* phwnd) override 506 { 507 if (!phwnd) 508 return E_INVALIDARG; 509 *phwnd = m_hWnd; 510 return S_OK; 511 } 512 513 STDMETHODIMP 514 ContextSensitiveHelp(BOOL fEnterMode) override 515 { 516 return E_NOTIMPL; 517 } 518 519 HRESULT Initialize(IN HWND hwndParent) 520 { 521 const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 522 Create(hwndParent, 0, NULL, dwStyle, WS_EX_STATICEDGE); 523 return m_hWnd ? S_OK : E_FAIL; 524 } 525 526 DECLARE_NOT_AGGREGATABLE(CTrayNotifyWnd) 527 528 DECLARE_PROTECT_FINAL_CONSTRUCT() 529 BEGIN_COM_MAP(CTrayNotifyWnd) 530 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 531 END_COM_MAP() 532 533 DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE) 534 535 BEGIN_MSG_MAP(CTrayNotifyWnd) 536 MESSAGE_HANDLER(WM_CREATE, OnCreate) 537 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 538 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 539 MESSAGE_HANDLER(WM_SIZE, OnSize) 540 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 541 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 542 MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove) 543 MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) 544 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnClockMessage) 545 MESSAGE_HANDLER(WM_SETFONT, OnClockMessage) 546 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnPagerMessage) 547 MESSAGE_HANDLER(WM_COPYDATA, OnPagerMessage) 548 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) 549 NOTIFY_CODE_HANDLER(NTNWM_REALIGN, OnRealign) 550 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize) 551 MESSAGE_HANDLER(TNWM_GETSHOWDESKTOPBUTTON, OnGetShowDesktopButton) 552 END_MSG_MAP() 553}; 554 555HRESULT CTrayNotifyWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv) 556{ 557 return ShellObjectCreatorInit<CTrayNotifyWnd>(hwndParent, riid, ppv); 558}