Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559/* * ReactOS Explorer * * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org> * Copyright 2018 Ged Murphy <gedmurphy@reactos.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "precomp.h"#include <commoncontrols.h>
static const WCHAR szTrayNotifyWndClass[] = L"TrayNotifyWnd";
#define TRAY_NOTIFY_WND_SPACING_X 1#define TRAY_NOTIFY_WND_SPACING_Y 1#define CLOCK_TEXT_HACK 4
/* * TrayNotifyWnd */
class CTrayNotifyWnd : public CComCoClass<CTrayNotifyWnd>, public CComObjectRootEx<CComMultiThreadModelNoCS>, public CWindowImpl < CTrayNotifyWnd, CWindow, CControlWinTraits >, public IOleWindow{ CComPtr<IUnknown> m_clock; CTrayShowDesktopButton m_ShowDesktopButton; CComPtr<IUnknown> m_pager;
HWND m_hwndClock; HWND m_hwndShowDesktop; HWND m_hwndPager;
HTHEME TrayTheme; SIZE trayClockMinSize; SIZE trayShowDesktopSize; SIZE trayNotifySize; MARGINS ContentMargin; BOOL IsHorizontal;
public: CTrayNotifyWnd() : m_hwndClock(NULL), m_hwndPager(NULL), TrayTheme(NULL), IsHorizontal(FALSE) { ZeroMemory(&trayClockMinSize, sizeof(trayClockMinSize)); ZeroMemory(&trayShowDesktopSize, sizeof(trayShowDesktopSize)); ZeroMemory(&trayNotifySize, sizeof(trayNotifySize)); ZeroMemory(&ContentMargin, sizeof(ContentMargin)); } ~CTrayNotifyWnd() { }
LRESULT OnThemeChanged() { if (TrayTheme) CloseThemeData(TrayTheme);
if (IsThemeActive()) TrayTheme = OpenThemeData(m_hWnd, L"TrayNotify"); else TrayTheme = NULL;
if (TrayTheme) { SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, 0);
GetThemeMargins(TrayTheme, NULL, TNP_BACKGROUND, 0, TMT_CONTENTMARGINS, NULL, &ContentMargin); } else { SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, WS_EX_STATICEDGE);
ContentMargin.cxLeftWidth = 2; ContentMargin.cxRightWidth = 2; ContentMargin.cyTopHeight = 2; ContentMargin.cyBottomHeight = 2; }
return TRUE; }
LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return OnThemeChanged(); }
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HRESULT hr;
hr = CTrayClockWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_clock)); if (FAILED_UNEXPECTEDLY(hr)) return FALSE;
hr = IUnknown_GetWindow(m_clock, &m_hwndClock); if (FAILED_UNEXPECTEDLY(hr)) return FALSE;
hr = CSysPagerWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_pager)); if (FAILED_UNEXPECTEDLY(hr)) return FALSE;
hr = IUnknown_GetWindow(m_pager, &m_hwndPager); if (FAILED_UNEXPECTEDLY(hr)) return FALSE;
/* Create the 'Show Desktop' button */ m_ShowDesktopButton.DoCreate(m_hWnd); m_hwndShowDesktop = m_ShowDesktopButton.m_hWnd;
return TRUE; }
BOOL GetMinimumSize(IN OUT PSIZE pSize) { SIZE clockSize = { 0, 0 }; SIZE traySize = { 0, 0 }; SIZE showDesktopSize = { 0, 0 }; BOOL bHideClock = GetHideClock();
if (!bHideClock) { if (IsHorizontal) { clockSize.cy = pSize->cy; if (clockSize.cy <= 0) goto NoClock; } else { clockSize.cx = pSize->cx; if (clockSize.cx <= 0) goto NoClock; }
::SendMessage(m_hwndClock, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &clockSize);
trayClockMinSize = clockSize; } else NoClock: trayClockMinSize = clockSize;
if (IsHorizontal) { traySize.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y; } else { traySize.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X; }
::SendMessage(m_hwndPager, TNWM_GETMINIMUMSIZE, (WPARAM) IsHorizontal, (LPARAM) &traySize);
trayNotifySize = traySize;
INT showDesktopButtonExtent = 0; if (g_TaskbarSettings.bShowDesktopButton) { showDesktopButtonExtent = m_ShowDesktopButton.WidthOrHeight(); if (IsHorizontal) { showDesktopSize.cx = showDesktopButtonExtent; showDesktopSize.cy = pSize->cy; } else { showDesktopSize.cx = pSize->cx; showDesktopSize.cy = showDesktopButtonExtent; } } trayShowDesktopSize = showDesktopSize;
if (IsHorizontal) { pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X;
if (!bHideClock) pSize->cx += TRAY_NOTIFY_WND_SPACING_X + trayClockMinSize.cx;
if (g_TaskbarSettings.bShowDesktopButton) pSize->cx += showDesktopButtonExtent;
pSize->cx += traySize.cx; pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; } else { pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y;
if (!bHideClock) pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + trayClockMinSize.cy;
if (g_TaskbarSettings.bShowDesktopButton) pSize->cy += showDesktopButtonExtent;
pSize->cy += traySize.cy; pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; }
return TRUE; }
VOID Size(IN OUT SIZE *pszClient) { RECT rcClient = {0, 0, pszClient->cx, pszClient->cy}; AlignControls(&rcClient); pszClient->cx = rcClient.right - rcClient.left; pszClient->cy = rcClient.bottom - rcClient.top; }
VOID AlignControls(IN CONST PRECT prcClient OPTIONAL) { RECT rcClient; if (prcClient != NULL) rcClient = *prcClient; else GetClientRect(&rcClient);
rcClient.left += ContentMargin.cxLeftWidth; rcClient.top += ContentMargin.cyTopHeight; rcClient.right -= ContentMargin.cxRightWidth; rcClient.bottom -= ContentMargin.cyBottomHeight;
CONST UINT swpFlags = SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_NOZORDER;
if (g_TaskbarSettings.bShowDesktopButton) { POINT ptShowDesktop = { rcClient.left, rcClient.top }; SIZE showDesktopSize = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top };
INT cxyShowDesktop = m_ShowDesktopButton.WidthOrHeight(); if (IsHorizontal) { if (!TrayTheme) { ptShowDesktop.y -= ContentMargin.cyTopHeight; showDesktopSize.cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight; }
rcClient.right -= (cxyShowDesktop - ContentMargin.cxRightWidth);
ptShowDesktop.x = rcClient.right; showDesktopSize.cx = cxyShowDesktop;
// HACK: Clock has layout problems - remove this once addressed. rcClient.right -= CLOCK_TEXT_HACK; } else { if (!TrayTheme) { ptShowDesktop.x -= ContentMargin.cxLeftWidth; showDesktopSize.cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth; }
rcClient.bottom -= (cxyShowDesktop - ContentMargin.cyBottomHeight);
ptShowDesktop.y = rcClient.bottom; showDesktopSize.cy = cxyShowDesktop;
// HACK: Clock has layout problems - remove this once addressed. rcClient.bottom -= CLOCK_TEXT_HACK; }
/* Resize and reposition the button */ ::SetWindowPos(m_hwndShowDesktop, NULL, ptShowDesktop.x, ptShowDesktop.y, showDesktopSize.cx, showDesktopSize.cy, swpFlags); }
if (!GetHideClock()) { POINT ptClock = { rcClient.left, rcClient.top }; SIZE clockSize = { rcClient.right - rcClient.left, rcClient.bottom - rcClient.top };
if (IsHorizontal) { rcClient.right -= trayClockMinSize.cx;
ptClock.x = rcClient.right; clockSize.cx = trayClockMinSize.cx; } else { rcClient.bottom -= trayClockMinSize.cy;
ptClock.y = rcClient.bottom; clockSize.cy = trayClockMinSize.cy; }
::SetWindowPos(m_hwndClock, NULL, ptClock.x, ptClock.y, clockSize.cx, clockSize.cy, swpFlags); }
POINT ptPager; if (IsHorizontal) { ptPager.x = ContentMargin.cxLeftWidth; ptPager.y = ((rcClient.bottom - rcClient.top) - trayNotifySize.cy) / 2; if (g_TaskbarSettings.UseCompactTrayIcons()) ptPager.y += ContentMargin.cyTopHeight; } else { ptPager.x = ((rcClient.right - rcClient.left) - trayNotifySize.cx) / 2; if (g_TaskbarSettings.UseCompactTrayIcons()) ptPager.x += ContentMargin.cxLeftWidth; ptPager.y = ContentMargin.cyTopHeight; }
::SetWindowPos(m_hwndPager, NULL, ptPager.x, ptPager.y, trayNotifySize.cx, trayNotifySize.cy, swpFlags);
if (prcClient != NULL) { prcClient->left = rcClient.left - ContentMargin.cxLeftWidth; prcClient->top = rcClient.top - ContentMargin.cyTopHeight; prcClient->right = rcClient.right + ContentMargin.cxRightWidth; prcClient->bottom = rcClient.bottom + ContentMargin.cyBottomHeight; } }
LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HDC hdc = (HDC) wParam;
if (!TrayTheme) { bHandled = FALSE; return 0; }
RECT rect; GetClientRect(&rect); if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0)) DrawThemeParentBackground(m_hWnd, hdc, &rect);
DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
return TRUE; }
LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { BOOL Horizontal = (BOOL) wParam;
if (Horizontal != IsHorizontal) IsHorizontal = Horizontal;
SetWindowTheme(m_hWnd, IsHorizontal ? L"TrayNotifyHoriz" : L"TrayNotifyVert", NULL); m_ShowDesktopButton.m_bHorizontal = Horizontal;
return (LRESULT)GetMinimumSize((PSIZE)lParam); }
LRESULT OnGetShowDesktopButton(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == NULL) return 0;
CTrayShowDesktopButton** ptr = (CTrayShowDesktopButton**)wParam; if (!m_ShowDesktopButton) { *ptr = NULL; return 0; }
*ptr = &m_ShowDesktopButton; bHandled = TRUE; return 0; }
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SIZE clientSize;
clientSize.cx = LOWORD(lParam); clientSize.cy = HIWORD(lParam);
Size(&clientSize);
return TRUE; }
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
if (m_ShowDesktopButton && m_ShowDesktopButton.PtInButton(&pt)) return HTCLIENT;
return HTTRANSPARENT; }
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; ::GetCursorPos(&pt);
if (m_ShowDesktopButton && m_ShowDesktopButton.PtInButton(&pt)) m_ShowDesktopButton.StartHovering();
return TRUE; }
LRESULT OnCtxMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = TRUE;
if (reinterpret_cast<HWND>(wParam) == m_hwndClock) return GetParent().SendMessage(uMsg, wParam, lParam); else return 0; }
LRESULT OnClockMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return SendMessageW(m_hwndClock, uMsg, wParam, lParam); }
LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
/* Toggle show desktop button */ if (newSettings->bShowDesktopButton != g_TaskbarSettings.bShowDesktopButton) { g_TaskbarSettings.bShowDesktopButton = newSettings->bShowDesktopButton; ::ShowWindow(m_hwndShowDesktop, g_TaskbarSettings.bShowDesktopButton ? SW_SHOW : SW_HIDE);
/* Ask the parent to resize */ NMHDR nmh = {m_hWnd, 0, NTNWM_REALIGN}; SendMessage(WM_NOTIFY, 0, (LPARAM) &nmh); }
g_TaskbarSettings.bHideInactiveIcons = newSettings->bHideInactiveIcons;
return OnClockMessage(uMsg, wParam, lParam, bHandled); }
LRESULT OnPagerMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { return SendMessageW(m_hwndPager, uMsg, wParam, lParam); }
LRESULT OnRealign(INT uCode, LPNMHDR hdr, BOOL& bHandled) { hdr->hwndFrom = m_hWnd; return GetParent().SendMessage(WM_NOTIFY, 0, (LPARAM)hdr); }
// *** IOleWindow methods ***
STDMETHODIMP GetWindow(HWND* phwnd) override { if (!phwnd) return E_INVALIDARG; *phwnd = m_hWnd; return S_OK; }
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) override { return E_NOTIMPL; }
HRESULT Initialize(IN HWND hwndParent) { const DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; Create(hwndParent, 0, NULL, dwStyle, WS_EX_STATICEDGE); return m_hWnd ? S_OK : E_FAIL; }
DECLARE_NOT_AGGREGATABLE(CTrayNotifyWnd)
DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CTrayNotifyWnd) COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) END_COM_MAP()
DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE)
BEGIN_MSG_MAP(CTrayNotifyWnd) MESSAGE_HANDLER(WM_CREATE, OnCreate) MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_CONTEXTMENU, OnCtxMenu) MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnClockMessage) MESSAGE_HANDLER(WM_SETFONT, OnClockMessage) MESSAGE_HANDLER(WM_SETTINGCHANGE, OnPagerMessage) MESSAGE_HANDLER(WM_COPYDATA, OnPagerMessage) MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) NOTIFY_CODE_HANDLER(NTNWM_REALIGN, OnRealign) MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize) MESSAGE_HANDLER(TNWM_GETSHOWDESKTOPBUTTON, OnGetShowDesktopButton) END_MSG_MAP()};
HRESULT CTrayNotifyWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv){ return ShellObjectCreatorInit<CTrayNotifyWnd>(hwndParent, riid, ppv);}