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 m_Banner = hBitmap; 555 556 BOOL bHandled; 557 _OnSize(WM_SIZE, 0, 0, bHandled); 558 559 return S_OK; 560 } 561 562 HRESULT STDMETHODCALLTYPE CMenuDeskBar::GetBitmap(THIS_ HBITMAP* phBitmap) 563 { 564 if (phBitmap) 565 *phBitmap = m_Banner; 566 return S_OK; 567 } 568 569 HRESULT STDMETHODCALLTYPE CMenuDeskBar::SetSubMenu(IMenuPopup *pmp, BOOL fSet) 570 { 571 // Called by the MenuBand to assign itself as the logical child of the DeskBar 572 573 if (fSet) 574 { 575 m_SubMenuChild = pmp; 576 } 577 else 578 { 579 if (m_SubMenuChild) 580 { 581 if (pmp == m_SubMenuChild) 582 { 583 m_SubMenuChild = NULL; 584 } 585 } 586 } 587 return S_OK; 588 } 589 590 HRESULT STDMETHODCALLTYPE CMenuDeskBar::OnSelect(DWORD dwSelectType) 591 { 592 CComPtr<IDeskBar> safeThis = this; 593 CComPtr<IMenuPopup> oldParent = m_SubMenuParent; 594 595 TRACE("OnSelect dwSelectType=%d\n", this, dwSelectType); 596 switch (dwSelectType) 597 { 598 case MPOS_EXECUTE: 599 case MPOS_FULLCANCEL: 600 case MPOS_CANCELLEVEL: 601 602 _CloseBar(); 603 604 if (dwSelectType == MPOS_CANCELLEVEL) 605 return S_OK; 606 607 case MPOS_SELECTLEFT: 608 case MPOS_SELECTRIGHT: 609 case MPOS_CHILDTRACKING: 610 if (oldParent) 611 return oldParent->OnSelect(dwSelectType); 612 break; 613 } 614 615 return S_OK; 616 } 617 618 HRESULT CMenuDeskBar::_CloseBar() 619 { 620 CComPtr<IDeskBarClient> dbc; 621 HRESULT hr; 622 623 // Ensure that our data isn't destroyed while we are working 624 CComPtr<IDeskBar> safeThis = this; 625 626 m_Shown = false; 627 628 if (m_SubMenuParent) 629 { 630 m_SubMenuParent->SetSubMenu(this, FALSE); 631 } 632 633 if (m_SubMenuChild) 634 { 635 hr = m_SubMenuChild->OnSelect(MPOS_CANCELLEVEL); 636 if (FAILED_UNEXPECTEDLY(hr)) 637 return hr; 638 } 639 640 hr = m_Client->QueryInterface(IID_PPV_ARG(IDeskBarClient, &dbc)); 641 if (FAILED_UNEXPECTEDLY(hr)) 642 return hr; 643 644 hr = dbc->UIActivateDBC(FALSE); 645 if (FAILED_UNEXPECTEDLY(hr)) 646 return hr; 647 648 SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE); 649 650 return UIActivateIO(FALSE, NULL); 651 } 652 653 BOOL CMenuDeskBar::_IsSubMenuParent(HWND hwnd) 654 { 655 CComPtr<IMenuPopup> popup = m_SubMenuParent; 656 657 while (popup) 658 { 659 HRESULT hr; 660 HWND parent; 661 662 hr = IUnknown_GetWindow(popup, &parent); 663 if (FAILED_UNEXPECTEDLY(hr)) 664 return FALSE; 665 if (hwnd == parent) 666 return TRUE; 667 668 hr = IUnknown_GetSite(popup, IID_PPV_ARG(IMenuPopup, &popup)); 669 if (FAILED(hr)) 670 return FALSE; 671 } 672 673 return FALSE; 674 } 675 676 LRESULT CMenuDeskBar::_OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 677 { 678 if (m_Client) 679 { 680 RECT rc; 681 682 GetClientRect(&rc); 683 684 if (m_Banner != NULL) 685 { 686 BITMAP bm; 687 ::GetObject(m_Banner, sizeof(bm), &bm); 688 rc.left += bm.bmWidth; 689 } 690 691 ::SetWindowPos(m_ClientWindow, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0); 692 } 693 694 return 0; 695 } 696 697 LRESULT CMenuDeskBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 698 { 699 if (!m_Client) 700 return 0; 701 702 CComPtr<IWinEventHandler> winEventHandler; 703 HRESULT hr = m_Client->QueryInterface(IID_PPV_ARG(IWinEventHandler, &winEventHandler)); 704 if (FAILED_UNEXPECTEDLY(hr)) 705 return 0; 706 707 if (winEventHandler) 708 { 709 LRESULT result; 710 hr = winEventHandler->OnWinEvent(NULL, uMsg, wParam, lParam, &result); 711 if (FAILED_UNEXPECTEDLY(hr)) 712 return 0; 713 return result; 714 } 715 716 return 0; 717 } 718 719 LRESULT CMenuDeskBar::_OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 720 { 721 bHandled = FALSE; 722 723 if (m_Banner && !m_IconSize) 724 { 725 BITMAP bm; 726 PAINTSTRUCT ps; 727 HDC hdc = BeginPaint(&ps); 728 729 HDC hdcMem = ::CreateCompatibleDC(hdc); 730 HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_Banner); 731 732 ::GetObject(m_Banner, sizeof(bm), &bm); 733 734 RECT rc; 735 if (!GetClientRect(&rc)) 736 WARN("GetClientRect failed\n"); 737 738 const int bx = bm.bmWidth; 739 const int by = bm.bmHeight; 740 const int cy = rc.bottom; 741 742 TRACE("Painting banner: %d by %d\n", bm.bmWidth, bm.bmHeight); 743 744 if (!::StretchBlt(hdc, 0, 0, bx, cy - by, hdcMem, 0, 0, bx, 1, SRCCOPY)) 745 WARN("StretchBlt failed\n"); 746 747 if (!::BitBlt(hdc, 0, cy - by, bx, by, hdcMem, 0, 0, SRCCOPY)) 748 WARN("BitBlt failed\n"); 749 750 ::SelectObject(hdcMem, hbmOld); 751 ::DeleteDC(hdcMem); 752 753 EndPaint(&ps); 754 } 755 756 return TRUE; 757 } 758 759 LRESULT CMenuDeskBar::_OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 760 { 761 // BUG in ReactOS: WM_ACTIVATE/WA_INACTIVE makes no sense with lParam==hWnd 762 if (LOWORD(wParam) != 0 || reinterpret_cast<HWND>(lParam) == m_hWnd) 763 { 764 return 0; 765 } 766 767 // HACK! I just want it to work !!! 768 CComPtr<IDeskBar> db; 769 HRESULT hr = IUnknown_QueryService(m_Client, SID_SMenuBandChild, IID_PPV_ARG(IDeskBar, &db)); 770 if (FAILED_UNEXPECTEDLY(hr)) 771 return 0; 772 773 CComPtr<IUnknown> punk; 774 775 hr = db->GetClient(&punk); 776 if (FAILED_UNEXPECTEDLY(hr)) 777 return 0; 778 779 if (!punk && m_Shown) 780 { 781 if (!_IsSubMenuParent(reinterpret_cast<HWND>(lParam))) 782 { 783 OnSelect(MPOS_FULLCANCEL); 784 } 785 } 786 787 return 0; 788 } 789 790 LRESULT CMenuDeskBar::_OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 791 { 792 return MA_NOACTIVATE; 793 } 794 795 LRESULT CMenuDeskBar::_OnAppActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 796 { 797 #if 0 798 if (wParam == 0 && m_Shown) 799 { 800 OnSelect(MPOS_FULLCANCEL); 801 } 802 #endif 803 return 0; 804 } 805 806 LRESULT CMenuDeskBar::_OnWinIniChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 807 { 808 if (wParam == SPI_SETFLATMENU) 809 return _OnNotify(uMsg, wParam, lParam, bHandled); 810 811 return 0; 812 } 813 814 LRESULT CMenuDeskBar::_OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 815 { 816 /* If it is a flat style menu we need to handle WM_NCPAINT 817 * and paint the border with the right colour */ 818 if ((GetStyle() & WS_BORDER) == 0) 819 { 820 /* This isn't a flat style menu. */ 821 bHandled = FALSE; 822 return 0; 823 } 824 825 HDC hdc; 826 RECT rcWindow; 827 828 hdc = GetWindowDC(); 829 GetWindowRect(&rcWindow); 830 OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top); 831 FrameRect(hdc, &rcWindow, GetSysColorBrush(COLOR_BTNSHADOW)); 832 ReleaseDC(hdc); 833 return 0; 834 } 835 836 LRESULT CMenuDeskBar::_OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 837 { 838 /* Prevent the CMenuDeskBar from destroying on being sent a WM_CLOSE */ 839 return 0; 840 } 841 842 HRESULT CMenuDeskBar::_AdjustForTheme(BOOL bFlatStyle) 843 { 844 DWORD style = bFlatStyle ? WS_BORDER : WS_CLIPCHILDREN|WS_DLGFRAME; 845 DWORD mask = WS_BORDER|WS_CLIPCHILDREN|WS_DLGFRAME; 846 SHSetWindowBits(m_hWnd, GWL_STYLE, mask, style); 847 return S_OK; 848 } 849 850 extern "C" 851 HRESULT WINAPI RSHELL_CMenuDeskBar_CreateInstance(REFIID riid, LPVOID *ppv) 852 { 853 return ShellObjectCreator<CMenuDeskBar>(riid, ppv); 854 } 855