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
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 DbgPrint("%s is UNIMPLEMENTED!\n", __FUNCTION__)
36 HRESULT WINAPI
CMenuBand_Constructor(REFIID riid
, LPVOID
*ppv
)
40 CMenuBand
* site
= new CComObject
<CMenuBand
>();
45 HRESULT hr
= site
->QueryInterface(riid
, ppv
);
47 if (FAILED_UNEXPECTEDLY(hr
))
53 CMenuBand::CMenuBand() :
54 m_staticToolbar(NULL
),
62 m_topLevelWindow(NULL
),
66 m_focusManager
= CMenuFocusManager::AcquireManager();
69 CMenuBand::~CMenuBand()
71 CMenuFocusManager::ReleaseManager(m_focusManager
);
74 delete m_staticToolbar
;
80 HRESULT STDMETHODCALLTYPE
CMenuBand::Initialize(
81 IShellMenuCallback
*psmc
,
89 m_uIdAncestor
= uIdAncestor
;
94 _CallCB(SMC_CREATE
, 0, reinterpret_cast<LPARAM
>(&m_UserData
));
100 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenuInfo(
101 IShellMenuCallback
**ppsmc
,
106 if (!pdwFlags
) // maybe?
116 *puIdAncestor
= m_uIdAncestor
;
118 *pdwFlags
= m_dwFlags
;
123 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenu(
128 DbgPrint("CMenuBand::SetMenu called, hmenu=%p; hwnd=%p, flags=%x\n", hmenu
, hwnd
, dwFlags
);
130 BOOL created
= FALSE
;
132 if (m_staticToolbar
== NULL
)
134 m_staticToolbar
= new CMenuStaticToolbar(this);
140 HRESULT hr
= m_staticToolbar
->SetMenu(hmenu
, hwnd
, dwFlags
);
141 if (FAILED_UNEXPECTEDLY(hr
))
148 hr
= m_site
->GetWindow(&hwndParent
);
149 if (FAILED_UNEXPECTEDLY(hr
))
154 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
155 if (FAILED_UNEXPECTEDLY(hr
))
158 hr
= m_staticToolbar
->FillToolbar();
162 hr
= m_staticToolbar
->FillToolbar(TRUE
);
169 HRESULT STDMETHODCALLTYPE
CMenuBand::GetMenu(
174 if (m_staticToolbar
== NULL
)
177 return m_staticToolbar
->GetMenu(phmenu
, phwnd
, pdwFlags
);
180 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSite(IUnknown
*pUnkSite
)
187 if (pUnkSite
== NULL
)
191 hr
= pUnkSite
->QueryInterface(IID_PPV_ARG(IOleWindow
, &m_site
));
192 if (FAILED_UNEXPECTEDLY(hr
))
195 hr
= m_site
->GetWindow(&hwndParent
);
196 if (FAILED_UNEXPECTEDLY(hr
))
199 if (!::IsWindow(hwndParent
))
202 if (m_staticToolbar
!= NULL
)
204 hr
= m_staticToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
205 if (FAILED_UNEXPECTEDLY(hr
))
208 hr
= m_staticToolbar
->FillToolbar();
209 if (FAILED_UNEXPECTEDLY(hr
))
213 if (m_SFToolbar
!= NULL
)
215 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
216 if (FAILED_UNEXPECTEDLY(hr
))
219 hr
= m_SFToolbar
->FillToolbar();
220 if (FAILED_UNEXPECTEDLY(hr
))
224 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IMenuPopup
, &m_subMenuParent
));
225 if (hr
!= E_NOINTERFACE
&& FAILED_UNEXPECTEDLY(hr
))
228 CComPtr
<IOleWindow
> pTopLevelWindow
;
229 hr
= IUnknown_QueryService(m_site
, SID_STopLevelBrowser
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
230 if (FAILED_UNEXPECTEDLY(hr
))
233 return pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
236 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSite(REFIID riid
, PVOID
*ppvSite
)
241 return m_site
->QueryInterface(riid
, ppvSite
);
244 HRESULT STDMETHODCALLTYPE
CMenuBand::GetWindow(
247 if (m_SFToolbar
!= NULL
)
248 return m_SFToolbar
->GetWindow(phwnd
);
250 if (m_staticToolbar
!= NULL
)
251 return m_staticToolbar
->GetWindow(phwnd
);
256 HRESULT STDMETHODCALLTYPE
CMenuBand::OnPosRectChangeDB(RECT
*prc
)
258 SIZE sizeStatic
= { 0 };
259 SIZE sizeShlFld
= { 0 };
262 if (m_staticToolbar
!= NULL
)
263 hr
= m_staticToolbar
->GetIdealSize(sizeStatic
);
264 if (FAILED_UNEXPECTEDLY(hr
))
267 if (m_SFToolbar
!= NULL
)
268 hr
= m_SFToolbar
->GetIdealSize(sizeShlFld
);
269 if (FAILED_UNEXPECTEDLY(hr
))
272 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
275 int sy
= min(prc
->bottom
- prc
->top
, sizeStatic
.cy
+ sizeShlFld
.cy
);
277 int syStatic
= sizeStatic
.cy
;
278 int syShlFld
= sy
- syStatic
;
282 m_SFToolbar
->SetPosSize(
285 prc
->right
- prc
->left
,
290 m_staticToolbar
->SetPosSize(
293 prc
->right
- prc
->left
,
299 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBandInfo(
304 SIZE sizeStatic
= { 0 };
305 SIZE sizeShlFld
= { 0 };
309 if (m_staticToolbar
!= NULL
)
310 hr
= m_staticToolbar
->GetIdealSize(sizeStatic
);
311 if (FAILED_UNEXPECTEDLY(hr
))
314 if (m_SFToolbar
!= NULL
)
315 hr
= m_SFToolbar
->GetIdealSize(sizeShlFld
);
316 if (FAILED_UNEXPECTEDLY(hr
))
319 if (m_staticToolbar
== NULL
&& m_SFToolbar
== NULL
)
322 pdbi
->ptMinSize
.x
= max(sizeStatic
.cx
, sizeShlFld
.cx
) + 20;
323 pdbi
->ptMinSize
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
324 pdbi
->ptMaxSize
.x
= max(sizeStatic
.cx
, sizeShlFld
.cx
) + 20;
325 pdbi
->ptMaxSize
.y
= sizeStatic
.cy
+ sizeShlFld
.cy
;
330 HRESULT STDMETHODCALLTYPE
CMenuBand::ShowDW(BOOL fShow
)
334 if (m_staticToolbar
!= NULL
)
335 hr
= m_staticToolbar
->ShowWindow(fShow
);
336 if (FAILED_UNEXPECTEDLY(hr
))
338 if (m_SFToolbar
!= NULL
)
339 hr
= m_SFToolbar
->ShowWindow(fShow
);
340 if (FAILED_UNEXPECTEDLY(hr
))
345 hr
= _CallCB(SMC_INITMENU
, 0, 0);
346 if (FAILED_UNEXPECTEDLY(hr
))
350 if (m_dwFlags
& SMINIT_VERTICAL
)
353 hr
= m_focusManager
->PushMenu(this);
355 hr
= m_focusManager
->PopMenu(this);
361 HRESULT STDMETHODCALLTYPE
CMenuBand::CloseDW(DWORD dwReserved
)
365 if (m_staticToolbar
!= NULL
)
366 return m_staticToolbar
->Close();
368 if (m_SFToolbar
!= NULL
)
369 return m_SFToolbar
->Close();
373 HRESULT STDMETHODCALLTYPE
CMenuBand::ResizeBorderDW(LPCRECT prcBorder
, IUnknown
*punkToolbarSite
, BOOL fReserved
)
379 HRESULT STDMETHODCALLTYPE
CMenuBand::ContextSensitiveHelp(BOOL fEnterMode
)
385 HRESULT STDMETHODCALLTYPE
CMenuBand::UIActivateIO(BOOL fActivate
, LPMSG lpMsg
)
391 hr
= m_subMenuParent
->SetSubMenu(this, fActivate
);
392 if (FAILED_UNEXPECTEDLY(hr
))
398 CComPtr
<IOleWindow
> pTopLevelWindow
;
399 hr
= IUnknown_QueryService(m_site
, SID_SMenuPopup
, IID_PPV_ARG(IOleWindow
, &pTopLevelWindow
));
400 if (FAILED_UNEXPECTEDLY(hr
))
403 hr
= pTopLevelWindow
->GetWindow(&m_topLevelWindow
);
404 if (FAILED_UNEXPECTEDLY(hr
))
409 m_topLevelWindow
= NULL
;
415 HRESULT STDMETHODCALLTYPE
CMenuBand::Exec(const GUID
*pguidCmdGroup
, DWORD nCmdID
, DWORD nCmdexecopt
, VARIANT
*pvaIn
, VARIANT
*pvaOut
)
420 if (IsEqualGUID(*pguidCmdGroup
, CLSID_MenuBand
))
422 if (nCmdID
== 16) // set (big) icon size
424 this->m_useBigIcons
= nCmdexecopt
== 2;
427 else if (nCmdID
== 19) // popup-related
439 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryService(REFGUID guidService
, REFIID riid
, void **ppvObject
)
441 if (IsEqualIID(guidService
, SID_SMenuBandChild
) ||
442 IsEqualIID(guidService
, SID_SMenuBandBottom
) ||
443 IsEqualIID(guidService
, SID_SMenuBandBottomSelected
))
444 return this->QueryInterface(riid
, ppvObject
);
445 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService
));
446 return E_NOINTERFACE
;
449 HRESULT STDMETHODCALLTYPE
CMenuBand::Popup(POINTL
*ppt
, RECTL
*prcExclude
, MP_POPUPFLAGS dwFlags
)
455 HRESULT STDMETHODCALLTYPE
CMenuBand::OnSelect(DWORD dwSelectType
)
457 switch (dwSelectType
)
459 case MPOS_CHILDTRACKING
:
460 if (!m_subMenuParent
)
462 // TODO: Cancel timers?
463 return m_subMenuParent
->OnSelect(dwSelectType
);
464 case MPOS_SELECTLEFT
:
466 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
467 if (!m_subMenuParent
)
469 return m_subMenuParent
->OnSelect(dwSelectType
);
470 case MPOS_SELECTRIGHT
:
471 if (!m_subMenuParent
)
473 return m_subMenuParent
->OnSelect(dwSelectType
);
475 case MPOS_FULLCANCEL
:
477 m_subMenuChild
->OnSelect(dwSelectType
);
478 if (!m_subMenuParent
)
480 return m_subMenuParent
->OnSelect(dwSelectType
);
481 case MPOS_CANCELLEVEL
:
483 m_subMenuChild
->OnSelect(dwSelectType
);
489 HRESULT STDMETHODCALLTYPE
CMenuBand::SetSubMenu(IMenuPopup
*pmp
, BOOL fSet
)
495 HRESULT STDMETHODCALLTYPE
CMenuBand::SetClient(IUnknown
*punkClient
)
501 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClient(IUnknown
**ppunkClient
)
503 // HACK, so I can test for a submenu in the DeskBar
508 *ppunkClient
= m_subMenuChild
;
515 HRESULT STDMETHODCALLTYPE
CMenuBand::IsMenuMessage(MSG
*pmsg
)
523 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateMenuMessage(MSG
*pmsg
, LRESULT
*plRet
)
529 HRESULT STDMETHODCALLTYPE
CMenuBand::SetShellFolder(IShellFolder
*psf
, LPCITEMIDLIST pidlFolder
, HKEY hKey
, DWORD dwFlags
)
531 if (m_SFToolbar
== NULL
)
533 m_SFToolbar
= new CMenuSFToolbar(this);
536 HRESULT hr
= m_SFToolbar
->SetShellFolder(psf
, pidlFolder
, hKey
, dwFlags
);
537 if (FAILED_UNEXPECTEDLY(hr
))
544 hr
= m_site
->GetWindow(&hwndParent
);
545 if (FAILED_UNEXPECTEDLY(hr
))
548 hr
= m_SFToolbar
->CreateToolbar(hwndParent
, m_dwFlags
);
549 if (FAILED_UNEXPECTEDLY(hr
))
552 hr
= m_SFToolbar
->FillToolbar();
558 HRESULT STDMETHODCALLTYPE
CMenuBand::GetShellFolder(DWORD
*pdwFlags
, LPITEMIDLIST
*ppidl
, REFIID riid
, void **ppv
)
561 return m_SFToolbar
->GetShellFolder(pdwFlags
, ppidl
, riid
, ppv
);
565 HRESULT STDMETHODCALLTYPE
CMenuBand::InvalidateItem(LPSMDATA psmd
, DWORD dwFlags
)
571 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(LPSMDATA psmd
)
577 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMenuToolbar(IUnknown
*punk
, DWORD dwFlags
)
583 HRESULT STDMETHODCALLTYPE
CMenuBand::OnWinEvent(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*theResult
)
587 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
589 return m_staticToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
592 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
594 return m_SFToolbar
->OnWinEvent(hWnd
, uMsg
, wParam
, lParam
, theResult
);
600 HRESULT STDMETHODCALLTYPE
CMenuBand::IsWindowOwner(HWND hWnd
)
602 if (m_staticToolbar
&& m_staticToolbar
->IsWindowOwner(hWnd
) == S_OK
)
605 if (m_SFToolbar
&& m_SFToolbar
->IsWindowOwner(hWnd
) == S_OK
)
611 HRESULT
CMenuBand::_CallCBWithItemId(UINT id
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
613 return _CallCB(uMsg
, wParam
, lParam
, id
);
616 HRESULT
CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
618 return _CallCB(uMsg
, wParam
, lParam
, 0, pidl
);
621 HRESULT
CMenuBand::_CallCB(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT id
, LPITEMIDLIST pidl
)
629 SMDATA smData
= { 0 };
630 smData
.punk
= static_cast<IShellMenu2
*>(this);
632 smData
.uIdParent
= m_uId
;
633 smData
.uIdAncestor
= m_uIdAncestor
;
635 smData
.pidlItem
= pidl
;
638 smData
.hmenu
= m_hmenu
;
640 smData
.pvUserData
= NULL
;
642 m_SFToolbar
->GetShellFolder(NULL
, &smData
.pidlFolder
, IID_PPV_ARG(IShellFolder
, &smData
.psf
));
643 HRESULT hr
= m_psmc
->CallbackSM(&smData
, uMsg
, wParam
, lParam
);
644 ILFree(smData
.pidlFolder
);
646 smData
.psf
->Release();
650 HRESULT
CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup
, INT x
, INT y
, RECT
& rcExclude
)
652 TPMPARAMS params
= { sizeof(TPMPARAMS
), rcExclude
};
654 UINT flags
= TPM_VERPOSANIMATION
| TPM_VERTICAL
| TPM_LEFTALIGN
;
658 ::TrackPopupMenuEx(popup
, flags
, x
, y
, m_menuOwner
, ¶ms
);
662 ::TrackPopupMenuEx(popup
, flags
, x
, y
, m_topLevelWindow
, ¶ms
);
668 HRESULT
CMenuBand::_GetTopLevelWindow(HWND
*topLevel
)
670 *topLevel
= m_topLevelWindow
;
674 HRESULT
CMenuBand::_OnHotItemChanged(CMenuToolbarBase
* tb
, INT id
)
678 if (m_staticToolbar
) m_staticToolbar
->OnHotItemChanged(tb
, id
);
679 if (m_SFToolbar
) m_SFToolbar
->OnHotItemChanged(tb
, id
);
683 HRESULT
CMenuBand::_MenuItemHotTrack(DWORD changeType
)
687 if (changeType
== VK_DOWN
)
689 if (m_SFToolbar
&& (m_hotBar
== m_SFToolbar
|| m_hotBar
== NULL
))
691 hr
= m_SFToolbar
->ChangeHotItem(VK_DOWN
);
695 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
697 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
701 else if (m_staticToolbar
&& m_hotBar
== m_staticToolbar
)
703 hr
= m_staticToolbar
->ChangeHotItem(VK_DOWN
);
707 return m_SFToolbar
->ChangeHotItem(VK_HOME
);
709 return m_staticToolbar
->ChangeHotItem(VK_HOME
);
714 else if (changeType
== VK_UP
)
716 if (m_staticToolbar
&& (m_hotBar
== m_staticToolbar
|| m_hotBar
== NULL
))
718 hr
= m_staticToolbar
->ChangeHotItem(VK_UP
);
722 return m_SFToolbar
->ChangeHotItem(VK_END
);
724 return m_staticToolbar
->ChangeHotItem(VK_END
);
728 else if (m_SFToolbar
&& m_hotBar
== m_SFToolbar
)
730 hr
= m_SFToolbar
->ChangeHotItem(VK_UP
);
734 return m_staticToolbar
->ChangeHotItem(VK_END
);
736 return m_SFToolbar
->ChangeHotItem(VK_END
);
741 else if (changeType
== MPOS_SELECTLEFT
)
744 m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
745 if (!m_subMenuParent
)
747 return m_subMenuParent
->OnSelect(MPOS_CANCELLEVEL
);
749 else if (changeType
== MPOS_SELECTRIGHT
)
751 if (m_hotBar
&& m_hotItem
>= 0)
753 if (m_hotBar
->HasSubMenu(m_hotItem
)==S_OK
)
755 m_hotBar
->PopupItem(m_hotItem
);
759 if (!m_subMenuParent
)
761 return m_subMenuParent
->OnSelect(changeType
);
765 if (!m_subMenuParent
)
767 return m_subMenuParent
->OnSelect(changeType
);
772 HRESULT
CMenuBand::_OnPopupSubMenu(IMenuPopup
* popup
, POINTL
* pAt
, RECTL
* pExclude
, CMenuToolbarBase
* toolbar
, INT item
)
776 HRESULT hr
= m_subMenuChild
->OnSelect(MPOS_CANCELLEVEL
);
777 if (FAILED_UNEXPECTEDLY(hr
))
780 if (m_staticToolbar
) m_staticToolbar
->OnPopupItemChanged(toolbar
, item
);
781 if (m_SFToolbar
) m_SFToolbar
->OnPopupItemChanged(toolbar
, item
);
782 m_subMenuChild
= popup
;
786 IUnknown_SetSite(popup
, m_subMenuParent
);
788 IUnknown_SetSite(popup
, m_site
);
790 popup
->Popup(pAt
, pExclude
, MPPF_RIGHT
);
795 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSubMenu(THIS
)
801 HRESULT STDMETHODCALLTYPE
CMenuBand::SetToolbar(THIS
)
807 HRESULT STDMETHODCALLTYPE
CMenuBand::SetMinWidth(THIS
)
813 HRESULT STDMETHODCALLTYPE
CMenuBand::SetNoBorder(THIS
)
819 HRESULT STDMETHODCALLTYPE
CMenuBand::SetTheme(THIS
)
825 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTop(THIS
)
831 HRESULT STDMETHODCALLTYPE
CMenuBand::GetBottom(THIS
)
837 HRESULT STDMETHODCALLTYPE
CMenuBand::GetTracked(THIS
)
843 HRESULT STDMETHODCALLTYPE
CMenuBand::GetParentSite(THIS
)
849 HRESULT STDMETHODCALLTYPE
CMenuBand::GetState(THIS
)
855 HRESULT STDMETHODCALLTYPE
CMenuBand::DoDefaultAction(THIS
)
861 HRESULT STDMETHODCALLTYPE
CMenuBand::IsEmpty(THIS
)
867 HRESULT STDMETHODCALLTYPE
CMenuBand::HasFocusIO()
873 HRESULT STDMETHODCALLTYPE
CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg
)
879 HRESULT STDMETHODCALLTYPE
CMenuBand::IsDirty()
885 HRESULT STDMETHODCALLTYPE
CMenuBand::Load(IStream
*pStm
)
891 HRESULT STDMETHODCALLTYPE
CMenuBand::Save(IStream
*pStm
, BOOL fClearDirty
)
897 HRESULT STDMETHODCALLTYPE
CMenuBand::GetSizeMax(ULARGE_INTEGER
*pcbSize
)
903 HRESULT STDMETHODCALLTYPE
CMenuBand::GetClassID(CLSID
*pClassID
)
909 HRESULT STDMETHODCALLTYPE
CMenuBand::QueryStatus(const GUID
*pguidCmdGroup
, ULONG cCmds
, OLECMD prgCmds
[], OLECMDTEXT
*pCmdText
)