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