From 07467c9e060525d439c4add457f6875038a3ed8b Mon Sep 17 00:00:00 2001 From: David Quintana Date: Fri, 21 Feb 2014 10:00:00 +0000 Subject: [PATCH] [RSHELL] * CMenuBand, CMenuDeskBar: Improve the SubMenu hierarchy and OnSelect flow. Now the menu will spread a FullCancel or Execute upwards and close the whole start menu. CORE-7881 svn path=/branches/shell-experiments/; revision=62280 --- base/shell/rshell/CMenuBand.cpp | 117 ++++++++++-------- base/shell/rshell/CMenuDeskBar.cpp | 124 +++++++++++++------- base/shell/rshell/logging/CMenuSiteWrap.cpp | 7 +- 3 files changed, 155 insertions(+), 93 deletions(-) diff --git a/base/shell/rshell/CMenuBand.cpp b/base/shell/rshell/CMenuBand.cpp index 5e4a4ce9530..4e2c799ce8a 100644 --- a/base/shell/rshell/CMenuBand.cpp +++ b/base/shell/rshell/CMenuBand.cpp @@ -140,7 +140,8 @@ private: CComPtr m_site; CComPtr m_psmc; - CComPtr m_childMenu; + CComPtr m_subMenuChild; + CComPtr m_subMenuParent; UINT m_uId; UINT m_uIdAncestor; @@ -269,7 +270,7 @@ public: HRESULT _GetTopLevelWindow(HWND*topLevel); HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id); HRESULT _MenuItemHotTrack(DWORD changeType); - HRESULT _OnPopupSubMenu(IMenuPopup * popup); + HRESULT _OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude); BOOL UseBigIcons() { @@ -332,7 +333,7 @@ private: private: // TODO: make dynamic -#define MAX_RECURSE 100 +#define MAX_RECURSE 20 CMenuBand* m_bandStack[MAX_RECURSE]; int m_bandCount; @@ -358,6 +359,8 @@ private: if (pItem) *pItem = m_bandStack[m_bandCount]; + m_bandStack[m_bandCount] = NULL; + return S_OK; } @@ -676,7 +679,7 @@ LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR case WM_TIMER: if (wParam == TIMERID_HOTTRACK) { - m_menuBand->_OnPopupSubMenu(NULL); + m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL); PopupItem(m_hotItem); KillTimer(hWnd, TIMERID_HOTTRACK); } @@ -776,9 +779,7 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, IShellMenu* childShellMenu) if (FAILED(hr)) return hr; - popup->Popup(&pt, &rcl, MPPF_TOP | MPPF_RIGHT); - - m_menuBand->_OnPopupSubMenu(popup); + m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl); return S_OK; } @@ -1037,11 +1038,12 @@ HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick) HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) { - HRESULT hr = m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0); + HRESULT hr; + hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); if (FAILED(hr)) return hr; - return CMenuToolbarBase::OnCommand(wParam, lParam, theResult); + return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0); } HRESULT CMenuStaticToolbar::PopupItem(UINT uItem) @@ -1099,13 +1101,9 @@ CMenuSFToolbar::~CMenuSFToolbar() HRESULT CMenuSFToolbar::FillToolbar() { HRESULT hr; - TBBUTTON tbb = { 0 }; int i = 0; PWSTR MenuString; - tbb.fsState = TBSTATE_ENABLED; - tbb.fsStyle = 0; - IEnumIDList * eidl; m_shellFolder->EnumObjects(m_hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl); @@ -1116,6 +1114,10 @@ HRESULT CMenuSFToolbar::FillToolbar() INT index = 0; INT indexOpen = 0; + TBBUTTON tbb = { 0 }; + tbb.fsState = TBSTATE_ENABLED; + tbb.fsStyle = 0; + CComPtr psi; SHCreateShellItem(NULL, m_shellFolder, item, &psi); @@ -1222,9 +1224,12 @@ HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick) HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) { - HRESULT hr = m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0); + HRESULT hr; + hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); + if (FAILED(hr)) + return hr; - return CMenuToolbarBase::OnCommand(wParam, lParam, theResult); + return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0); } HRESULT CMenuSFToolbar::PopupItem(UINT uItem) @@ -1299,7 +1304,7 @@ CMenuBand::CMenuBand() : m_useBigIcons(FALSE), m_hotBar(NULL), m_hotItem(-1), - m_childMenu(NULL) + m_subMenuChild(NULL) { m_focusManager = CMenuFocusManager::AcquireManager(); } @@ -1321,7 +1326,8 @@ HRESULT STDMETHODCALLTYPE CMenuBand::Initialize( UINT uIdAncestor, DWORD dwFlags) { - m_psmc = psmc; + if (m_psmc != psmc) + m_psmc = psmc; m_uId = uId; m_uIdAncestor = uIdAncestor; m_dwFlags = dwFlags; @@ -1446,6 +1452,10 @@ HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite) return hr; } + hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_subMenuParent)); + if (FAILED(hr)) + return hr; + CComPtr pTopLevelWindow; hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow)); if (FAILED(hr)) @@ -1498,7 +1508,10 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc) if (hwndStatic) SendMessageW(hwndStatic, TB_GETIDEALSIZE, TRUE, reinterpret_cast(&sizeStaticY)); if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETIDEALSIZE, TRUE, reinterpret_cast(&sizeShlFldY)); - int sy = max(prc->bottom - prc->top, sizeStaticY.cy + sizeShlFldY.cy); + int sy = min(prc->bottom - prc->top, sizeStaticY.cy + sizeShlFldY.cy); + + int syStatic = sizeStaticY.cy; + int syShlFld = sy - syStatic; if (hwndShlFld) { @@ -1506,7 +1519,7 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc) prc->left, prc->top, prc->right - prc->left, - sizeShlFldY.cy, + syShlFld, 0); DWORD btnSize = SendMessage(hwndShlFld, TB_GETBUTTONSIZE, 0, 0); SendMessage(hwndShlFld, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize))); @@ -1515,9 +1528,9 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc) { SetWindowPos(hwndStatic, hwndShlFld, prc->left, - prc->top + sizeShlFldY.cy, + prc->top + syShlFld, prc->right - prc->left, - sy - sizeShlFldY.cy, + syStatic, 0); DWORD btnSize = SendMessage(hwndStatic, TB_GETBUTTONSIZE, 0, 0); SendMessage(hwndStatic, TB_SETBUTTONSIZE, 0, MAKELPARAM(prc->right - prc->left, HIWORD(btnSize))); @@ -1573,6 +1586,9 @@ HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo( if (hwndStatic) SendMessageW(hwndStatic, TB_GETMAXSIZE, 0, reinterpret_cast(&sizeStatic)); if (hwndShlFld) SendMessageW(hwndShlFld, TB_GETMAXSIZE, 0, reinterpret_cast(&sizeShlFld)); + sizeStatic.cx += 64; + sizeShlFld.cx += 64; + pdbi->ptMaxSize.x = max(sizeStatic.cx, sizeShlFld.cx); // ignored pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy; } @@ -1629,7 +1645,7 @@ HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow) else hr = m_focusManager->PopMenu(this); - return hr; + return S_OK; } HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved) @@ -1659,13 +1675,8 @@ HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode) HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg) { HRESULT hr; - CComPtr pmp; - hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp)); - if (FAILED(hr)) - return hr; - - hr = pmp->SetSubMenu(this, fActivate); + hr = m_subMenuParent->SetSubMenu(this, fActivate); if (FAILED(hr)) return hr; @@ -1776,17 +1787,30 @@ HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_PO HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType) { - if (dwSelectType != MPOS_CANCELLEVEL) + switch (dwSelectType) { - if (dwSelectType == MPOS_SELECTLEFT) + case MPOS_CHILDTRACKING: + // TODO: Cancel timers? + return m_subMenuParent->OnSelect(dwSelectType); + case MPOS_SELECTLEFT: + if (m_subMenuChild) + m_subMenuChild->OnSelect(MPOS_CANCELLEVEL); + return m_subMenuParent->OnSelect(dwSelectType); + case MPOS_SELECTRIGHT: + if (m_hotBar && m_hotItem >= 0) { - dwSelectType = MPOS_CANCELLEVEL; + // TODO: popup the current child if it has subitems, otherwise spread up. } - CComPtr pmp; - HRESULT hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp)); - if (FAILED(hr)) - return hr; - return pmp->OnSelect(dwSelectType); + return m_subMenuParent->OnSelect(dwSelectType); + case MPOS_EXECUTE: + case MPOS_FULLCANCEL: + if (m_subMenuChild) + m_subMenuChild->OnSelect(dwSelectType); + return m_subMenuParent->OnSelect(dwSelectType); + case MPOS_CANCELLEVEL: + if (m_subMenuChild) + m_subMenuChild->OnSelect(dwSelectType); + break; } return S_FALSE; } @@ -2180,28 +2204,25 @@ HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType) } else { - CComPtr pmp; - hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &pmp)); - if (FAILED(hr)) - return hr; - pmp->OnSelect(changeType); + m_subMenuParent->OnSelect(changeType); } return S_OK; } -HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup) +HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude) { - if (m_childMenu) + if (m_subMenuChild) { - HRESULT hr = m_childMenu->OnSelect(MPOS_CANCELLEVEL); + HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL); if (FAILED(hr)) return hr; } - m_childMenu = popup; - if (m_childMenu) + m_subMenuChild = popup; + if (popup) { - return m_childMenu->SetSubMenu(this, TRUE); + IUnknown_SetSite(popup, m_subMenuParent); + popup->Popup(pAt, pExclude, MPPF_TOP | MPPF_RIGHT); } return S_OK; -} \ No newline at end of file +} diff --git a/base/shell/rshell/CMenuDeskBar.cpp b/base/shell/rshell/CMenuDeskBar.cpp index 793aa810bfa..f5f92f72be0 100644 --- a/base/shell/rshell/CMenuDeskBar.cpp +++ b/base/shell/rshell/CMenuDeskBar.cpp @@ -47,12 +47,15 @@ private: CComPtr m_Site; CComPtr m_Client; CComPtr m_SubMenuParent; + CComPtr m_SubMenuChild; HWND m_ClientWindow; DWORD m_IconSize; HBITMAP m_Banner; + INT m_Level; + public: CMenuDeskBar(); ~CMenuDeskBar(); @@ -130,6 +133,8 @@ private: LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT _OnWindowPosChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + + HRESULT _CloseBar(); }; extern "C" @@ -150,14 +155,18 @@ HRESULT CMenuDeskBar_Constructor(REFIID riid, LPVOID *ppv) return hr; } +INT deskBarCount=0; + CMenuDeskBar::CMenuDeskBar() : m_Client(NULL), - m_Banner(NULL) + m_Banner(NULL), + m_Level(deskBarCount++) { } CMenuDeskBar::~CMenuDeskBar() { + deskBarCount--; } HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd) @@ -316,8 +325,12 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnPosRectChangeDB(LPRECT prc) HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSite(IUnknown *pUnkSite) { + // Windows closes the bar if this is called when the bar is shown + m_Site = pUnkSite; + IUnknown_QueryService(m_Site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_SubMenuParent)); + return S_OK; } @@ -468,12 +481,24 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP int cx = rc.right; int cy = rc.bottom; - if (y < 0) + RECT rcWorkArea; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0); + + int waHeight = rcWorkArea.bottom - rcWorkArea.top; + + if (y < rcWorkArea.top) { - y = 0; + y = rcWorkArea.top; } - // if (y+cy > work area height) cy = work area height - y + if (cy > waHeight) + { + cy = waHeight; + } + else if (y + cy > rcWorkArea.bottom) + { + y = rcWorkArea.bottom - cy; + } this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, SWP_SHOWWINDOW); @@ -533,70 +558,87 @@ HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap) HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect( DWORD dwSelectType) { - CComPtr pmp; - CComPtr dbc; - HRESULT hr; + /* As far as I can tell, the submenu hierarchy looks like this: + + The DeskBar's Child is the Band it contains. + The DeskBar's Parent is the SID_SMenuPopup of the Site. + + The Band's Child is the IMenuPopup of the child submenu. + The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar). + + When the DeskBar receives a selection event: + If it requires closing the window, it will notify the Child (Band) using CancelLevel. + If it has to spread upwards (everything but CancelLevel), it will notify the Parent. + + When the Band receives a selection event, this is where it gets fuzzy: + In which cases does it call the Parent? Probably not CancelLevel. + In which cases does it call the Child? + How does it react to calls? + + */ switch (dwSelectType) { case MPOS_EXECUTE: case MPOS_FULLCANCEL: case MPOS_CANCELLEVEL: - hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IMenuPopup, &pmp)); - if (FAILED(hr)) - return hr; - hr = pmp->OnSelect(MPOS_CANCELLEVEL); - if (FAILED(hr)) - return hr; - - hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc)); - if (FAILED(hr)) - return hr; - - hr = dbc->UIActivateDBC(FALSE); - if (FAILED(hr)) - return hr; - - SetWindowPos(m_hWnd, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - - UIActivateIO(FALSE, NULL); + _CloseBar(); if (dwSelectType == MPOS_CANCELLEVEL) - break; + return S_OK; case MPOS_SELECTLEFT: case MPOS_SELECTRIGHT: - /*CComPtr pmp; - hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IMenuPopup, &pmp)); - if (FAILED(hr)) - return hr;*/ - - hr = m_SubMenuParent->OnSelect(dwSelectType); - if (FAILED(hr)) - return hr; case MPOS_CHILDTRACKING: + if (m_SubMenuParent) + return m_SubMenuParent->OnSelect(dwSelectType); break; } return S_OK; } -HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu( - IMenuPopup *pmp, - BOOL fSet) +HRESULT CMenuDeskBar::_CloseBar() { + CComPtr dbc; + HRESULT hr; + + if (m_SubMenuChild) + { + hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL); + if (FAILED(hr)) + return hr; + } + + hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc)); + if (FAILED(hr)) + return hr; + + hr = dbc->UIActivateDBC(FALSE); + if (FAILED(hr)) + return hr; + + SetWindowPos(m_hWnd, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + + return UIActivateIO(FALSE, NULL); +} + +HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) +{ + // Called by the CHILD to notify the parent of the submenu object + if (fSet) { - m_SubMenuParent = pmp; + m_SubMenuChild = pmp; } else { - if (m_SubMenuParent) + if (m_SubMenuChild) { - if (SHIsSameObject(pmp, m_SubMenuParent)) + if (SHIsSameObject(pmp, m_SubMenuChild)) { - m_SubMenuParent = NULL; + m_SubMenuChild = NULL; } } } diff --git a/base/shell/rshell/logging/CMenuSiteWrap.cpp b/base/shell/rshell/logging/CMenuSiteWrap.cpp index 6f720cb0fcc..99dab9f172b 100644 --- a/base/shell/rshell/logging/CMenuSiteWrap.cpp +++ b/base/shell/rshell/logging/CMenuSiteWrap.cpp @@ -180,7 +180,7 @@ HRESULT STDMETHODCALLTYPE CMenuSiteWrap::EnumBands(UINT uBand, DWORD* pdwBandID) HRESULT STDMETHODCALLTYPE CMenuSiteWrap::QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName) { - WrapLogEnter("CMenuSiteWrap<%p>::QueryBand(DWORD dwBandID=%d, IDeskBand **ppstb=%p, DWORD *pdwState=%p, LPWSTR pszName=%p, int cchName=%p)\n", this, dwBandID, ppstb, pdwState, pszName, cchName); + WrapLogEnter("CMenuSiteWrap<%p>::QueryBand(DWORD dwBandID=%d, IDeskBand **ppstb=%p, DWORD *pdwState=%p, LPWSTR pszName=%p, int cchName=%d)\n", this, dwBandID, ppstb, pdwState, pszName, cchName); HRESULT hr = m_IBandSite->QueryBand(dwBandID, ppstb, pdwState, pszName, cchName); if (ppstb) WrapLogPost("*ppstb=%p\n", *ppstb); if (pdwState) WrapLogPost("*pdwState=%d\n", *pdwState); @@ -190,7 +190,7 @@ HRESULT STDMETHODCALLTYPE CMenuSiteWrap::QueryBand(DWORD dwBandID, IDeskBand **p HRESULT STDMETHODCALLTYPE CMenuSiteWrap::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv) { - WrapLogEnter("CMenuSiteWrap<%p>::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv)\n", this, dwBandID, riid, ppv); + WrapLogEnter("CMenuSiteWrap<%p>::GetBandObject(DWORD dwBandID=%d, REFIID riid=%s, VOID **ppv=%p)\n", this, dwBandID, Wrap(riid), ppv); HRESULT hr = m_IBandSite->GetBandObject(dwBandID, riid, ppv); if (ppv) WrapLogPost("*ppv=%p\n", *ppv); WrapLogExit("CMenuSiteWrap::GetBandObject()", hr); @@ -201,7 +201,7 @@ HRESULT STDMETHODCALLTYPE CMenuSiteWrap::GetBandSiteInfo(BANDSITEINFO *pbsinfo) { WrapLogEnter("CMenuSiteWrap<%p>::GetBandSiteInfo(BANDSITEINFO *pbsinfo=%p)\n", this, pbsinfo); HRESULT hr = m_IBandSite->GetBandSiteInfo(pbsinfo); - if (pbsinfo) WrapLogPost("*pbsinfo=%p\n", *pbsinfo); + if (pbsinfo) WrapLogPost("*pbsinfo=%s\n", Wrap(*pbsinfo)); WrapLogExit("CMenuSiteWrap::GetBandSiteInfo()", hr); return hr; } @@ -236,7 +236,6 @@ HRESULT STDMETHODCALLTYPE CMenuSiteWrap::SetDeskBarSite(IUnknown *punkSite) { WrapLogEnter("CMenuSiteWrap<%p>::SetDeskBarSite(IUnknown *punkSite=%p)\n", this, punkSite); HRESULT hr = m_IDeskBarClient->SetDeskBarSite(punkSite); - if (punkSite) WrapLogPost("*punkSite=%p\n", *punkSite); WrapLogExit("CMenuSiteWrap::SetDeskBarSite()", hr); return hr; }