Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396/* * PROJECT: ReactOS Explorer * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Show Desktop tray button implementation * COPYRIGHT: Copyright 2006-2007 Thomas Weidenmueller <w3seek@reactos.org> * Copyright 2018-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> * Copyright 2023 Ethan Rodensky <splitwirez@gmail.com> */
#include "precomp.h"#include <commoncontrols.h>#include <uxtheme.h>
#define IDI_SHELL32_DESKTOP 35#define IDI_IMAGERES_DESKTOP 110
#define SHOW_DESKTOP_TIMER_ID 999#define SHOW_DESKTOP_TIMER_INTERVAL 200
CTrayShowDesktopButton::CTrayShowDesktopButton() : m_nClickedTime(0), m_inset({2, 2}), m_icon(NULL), m_highContrastMode(FALSE), m_drawWithDedicatedBackground(FALSE), m_bHovering(FALSE), m_hWndTaskbar(NULL), m_bPressed(FALSE), m_bHorizontal(FALSE){}
INT CTrayShowDesktopButton::WidthOrHeight() const{ if (IsThemeActive() && !m_highContrastMode) { if (m_drawWithDedicatedBackground) { if (GetSystemMetrics(SM_TABLETPC)) { //TODO: DPI scaling - return logical-to-physical conversion of 24, not fixed value return 24; } else return 15; } else { INT CurMargin = m_bHorizontal ? (m_ContentMargins.cxLeftWidth + m_ContentMargins.cxRightWidth) : (m_ContentMargins.cyTopHeight + m_ContentMargins.cyBottomHeight); return max(16 + CurMargin, 18) + 6; } } else { return max(2 * GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXSMICON), 2 * GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYSMICON)); }}
HRESULT CTrayShowDesktopButton::DoCreate(HWND hwndParent){ const DWORD style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_DEFPUSHBUTTON; Create(hwndParent, NULL, NULL, style);
if (!m_hWnd) return E_FAIL;
// Get desktop icon bool bIconRetrievalFailed = ExtractIconExW(L"imageres.dll", -IDI_IMAGERES_DESKTOP, NULL, &m_icon, 1) == UINT_MAX; if (bIconRetrievalFailed || !m_icon) ExtractIconExW(L"shell32.dll", -IDI_SHELL32_DESKTOP, NULL, &m_icon, 1);
// Get appropriate size at which to display desktop icon m_szIcon.cx = GetSystemMetrics(SM_CXSMICON); m_szIcon.cy = GetSystemMetrics(SM_CYSMICON);
// Create tooltip m_tooltip.Create(m_hWnd, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP);
TOOLINFOW ti = { 0 }; ti.cbSize = TTTOOLINFOW_V1_SIZE; ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS; ti.hwnd = m_hWnd; ti.uId = reinterpret_cast<UINT_PTR>(m_hWnd); ti.hinst = hExplorerInstance; ti.lpszText = MAKEINTRESOURCEW(IDS_TRAYDESKBTN_TOOLTIP);
m_tooltip.AddTool(&ti);
// Prep visual style EnsureWindowTheme(TRUE);
// Get HWND of Taskbar m_hWndTaskbar = ::GetParent(hwndParent); if (!::IsWindow(m_hWndTaskbar)) return E_FAIL;
return S_OK;}
LRESULT CTrayShowDesktopButton::OnClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ // The actual action can be delayed as an expected behaviour. // But a too late action is an unexpected behaviour. LONG nTime0 = m_nClickedTime; LONG nTime1 = ::GetMessageTime(); if (nTime1 - nTime0 >= 600) // Ignore after 0.6 sec return 0;
// Show/Hide Desktop ::SendMessage(m_hWndTaskbar, WM_COMMAND, TRAYCMD_TOGGLE_DESKTOP, 0);
return 0;}
// This function is called from OnLButtonDown and parent.VOID CTrayShowDesktopButton::Click(){ // The actual action can be delayed as an expected behaviour. m_nClickedTime = ::GetMessageTime(); PostMessage(TSDB_CLICK, 0, 0);}
LRESULT CTrayShowDesktopButton::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ m_bPressed = FALSE; ReleaseCapture(); Invalidate(TRUE);
POINT pt; ::GetCursorPos(&pt); if (PtInButton(&pt)) Click(); // Left-click return 0;}
LRESULT CTrayShowDesktopButton::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ m_bPressed = TRUE; SetCapture(); Invalidate(TRUE); return 0;}
LRESULT CTrayShowDesktopButton::OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ LRESULT ret = OnThemeChanged(uMsg, wParam, lParam, bHandled); EnsureWindowTheme(TRUE); return ret;}
LRESULT CTrayShowDesktopButton::OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ HIGHCONTRAST hcInfo; hcInfo.cbSize = sizeof(hcInfo); if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hcInfo), &hcInfo, FALSE)) m_highContrastMode = (hcInfo.dwFlags & HCF_HIGHCONTRASTON);
if (m_hTheme) { ::CloseThemeData(m_hTheme); m_hTheme = NULL; } if (m_hFallbackTheme) { ::CloseThemeData(m_hFallbackTheme); m_hFallbackTheme = NULL; }
EnsureWindowTheme(FALSE);
Invalidate(TRUE); return 0;}
LRESULT CTrayShowDesktopButton::OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ EnsureWindowTheme(TRUE); return 0;}
VOID CTrayShowDesktopButton::EnsureWindowTheme(BOOL setTheme){ if (setTheme) SetWindowTheme(m_hWnd, m_bHorizontal ? L"ShowDesktop" : L"VerticalShowDesktop", NULL);
if (::IsWindow(m_hWndTaskbar)) { m_hFallbackTheme = ::OpenThemeData(m_hWndTaskbar, L"Toolbar"); GetThemeMargins(m_hFallbackTheme, NULL, TP_BUTTON, 0, TMT_CONTENTMARGINS, NULL, &m_ContentMargins); } else { m_hFallbackTheme = NULL; }
MARGINS contentMargins; if (GetThemeMargins(GetWindowTheme(GetParent().m_hWnd), NULL, TNP_BACKGROUND, 0, TMT_CONTENTMARGINS, NULL, &contentMargins) == S_OK) { m_inset.cx = max(0, contentMargins.cxRightWidth - 5); m_inset.cy = max(0, contentMargins.cyBottomHeight - 5); } else { m_inset.cx = 2; m_inset.cy = 2; }
m_drawWithDedicatedBackground = FALSE; if (IsThemeActive()) { m_hTheme = OpenThemeData(m_hWnd, L"Button"); if (m_hTheme != NULL) m_drawWithDedicatedBackground = !IsThemePartDefined(m_hTheme, BP_PUSHBUTTON, 0); }}
LRESULT CTrayShowDesktopButton::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ RECT rc; GetClientRect(&rc);
PAINTSTRUCT ps; HDC hdc = BeginPaint(&ps); OnDraw(hdc, &rc); EndPaint(&ps);
return 0;}
LRESULT CTrayShowDesktopButton::OnPrintClient(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ if ((lParam & PRF_CHECKVISIBLE) && !IsWindowVisible()) return 0;
RECT rc; GetClientRect(&rc);
HDC hdc = (HDC)wParam; OnDraw(hdc, &rc);
return 0;}
BOOL CTrayShowDesktopButton::PtInButton(LPPOINT ppt) const{ if (!ppt || !IsWindow()) return FALSE;
RECT rc; GetWindowRect(&rc); INT cxEdge = ::GetSystemMetrics(SM_CXEDGE), cyEdge = ::GetSystemMetrics(SM_CYEDGE); ::InflateRect(&rc, max(cxEdge, 1), max(cyEdge, 1));
return m_bHorizontal ? (ppt->x > rc.left) : (ppt->y > rc.top);}
VOID CTrayShowDesktopButton::StartHovering(){ if (m_bHovering) return;
m_bHovering = TRUE; Invalidate(TRUE);
SetTimer(SHOW_DESKTOP_TIMER_ID, SHOW_DESKTOP_TIMER_INTERVAL, NULL);
::PostMessage(m_hWndTaskbar, WM_NCPAINT, 0, 0);}
LRESULT CTrayShowDesktopButton::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ StartHovering(); return 0;}
LRESULT CTrayShowDesktopButton::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ if (wParam != SHOW_DESKTOP_TIMER_ID || !m_bHovering) return 0;
POINT pt; ::GetCursorPos(&pt); if (!PtInButton(&pt)) // The end of hovering? { m_bHovering = FALSE; KillTimer(SHOW_DESKTOP_TIMER_ID); Invalidate(TRUE);
::PostMessage(m_hWndTaskbar, WM_NCPAINT, 0, 0); }
return 0;}
LRESULT CTrayShowDesktopButton::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){ if (m_hTheme) { ::CloseThemeData(m_hTheme); m_hTheme = NULL; } if (m_hFallbackTheme) { ::CloseThemeData(m_hFallbackTheme); m_hFallbackTheme = NULL; }
return 0;}
VOID CTrayShowDesktopButton::OnDraw(HDC hdc, LPRECT prc){ RECT rc = { prc->left, prc->top, prc->right, prc->bottom }; LPRECT lpRc = &rc; HBRUSH hbrBackground = NULL;
if (m_hTheme) { HTHEME theme; int part = 0; int state = 0; if (m_drawWithDedicatedBackground) { theme = m_hTheme;
if (m_bPressed) state = PBS_PRESSED; else if (m_bHovering) state = PBS_HOT; else state = PBS_NORMAL; } else { part = TP_BUTTON; theme = m_hFallbackTheme;
if (m_bPressed) state = TS_PRESSED; else if (m_bHovering) state = TS_HOT; else state = TS_NORMAL;
if (m_bHorizontal) rc.right -= m_inset.cx; else rc.bottom -= m_inset.cy; }
if (::IsThemeBackgroundPartiallyTransparent(theme, part, state)) ::DrawThemeParentBackground(m_hWnd, hdc, NULL);
::DrawThemeBackground(theme, hdc, part, state, lpRc, lpRc); } else { hbrBackground = ::GetSysColorBrush(COLOR_3DFACE); ::FillRect(hdc, lpRc, hbrBackground);
if (m_bPressed || m_bHovering) { UINT edge = m_bPressed ? BDR_SUNKENOUTER : BDR_RAISEDINNER; DrawEdge(hdc, lpRc, edge, BF_RECT); } }
if (m_highContrastMode || !m_drawWithDedicatedBackground) { /* Prepare to draw icon */
// Determine X-position of icon's top-left corner int iconX = rc.left; iconX += (rc.right - iconX) / 2; iconX -= m_szIcon.cx / 2;
// Determine Y-position of icon's top-left corner int iconY = rc.top; iconY += (rc.bottom - iconY) / 2; iconY -= m_szIcon.cy / 2;
// Ok now actually draw the icon itself if (m_icon) { DrawIconEx(hdc, iconX, iconY, m_icon, 0, 0, 0, hbrBackground, DI_NORMAL); } }}