From b62a6757ee84a5182092b82eb1bc640fdb5f4bc5 Mon Sep 17 00:00:00 2001 From: David Quintana Date: Mon, 24 Feb 2014 11:59:34 +0000 Subject: [PATCH] [RSHELL] * Move some classes to separate files. * Move class declarations to .h files. CORE-7586 svn path=/branches/shell-experiments/; revision=62319 --- base/shell/rshell/CMakeLists.txt | 2 + base/shell/rshell/CMenuBand.cpp | 1416 +---------------------- base/shell/rshell/CMenuBand.h | 191 +++ base/shell/rshell/CMenuDeskBar.cpp | 159 +-- base/shell/rshell/CMenuDeskBar.h | 135 +++ base/shell/rshell/CMenuFocusManager.cpp | 252 ++++ base/shell/rshell/CMenuFocusManager.h | 75 ++ base/shell/rshell/CMenuSite.cpp | 89 +- base/shell/rshell/CMenuSite.h | 106 ++ base/shell/rshell/CMenuToolbars.cpp | 895 ++++++++++++++ base/shell/rshell/CMenuToolbars.h | 119 ++ 11 files changed, 1818 insertions(+), 1621 deletions(-) create mode 100644 base/shell/rshell/CMenuBand.h create mode 100644 base/shell/rshell/CMenuDeskBar.h create mode 100644 base/shell/rshell/CMenuFocusManager.cpp create mode 100644 base/shell/rshell/CMenuFocusManager.h create mode 100644 base/shell/rshell/CMenuSite.h create mode 100644 base/shell/rshell/CMenuToolbars.cpp create mode 100644 base/shell/rshell/CMenuToolbars.h diff --git a/base/shell/rshell/CMakeLists.txt b/base/shell/rshell/CMakeLists.txt index f224d88409d..7bb3eaa9139 100644 --- a/base/shell/rshell/CMakeLists.txt +++ b/base/shell/rshell/CMakeLists.txt @@ -10,7 +10,9 @@ list(APPEND SOURCE CDesktopBrowser.cpp CMenuBand.cpp CMenuDeskBar.cpp + CMenuFocusManager.cpp CMenuSite.cpp + CMenuToolbars.cpp CStartMenu.cpp misc.cpp wraplog.cpp diff --git a/base/shell/rshell/CMenuBand.cpp b/base/shell/rshell/CMenuBand.cpp index fe996ef96e0..f316aa85869 100644 --- a/base/shell/rshell/CMenuBand.cpp +++ b/base/shell/rshell/CMenuBand.cpp @@ -1,563 +1,33 @@ /* -* Shell Menu Band -* -* Copyright 2014 David Quintana -* -* 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 St, Fifth Floor, Boston, MA 02110-1301, USA -*/ + * Shell Menu Band + * + * Copyright 2014 David Quintana + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ #include "precomp.h" #include #include #include -extern "C" -HRESULT WINAPI SHGetImageList( - _In_ int iImageList, - _In_ REFIID riid, - _Out_ void **ppv - ); - - -#define TBSTYLE_EX_VERTICAL 4 +#include "CMenuBand.h" +#include "CMenuToolbars.h" +#include "CMenuFocusManager.h" WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand); -#define TIMERID_HOTTRACK 1 -#define SUBCLASS_ID_MENUBAND 1 - -extern "C" BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList); - -class CMenuBand; -class CMenuFocusManager; - -class CMenuToolbarBase -{ -private: - HWND m_hwnd; // May be the pager - -protected: - CMenuBand * m_menuBand; - HWND m_hwndToolbar; - DWORD m_dwMenuFlags; - INT m_hotItem; - WNDPROC m_SubclassOld; - BOOL m_hasIdealSize; - SIZE m_idealSize; - BOOL m_usePager; - -private: - static LRESULT CALLBACK s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -public: - CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager); - virtual ~CMenuToolbarBase() {} - - HRESULT IsWindowOwner(HWND hwnd); - HRESULT CreateToolbar(HWND hwndParent, DWORD dwFlags); - HRESULT GetWindow(HWND *phwnd); - HRESULT ShowWindow(BOOL fShow); - HRESULT Close(); - - virtual HRESULT FillToolbar() = 0; - virtual HRESULT PopupItem(UINT uItem) = 0; - virtual HRESULT HasSubMenu(UINT uItem) = 0; - virtual HRESULT OnContextMenu(NMMOUSE * rclick) = 0; - virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); - - HRESULT PopupSubMenu(UINT itemId, UINT index, IShellMenu* childShellMenu); - HRESULT PopupSubMenu(UINT index, HMENU menu); - HRESULT DoContextMenu(IContextMenu* contextMenu); - - HRESULT ChangeHotItem(DWORD changeType); - HRESULT OnHotItemChange(const NMTBHOTITEM * hot); - - HRESULT GetIdealSize(SIZE& size); - HRESULT SetPosSize(int x, int y, int cx, int cy); - - void InvalidateDraw(); - -protected: - LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -}; - -class CMenuStaticToolbar : - public CMenuToolbarBase -{ -private: - HMENU m_hmenu; - -public: - CMenuStaticToolbar(CMenuBand *menuBand); - virtual ~CMenuStaticToolbar() {} - - HRESULT SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags); - HRESULT GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags); - - virtual HRESULT FillToolbar(); - virtual HRESULT PopupItem(UINT uItem); - virtual HRESULT HasSubMenu(UINT uItem); - virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); - virtual HRESULT OnContextMenu(NMMOUSE * rclick); - -}; - -class CMenuSFToolbar : - public CMenuToolbarBase -{ -private: - IShellFolder * m_shellFolder; - LPCITEMIDLIST m_idList; - HKEY m_hKey; - -public: - CMenuSFToolbar(CMenuBand *menuBand); - virtual ~CMenuSFToolbar(); - - HRESULT SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags); - HRESULT GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv); - - virtual HRESULT FillToolbar(); - 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 = NULL); -}; - -class CMenuBand : - public CComCoClass, - public CComObjectRootEx, - public IDeskBand, - public IObjectWithSite, - public IInputObject, - public IPersistStream, - public IOleCommandTarget, - public IServiceProvider, - public IMenuPopup, - public IMenuBand, - public IShellMenu2, - public IWinEventHandler, - public IShellMenuAcc -{ -private: - CMenuFocusManager * m_focusManager; - CMenuStaticToolbar * m_staticToolbar; - CMenuSFToolbar * m_SFToolbar; - - CComPtr m_site; - CComPtr m_psmc; - CComPtr m_subMenuChild; - CComPtr m_subMenuParent; - - UINT m_uId; - UINT m_uIdAncestor; - DWORD m_dwFlags; - PVOID m_UserData; - HMENU m_hmenu; - HWND m_menuOwner; - - BOOL m_useBigIcons; - HWND m_topLevelWindow; - - CMenuToolbarBase * m_hotBar; - INT m_hotItem; - INT m_popupItem; - - HFONT m_marlett; - -public: - CMenuBand(); - ~CMenuBand(); - - DECLARE_NOT_AGGREGATABLE(CMenuBand) - DECLARE_PROTECT_FINAL_CONSTRUCT() - - BEGIN_COM_MAP(CMenuBand) - COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup) - COM_INTERFACE_ENTRY_IID(IID_IShellMenu, IShellMenu) - COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) - COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IDeskBand) - COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow) - COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) - COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) - COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) - COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream) - COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersistStream) - COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) - COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup) - COM_INTERFACE_ENTRY_IID(IID_IMenuBand, IMenuBand) - COM_INTERFACE_ENTRY_IID(IID_IShellMenu2, IShellMenu2) - COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) - COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc, IShellMenuAcc) - END_COM_MAP() - - // *** IDeskBand methods *** - virtual HRESULT STDMETHODCALLTYPE GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi); - - // *** IDockingWindow methods *** - virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow); - virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved); - virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved); - - // *** IOleWindow methods *** - virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); - virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); - - // *** IObjectWithSite methods *** - virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); - virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite); - - // *** IInputObject methods *** - virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); - virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); - virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); - - // *** IPersistStream methods *** - virtual HRESULT STDMETHODCALLTYPE IsDirty(); - virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm); - virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty); - virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize); - - // *** IPersist methods *** - virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); - - // *** IOleCommandTarget methods *** - virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); - virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); - - // *** IServiceProvider methods *** - virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); - - // *** IMenuPopup methods *** - virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags); - virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType); - virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet); - - // *** IDeskBar methods *** - virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient); - virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient); - virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc); - - // *** IMenuBand methods *** - virtual HRESULT STDMETHODCALLTYPE IsMenuMessage(MSG *pmsg); - virtual HRESULT STDMETHODCALLTYPE TranslateMenuMessage(MSG *pmsg, LRESULT *plRet); - - // *** IShellMenu methods *** - virtual HRESULT STDMETHODCALLTYPE Initialize(IShellMenuCallback *psmc, UINT uId, UINT uIdAncestor, DWORD dwFlags); - virtual HRESULT STDMETHODCALLTYPE GetMenuInfo(IShellMenuCallback **ppsmc, UINT *puId, UINT *puIdAncestor, DWORD *pdwFlags); - virtual HRESULT STDMETHODCALLTYPE SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags); - virtual HRESULT STDMETHODCALLTYPE GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv); - virtual HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags); - virtual HRESULT STDMETHODCALLTYPE GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags); - virtual HRESULT STDMETHODCALLTYPE InvalidateItem(LPSMDATA psmd, DWORD dwFlags); - virtual HRESULT STDMETHODCALLTYPE GetState(LPSMDATA psmd); - virtual HRESULT STDMETHODCALLTYPE SetMenuToolbar(IUnknown *punk, DWORD dwFlags); - - // *** IWinEventHandler methods *** - virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult); - virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd); - - // *** IShellMenu2 methods *** - virtual HRESULT STDMETHODCALLTYPE GetSubMenu(THIS); - virtual HRESULT STDMETHODCALLTYPE SetToolbar(THIS); - virtual HRESULT STDMETHODCALLTYPE SetMinWidth(THIS); - virtual HRESULT STDMETHODCALLTYPE SetNoBorder(THIS); - virtual HRESULT STDMETHODCALLTYPE SetTheme(THIS); - - // *** IShellMenuAcc methods *** - virtual HRESULT STDMETHODCALLTYPE GetTop(THIS); - virtual HRESULT STDMETHODCALLTYPE GetBottom(THIS); - virtual HRESULT STDMETHODCALLTYPE GetTracked(THIS); - virtual HRESULT STDMETHODCALLTYPE GetParentSite(THIS); - virtual HRESULT STDMETHODCALLTYPE GetState(THIS); - virtual HRESULT STDMETHODCALLTYPE DoDefaultAction(THIS); - virtual HRESULT STDMETHODCALLTYPE IsEmpty(THIS); - - HRESULT _CallCBWithItemId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam); - HRESULT _CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam); - HRESULT _TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y); - HRESULT _GetTopLevelWindow(HWND*topLevel); - HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id); - HRESULT _MenuItemHotTrack(DWORD changeType); - HRESULT _OnPopupSubMenu(INT popupItem, IMenuPopup * popup, POINTL * pAt, RECTL * pExclude); - - BOOL UseBigIcons() - { - return m_useBigIcons; - } - -private: - HRESULT _CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id = 0, LPITEMIDLIST pidl = NULL); -}; - -class CMenuFocusManager : - public CComCoClass, - public CComObjectRootEx -{ -private: - static DWORD TlsIndex; - - static CMenuFocusManager * GetManager() - { - return reinterpret_cast(TlsGetValue(TlsIndex)); - } - -public: - static CMenuFocusManager * AcquireManager() - { - CMenuFocusManager * obj = NULL; - - if (!TlsIndex) - { - if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) - return NULL; - } - - obj = GetManager(); - - if (!obj) - { - obj = new CComObject(); - TlsSetValue(TlsIndex, obj); - } - - obj->AddRef(); - - return obj; - } - - static void ReleaseManager(CMenuFocusManager * obj) - { - if (!obj->Release()) - { - TlsSetValue(TlsIndex, NULL); - } - } - -private: - static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) - { - return GetManager()->GetMsgHook(nCode, wParam, lParam); - } - -private: - CMenuBand * m_currentBand; - HWND m_currentFocus; - HHOOK m_hHook; - DWORD m_threadId; - - // TODO: make dynamic -#define MAX_RECURSE 20 - CMenuBand* m_bandStack[MAX_RECURSE]; - int m_bandCount; - - HRESULT PushToArray(CMenuBand * item) - { - if (m_bandCount >= MAX_RECURSE) - return E_OUTOFMEMORY; - - m_bandStack[m_bandCount++] = item; - return S_OK; - } - - HRESULT PopFromArray(CMenuBand ** pItem) - { - if (pItem) - *pItem = NULL; - - if (m_bandCount <= 0) - return E_FAIL; - - m_bandCount--; - - if (pItem) - *pItem = m_bandStack[m_bandCount]; - - m_bandStack[m_bandCount] = NULL; - - return S_OK; - } - - HRESULT PeekArray(CMenuBand ** pItem) - { - if (!pItem) - return E_FAIL; - - *pItem = NULL; - - if (m_bandCount <= 0) - return E_FAIL; - - *pItem = m_bandStack[m_bandCount - 1]; - - return S_OK; - } - -protected: - CMenuFocusManager() : - m_currentBand(NULL), - m_currentFocus(NULL), - m_bandCount(0) - { - m_threadId = GetCurrentThreadId(); - } - - ~CMenuFocusManager() - { - } - -public: - - DECLARE_NOT_AGGREGATABLE(CMenuFocusManager) - DECLARE_PROTECT_FINAL_CONSTRUCT() - BEGIN_COM_MAP(CMenuFocusManager) - END_COM_MAP() - - LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) - { - if (nCode < 0) - return CallNextHookEx(m_hHook, nCode, wParam, lParam); - - if (nCode == HC_ACTION) - { - BOOL callNext = TRUE; - MSG* msg = reinterpret_cast(lParam); - - // Do whatever is necessary here - - switch (msg->message) - { - case WM_CLOSE: - break; - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - switch (msg->wParam) - { - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL); - break; - case VK_LEFT: - m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT); - break; - case VK_RIGHT: - m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT); - break; - case VK_UP: - m_currentBand->_MenuItemHotTrack(VK_UP); - break; - case VK_DOWN: - m_currentBand->_MenuItemHotTrack(VK_DOWN); - break; - } - break; - case WM_CHAR: - //if (msg->wParam >= 'a' && msg->wParam <= 'z') - //{ - // callNext = FALSE; - // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam); - //} - break; - } - - if (!callNext) - return 0; - } - - return CallNextHookEx(m_hHook, nCode, wParam, lParam); - } - - HRESULT PlaceHooks(HWND window) - { - //SetCapture(window); - m_hHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId); - return S_OK; - } - - HRESULT RemoveHooks(HWND window) - { - UnhookWindowsHookEx(m_hHook); - //ReleaseCapture(); - return S_OK; - } - - HRESULT UpdateFocus(CMenuBand * newBand) - { - HRESULT hr; - HWND newFocus; - - if (newBand == NULL) - { - hr = RemoveHooks(m_currentFocus); - m_currentFocus = NULL; - m_currentBand = NULL; - return S_OK; - } - - hr = newBand->_GetTopLevelWindow(&newFocus); - if (FAILED(hr)) - return hr; - - if (!m_currentBand) - { - hr = PlaceHooks(newFocus); - if (FAILED(hr)) - return hr; - } - - m_currentFocus = newFocus; - m_currentBand = newBand; - - return S_OK; - } - -public: - HRESULT PushMenu(CMenuBand * mb) - { - HRESULT hr; - - hr = PushToArray(mb); - if (FAILED(hr)) - return hr; - - return UpdateFocus(mb); - } - - HRESULT PopMenu(CMenuBand * mb) - { - CMenuBand * mbc; - HRESULT hr; - - hr = PopFromArray(&mbc); - if (FAILED(hr)) - return hr; - - if (mb != mbc) - return E_FAIL; - - hr = PeekArray(&mbc); - - return UpdateFocus(mbc); - } -}; - -DWORD CMenuFocusManager::TlsIndex = 0; - extern "C" HRESULT CMenuBand_Constructor(REFIID riid, LPVOID *ppv) { @@ -576,850 +46,6 @@ HRESULT CMenuBand_Constructor(REFIID riid, LPVOID *ppv) return hr; } -CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) : - m_hwnd(NULL), - m_menuBand(menuBand), - m_hwndToolbar(NULL), - m_dwMenuFlags(0), - m_hasIdealSize(FALSE) -{ -} - -HRESULT CMenuToolbarBase::IsWindowOwner(HWND hwnd) -{ - return (m_hwnd && m_hwnd == hwnd) || - (m_hwndToolbar && m_hwndToolbar == hwnd) ? S_OK : S_FALSE; -} - -void CMenuToolbarBase::InvalidateDraw() -{ - InvalidateRect(m_hwnd, NULL, FALSE); -} - -HRESULT CMenuToolbarBase::ShowWindow(BOOL fShow) -{ - ::ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE); - - HIMAGELIST ilBig, ilSmall; - Shell_GetImageLists(&ilBig, &ilSmall); - - if (m_menuBand->UseBigIcons()) - { - SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast(ilBig)); - } - else - { - SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast(ilSmall)); - } - - return S_OK; -} - -HRESULT CMenuToolbarBase::Close() -{ - DestroyWindow(m_hwndToolbar); - if (m_hwndToolbar != m_hwnd) - DestroyWindow(m_hwnd); - m_hwndToolbar = NULL; - m_hwnd = NULL; - return S_OK; -} - -HRESULT CMenuToolbarBase::CreateToolbar(HWND hwndParent, DWORD dwFlags) -{ - LONG tbStyles = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | - TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE | - CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP; - LONG tbExStyles = TBSTYLE_EX_DOUBLEBUFFER; - - if (dwFlags & SMINIT_VERTICAL) - { - tbStyles |= CCS_VERT; - tbExStyles |= TBSTYLE_EX_VERTICAL | WS_EX_TOOLWINDOW; - } - - RECT rc; - - if (!::GetClientRect(hwndParent, &rc) || (rc.left == rc.right) || (rc.top == rc.bottom)) - { - rc.left = 0; - rc.top = 0; - rc.right = 1; - rc.bottom = 1; - } - - HWND hwndToolbar = CreateWindowEx( - tbExStyles, TOOLBARCLASSNAMEW, NULL, - tbStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, - hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0); - - if (hwndToolbar == NULL) - return E_FAIL; - - if (m_usePager) - { - LONG pgStyles = PGS_VERT | WS_CHILD | WS_VISIBLE; - LONG pgExStyles = 0; - - HWND hwndPager = CreateWindowEx( - pgExStyles, WC_PAGESCROLLER, NULL, - pgStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, - hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0); - - ::SetParent(hwndToolbar, hwndPager); - ::SetParent(hwndPager, hwndParent); - - SendMessage(hwndPager, PGM_SETCHILD, 0, reinterpret_cast(hwndToolbar)); - m_hwndToolbar = hwndToolbar; - m_hwnd = hwndPager; - } - else - { - ::SetParent(hwndToolbar, hwndParent); - m_hwndToolbar = hwndToolbar; - m_hwnd = hwndToolbar; - } - - /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */ - SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); - - //if (dwFlags & SMINIT_TOPLEVEL) - //{ - // /* Hide the placeholders for the button images */ - // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0); - //} - //else - int shiml; - if (m_menuBand->UseBigIcons()) - { - shiml = SHIL_LARGE; - SendMessageW(hwndToolbar, TB_SETPADDING, 0, MAKELPARAM(0, 0)); - } - else - { - shiml = SHIL_SMALL; - } - - IImageList * piml; - HRESULT hr = SHGetImageList(shiml, IID_PPV_ARG(IImageList, &piml)); - if (SUCCEEDED(hr)) - { - SendMessageW(hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast(piml)); - } - else - { - SendMessageW(hwndToolbar, TB_SETIMAGELIST, 0, 0); - } - - SetWindowLongPtr(hwndToolbar, GWLP_USERDATA, reinterpret_cast(this)); - m_SubclassOld = (WNDPROC) SetWindowLongPtr(hwndToolbar, GWLP_WNDPROC, reinterpret_cast(CMenuToolbarBase::s_SubclassProc)); - - return S_OK; -} - -HRESULT CMenuToolbarBase::GetIdealSize(SIZE& size) -{ - size.cx = size.cy = 0; - - if (m_hwndToolbar && !m_hasIdealSize) - { - SendMessageW(m_hwndToolbar, TB_AUTOSIZE, 0, 0); - SendMessageW(m_hwndToolbar, TB_GETMAXSIZE, 0, reinterpret_cast(&m_idealSize)); - m_hasIdealSize = TRUE; - } - - size = m_idealSize; - - return S_OK; -} - -HRESULT CMenuToolbarBase::SetPosSize(int x, int y, int cx, int cy) -{ - if (m_hwnd != m_hwndToolbar) - { - SetWindowPos(m_hwndToolbar, NULL, x, y, cx, m_idealSize.cy, 0); - } - SetWindowPos(m_hwnd, NULL, x, y, cx, cy, 0); - DWORD btnSize = SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0); - SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, HIWORD(btnSize))); - return S_OK; -} - -HRESULT CMenuToolbarBase::GetWindow(HWND *phwnd) -{ - if (!phwnd) - return E_FAIL; - - *phwnd = m_hwnd; - - return S_OK; -} - -LRESULT CALLBACK CMenuToolbarBase::s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - CMenuToolbarBase * pthis = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - return pthis->SubclassProc(hWnd, uMsg, wParam, lParam); -} - -LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_TIMER: - if (wParam == TIMERID_HOTTRACK) - { - KillTimer(hWnd, TIMERID_HOTTRACK); - - m_menuBand->_OnPopupSubMenu(-1, NULL, NULL, NULL); - - if (HasSubMenu(m_hotItem) == S_OK) - { - PopupItem(m_hotItem); - } - } - } - - return m_SubclassOld(hWnd, uMsg, wParam, lParam); -} - -HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot) -{ - if (hot->dwFlags & HICF_LEAVING) - { - KillTimer(m_hwndToolbar, TIMERID_HOTTRACK); - m_hotItem = -1; - m_menuBand->_OnHotItemChanged(NULL, -1); - m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); - } - else if (m_hotItem != hot->idNew) - { - DWORD elapsed = 0; - SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0); - SetTimer(m_hwndToolbar, TIMERID_HOTTRACK, elapsed, NULL); - - m_hotItem = hot->idNew; - m_menuBand->_OnHotItemChanged(this, m_hotItem); - m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); - } - return S_OK; -} - -HRESULT CMenuToolbarBase::PopupSubMenu(UINT itemId, UINT index, IShellMenu* childShellMenu) -{ - IBandSite* pBandSite; - IDeskBar* pDeskBar; - - HRESULT hr = 0; - RECT rc = { 0 }; - - if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast(&rc))) - return E_FAIL; - - POINT a = { rc.left, rc.top }; - POINT b = { rc.right, rc.bottom }; - - ClientToScreen(m_hwndToolbar, &a); - ClientToScreen(m_hwndToolbar, &b); - - POINTL pt = { b.x, a.y }; - RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar? - - -#if USE_SYSTEM_MENUSITE - hr = CoCreateInstance(CLSID_MenuBandSite, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARG(IBandSite, &pBandSite)); -#else - hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite)); -#endif - if (FAILED(hr)) - return hr; -#if WRAP_MENUSITE - hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite)); - if (FAILED(hr)) - return hr; -#endif - -#if USE_SYSTEM_MENUDESKBAR - hr = CoCreateInstance(CLSID_MenuDeskBar, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARG(IDeskBar, &pDeskBar)); -#else - hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar)); -#endif - if (FAILED(hr)) - return hr; -#if WRAP_MENUDESKBAR - hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar)); - if (FAILED(hr)) - return hr; -#endif - - hr = pDeskBar->SetClient(pBandSite); - if (FAILED(hr)) - return hr; - - hr = pBandSite->AddBand(childShellMenu); - if (FAILED(hr)) - return hr; - - CComPtr popup; - hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup)); - if (FAILED(hr)) - return hr; - - m_menuBand->_OnPopupSubMenu(itemId, popup, &pt, &rcl); - - return S_OK; -} - -HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, HMENU menu) -{ - RECT rc = { 0 }; - - if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast(&rc))) - return E_FAIL; - - POINT b = { rc.right, rc.bottom }; - - ClientToScreen(m_hwndToolbar, &b); - - HMENU popup = GetSubMenu(menu, index); - - m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, b.x, b.y); - - return S_OK; -} - -HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu) -{ - HRESULT hr; - HMENU hPopup = CreatePopupMenu(); - - if (hPopup == NULL) - return E_FAIL; - - hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL); - if (FAILED(hr)) - { - DestroyMenu(hPopup); - return hr; - } - - DWORD dwPos = GetMessagePos(); - UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL); - if (uCommand == 0) - return S_FALSE; - - CMINVOKECOMMANDINFO cmi = { 0 }; - cmi.cbSize = sizeof(cmi); - cmi.lpVerb = MAKEINTRESOURCEA(uCommand); - cmi.hwnd = m_hwnd; - hr = contextMenu->InvokeCommand(&cmi); - - DestroyMenu(hPopup); - return hr; -} - -HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) -{ - theResult = 0; - if (HasSubMenu(wParam) == S_OK) - { - KillTimer(m_hwndToolbar, TIMERID_HOTTRACK); - PopupItem(wParam); - return S_FALSE; - } - return m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE); -} - -HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType) -{ - int prev = m_hotItem; - int index = -1; - - if (dwSelectType != 0xFFFFFFFF) - { - int count = SendMessage(m_hwndToolbar, TB_BUTTONCOUNT, 0, 0); - - if (m_hotItem >= 0) - { - TBBUTTONINFO info = { 0 }; - info.cbSize = sizeof(TBBUTTONINFO); - info.dwMask = 0; - index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast(&info)); - } - - if (dwSelectType == VK_HOME) - { - index = 0; - dwSelectType = VK_DOWN; - } - else if (dwSelectType == VK_END) - { - index = count - 1; - dwSelectType = VK_UP; - } - else if (index < 0) - { - if (dwSelectType == VK_UP) - { - index = count - 1; - } - else if (dwSelectType == VK_DOWN) - { - index = 0; - } - } - else - { - if (dwSelectType == VK_UP) - { - index--; - } - else if (dwSelectType == VK_DOWN) - { - index++; - } - } - - TBBUTTON btn = { 0 }; - while (index >= 0 && index < count) - { - DWORD res = SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn)); - if (!res) - return E_FAIL; - - if (btn.dwData) - { - m_hotItem = btn.idCommand; - if (prev != m_hotItem) - { - SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0); - return m_menuBand->_OnHotItemChanged(this, m_hotItem); - } - return S_OK; - } - - if (dwSelectType == VK_UP) - { - index--; - } - else if (dwSelectType == VK_DOWN) - { - index++; - } - } - } - - m_hotItem = -1; - if (prev != m_hotItem) - { - SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0); - m_menuBand->_OnHotItemChanged(NULL, -1); - } - return S_FALSE; -} - -BOOL -AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String) -{ - int Length; - - Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION); - - if (!Length) - return FALSE; - - /* Also allocate space for the terminating NULL character */ - ++Length; - *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR)); - - GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION); - - return TRUE; -} - -CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) : - CMenuToolbarBase(menuBand, FALSE), - m_hmenu(NULL) -{ -} - -HRESULT CMenuStaticToolbar::GetMenu( - HMENU *phmenu, - HWND *phwnd, - DWORD *pdwFlags) -{ - *phmenu = m_hmenu; - *phwnd = NULL; - *pdwFlags = m_dwMenuFlags; - - return S_OK; -} - -HRESULT CMenuStaticToolbar::SetMenu( - HMENU hmenu, - HWND hwnd, - DWORD dwFlags) -{ - m_hmenu = hmenu; - m_dwMenuFlags = dwFlags; - - return S_OK; -} - -HRESULT CMenuStaticToolbar::FillToolbar() -{ - int i; - int ic = GetMenuItemCount(m_hmenu); - - for (i = 0; i < ic; i++) - { - MENUITEMINFOW info; - TBBUTTON tbb = { 0 }; - PWSTR MenuString = NULL; - - tbb.fsState = TBSTATE_ENABLED; - tbb.fsStyle = 0; - - info.cbSize = sizeof(info); - info.fMask = MIIM_FTYPE | MIIM_ID; - - GetMenuItemInfoW(m_hmenu, i, TRUE, &info); - - if (info.fType == MFT_STRING) - { - if (!AllocAndGetMenuString(m_hmenu, i, &MenuString)) - return E_OUTOFMEMORY; - if (::GetSubMenu(m_hmenu, i) != NULL) - tbb.fsStyle |= BTNS_DROPDOWN; - tbb.iString = (INT_PTR) MenuString; - tbb.idCommand = info.wID; - - SMINFO * sminfo = new SMINFO(); - sminfo->dwMask = SMIM_ICON | SMIM_FLAGS; - if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast(sminfo)))) - { - tbb.iBitmap = sminfo->iIcon; - tbb.dwData = reinterpret_cast(sminfo); - // FIXME: remove before deleting the toolbar or it will leak - } - } - else - { - tbb.fsStyle |= BTNS_SEP; - } - - SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); - - if (MenuString) - HeapFree(GetProcessHeap(), 0, MenuString); - } - - return S_OK; -} - -HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick) -{ - CComPtr contextMenu; - HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast(&IID_IContextMenu), reinterpret_cast(&contextMenu)); - if (hr != S_OK) - return hr; - - return DoContextMenu(contextMenu); -} - -HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) -{ - HRESULT hr; - hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); - if (FAILED(hr)) - return hr; - - // in case the clicked item has a submenu, we do not need to execute the item - if (hr == S_FALSE) - return hr; - - return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0); -} - -HRESULT CMenuStaticToolbar::PopupItem(UINT uItem) -{ - TBBUTTONINFO info = { 0 }; - info.cbSize = sizeof(TBBUTTONINFO); - info.dwMask = 0; - int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); - if (index < 0) - return E_FAIL; - - TBBUTTON btn = { 0 }; - SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn)); - - SMINFO * nfo = reinterpret_cast(btn.dwData); - if (!nfo) - return E_FAIL; - - if (nfo->dwFlags&SMIF_TRACKPOPUP) - { - return PopupSubMenu(index, m_hmenu); - } - else - { - CComPtr shellMenu; - HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast(&IID_IShellMenu), reinterpret_cast(&shellMenu)); - if (FAILED(hr)) - return hr; - - return PopupSubMenu(uItem, index, shellMenu); - } -} - -HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem) -{ - TBBUTTONINFO info = { 0 }; - info.cbSize = sizeof(TBBUTTONINFO); - info.dwMask = 0; - int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); - if (index < 0) - return E_FAIL; - return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE; -} - -CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) : - CMenuToolbarBase(menuBand, TRUE), - m_shellFolder(NULL) -{ -} - -CMenuSFToolbar::~CMenuSFToolbar() -{ -} - -HRESULT CMenuSFToolbar::FillToolbar() -{ - HRESULT hr; - int i = 0; - PWSTR MenuString; - - IEnumIDList * eidl; - m_shellFolder->EnumObjects(m_hwndToolbar, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl); - - LPITEMIDLIST item = static_cast(CoTaskMemAlloc(sizeof(ITEMIDLIST))); - ULONG fetched; - while ((hr = eidl->Next(1, &item, &fetched)) == S_OK) - { - INT index = 0; - INT indexOpen = 0; - - TBBUTTON tbb = { 0 }; - tbb.fsState = TBSTATE_ENABLED; - tbb.fsStyle = 0; - - CComPtr psi; - hr = SHCreateShellItem(NULL, m_shellFolder, item, &psi); - if (FAILED(hr)) - return hr; - - hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString); - if (FAILED(hr)) - return hr; - - index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen); - - SFGAOF attrs; - hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); - - if (attrs != 0) - { - tbb.fsStyle |= BTNS_DROPDOWN; - } - - tbb.idCommand = ++i; - tbb.iString = (INT_PTR) MenuString; - tbb.iBitmap = index; - tbb.dwData = reinterpret_cast(ILClone(item)); - // FIXME: remove before deleting the toolbar or it will leak - - SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); - HeapFree(GetProcessHeap(), 0, MenuString); - - } - CoTaskMemFree(item); - - // If no items were added, show the "empty" placeholder - if (i == 0) - { - TBBUTTON tbb = { 0 }; - PCWSTR MenuString = L"(Empty)"; - - tbb.fsState = 0/*TBSTATE_DISABLED*/; - tbb.fsStyle = 0; - tbb.iString = (INT_PTR) MenuString; - tbb.iBitmap = -1; - - SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); - - return S_OK; - } - - return hr; -} - -HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags) -{ - m_shellFolder = psf; - m_idList = pidlFolder; - m_hKey = hKey; - m_dwMenuFlags = dwFlags; - return S_OK; -} - -HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv) -{ - HRESULT hr; - - hr = m_shellFolder->QueryInterface(riid, ppv); - if (FAILED(hr)) - return hr; - - if (pdwFlags) - *pdwFlags = m_dwMenuFlags; - - if (ppidl) - { - LPITEMIDLIST pidl = NULL; - - if (m_idList) - { - pidl = ILClone(m_idList); - if (!pidl) - { - (*(IUnknown**) ppv)->Release(); - return E_FAIL; - } - } - - *ppidl = pidl; - } - - return hr; -} - -LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex) -{ - TBBUTTONINFO info = { 0 }; - info.cbSize = sizeof(TBBUTTONINFO); - info.dwMask = 0; - int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); - if (index < 0) - return NULL; - - if (pIndex) - *pIndex = index; - - TBBUTTON btn = { 0 }; - if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn))) - return NULL; - - return reinterpret_cast(btn.dwData); -} - -HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick) -{ - HRESULT hr; - CComPtr contextMenu; - LPCITEMIDLIST pidl = reinterpret_cast(rclick->dwItemData); - - hr = m_shellFolder->GetUIObjectOf(m_hwndToolbar, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast(&contextMenu)); - if (hr != S_OK) - return hr; - - return DoContextMenu(contextMenu); -} - -HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) -{ - HRESULT hr; - hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); - if (FAILED(hr)) - return hr; - - // in case the clicked item has a submenu, we do not need to execute the item - if (hr == S_FALSE) - return hr; - - return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0); -} - -HRESULT CMenuSFToolbar::PopupItem(UINT uItem) -{ - HRESULT hr; - UINT uId; - UINT uIdAncestor; - DWORD flags; - int index; - CComPtr psmc; - CComPtr shellMenu; - - LPITEMIDLIST pidl = GetPidlFromId(uItem, &index); - - if (!pidl) - return E_FAIL; - -#if USE_SYSTEM_MENUBAND - hr = CoCreateInstance(CLSID_MenuBand, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARG(IShellMenu, &shellMenu)); -#else - hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu)); -#endif - if (FAILED(hr)) - return hr; -#if WRAP_MENUBAND - hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu)); - if (FAILED(hr)) - return hr; -#endif - - m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags); - - // FIXME: not sure what to use as uId/uIdAncestor here - hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL); - if (FAILED(hr)) - return hr; - - CComPtr childFolder; - hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder)); - if (FAILED(hr)) - return hr; - - hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0); - if (FAILED(hr)) - return hr; - - return PopupSubMenu(uItem, index, shellMenu); -} - -HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem) -{ - HRESULT hr; - CComPtr psi; - hr = SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi); - if (FAILED(hr)) - return S_FALSE; - - SFGAOF attrs; - hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); - if (FAILED(hr)) - return hr; - - return (attrs != 0) ? S_OK : S_FALSE; -} - CMenuBand::CMenuBand() : m_staticToolbar(NULL), m_SFToolbar(NULL), diff --git a/base/shell/rshell/CMenuBand.h b/base/shell/rshell/CMenuBand.h new file mode 100644 index 00000000000..7e19ee50447 --- /dev/null +++ b/base/shell/rshell/CMenuBand.h @@ -0,0 +1,191 @@ +/* +* Shell Menu Band +* +* Copyright 2014 David Quintana +* +* 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 St, Fifth Floor, Boston, MA 02110-1301, USA +*/ +#pragma once + +class CMenuToolbarBase; +class CMenuStaticToolbar; +class CMenuSFToolbar; +class CMenuFocusManager; + +class CMenuBand : + public CComCoClass, + public CComObjectRootEx, + public IDeskBand, + public IObjectWithSite, + public IInputObject, + public IPersistStream, + public IOleCommandTarget, + public IServiceProvider, + public IMenuPopup, + public IMenuBand, + public IShellMenu2, + public IWinEventHandler, + public IShellMenuAcc +{ +private: + CMenuFocusManager * m_focusManager; + CMenuStaticToolbar * m_staticToolbar; + CMenuSFToolbar * m_SFToolbar; + + CComPtr m_site; + CComPtr m_psmc; + CComPtr m_subMenuChild; + CComPtr m_subMenuParent; + + UINT m_uId; + UINT m_uIdAncestor; + DWORD m_dwFlags; + PVOID m_UserData; + HMENU m_hmenu; + HWND m_menuOwner; + + BOOL m_useBigIcons; + HWND m_topLevelWindow; + + CMenuToolbarBase * m_hotBar; + INT m_hotItem; + INT m_popupItem; + + HFONT m_marlett; + +public: + CMenuBand(); + ~CMenuBand(); + + DECLARE_NOT_AGGREGATABLE(CMenuBand) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CMenuBand) + COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IShellMenu, IShellMenu) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IDeskBand) + COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow) + COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) + COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersistStream) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IMenuBand, IMenuBand) + COM_INTERFACE_ENTRY_IID(IID_IShellMenu2, IShellMenu2) + COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) + COM_INTERFACE_ENTRY_IID(IID_IShellMenuAcc, IShellMenuAcc) + END_COM_MAP() + + // *** IDeskBand methods *** + virtual HRESULT STDMETHODCALLTYPE GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO *pdbi); + + // *** IDockingWindow methods *** + virtual HRESULT STDMETHODCALLTYPE ShowDW(BOOL fShow); + virtual HRESULT STDMETHODCALLTYPE CloseDW(DWORD dwReserved); + virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved); + + // *** IOleWindow methods *** + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + + // *** IObjectWithSite methods *** + virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); + virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite); + + // *** IInputObject methods *** + virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); + virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); + + // *** IPersistStream methods *** + virtual HRESULT STDMETHODCALLTYPE IsDirty(); + virtual HRESULT STDMETHODCALLTYPE Load(IStream *pStm); + virtual HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty); + virtual HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize); + + // *** IPersist methods *** + virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + + // *** IOleCommandTarget methods *** + virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); + virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); + + // *** IServiceProvider methods *** + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + + // *** IMenuPopup methods *** + virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags); + virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType); + virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet); + + // *** IDeskBar methods *** + virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient); + virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient); + virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc); + + // *** IMenuBand methods *** + virtual HRESULT STDMETHODCALLTYPE IsMenuMessage(MSG *pmsg); + virtual HRESULT STDMETHODCALLTYPE TranslateMenuMessage(MSG *pmsg, LRESULT *plRet); + + // *** IShellMenu methods *** + virtual HRESULT STDMETHODCALLTYPE Initialize(IShellMenuCallback *psmc, UINT uId, UINT uIdAncestor, DWORD dwFlags); + virtual HRESULT STDMETHODCALLTYPE GetMenuInfo(IShellMenuCallback **ppsmc, UINT *puId, UINT *puIdAncestor, DWORD *pdwFlags); + virtual HRESULT STDMETHODCALLTYPE SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags); + virtual HRESULT STDMETHODCALLTYPE GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv); + virtual HRESULT STDMETHODCALLTYPE SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags); + virtual HRESULT STDMETHODCALLTYPE GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags); + virtual HRESULT STDMETHODCALLTYPE InvalidateItem(LPSMDATA psmd, DWORD dwFlags); + virtual HRESULT STDMETHODCALLTYPE GetState(LPSMDATA psmd); + virtual HRESULT STDMETHODCALLTYPE SetMenuToolbar(IUnknown *punk, DWORD dwFlags); + + // *** IWinEventHandler methods *** + virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd); + + // *** IShellMenu2 methods *** + virtual HRESULT STDMETHODCALLTYPE GetSubMenu(THIS); + virtual HRESULT STDMETHODCALLTYPE SetToolbar(THIS); + virtual HRESULT STDMETHODCALLTYPE SetMinWidth(THIS); + virtual HRESULT STDMETHODCALLTYPE SetNoBorder(THIS); + virtual HRESULT STDMETHODCALLTYPE SetTheme(THIS); + + // *** IShellMenuAcc methods *** + virtual HRESULT STDMETHODCALLTYPE GetTop(THIS); + virtual HRESULT STDMETHODCALLTYPE GetBottom(THIS); + virtual HRESULT STDMETHODCALLTYPE GetTracked(THIS); + virtual HRESULT STDMETHODCALLTYPE GetParentSite(THIS); + virtual HRESULT STDMETHODCALLTYPE GetState(THIS); + virtual HRESULT STDMETHODCALLTYPE DoDefaultAction(THIS); + virtual HRESULT STDMETHODCALLTYPE IsEmpty(THIS); + + HRESULT _CallCBWithItemId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam); + HRESULT _CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam); + HRESULT _TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y); + HRESULT _GetTopLevelWindow(HWND*topLevel); + HRESULT _OnHotItemChanged(CMenuToolbarBase * tb, INT id); + HRESULT _MenuItemHotTrack(DWORD changeType); + HRESULT _OnPopupSubMenu(INT popupItem, IMenuPopup * popup, POINTL * pAt, RECTL * pExclude); + + BOOL UseBigIcons() + { + return m_useBigIcons; + } + +private: + HRESULT _CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id = 0, LPITEMIDLIST pidl = NULL); +}; diff --git a/base/shell/rshell/CMenuDeskBar.cpp b/base/shell/rshell/CMenuDeskBar.cpp index a5da7e210c3..d8135842811 100644 --- a/base/shell/rshell/CMenuDeskBar.cpp +++ b/base/shell/rshell/CMenuDeskBar.cpp @@ -1,147 +1,32 @@ /* -* Shell Menu Desk Bar -* -* Copyright 2014 David Quintana -* -* 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 St, Fifth Floor, Boston, MA 02110-1301, USA -*/ + * Shell Menu Desk Bar + * + * Copyright 2014 David Quintana + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ #include "precomp.h" #include #include +#include "CMenuDeskBar.h" + WINE_DEFAULT_DEBUG_CHANNEL(CMenuDeskBar); const static GUID CGID_MenuDeskBar = { 0x5C9F0A12, 0x959E, 0x11D0, { 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x08, 0x26, 0x36 } }; -typedef CWinTraits< - WS_POPUP | WS_DLGFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, - WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_PALETTEWINDOW -> CMenuWinTraits; - -class CMenuDeskBar : - public CWindowImpl, - public CComCoClass, - public CComObjectRootEx, - public IOleCommandTarget, - public IServiceProvider, - public IInputObjectSite, - public IInputObject, - public IMenuPopup, - public IObjectWithSite, - public IBanneredBar, - public IInitializeObject -{ -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; - - BOOL m_Shown; - -public: - CMenuDeskBar(); - ~CMenuDeskBar(); - - DECLARE_NOT_AGGREGATABLE(CMenuDeskBar) - DECLARE_PROTECT_FINAL_CONSTRUCT() - - DECLARE_WND_CLASS_EX(_T("BaseBar"), CS_SAVEBITS | CS_DROPSHADOW, COLOR_3DFACE) - - BEGIN_MSG_MAP(CMenuDeskBar) - MESSAGE_HANDLER(WM_SIZE, _OnSize) - MESSAGE_HANDLER(WM_NOTIFY, _OnNotify) - MESSAGE_HANDLER(WM_PAINT, _OnPaint) - MESSAGE_HANDLER(WM_ACTIVATE, _OnActivate) - MESSAGE_HANDLER(WM_ACTIVATEAPP, _OnAppActivate) - END_MSG_MAP() - - BEGIN_COM_MAP(CMenuDeskBar) - COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup) - COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) - COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) - COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) - COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) - COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup) - COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IMenuPopup) - COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) - COM_INTERFACE_ENTRY_IID(IID_IBanneredBar, IBanneredBar) - COM_INTERFACE_ENTRY_IID(IID_IInitializeObject, IInitializeObject) - END_COM_MAP() - - // *** IMenuPopup methods *** - virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags); - virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType); - virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet); - - // *** IOleWindow methods *** - virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); - virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); - - // *** IObjectWithSite methods *** - virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); - virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite); - - // *** IBanneredBar methods *** - virtual HRESULT STDMETHODCALLTYPE SetIconSize(DWORD iIcon); - virtual HRESULT STDMETHODCALLTYPE GetIconSize(DWORD* piIcon); - virtual HRESULT STDMETHODCALLTYPE SetBitmap(HBITMAP hBitmap); - virtual HRESULT STDMETHODCALLTYPE GetBitmap(HBITMAP* phBitmap); - - // *** IInitializeObject methods *** - virtual HRESULT STDMETHODCALLTYPE Initialize(THIS); - - // *** IOleCommandTarget methods *** - virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); - virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); - - // *** IServiceProvider methods *** - virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); - - // *** IInputObjectSite methods *** - virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(LPUNKNOWN lpUnknown, BOOL bFocus); - - // *** IInputObject methods *** - virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL bActivating, LPMSG lpMsg); - virtual HRESULT STDMETHODCALLTYPE HasFocusIO(THIS); - virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); - - // *** IDeskBar methods *** - virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient); - virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient); - virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(LPRECT prc); - -private: - // message handlers - LRESULT _OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - LRESULT _OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - LRESULT _OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); - - BOOL _IsSubMenuParent(HWND hwnd); - HRESULT _CloseBar(); -}; - extern "C" HRESULT CMenuDeskBar_Constructor(REFIID riid, LPVOID *ppv) { @@ -160,19 +45,15 @@ HRESULT CMenuDeskBar_Constructor(REFIID riid, LPVOID *ppv) return hr; } -INT deskBarCount=0; - CMenuDeskBar::CMenuDeskBar() : m_Client(NULL), m_Banner(NULL), - m_Level(deskBarCount++), m_Shown(FALSE) { } CMenuDeskBar::~CMenuDeskBar() { - deskBarCount--; } HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS) diff --git a/base/shell/rshell/CMenuDeskBar.h b/base/shell/rshell/CMenuDeskBar.h new file mode 100644 index 00000000000..4665f8265d6 --- /dev/null +++ b/base/shell/rshell/CMenuDeskBar.h @@ -0,0 +1,135 @@ +/* +* Shell Menu Desk Bar +* +* Copyright 2014 David Quintana +* +* 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 St, Fifth Floor, Boston, MA 02110-1301, USA +*/ +#pragma once + +typedef CWinTraits< + WS_POPUP | WS_DLGFRAME | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_PALETTEWINDOW +> CMenuWinTraits; + +class CMenuDeskBar : + public CWindowImpl, + public CComCoClass, + public CComObjectRootEx, + public IOleCommandTarget, + public IServiceProvider, + public IInputObjectSite, + public IInputObject, + public IMenuPopup, + public IObjectWithSite, + public IBanneredBar, + public IInitializeObject +{ +private: + CComPtr m_Site; + CComPtr m_Client; + CComPtr m_SubMenuParent; + CComPtr m_SubMenuChild; + + HWND m_ClientWindow; + + DWORD m_IconSize; + HBITMAP m_Banner; + + BOOL m_Shown; + +public: + CMenuDeskBar(); + ~CMenuDeskBar(); + + DECLARE_NOT_AGGREGATABLE(CMenuDeskBar) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + DECLARE_WND_CLASS_EX(_T("BaseBar"), CS_SAVEBITS | CS_DROPSHADOW, COLOR_3DFACE) + + BEGIN_MSG_MAP(CMenuDeskBar) + MESSAGE_HANDLER(WM_SIZE, _OnSize) + MESSAGE_HANDLER(WM_NOTIFY, _OnNotify) + MESSAGE_HANDLER(WM_PAINT, _OnPaint) + MESSAGE_HANDLER(WM_ACTIVATE, _OnActivate) + MESSAGE_HANDLER(WM_ACTIVATEAPP, _OnAppActivate) + END_MSG_MAP() + + BEGIN_COM_MAP(CMenuDeskBar) + COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) + COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) + COM_INTERFACE_ENTRY_IID(IID_IDeskBar, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IMenuPopup) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + COM_INTERFACE_ENTRY_IID(IID_IBanneredBar, IBanneredBar) + COM_INTERFACE_ENTRY_IID(IID_IInitializeObject, IInitializeObject) + END_COM_MAP() + + // *** IMenuPopup methods *** + virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags); + virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType); + virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet); + + // *** IOleWindow methods *** + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + + // *** IObjectWithSite methods *** + virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); + virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, PVOID *ppvSite); + + // *** IBanneredBar methods *** + virtual HRESULT STDMETHODCALLTYPE SetIconSize(DWORD iIcon); + virtual HRESULT STDMETHODCALLTYPE GetIconSize(DWORD* piIcon); + virtual HRESULT STDMETHODCALLTYPE SetBitmap(HBITMAP hBitmap); + virtual HRESULT STDMETHODCALLTYPE GetBitmap(HBITMAP* phBitmap); + + // *** IInitializeObject methods *** + virtual HRESULT STDMETHODCALLTYPE Initialize(THIS); + + // *** IOleCommandTarget methods *** + virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); + virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); + + // *** IServiceProvider methods *** + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + + // *** IInputObjectSite methods *** + virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(LPUNKNOWN lpUnknown, BOOL bFocus); + + // *** IInputObject methods *** + virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL bActivating, LPMSG lpMsg); + virtual HRESULT STDMETHODCALLTYPE HasFocusIO(THIS); + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); + + // *** IDeskBar methods *** + virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient); + virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown **ppunkClient); + virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(LPRECT prc); + +private: + // message handlers + LRESULT _OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT _OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + + BOOL _IsSubMenuParent(HWND hwnd); + HRESULT _CloseBar(); +}; diff --git a/base/shell/rshell/CMenuFocusManager.cpp b/base/shell/rshell/CMenuFocusManager.cpp new file mode 100644 index 00000000000..56b2759fdd3 --- /dev/null +++ b/base/shell/rshell/CMenuFocusManager.cpp @@ -0,0 +1,252 @@ +/* + * Shell Menu Band + * + * Copyright 2014 David Quintana + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "precomp.h" +#include +#include +#include + +#include "CMenuFocusManager.h" +#include "CMenuBand.h" + +WINE_DEFAULT_DEBUG_CHANNEL(CMenuFocus); + +DWORD CMenuFocusManager::TlsIndex = 0; + +CMenuFocusManager * CMenuFocusManager::GetManager() +{ + return reinterpret_cast(TlsGetValue(TlsIndex)); +} + +CMenuFocusManager * CMenuFocusManager::AcquireManager() +{ + CMenuFocusManager * obj = NULL; + + if (!TlsIndex) + { + if ((TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return NULL; + } + + obj = GetManager(); + + if (!obj) + { + obj = new CComObject(); + TlsSetValue(TlsIndex, obj); + } + + obj->AddRef(); + + return obj; +} + +void CMenuFocusManager::ReleaseManager(CMenuFocusManager * obj) +{ + if (!obj->Release()) + { + TlsSetValue(TlsIndex, NULL); + } +} + +LRESULT CALLBACK CMenuFocusManager::s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) +{ + return GetManager()->GetMsgHook(nCode, wParam, lParam); +} + +HRESULT CMenuFocusManager::PushToArray(CMenuBand * item) +{ + if (m_bandCount >= MAX_RECURSE) + return E_OUTOFMEMORY; + + m_bandStack[m_bandCount++] = item; + return S_OK; +} + +HRESULT CMenuFocusManager::PopFromArray(CMenuBand ** pItem) +{ + if (pItem) + *pItem = NULL; + + if (m_bandCount <= 0) + return E_FAIL; + + m_bandCount--; + + if (pItem) + *pItem = m_bandStack[m_bandCount]; + + m_bandStack[m_bandCount] = NULL; + + return S_OK; +} + +HRESULT CMenuFocusManager::PeekArray(CMenuBand ** pItem) +{ + if (!pItem) + return E_FAIL; + + *pItem = NULL; + + if (m_bandCount <= 0) + return E_FAIL; + + *pItem = m_bandStack[m_bandCount - 1]; + + return S_OK; +} + +CMenuFocusManager::CMenuFocusManager() : + m_currentBand(NULL), + m_currentFocus(NULL), + m_bandCount(0) +{ + m_threadId = GetCurrentThreadId(); +} + +CMenuFocusManager::~CMenuFocusManager() +{ +} + +LRESULT CMenuFocusManager::GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam) +{ + if (nCode < 0) + return CallNextHookEx(m_hHook, nCode, wParam, lParam); + + if (nCode == HC_ACTION) + { + BOOL callNext = TRUE; + MSG* msg = reinterpret_cast(lParam); + + // Do whatever is necessary here + + switch (msg->message) + { + case WM_CLOSE: + break; + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + switch (msg->wParam) + { + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + m_currentBand->_MenuItemHotTrack(MPOS_FULLCANCEL); + break; + case VK_LEFT: + m_currentBand->_MenuItemHotTrack(MPOS_SELECTLEFT); + break; + case VK_RIGHT: + m_currentBand->_MenuItemHotTrack(MPOS_SELECTRIGHT); + break; + case VK_UP: + m_currentBand->_MenuItemHotTrack(VK_UP); + break; + case VK_DOWN: + m_currentBand->_MenuItemHotTrack(VK_DOWN); + break; + } + break; + case WM_CHAR: + //if (msg->wParam >= 'a' && msg->wParam <= 'z') + //{ + // callNext = FALSE; + // PostMessage(m_currentFocus, WM_SYSCHAR, wParam, lParam); + //} + break; + } + + if (!callNext) + return 0; + } + + return CallNextHookEx(m_hHook, nCode, wParam, lParam); +} + +HRESULT CMenuFocusManager::PlaceHooks(HWND window) +{ + //SetCapture(window); + m_hHook = SetWindowsHookEx(WH_GETMESSAGE, s_GetMsgHook, NULL, m_threadId); + return S_OK; +} + +HRESULT CMenuFocusManager::RemoveHooks(HWND window) +{ + UnhookWindowsHookEx(m_hHook); + //ReleaseCapture(); + return S_OK; +} + +HRESULT CMenuFocusManager::UpdateFocus(CMenuBand * newBand) +{ + HRESULT hr; + HWND newFocus; + + if (newBand == NULL) + { + hr = RemoveHooks(m_currentFocus); + m_currentFocus = NULL; + m_currentBand = NULL; + return S_OK; + } + + hr = newBand->_GetTopLevelWindow(&newFocus); + if (FAILED(hr)) + return hr; + + if (!m_currentBand) + { + hr = PlaceHooks(newFocus); + if (FAILED(hr)) + return hr; + } + + m_currentFocus = newFocus; + m_currentBand = newBand; + + return S_OK; +} + +HRESULT CMenuFocusManager::PushMenu(CMenuBand * mb) +{ + HRESULT hr; + + hr = PushToArray(mb); + if (FAILED(hr)) + return hr; + + return UpdateFocus(mb); +} + +HRESULT CMenuFocusManager::PopMenu(CMenuBand * mb) +{ + CMenuBand * mbc; + HRESULT hr; + + hr = PopFromArray(&mbc); + if (FAILED(hr)) + return hr; + + if (mb != mbc) + return E_FAIL; + + hr = PeekArray(&mbc); + + return UpdateFocus(mbc); +} diff --git a/base/shell/rshell/CMenuFocusManager.h b/base/shell/rshell/CMenuFocusManager.h new file mode 100644 index 00000000000..fd848880aba --- /dev/null +++ b/base/shell/rshell/CMenuFocusManager.h @@ -0,0 +1,75 @@ +/* +* Shell Menu Band +* +* Copyright 2014 David Quintana +* +* 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 St, Fifth Floor, Boston, MA 02110-1301, USA +*/ +#pragma once + +class CMenuBand; + +class CMenuFocusManager : + public CComCoClass, + public CComObjectRootEx +{ +private: + static DWORD TlsIndex; + + static CMenuFocusManager * GetManager(); + +public: + static CMenuFocusManager * AcquireManager(); + + static void ReleaseManager(CMenuFocusManager * obj); + +private: + static LRESULT CALLBACK s_GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam); + +private: + CMenuBand * m_currentBand; + HWND m_currentFocus; + HHOOK m_hHook; + DWORD m_threadId; + + // TODO: make dynamic +#define MAX_RECURSE 20 + CMenuBand* m_bandStack[MAX_RECURSE]; + int m_bandCount; + + HRESULT PushToArray(CMenuBand * item); + HRESULT PopFromArray(CMenuBand ** pItem); + HRESULT PeekArray(CMenuBand ** pItem); + +protected: + CMenuFocusManager(); + ~CMenuFocusManager(); + +public: + + DECLARE_NOT_AGGREGATABLE(CMenuFocusManager) + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(CMenuFocusManager) + END_COM_MAP() + + LRESULT GetMsgHook(INT nCode, WPARAM wParam, LPARAM lParam); + HRESULT PlaceHooks(HWND window); + HRESULT RemoveHooks(HWND window); + HRESULT UpdateFocus(CMenuBand * newBand); + +public: + HRESULT PushMenu(CMenuBand * mb); + HRESULT PopMenu(CMenuBand * mb); +}; diff --git a/base/shell/rshell/CMenuSite.cpp b/base/shell/rshell/CMenuSite.cpp index 02c0ece5230..a03955769da 100644 --- a/base/shell/rshell/CMenuSite.cpp +++ b/base/shell/rshell/CMenuSite.cpp @@ -17,98 +17,13 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ - #include "precomp.h" #include #include -WINE_DEFAULT_DEBUG_CHANNEL(menusite); +#include "CMenuSite.h" -class CMenuSite : - public CComObjectRootEx, - public CWindowImpl, - public IBandSite, - public IDeskBarClient, - public IOleCommandTarget, - public IInputObject, - public IInputObjectSite, - public IWinEventHandler, - public IServiceProvider -{ -private: - CComPtr m_DeskBarSite; - CComPtr m_BandObject; - CComPtr m_DeskBand; - CComPtr m_WinEventHandler; - HWND m_hWndBand; - -public: - CMenuSite(); - ~CMenuSite() {} - - DECLARE_WND_CLASS_EX(_T("MenuSite"), 0, COLOR_MENU) - - DECLARE_NOT_AGGREGATABLE(CMenuSite) - DECLARE_PROTECT_FINAL_CONSTRUCT() - BEGIN_COM_MAP(CMenuSite) - COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite) - COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient) - COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) - COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) - COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) - COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) - COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) - COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) - END_COM_MAP() - - // IBandSite - virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown * punk); - virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD* pdwBandID); - virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName); - virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv); - - // IDeskBarClient - virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite); - virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc); - virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState); - - // IOleWindow - virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); - - // IOleCommandTarget - virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); - virtual HRESULT STDMETHODCALLTYPE Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); - - // IInputObject - virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); - virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); - virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); - - // IInputObjectSite - virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus); - - // IWinEventHandler - virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd); - virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult); - - // IServiceProvider - virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); - - - // Using custom message map instead - virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId = 0); - - // UNIMPLEMENTED - virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); - virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo); - virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID); - virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo); - virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState); - virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode); - -private: - IUnknown * ToIUnknown() { return static_cast(this); } -}; +WINE_DEFAULT_DEBUG_CHANNEL(menusite); extern "C" HRESULT CMenuSite_Constructor(REFIID riid, LPVOID *ppv) diff --git a/base/shell/rshell/CMenuSite.h b/base/shell/rshell/CMenuSite.h new file mode 100644 index 00000000000..1539a15c091 --- /dev/null +++ b/base/shell/rshell/CMenuSite.h @@ -0,0 +1,106 @@ +/* + * Shell Menu Site + * + * Copyright 2014 David Quintana + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#pragma once + +class CMenuSite : + public CComObjectRootEx, + public CWindowImpl, + public IBandSite, + public IDeskBarClient, + public IOleCommandTarget, + public IInputObject, + public IInputObjectSite, + public IWinEventHandler, + public IServiceProvider +{ +private: + CComPtr m_DeskBarSite; + CComPtr m_BandObject; + CComPtr m_DeskBand; + CComPtr m_WinEventHandler; + HWND m_hWndBand; + +public: + CMenuSite(); + ~CMenuSite() {} + + DECLARE_WND_CLASS_EX(_T("MenuSite"), 0, COLOR_MENU) + + DECLARE_NOT_AGGREGATABLE(CMenuSite) + DECLARE_PROTECT_FINAL_CONSTRUCT() + BEGIN_COM_MAP(CMenuSite) + COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite) + COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) + COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) + COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + END_COM_MAP() + + // IBandSite + virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown * punk); + virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD* pdwBandID); + virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName); + virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv); + + // IDeskBarClient + virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite); + virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc); + virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState); + + // IOleWindow + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + + // IOleCommandTarget + virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText); + virtual HRESULT STDMETHODCALLTYPE Exec(const GUID * pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut); + + // IInputObject + virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); + virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); + + // IInputObjectSite + virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus); + + // IWinEventHandler + virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd); + virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult); + + // IServiceProvider + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + + + // Using custom message map instead + virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD mapId = 0); + + // UNIMPLEMENTED + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo); + virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID); + virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo); + virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState); + virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode); + +private: + IUnknown * ToIUnknown() { return static_cast(this); } +}; diff --git a/base/shell/rshell/CMenuToolbars.cpp b/base/shell/rshell/CMenuToolbars.cpp new file mode 100644 index 00000000000..67007dab018 --- /dev/null +++ b/base/shell/rshell/CMenuToolbars.cpp @@ -0,0 +1,895 @@ +/* + * Shell Menu Band + * + * Copyright 2014 David Quintana + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "precomp.h" +#include +#include +#include + +#include "CMenuBand.h" +#include "CMenuToolbars.h" + +WINE_DEFAULT_DEBUG_CHANNEL(CMenuToolbars); + +extern "C" +HRESULT WINAPI SHGetImageList( + _In_ int iImageList, + _In_ REFIID riid, + _Out_ void **ppv + ); + +#define TBSTYLE_EX_VERTICAL 4 + + +#define TIMERID_HOTTRACK 1 +#define SUBCLASS_ID_MENUBAND 1 + +CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) : + m_hwnd(NULL), + m_menuBand(menuBand), + m_hwndToolbar(NULL), + m_dwMenuFlags(0), + m_hasIdealSize(FALSE) +{ +} + +HRESULT CMenuToolbarBase::IsWindowOwner(HWND hwnd) +{ + return (m_hwnd && m_hwnd == hwnd) || + (m_hwndToolbar && m_hwndToolbar == hwnd) ? S_OK : S_FALSE; +} + +void CMenuToolbarBase::InvalidateDraw() +{ + InvalidateRect(m_hwnd, NULL, FALSE); +} + +HRESULT CMenuToolbarBase::ShowWindow(BOOL fShow) +{ + ::ShowWindow(m_hwnd, fShow ? SW_SHOW : SW_HIDE); + + int shiml; + if (m_menuBand->UseBigIcons()) + { + shiml = SHIL_LARGE; + SendMessageW(m_hwndToolbar, TB_SETPADDING, 0, MAKELPARAM(0, 0)); + } + else + { + shiml = SHIL_SMALL; + } + + IImageList * piml; + HRESULT hr = SHGetImageList(shiml, IID_PPV_ARG(IImageList, &piml)); + if (SUCCEEDED(hr)) + { + SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast(piml)); + } + else + { + SendMessageW(m_hwndToolbar, TB_SETIMAGELIST, 0, 0); + } + + return S_OK; +} + +HRESULT CMenuToolbarBase::Close() +{ + DestroyWindow(m_hwndToolbar); + if (m_hwndToolbar != m_hwnd) + DestroyWindow(m_hwnd); + m_hwndToolbar = NULL; + m_hwnd = NULL; + return S_OK; +} + +HRESULT CMenuToolbarBase::CreateToolbar(HWND hwndParent, DWORD dwFlags) +{ + LONG tbStyles = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | + TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE | + CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP; + LONG tbExStyles = TBSTYLE_EX_DOUBLEBUFFER; + + if (dwFlags & SMINIT_VERTICAL) + { + tbStyles |= CCS_VERT; + tbExStyles |= TBSTYLE_EX_VERTICAL | WS_EX_TOOLWINDOW; + } + + RECT rc; + + if (!::GetClientRect(hwndParent, &rc) || (rc.left == rc.right) || (rc.top == rc.bottom)) + { + rc.left = 0; + rc.top = 0; + rc.right = 1; + rc.bottom = 1; + } + + HWND hwndToolbar = CreateWindowEx( + tbExStyles, TOOLBARCLASSNAMEW, NULL, + tbStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0); + + if (hwndToolbar == NULL) + return E_FAIL; + + if (m_usePager) + { + LONG pgStyles = PGS_VERT | WS_CHILD | WS_VISIBLE; + LONG pgExStyles = 0; + + HWND hwndPager = CreateWindowEx( + pgExStyles, WC_PAGESCROLLER, NULL, + pgStyles, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, + hwndParent, NULL, _AtlBaseModule.GetModuleInstance(), 0); + + ::SetParent(hwndToolbar, hwndPager); + ::SetParent(hwndPager, hwndParent); + + SendMessage(hwndPager, PGM_SETCHILD, 0, reinterpret_cast(hwndToolbar)); + m_hwndToolbar = hwndToolbar; + m_hwnd = hwndPager; + } + else + { + ::SetParent(hwndToolbar, hwndParent); + m_hwndToolbar = hwndToolbar; + m_hwnd = hwndToolbar; + } + + /* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */ + SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); + + //if (dwFlags & SMINIT_TOPLEVEL) + //{ + // /* Hide the placeholders for the button images */ + // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0); + //} + //else + int shiml; + if (m_menuBand->UseBigIcons()) + { + shiml = SHIL_LARGE; + SendMessageW(hwndToolbar, TB_SETPADDING, 0, MAKELPARAM(0, 0)); + } + else + { + shiml = SHIL_SMALL; + } + + IImageList * piml; + HRESULT hr = SHGetImageList(shiml, IID_PPV_ARG(IImageList, &piml)); + if (SUCCEEDED(hr)) + { + SendMessageW(hwndToolbar, TB_SETIMAGELIST, 0, reinterpret_cast(piml)); + } + else + { + SendMessageW(hwndToolbar, TB_SETIMAGELIST, 0, 0); + } + + SetWindowLongPtr(hwndToolbar, GWLP_USERDATA, reinterpret_cast(this)); + m_SubclassOld = (WNDPROC) SetWindowLongPtr(hwndToolbar, GWLP_WNDPROC, reinterpret_cast(CMenuToolbarBase::s_SubclassProc)); + + return S_OK; +} + +HRESULT CMenuToolbarBase::GetIdealSize(SIZE& size) +{ + size.cx = size.cy = 0; + + if (m_hwndToolbar && !m_hasIdealSize) + { + SendMessageW(m_hwndToolbar, TB_AUTOSIZE, 0, 0); + SendMessageW(m_hwndToolbar, TB_GETMAXSIZE, 0, reinterpret_cast(&m_idealSize)); + m_hasIdealSize = TRUE; + } + + size = m_idealSize; + + return S_OK; +} + +HRESULT CMenuToolbarBase::SetPosSize(int x, int y, int cx, int cy) +{ + if (m_hwnd != m_hwndToolbar) + { + SetWindowPos(m_hwndToolbar, NULL, x, y, cx, m_idealSize.cy, 0); + } + SetWindowPos(m_hwnd, NULL, x, y, cx, cy, 0); + DWORD btnSize = SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0); + SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, HIWORD(btnSize))); + return S_OK; +} + +HRESULT CMenuToolbarBase::GetWindow(HWND *phwnd) +{ + if (!phwnd) + return E_FAIL; + + *phwnd = m_hwnd; + + return S_OK; +} + +LRESULT CALLBACK CMenuToolbarBase::s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CMenuToolbarBase * pthis = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + return pthis->SubclassProc(hWnd, uMsg, wParam, lParam); +} + +LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_TIMER: + if (wParam == TIMERID_HOTTRACK) + { + KillTimer(hWnd, TIMERID_HOTTRACK); + + m_menuBand->_OnPopupSubMenu(-1, NULL, NULL, NULL); + + if (HasSubMenu(m_hotItem) == S_OK) + { + PopupItem(m_hotItem); + } + } + } + + return m_SubclassOld(hWnd, uMsg, wParam, lParam); +} + +HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot) +{ + if (hot->dwFlags & HICF_LEAVING) + { + KillTimer(m_hwndToolbar, TIMERID_HOTTRACK); + m_hotItem = -1; + m_menuBand->_OnHotItemChanged(NULL, -1); + m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); + } + else if (m_hotItem != hot->idNew) + { + DWORD elapsed = 0; + SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0); + SetTimer(m_hwndToolbar, TIMERID_HOTTRACK, elapsed, NULL); + + m_hotItem = hot->idNew; + m_menuBand->_OnHotItemChanged(this, m_hotItem); + m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING); + } + return S_OK; +} + +HRESULT CMenuToolbarBase::PopupSubMenu(UINT itemId, UINT index, IShellMenu* childShellMenu) +{ + IBandSite* pBandSite; + IDeskBar* pDeskBar; + + HRESULT hr = 0; + RECT rc = { 0 }; + + if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast(&rc))) + return E_FAIL; + + POINT a = { rc.left, rc.top }; + POINT b = { rc.right, rc.bottom }; + + ClientToScreen(m_hwndToolbar, &a); + ClientToScreen(m_hwndToolbar, &b); + + POINTL pt = { b.x, a.y }; + RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar? + + +#if USE_SYSTEM_MENUSITE + hr = CoCreateInstance(CLSID_MenuBandSite, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IBandSite, &pBandSite)); +#else + hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite)); +#endif + if (FAILED(hr)) + return hr; +#if WRAP_MENUSITE + hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite)); + if (FAILED(hr)) + return hr; +#endif + +#if USE_SYSTEM_MENUDESKBAR + hr = CoCreateInstance(CLSID_MenuDeskBar, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IDeskBar, &pDeskBar)); +#else + hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar)); +#endif + if (FAILED(hr)) + return hr; +#if WRAP_MENUDESKBAR + hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar)); + if (FAILED(hr)) + return hr; +#endif + + hr = pDeskBar->SetClient(pBandSite); + if (FAILED(hr)) + return hr; + + hr = pBandSite->AddBand(childShellMenu); + if (FAILED(hr)) + return hr; + + CComPtr popup; + hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup)); + if (FAILED(hr)) + return hr; + + m_menuBand->_OnPopupSubMenu(itemId, popup, &pt, &rcl); + + return S_OK; +} + +HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, HMENU menu) +{ + RECT rc = { 0 }; + + if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast(&rc))) + return E_FAIL; + + POINT b = { rc.right, rc.bottom }; + + ClientToScreen(m_hwndToolbar, &b); + + HMENU popup = GetSubMenu(menu, index); + + m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, b.x, b.y); + + return S_OK; +} + +HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu) +{ + HRESULT hr; + HMENU hPopup = CreatePopupMenu(); + + if (hPopup == NULL) + return E_FAIL; + + hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL); + if (FAILED(hr)) + { + DestroyMenu(hPopup); + return hr; + } + + DWORD dwPos = GetMessagePos(); + UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL); + if (uCommand == 0) + return S_FALSE; + + CMINVOKECOMMANDINFO cmi = { 0 }; + cmi.cbSize = sizeof(cmi); + cmi.lpVerb = MAKEINTRESOURCEA(uCommand); + cmi.hwnd = m_hwnd; + hr = contextMenu->InvokeCommand(&cmi); + + DestroyMenu(hPopup); + return hr; +} + +HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ + theResult = 0; + if (HasSubMenu(wParam) == S_OK) + { + KillTimer(m_hwndToolbar, TIMERID_HOTTRACK); + PopupItem(wParam); + return S_FALSE; + } + return m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE); +} + +HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType) +{ + int prev = m_hotItem; + int index = -1; + + if (dwSelectType != 0xFFFFFFFF) + { + int count = SendMessage(m_hwndToolbar, TB_BUTTONCOUNT, 0, 0); + + if (m_hotItem >= 0) + { + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, m_hotItem, reinterpret_cast(&info)); + } + + if (dwSelectType == VK_HOME) + { + index = 0; + dwSelectType = VK_DOWN; + } + else if (dwSelectType == VK_END) + { + index = count - 1; + dwSelectType = VK_UP; + } + else if (index < 0) + { + if (dwSelectType == VK_UP) + { + index = count - 1; + } + else if (dwSelectType == VK_DOWN) + { + index = 0; + } + } + else + { + if (dwSelectType == VK_UP) + { + index--; + } + else if (dwSelectType == VK_DOWN) + { + index++; + } + } + + TBBUTTON btn = { 0 }; + while (index >= 0 && index < count) + { + DWORD res = SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn)); + if (!res) + return E_FAIL; + + if (btn.dwData) + { + m_hotItem = btn.idCommand; + if (prev != m_hotItem) + { + SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0); + return m_menuBand->_OnHotItemChanged(this, m_hotItem); + } + return S_OK; + } + + if (dwSelectType == VK_UP) + { + index--; + } + else if (dwSelectType == VK_DOWN) + { + index++; + } + } + } + + m_hotItem = -1; + if (prev != m_hotItem) + { + SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0); + m_menuBand->_OnHotItemChanged(NULL, -1); + } + return S_FALSE; +} + +BOOL +AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String) +{ + int Length; + + Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION); + + if (!Length) + return FALSE; + + /* Also allocate space for the terminating NULL character */ + ++Length; + *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR)); + + GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION); + + return TRUE; +} + +CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) : + CMenuToolbarBase(menuBand, FALSE), + m_hmenu(NULL) +{ +} + +HRESULT CMenuStaticToolbar::GetMenu( + HMENU *phmenu, + HWND *phwnd, + DWORD *pdwFlags) +{ + *phmenu = m_hmenu; + *phwnd = NULL; + *pdwFlags = m_dwMenuFlags; + + return S_OK; +} + +HRESULT CMenuStaticToolbar::SetMenu( + HMENU hmenu, + HWND hwnd, + DWORD dwFlags) +{ + m_hmenu = hmenu; + m_dwMenuFlags = dwFlags; + + return S_OK; +} + +HRESULT CMenuStaticToolbar::FillToolbar() +{ + int i; + int ic = GetMenuItemCount(m_hmenu); + + for (i = 0; i < ic; i++) + { + MENUITEMINFOW info; + TBBUTTON tbb = { 0 }; + PWSTR MenuString = NULL; + + tbb.fsState = TBSTATE_ENABLED; + tbb.fsStyle = 0; + + info.cbSize = sizeof(info); + info.fMask = MIIM_FTYPE | MIIM_ID; + + GetMenuItemInfoW(m_hmenu, i, TRUE, &info); + + if (info.fType == MFT_STRING) + { + if (!AllocAndGetMenuString(m_hmenu, i, &MenuString)) + return E_OUTOFMEMORY; + if (::GetSubMenu(m_hmenu, i) != NULL) + tbb.fsStyle |= BTNS_DROPDOWN; + tbb.iString = (INT_PTR) MenuString; + tbb.idCommand = info.wID; + + SMINFO * sminfo = new SMINFO(); + sminfo->dwMask = SMIM_ICON | SMIM_FLAGS; + if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast(sminfo)))) + { + tbb.iBitmap = sminfo->iIcon; + tbb.dwData = reinterpret_cast(sminfo); + // FIXME: remove before deleting the toolbar or it will leak + } + } + else + { + tbb.fsStyle |= BTNS_SEP; + } + + SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); + + if (MenuString) + HeapFree(GetProcessHeap(), 0, MenuString); + } + + return S_OK; +} + +HRESULT CMenuStaticToolbar::OnContextMenu(NMMOUSE * rclick) +{ + CComPtr contextMenu; + HRESULT hr = m_menuBand->_CallCBWithItemId(rclick->dwItemSpec, SMC_GETOBJECT, reinterpret_cast(&IID_IContextMenu), reinterpret_cast(&contextMenu)); + if (hr != S_OK) + return hr; + + return DoContextMenu(contextMenu); +} + +HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ + HRESULT hr; + hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); + if (FAILED(hr)) + return hr; + + // in case the clicked item has a submenu, we do not need to execute the item + if (hr == S_FALSE) + return hr; + + return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0); +} + +HRESULT CMenuStaticToolbar::PopupItem(UINT uItem) +{ + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); + if (index < 0) + return E_FAIL; + + TBBUTTON btn = { 0 }; + SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn)); + + SMINFO * nfo = reinterpret_cast(btn.dwData); + if (!nfo) + return E_FAIL; + + if (nfo->dwFlags&SMIF_TRACKPOPUP) + { + return PopupSubMenu(index, m_hmenu); + } + else + { + CComPtr shellMenu; + HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast(&IID_IShellMenu), reinterpret_cast(&shellMenu)); + if (FAILED(hr)) + return hr; + + return PopupSubMenu(uItem, index, shellMenu); + } +} + +HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem) +{ + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); + if (index < 0) + return E_FAIL; + return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE; +} + +CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) : + CMenuToolbarBase(menuBand, TRUE), + m_shellFolder(NULL) +{ +} + +CMenuSFToolbar::~CMenuSFToolbar() +{ +} + +HRESULT CMenuSFToolbar::FillToolbar() +{ + HRESULT hr; + int i = 0; + PWSTR MenuString; + + IEnumIDList * eidl; + m_shellFolder->EnumObjects(m_hwndToolbar, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &eidl); + + LPITEMIDLIST item = static_cast(CoTaskMemAlloc(sizeof(ITEMIDLIST))); + ULONG fetched; + while ((hr = eidl->Next(1, &item, &fetched)) == S_OK) + { + INT index = 0; + INT indexOpen = 0; + + TBBUTTON tbb = { 0 }; + tbb.fsState = TBSTATE_ENABLED; + tbb.fsStyle = 0; + + CComPtr psi; + hr = SHCreateShellItem(NULL, m_shellFolder, item, &psi); + if (FAILED(hr)) + return hr; + + hr = psi->GetDisplayName(SIGDN_NORMALDISPLAY, &MenuString); + if (FAILED(hr)) + return hr; + + index = SHMapPIDLToSystemImageListIndex(m_shellFolder, item, &indexOpen); + + SFGAOF attrs; + hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); + + if (attrs != 0) + { + tbb.fsStyle |= BTNS_DROPDOWN; + } + + tbb.idCommand = ++i; + tbb.iString = (INT_PTR) MenuString; + tbb.iBitmap = index; + tbb.dwData = reinterpret_cast(ILClone(item)); + // FIXME: remove before deleting the toolbar or it will leak + + SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); + HeapFree(GetProcessHeap(), 0, MenuString); + + } + CoTaskMemFree(item); + + // If no items were added, show the "empty" placeholder + if (i == 0) + { + TBBUTTON tbb = { 0 }; + PCWSTR MenuString = L"(Empty)"; + + tbb.fsState = 0/*TBSTATE_DISABLED*/; + tbb.fsStyle = 0; + tbb.iString = (INT_PTR) MenuString; + tbb.iBitmap = -1; + + SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast(&tbb)); + + return S_OK; + } + + return hr; +} + +HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags) +{ + m_shellFolder = psf; + m_idList = pidlFolder; + m_hKey = hKey; + m_dwMenuFlags = dwFlags; + return S_OK; +} + +HRESULT CMenuSFToolbar::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv) +{ + HRESULT hr; + + hr = m_shellFolder->QueryInterface(riid, ppv); + if (FAILED(hr)) + return hr; + + if (pdwFlags) + *pdwFlags = m_dwMenuFlags; + + if (ppidl) + { + LPITEMIDLIST pidl = NULL; + + if (m_idList) + { + pidl = ILClone(m_idList); + if (!pidl) + { + (*(IUnknown**) ppv)->Release(); + return E_FAIL; + } + } + + *ppidl = pidl; + } + + return hr; +} + +LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex) +{ + TBBUTTONINFO info = { 0 }; + info.cbSize = sizeof(TBBUTTONINFO); + info.dwMask = 0; + int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast(&info)); + if (index < 0) + return NULL; + + if (pIndex) + *pIndex = index; + + TBBUTTON btn = { 0 }; + if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast(&btn))) + return NULL; + + return reinterpret_cast(btn.dwData); +} + +HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick) +{ + HRESULT hr; + CComPtr contextMenu; + LPCITEMIDLIST pidl = reinterpret_cast(rclick->dwItemData); + + hr = m_shellFolder->GetUIObjectOf(m_hwndToolbar, 1, &pidl, IID_IContextMenu, NULL, reinterpret_cast(&contextMenu)); + if (hr != S_OK) + return hr; + + return DoContextMenu(contextMenu); +} + +HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ + HRESULT hr; + hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); + if (FAILED(hr)) + return hr; + + // in case the clicked item has a submenu, we do not need to execute the item + if (hr == S_FALSE) + return hr; + + return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0); +} + +HRESULT CMenuSFToolbar::PopupItem(UINT uItem) +{ + HRESULT hr; + UINT uId; + UINT uIdAncestor; + DWORD flags; + int index; + CComPtr psmc; + CComPtr shellMenu; + + LPITEMIDLIST pidl = GetPidlFromId(uItem, &index); + + if (!pidl) + return E_FAIL; + +#if USE_SYSTEM_MENUBAND + hr = CoCreateInstance(CLSID_MenuBand, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IShellMenu, &shellMenu)); +#else + hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu)); +#endif + if (FAILED(hr)) + return hr; +#if WRAP_MENUBAND + hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu)); + if (FAILED(hr)) + return hr; +#endif + + m_menuBand->GetMenuInfo(&psmc, &uId, &uIdAncestor, &flags); + + // FIXME: not sure what to use as uId/uIdAncestor here + hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL); + if (FAILED(hr)) + return hr; + + CComPtr childFolder; + hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder)); + if (FAILED(hr)) + return hr; + + hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0); + if (FAILED(hr)) + return hr; + + return PopupSubMenu(uItem, index, shellMenu); +} + +HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem) +{ + HRESULT hr; + CComPtr psi; + hr = SHCreateShellItem(NULL, m_shellFolder, GetPidlFromId(uItem), &psi); + if (FAILED(hr)) + return S_FALSE; + + SFGAOF attrs; + hr = psi->GetAttributes(SFGAO_FOLDER, &attrs); + if (FAILED(hr)) + return hr; + + return (attrs != 0) ? S_OK : S_FALSE; +} diff --git a/base/shell/rshell/CMenuToolbars.h b/base/shell/rshell/CMenuToolbars.h new file mode 100644 index 00000000000..4ad19a84109 --- /dev/null +++ b/base/shell/rshell/CMenuToolbars.h @@ -0,0 +1,119 @@ +/* +* Shell Menu Band +* +* Copyright 2014 David Quintana +* +* 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 St, Fifth Floor, Boston, MA 02110-1301, USA +*/ +#pragma once + +class CMenuBand; +class CMenuFocusManager; + +class CMenuToolbarBase +{ +private: + HWND m_hwnd; // May be the pager + +protected: + CMenuBand * m_menuBand; + HWND m_hwndToolbar; + DWORD m_dwMenuFlags; + INT m_hotItem; + WNDPROC m_SubclassOld; + BOOL m_hasIdealSize; + SIZE m_idealSize; + BOOL m_usePager; + +private: + static LRESULT CALLBACK s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +public: + CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager); + virtual ~CMenuToolbarBase() {} + + HRESULT IsWindowOwner(HWND hwnd); + HRESULT CreateToolbar(HWND hwndParent, DWORD dwFlags); + HRESULT GetWindow(HWND *phwnd); + HRESULT ShowWindow(BOOL fShow); + HRESULT Close(); + + virtual HRESULT FillToolbar() = 0; + virtual HRESULT PopupItem(UINT uItem) = 0; + virtual HRESULT HasSubMenu(UINT uItem) = 0; + virtual HRESULT OnContextMenu(NMMOUSE * rclick) = 0; + virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + + HRESULT PopupSubMenu(UINT itemId, UINT index, IShellMenu* childShellMenu); + HRESULT PopupSubMenu(UINT index, HMENU menu); + HRESULT DoContextMenu(IContextMenu* contextMenu); + + HRESULT ChangeHotItem(DWORD changeType); + HRESULT OnHotItemChange(const NMTBHOTITEM * hot); + + HRESULT GetIdealSize(SIZE& size); + HRESULT SetPosSize(int x, int y, int cx, int cy); + + void InvalidateDraw(); + +protected: + LRESULT CALLBACK SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; + +class CMenuStaticToolbar : + public CMenuToolbarBase +{ +private: + HMENU m_hmenu; + +public: + CMenuStaticToolbar(CMenuBand *menuBand); + virtual ~CMenuStaticToolbar() {} + + HRESULT SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags); + HRESULT GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags); + + virtual HRESULT FillToolbar(); + virtual HRESULT PopupItem(UINT uItem); + virtual HRESULT HasSubMenu(UINT uItem); + virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT OnContextMenu(NMMOUSE * rclick); + +}; + +class CMenuSFToolbar : + public CMenuToolbarBase +{ +private: + IShellFolder * m_shellFolder; + LPCITEMIDLIST m_idList; + HKEY m_hKey; + +public: + CMenuSFToolbar(CMenuBand *menuBand); + virtual ~CMenuSFToolbar(); + + HRESULT SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags); + HRESULT GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv); + + virtual HRESULT FillToolbar(); + 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 = NULL); +}; -- 2.17.1