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