Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1509 lines
41 KiB

  1. #include "shellprv.h"
  2. #include "common.h"
  3. #include "mnstatic.h"
  4. #include "menuband.h"
  5. #include "dpastuff.h" // COrderList_*
  6. #include "resource.h"
  7. #include "mnbase.h"
  8. #include "oleacc.h"
  9. #include "apithk.h"
  10. #include <uxtheme.h>
  11. #include "menuisf.h"
  12. #define PGMP_RECALCSIZE 200
  13. //*** IDTTOIDM -- convert idtCmd to idmMenu
  14. // NOTES
  15. // as an optimization, we make the toolbar idtCmd the same as the menu idm.
  16. // this macro (hopefully) makes things a bit clearer in the code by making
  17. // the type conversion explicit.
  18. #define IDTTOIDM(idtBtn) (idtBtn)
  19. BOOL TBHasImage(HWND hwnd, int iImageIndex);
  20. //------------------------------------------------------------------------
  21. //
  22. // CMenuStaticToolbar::CMenuStaticData class
  23. //
  24. //------------------------------------------------------------------------
  25. CMenuStaticToolbar::CMenuStaticData::~CMenuStaticData()
  26. {
  27. ATOMICRELEASE(_punkSubMenu);
  28. }
  29. void CMenuStaticToolbar::CMenuStaticData::SetSubMenu(IUnknown* punk)
  30. {
  31. ATOMICRELEASE(_punkSubMenu);
  32. _punkSubMenu = punk;
  33. if (_punkSubMenu)
  34. _punkSubMenu->AddRef();
  35. }
  36. HRESULT CMenuStaticToolbar::CMenuStaticData::GetSubMenu(const GUID* pguidService, REFIID riid, void** ppvObj)
  37. {
  38. if (_punkSubMenu)
  39. {
  40. if (pguidService)
  41. {
  42. return IUnknown_QueryService(_punkSubMenu, *pguidService, riid, ppvObj);
  43. }
  44. else
  45. return _punkSubMenu->QueryInterface(riid, ppvObj);
  46. }
  47. else
  48. return E_NOINTERFACE;
  49. }
  50. //------------------------------------------------------------------------
  51. //
  52. // CMenuStaticToolbar
  53. //
  54. //------------------------------------------------------------------------
  55. CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand* pmb, HMENU hmenu, HWND hwnd, UINT idCmd, DWORD dwFlags)
  56. : CMenuToolbarBase(pmb, dwFlags)
  57. {
  58. _hmenu = hmenu;
  59. _hwndMenuOwner = hwnd;
  60. _idCmd = idCmd;
  61. _iDragOverButton = -1;
  62. _fDirty = TRUE;
  63. }
  64. CMenuStaticToolbar::~CMenuStaticToolbar()
  65. {
  66. if (!(_dwFlags & SMSET_DONTOWN))
  67. {
  68. DestroyMenu(_hmenu);
  69. }
  70. }
  71. STDMETHODIMP CMenuStaticToolbar::QueryInterface(REFIID riid, void** ppvObj)
  72. {
  73. static const QITAB qit[] =
  74. {
  75. QITABENT(CMenuStaticToolbar, IDropTarget),
  76. { 0 },
  77. };
  78. // If you QI MenuStatic for a drop target, you get a different
  79. // one than if you QI MenuShellFolder. This breaks COM identity rules.
  80. // Proper fix would be to implement a drop target that encapsulates both.
  81. HRESULT hres = QISearch(this, qit, riid, ppvObj);
  82. if (FAILED(hres))
  83. hres = CMenuToolbarBase::QueryInterface(riid, ppvObj);
  84. return hres;
  85. }
  86. void CMenuStaticToolbar::_CheckSeparators()
  87. {
  88. if (_fHasTopSep)
  89. {
  90. if (_pcmb->_pmtbTop->DontShowEmpty() )
  91. {
  92. if (!_fTopSepRemoved)
  93. {
  94. SendMessage(_hwndMB, TB_DELETEBUTTON, 0, 0);
  95. _fTopSepRemoved = TRUE;
  96. }
  97. }
  98. else
  99. {
  100. if (_fTopSepRemoved)
  101. {
  102. MENUITEMINFO mii = {0};
  103. mii.cbSize = sizeof(mii);
  104. mii.fType = MFT_SEPARATOR;
  105. _Insert(0, &mii);
  106. _fTopSepRemoved = FALSE;
  107. }
  108. }
  109. }
  110. if (_fHasBottomSep)
  111. {
  112. if (_pcmb->_pmtbBottom->DontShowEmpty() )
  113. {
  114. if (!_fBottomSepRemoved)
  115. {
  116. SendMessage(_hwndMB, TB_DELETEBUTTON, ToolBar_ButtonCount(_hwndMB) - 1, 0);
  117. _fBottomSepRemoved = TRUE;
  118. }
  119. }
  120. else
  121. {
  122. if (_fBottomSepRemoved)
  123. {
  124. MENUITEMINFO mii = {0};
  125. mii.cbSize = sizeof(mii);
  126. mii.fType = SMIT_SEPARATOR;
  127. _Insert(-1, &mii);
  128. _fBottomSepRemoved = FALSE;
  129. }
  130. }
  131. }
  132. }
  133. void CMenuStaticToolbar::v_Show(BOOL fShow, BOOL fForceUpdate)
  134. {
  135. CMenuToolbarBase::v_Show(fShow, fForceUpdate);
  136. _fShowMB = fShow;
  137. if (fShow)
  138. {
  139. _fFirstTime = FALSE;
  140. _fClickHandled = FALSE;
  141. _FillToolbar();
  142. _pcmb->SetTracked(NULL);
  143. ToolBar_SetHotItem(_hwndMB, -1);
  144. // Have the menubar think about changing its height
  145. IUnknown_QueryServiceExec(_pcmb->_punkSite, SID_SMenuPopup, &CGID_MENUDESKBAR,
  146. MBCID_SETEXPAND, (int)_pcmb->_fExpanded, NULL, NULL);
  147. if (fForceUpdate)
  148. v_UpdateButtons(FALSE);
  149. #if 0
  150. // need top level frame available for D&D if possible.
  151. _hwndDD = GetParent(_hwndMB);
  152. IOleWindow *pOleWindow;
  153. HRESULT hr = IUnknown_QueryService(_pcmb->_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IOleWindow, &pOleWindow));
  154. if (SUCCEEDED(hr))
  155. {
  156. ASSERT(pOleWindow);
  157. pOleWindow->GetWindow(&_hwndDD);
  158. pOleWindow->Release();
  159. }
  160. #endif
  161. CDelegateDropTarget::Init();
  162. }
  163. else
  164. KillTimer(_hwndMB, MBTIMER_UEMTIMEOUT);
  165. // n.b. for !fShow, we don't kill the tracked site chain. we
  166. // count on this in startmnu.cpp!CStartMenuCallback::_OnExecItem,
  167. // where we walk up the chain to find all hit 'nodes'. if we need
  168. // to change this we could fire a 'pre-exec' event.
  169. }
  170. void CMenuStaticToolbar::_Insert(int iIndex, MENUITEMINFO* pmii)
  171. {
  172. CMenuStaticData* pmsd = new CMenuStaticData();
  173. if (pmsd)
  174. {
  175. BYTE bTBStyle = TBSTYLE_BUTTON | TBSTYLE_DROPDOWN;
  176. SMINFO sminfo = {0};
  177. sminfo.dwMask = SMIM_TYPE | SMIM_FLAGS | SMIM_ICON;
  178. // These are somethings that the callback does not fill in:
  179. if ( pmii->hSubMenu )
  180. sminfo.dwFlags |= SMIF_SUBMENU;
  181. if ( pmii->fState & MFS_CHECKED)
  182. sminfo.dwFlags |= SMIF_CHECKED;
  183. if (pmii->fState & MFS_DISABLED || pmii->fState & MFS_GRAYED)
  184. sminfo.dwFlags |= SMIF_DISABLED;
  185. if ( pmii->fType & MFT_SEPARATOR)
  186. {
  187. sminfo.dwType = SMIT_SEPARATOR;
  188. bTBStyle &= ~TBSTYLE_BUTTON;
  189. bTBStyle |= TBSTYLE_SEP;
  190. }
  191. else
  192. sminfo.dwType = SMIT_STRING;
  193. if (!_fVerticalMB)
  194. bTBStyle |= TBSTYLE_AUTOSIZE;
  195. if (S_OK != CallCB(pmii->wID, SMC_GETINFO, 0, (LPARAM)&sminfo))
  196. {
  197. sminfo.iIcon = -1;
  198. }
  199. pmsd->_dwFlags = sminfo.dwFlags;
  200. // Now add it to the toolbar
  201. TBBUTTON tbb = {0};
  202. tbb.iBitmap = sminfo.iIcon;
  203. tbb.idCommand = pmii->wID;
  204. tbb.dwData = (DWORD_PTR)pmsd;
  205. tbb.fsState = (sminfo.dwFlags & SMIF_HIDDEN)?TBSTATE_HIDDEN : TBSTATE_ENABLED;
  206. tbb.fsStyle = bTBStyle;
  207. if (_dwFlags & SMSET_NOPREFIX)
  208. tbb.fsStyle |= BTNS_NOPREFIX;
  209. TCHAR szMenuString[MAX_PATH];
  210. if (pmii->fType & MFT_OWNERDRAW)
  211. {
  212. // dwTypeData is user defined 32 bit value, not a string if MFT_OWNERDRAW is set
  213. // then the (unicode) string is the very first element in a structure dwItemData
  214. // points to
  215. LPWSTR pwsz = (LPWSTR)pmii->dwItemData;
  216. SHUnicodeToTChar(pwsz, szMenuString, ARRAYSIZE(szMenuString));
  217. tbb.iString = (INT_PTR)(szMenuString);
  218. }
  219. else
  220. tbb.iString = (INT_PTR)(LPTSTR)pmii->dwTypeData;
  221. SendMessage(_hwndMB, TB_INSERTBUTTON, iIndex, (LPARAM)&tbb);
  222. }
  223. }
  224. /*----------------------------------------------------------
  225. Purpose: GetMenu method
  226. */
  227. HRESULT CMenuStaticToolbar::GetMenu(HMENU* phmenu, HWND* phwnd, DWORD* pdwFlags)
  228. {
  229. if (phmenu)
  230. *phmenu = _hmenu;
  231. if (phwnd)
  232. *phwnd = _hwndMenuOwner;
  233. if (pdwFlags)
  234. *pdwFlags = _dwFlags;
  235. return S_OK;
  236. }
  237. HRESULT CMenuStaticToolbar::SetMenu(HMENU hmenu, HWND hwnd, DWORD dwFlags)
  238. {
  239. // When we are merging in a new menu, we need to destroy the old one if we own it.
  240. if (_hmenu && !(_dwFlags & SMSET_DONTOWN))
  241. {
  242. DestroyMenu(_hmenu);
  243. }
  244. _hmenu = hmenu;
  245. // If we're processing a change notify, we cannot do anything that will modify state.
  246. if (_pcmb->_pmbState &&
  247. _pcmb->_pmbState->IsProcessingChangeNotify())
  248. {
  249. _fDirty = TRUE;
  250. }
  251. else
  252. {
  253. EmptyToolbar();
  254. _pcmb->_fInSubMenu = FALSE;
  255. IUnknown_SetSite(_pcmb->_pmpSubMenu, NULL);
  256. ATOMICRELEASE(_pcmb->_pmpSubMenu);
  257. if (_fShowMB)
  258. _FillToolbar();
  259. BOOL fSmooth = FALSE;
  260. #ifdef CLEARTYPE // Don't use SPI_CLEARTYPE because it's defined because of APIThk, but not in NT.
  261. SystemParametersInfo(SPI_GETCLEARTYPE, 0, &fSmooth, 0);
  262. #endif
  263. // This causes a paint to occur right away instead of waiting until the
  264. // next message dispatch which could take a noticably long time.
  265. RedrawWindow(_hwndMB, NULL, NULL, (fSmooth? RDW_ERASE: 0) | RDW_INVALIDATE | RDW_UPDATENOW);
  266. }
  267. return S_OK;
  268. }
  269. CMenuStaticToolbar::CMenuStaticData* CMenuStaticToolbar::_IDToData(int idCmd)
  270. {
  271. CMenuStaticData* pmsd= NULL;
  272. // Initialize to NULL in case the GetButtonInfo Fails. We won't fault because
  273. // the lParam is just stack garbage.
  274. TBBUTTONINFO tbbi = {0};
  275. int iPos;
  276. tbbi.cbSize = sizeof(tbbi);
  277. tbbi.dwMask = TBIF_LPARAM;
  278. iPos = ToolBar_GetButtonInfo(_hwndMB, idCmd, &tbbi);
  279. if (iPos >= 0)
  280. pmsd = (CMenuStaticData*)tbbi.lParam;
  281. return pmsd;
  282. }
  283. HRESULT CMenuStaticToolbar::v_CreateTrackPopup(int idCmd, REFIID riid, void** ppvObj)
  284. {
  285. HRESULT hres = E_OUTOFMEMORY;
  286. int iPos = (int)SendMessage(_hwndMB, TB_COMMANDTOINDEX, idCmd, 0);
  287. if (iPos >= 0)
  288. {
  289. CTrackPopupBar* ptpb = new CTrackPopupBar(_pcmb->_pmbState->GetContext(), iPos, _hmenu, _hwndMenuOwner);
  290. if (ptpb)
  291. {
  292. hres = ptpb->QueryInterface(riid, ppvObj);
  293. if (SUCCEEDED(hres))
  294. IUnknown_SetSite(SAFECAST(ptpb, IMenuPopup*), SAFECAST(_pcmb, IMenuPopup*));
  295. PostMessage(_pcmb->_pmbState->GetSubclassedHWND(), g_nMBAutomation, (WPARAM)_hmenu, (LPARAM)iPos);
  296. ptpb->Release();
  297. }
  298. }
  299. return hres;
  300. }
  301. HRESULT CMenuStaticToolbar::v_GetSubMenu(int idCmd, const GUID* pguidService, REFIID riid, void** ppvObj)
  302. {
  303. HRESULT hres = E_FAIL;
  304. CMenuStaticData* pmsd = _IDToData(idCmd);
  305. ASSERT(IS_VALID_WRITE_PTR(ppvObj, void*));
  306. *ppvObj = NULL;
  307. if (pmsd)
  308. {
  309. // Get the cached submenu
  310. hres = pmsd->GetSubMenu(pguidService, riid, ppvObj);
  311. // Did that fail?
  312. if (FAILED(hres) && (pmsd->_dwFlags & SMIF_SUBMENU) &&
  313. IsEqualGUID(riid, IID_IShellMenu))
  314. {
  315. // Yes; ask the callback for it
  316. hres = CallCB(idCmd, SMC_GETOBJECT, (WPARAM)&riid, (LPARAM)ppvObj);
  317. if (S_OK != hres)
  318. {
  319. hres = E_OUTOFMEMORY; // Set to error case incase something happens
  320. // Callback didn't handle it, try and see if we can get it
  321. MENUITEMINFO mii;
  322. mii.cbSize = sizeof(MENUITEMINFO);
  323. mii.fMask = MIIM_SUBMENU | MIIM_ID;
  324. if (GetMenuItemInfo(_hmenu, idCmd, MF_BYCOMMAND, &mii) && mii.hSubMenu)
  325. {
  326. IShellMenu* psm = (IShellMenu*)new CMenuBand();
  327. if (psm)
  328. {
  329. UINT uIdAncestor = _pcmb->_uIdAncestor;
  330. if (uIdAncestor == ANCESTORDEFAULT)
  331. uIdAncestor = idCmd;
  332. hres = psm->Initialize(_pcmb->_psmcb, idCmd, uIdAncestor, SMINIT_VERTICAL);
  333. if (SUCCEEDED(hres))
  334. {
  335. hres = psm->SetMenu(mii.hSubMenu, _hwndMenuOwner, SMSET_TOP | SMSET_DONTOWN);
  336. if (SUCCEEDED(hres))
  337. {
  338. hres = psm->QueryInterface(riid, ppvObj);
  339. }
  340. }
  341. psm->Release();
  342. }
  343. }
  344. }
  345. if (*ppvObj)
  346. {
  347. // Cache it now
  348. pmsd->SetSubMenu((IUnknown*)*ppvObj);
  349. // Initialize the fonts
  350. VARIANT Var;
  351. Var.vt = VT_UNKNOWN;
  352. Var.byref = SAFECAST(_pcmb->_pmbm, IUnknown*);
  353. IUnknown_Exec((IUnknown*)*ppvObj, &CGID_MenuBand, MBANDCID_SETFONTS, 0, &Var, NULL);
  354. // Set the CMenuBandState into the new menuband
  355. Var.vt = VT_INT_PTR;
  356. Var.byref = _pcmb->_pmbState;
  357. IUnknown_Exec((IUnknown*)*ppvObj, &CGID_MenuBand, MBANDCID_SETSTATEOBJECT, 0, &Var, NULL);
  358. ASSERT(IsEqualGUID(riid, IID_IShellMenu));
  359. _SetMenuBand((IShellMenu*)*ppvObj);
  360. }
  361. }
  362. }
  363. else
  364. {
  365. hres = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  366. }
  367. return hres;
  368. }
  369. HRESULT CMenuStaticToolbar::v_GetInfoTip(int idCmd, LPTSTR psz, UINT cch)
  370. {
  371. return CallCB(idCmd, SMC_GETINFOTIP, (WPARAM)psz, (LPARAM)cch);
  372. }
  373. HRESULT CMenuStaticToolbar::v_ExecItem(int idCmd)
  374. {
  375. HRESULT hres = CallCB(idCmd, SMC_EXEC, 0, 0);
  376. if (S_OK != hres && _hwndMenuOwner)
  377. {
  378. PostMessage(_hwndMenuOwner, WM_COMMAND, idCmd, 0);
  379. hres = S_OK;
  380. }
  381. return hres;
  382. }
  383. DWORD CMenuStaticToolbar::v_GetFlags(int idCmd)
  384. {
  385. CMenuStaticData* pmsd = _IDToData(idCmd);
  386. // Toolbar is allowed to pass a bad command in the case of erasing the background
  387. if (pmsd)
  388. {
  389. return pmsd->_dwFlags;
  390. }
  391. else
  392. return 0;
  393. }
  394. void CMenuStaticToolbar::v_SendMenuNotification(UINT idCmd, BOOL fClear)
  395. {
  396. if (S_FALSE == CallCB(idCmd, SMC_SELECTITEM, (WPARAM)fClear, 0))
  397. {
  398. UINT uFlags = (UINT)-1;
  399. if (v_GetFlags(idCmd) & SMIF_SUBMENU)
  400. uFlags = MF_POPUP;
  401. if (!fClear)
  402. uFlags = MF_HILITE;
  403. PostMessage(_pcmb->_pmbState->GetSubclassedHWND(), WM_MENUSELECT,
  404. MAKEWPARAM(idCmd, uFlags), fClear? NULL : (LPARAM)_hmenu);
  405. }
  406. }
  407. BOOL CMenuStaticToolbar::v_TrackingSubContextMenu()
  408. {
  409. return (_pcm != NULL);
  410. }
  411. HWND CMenuStaticToolbar::_CreatePager(HWND hwndParent)
  412. {
  413. _hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL,
  414. WS_CHILD | WS_TABSTOP |
  415. WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  416. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  417. if (_hwndPager)
  418. {
  419. hwndParent = _hwndPager;
  420. }
  421. return hwndParent;
  422. }
  423. HRESULT CMenuStaticToolbar::CreateToolbar(HWND hwndParent)
  424. {
  425. HRESULT hr = S_OK;
  426. if (!_hwndMB)
  427. {
  428. if (_dwFlags & SMSET_USEPAGER)
  429. {
  430. hwndParent = _CreatePager(hwndParent);
  431. }
  432. _hwndMB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, TEXT("Menu"),
  433. WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  434. WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  435. CCS_NODIVIDER | CCS_NOPARENTALIGN |
  436. CCS_NORESIZE | TBSTYLE_REGISTERDROP,
  437. 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  438. if (!_hwndMB)
  439. {
  440. TraceMsg(TF_MENUBAND, "CMenuStaticToolbar::CreateToolbar: Failed to Create Toolbar");
  441. return HRESULT_FROM_WIN32(GetLastError());
  442. }
  443. if (_hwndPager)
  444. SendMessage(_hwndPager, PGM_SETCHILD, 0, (LPARAM)_hwndMB);
  445. SendMessage(_hwndMB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  446. SendMessage(_hwndMB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  447. // Set the format to ANSI or UNICODE as appropriate.
  448. ToolBar_SetUnicodeFormat(_hwndMB, DLL_IS_UNICODE);
  449. _SubclassWindow(_hwndMB);
  450. _RegisterWindow(_hwndMB, NULL, SHCNE_UPDATEIMAGE);
  451. // Make sure we're on the same wavelength.
  452. SendMessage(_hwndMB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  453. RECT rc;
  454. SIZE size;
  455. SystemParametersInfoA(SPI_GETWORKAREA, sizeof(RECT), &rc, FALSE);
  456. if (!_hwndPager)
  457. {
  458. size.cx = RECTWIDTH(rc);
  459. size.cy = GetSystemMetrics(SM_CYSCREEN) - (2 * GetSystemMetrics(SM_CYEDGE)); // Need to subrtact off the borders
  460. }
  461. else
  462. {
  463. //HACKHACK: THIS WILL FORCE NO WRAP TO HAPPEN FOR PROPER WIDTH CALC WHEN PAGER IS PRESENT.
  464. size.cx = RECTWIDTH(rc);
  465. size.cy = 32000;
  466. }
  467. ToolBar_SetBoundingSize(_hwndMB, &size);
  468. if (_hwndPager)
  469. {
  470. SHSetWindowBits(_hwndPager, GWL_STYLE, PGS_DRAGNDROP, PGS_DRAGNDROP);
  471. SHSetWindowBits(_hwndPager, GWL_STYLE, PGS_AUTOSCROLL, PGS_AUTOSCROLL);
  472. SHSetWindowBits(_hwndPager, GWL_STYLE, PGS_HORZ|PGS_VERT,
  473. _fVerticalMB ? PGS_VERT : PGS_HORZ);
  474. }
  475. SetWindowTheme(_hwndMB, L"", L"");
  476. hr = CMenuToolbarBase::CreateToolbar(hwndParent);
  477. }
  478. else if (GetParent(_hwndMB) != hwndParent)
  479. ::SetParent(_hwndMB, hwndParent);
  480. return hr;
  481. }
  482. STDMETHODIMP CMenuStaticToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  483. {
  484. HRESULT hr = E_FAIL;
  485. AddRef();
  486. if (SHCNE_UPDATEIMAGE == lEvent) // global
  487. {
  488. hr = S_OK;
  489. if (pidl1)
  490. {
  491. int iImage = *(int UNALIGNED *)((BYTE *)pidl1 + 2);
  492. IEInvalidateImageList(); // We may need to use different icons.
  493. if (pidl2)
  494. {
  495. iImage = SHHandleUpdateImage( pidl2 );
  496. if ( iImage == -1 )
  497. {
  498. hr = E_FAIL;
  499. }
  500. }
  501. if (SUCCEEDED(hr) && (iImage == -1 || TBHasImage(_hwndMB, iImage)))
  502. {
  503. v_UpdateIconSize(-1, TRUE);
  504. v_Refresh();
  505. }
  506. }
  507. else
  508. {
  509. v_Refresh();
  510. }
  511. }
  512. Release();
  513. return hr;
  514. }
  515. LRESULT CMenuStaticToolbar::_DefWindowProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  516. {
  517. LRESULT lres = 0;
  518. switch(uMessage)
  519. {
  520. case WM_TIMER:
  521. if (_OnTimer(wParam))
  522. return 1;
  523. break;
  524. case WM_GETOBJECT:
  525. // Yet another poor design choice on the part of the accessibility team.
  526. // Typically, if you do not answer a WM_* you return 0. They choose 0 as their success
  527. // code.
  528. return _DefWindowProcMB(hwnd, uMessage, wParam, lParam);
  529. break;
  530. }
  531. return CNotifySubclassWndProc::_DefWindowProc(hwnd, uMessage, wParam, lParam);
  532. }
  533. //***
  534. // NOTES
  535. // idtCmd is currently always -1. we'll need other values when we're
  536. // called from CallCB. however we can't do that until we fix mnfolder.cpp.
  537. HRESULT CMenuStaticToolbar::v_GetState(int idtCmd, LPSMDATA psmd)
  538. {
  539. psmd->dwMask = SMDM_HMENU;
  540. psmd->hmenu = _hmenu;
  541. psmd->hwnd = _hwndMenuOwner;
  542. psmd->uIdParent = _idCmd;
  543. if (idtCmd == -1)
  544. idtCmd = GetButtonCmd(_hwndMB, ToolBar_GetHotItem(_hwndMB));
  545. psmd->uId = IDTTOIDM(idtCmd);
  546. psmd->punk = SAFECAST(_pcmb, IShellMenu*);
  547. psmd->punk->AddRef();
  548. return S_OK;
  549. }
  550. HRESULT CMenuStaticToolbar::CallCB(UINT idCmd, DWORD dwMsg, WPARAM wParam, LPARAM lParam)
  551. {
  552. if (!_pcmb->_psmcb)
  553. return S_FALSE;
  554. SMDATA smd;
  555. HRESULT hres = S_FALSE;
  556. // todo: call v_GetState (but see comment in mnfolder.cpp)
  557. smd.dwMask = SMDM_HMENU;
  558. smd.hmenu = _hmenu;
  559. smd.hwnd = _hwndMenuOwner;
  560. smd.uIdParent = _idCmd;
  561. smd.uIdAncestor = _pcmb->_uIdAncestor;
  562. smd.uId = idCmd;
  563. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  564. smd.pvUserData = _pcmb->_pvUserData;
  565. hres = _pcmb->_psmcb->CallbackSM(&smd, dwMsg, wParam, lParam);
  566. return hres;
  567. }
  568. HRESULT CMenuStaticToolbar::v_CallCBItem(int idtCmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  569. {
  570. int idm;
  571. idm = IDTTOIDM(idtCmd);
  572. return CallCB(idm, uMsg, wParam, lParam);
  573. }
  574. void CMenuStaticToolbar::v_UpdateButtons(BOOL fNegotiateSize)
  575. {
  576. if (_hwndMB)
  577. {
  578. _SetToolbarState();
  579. int cxMin, cxMax;
  580. v_CalcWidth(&cxMin, &cxMax);
  581. SendMessage(_hwndMB, TB_SETBUTTONWIDTH, 0, MAKELONG(cxMin, cxMax));
  582. SendMessage(_hwndMB, TB_AUTOSIZE, 0, 0);
  583. // Should we renegotiate size? AND are we vertical,
  584. // because we cannot renegoitate when horizontal.
  585. if (fNegotiateSize && _fVerticalMB)
  586. NegotiateSize();
  587. }
  588. }
  589. BOOL CMenuStaticToolbar::v_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  590. {
  591. if (-1 == uIconSize)
  592. uIconSize = _uIconSizeMB;
  593. BOOL fChanged = (_uIconSizeMB != uIconSize);
  594. _uIconSizeMB = uIconSize;
  595. if (_hwndMB)
  596. {
  597. if (_fVerticalMB)
  598. {
  599. HIMAGELIST himlLarge, himlSmall;
  600. // set the imagelist size
  601. for (int i = 0; CallCB(i, SMC_GETIMAGELISTS, (WPARAM)&himlLarge, (LPARAM)&himlSmall) == S_OK; i++)
  602. {
  603. HIMAGELIST himl = (_uIconSizeMB == ISFBVIEWMODE_LARGEICONS) ? himlLarge : himlSmall;
  604. SendMessage(_hwndMB, TB_SETIMAGELIST, i, (LPARAM)himl);
  605. }
  606. if (i == 0)
  607. {
  608. IImageList* piml;
  609. int iImageList = (_uIconSizeMB == ISFBVIEWMODE_LARGEICONS) ? SHIL_LARGE : SHIL_SYSSMALL;
  610. HRESULT hr = SHGetImageList(iImageList, IID_PPV_ARG(IImageList, &piml));
  611. if (SUCCEEDED(hr))
  612. {
  613. SendMessage(_hwndMB, TB_SETIMAGELIST, 0, (LPARAM)IImageListToHIMAGELIST(piml));
  614. piml->Release();
  615. }
  616. }
  617. }
  618. else
  619. {
  620. // sending a null himl is significant.. it means no image list
  621. SendMessage(_hwndMB, TB_SETIMAGELIST, 0, NULL);
  622. }
  623. if (fUpdateButtons)
  624. v_UpdateButtons(TRUE);
  625. }
  626. return fChanged;
  627. }
  628. void CMenuStaticToolbar::_OnGetDispInfo(LPNMHDR pnm, BOOL fUnicode)
  629. {
  630. LPNMTBDISPINFO pdi = (LPNMTBDISPINFO)pnm;
  631. if (pdi->dwMask & TBNF_IMAGE)
  632. {
  633. if (_fVerticalMB)
  634. {
  635. SMINFO smi;
  636. smi.dwMask = SMIM_ICON;
  637. if (CallCB(pdi->idCommand, SMC_GETINFO, 0, (LPARAM)&smi) == S_OK)
  638. pdi->iImage = smi.iIcon;
  639. else
  640. pdi->iImage = -1;
  641. }
  642. else
  643. pdi->iImage = -1;
  644. }
  645. if (pdi->dwMask & TBNF_TEXT)
  646. {
  647. if (pdi->pszText)
  648. {
  649. if (fUnicode)
  650. {
  651. pdi->pszText[0] = 0;
  652. }
  653. else
  654. {
  655. pdi->pszText[0] = 0;
  656. }
  657. }
  658. }
  659. pdi->dwMask |= TBNF_DI_SETITEM;
  660. return;
  661. }
  662. LRESULT CMenuStaticToolbar::_OnGetObject(NMOBJECTNOTIFY* pon)
  663. {
  664. pon->hResult = QueryInterface(*pon->piid, &pon->pObject);
  665. return 1;
  666. }
  667. LRESULT CMenuStaticToolbar::_OnHotItemChange(NMTBHOTITEM * pnm)
  668. {
  669. LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnm;
  670. if (_hwndPager && (lpnmhi->dwFlags & (HICF_ARROWKEYS | HICF_ACCELERATOR)) )
  671. {
  672. int iOldPos, iNewPos;
  673. RECT rc, rcPager;
  674. int heightPager;
  675. int iSelected = ToolBar_CommandToIndex(_hwndMB, lpnmhi->idNew);
  676. iOldPos = (int)SendMessage(_hwndPager, PGM_GETPOS, (WPARAM)0, (LPARAM)0);
  677. iNewPos = iOldPos;
  678. SendMessage(_hwndMB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc);
  679. if (rc.top < iOldPos)
  680. {
  681. iNewPos =rc.top;
  682. }
  683. GetClientRect(_hwndPager, &rcPager);
  684. heightPager = RECTHEIGHT(rcPager);
  685. if (rc.top >= iOldPos + heightPager)
  686. {
  687. iNewPos += (rc.bottom - (iOldPos + heightPager)) ;
  688. }
  689. if (iNewPos != iOldPos)
  690. SendMessage(_hwndPager, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos);
  691. }
  692. return CMenuToolbarBase::_OnHotItemChange(pnm);
  693. }
  694. LRESULT CMenuStaticToolbar::v_OnCustomDraw(NMCUSTOMDRAW * pnmcd)
  695. {
  696. LRESULT lRes = CMenuToolbarBase::v_OnCustomDraw(pnmcd);
  697. #ifdef FLATMENU_ICONBAR
  698. // In flat menu mode, we may have an icon banner
  699. if (pnmcd->dwDrawStage == CDDS_PREERASE && _pcmb->_pmbm->_fFlatMenuMode)
  700. {
  701. UINT cBits = GetDeviceCaps(pnmcd->hdc, BITSPIXEL);
  702. // We only do the banner on 16bit color
  703. if (cBits > 8)
  704. {
  705. RECT rcClient;
  706. GetClientRect(_hwndMB, &rcClient);
  707. // This draw's the gradient along the background of the icons
  708. // We only do it in large icons for "design" reasons.
  709. if (_uIconSizeMB == ISFBVIEWMODE_LARGEICONS)
  710. {
  711. rcClient.right = GetTBImageListWidth(_hwndMB) + ICONBACKGROUNDFUDGE;
  712. COLORREF cr1 = GetSysColor(COLOR_MENU);
  713. COLORREF cr2 = _pcmb->_pmbm->_clrMenuGrad;
  714. TRIVERTEX pt[2];
  715. GRADIENT_RECT gr;
  716. pt[0].x = 0;
  717. pt[0].y = 0;
  718. pt[1].x = RECTWIDTH(rcClient);
  719. pt[1].y = RECTHEIGHT(rcClient);
  720. pt[0].Red = GetRValue(cr1) << 8;
  721. pt[0].Green = GetGValue(cr1) << 8;
  722. pt[0].Blue = GetBValue(cr1) << 8;
  723. pt[0].Alpha = 0x0000;
  724. pt[1].Red = GetRValue(cr2) << 8;
  725. pt[1].Green = GetGValue(cr2) << 8;
  726. pt[1].Blue = GetBValue(cr2) << 8;
  727. pt[1].Alpha = 0x0000;
  728. gr.UpperLeft = 0;
  729. gr.LowerRight = 1;
  730. GradientFill(pnmcd->hdc, pt, 2, &gr, 1, GRADIENT_FILL_RECT_V);
  731. }
  732. else
  733. {
  734. rcClient.right = GetTBImageListWidth(_hwndMB) + ICONBACKGROUNDFUDGE;
  735. SHFillRectClr(pnmcd->hdc, &rcClient, _pcmb->_pmbm->_clrMenuGrad);
  736. }
  737. }
  738. }
  739. #endif
  740. return lRes;
  741. }
  742. LRESULT CMenuStaticToolbar::_OnNotify(LPNMHDR pnm)
  743. {
  744. LRESULT lres = 0;
  745. //The following statement traps all pager control notification messages.
  746. if ((pnm->code <= PGN_FIRST) && (pnm->code >= PGN_LAST))
  747. {
  748. return SendMessage(_hwndMB, WM_NOTIFY, (WPARAM)0, (LPARAM)pnm);
  749. }
  750. switch (pnm->code)
  751. {
  752. case TBN_DRAGOUT:
  753. lres = 0;
  754. break;
  755. case TBN_DELETINGBUTTON:
  756. {
  757. if (!_fEmptyingToolbar)
  758. {
  759. TBNOTIFY *ptbn = (TBNOTIFY*)pnm;
  760. CMenuStaticData* pmsd = (CMenuStaticData*)ptbn->tbButton.dwData;
  761. if (pmsd)
  762. delete pmsd;
  763. }
  764. break;
  765. }
  766. case NM_TOOLTIPSCREATED:
  767. SHSetWindowBits(((NMTOOLTIPSCREATED*)pnm)->hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST, TTS_ALWAYSTIP | TTS_TOPMOST);
  768. SendMessage(((NMTOOLTIPSCREATED*)pnm)->hwndToolTips, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAXSHORT);
  769. break;
  770. case NM_RCLICK:
  771. lres = _OnContextMenu(NULL, GetMessagePos());
  772. break;
  773. case TBN_GETDISPINFOA:
  774. _OnGetDispInfo(pnm, FALSE);
  775. break;
  776. case TBN_GETDISPINFOW:
  777. _OnGetDispInfo(pnm, TRUE);
  778. break;
  779. case TBN_GETOBJECT:
  780. lres = _OnGetObject((NMOBJECTNOTIFY*)pnm);
  781. break;
  782. case TBN_MAPACCELERATOR:
  783. lres = _OnAccelerator((NMCHAR*)pnm);
  784. break;
  785. default:
  786. lres = CMenuToolbarBase::_OnNotify(pnm);
  787. }
  788. return(lres);
  789. }
  790. void CMenuStaticToolbar::_FillToolbar()
  791. {
  792. if (_fDirty && _hmenu && _hwndMB && !_pcmb->_fClosing)
  793. {
  794. EmptyToolbar();
  795. BOOL_PTR fRedraw = SendMessage(_hwndMB, WM_SETREDRAW, FALSE, 0);
  796. TCHAR szName[MAX_PATH];
  797. MENUITEMINFO mii;
  798. mii.cbSize = sizeof(mii);
  799. mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
  800. int iCount = GetMenuItemCount(_hmenu);
  801. for (int i = 0; i < iCount; i++)
  802. {
  803. mii.dwTypeData = szName;
  804. mii.cch = ARRAYSIZE(szName);
  805. if (GetMenuItemInfo(_hmenu, i, MF_BYPOSITION, &mii))
  806. {
  807. if (mii.fType & MFT_SEPARATOR)
  808. {
  809. if (i == 0)
  810. _fHasTopSep = TRUE;
  811. else if (i == iCount - 1)
  812. _fHasBottomSep = TRUE;
  813. }
  814. _Insert(i, &mii);
  815. }
  816. }
  817. if (iCount == 0)
  818. _fEmpty = TRUE;
  819. if (_hwndPager)
  820. SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0);
  821. SendMessage(_hwndMB, WM_SETREDRAW, fRedraw, 0);
  822. _fDirty = FALSE;
  823. v_UpdateButtons(TRUE);
  824. _pcmb->ResizeMenuBar();
  825. }
  826. }
  827. void CMenuStaticToolbar::v_OnDeleteButton(void *pData)
  828. {
  829. CMenuStaticData* pmsd = (CMenuStaticData*)pData;
  830. if (pmsd)
  831. delete pmsd;
  832. }
  833. void CMenuStaticToolbar::v_OnEmptyToolbar()
  834. {
  835. CMenuToolbarBase::v_OnEmptyToolbar();
  836. _fDirty = TRUE;
  837. _fHasTopSep = FALSE;
  838. _fHasBottomSep = FALSE;
  839. _fTopSepRemoved = FALSE;
  840. _fBottomSepRemoved = FALSE;
  841. }
  842. void CMenuStaticToolbar::v_Close()
  843. {
  844. if (_hwndMB)
  845. {
  846. _UnregisterWindow(_hwndMB);
  847. _UnsubclassWindow(_hwndMB);
  848. }
  849. CMenuToolbarBase::v_Close();
  850. if (_hwndPager)
  851. {
  852. DestroyWindow(_hwndPager); // Should Destroy Toolbar.
  853. _hwndPager = NULL;
  854. }
  855. }
  856. void CMenuStaticToolbar::v_Refresh()
  857. {
  858. EmptyToolbar();
  859. _FillToolbar();
  860. v_UpdateButtons(TRUE);
  861. }
  862. /*----------------------------------------------------------
  863. Purpose: IWinEventHandler::IsWindowOwner method
  864. Processes messages passed on from the menuband.
  865. */
  866. STDMETHODIMP CMenuStaticToolbar::IsWindowOwner(HWND hwnd)
  867. {
  868. if ( hwnd == _hwndMB || _hwndPager == hwnd || hwnd == HWND_BROADCAST)
  869. return S_OK;
  870. else
  871. return S_FALSE;
  872. }
  873. /*----------------------------------------------------------
  874. Purpose: CDelegateDropTarget::GetWindowsDDT
  875. */
  876. HRESULT CMenuStaticToolbar::GetWindowsDDT (HWND * phwndLock, HWND * phwndScroll)
  877. {
  878. *phwndLock = _hwndMB;
  879. *phwndScroll = _hwndMB;
  880. return S_OK;
  881. }
  882. /*----------------------------------------------------------
  883. Purpose: CDelegateDropTarget::HitTestDDT
  884. */
  885. HRESULT CMenuStaticToolbar::HitTestDDT (UINT nEvent, LPPOINT ppt, DWORD_PTR * pdwId, DWORD *pdwEffect)
  886. {
  887. switch (nEvent)
  888. {
  889. case HTDDT_ENTER:
  890. // OLE is in its modal drag/drop loop, and it has the capture.
  891. // We shouldn't take the capture back during this time.
  892. if (!(_pcmb->_dwFlags & SMINIT_RESTRICT_DRAGDROP))
  893. {
  894. _pcmb->_pmbState->HasDrag(TRUE);
  895. GetMessageFilter()->PreventCapture(TRUE);
  896. if (_pcmb->_pmtbShellFolder &&
  897. _pcmb->_pmtbShellFolder->DontShowEmpty())
  898. {
  899. DAD_ShowDragImage(FALSE);
  900. _pcmb->_pmtbShellFolder->DontShowEmpty(FALSE);
  901. _pcmb->ResizeMenuBar();
  902. UpdateWindow(_hwndMB);
  903. DAD_ShowDragImage(TRUE);
  904. }
  905. return S_OK;
  906. }
  907. else
  908. return S_FALSE;
  909. case HTDDT_OVER:
  910. {
  911. TBINSERTMARK tbim;
  912. *pdwEffect = DROPEFFECT_NONE;
  913. POINT pt = *ppt;
  914. if (WindowFromPoint(pt) == _hwndPager )
  915. {
  916. *pdwId = IBHT_PAGER;
  917. }
  918. else if (!ToolBar_InsertMarkHitTest(_hwndMB, &pt, &tbim))
  919. {
  920. int idCmd = GetButtonCmd(_hwndMB, tbim.iButton);
  921. DWORD dwFlags = v_GetFlags(idCmd);
  922. if (((dwFlags & SMIF_DROPCASCADE) || (dwFlags & SMIF_DROPTARGET) || (dwFlags & SMIF_DRAGNDROP)) &&
  923. (tbim.iButton != _iDragOverButton))
  924. {
  925. *pdwId = idCmd;
  926. DAD_ShowDragImage(FALSE);
  927. _pcmb->SetTracked(this);
  928. _iDragOverButton = tbim.iButton;
  929. SetTimer(_hwndMB, MBTIMER_DRAGOVER, 1000, NULL);
  930. _pcmb->_SiteOnSelect(MPOS_CHILDTRACKING);
  931. BOOL_PTR fOldAnchor = ToolBar_SetAnchorHighlight(_hwndMB, FALSE);
  932. ToolBar_SetHotItem(_hwndMB, _iDragOverButton);
  933. ToolBar_SetAnchorHighlight(_hwndMB, fOldAnchor);
  934. UpdateWindow(_hwndMB);
  935. DAD_ShowDragImage(TRUE);
  936. }
  937. }
  938. }
  939. break;
  940. case HTDDT_LEAVE:
  941. // We can take the capture back anytime now
  942. _pcmb->_pmbState->HasDrag(FALSE);
  943. _SetTimer(MBTIMER_DRAGPOPDOWN);
  944. GetMessageFilter()->PreventCapture(FALSE);
  945. _iDragOverButton = -1;
  946. DAD_ShowDragImage(FALSE);
  947. ToolBar_SetHotItem(_hwndMB, -1);
  948. DAD_ShowDragImage(TRUE);
  949. break;
  950. }
  951. return S_OK;
  952. }
  953. /*----------------------------------------------------------
  954. Purpose: CDelegateDropTarget::GetObjectDDT
  955. */
  956. HRESULT CMenuStaticToolbar::GetObjectDDT (DWORD_PTR dwId, REFIID riid, void **ppvObj)
  957. {
  958. HRESULT hres = E_FAIL;
  959. // FEATURE: Pager Support look in mnfolder.cpp
  960. if (dwId == IBHT_PAGER)
  961. {
  962. SendMessage(_hwndPager, PGM_GETDROPTARGET, 0, (LPARAM)ppvObj);
  963. }
  964. else
  965. {
  966. SMDATA smd = {0};
  967. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  968. smd.uIdParent = (UINT) dwId;
  969. if (_pcmb->_psmcb)
  970. {
  971. hres = _pcmb->_psmcb->CallbackSM(&smd, SMC_GETOBJECT, (WPARAM)&riid, (LPARAM)ppvObj);
  972. if (hres == S_FALSE)
  973. hres = E_FAIL;
  974. }
  975. }
  976. return hres;
  977. }
  978. /*----------------------------------------------------------
  979. Purpose: CDelegateDropTarget::OnDropDDT
  980. */
  981. HRESULT CMenuStaticToolbar::OnDropDDT (IDropTarget *pdt, IDataObject *pdtobj,
  982. DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  983. {
  984. return E_NOTIMPL;
  985. }
  986. HRESULT CMenuStaticToolbar::v_InvalidateItem(LPSMDATA psmd, DWORD dwFlags)
  987. {
  988. HRESULT hres = S_FALSE;
  989. if (NULL == psmd)
  990. {
  991. if (dwFlags & SMINV_REFRESH)
  992. {
  993. // Refresh the whole thing
  994. v_Refresh();
  995. }
  996. }
  997. // Are we dealing with an Hmenu?
  998. // Have we filled it yet? (If not, then we can skip the invalidate
  999. // here, because we'll catch it when we fill it.)
  1000. else if ((psmd->dwMask & SMDM_HMENU) && !_fDirty)
  1001. {
  1002. // Yes; What are they asking for?
  1003. int iPos = -1; // Assume this is a position
  1004. int idCmd = -1;
  1005. // Did they pass an ID instead of a position?
  1006. if (dwFlags & SMINV_ID)
  1007. {
  1008. // Yes; Crack out the position.
  1009. iPos = GetMenuPosFromID(_hmenu, psmd->uId);
  1010. idCmd = psmd->uId;
  1011. }
  1012. if (dwFlags & SMINV_POSITION)
  1013. {
  1014. iPos = psmd->uId;
  1015. idCmd = GetMenuItemID(_hmenu, iPos);
  1016. }
  1017. if (dwFlags & SMINV_REFRESH)
  1018. {
  1019. // Do they want to refresh a sepcific button?
  1020. if (idCmd >= 0)
  1021. {
  1022. // Yes;
  1023. // First delete the old one if it exists.
  1024. int iTBPos = ToolBar_CommandToIndex(_hwndMB, idCmd);
  1025. if (iTBPos >= 0)
  1026. SendMessage(_hwndMB, TB_DELETEBUTTON, iTBPos, 0);
  1027. // Now Insert a new one
  1028. MENUITEMINFO mii;
  1029. TCHAR szName[MAX_PATH];
  1030. mii.cbSize = sizeof(mii);
  1031. mii.cch = ARRAYSIZE(szName);
  1032. mii.dwTypeData = szName;
  1033. mii.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
  1034. // This can fail...
  1035. if (GetMenuItemInfo(_hmenu, iPos, MF_BYPOSITION, &mii))
  1036. {
  1037. _Insert(iPos, &mii);
  1038. hres = S_OK;
  1039. }
  1040. }
  1041. else
  1042. {
  1043. // No; Refresh the whole thing
  1044. v_Refresh();
  1045. }
  1046. if (!_fShowMB)
  1047. _pcmb->_fForceButtonUpdate = TRUE;
  1048. _pcmb->ResizeMenuBar();
  1049. }
  1050. }
  1051. return hres;
  1052. }
  1053. void CMenuStaticToolbar::GetSize(SIZE* psize)
  1054. {
  1055. _CheckSeparators();
  1056. CMenuToolbarBase::GetSize(psize);
  1057. }
  1058. LRESULT CMenuStaticToolbar::_OnAccelerator(NMCHAR* pnmChar)
  1059. {
  1060. SMDATA smdOut = {0};
  1061. SMDATA smd = {0};
  1062. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  1063. smd.uIdParent = _pcmb->_uId;
  1064. if (_pcmb->_psmcb &&
  1065. S_FALSE != _pcmb->_psmcb->CallbackSM(&smd, SMC_MAPACCELERATOR, (WPARAM)pnmChar->ch, (LPARAM)&smdOut))
  1066. {
  1067. pnmChar->dwItemNext = ToolBar_CommandToIndex(_hwndMB, smdOut.uId);;
  1068. return TRUE;
  1069. }
  1070. return FALSE;
  1071. }
  1072. LRESULT CMenuStaticToolbar::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  1073. {
  1074. LRESULT lres = 0;
  1075. LockSetForegroundWindow(LSFW_UNLOCK);
  1076. if (!(_pcmb->_dwFlags & SMINIT_RESTRICT_CONTEXTMENU))
  1077. {
  1078. RECT rc;
  1079. LPRECT prcExclude = NULL;
  1080. POINT pt;
  1081. int i;
  1082. if (lParam != (LPARAM)-1)
  1083. {
  1084. pt.x = GET_X_LPARAM(lParam);
  1085. pt.y = GET_Y_LPARAM(lParam);
  1086. POINT pt2 = pt;
  1087. MapWindowPoints(HWND_DESKTOP, _hwndMB, &pt2, 1);
  1088. i = ToolBar_HitTest(_hwndMB, &pt2);
  1089. }
  1090. else
  1091. {
  1092. // keyboard context menu.
  1093. i = (int)SendMessage(_hwndMB, TB_GETHOTITEM, 0, 0);
  1094. if (i >= 0)
  1095. {
  1096. SendMessage(_hwndMB, TB_GETITEMRECT, i, (LPARAM)&rc);
  1097. MapWindowPoints(_hwndMB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  1098. pt.x = rc.left;
  1099. pt.y = rc.bottom;
  1100. prcExclude = &rc;
  1101. }
  1102. }
  1103. if (i >= 0)
  1104. {
  1105. UINT idCmd = GetButtonCmd(_hwndMB, i);
  1106. if (S_OK == CallCB(idCmd, SMC_GETOBJECT, (WPARAM)(GUID*)&IID_IContextMenu, (LPARAM)(void**)(&_pcm)))
  1107. {
  1108. TPMPARAMS tpm;
  1109. TPMPARAMS * ptpm = NULL;
  1110. if (prcExclude)
  1111. {
  1112. tpm.cbSize = sizeof(tpm);
  1113. tpm.rcExclude = *((LPRECT)prcExclude);
  1114. ptpm = &tpm;
  1115. }
  1116. HMENU hmenu = CreatePopupMenu();
  1117. if (hmenu)
  1118. {
  1119. KillTimer(_hwndMB, MBTIMER_INFOTIP);
  1120. _pcmb->_pmbState->HideTooltip(FALSE);
  1121. _pcm->QueryContextMenu(hmenu, 0, 0, -1, 0);
  1122. idCmd = TrackPopupMenuEx(hmenu,
  1123. TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1124. pt.x, pt.y, _hwndMB, ptpm);
  1125. CMINVOKECOMMANDINFO ici = {
  1126. sizeof(CMINVOKECOMMANDINFO),
  1127. 0,
  1128. _hwndMB,
  1129. MAKEINTRESOURCEA(idCmd),
  1130. NULL, NULL,
  1131. SW_NORMAL,
  1132. };
  1133. _pcm->InvokeCommand(&ici);
  1134. DestroyMenu(hmenu);
  1135. }
  1136. ATOMICRELEASE(_pcm);
  1137. }
  1138. }
  1139. GetMessageFilter()->RetakeCapture();
  1140. }
  1141. return lres;
  1142. }
  1143. STDMETHODIMP CMenuStaticToolbar::OnWinEvent(HWND hwnd, UINT dwMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1144. {
  1145. if (WM_CONTEXTMENU == dwMsg)
  1146. {
  1147. *plres = _OnContextMenu(wParam, lParam);
  1148. }
  1149. else
  1150. return CMenuToolbarBase::OnWinEvent(hwnd, dwMsg, wParam, lParam, plres);
  1151. return S_OK;
  1152. }
  1153. void CMenuStaticToolbar::v_ForwardMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1154. {
  1155. RECT rc;
  1156. POINT pt;
  1157. HWND hwndFwd;
  1158. // These are in screen coords
  1159. pt.x = GET_X_LPARAM(lParam);
  1160. pt.y = GET_Y_LPARAM(lParam);
  1161. hwndFwd = _hwndPager ? _hwndPager : _hwndMB;
  1162. GetWindowRect(hwndFwd, &rc);
  1163. if (PtInRect(&rc, pt))
  1164. {
  1165. MapWindowPoints(NULL, hwndFwd, &pt, 1);
  1166. HWND hwnd = ChildWindowFromPoint(hwndFwd, pt);
  1167. if (hwnd)
  1168. {
  1169. MapWindowPoints(hwndFwd, hwnd, &pt, 1);
  1170. }
  1171. else
  1172. {
  1173. hwnd = hwndFwd;
  1174. }
  1175. SendMessage(hwnd, uMsg, wParam, MAKELONG(pt.x, pt.y));
  1176. }
  1177. }
  1178. void CMenuStaticToolbar::SetParent(HWND hwndParent)
  1179. {
  1180. int nCmdShow = SW_SHOW;
  1181. if (hwndParent)
  1182. {
  1183. if (!_hwndMB)
  1184. CreateToolbar(hwndParent);
  1185. else
  1186. {
  1187. // make sure width is set correctly . . .
  1188. // SendMessage(_hwndMB, TB_SETBUTTONWIDTH, 0, MAKELONG(_cxMin, _cxMax));
  1189. }
  1190. }
  1191. else
  1192. {
  1193. // As an optimization, we implement "disowning" ourselves
  1194. // as just moving ourselves offscreen. The previous parent
  1195. // still owns us. The parent is invariably the menusite.
  1196. RECT rc = {-1,-1,-1,-1};
  1197. SetWindowPos(NULL, &rc, 0);
  1198. nCmdShow = SW_HIDE;
  1199. }
  1200. HWND hwnd = _hwndPager ? _hwndPager: _hwndMB;
  1201. if (IsWindow(hwnd)) // JANK : Fix for bug #98253
  1202. {
  1203. if (nCmdShow == SW_HIDE)
  1204. {
  1205. ShowWindow(hwnd, nCmdShow);
  1206. }
  1207. ::SetParent(hwnd, hwndParent);
  1208. SendMessage(hwnd, TB_SETPARENT, (WPARAM)hwndParent, NULL);
  1209. if (nCmdShow == SW_SHOW)
  1210. {
  1211. ShowWindow(hwnd, nCmdShow);
  1212. }
  1213. }
  1214. }
  1215. void CMenuStaticToolbar::SetWindowPos(LPSIZE psize, LPRECT prc, DWORD dwFlags)
  1216. {
  1217. if (!_hwndPager)
  1218. {
  1219. CMenuToolbarBase::SetWindowPos(psize, prc, dwFlags);
  1220. return;
  1221. }
  1222. DWORD rectWidth = RECTWIDTH(*prc);
  1223. TraceMsg(TF_MENUBAND, "CMSFTB::SetWindowPos %d - (%d,%d,%d,%d)", psize?psize->cx:0,
  1224. prc->left, prc->top, prc->right, prc->bottom);
  1225. ShowWindow(_hwndPager, SW_SHOW);
  1226. ::SetWindowPos(_hwndPager, NULL, prc->left, prc->top,
  1227. rectWidth, RECTHEIGHT(*prc), SWP_NOZORDER | SWP_NOACTIVATE | dwFlags);
  1228. if (psize)
  1229. {
  1230. int cx = psize->cx;
  1231. ToolBar_SetButtonWidth(_hwndMB, cx, cx);
  1232. }
  1233. SendMessage(_hwndPager, PGMP_RECALCSIZE, 0L, 0L);
  1234. }