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.

390 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993 - 2001.
  5. //
  6. // File: Toolbar.cpp
  7. //
  8. // Contents: implementation of CToolbar
  9. //
  10. //----------------------------------------------------------------------------
  11. #include "stdafx.h"
  12. #include "Toolbar.h"
  13. class CAppCommandHook
  14. {
  15. public:
  16. static void SetHook(HWND hWnd)
  17. {
  18. CAppCommandHook *pach = _GetInfo(TRUE);
  19. if (pach)
  20. {
  21. if (NULL != pach->_hHook)
  22. {
  23. UnhookWindowsHookEx(pach->_hHook);
  24. pach->_hHook = NULL;
  25. pach->_hWnd = NULL;
  26. }
  27. if (NULL != hWnd)
  28. {
  29. pach->_hWnd = hWnd;
  30. pach->_hHook = SetWindowsHookEx(WH_SHELL, _HookProc, NULL, GetCurrentThreadId());
  31. }
  32. }
  33. }
  34. static void Unhook(void)
  35. {
  36. CAppCommandHook *pach = _GetInfo(FALSE);
  37. if (-1 != g_tlsAppCommandHook)
  38. {
  39. TlsSetValue(g_tlsAppCommandHook, NULL);
  40. }
  41. delete pach;
  42. }
  43. private:
  44. CAppCommandHook() : _hHook(NULL), _hWnd(NULL) {}
  45. ~CAppCommandHook()
  46. {
  47. if (NULL != _hHook)
  48. UnhookWindowsHookEx(_hHook);
  49. }
  50. static CAppCommandHook* _GetInfo(BOOL bAlloc)
  51. {
  52. CAppCommandHook *pach = NULL;
  53. if (-1 != g_tlsAppCommandHook)
  54. {
  55. pach = (CAppCommandHook*)TlsGetValue(g_tlsAppCommandHook);
  56. if (NULL == pach && bAlloc)
  57. {
  58. pach = new CAppCommandHook;
  59. if (NULL != pach)
  60. {
  61. TlsSetValue(g_tlsAppCommandHook, pach);
  62. }
  63. }
  64. }
  65. return pach;
  66. }
  67. static LRESULT CALLBACK _HookProc(int nCode, WPARAM wParam, LPARAM lParam)
  68. {
  69. CAppCommandHook *pach = _GetInfo(FALSE);
  70. if (pach)
  71. {
  72. if (nCode == HSHELL_APPCOMMAND && NULL != pach->_hWnd)
  73. {
  74. if (::SendMessage(pach->_hWnd, WM_APPCOMMAND, wParam, lParam))
  75. return 0;
  76. }
  77. if (NULL != pach->_hHook)
  78. return CallNextHookEx(pach->_hHook, nCode, wParam, lParam);
  79. }
  80. return 0;
  81. }
  82. private:
  83. HHOOK _hHook;
  84. HWND _hWnd;
  85. };
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CToolbar
  88. LRESULT CToolbar::_OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  89. {
  90. m_hAccel = LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ACCEL));
  91. DWORD dwExStyle = TBSTYLE_EX_MIXEDBUTTONS;
  92. //
  93. // NTRAID#NTBUG9-300152-2001/02/02-jeffreys Toolbar isn't mirrored
  94. //
  95. // The HTA frame window isn't getting the right layout style on mirrored
  96. // builds. This style is normally inherited from parent to child, so
  97. // we shouldn't have to do anything here.
  98. //
  99. // However, I'm putting this in temporarily so the toolbar will be
  100. // mirrored for beta 2. After beta 2, or whenever trident fixes the
  101. // HTA problem, this can be removed.
  102. //
  103. CComVariant varRTL;
  104. if (SUCCEEDED(GetAmbientProperty(DISPID_AMBIENT_RIGHTTOLEFT, varRTL))
  105. && varRTL.boolVal == VARIANT_TRUE)
  106. {
  107. dwExStyle |= WS_EX_NOINHERITLAYOUT | WS_EX_LAYOUTRTL;
  108. }
  109. RECT rc = {0,0,0,0};
  110. m_ctlToolbar.Create(m_hWnd,
  111. &rc,
  112. NULL,
  113. WS_CHILD | WS_VISIBLE | CCS_NODIVIDER | CCS_TOP | CCS_NOPARENTALIGN | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TOOLTIPS,
  114. dwExStyle);
  115. if (!m_ctlToolbar)
  116. return -1;
  117. m_ctlToolbar.SendMessage(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  118. int idBmp = IDB_NAVBAR;
  119. if (SHGetCurColorRes() > 8)
  120. idBmp += (IDB_NAVBARHICOLOR - IDB_NAVBAR);
  121. m_himlNBDef = ImageList_LoadImageW(_Module.GetResourceInstance(),
  122. MAKEINTRESOURCE(idBmp),
  123. NAVBAR_CX,
  124. 0,
  125. CLR_DEFAULT,
  126. IMAGE_BITMAP,
  127. LR_CREATEDIBSECTION);
  128. if (m_himlNBDef)
  129. {
  130. m_ctlToolbar.SendMessage(TB_SETIMAGELIST, 0, (LPARAM)m_himlNBDef);
  131. }
  132. m_himlNBHot = ImageList_LoadImageW(_Module.GetResourceInstance(),
  133. MAKEINTRESOURCE(idBmp+1),
  134. NAVBAR_CX,
  135. 0,
  136. CLR_DEFAULT,
  137. IMAGE_BITMAP,
  138. LR_CREATEDIBSECTION);
  139. if (m_himlNBHot)
  140. {
  141. m_ctlToolbar.SendMessage(TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlNBHot);
  142. }
  143. if (!m_himlNBDef && !m_himlNBHot)
  144. {
  145. // Must be serious low memory or other resource problems.
  146. // There's no point having a toolbar without any images.
  147. m_ctlToolbar.DestroyWindow();
  148. return -1;
  149. }
  150. TCHAR szBack[64];
  151. TCHAR szHome[64];
  152. TBBUTTON rgButtons[] =
  153. {
  154. {0, ID_BACK, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szBack},
  155. {1, ID_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
  156. {2, ID_HOME, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szHome},
  157. };
  158. ::LoadStringW(_Module.GetResourceInstance(), ID_BACK, szBack, ARRAYSIZE(szBack));
  159. ::LoadStringW(_Module.GetResourceInstance(), ID_HOME, szHome, ARRAYSIZE(szHome));
  160. m_ctlToolbar.SendMessage(TB_ADDBUTTONSW, ARRAYSIZE(rgButtons), (LPARAM)rgButtons);
  161. // Update the position and extent stuff. Do this asynchronously since ATL
  162. // will call SetObjectRects shortly after we return from this method (with
  163. // the original rect).
  164. PostMessage(PWM_UPDATESIZE);
  165. // Set a hook to redirect WM_APPCOMMAND messages to our control window
  166. CAppCommandHook::SetHook(m_hWnd);
  167. return 0;
  168. }
  169. LRESULT CToolbar::_OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  170. {
  171. CAppCommandHook::Unhook();
  172. return 0;
  173. }
  174. LRESULT CToolbar::_OnAppCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  175. {
  176. switch (GET_APPCOMMAND_LPARAM(lParam))
  177. {
  178. case APPCOMMAND_BROWSER_BACKWARD:
  179. Fire_OnButtonClick(0);
  180. break;
  181. case APPCOMMAND_BROWSER_FORWARD:
  182. Fire_OnButtonClick(1);
  183. break;
  184. case APPCOMMAND_BROWSER_HOME:
  185. Fire_OnButtonClick(2);
  186. break;
  187. default:
  188. bHandled = FALSE;
  189. break;
  190. }
  191. return 0;
  192. }
  193. LRESULT CToolbar::_UpdateSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  194. {
  195. if (m_ctlToolbar)
  196. {
  197. //
  198. // TB_AUTOSIZE causes m_ctlToolbar to set its preferred height, but it
  199. // doesn't adjust it's width or position because of the styles we use
  200. // (CCS_TOP | CCS_NOPARENTALIGN).
  201. //
  202. // The width will always be the same as m_rcPos because we keep them
  203. // in sync via SetObjectRects below.
  204. //
  205. // If the height is different after TB_AUTOSIZE, ask the container to
  206. // adjust our rect.
  207. //
  208. m_ctlToolbar.SendMessage(TB_AUTOSIZE, 0, 0);
  209. RECT rc;
  210. m_ctlToolbar.GetWindowRect(&rc);
  211. ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rc, 2);
  212. if ((rc.bottom - rc.top) != (m_rcPos.bottom - m_rcPos.top))
  213. {
  214. //
  215. // We only want to set the height (leave the width alone), but
  216. // OnPosRectChange sets both the height and the width. Moreover,
  217. // it sets the width to a fixed (pixel) width, nuking styles such
  218. // as "100%". We get around this by getting the current width
  219. // now and restoring it after calling OnPosRectChange.
  220. //
  221. CComPtr<IHTMLStyle> spStyle;
  222. CComVariant varWidth;
  223. CComQIPtr<IOleControlSite> spCtrlSite(m_spClientSite);
  224. if (spCtrlSite)
  225. {
  226. CComPtr<IDispatch> spDispatch;
  227. spCtrlSite->GetExtendedControl(&spDispatch);
  228. if (spDispatch)
  229. {
  230. CComQIPtr<IHTMLElement> spElement(spDispatch);
  231. if (spElement)
  232. {
  233. spElement->get_style(&spStyle);
  234. if (spStyle)
  235. {
  236. spStyle->get_width(&varWidth);
  237. }
  238. }
  239. }
  240. }
  241. // Ask the container to give us a new rect
  242. m_spInPlaceSite->OnPosRectChange(&rc);
  243. // Restore the previous width style
  244. if (spStyle)
  245. {
  246. spStyle->setAttribute(L"width", varWidth, 0);
  247. }
  248. }
  249. }
  250. return 0;
  251. }
  252. HRESULT CToolbar::OnAmbientPropertyChange(DISPID dispid)
  253. {
  254. switch (dispid)
  255. {
  256. case DISPID_UNKNOWN:
  257. case DISPID_AMBIENT_FONT:
  258. _ClearAmbientFont();
  259. _GetAmbientFont();
  260. m_ctlToolbar.SendMessage(WM_SETFONT, (WPARAM)m_hFont, FALSE);
  261. m_ctlToolbar.InvalidateRect(NULL); // redraw
  262. break;
  263. }
  264. return S_OK;
  265. }
  266. void CToolbar::_ClearAmbientFont(void)
  267. {
  268. if (m_pFont)
  269. {
  270. if (m_hFont)
  271. m_pFont->ReleaseHfont(m_hFont);
  272. m_pFont->Release();
  273. m_pFont = NULL;
  274. }
  275. m_hFont = NULL;
  276. }
  277. void CToolbar::_GetAmbientFont(void)
  278. {
  279. if (!m_hFont)
  280. {
  281. // Try to get the ambient font from our container
  282. if (SUCCEEDED(GetAmbientFont(&m_pFont)))
  283. {
  284. if (SUCCEEDED(m_pFont->get_hFont(&m_hFont)))
  285. {
  286. // Yea, everybody is happy
  287. m_pFont->AddRefHfont(m_hFont);
  288. }
  289. else
  290. {
  291. // Darn, couldn't get the font from container
  292. _ClearAmbientFont();
  293. }
  294. }
  295. }
  296. }
  297. STDMETHODIMP CToolbar::get_enabled(VARIANT vIndex, VARIANT_BOOL *pVal)
  298. {
  299. if (!pVal)
  300. return E_POINTER;
  301. *pVal = VARIANT_FALSE;
  302. if (FAILED(VariantChangeType(&vIndex, &vIndex, 0, VT_I4)))
  303. return E_INVALIDARG;
  304. LRESULT state = m_ctlToolbar.SendMessage(TB_GETSTATE, ID_BACK + vIndex.lVal, 0);
  305. if (-1 == state)
  306. return E_INVALIDARG;
  307. if (state & TBSTATE_ENABLED)
  308. *pVal = VARIANT_TRUE;
  309. return S_OK;
  310. }
  311. STDMETHODIMP CToolbar::put_enabled(VARIANT vIndex, VARIANT_BOOL newVal)
  312. {
  313. if (FAILED(VariantChangeType(&vIndex, &vIndex, 0, VT_I4)))
  314. return E_INVALIDARG;
  315. m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BACK + vIndex.lVal, MAKELONG((VARIANT_TRUE == newVal), 0));
  316. return S_OK;
  317. }
  318. void CToolbar::Fire_OnButtonClick(int buttonIndex)
  319. {
  320. int nConnectionIndex;
  321. CComVariant* pvars = new CComVariant[1];
  322. int nConnections = m_vec.GetSize();
  323. for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
  324. {
  325. Lock();
  326. CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
  327. Unlock();
  328. IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
  329. if (pDispatch != NULL)
  330. {
  331. pvars[0] = buttonIndex;
  332. DISPPARAMS disp = { pvars, NULL, 1, 0 };
  333. pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
  334. }
  335. }
  336. delete[] pvars;
  337. }