4 * Copyright 2014 David Quintana
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "shellmenu.h"
22 #include <commoncontrols.h>
23 #include <shlwapi_undoc.h>
25 #include "CMenuBand.h"
26 #include "CMenuToolbars.h"
27 #include "CMenuFocusManager.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand
);
33 #define UNIMPLEMENTED TRACE("%s is UNIMPLEMENTED!\n", __FUNCTION__)
35 CMenuBand::CMenuBand() :
36 m_staticToolbar(NULL
),
41 m_subMenuParent(NULL
),
47 m_topLevelWindow(NULL
),
57 m_focusManager
= CMenuFocusManager::AcquireManager();
60 CMenuBand::~CMenuBand()
62 CMenuFocusManager::ReleaseManager(m_focusManager
);
64 delete m_staticToolbar
;
71 HRESULT STDMETHODCALLTYPE
CMenuBand::Initialize(
72 IShellMenuCallback
*psmc
,
80 m_uIdAncestor
= uIdAncestor
;
85 _CallCB(SMC_CREATE
, 0, reinterpret_cast<LPARAM
>(&m_UserData
));
91 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenuInfo(
92 IShellMenuCallback
**ppsmc
,
97 if (!pdwFlags
) // maybe?
111 *puIdAncestor
= m_uIdAncestor
;
113 *pdwFlags
= m_dwFlags
;
118 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenu(
125 TRACE("CMenuBand::SetMenu called, hmenu=%p; hwnd=%p, flags=%x\n", hmenu
, hwnd
, dwFlags
);
127 BOOL created
= FALSE
;
129 if (m_hmenu
&& m_hmenu
!= hmenu
)
131 DestroyMenu(m_hmenu
);
138 if (m_hmenu
&& m_staticToolbar
== NULL
)
140 m_staticToolbar
= new CMenuStaticToolbar(this);
146 hr
= m_staticToolbar
->SetMenu(hmenu
, hwnd
, dwFlags
);
147 if (FAILED_UNEXPECTEDLY(hr
))
155 hr
= m_site
->GetWindow(&hwndParent
);
156 if (FAILED_UNEXPECTEDLY(hr
))
161 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
162 if (FAILED_UNEXPECTEDLY(hr
))
165 hr
= m_staticToolbar
->FillToolbar();
169 hr
= m_staticToolbar
->FillToolbar(TRUE
);
176 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenu(
181 if (m_staticToolbar
== NULL
)
184 return m_staticToolbar
->GetMenu(phmenu
, phwnd
, pdwFlags
);
187 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSite(IUnknown
*pUnkSite
)
194 if (pUnkSite
== NULL
)
198 hr
= pUnkSite
->QueryInterface(IID_PPV_ARG(IOleWindow
, &m_site
));
199 if (FAILED_UNEXPECTEDLY(hr
))
202 hr
= m_site
->GetWindow(&hwndParent
);
203 if (FAILED_UNEXPECTEDLY(hr
))
206 if (!::IsWindow(hwndParent
))
209 if (m_staticToolbar
!= NULL
)
211 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
212 if (FAILED_UNEXPECTEDLY(hr
))
215 hr
= m_staticToolbar
->FillToolbar();
216 if (FAILED_UNEXPECTEDLY(hr
))
220 if (m_SFToolbar
!= NULL
)
222 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
223 if (FAILED_UNEXPECTEDLY(hr
))
226 hr
= m_SFToolbar
->FillToolbar();
227 if (FAILED_UNEXPECTEDLY(hr
))
231 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IMenuPopup
, &m_subMenuParent
));
232 if (hr
!= E_NOINTERFACE
&& FAILED_UNEXPECTEDLY(hr
))
235 CComPtr
<IOleWindow
> pTopLevelWindow
;
236 hr
= IUnknown_QueryService(m_site
, SID_STopLevelBrowser
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
239 hr
= pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
240 if (FAILED_UNEXPECTEDLY(hr
))
245 m_topLevelWindow
= hwndParent
;
251 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSite(REFIID riid
, PVOID
*ppvSite
)
256 return m_site
->QueryInterface(riid
, ppvSite
);
259 HRESULT STDMETHODCALLTYPE
CMenuBand::GetWindow(HWND
*phwnd
)
261 if (m_SFToolbar
!= NULL
)
262 return m_SFToolbar
->GetWindow(phwnd
);
264 if (m_staticToolbar
!= NULL
)
265 return m_staticToolbar
->GetWindow(phwnd
);
267 if (phwnd
) *phwnd
= NULL
;
272 HRESULT STDMETHODCALLTYPE
CMenuBand::OnPosRectChangeDB(RECT
*prc
)
274 SIZE maxStatic
= { 0 };
275 SIZE maxShlFld
= { 0 };
278 if (m_staticToolbar
!= NULL
)
279 hr
= m_staticToolbar
->GetSizes(NULL
, &maxStatic
, NULL
);
280 if (FAILED_UNEXPECTEDLY(hr
))
283 if (m_SFToolbar
!= NULL
)
284 hr
= m_SFToolbar
->GetSizes(NULL
, &maxShlFld
, NULL
);
285 if (FAILED_UNEXPECTEDLY(hr
))
288 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
291 int sy
= min(prc
->bottom
- prc
->top
, maxStatic
.cy
+ maxShlFld
.cy
);
293 int syStatic
= maxStatic
.cy
;
294 int syShlFld
= sy
- syStatic
;
296 // TODO: Windows has a more complex system to decide ordering.
297 // Because we only support two toolbars at once, this is enough for us.
300 // Static menu on top
303 m_SFToolbar
->SetPosSize(
306 prc
->right
- prc
->left
,
311 m_staticToolbar
->SetPosSize(
314 prc
->right
- prc
->left
,
320 // Folder menu on top
323 m_SFToolbar
->SetPosSize(
326 prc
->right
- prc
->left
,
331 m_staticToolbar
->SetPosSize(
334 prc
->right
- prc
->left
,
342 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBandInfo(
347 SIZE minStatic
= { 0 };
348 SIZE minShlFld
= { 0 };
349 SIZE maxStatic
= { 0 };
350 SIZE maxShlFld
= { 0 };
351 SIZE intStatic
= { 0 };
352 SIZE intShlFld
= { 0 };
356 if (m_staticToolbar
!= NULL
)
357 hr
= m_staticToolbar
->GetSizes(&minStatic
, &maxStatic
, &intStatic
);
358 if (FAILED_UNEXPECTEDLY(hr
))
361 if (m_SFToolbar
!= NULL
)
362 hr
= m_SFToolbar
->GetSizes(&minShlFld
, &maxShlFld
, &intShlFld
);
363 if (FAILED_UNEXPECTEDLY(hr
))
366 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
369 if (m_dwFlags
& SMINIT_VERTICAL
)
371 pdbi
->ptMinSize
.x
= max(minStatic
.cx
, minShlFld
.cx
) + 20;
372 pdbi
->ptMinSize
.y
= minStatic
.cy
+ minShlFld
.cy
;
373 pdbi
->ptMaxSize
.x
= max(maxStatic
.cx
, maxShlFld
.cx
) + 20;
374 pdbi
->ptMaxSize
.y
= maxStatic
.cy
+ maxShlFld
.cy
;
375 pdbi
->dwModeFlags
= DBIMF_VARIABLEHEIGHT
;
379 pdbi
->ptMinSize
.x
= minStatic
.cx
+ minShlFld
.cx
;
380 pdbi
->ptMinSize
.y
= max(minStatic
.cy
, minShlFld
.cy
);
381 pdbi
->ptMaxSize
.x
= maxStatic
.cx
+ maxShlFld
.cx
;
382 pdbi
->ptMaxSize
.y
= max(maxStatic
.cy
, maxShlFld
.cy
);
384 pdbi
->ptIntegral
.x
= max(intStatic
.cx
, intShlFld
.cx
);
385 pdbi
->ptIntegral
.y
= max(intStatic
.cy
, intShlFld
.cy
);
386 pdbi
->ptActual
= pdbi
->ptMinSize
;
391 HRESULT STDMETHODCALLTYPE
CMenuBand::ShowDW(BOOL fShow
)
400 if (m_staticToolbar
!= NULL
)
402 hr
= m_staticToolbar
->ShowDW(fShow
);
403 if (FAILED_UNEXPECTEDLY(hr
))
407 if (m_SFToolbar
!= NULL
)
409 hr
= m_SFToolbar
->ShowDW(fShow
);
410 if (FAILED_UNEXPECTEDLY(hr
))
416 hr
= _CallCB(SMC_INITMENU
, 0, 0);
417 if (FAILED_UNEXPECTEDLY(hr
))
420 else if (m_parentBand
)
422 m_parentBand
->SetClient(NULL
);
425 if (_IsPopup() == S_OK
)
428 hr
= m_focusManager
->PushMenuPopup(this);
430 hr
= m_focusManager
->PopMenuPopup(this);
435 hr
= m_focusManager
->PushMenuBar(this);
437 hr
= m_focusManager
->PopMenuBar(this);
443 HRESULT STDMETHODCALLTYPE
CMenuBand::CloseDW(DWORD dwReserved
)
447 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
452 TRACE("Child object should have removed itself.\n");
457 if (m_staticToolbar
!= NULL
)
459 m_staticToolbar
->Close();
462 if (m_SFToolbar
!= NULL
)
464 m_SFToolbar
->Close();
467 if (m_site
) m_site
.Release();
468 if (m_subMenuChild
) m_subMenuChild
.Release();
469 if (m_subMenuParent
) m_subMenuParent
.Release();
470 if (m_childBand
) m_childBand
.Release();
471 if (m_parentBand
) m_parentBand
.Release();
476 HRESULT STDMETHODCALLTYPE
CMenuBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
482 hr
= m_subMenuParent
->SetSubMenu(this, fActivate
);
483 if (FAILED_UNEXPECTEDLY(hr
))
489 CComPtr
<IOleWindow
> pTopLevelWindow
;
490 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
491 if (FAILED_UNEXPECTEDLY(hr
))
494 hr
= pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
495 if (FAILED_UNEXPECTEDLY(hr
))
500 m_topLevelWindow
= NULL
;
506 HRESULT STDMETHODCALLTYPE
CMenuBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
511 if (IsEqualGUID(*pguidCmdGroup
, CLSID_MenuBand
))
513 if (nCmdID
== 16) // set (big) icon size
515 this->m_useBigIcons
= nCmdexecopt
== 2;
518 else if (nCmdID
== 19) // popup-related
522 else if (nCmdID
== 5) // select an item
524 if (nCmdexecopt
== 0) // first
526 _KeyboardItemChange(VK_HOME
);
530 _KeyboardItemChange(VK_END
);
542 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
544 if (IsEqualIID(guidService
, SID_SMenuBandChild
) ||
545 IsEqualIID(guidService
, SID_SMenuBandBottom
) ||
546 IsEqualIID(guidService
, SID_SMenuBandBottomSelected
))
547 return this->QueryInterface(riid
, ppvObject
);
548 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService
));
549 return E_NOINTERFACE
;
552 HRESULT STDMETHODCALLTYPE
CMenuBand::Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
)
558 HRESULT STDMETHODCALLTYPE
CMenuBand::OnSelect(DWORD dwSelectType
)
560 // When called from outside, this is straightforward:
561 // Things that a submenu needs to know, are spread down, and
562 // things that the parent needs to know, are spread up. No drama.
563 // The fun is in _MenuItemSelect (internal method).
564 switch (dwSelectType
)
566 case MPOS_CHILDTRACKING
:
567 if (!m_subMenuParent
)
569 // TODO: Cancel timers?
570 return m_subMenuParent
->OnSelect(dwSelectType
);
571 case MPOS_SELECTLEFT
:
573 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
574 if (!m_subMenuParent
)
576 return m_subMenuParent
->OnSelect(dwSelectType
);
577 case MPOS_SELECTRIGHT
:
578 if (!m_subMenuParent
)
580 return m_subMenuParent
->OnSelect(dwSelectType
);
582 case MPOS_FULLCANCEL
:
584 m_subMenuChild
->OnSelect(dwSelectType
);
585 if (!m_subMenuParent
)
587 return m_subMenuParent
->OnSelect(dwSelectType
);
588 case MPOS_CANCELLEVEL
:
590 m_subMenuChild
->OnSelect(dwSelectType
);
596 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
)
602 // Used by the focus manager to update the child band pointer
603 HRESULT
CMenuBand::_SetChildBand(CMenuBand
* child
)
608 _ChangePopupItem(NULL
, -1);
613 // User by the focus manager to update the parent band pointer
614 HRESULT
CMenuBand::_SetParentBand(CMenuBand
* parent
)
616 m_parentBand
= parent
;
620 HRESULT
CMenuBand::_IsPopup()
622 return !(m_dwFlags
& SMINIT_VERTICAL
);
625 HRESULT
CMenuBand::_IsTracking()
627 return m_popupBar
!= NULL
;
630 HRESULT STDMETHODCALLTYPE
CMenuBand::SetClient(IUnknown
*punkClient
)
632 CComPtr
<IMenuPopup
> child
= m_subMenuChild
;
634 m_subMenuChild
= NULL
;
638 IUnknown_SetSite(child
, NULL
);
647 return punkClient
->QueryInterface(IID_PPV_ARG(IMenuPopup
, &m_subMenuChild
));
650 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClient(IUnknown
**ppunkClient
)
658 m_subMenuChild
->AddRef();
659 *ppunkClient
= m_subMenuChild
;
665 HRESULT STDMETHODCALLTYPE
CMenuBand::IsMenuMessage(MSG
*pmsg
)
670 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
)
672 if (pmsg
->message
== WM_ACTIVATE
&& _IsPopup() == S_FALSE
)
675 m_staticToolbar
->Invalidate();
677 m_SFToolbar
->Invalidate();
683 HRESULT STDMETHODCALLTYPE
CMenuBand::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
688 if (m_SFToolbar
== NULL
)
690 m_SFToolbar
= new CMenuSFToolbar(this);
693 HRESULT hr
= m_SFToolbar
->SetShellFolder(psf
, pidlFolder
, hKey
, dwFlags
);
694 if (FAILED_UNEXPECTEDLY(hr
))
697 m_shellBottom
= (dwFlags
& SMSET_BOTTOM
) != 0;
703 hr
= m_site
->GetWindow(&hwndParent
);
704 if (FAILED_UNEXPECTEDLY(hr
))
707 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
708 if (FAILED_UNEXPECTEDLY(hr
))
711 hr
= m_SFToolbar
->FillToolbar();
717 HRESULT STDMETHODCALLTYPE
CMenuBand::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
720 return m_SFToolbar
->GetShellFolder(pdwFlags
, ppidl
, riid
, ppv
);
724 HRESULT STDMETHODCALLTYPE
CMenuBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
729 if (uMsg
== WM_WININICHANGE
&& wParam
== SPI_SETFLATMENU
)
732 SystemParametersInfo(SPI_GETFLATMENU
, 0, &bFlatMenus
, 0);
733 AdjustForTheme(bFlatMenus
);
736 m_staticToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
739 m_SFToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
744 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
746 return m_staticToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
749 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
751 return m_SFToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
757 HRESULT STDMETHODCALLTYPE
CMenuBand::IsWindowOwner(HWND hWnd
)
759 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
762 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
768 HRESULT
CMenuBand::_CallCBWithItemId(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
770 return _CallCB(uMsg
, wParam
, lParam
, id
);
773 HRESULT
CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
775 return _CallCB(uMsg
, wParam
, lParam
, 0, pidl
);
778 HRESULT
CMenuBand::_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
, LPITEMIDLIST pidl
)
783 SMDATA smData
= { 0 };
784 smData
.punk
= static_cast<IShellMenu2
*>(this);
786 smData
.uIdParent
= m_uId
;
787 smData
.uIdAncestor
= m_uIdAncestor
;
788 smData
.pidlItem
= pidl
;
789 smData
.hwnd
= m_menuOwner
? m_menuOwner
: m_topLevelWindow
;
790 smData
.hmenu
= m_hmenu
;
792 m_SFToolbar
->GetShellFolder(NULL
, &smData
.pidlFolder
, IID_PPV_ARG(IShellFolder
, &smData
.psf
));
793 HRESULT hr
= m_psmc
->CallbackSM(&smData
, uMsg
, wParam
, lParam
);
794 ILFree(smData
.pidlFolder
);
796 smData
.psf
->Release();
800 HRESULT
CMenuBand::_TrackSubMenu(HMENU popup
, INT x
, INT y
, RECT
& rcExclude
)
802 TPMPARAMS params
= { sizeof(TPMPARAMS
), rcExclude
};
803 UINT flags
= TPM_VERPOSANIMATION
| TPM_VERTICAL
| TPM_LEFTALIGN
;
804 HWND hwnd
= m_menuOwner
? m_menuOwner
: m_topLevelWindow
;
806 m_trackedPopup
= popup
;
807 m_trackedHwnd
= hwnd
;
809 m_focusManager
->PushTrackedPopup(popup
);
810 ::TrackPopupMenuEx(popup
, flags
, x
, y
, hwnd
, ¶ms
);
811 m_focusManager
->PopTrackedPopup(popup
);
813 m_trackedPopup
= NULL
;
814 m_trackedHwnd
= NULL
;
816 _DisableMouseTrack(FALSE
);
821 HRESULT
CMenuBand::_TrackContextMenu(IContextMenu
* contextMenu
, INT x
, INT y
)
826 // Ensure that the menu doesn't disappear on us
827 CComPtr
<IContextMenu
> ctxMenu
= contextMenu
;
829 HMENU popup
= CreatePopupMenu();
834 TRACE("Before Query\n");
835 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
836 if (FAILED_UNEXPECTEDLY(hr
))
838 TRACE("Query failed\n");
843 HWND hwnd
= m_menuOwner
? m_menuOwner
: m_topLevelWindow
;
845 m_focusManager
->PushTrackedPopup(popup
);
847 TRACE("Before Tracking\n");
848 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, hwnd
, NULL
);
850 m_focusManager
->PopTrackedPopup(popup
);
854 _MenuItemSelect(MPOS_FULLCANCEL
);
856 TRACE("Before InvokeCommand\n");
857 CMINVOKECOMMANDINFO cmi
= { 0 };
858 cmi
.cbSize
= sizeof(cmi
);
859 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
861 hr
= contextMenu
->InvokeCommand(&cmi
);
862 TRACE("InvokeCommand returned hr=%08x\n", hr
);
866 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
874 HRESULT
CMenuBand::_GetTopLevelWindow(HWND
*topLevel
)
876 *topLevel
= m_topLevelWindow
;
880 HRESULT
CMenuBand::_ChangeHotItem(CMenuToolbarBase
* tb
, INT id
, DWORD dwFlags
)
882 if (m_hotBar
== tb
&& m_hotItem
== id
)
885 TRACE("Hot item changed from %p %p, to %p %p\n", m_hotBar
, m_hotItem
, tb
, id
);
891 if (m_staticToolbar
) m_staticToolbar
->ChangeHotItem(tb
, id
, dwFlags
);
892 if (m_SFToolbar
) m_SFToolbar
->ChangeHotItem(tb
, id
, dwFlags
);
894 _MenuItemSelect(MPOS_CHILDTRACKING
);
899 HRESULT
CMenuBand::_ChangePopupItem(CMenuToolbarBase
* tb
, INT id
)
901 TRACE("Popup item changed from %p %p, to %p %p\n", m_popupBar
, m_popupItem
, tb
, id
);
905 if (m_staticToolbar
) m_staticToolbar
->ChangePopupItem(tb
, id
);
906 if (m_SFToolbar
) m_SFToolbar
->ChangePopupItem(tb
, id
);
911 HRESULT
CMenuBand::_KeyboardItemChange(DWORD change
)
914 CMenuToolbarBase
*tb
= m_hotBar
;
918 // If no hot item was selected choose the appropriate toolbar
919 if (change
== VK_UP
|| change
== VK_END
)
922 tb
= m_staticToolbar
;
926 else if (change
== VK_DOWN
|| change
== VK_HOME
)
931 tb
= m_staticToolbar
;
935 // Ask the first toolbar to change
936 hr
= tb
->KeyboardItemChange(change
);
941 // Select the second toolbar based on the first
942 if (tb
== m_SFToolbar
&& m_staticToolbar
)
943 tb
= m_staticToolbar
;
944 else if (m_SFToolbar
)
950 // Ask the second toolbar to change
951 return tb
->KeyboardItemChange(change
== VK_DOWN
? VK_HOME
: VK_END
);
954 HRESULT
CMenuBand::_MenuItemSelect(DWORD changeType
)
956 // Needed to prevent the this point from vanishing mid-function
957 CComPtr
<CMenuBand
> safeThis
= this;
960 if (m_dwFlags
& SMINIT_VERTICAL
)
966 return _KeyboardItemChange(changeType
);
968 // TODO: Left/Right across multi-column menus, if they ever work.
970 changeType
= MPOS_SELECTLEFT
;
973 changeType
= MPOS_SELECTRIGHT
;
979 // In horizontal menubars, left/right are equivalent to vertical's up/down
983 hr
= _KeyboardItemChange(VK_UP
);
987 hr
= _KeyboardItemChange(VK_DOWN
);
993 // In this context, the parent is the CMenuDeskBar, so when it bubbles upward,
994 // it is notifying the deskbar, and not the the higher-level menu.
995 // Same for the child: since it points to a CMenuDeskBar, it's not just recursing.
1000 CMenuToolbarBase
* tb
= m_hotBar
;
1001 int item
= m_hotItem
;
1002 tb
->PrepareExecuteItem(item
);
1003 if (m_subMenuParent
)
1005 m_subMenuParent
->OnSelect(changeType
);
1007 TRACE("Menu closed, executing item...\n");
1011 case MPOS_SELECTLEFT
:
1012 if (m_parentBand
&& m_parentBand
->_IsPopup()==S_FALSE
)
1013 return m_parentBand
->_MenuItemSelect(VK_LEFT
);
1015 return m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
1016 if (!m_subMenuParent
)
1018 return m_subMenuParent
->OnSelect(MPOS_CANCELLEVEL
);
1020 case MPOS_SELECTRIGHT
:
1021 if (m_hotBar
&& m_hotItem
>= 0 && m_hotBar
->PopupItem(m_hotItem
, TRUE
) == S_OK
)
1024 return m_parentBand
->_MenuItemSelect(VK_RIGHT
);
1025 if (!m_subMenuParent
)
1027 return m_subMenuParent
->OnSelect(MPOS_SELECTRIGHT
);
1030 if (!m_subMenuParent
)
1032 return m_subMenuParent
->OnSelect(changeType
);
1038 HRESULT
CMenuBand::_CancelCurrentPopup()
1042 HRESULT hr
= m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
1048 ::SendMessage(m_trackedHwnd
, WM_CANCELMODE
, 0, 0);
1055 HRESULT
CMenuBand::_OnPopupSubMenu(IShellMenu
* childShellMenu
, POINTL
* pAt
, RECTL
* pExclude
, BOOL keyInitiated
)
1058 CComPtr
<IBandSite
> pBandSite
;
1059 CComPtr
<IDeskBar
> pDeskBar
;
1061 // Create the necessary objects
1062 hr
= CMenuSite_CreateInstance(IID_PPV_ARG(IBandSite
, &pBandSite
));
1063 if (FAILED_UNEXPECTEDLY(hr
))
1066 hr
= CMenuDeskBar_CreateInstance(IID_PPV_ARG(IDeskBar
, &pDeskBar
));
1067 if (FAILED_UNEXPECTEDLY(hr
))
1070 hr
= pDeskBar
->SetClient(pBandSite
);
1071 if (FAILED_UNEXPECTEDLY(hr
))
1074 hr
= pBandSite
->AddBand(childShellMenu
);
1075 if (FAILED_UNEXPECTEDLY(hr
))
1079 CComPtr
<IMenuPopup
> popup
;
1080 hr
= pDeskBar
->QueryInterface(IID_PPV_ARG(IMenuPopup
, &popup
));
1081 if (FAILED_UNEXPECTEDLY(hr
))
1084 m_subMenuChild
= popup
;
1086 if (m_subMenuParent
)
1087 IUnknown_SetSite(popup
, m_subMenuParent
);
1089 IUnknown_SetSite(popup
, m_site
);
1091 DWORD flags
= MPPF_RIGHT
;
1093 if (keyInitiated
&& m_dwFlags
& SMINIT_VERTICAL
)
1094 flags
|= MPPF_INITIALSELECT
;
1096 popup
->Popup(pAt
, pExclude
, flags
);
1101 HRESULT
CMenuBand::_BeforeCancelPopup()
1103 if (m_staticToolbar
)
1104 m_staticToolbar
->BeforeCancelPopup();
1106 m_SFToolbar
->BeforeCancelPopup();
1110 HRESULT
CMenuBand::_DisableMouseTrack(BOOL bDisable
)
1112 if (m_staticToolbar
)
1113 m_staticToolbar
->DisableMouseTrack(bDisable
);
1115 m_SFToolbar
->DisableMouseTrack(bDisable
);
1119 HRESULT
CMenuBand::_KillPopupTimers()
1122 if (m_staticToolbar
)
1123 hr
= m_staticToolbar
->KillPopupTimer();
1128 hr
= m_SFToolbar
->KillPopupTimer();
1133 HRESULT
CMenuBand::_MenuBarMouseDown(HWND hwnd
, INT item
, BOOL isLButton
)
1135 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hwnd
) == S_OK
)
1136 m_staticToolbar
->MenuBarMouseDown(item
, isLButton
);
1137 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hwnd
) == S_OK
)
1138 m_SFToolbar
->MenuBarMouseDown(item
, isLButton
);
1142 HRESULT
CMenuBand::_MenuBarMouseUp(HWND hwnd
, INT item
, BOOL isLButton
)
1144 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hwnd
) == S_OK
)
1145 m_staticToolbar
->MenuBarMouseUp(item
, isLButton
);
1146 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hwnd
) == S_OK
)
1147 m_SFToolbar
->MenuBarMouseUp(item
, isLButton
);
1151 HRESULT
CMenuBand::_HasSubMenu()
1153 return m_popupBar
? S_OK
: S_FALSE
;
1156 HRESULT
CMenuBand::AdjustForTheme(BOOL bFlatStyle
)
1158 return IUnknown_QueryServiceExec(m_site
, SID_SMenuPopup
, &CGID_MenuDeskBar
, 4, bFlatStyle
, NULL
, NULL
);
1161 HRESULT STDMETHODCALLTYPE
CMenuBand::InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
)
1167 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(LPSMDATA psmd
)
1173 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
)
1179 HRESULT STDMETHODCALLTYPE
CMenuBand::ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
1185 HRESULT STDMETHODCALLTYPE
CMenuBand::ContextSensitiveHelp(BOOL fEnterMode
)
1191 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSubMenu(THIS
)
1197 HRESULT STDMETHODCALLTYPE
CMenuBand::SetToolbar(THIS
)
1203 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMinWidth(THIS
)
1209 HRESULT STDMETHODCALLTYPE
CMenuBand::SetNoBorder(THIS
)
1215 HRESULT STDMETHODCALLTYPE
CMenuBand::SetTheme(THIS
)
1221 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTop(THIS
)
1227 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBottom(THIS
)
1233 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTracked(THIS
)
1239 HRESULT STDMETHODCALLTYPE
CMenuBand::GetParentSite(THIS
)
1245 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(THIS
)
1251 HRESULT STDMETHODCALLTYPE
CMenuBand::DoDefaultAction(THIS
)
1257 HRESULT STDMETHODCALLTYPE
CMenuBand::IsEmpty(THIS
)
1263 HRESULT STDMETHODCALLTYPE
CMenuBand::HasFocusIO()
1270 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg
)
1272 // TODO: Alt down -> toggle menu focus
1276 HRESULT STDMETHODCALLTYPE
CMenuBand::IsDirty()
1282 HRESULT STDMETHODCALLTYPE
CMenuBand::Load(IStream
*pStm
)
1288 HRESULT STDMETHODCALLTYPE
CMenuBand::Save(IStream
*pStm
, BOOL fClearDirty
)
1294 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
1300 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClassID(CLSID
*pClassID
)
1306 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)
1313 HRESULT WINAPI
RSHELL_CMenuBand_CreateInstance(REFIID riid
, LPVOID
*ppv
)
1315 return ShellObjectCreator
<CMenuBand
>(riid
, ppv
);