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