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