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 BOOL GetMinimumSize(IN OUT PSIZE pSize) 128 { 129 SIZE szClock = { 0, 0 }; 130 SIZE szTray = { 0, 0 }; 131 132 if (!g_TaskbarSettings.sr.HideClock) 133 { 134 if (IsHorizontal) 135 { 136 szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; 137 if (szClock.cy <= 0) 138 goto NoClock; 139 } 140 else 141 { 142 szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; 143 if (szClock.cx <= 0) 144 goto NoClock; 145 } 146 147 ::SendMessage(m_hwndClock, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &szClock); 148 149 szTrayClockMin = szClock; 150 } 151 else 152 NoClock: 153 szTrayClockMin = szClock; 154 155 if (IsHorizontal) 156 { 157 szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; 158 } 159 else 160 { 161 szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; 162 } 163 164 ::SendMessage(m_hwndPager, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &szTray); 165 166 szTrayNotify = szTray; 167 168 if (IsHorizontal) 169 { 170 pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X; 171 172 if (!g_TaskbarSettings.sr.HideClock) 173 pSize->cx += TRAY_NOTIFY_WND_SPACING_X + szTrayClockMin.cx; 174 175 pSize->cx += szTray.cx; 176 pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; 177 } 178 else 179 { 180 pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y; 181 182 if (!g_TaskbarSettings.sr.HideClock) 183 pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + szTrayClockMin.cy; 184 185 pSize->cy += szTray.cy; 186 pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; 187 } 188 189 return TRUE; 190 } 191 192 VOID Size(IN const SIZE *pszClient) 193 { 194 if (!g_TaskbarSettings.sr.HideClock) 195 { 196 POINT ptClock; 197 SIZE szClock; 198 199 if (IsHorizontal) 200 { 201 ptClock.x = pszClient->cx - szTrayClockMin.cx - ContentMargin.cxRightWidth; 202 ptClock.y = ContentMargin.cyTopHeight; 203 szClock.cx = szTrayClockMin.cx; 204 szClock.cy = pszClient->cy - ContentMargin.cyTopHeight - ContentMargin.cyBottomHeight; 205 } 206 else 207 { 208 ptClock.x = ContentMargin.cxLeftWidth; 209 ptClock.y = pszClient->cy - szTrayClockMin.cy; 210 szClock.cx = pszClient->cx - ContentMargin.cxLeftWidth - ContentMargin.cxRightWidth; 211 szClock.cy = szTrayClockMin.cy; 212 } 213 214 ::SetWindowPos(m_hwndClock, 215 NULL, 216 ptClock.x, 217 ptClock.y, 218 szClock.cx, 219 szClock.cy, 220 SWP_NOZORDER); 221 } 222 223 POINT ptPager; 224 225 if (IsHorizontal) 226 { 227 ptPager.x = ContentMargin.cxLeftWidth; 228 ptPager.y = (pszClient->cy - szTrayNotify.cy)/2; 229 } 230 else 231 { 232 ptPager.x = (pszClient->cx - szTrayNotify.cx)/2; 233 ptPager.y = ContentMargin.cyTopHeight; 234 } 235 236 ::SetWindowPos(m_hwndPager, 237 NULL, 238 ptPager.x, 239 ptPager.y, 240 szTrayNotify.cx, 241 szTrayNotify.cy, 242 SWP_NOZORDER); 243 } 244 245 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 246 { 247 HDC hdc = (HDC) wParam; 248 249 if (!TrayTheme) 250 { 251 bHandled = FALSE; 252 return 0; 253 } 254 255 RECT rect; 256 GetClientRect(&rect); 257 if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0)) 258 DrawThemeParentBackground(m_hWnd, hdc, &rect); 259 260 DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0); 261 262 return TRUE; 263 } 264 265 LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 266 { 267 BOOL Horizontal = (BOOL) wParam; 268 269 if (Horizontal != IsHorizontal) 270 { 271 IsHorizontal = Horizontal; 272 if (IsHorizontal) 273 SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL); 274 else 275 SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL); 276 } 277 278 return (LRESULT) GetMinimumSize((PSIZE) lParam); 279 } 280 281 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 282 { 283 SIZE szClient; 284 285 szClient.cx = LOWORD(lParam); 286 szClient.cy = HIWORD(lParam); 287 288 Size(&szClient); 289 290 return TRUE; 291 } 292 293 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 294 { 295 return HTTRANSPARENT; 296 } 297 298 LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 299 { 300 bHandled = TRUE; 301 return 0; 302 } 303 304 LRESULT OnClockMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 305 { 306 return SendMessageW(m_hwndClock, uMsg, wParam, lParam); 307 } 308 309 LRESULT OnPagerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 310 { 311 return SendMessageW(m_hwndPager, uMsg, wParam, lParam); 312 } 313 314 LRESULT OnRealign(INT uCode, LPNMHDR hdr, BOOL& bHandled) 315 { 316 hdr->hwndFrom = m_hWnd; 317 return GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM)hdr); 318 } 319 320 HRESULT WINAPI GetWindow(HWND* phwnd) 321 { 322 if (!phwnd) 323 return E_INVALIDARG; 324 *phwnd = m_hWnd; 325 return S_OK; 326 } 327 328 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode) 329 { 330 return E_NOTIMPL; 331 } 332 333 DECLARE_NOT_AGGREGATABLE(CTrayNotifyWnd) 334 335 DECLARE_PROTECT_FINAL_CONSTRUCT() 336 BEGIN_COM_MAP(CTrayNotifyWnd) 337 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 338 END_COM_MAP() 339 340 DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE) 341 342 BEGIN_MSG_MAP(CTrayNotifyWnd) 343 MESSAGE_HANDLER(WM_CREATE, OnCreate) 344 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 345 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 346 MESSAGE_HANDLER(WM_SIZE, OnSize) 347 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 348 MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) // FIXME: This handler is not necessary in Windows 349 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnClockMessage) 350 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnClockMessage) 351 MESSAGE_HANDLER(WM_SETFONT, OnClockMessage) 352 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnPagerMessage) 353 MESSAGE_HANDLER(WM_COPYDATA, OnPagerMessage) 354 NOTIFY_CODE_HANDLER(NTNWM_REALIGN, OnRealign) 355 MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize) 356 END_MSG_MAP() 357 358 HRESULT Initialize(IN HWND hwndParent) 359 { 360 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 361 Create(hwndParent, 0, NULL, dwStyle, WS_EX_STATICEDGE); 362 if (!m_hWnd) 363 return E_FAIL; 364 return S_OK; 365 } 366 }; 367 368 HRESULT CTrayNotifyWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv) 369 { 370 return ShellObjectCreatorInit<CTrayNotifyWnd>(hwndParent, riid, ppv); 371 } 372