229cb1ef8e4e7d1794b1a2f2deffb068a78a4ac6
[reactos.git] / base / shell / rshell / CMenuBand.cpp
1 /*
2 * Shell Menu Band
3 *
4 * Copyright 2014 David Quintana
5 *
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.
10 *
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.
15 *
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
19 */
20 #include "precomp.h"
21 #include <windowsx.h>
22 #include <commoncontrols.h>
23 #include <shlwapi_undoc.h>
24
25 #include "CMenuBand.h"
26 #include "CMenuToolbars.h"
27 #include "CMenuFocusManager.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(CMenuBand);
30
31 #undef UNIMPLEMENTED
32
33 #define UNIMPLEMENTED TRACE("%s is UNIMPLEMENTED!\n", __FUNCTION__)
34
35 extern "C"
36 HRESULT WINAPI CMenuBand_Constructor(REFIID riid, LPVOID *ppv)
37 {
38 HRESULT hr;
39 #if USE_SYSTEM_MENUBAND
40 hr = CoCreateInstance(CLSID_MenuBand,
41 NULL,
42 CLSCTX_INPROC_SERVER,
43 riid, ppv);
44 #else
45 *ppv = NULL;
46
47 CMenuBand * site = new CComObject<CMenuBand>();
48
49 if (!site)
50 return E_OUTOFMEMORY;
51
52 hr = site->QueryInterface(riid, ppv);
53
54 if (FAILED_UNEXPECTEDLY(hr))
55 delete site;
56 #endif
57
58 return hr;
59 }
60
61 CMenuBand::CMenuBand() :
62 m_staticToolbar(NULL),
63 m_SFToolbar(NULL),
64 m_site(NULL),
65 m_psmc(NULL),
66 m_subMenuChild(NULL),
67 m_subMenuParent(NULL),
68 m_childBand(NULL),
69 m_parentBand(NULL),
70 m_hmenu(NULL),
71 m_menuOwner(NULL),
72 m_useBigIcons(FALSE),
73 m_topLevelWindow(NULL),
74 m_hotBar(NULL),
75 m_hotItem(-1),
76 m_popupBar(NULL),
77 m_popupItem(-1),
78 m_Show(FALSE)
79 {
80 m_focusManager = CMenuFocusManager::AcquireManager();
81 }
82
83 CMenuBand::~CMenuBand()
84 {
85 CMenuFocusManager::ReleaseManager(m_focusManager);
86
87 if (m_staticToolbar)
88 delete m_staticToolbar;
89
90 if (m_SFToolbar)
91 delete m_SFToolbar;
92 }
93
94 HRESULT STDMETHODCALLTYPE CMenuBand::Initialize(
95 IShellMenuCallback *psmc,
96 UINT uId,
97 UINT uIdAncestor,
98 DWORD dwFlags)
99 {
100 if (m_psmc != psmc)
101 m_psmc = psmc;
102 m_uId = uId;
103 m_uIdAncestor = uIdAncestor;
104 m_dwFlags = dwFlags;
105
106 if (m_psmc)
107 {
108 _CallCB(SMC_CREATE, 0, reinterpret_cast<LPARAM>(&m_UserData));
109 }
110
111 return S_OK;
112 }
113
114 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenuInfo(
115 IShellMenuCallback **ppsmc,
116 UINT *puId,
117 UINT *puIdAncestor,
118 DWORD *pdwFlags)
119 {
120 if (!pdwFlags) // maybe?
121 return E_INVALIDARG;
122
123 if (ppsmc)
124 *ppsmc = m_psmc;
125
126 if (puId)
127 *puId = m_uId;
128
129 if (puIdAncestor)
130 *puIdAncestor = m_uIdAncestor;
131
132 *pdwFlags = m_dwFlags;
133
134 return S_OK;
135 }
136
137 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenu(
138 HMENU hmenu,
139 HWND hwnd,
140 DWORD dwFlags)
141 {
142 TRACE("CMenuBand::SetMenu called, hmenu=%p; hwnd=%p, flags=%x\n", hmenu, hwnd, dwFlags);
143
144 BOOL created = FALSE;
145
146 if (m_staticToolbar == NULL)
147 {
148 m_staticToolbar = new CMenuStaticToolbar(this);
149 created = true;
150 }
151 m_hmenu = hmenu;
152 m_menuOwner = hwnd;
153
154 HRESULT hr = m_staticToolbar->SetMenu(hmenu, hwnd, dwFlags);
155 if (FAILED_UNEXPECTEDLY(hr))
156 return hr;
157
158 if (m_site)
159 {
160 HWND hwndParent;
161
162 hr = m_site->GetWindow(&hwndParent);
163 if (FAILED_UNEXPECTEDLY(hr))
164 return hr;
165
166 if (created)
167 {
168 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
169 if (FAILED_UNEXPECTEDLY(hr))
170 return hr;
171
172 hr = m_staticToolbar->FillToolbar();
173 }
174 else
175 {
176 hr = m_staticToolbar->FillToolbar(TRUE);
177 }
178 }
179
180 return hr;
181 }
182
183 HRESULT STDMETHODCALLTYPE CMenuBand::GetMenu(
184 HMENU *phmenu,
185 HWND *phwnd,
186 DWORD *pdwFlags)
187 {
188 if (m_staticToolbar == NULL)
189 return E_FAIL;
190
191 return m_staticToolbar->GetMenu(phmenu, phwnd, pdwFlags);
192 }
193
194 HRESULT STDMETHODCALLTYPE CMenuBand::SetSite(IUnknown *pUnkSite)
195 {
196 HWND hwndParent;
197 HRESULT hr;
198
199 m_site = NULL;
200
201 if (pUnkSite == NULL)
202 return S_OK;
203
204 hwndParent = NULL;
205 hr = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &m_site));
206 if (FAILED_UNEXPECTEDLY(hr))
207 return hr;
208
209 hr = m_site->GetWindow(&hwndParent);
210 if (FAILED_UNEXPECTEDLY(hr))
211 return hr;
212
213 if (!::IsWindow(hwndParent))
214 return E_FAIL;
215
216 if (m_staticToolbar != NULL)
217 {
218 hr = m_staticToolbar->CreateToolbar(hwndParent, m_dwFlags);
219 if (FAILED_UNEXPECTEDLY(hr))
220 return hr;
221
222 hr = m_staticToolbar->FillToolbar();
223 if (FAILED_UNEXPECTEDLY(hr))
224 return hr;
225 }
226
227 if (m_SFToolbar != NULL)
228 {
229 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
230 if (FAILED_UNEXPECTEDLY(hr))
231 return hr;
232
233 hr = m_SFToolbar->FillToolbar();
234 if (FAILED_UNEXPECTEDLY(hr))
235 return hr;
236 }
237
238 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_subMenuParent));
239 if (hr != E_NOINTERFACE && FAILED_UNEXPECTEDLY(hr))
240 return hr;
241
242 CComPtr<IOleWindow> pTopLevelWindow;
243 hr = IUnknown_QueryService(m_site, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
244 if (FAILED_UNEXPECTEDLY(hr))
245 return hr;
246
247 return pTopLevelWindow->GetWindow(&m_topLevelWindow);
248 }
249
250 HRESULT STDMETHODCALLTYPE CMenuBand::GetSite(REFIID riid, PVOID *ppvSite)
251 {
252 if (m_site == NULL)
253 return E_FAIL;
254
255 return m_site->QueryInterface(riid, ppvSite);
256 }
257
258 HRESULT STDMETHODCALLTYPE CMenuBand::GetWindow(HWND *phwnd)
259 {
260 if (m_SFToolbar != NULL)
261 return m_SFToolbar->GetWindow(phwnd);
262
263 if (m_staticToolbar != NULL)
264 return m_staticToolbar->GetWindow(phwnd);
265
266 if (phwnd) *phwnd = NULL;
267
268 return E_FAIL;
269 }
270
271 HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc)
272 {
273 SIZE maxStatic = { 0 };
274 SIZE maxShlFld = { 0 };
275 HRESULT hr = S_OK;
276
277 if (m_staticToolbar != NULL)
278 hr = m_staticToolbar->GetSizes(NULL, &maxStatic, NULL);
279 if (FAILED_UNEXPECTEDLY(hr))
280 return hr;
281
282 if (m_SFToolbar != NULL)
283 hr = m_SFToolbar->GetSizes(NULL, &maxShlFld, NULL);
284 if (FAILED_UNEXPECTEDLY(hr))
285 return hr;
286
287 if (m_staticToolbar == NULL && m_SFToolbar == NULL)
288 return E_FAIL;
289
290 int sy = min(prc->bottom - prc->top, maxStatic.cy + maxShlFld.cy);
291
292 int syStatic = maxStatic.cy;
293 int syShlFld = sy - syStatic;
294
295 if (m_SFToolbar)
296 {
297 m_SFToolbar->SetPosSize(
298 prc->left,
299 prc->top,
300 prc->right - prc->left,
301 syShlFld);
302 }
303 if (m_staticToolbar)
304 {
305 m_staticToolbar->SetPosSize(
306 prc->left,
307 prc->top + syShlFld,
308 prc->right - prc->left,
309 syStatic);
310 }
311
312 return S_OK;
313 }
314
315 HRESULT STDMETHODCALLTYPE CMenuBand::GetBandInfo(
316 DWORD dwBandID,
317 DWORD dwViewMode,
318 DESKBANDINFO *pdbi)
319 {
320 SIZE minStatic = { 0 };
321 SIZE minShlFld = { 0 };
322 SIZE maxStatic = { 0 };
323 SIZE maxShlFld = { 0 };
324 SIZE intStatic = { 0 };
325 SIZE intShlFld = { 0 };
326
327 HRESULT hr = S_OK;
328
329 if (m_staticToolbar != NULL)
330 hr = m_staticToolbar->GetSizes(&minStatic, &maxStatic, &intStatic);
331 if (FAILED_UNEXPECTEDLY(hr))
332 return hr;
333
334 if (m_SFToolbar != NULL)
335 hr = m_SFToolbar->GetSizes(&minShlFld, &maxShlFld, &intShlFld);
336 if (FAILED_UNEXPECTEDLY(hr))
337 return hr;
338
339 if (m_staticToolbar == NULL && m_SFToolbar == NULL)
340 return E_FAIL;
341
342 if (m_dwFlags & SMINIT_VERTICAL)
343 {
344 pdbi->ptMinSize.x = max(minStatic.cx, minShlFld.cx) + 20;
345 pdbi->ptMinSize.y = minStatic.cy + minShlFld.cy;
346 pdbi->ptMaxSize.x = max(maxStatic.cx, maxShlFld.cx) + 20;
347 pdbi->ptMaxSize.y = maxStatic.cy + maxShlFld.cy;
348 pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
349 }
350 else
351 {
352 pdbi->ptMinSize.x = minStatic.cx + minShlFld.cx;
353 pdbi->ptMinSize.y = max(minStatic.cy, minShlFld.cy);
354 pdbi->ptMaxSize.x = maxStatic.cx + maxShlFld.cx;
355 pdbi->ptMaxSize.y = max(maxStatic.cy, maxShlFld.cy);
356 }
357 pdbi->ptIntegral.x = max(intStatic.cx, intShlFld.cx);
358 pdbi->ptIntegral.y = max(intStatic.cy, intShlFld.cy);
359 pdbi->ptActual = pdbi->ptMinSize;
360
361 return S_OK;
362 }
363
364 HRESULT STDMETHODCALLTYPE CMenuBand::ShowDW(BOOL fShow)
365 {
366 HRESULT hr = S_OK;
367
368 if (m_Show == fShow)
369 return S_OK;
370
371 if (m_staticToolbar != NULL)
372 {
373 hr = m_staticToolbar->ShowWindow(fShow);
374 if (FAILED_UNEXPECTEDLY(hr))
375 return hr;
376 }
377
378 if (m_SFToolbar != NULL)
379 {
380 hr = m_SFToolbar->ShowWindow(fShow);
381 if (FAILED_UNEXPECTEDLY(hr))
382 return hr;
383 }
384
385 if (fShow)
386 {
387 hr = _CallCB(SMC_INITMENU, 0, 0);
388 if (FAILED_UNEXPECTEDLY(hr))
389 return hr;
390 }
391 else if (m_parentBand)
392 {
393 m_parentBand->SetClient(NULL);
394 }
395
396 if (_IsPopup() == S_OK)
397 {
398 if (fShow)
399 hr = m_focusManager->PushMenuPopup(this);
400 else
401 hr = m_focusManager->PopMenuPopup(this);
402 }
403 else
404 {
405 if (fShow)
406 hr = m_focusManager->PushMenuBar(this);
407 else
408 hr = m_focusManager->PopMenuBar(this);
409 }
410
411 m_Show = fShow;
412
413 return S_OK;
414 }
415
416 HRESULT STDMETHODCALLTYPE CMenuBand::CloseDW(DWORD dwReserved)
417 {
418 ShowDW(FALSE);
419
420 if (m_staticToolbar != NULL)
421 {
422 m_staticToolbar->Close();
423 delete m_staticToolbar;
424 m_staticToolbar = NULL;
425 }
426
427 if (m_SFToolbar != NULL)
428 {
429 m_SFToolbar->Close();
430 delete m_staticToolbar;
431 m_staticToolbar = NULL;
432 }
433
434 if (m_site) m_site.Release();
435 if (m_psmc) m_psmc.Release();
436 if (m_subMenuChild) m_subMenuChild.Release();
437 if (m_subMenuParent) m_subMenuParent.Release();
438 if (m_childBand) m_childBand.Release();
439 if (m_parentBand) m_parentBand.Release();
440
441 return S_OK;
442 }
443
444 HRESULT STDMETHODCALLTYPE CMenuBand::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
445 {
446 HRESULT hr;
447
448 if (m_subMenuParent)
449 {
450 hr = m_subMenuParent->SetSubMenu(this, fActivate);
451 if (FAILED_UNEXPECTEDLY(hr))
452 return hr;
453 }
454
455 if (fActivate)
456 {
457 CComPtr<IOleWindow> pTopLevelWindow;
458 hr = IUnknown_QueryService(m_site, SID_SMenuPopup, IID_PPV_ARG(IOleWindow, &pTopLevelWindow));
459 if (FAILED_UNEXPECTEDLY(hr))
460 return hr;
461
462 hr = pTopLevelWindow->GetWindow(&m_topLevelWindow);
463 if (FAILED_UNEXPECTEDLY(hr))
464 return hr;
465 }
466 else
467 {
468 m_topLevelWindow = NULL;
469 }
470
471 return S_FALSE;
472 }
473
474 HRESULT STDMETHODCALLTYPE CMenuBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
475 {
476 if (!pguidCmdGroup)
477 return E_FAIL;
478
479 if (IsEqualGUID(*pguidCmdGroup, CLSID_MenuBand))
480 {
481 if (nCmdID == 16) // set (big) icon size
482 {
483 this->m_useBigIcons = nCmdexecopt == 2;
484 return S_OK;
485 }
486 else if (nCmdID == 19) // popup-related
487 {
488 return S_FALSE;
489 }
490 else if (nCmdID == 5) // select an item
491 {
492 if (nCmdexecopt == 0) // first
493 {
494 _KeyboardItemChange(VK_HOME);
495 }
496 else // last
497 {
498 _KeyboardItemChange(VK_END);
499 }
500 return S_FALSE;
501 }
502
503 return S_FALSE;
504 }
505
506 UNIMPLEMENTED;
507 return S_OK;
508 }
509
510 HRESULT STDMETHODCALLTYPE CMenuBand::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
511 {
512 if (IsEqualIID(guidService, SID_SMenuBandChild) ||
513 IsEqualIID(guidService, SID_SMenuBandBottom) ||
514 IsEqualIID(guidService, SID_SMenuBandBottomSelected))
515 return this->QueryInterface(riid, ppvObject);
516 WARN("Unknown service requested %s\n", wine_dbgstr_guid(&guidService));
517 return E_NOINTERFACE;
518 }
519
520 HRESULT STDMETHODCALLTYPE CMenuBand::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
521 {
522 UNIMPLEMENTED;
523 return S_OK;
524 }
525
526 HRESULT STDMETHODCALLTYPE CMenuBand::OnSelect(DWORD dwSelectType)
527 {
528 switch (dwSelectType)
529 {
530 case MPOS_CHILDTRACKING:
531 if (!m_subMenuParent)
532 break;
533 // TODO: Cancel timers?
534 return m_subMenuParent->OnSelect(dwSelectType);
535 case MPOS_SELECTLEFT:
536 if (m_subMenuChild)
537 m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
538 if (!m_subMenuParent)
539 break;
540 return m_subMenuParent->OnSelect(dwSelectType);
541 case MPOS_SELECTRIGHT:
542 if (!m_subMenuParent)
543 break;
544 return m_subMenuParent->OnSelect(dwSelectType);
545 case MPOS_EXECUTE:
546 case MPOS_FULLCANCEL:
547 if (m_subMenuChild)
548 m_subMenuChild->OnSelect(dwSelectType);
549 if (!m_subMenuParent)
550 break;
551 return m_subMenuParent->OnSelect(dwSelectType);
552 case MPOS_CANCELLEVEL:
553 if (m_subMenuChild)
554 m_subMenuChild->OnSelect(dwSelectType);
555 break;
556 }
557 return S_FALSE;
558 }
559
560 HRESULT STDMETHODCALLTYPE CMenuBand::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
561 {
562 UNIMPLEMENTED;
563 return S_OK;
564 }
565
566 HRESULT CMenuBand::_SetChildBand(CMenuBand * child)
567 {
568 m_childBand = child;
569 if (!child)
570 {
571 _ChangePopupItem(NULL, -1);
572 }
573 return S_OK;
574 }
575
576 HRESULT CMenuBand::_SetParentBand(CMenuBand * parent)
577 {
578 m_parentBand = parent;
579 return S_OK;
580 }
581
582 HRESULT CMenuBand::_IsPopup()
583 {
584 return m_subMenuParent ? S_OK : S_FALSE;
585 }
586
587 HRESULT CMenuBand::_IsTracking()
588 {
589 return m_popupBar != NULL;
590 }
591
592 HRESULT STDMETHODCALLTYPE CMenuBand::SetClient(IUnknown *punkClient)
593 {
594 m_subMenuChild = NULL;
595
596 if (!punkClient)
597 {
598 return S_OK;
599 }
600
601 HRESULT hr = punkClient->QueryInterface(IID_PPV_ARG(IMenuPopup, &m_subMenuChild));
602
603 return hr;
604 }
605
606 HRESULT STDMETHODCALLTYPE CMenuBand::GetClient(IUnknown **ppunkClient)
607 {
608 // HACK, so I can test for a submenu in the DeskBar
609 if (ppunkClient)
610 {
611 if (m_subMenuChild)
612 *ppunkClient = m_subMenuChild;
613 else
614 *ppunkClient = NULL;
615 }
616 return S_OK;
617 }
618
619 HRESULT STDMETHODCALLTYPE CMenuBand::IsMenuMessage(MSG *pmsg)
620 {
621 return S_FALSE;
622 }
623
624 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateMenuMessage(MSG *pmsg, LRESULT *plRet)
625 {
626 return S_FALSE;
627 }
628
629 HRESULT STDMETHODCALLTYPE CMenuBand::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
630 {
631 if (m_SFToolbar == NULL)
632 {
633 m_SFToolbar = new CMenuSFToolbar(this);
634 }
635
636 HRESULT hr = m_SFToolbar->SetShellFolder(psf, pidlFolder, hKey, dwFlags);
637 if (FAILED_UNEXPECTEDLY(hr))
638 return hr;
639
640 if (m_site)
641 {
642 HWND hwndParent;
643
644 hr = m_site->GetWindow(&hwndParent);
645 if (FAILED_UNEXPECTEDLY(hr))
646 return hr;
647
648 hr = m_SFToolbar->CreateToolbar(hwndParent, m_dwFlags);
649 if (FAILED_UNEXPECTEDLY(hr))
650 return hr;
651
652 hr = m_SFToolbar->FillToolbar();
653 }
654
655 return hr;
656 }
657
658 HRESULT STDMETHODCALLTYPE CMenuBand::GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv)
659 {
660 if (m_SFToolbar)
661 return m_SFToolbar->GetShellFolder(pdwFlags, ppidl, riid, ppv);
662 return E_FAIL;
663 }
664
665 HRESULT STDMETHODCALLTYPE CMenuBand::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
666 {
667 *theResult = 0;
668
669 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
670 {
671 return m_staticToolbar->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
672 }
673
674 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
675 {
676 return m_SFToolbar->OnWinEvent(hWnd, uMsg, wParam, lParam, theResult);
677 }
678
679 return S_FALSE;
680 }
681
682 HRESULT STDMETHODCALLTYPE CMenuBand::IsWindowOwner(HWND hWnd)
683 {
684 if (m_staticToolbar && m_staticToolbar->IsWindowOwner(hWnd) == S_OK)
685 return S_OK;
686
687 if (m_SFToolbar && m_SFToolbar->IsWindowOwner(hWnd) == S_OK)
688 return S_OK;
689
690 return S_FALSE;
691 }
692
693 HRESULT CMenuBand::_CallCBWithItemId(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam)
694 {
695 return _CallCB(uMsg, wParam, lParam, id);
696 }
697
698 HRESULT CMenuBand::_CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam)
699 {
700 return _CallCB(uMsg, wParam, lParam, 0, pidl);
701 }
702
703 HRESULT CMenuBand::_CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id, LPITEMIDLIST pidl)
704 {
705 if (!m_psmc)
706 return S_FALSE;
707
708 HWND hwnd;
709 GetWindow(&hwnd);
710
711 SMDATA smData = { 0 };
712 smData.punk = static_cast<IShellMenu2*>(this);
713 smData.uId = id;
714 smData.uIdParent = m_uId;
715 smData.uIdAncestor = m_uIdAncestor;
716 smData.pidlItem = pidl;
717 smData.hwnd = hwnd;
718 if (m_hmenu)
719 smData.hmenu = m_hmenu;
720 smData.pvUserData = NULL;
721 if (m_SFToolbar)
722 m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf));
723 HRESULT hr = m_psmc->CallbackSM(&smData, uMsg, wParam, lParam);
724 ILFree(smData.pidlFolder);
725 if (smData.psf)
726 smData.psf->Release();
727 return hr;
728 }
729
730 HRESULT CMenuBand::_TrackSubMenu(HMENU popup, INT x, INT y, RECT& rcExclude)
731 {
732 TPMPARAMS params = { sizeof(TPMPARAMS), rcExclude };
733 UINT flags = TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_LEFTALIGN;
734 HWND hwnd = m_menuOwner ? m_menuOwner : m_topLevelWindow;
735
736 m_focusManager->PushTrackedPopup(popup);
737 ::TrackPopupMenuEx(popup, flags, x, y, hwnd, &params);
738 m_focusManager->PopTrackedPopup(popup);
739
740 _DisableMouseTrack(FALSE);
741
742 return S_OK;
743 }
744
745 HRESULT CMenuBand::_TrackContextMenu(IContextMenu * contextMenu, INT x, INT y)
746 {
747 HRESULT hr;
748 UINT uCommand;
749 HMENU popup = CreatePopupMenu();
750
751 if (popup == NULL)
752 return E_FAIL;
753
754 TRACE("Before Query\n");
755 hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL);
756 if (FAILED_UNEXPECTEDLY(hr))
757 {
758 TRACE("Query failed\n");
759 DestroyMenu(popup);
760 return hr;
761 }
762
763 HWND hwnd = m_menuOwner ? m_menuOwner : m_topLevelWindow;
764
765 TRACE("Before Tracking\n");
766 uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, hwnd, NULL);
767
768 if (uCommand != 0)
769 {
770 TRACE("Before InvokeCommand\n");
771 CMINVOKECOMMANDINFO cmi = { 0 };
772 cmi.cbSize = sizeof(cmi);
773 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
774 cmi.hwnd = hwnd;
775 hr = contextMenu->InvokeCommand(&cmi);
776 }
777 else
778 {
779 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError());
780 hr = S_FALSE;
781 }
782
783 DestroyMenu(popup);
784 return hr;
785 }
786
787 HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel)
788 {
789 *topLevel = m_topLevelWindow;
790 return S_OK;
791 }
792
793 HRESULT CMenuBand::_ChangeHotItem(CMenuToolbarBase * tb, INT id, DWORD dwFlags)
794 {
795 if (m_hotBar == tb && m_hotItem == id)
796 return S_FALSE;
797
798 TRACE("Hot item changed from %p %p, to %p %p\n", m_hotBar, m_hotItem, tb, id);
799
800 _KillPopupTimers();
801
802 m_hotBar = tb;
803 m_hotItem = id;
804 if (m_staticToolbar) m_staticToolbar->ChangeHotItem(tb, id, dwFlags);
805 if (m_SFToolbar) m_SFToolbar->ChangeHotItem(tb, id, dwFlags);
806
807 _MenuItemHotTrack(MPOS_CHILDTRACKING);
808
809
810 return S_OK;
811 }
812
813 HRESULT CMenuBand::_ChangePopupItem(CMenuToolbarBase * tb, INT id)
814 {
815 TRACE("Popup item changed from %p %p, to %p %p\n", m_popupBar, m_popupItem, tb, id);
816
817 m_popupBar = tb;
818 m_popupItem = id;
819 if (m_staticToolbar) m_staticToolbar->ChangePopupItem(tb, id);
820 if (m_SFToolbar) m_SFToolbar->ChangePopupItem(tb, id);
821
822 return S_OK;
823 }
824
825 HRESULT CMenuBand::_KeyboardItemChange(DWORD change)
826 {
827 HRESULT hr;
828 CMenuToolbarBase *tb = m_hotBar;
829
830 if (!tb)
831 {
832 // If no hot item was selected choose the appropriate toolbar
833 if (change == VK_UP || change == VK_END)
834 {
835 if (m_staticToolbar)
836 tb = m_staticToolbar;
837 else
838 tb = m_SFToolbar;
839 }
840 else if (change == VK_DOWN || change == VK_HOME)
841 {
842 if (m_SFToolbar)
843 tb = m_SFToolbar;
844 else
845 tb = m_staticToolbar;
846 }
847 }
848
849 // Ask the first toolbar to change
850 hr = tb->KeyboardItemChange(change);
851
852 if (hr != S_FALSE)
853 return hr;
854
855 // Select the second toolbar based on the first
856 if (tb == m_SFToolbar && m_staticToolbar)
857 tb = m_staticToolbar;
858 else if (m_SFToolbar)
859 tb = m_SFToolbar;
860
861 if (!tb)
862 return hr;
863
864 // Ask the second toolbar to change
865 return tb->KeyboardItemChange(change == VK_DOWN ? VK_HOME : VK_END);
866 }
867
868 HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType)
869 {
870 HRESULT hr;
871
872 if (m_dwFlags & SMINIT_VERTICAL)
873 {
874 switch (changeType)
875 {
876 case VK_UP:
877 case VK_DOWN:
878 return _KeyboardItemChange(changeType);
879
880 // TODO: Left/Right across multi-column menus, if they ever work.
881 case VK_LEFT:
882 changeType = MPOS_SELECTLEFT;
883 break;
884 case VK_RIGHT:
885 changeType = MPOS_SELECTRIGHT;
886 break;
887 }
888 }
889 else
890 {
891 // In horizontal menubars, left/right are equivalent to vertical's up/down
892 switch (changeType)
893 {
894 case VK_LEFT:
895 hr = _KeyboardItemChange(VK_UP);
896 if (hr != S_FALSE)
897 return hr;
898 case VK_RIGHT:
899 hr = _KeyboardItemChange(VK_DOWN);
900 if (hr != S_FALSE)
901 return hr;
902 }
903 }
904
905 switch (changeType)
906 {
907 case MPOS_EXECUTE:
908 m_hotBar->ExecuteItem(m_hotItem);
909 break;
910
911 case MPOS_SELECTLEFT:
912 if (m_parentBand && m_parentBand->_IsPopup()==S_FALSE)
913 return m_parentBand->_MenuItemHotTrack(VK_LEFT);
914 if (m_subMenuChild)
915 return m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
916 if (!m_subMenuParent)
917 return S_OK;
918 return m_subMenuParent->OnSelect(MPOS_CANCELLEVEL);
919
920 case MPOS_SELECTRIGHT:
921 if (m_hotBar && m_hotItem >= 0 && m_hotBar->PopupItem(m_hotItem, TRUE) == S_OK)
922 return S_FALSE;
923 if (m_parentBand)
924 return m_parentBand->_MenuItemHotTrack(VK_RIGHT);
925 if (!m_subMenuParent)
926 return S_OK;
927 return m_subMenuParent->OnSelect(MPOS_SELECTRIGHT);
928
929 default:
930 if (!m_subMenuParent)
931 return S_OK;
932 return m_subMenuParent->OnSelect(changeType);
933 }
934
935 return S_OK;
936 }
937
938 HRESULT CMenuBand::_CancelCurrentPopup()
939 {
940 if (!m_subMenuChild)
941 return S_FALSE;
942
943 HRESULT hr = m_subMenuChild->OnSelect(MPOS_CANCELLEVEL);
944 return hr;
945 }
946
947 HRESULT CMenuBand::_OnPopupSubMenu(IShellMenu * childShellMenu, POINTL * pAt, RECTL * pExclude, BOOL keyInitiated)
948 {
949 HRESULT hr = 0;
950 IBandSite* pBandSite;
951 IDeskBar* pDeskBar;
952
953 // Create the necessary objects
954 hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
955 if (FAILED_UNEXPECTEDLY(hr))
956 return hr;
957
958 hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
959 if (FAILED_UNEXPECTEDLY(hr))
960 return hr;
961
962 hr = pDeskBar->SetClient(pBandSite);
963 if (FAILED_UNEXPECTEDLY(hr))
964 return hr;
965
966 hr = pBandSite->AddBand(childShellMenu);
967 if (FAILED_UNEXPECTEDLY(hr))
968 return hr;
969
970 //
971 CComPtr<IMenuPopup> popup;
972 hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
973 if (FAILED_UNEXPECTEDLY(hr))
974 return hr;
975
976 m_subMenuChild = popup;
977
978 if (m_subMenuParent)
979 IUnknown_SetSite(popup, m_subMenuParent);
980 else
981 IUnknown_SetSite(popup, m_site);
982
983 DWORD flags = MPPF_RIGHT;
984
985 if (keyInitiated && m_dwFlags & SMINIT_VERTICAL)
986 flags |= MPPF_INITIALSELECT;
987
988 popup->Popup(pAt, pExclude, flags);
989
990 return S_OK;
991 }
992
993 HRESULT CMenuBand::_DisableMouseTrack(BOOL bDisable)
994 {
995 if (m_staticToolbar)
996 m_staticToolbar->DisableMouseTrack(bDisable);
997 if (m_SFToolbar)
998 m_SFToolbar->DisableMouseTrack(bDisable);
999 return S_OK;
1000 }
1001
1002 HRESULT CMenuBand::_KillPopupTimers()
1003 {
1004 HRESULT hr = S_OK;
1005 if (m_staticToolbar)
1006 hr = m_staticToolbar->KillPopupTimer();
1007 if (FAILED(hr))
1008 return hr;
1009
1010 if (m_SFToolbar)
1011 hr = m_SFToolbar->KillPopupTimer();
1012
1013 return hr;
1014 }
1015
1016 HRESULT STDMETHODCALLTYPE CMenuBand::InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
1017 {
1018 UNIMPLEMENTED;
1019 return S_OK;
1020 }
1021
1022 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(LPSMDATA psmd)
1023 {
1024 UNIMPLEMENTED;
1025 return S_OK;
1026 }
1027
1028 HRESULT STDMETHODCALLTYPE CMenuBand::SetMenuToolbar(IUnknown *punk, DWORD dwFlags)
1029 {
1030 UNIMPLEMENTED;
1031 return S_OK;
1032 }
1033
1034 HRESULT STDMETHODCALLTYPE CMenuBand::ResizeBorderDW(LPCRECT prcBorder, IUnknown *punkToolbarSite, BOOL fReserved)
1035 {
1036 UNIMPLEMENTED;
1037 return S_OK;
1038 }
1039
1040 HRESULT STDMETHODCALLTYPE CMenuBand::ContextSensitiveHelp(BOOL fEnterMode)
1041 {
1042 UNIMPLEMENTED;
1043 return S_OK;
1044 }
1045
1046 HRESULT STDMETHODCALLTYPE CMenuBand::GetSubMenu(THIS)
1047 {
1048 UNIMPLEMENTED;
1049 return S_OK;
1050 }
1051
1052 HRESULT STDMETHODCALLTYPE CMenuBand::SetToolbar(THIS)
1053 {
1054 UNIMPLEMENTED;
1055 return S_OK;
1056 }
1057
1058 HRESULT STDMETHODCALLTYPE CMenuBand::SetMinWidth(THIS)
1059 {
1060 UNIMPLEMENTED;
1061 return S_OK;
1062 }
1063
1064 HRESULT STDMETHODCALLTYPE CMenuBand::SetNoBorder(THIS)
1065 {
1066 UNIMPLEMENTED;
1067 return S_OK;
1068 }
1069
1070 HRESULT STDMETHODCALLTYPE CMenuBand::SetTheme(THIS)
1071 {
1072 UNIMPLEMENTED;
1073 return S_OK;
1074 }
1075
1076 HRESULT STDMETHODCALLTYPE CMenuBand::GetTop(THIS)
1077 {
1078 UNIMPLEMENTED;
1079 return S_OK;
1080 }
1081
1082 HRESULT STDMETHODCALLTYPE CMenuBand::GetBottom(THIS)
1083 {
1084 UNIMPLEMENTED;
1085 return S_OK;
1086 }
1087
1088 HRESULT STDMETHODCALLTYPE CMenuBand::GetTracked(THIS)
1089 {
1090 UNIMPLEMENTED;
1091 return S_OK;
1092 }
1093
1094 HRESULT STDMETHODCALLTYPE CMenuBand::GetParentSite(THIS)
1095 {
1096 UNIMPLEMENTED;
1097 return S_OK;
1098 }
1099
1100 HRESULT STDMETHODCALLTYPE CMenuBand::GetState(THIS)
1101 {
1102 UNIMPLEMENTED;
1103 return S_OK;
1104 }
1105
1106 HRESULT STDMETHODCALLTYPE CMenuBand::DoDefaultAction(THIS)
1107 {
1108 UNIMPLEMENTED;
1109 return S_OK;
1110 }
1111
1112 HRESULT STDMETHODCALLTYPE CMenuBand::IsEmpty(THIS)
1113 {
1114 UNIMPLEMENTED;
1115 return S_OK;
1116 }
1117
1118 HRESULT STDMETHODCALLTYPE CMenuBand::HasFocusIO()
1119 {
1120 if (m_popupBar)
1121 return S_OK;
1122 return S_FALSE;
1123 }
1124
1125 HRESULT STDMETHODCALLTYPE CMenuBand::TranslateAcceleratorIO(LPMSG lpMsg)
1126 {
1127 // TODO: Alt down -> toggle menu focus
1128 return S_FALSE;
1129 }
1130
1131 HRESULT STDMETHODCALLTYPE CMenuBand::IsDirty()
1132 {
1133 UNIMPLEMENTED;
1134 return S_OK;
1135 }
1136
1137 HRESULT STDMETHODCALLTYPE CMenuBand::Load(IStream *pStm)
1138 {
1139 UNIMPLEMENTED;
1140 return S_OK;
1141 }
1142
1143 HRESULT STDMETHODCALLTYPE CMenuBand::Save(IStream *pStm, BOOL fClearDirty)
1144 {
1145 UNIMPLEMENTED;
1146 return S_OK;
1147 }
1148
1149 HRESULT STDMETHODCALLTYPE CMenuBand::GetSizeMax(ULARGE_INTEGER *pcbSize)
1150 {
1151 UNIMPLEMENTED;
1152 return S_OK;
1153 }
1154
1155 HRESULT STDMETHODCALLTYPE CMenuBand::GetClassID(CLSID *pClassID)
1156 {
1157 UNIMPLEMENTED;
1158 return S_OK;
1159 }
1160
1161 HRESULT STDMETHODCALLTYPE CMenuBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
1162 {
1163 UNIMPLEMENTED;
1164 return S_OK;
1165 }