Leaked source code of windows server 2003
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.

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