From b42655951ce3ca5ee38238d5b8a07a806f69ffed Mon Sep 17 00:00:00 2001 From: David Quintana Date: Mon, 17 Feb 2014 18:38:31 +0000 Subject: [PATCH] [RSHELL] * CMenuBand: Begin implementing submenus for shell items. * CMenuBand: Begin implementing context menus. CORE-7881 svn path=/branches/shell-experiments/; revision=62232 --- base/shell/rshell/CMenuBand.cpp | 231 ++++++++++++++++++++++++++++--- base/shell/rshell/CStartMenu.cpp | 2 +- 2 files changed, 213 insertions(+), 20 deletions(-) diff --git a/base/shell/rshell/CMenuBand.cpp b/base/shell/rshell/CMenuBand.cpp index 6d5930f705e..e5046beeda2 100644 --- a/base/shell/rshell/CMenuBand.cpp +++ b/base/shell/rshell/CMenuBand.cpp @@ -51,10 +51,11 @@ public: virtual HRESULT PopupItem(UINT uItem) = 0; virtual HRESULT HasSubMenu(UINT uItem) = 0; virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) = 0; + virtual HRESULT OnContextMenu(NMMOUSE * rclick) = 0; HRESULT OnHotItemChange(const NMTBHOTITEM * hot); - HRESULT PopupSubMenu(UINT uItem, IShellMenu* childShellMenu); + HRESULT PopupSubMenu(UINT index, IShellMenu* childShellMenu); static LRESULT CALLBACK s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); protected: @@ -83,6 +84,8 @@ public: virtual HRESULT PopupItem(UINT uItem); virtual HRESULT HasSubMenu(UINT uItem); virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT OnContextMenu(NMMOUSE * rclick); + private: HMENU m_hmenu; }; @@ -100,9 +103,10 @@ public: virtual HRESULT PopupItem(UINT uItem); virtual HRESULT HasSubMenu(UINT uItem); virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); - + virtual HRESULT OnContextMenu(NMMOUSE * rclick); private: + LPITEMIDLIST GetPidlFromId(UINT uItem, INT* pIndex); IShellFolder * m_shellFolder; LPCITEMIDLIST m_idList; @@ -248,6 +252,7 @@ public: virtual HRESULT STDMETHODCALLTYPE IsEmpty(THIS); HRESULT CallCBWithId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam); + HRESULT CallCBWithPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL UseBigIcons() { return m_useBigIcons; @@ -957,15 +962,14 @@ HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot) return S_OK; } -HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, IShellMenu* childShellMenu) +HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, IShellMenu* childShellMenu) { + IBandSite* pBandSite; + IDeskBar* pDeskBar; + + HRESULT hr; + RECT rc; - TBBUTTONINFO info = { 0 }; - info.cbSize = sizeof(TBBUTTONINFO); - info.dwMask = 0; - int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, (LPARAM) &info); - if (index < 0) - return E_FAIL; if (!SendMessage(m_hwnd, TB_GETITEMRECT, index, (LPARAM) &rc)) return E_FAIL; @@ -978,10 +982,6 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, IShellMenu* childShellMenu) POINTL pt = { b.x, b.y }; RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar? - IBandSite* pBandSite; - IDeskBar* pDeskBar; - - HRESULT hr; #ifndef USE_BUILTIN_MENUSITE hr = CoCreateInstance(CLSID_MenuBandSite, @@ -1119,6 +1119,56 @@ HRESULT CMenuStaticToolbar::FillToolbar() return S_OK; } +HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick) +{ + CComPtr contextMenu; + HRESULT hr = m_menuBand->CallCBWithId(rclick->dwItemSpec, SMC_GETOBJECT, (WPARAM) &IID_IContextMenu, (LPARAM) &contextMenu); + if (hr != S_OK) + return hr; + + HMENU hPopup = CreatePopupMenu(); + + if (hPopup == NULL) + return E_FAIL; + + int ID_SHELL_CMD_FIRST = 0xF; + int ID_SHELL_CMD_LAST = 0x7fef; + hr = contextMenu->QueryContextMenu(hPopup, 0, ID_SHELL_CMD_FIRST, ID_SHELL_CMD_LAST, CMF_VERBSONLY); + if (FAILED(hr)) + { + DestroyMenu(hPopup); + return hr; + } + + POINT pt = rclick->pt; + if (!ClientToScreen(m_hwnd, &pt)) + { + DestroyMenu(hPopup); + return HRESULT_FROM_WIN32(GetLastError()); + } + + CComPtr site; + hr = m_menuBand->GetSite(IID_PPV_ARG(IOleWindow, &site)); + if (FAILED(hr)) + { + DestroyMenu(hPopup); + return hr; + } + + HWND hwndSite; + hr = site->GetWindow(&hwndSite); + if (FAILED(hr)) + { + DestroyMenu(hPopup); + return hr; + } + + ::TrackPopupMenu(hPopup, 0, pt.x, pt.y, 0, hwndSite, NULL); + + DestroyMenu(hPopup); + return S_OK; +} + HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) { return m_menuBand->CallCBWithId(wParam, SMC_EXEC, 0, 0); @@ -1131,7 +1181,14 @@ HRESULT CMenuStaticToolbar::PopupItem(UINT uItem) if (FAILED(hr)) return hr; - return PopupSubMenu(uItem, shellMenu); + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, (LPARAM) &info); + if (index < 0) + return E_FAIL; + + return PopupSubMenu(index, shellMenu); } HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem) @@ -1175,7 +1232,7 @@ HRESULT CMenuSFToolbar::FillToolbar() INT index = 0; INT indexOpen = 0; - IShellItem *psi; + CComPtr psi; SHCreateShellItem(NULL, m_shellFolder, item, &psi); hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString); @@ -1184,9 +1241,18 @@ HRESULT CMenuSFToolbar::FillToolbar() index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen); + SFGAOF attrs; + hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); + + if (attrs != 0) + { + tbb.fsStyle |= BTNS_WHOLEDROPDOWN; + } + tbb.idCommand = i++; tbb.iString = (INT_PTR) MenuString; tbb.iBitmap = index; + tbb.dwData = (DWORD_PTR) ILClone(item); SendMessageW(m_hwnd, TB_ADDBUTTONS, 1, (LPARAM) (LPTBBUTTON) &tbb); HeapFree(GetProcessHeap(), 0, MenuString); @@ -1236,20 +1302,104 @@ HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REF return hr; } -HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) + +LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex) +{ + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + int index = SendMessage(m_hwnd, TB_GETBUTTONINFO, uItem, (LPARAM) &info); + if (index < 0) + return NULL; + + if (pIndex) + *pIndex = index; + + TBBUTTON btn = { 0 }; + if (!SendMessage(m_hwnd, TB_GETBUTTON, index, (LPARAM) &btn)) + return NULL; + + return (LPITEMIDLIST)btn.dwData; +} + +HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick) { - // TODO: return m_menuBand->CallCBWithPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0); + HRESULT hr; + CComPtr site; + CComPtr contextMenu; + + hr = m_menuBand->GetSite(IID_PPV_ARG(IOleWindow, &site)); + if (FAILED(hr)) + { + return hr; + } + + HWND hwndSite; + hr = site->GetWindow(&hwndSite); + if (FAILED(hr)) + { + return hr; + } + + LPITEMIDLIST pidl = GetPidlFromId(rclick->dwItemData, NULL); + + hr = m_shellFolder->GetUIObjectOf(hwndSite, 1, (LPCITEMIDLIST *) &pidl, IID_IContextMenu, NULL, (PVOID *) &contextMenu); + if (hr != S_OK) + return hr; + + HMENU hPopup = CreatePopupMenu(); + + if (hPopup == NULL) + return E_FAIL; + + int ID_SHELL_CMD_FIRST = 0xF; + int ID_SHELL_CMD_LAST = 0x7fef; + hr = contextMenu->QueryContextMenu(hPopup, 0, ID_SHELL_CMD_FIRST, ID_SHELL_CMD_LAST, CMF_VERBSONLY); + if (FAILED(hr)) + { + DestroyMenu(hPopup); + return hr; + } + + POINT pt = rclick->pt; + if (!ClientToScreen(m_hwnd, &pt)) + { + DestroyMenu(hPopup); + return HRESULT_FROM_WIN32(GetLastError()); + } + + ::TrackPopupMenu(hPopup, 0, pt.x, pt.y, 0, hwndSite, NULL); + + DestroyMenu(hPopup); return S_OK; } +HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ + return m_menuBand->CallCBWithPidl(GetPidlFromId(wParam, NULL), SMC_SFEXEC, 0, 0); +} + HRESULT CMenuSFToolbar::PopupItem(UINT uItem) { - return S_OK; + int index; + CComPtr shellMenu; + HRESULT hr = m_menuBand->CallCBWithPidl(GetPidlFromId(uItem, &index), SMC_GETOBJECT, (WPARAM) &IID_IShellMenu, (LPARAM) &shellMenu); + if (FAILED(hr)) + return hr; + + return PopupSubMenu(index, shellMenu); } HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem) { - return S_FALSE; // GetSubMenu(m_hmenu, uItem) ? S_OK : S_FALSE; + HRESULT hr; + CComPtr psi; + SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem, NULL), &psi); + + SFGAOF attrs; + hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); + + return (attrs != 0) ? S_OK : S_FALSE; } CMenuBand::CMenuBand() : @@ -1811,6 +1961,7 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wPa NMHDR * hdr = (LPNMHDR) lParam; NMTBCUSTOMDRAW * cdraw; NMTBHOTITEM * hot; + NMMOUSE * rclick; switch (hdr->code) { case TBN_HOTITEMCHANGE: @@ -1828,6 +1979,20 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wPa return S_OK; + case NM_RCLICK: + rclick = (LPNMMOUSE) hdr; + + if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd)) + { + return m_staticToolbar->OnContextMenu(rclick); + } + + if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd)) + { + return m_SFToolbar->OnContextMenu(rclick); + } + + return S_OK; case NM_CUSTOMDRAW: cdraw = (LPNMTBCUSTOMDRAW) hdr; switch (cdraw->nmcd.dwDrawStage) @@ -1984,6 +2149,34 @@ HRESULT CMenuBand::CallCBWithId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam return hr; } +HRESULT CMenuBand::CallCBWithPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!m_psmc) + return S_FALSE; + + HWND hwnd; + GetWindow(&hwnd); + + SMDATA smData = { 0 }; + smData.punk = (IShellMenu2*)this; + smData.uIdParent = m_uId; + smData.uIdAncestor = m_uIdAncestor; + smData.hwnd = hwnd; + smData.pidlItem = pidl; + if (m_staticToolbar) + { + smData.hmenu = m_hmenu; + } + smData.pvUserData = NULL; + if (m_SFToolbar) + m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf)); + HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam); + ILFree(smData.pidlFolder); + if (smData.psf) + smData.psf->Release(); + return hr; +} + HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam) { if (!m_psmc) diff --git a/base/shell/rshell/CStartMenu.cpp b/base/shell/rshell/CStartMenu.cpp index 6c319f90fb5..6e51e10b6fc 100644 --- a/base/shell/rshell/CStartMenu.cpp +++ b/base/shell/rshell/CStartMenu.cpp @@ -20,7 +20,7 @@ #include "precomp.h" -/* NOTE: The following constants may *NOT* be changed because +/* NOTE: The following constants *MUST NOT* be changed because they're hardcoded and need to be the exact values in order to get the start menu to work! */ #define IDM_PROGRAMS 504 -- 2.17.1