Index: reactos/base/shell/explorer/traywnd.cpp =================================================================== --- reactos/base/shell/explorer/traywnd.cpp (revision 74469) +++ reactos/base/shell/explorer/traywnd.cpp (working copy) @@ -2,6 +2,7 @@ * ReactOS Explorer * * Copyright 2006 - 2007 Thomas Weidenmueller + * Copyright 2017 Katayama Hirofumi MZ * * this library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -169,6 +170,179 @@ } }; +/* window list for Win+D and Win+M */ +class WindowList +{ + struct NODE + { + NODE *Next; + NODE *Prev; + HWND hwnd; + BOOL IsTarget; + BOOL CanMinimize; + }; + NODE *m_pHead, *m_pTail; + + WindowList(const WindowList&); + WindowList& operator=(const WindowList&); + +public: + WindowList() + { + m_pHead = m_pTail = NULL; + } + + ~WindowList() + { + Destroy(); + } + + BOOL IsEmpty() const + { + return m_pHead == NULL; + } + + void Destroy() + { + NODE *pNode = m_pHead; + while (pNode) + { + NODE *pNext = pNode->Next; + delete pNode; + pNode = pNext; + } + + m_pHead = m_pTail = NULL; + } + + void AddNode(HWND hwnd, BOOL IsTarget, BOOL CanMinimize) + { + NODE *pNode = new NODE; + pNode->hwnd = hwnd; + pNode->IsTarget = IsTarget; + pNode->CanMinimize = CanMinimize; + pNode->Prev = NULL; + + if (m_pHead) + { + m_pHead->Prev = pNode; + pNode->Next = m_pHead; + m_pHead = pNode; + } + else + { + pNode->Next = NULL; + m_pHead = m_pTail = pNode; + } + } + + void PostMinimizeFlaged() + { + /* minimize the targets if possible */ + for (NODE *pNode = m_pHead; pNode; pNode = pNode->Next) + { + if (pNode->IsTarget && pNode->CanMinimize) + { + ::PostMessageW(pNode->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0); + } + } + } + + void ForceMinimizeFlaged(HWND m_DesktopWnd) + { + /* make all the task windows under m_DesktopWnd */ + for (NODE *pNode = m_pHead; pNode; pNode = pNode->Next) + { + if (pNode->IsTarget) + { + ::SetWindowPos(pNode->hwnd, m_DesktopWnd, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + } + + void GetList(HWND m_hWnd, HWND m_DesktopWnd, BOOL Check); + void RestoreAll(); +}; + +void WindowList::RestoreAll() +{ + if (IsEmpty()) + return; + + /* restore without activation */ + HWND hwndPrev = HWND_BOTTOM; + for (NODE *pNode = m_pTail; pNode; pNode = pNode->Prev) + { + if (pNode->IsTarget) + { + ::ShowWindowAsync(pNode->hwnd, SW_SHOWNOACTIVATE); + + /* insert after hwndPrev */ + ::SetWindowPos(pNode->hwnd, hwndPrev, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + hwndPrev = pNode->hwnd; + } + + /* activate previous top window */ + for (NODE *pNode = m_pTail; pNode; pNode = pNode->Prev) + { + if (::IsWindowVisible(pNode->hwnd)) + { + if (pNode->IsTarget || pNode->CanMinimize) + { + ::SetWindowPos(pNode->hwnd, NULL, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); + ::BringWindowToTop(pNode->hwnd); + break; + } + } + } + + Destroy(); +} + +void WindowList::GetList(HWND m_hWnd, HWND m_DesktopWnd, BOOL Check) +{ + for (HWND hwndTop = ::GetTopWindow(NULL); + hwndTop; hwndTop = ::GetWindow(hwndTop, GW_HWNDNEXT)) + { + /* ignore special windows */ + if (m_hWnd == hwndTop || m_DesktopWnd == hwndTop) + continue; + + BOOL IsTarget, CanMinimize = TRUE; + if (Check) + { + /* is SC_MINIMIZE enabled in system menu? */ + HMENU hSysMenu = ::GetSystemMenu(hwndTop, FALSE); + MENUITEMINFOW Info; + ZeroMemory(&Info, sizeof(Info)); + Info.cbSize = sizeof(Info); + Info.fMask = MIIM_STATE; + if (::GetWindow(hwndTop, GW_OWNER) != NULL || + !::GetMenuItemInfoW(hSysMenu, SC_MINIMIZE, FALSE, &Info) || + (Info.fState & MFS_DISABLED)) + { + CanMinimize = FALSE; + } + } + + if (::IsWindowVisible(hwndTop) && !::IsIconic(hwndTop)) + { + IsTarget = TRUE; + } + else + { + IsTarget = FALSE; + CanMinimize = FALSE; + } + + AddNode(hwndTop, IsTarget, CanMinimize); + } +} + class CTrayWindow : public CComCoClass, public CComObjectRootEx, @@ -212,6 +386,8 @@ HDPA m_ShellServices; + WindowList m_WindowList; + public: CComPtr m_TrayBandSite; @@ -520,6 +696,33 @@ return TRUE; } + void MinimizeAll() + { + m_WindowList.Destroy(); + m_WindowList.GetList(m_hWnd, m_DesktopWnd, TRUE); + m_WindowList.PostMinimizeFlaged(); + ::SetForegroundWindow(m_DesktopWnd); + ::SetFocus(m_DesktopWnd); + } + + void WinDesktop() + { + if (!m_WindowList.IsEmpty()) + { + RestoreAll(); + return; + } + m_WindowList.GetList(m_hWnd, m_DesktopWnd, FALSE); + m_WindowList.ForceMinimizeFlaged(m_DesktopWnd); + ::SetForegroundWindow(m_DesktopWnd); + ::SetFocus(m_DesktopWnd); + } + + void RestoreAll() + { + m_WindowList.RestoreAll(); + } + LRESULT HandleHotKey(DWORD id) { switch (id) @@ -550,10 +753,13 @@ case IDHK_PREV_TASK: break; case IDHK_MINIMIZE_ALL: + MinimizeAll(); break; case IDHK_RESTORE_ALL: + RestoreAll(); break; case IDHK_DESKTOP: + WinDesktop(); break; case IDHK_PAGER: break;