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