[RSHELL][SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shellmenu / CMenuDeskBar.cpp
1 /*
2 * Shell Menu Desk Bar
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 <atlwin.h>
22 #include <shlwapi_undoc.h>
23
24 #include "CMenuDeskBar.h"
25
26 /* As far as I can tell, the submenu hierarchy looks like this:
27 *
28 * The DeskBar's Child is the Band it contains.
29 * The DeskBar's Parent is the SID_SMenuPopup of the Site.
30 *
31 * The Band's Child is the IMenuPopup of the child submenu.
32 * The Band's Parent is the SID_SMenuPopup of the Site (the DeskBar).
33 *
34 * When the DeskBar receives a selection event:
35 * If it requires closing the window, it will notify the Child (Band) using CancelLevel.
36 * If it has to spread upwards (everything but CancelLevel), it will notify the Parent.
37 *
38 * When the Band receives a selection event, this is where it gets fuzzy:
39 * In which cases does it call the Parent? Probably not CancelLevel.
40 * In which cases does it call the Child?
41 * How does it react to calls?
42 *
43 */
44
45
46 WINE_DEFAULT_DEBUG_CHANNEL(CMenuDeskBar);
47
48 extern "C"
49 HRESULT WINAPI CMenuDeskBar_Constructor(REFIID riid, LPVOID *ppv)
50 {
51 return ShellObjectCreator<CMenuDeskBar>(riid, ppv);
52 }
53
54 CMenuDeskBar::CMenuDeskBar() :
55 m_Client(NULL),
56 m_ClientWindow(NULL),
57 m_IconSize(0),
58 m_Banner(NULL),
59 m_Shown(FALSE),
60 m_ShowFlags(0),
61 m_didAddRef(FALSE)
62 {
63 }
64
65 CMenuDeskBar::~CMenuDeskBar()
66 {
67 }
68
69 LRESULT CMenuDeskBar::_OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
70 {
71 if (!m_didAddRef)
72 {
73 this->AddRef();
74 m_didAddRef = TRUE;
75 }
76
77 bHandled = FALSE;
78 return 0;
79 }
80
81 void CMenuDeskBar::OnFinalMessage(HWND /* hWnd */)
82 {
83 if (m_didAddRef)
84 {
85 this->Release();
86 m_didAddRef = FALSE;
87 }
88 }
89
90 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Initialize(THIS)
91 {
92 return S_OK;
93 }
94
95 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetWindow(HWND *lphwnd)
96 {
97 if (lphwnd == NULL)
98 return E_POINTER;
99 *lphwnd = m_hWnd;
100 return S_OK;
101 }
102
103 HRESULT STDMETHODCALLTYPE CMenuDeskBar::ContextSensitiveHelp(BOOL fEnterMode)
104 {
105 return E_NOTIMPL;
106 }
107
108 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus)
109 {
110 return IUnknown_OnFocusChangeIS(m_Client, punkObj, fSetFocus);
111 }
112
113 HRESULT STDMETHODCALLTYPE CMenuDeskBar::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
114 OLECMD prgCmds [], OLECMDTEXT *pCmdText)
115 {
116 return E_NOTIMPL;
117 }
118
119 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
120 DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
121 {
122 if (IsEqualIID(*pguidCmdGroup, CGID_MenuDeskBar))
123 {
124 switch (nCmdID)
125 {
126 case 2: // refresh
127 return S_OK;
128 case 3: // load complete
129 return S_OK;
130 case 4: // set font metrics
131 return _AdjustForTheme(nCmdexecopt);
132 }
133 }
134 if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
135 {
136 }
137 else if (IsEqualIID(*pguidCmdGroup, IID_IDeskBarClient))
138 {
139 switch (nCmdID)
140 {
141 case 0:
142 // hide current band
143 break;
144 case 2:
145 break;
146 case 3:
147 break;
148 }
149 }
150 return E_NOTIMPL;
151 }
152
153 HRESULT STDMETHODCALLTYPE CMenuDeskBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
154 {
155 HRESULT hr;
156
157 if (IsEqualGUID(guidService, SID_SMenuPopup) ||
158 IsEqualGUID(guidService, SID_SMenuBandParent) ||
159 IsEqualGUID(guidService, SID_STopLevelBrowser))
160 {
161 hr = this->QueryInterface(riid, ppvObject);
162 if (SUCCEEDED(hr))
163 return hr;
164 }
165
166 if (IsEqualGUID(guidService, SID_SMenuBandBottom) ||
167 IsEqualGUID(guidService, SID_SMenuBandBottomSelected) ||
168 IsEqualGUID(guidService, SID_SMenuBandChild))
169 {
170 if (m_Client == NULL)
171 return E_NOINTERFACE;
172
173 hr = IUnknown_QueryService(m_Client, guidService, riid, ppvObject);
174 if (SUCCEEDED(hr))
175 return hr;
176 }
177
178
179 if (m_Site == NULL)
180 return E_NOINTERFACE;
181
182 return IUnknown_QueryService(m_Site, guidService, riid, ppvObject);
183 }
184
185 HRESULT STDMETHODCALLTYPE CMenuDeskBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
186 {
187 return IUnknown_UIActivateIO(m_Client, fActivate, lpMsg);
188 }
189
190 HRESULT STDMETHODCALLTYPE CMenuDeskBar::HasFocusIO()
191 {
192 return IUnknown_HasFocusIO(m_Client);
193 }
194
195 HRESULT STDMETHODCALLTYPE CMenuDeskBar::TranslateAcceleratorIO(LPMSG lpMsg)
196 {
197 return IUnknown_TranslateAcceleratorIO(m_Client, lpMsg);
198 }
199
200 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetClient(IUnknown *punkClient)
201 {
202 CComPtr<IDeskBarClient> pDeskBandClient;
203 HRESULT hr;
204
205 if (m_Client)
206 {
207 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDeskBandClient));
208 if (FAILED_UNEXPECTEDLY(hr))
209 return hr;
210
211 pDeskBandClient->SetDeskBarSite(NULL);
212
213 pDeskBandClient = NULL;
214 m_Client = NULL;
215 }
216
217 if (punkClient == NULL)
218 return S_OK;
219
220 if (m_hWnd == NULL)
221 {
222 Create(NULL);
223 }
224
225 hr = punkClient->QueryInterface(IID_PPV_ARG(IUnknown, &m_Client));
226 if (FAILED_UNEXPECTEDLY(hr))
227 return hr;
228
229 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDeskBandClient));
230 if (FAILED_UNEXPECTEDLY(hr))
231 return hr;
232
233 hr = pDeskBandClient->SetDeskBarSite(static_cast<IDeskBar*>(this));
234 if (FAILED_UNEXPECTEDLY(hr))
235 return hr;
236
237 return IUnknown_GetWindow(m_Client, &m_ClientWindow);
238 }
239
240 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetClient(IUnknown **ppunkClient)
241 {
242 if (ppunkClient == NULL)
243 return E_POINTER;
244
245 if (!m_Client)
246 return E_FAIL;
247
248 return m_Client->QueryInterface(IID_PPV_ARG(IUnknown, ppunkClient));
249 }
250
251 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnPosRectChangeDB(LPRECT prc)
252 {
253 if (prc == NULL)
254 return E_POINTER;
255
256 return S_OK;
257 }
258
259 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSite(IUnknown *pUnkSite)
260 {
261 // Windows closes the bar if this is called when the bar is shown
262
263 if (m_Shown)
264 _CloseBar();
265
266 m_SubMenuParent = NULL;
267
268 m_Site = pUnkSite;
269
270 if (m_Site)
271 {
272 IUnknown_QueryService(m_Site, SID_SMenuPopup, IID_PPV_ARG(IMenuPopup, &m_SubMenuParent));
273 }
274 else
275 {
276 SetClient(NULL);
277 DestroyWindow();
278 }
279
280 return S_OK;
281 }
282
283 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetSite(REFIID riid, void **ppvSite)
284 {
285 if (m_Site == NULL)
286 return E_FAIL;
287
288 return m_Site->QueryInterface(riid, ppvSite);
289 }
290
291 static void AdjustForExcludeArea(BOOL alignLeft, BOOL alignTop, BOOL preferVertical, PINT px, PINT py, INT cx, INT cy, RECTL rcExclude) {
292 RECT rcWindow = { *px, *py, *px + cx, *py + cy };
293
294 if (rcWindow.right > rcExclude.left && rcWindow.left < rcExclude.right &&
295 rcWindow.bottom > rcExclude.top && rcWindow.top < rcExclude.bottom)
296 {
297 if (preferVertical)
298 {
299 if (alignTop && rcWindow.bottom > rcExclude.top)
300 *py = rcExclude.top - cy;
301 else if (!alignTop && rcWindow.top < rcExclude.bottom)
302 *py = rcExclude.bottom;
303 else if (alignLeft && rcWindow.right > rcExclude.left)
304 *px = rcExclude.left - cx;
305 else if (!alignLeft && rcWindow.left < rcExclude.right)
306 *px = rcExclude.right;
307 }
308 else
309 {
310 if (alignLeft && rcWindow.right > rcExclude.left)
311 *px = rcExclude.left - cx;
312 else if (!alignLeft && rcWindow.left < rcExclude.right)
313 *px = rcExclude.right;
314 else if (alignTop && rcWindow.bottom > rcExclude.top)
315 *py = rcExclude.top - cy;
316 else if (!alignTop && rcWindow.top < rcExclude.bottom)
317 *py = rcExclude.bottom;
318 }
319 }
320 }
321
322 HRESULT STDMETHODCALLTYPE CMenuDeskBar::Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
323 {
324 HRESULT hr;
325 CComPtr<IOleCommandTarget> oct;
326 CComPtr<IInputObject> io;
327 CComPtr<IDeskBand> band;
328 CComPtr<IDeskBarClient> dbc;
329
330 if (m_hWnd == NULL)
331 return E_FAIL;
332
333 hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IOleCommandTarget, &oct));
334 if (FAILED_UNEXPECTEDLY(hr))
335 return hr;
336
337 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc));
338 if (FAILED_UNEXPECTEDLY(hr))
339 return hr;
340
341 // Windows calls this, but it appears to be unimplemented?
342 hr = dbc->SetModeDBC(1);
343 // Allow it to fail with E_NOTIMPL.
344
345 // No clue about the arg, using anything != 0
346 hr = dbc->UIActivateDBC(TRUE);
347 if (FAILED_UNEXPECTEDLY(hr))
348 return hr;
349
350 RECT rc = { 0 };
351 hr = dbc->GetSize(0, &rc);
352 if (FAILED_UNEXPECTEDLY(hr))
353 return hr;
354
355 // Unknown meaning
356 const int CMD = 19;
357 const int CMD_EXEC_OPT = 0;
358
359 hr = IUnknown_QueryServiceExec(m_Client, SID_SMenuBandChild, &CLSID_MenuBand, CMD, CMD_EXEC_OPT, NULL, NULL);
360 if (FAILED_UNEXPECTEDLY(hr))
361 return hr;
362
363 ::AdjustWindowRect(&rc, ::GetWindowLong(m_hWnd, GWL_STYLE), FALSE);
364 ::OffsetRect(&rc, -rc.left, -rc.top);
365
366 if (m_Banner != NULL)
367 {
368 BITMAP bm;
369 ::GetObject(m_Banner, sizeof(bm), &bm);
370 rc.right += bm.bmWidth;
371 }
372
373 RECT rcWorkArea;
374 ::GetWindowRect(GetDesktopWindow(), &rcWorkArea);
375 int cxWorkArea = rcWorkArea.right - rcWorkArea.left;
376 int cyWorkArea = rcWorkArea.bottom - rcWorkArea.top;
377
378 int x = ppt->x;
379 int y = ppt->y;
380 int cx = rc.right - rc.left;
381 int cy = rc.bottom - rc.top;
382
383 // TODO: Make alignLeft default to TRUE in LTR systems or whenever necessary.
384 BOOL alignLeft = FALSE;
385 BOOL alignTop = FALSE;
386 BOOL preferVertical = FALSE;
387 switch (dwFlags & MPPF_POS_MASK)
388 {
389 case MPPF_TOP:
390 alignTop = TRUE;
391 preferVertical = TRUE;
392 break;
393 case MPPF_LEFT:
394 alignLeft = TRUE;
395 break;
396 case MPPF_BOTTOM:
397 alignTop = FALSE;
398 preferVertical = TRUE;
399 break;
400 case MPPF_RIGHT:
401 alignLeft = FALSE;
402 break;
403 }
404
405 // Try the selected alignment and verify that it doesn't escape the work area.
406 if (alignLeft)
407 {
408 x = ppt->x - cx;
409 }
410 else
411 {
412 x = ppt->x;
413 }
414
415 if (alignTop)
416 {
417 y = ppt->y - cy;
418 }
419 else
420 {
421 y = ppt->y;
422 }
423
424 if (prcExclude)
425 AdjustForExcludeArea(alignLeft, alignTop, preferVertical, &x, &y, cx, cy, *prcExclude);
426
427 // Verify that it doesn't escape the work area, and flip.
428 if (alignLeft)
429 {
430 if (x < rcWorkArea.left && (ppt->x+cx) <= rcWorkArea.right)
431 {
432 alignLeft = FALSE;
433 if (prcExclude)
434 x = prcExclude->right - ((x + cx) - prcExclude->left);
435 else
436 x = ppt->x;
437 }
438 }
439 else
440 {
441 if ((ppt->x + cx) > rcWorkArea.right && x >= rcWorkArea.left)
442 {
443 alignLeft = TRUE;
444 if (prcExclude)
445 x = prcExclude->left - cx + (prcExclude->right - x);
446 else
447 x = ppt->x - cx;
448 }
449 }
450
451 BOOL flipV = FALSE;
452 if (alignTop)
453 {
454 if (y < rcWorkArea.top && (ppt->y + cy) <= rcWorkArea.bottom)
455 {
456 alignTop = FALSE;
457 if (prcExclude)
458 y = prcExclude->bottom - ((y + cy) - prcExclude->top);
459 else
460 y = ppt->y;
461
462 flipV = true;
463 }
464 }
465 else
466 {
467 if ((ppt->y + cy) > rcWorkArea.bottom && y >= rcWorkArea.top)
468 {
469 alignTop = TRUE;
470 if (prcExclude)
471 y = prcExclude->top - cy + (prcExclude->bottom - y);
472 else
473 y = ppt->y - cy;
474
475 flipV = true;
476 }
477 }
478
479 if (prcExclude)
480 AdjustForExcludeArea(alignLeft, alignTop, preferVertical, &x, &y, cx, cy, *prcExclude);
481
482 if (x < rcWorkArea.left)
483 x = rcWorkArea.left;
484
485 if (cx > cxWorkArea)
486 cx = cxWorkArea;
487
488 if (x + cx > rcWorkArea.right)
489 x = rcWorkArea.right - cx;
490
491 if (y < rcWorkArea.top)
492 y = rcWorkArea.top;
493
494 if (cy > cyWorkArea)
495 cy = cyWorkArea;
496
497 if (y + cy > rcWorkArea.bottom)
498 y = rcWorkArea.bottom - cy;
499
500 int flags = SWP_SHOWWINDOW | SWP_NOACTIVATE;
501
502 this->SetWindowPos(HWND_TOPMOST, x, y, cx, cy, flags);
503
504 if (flipV)
505 {
506 if (dwFlags & MPPF_INITIALSELECT)
507 dwFlags = (dwFlags ^ MPPF_INITIALSELECT) | MPPF_FINALSELECT;
508 else if (dwFlags & MPPF_FINALSELECT)
509 dwFlags = (dwFlags ^ MPPF_FINALSELECT) | MPPF_INITIALSELECT;
510 }
511
512 m_ShowFlags = dwFlags;
513 m_Shown = true;
514
515 // HACK: The bar needs to be notified of the size AFTER it is shown.
516 // Quick & dirty way of getting it done.
517 BOOL bHandled;
518 _OnSize(WM_SIZE, 0, 0, bHandled);
519
520 UIActivateIO(TRUE, NULL);
521
522 if (dwFlags & (MPPF_INITIALSELECT | MPPF_FINALSELECT))
523 {
524 const int CMD_SELECT = 5;
525 int CMD_SELECT_OPTS = dwFlags & MPPF_INITIALSELECT ? 0 : -2;
526 IUnknown_QueryServiceExec(m_Client, SID_SMenuBandChild, &CLSID_MenuBand, CMD_SELECT, CMD_SELECT_OPTS, NULL, NULL);
527 }
528
529 return S_OK;
530 }
531
532 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetIconSize(THIS_ DWORD iIcon)
533 {
534 HRESULT hr;
535 m_IconSize = iIcon;
536
537 // Unknown meaning (set flags? set icon size?)
538 const int CMD = 16;
539 const int CMD_EXEC_OPT = iIcon ? 0 : 2; // seems to work
540
541 hr = IUnknown_QueryServiceExec(m_Client, SID_SMenuBandChild, &CLSID_MenuBand, CMD, CMD_EXEC_OPT, NULL, NULL);
542 if (FAILED_UNEXPECTEDLY(hr))
543 return hr;
544
545 BOOL bHandled;
546 _OnSize(WM_SIZE, 0, 0, bHandled);
547
548 return hr;
549 }
550
551 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetIconSize(THIS_ DWORD* piIcon)
552 {
553 if (piIcon)
554 *piIcon = m_IconSize;
555 return S_OK;
556 }
557
558 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetBitmap(THIS_ HBITMAP hBitmap)
559 {
560 m_Banner = hBitmap;
561
562 BOOL bHandled;
563 _OnSize(WM_SIZE, 0, 0, bHandled);
564
565 return S_OK;
566 }
567
568 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap)
569 {
570 if (phBitmap)
571 *phBitmap = m_Banner;
572 return S_OK;
573 }
574
575 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet)
576 {
577 // Called by the MenuBand to assign itself as the logical child of the DeskBar
578
579 if (fSet)
580 {
581 m_SubMenuChild = pmp;
582 }
583 else
584 {
585 if (m_SubMenuChild)
586 {
587 if (pmp == m_SubMenuChild)
588 {
589 m_SubMenuChild = NULL;
590 }
591 }
592 }
593 return S_OK;
594 }
595
596 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType)
597 {
598 CComPtr<IDeskBar> safeThis = this;
599 CComPtr<IMenuPopup> oldParent = m_SubMenuParent;
600
601 TRACE("OnSelect dwSelectType=%d\n", this, dwSelectType);
602 switch (dwSelectType)
603 {
604 case MPOS_EXECUTE:
605 case MPOS_FULLCANCEL:
606 case MPOS_CANCELLEVEL:
607
608 _CloseBar();
609
610 if (dwSelectType == MPOS_CANCELLEVEL)
611 return S_OK;
612
613 case MPOS_SELECTLEFT:
614 case MPOS_SELECTRIGHT:
615 case MPOS_CHILDTRACKING:
616 if (oldParent)
617 return oldParent->OnSelect(dwSelectType);
618 break;
619 }
620
621 return S_OK;
622 }
623
624 HRESULT CMenuDeskBar::_CloseBar()
625 {
626 CComPtr<IDeskBarClient> dbc;
627 HRESULT hr;
628
629 // Ensure that our data isn't destroyed while we are working
630 CComPtr<IDeskBar> safeThis = this;
631
632 m_Shown = false;
633
634 if (m_SubMenuParent)
635 {
636 m_SubMenuParent->SetSubMenu(this, FALSE);
637 }
638
639 if (m_SubMenuChild)
640 {
641 hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL);
642 if (FAILED_UNEXPECTEDLY(hr))
643 return hr;
644 }
645
646 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc));
647 if (FAILED_UNEXPECTEDLY(hr))
648 return hr;
649
650 hr = dbc->UIActivateDBC(FALSE);
651 if (FAILED_UNEXPECTEDLY(hr))
652 return hr;
653
654 SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE);
655
656 return UIActivateIO(FALSE, NULL);
657 }
658
659 BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd)
660 {
661 CComPtr<IMenuPopup> popup = m_SubMenuParent;
662
663 while (popup)
664 {
665 HRESULT hr;
666 HWND parent;
667
668 hr = IUnknown_GetWindow(popup, &parent);
669 if (FAILED_UNEXPECTEDLY(hr))
670 return FALSE;
671 if (hwnd == parent)
672 return TRUE;
673
674 hr = IUnknown_GetSite(popup, IID_PPV_ARG(IMenuPopup, &popup));
675 if (FAILED(hr))
676 return FALSE;
677 }
678
679 return FALSE;
680 }
681
682 LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
683 {
684 if (m_Client)
685 {
686 RECT rc;
687
688 GetClientRect(&rc);
689
690 if (m_Banner != NULL)
691 {
692 BITMAP bm;
693 ::GetObject(m_Banner, sizeof(bm), &bm);
694 rc.left += bm.bmWidth;
695 }
696
697 ::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0);
698 }
699
700 return 0;
701 }
702
703 LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
704 {
705 if (!m_Client)
706 return 0;
707
708 CComPtr<IWinEventHandler> winEventHandler;
709 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler));
710 if (FAILED_UNEXPECTEDLY(hr))
711 return 0;
712
713 if (winEventHandler)
714 {
715 LRESULT result;
716 hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result);
717 if (FAILED_UNEXPECTEDLY(hr))
718 return 0;
719 return result;
720 }
721
722 return 0;
723 }
724
725 LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
726 {
727 bHandled = FALSE;
728
729 if (m_Banner && !m_IconSize)
730 {
731 BITMAP bm;
732 PAINTSTRUCT ps;
733 HDC hdc = BeginPaint(&ps);
734
735 HDC hdcMem = ::CreateCompatibleDC(hdc);
736 HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner);
737
738 ::GetObject(m_Banner, sizeof(bm), &bm);
739
740 RECT rc;
741 if (!GetClientRect(&rc))
742 WARN("GetClientRect failed\n");
743
744 const int bx = bm.bmWidth;
745 const int by = bm.bmHeight;
746 const int cy = rc.bottom;
747
748 TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight);
749
750 if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY))
751 WARN("StretchBlt failed\n");
752
753 if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY))
754 WARN("BitBlt failed\n");
755
756 ::SelectObject(hdcMem, hbmOld);
757 ::DeleteDC(hdcMem);
758
759 EndPaint(&ps);
760 }
761
762 return TRUE;
763 }
764
765 LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
766 {
767 // BUG in ReactOS: WM_ACTIVATE/WA_INACTIVE makes no sense with lParam==hWnd
768 if (LOWORD(wParam) != 0 || reinterpret_cast<HWND>(lParam) == m_hWnd)
769 {
770 return 0;
771 }
772
773 // HACK! I just want it to work !!!
774 CComPtr<IDeskBar> db;
775 HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db));
776 if (FAILED_UNEXPECTEDLY(hr))
777 return 0;
778
779 CComPtr<IUnknown> punk;
780
781 hr = db->GetClient(&punk);
782 if (FAILED_UNEXPECTEDLY(hr))
783 return 0;
784
785 if (!punk && m_Shown)
786 {
787 if (!_IsSubMenuParent(reinterpret_cast<HWND>(lParam)))
788 {
789 OnSelect(MPOS_FULLCANCEL);
790 }
791 }
792
793 return 0;
794 }
795
796 LRESULT CMenuDeskBar::_OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
797 {
798 return MA_NOACTIVATE;
799 }
800
801 LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
802 {
803 #if 0
804 if (wParam == 0 && m_Shown)
805 {
806 OnSelect(MPOS_FULLCANCEL);
807 }
808 #endif
809 return 0;
810 }
811
812 LRESULT CMenuDeskBar::_OnWinIniChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
813 {
814 if (wParam == SPI_SETFLATMENU)
815 return _OnNotify(uMsg, wParam, lParam, bHandled);
816
817 return 0;
818 }
819
820 HRESULT CMenuDeskBar::_AdjustForTheme(BOOL bFlatStyle)
821 {
822 DWORD style = bFlatStyle ? WS_BORDER : WS_CLIPCHILDREN|WS_DLGFRAME;
823 DWORD mask = WS_BORDER|WS_CLIPCHILDREN|WS_DLGFRAME;
824 SHSetWindowBits(m_hWnd, GWL_STYLE, mask, style);
825 return S_OK;
826 }