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 * TrayNotifyWnd 26 */ 27 28 static const WCHAR szTrayNotifyWndClass[] = L"TrayNotifyWnd"; 29 30 #define TRAY_NOTIFY_WND_SPACING_X 1 31 #define TRAY_NOTIFY_WND_SPACING_Y 1 32 33 class CTrayNotifyWnd : 34 public CComCoClass<CTrayNotifyWnd>, 35 public CComObjectRootEx<CComMultiThreadModelNoCS>, 36 public CWindowImpl < CTrayNotifyWnd, CWindow, CControlWinTraits >, 37 public IOleWindow 38 { 39 CComPtr<IUnknown> m_clock; 40 CComPtr<IUnknown> m_pager; 41 42 HWND m_hwndClock; 43 HWND m_hwndPager; 44 45 HTHEME TrayTheme; 46 SIZE szTrayClockMin; 47 SIZE szTrayNotify; 48 MARGINS ContentMargin; 49 BOOL IsHorizontal; 50 51 public: 52 CTrayNotifyWnd() : 53 m_hwndClock(NULL), 54 m_hwndPager(NULL), 55 TrayTheme(NULL), 56 IsHorizontal(FALSE) 57 { 58 ZeroMemory(&szTrayClockMin, sizeof(szTrayClockMin)); 59 ZeroMemory(&szTrayNotify, sizeof(szTrayNotify)); 60 ZeroMemory(&ContentMargin, sizeof(ContentMargin)); 61 } 62 virtual ~CTrayNotifyWnd() { } 63 64 LRESULT OnThemeChanged() 65 { 66 if (TrayTheme) 67 CloseThemeData(TrayTheme); 68 69 if (IsThemeActive()) 70 TrayTheme = OpenThemeData(m_hWnd, L"TrayNotify"); 71 else 72 TrayTheme = NULL; 73 74 if (TrayTheme) 75 { 76 SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, 0); 77 78 GetThemeMargins(TrayTheme, 79 NULL, 80 TNP_BACKGROUND, 81 0, 82 TMT_CONTENTMARGINS, 83 NULL, 84 &ContentMargin); 85 } 86 else 87 { 88 SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, WS_EX_STATICEDGE); 89 90 ContentMargin.cxLeftWidth = 2; 91 ContentMargin.cxRightWidth = 2; 92 ContentMargin.cyTopHeight = 2; 93 ContentMargin.cyBottomHeight = 2; 94 } 95 96 return TRUE; 97 } 98 99 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 100 { 101 return OnThemeChanged(); 102 } 103 104 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 105 { 106 HRESULT hr; 107 108 hr = CTrayClockWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_clock)); 109 if (FAILED_UNEXPECTEDLY(hr)) 110 return FALSE; 111 112 hr = IUnknown_GetWindow(m_clock, &m_hwndClock); 113 if (FAILED_UNEXPECTEDLY(hr)) 114 return FALSE; 115 116 hr = CSysPagerWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_pager)); 117 if (FAILED_UNEXPECTEDLY(hr)) 118 return FALSE; 119 120 hr = IUnknown_GetWindow(m_pager, &m_hwndPager); 121 if (FAILED_UNEXPECTEDLY(hr)) 122 return FALSE; 123 124 return TRUE; 125 } 126 127 LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 128 { 129 return MA_NOACTIVATE; 130 } 131 132 BOOL GetMinimumSize(IN OUT PSIZE pSize) 133 { 134 SIZE szClock = { 0, 0 }; 135 SIZE szTray = { 0, 0 }; 136 137 if (!g_TaskbarSettings.sr.HideClock) 138 { 139 if (IsHorizontal) 140 { 141 szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; 142 if (szClock.cy <= 0) 143 goto NoClock; 144 } 145 else 146 { 147 szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; 148 if (szClock.cx <= 0) 149 goto NoClock; 150 } 151 152 ::SendMessage(m_hwndClock, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &szClock); 153 154 szTrayClockMin = szClock; 155 } 156 else 157 NoClock: 158 szTrayClockMin = szClock; 159 160 if (IsHorizontal) 161 { 162 szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; 163 } 164 else 165 { 166 szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; 167 } 168 169 ::SendMessage(m_hwndPager, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &szTray); 170 171 szTrayNotify = szTray; 172 173 if (IsHorizontal) 174 { 175 pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X; 176 177 if (!g_TaskbarSettings.sr.HideClock) 178 pSize->cx += TRAY_NOTIFY_WND_SPACING_X + szTrayClockMin.cx; 179 180 pSize->cx += szTray.cx; 181 pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; 182 } 183 else 184 { 185 pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y; 186 187 if (!g_TaskbarSettings.sr.HideClock) 188 pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + szTrayClockMin.cy; 189 190 pSize->cy += szTray.cy; 191 pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; 192 } 193 194 return TRUE; 195 } 196 197 VOID Size(IN const SIZE *pszClient) 198 { 199 if (!g_TaskbarSettings.sr.HideClock) 200 { 201 POINT ptClock; 202 SIZE szClock; 203 204 if (IsHorizontal) 205 { 206 ptClock.x = pszClient->cx - szTrayClockMin.cx - ContentMargin.cxRightWidth; 207 ptClock.y = ContentMargin.cyTopHeight; 208 szClock.cx = szTrayClockMin.cx; 209 szClock.cy = pszClient->cy - ContentMargin.cyTopHeight - ContentMargin.cyBottomHeight; 210 } 211 else 212 { 213 ptClock.x = ContentMargin.cxLeftWidth; 214 ptClock.y = pszClient->cy - szTrayClockMin.cy; 215 szClock.cx = pszClient->cx - ContentMargin.cxLeftWidth - ContentMargin.cxRightWidth; 216 szClock.cy = szTrayClockMin.cy; 217 } 218 219 ::SetWindowPos(m_hwndClock, 220 NULL, 221 ptClock.x, 222 ptClock.y, 223 szClock.cx, 224 szClock.cy, 225 SWP_NOZORDER); 226 } 227 228 POINT ptPager; 229 230 if (IsHorizontal) 231 { 232 ptPager.x = ContentMargin.cxLeftWidth; 233 ptPager.y = (pszClient->cy - szTrayNotify.cy)/2; 234 } 235 else 236 { 237 ptPager.x = (pszClient->cx - szTrayNotify.cx)/2; 238 ptPager.y = ContentMargin.cyTopHeight; 239 } 240 241 ::SetWindowPos(m_hwndPager, 242 NULL, 243 ptPager.x, 244 ptPager.y, 245 szTrayNotify.cx, 246 szTrayNotify.cy, 247 SWP_NOZORDER); 248 } 249 250 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 251 { 252 HDC hdc = (HDC) wParam; 253 254 if (!TrayTheme) 255 { 256 bHandled = FALSE; 257 return 0; 258 } 259 260 RECT rect; 261 GetClientRect(&rect); 262 if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0)) 263 DrawThemeParentBackground(m_hWnd, hdc, &rect); 264 265 DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0); 266 267 return TRUE; 268 } 269 270 LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 271 { 272 BOOL Horizontal = (BOOL) wParam; 273 274 if (Horizontal != IsHorizontal) 275 { 276 IsHorizontal = Horizontal; 277 if (IsHorizontal) 278 SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL); 279 else 280 SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL); 281 } 282 283 return (LRESULT) GetMinimumSize((PSIZE) lParam); 284 } 285 286 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 287 { 288 SIZE szClient; 289 290 szClient.cx = LOWORD(lParam); 291 szClient.cy = HIWORD(lParam); 292 293 Size(&szClient); 294 295 return TRUE; 296 } 297 298 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 299 { 300 return HTTRANSPARENT; 301 } 302 303 LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 304 { 305 bHandled = TRUE; 306 307 if (reinterpret_cast<HWND>(wParam) == m_hwndClock) 308 return GetParent().SendMessage(uMsg, wParam, lParam); 309 else 310 return 0; 311 } 312 313 LRESULT OnClockMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 314 { 315 return SendMessageW(m_hwndClock, uMsg, wParam, lParam); 316 } 317 318 LRESULT OnPagerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 319 { 320 return SendMessageW(m_hwndPager, uMsg, wParam, lParam); 321 } 322 323 LRESULT OnRealign(INT uCode, LPNMHDR hdr, BOOL& bHandled) 324 { 325 hdr->hwndFrom = m_hWnd; 326 return GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM)hdr); 327 } 328 329 HRESULT WINAPI GetWindow(HWND* phwnd) 330 { 331 if (!phwnd) 332 return E_INVALIDARG; 333 *phwnd = m_hWnd; 334 return S_OK; 335 } 336 337 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode) 338 { 339 return E_NOTIMPL; 340 } 341 342 DECLARE_NOT_AGGREGATABLE(CTrayNotifyWnd) 343 344 DECLARE_PROTECT_FINAL_CONSTRUCT() 345 BEGIN_COM_MAP(CTrayNotifyWnd) 346 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 347 END_COM_MAP() 348 349 DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE) 350 351 BEGIN_MSG_MAP(CTrayNotifyWnd) 352 MESSAGE_HANDLER(WM_CREATE, OnCreate) 353 MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) 354 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 355 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 356 MESSAGE_HANDLER(WM_SIZE, OnSize) 357 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 358 MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) 359 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnClockMessage) 360 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnClockMessage) 361 MESSAGE_HANDLER(WM_SETFONT, OnClockMessage) 362 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnPagerMessage) 363 MESSAGE_HANDLER(WM_COPYDATA, OnPagerMessage) 364 NOTIFY_CODE_HANDLER(NTNWM_REALIGN, OnRealign) 365 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize) 366 END_MSG_MAP() 367 368 HRESULT Initialize(IN HWND hwndParent) 369 { 370 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 371 Create(hwndParent, 0, NULL, dwStyle, WS_EX_STATICEDGE); 372 if (!m_hWnd) 373 return E_FAIL; 374 return S_OK; 375 } 376 }; 377 378 HRESULT CTrayNotifyWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv) 379 { 380 return ShellObjectCreatorInit<CTrayNotifyWnd>(hwndParent, riid, ppv); 381 } 382