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.

611 lines
16 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: tbtrack.cpp
  7. *
  8. * Contents: Implementation file for CToolbarTracker
  9. *
  10. * History: 15-May-98 JeffRo Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "stdafx.h"
  14. #include "amc.h"
  15. #include "tbtrack.h"
  16. #include "controls.h"
  17. #include "mainfrm.h"
  18. #include "childfrm.h"
  19. /*+-------------------------------------------------------------------------*
  20. * GetMainAuxWnd
  21. *
  22. *
  23. *--------------------------------------------------------------------------*/
  24. CToolbarTrackerAuxWnd* GetMainAuxWnd()
  25. {
  26. CMainFrame* pFrame = AMCGetMainWnd();
  27. if (pFrame == NULL)
  28. return (NULL);
  29. CToolbarTracker* pTracker = pFrame->GetToolbarTracker();
  30. if (pTracker == NULL)
  31. return (NULL);
  32. return (pTracker->GetAuxWnd());
  33. }
  34. /*--------------------------------------------------------------------------*
  35. * IsToolbar
  36. *
  37. *
  38. *--------------------------------------------------------------------------*/
  39. static bool IsToolbar (HWND hwnd)
  40. {
  41. TCHAR szClassName[countof (TOOLBARCLASSNAME) + 1];
  42. GetClassName (hwnd, szClassName, countof (szClassName));
  43. return (lstrcmpi (szClassName, TOOLBARCLASSNAME) == 0);
  44. }
  45. /*--------------------------------------------------------------------------*
  46. * CToolbarTracker::CToolbarTracker
  47. *
  48. *
  49. *--------------------------------------------------------------------------*/
  50. CToolbarTracker::CToolbarTracker(CWnd* pMainFrame)
  51. : m_Subclasser (this, pMainFrame),
  52. m_pAuxWnd (NULL),
  53. m_fTerminating (false)
  54. {
  55. }
  56. /*--------------------------------------------------------------------------*
  57. * CToolbarTracker::~CToolbarTracker
  58. *
  59. *
  60. *--------------------------------------------------------------------------*/
  61. CToolbarTracker::~CToolbarTracker()
  62. {
  63. if (IsTracking ())
  64. EndTracking ();
  65. ASSERT (!IsTracking ());
  66. ASSERT (m_pAuxWnd == NULL);
  67. }
  68. /*--------------------------------------------------------------------------*
  69. * CToolbarTracker::BeginTracking
  70. *
  71. *
  72. *--------------------------------------------------------------------------*/
  73. bool CToolbarTracker::BeginTracking()
  74. {
  75. ASSERT (!m_fTerminating);
  76. ASSERT (!IsTracking ());
  77. /*
  78. * Allocate a new CToolbarTrackerAuxWnd. We want to hold it in a
  79. * temporary instead of assigning directly to m_pAuxWnd so that
  80. * CMMCToolBarCtrlEx::OnHotItemChange will allow the hot item
  81. * changes that CToolbarTrackerAuxWnd::EnumerateToolbars will attempt.
  82. */
  83. std::auto_ptr<CToolbarTrackerAuxWnd> spAuxWnd(new CToolbarTrackerAuxWnd(this));
  84. if (!spAuxWnd->BeginTracking ())
  85. return (false);
  86. m_pAuxWnd = spAuxWnd.release();
  87. ASSERT (IsTracking ());
  88. return (true);
  89. }
  90. /*--------------------------------------------------------------------------*
  91. * CToolbarTracker::EndTracking
  92. *
  93. *
  94. *--------------------------------------------------------------------------*/
  95. void CToolbarTracker::EndTracking()
  96. {
  97. if (m_fTerminating)
  98. return;
  99. ASSERT (IsTracking ());
  100. m_fTerminating = true;
  101. m_pAuxWnd->EndTracking ();
  102. delete m_pAuxWnd;
  103. m_pAuxWnd = NULL;
  104. m_fTerminating = false;
  105. }
  106. /*--------------------------------------------------------------------------*
  107. * CToolbarTracker::CFrameSubclasser::CFrameSubclasser
  108. *
  109. *
  110. *--------------------------------------------------------------------------*/
  111. CToolbarTracker::CFrameSubclasser::CFrameSubclasser (CToolbarTracker* pTracker, CWnd* pwnd)
  112. : m_hwnd (pwnd->GetSafeHwnd()),
  113. m_pTracker (pTracker)
  114. {
  115. GetSubclassManager().SubclassWindow (m_hwnd, this);
  116. }
  117. /*--------------------------------------------------------------------------*
  118. * CToolbarTracker::CFrameSubclasser::~CFrameSubclasser
  119. *
  120. *
  121. *--------------------------------------------------------------------------*/
  122. CToolbarTracker::CFrameSubclasser::~CFrameSubclasser ()
  123. {
  124. GetSubclassManager().UnsubclassWindow (m_hwnd, this);
  125. }
  126. /*--------------------------------------------------------------------------*
  127. * CToolbarTracker::CFrameSubclasser::Callback
  128. *
  129. *
  130. *--------------------------------------------------------------------------*/
  131. LRESULT CToolbarTracker::CFrameSubclasser::Callback (
  132. HWND& hwnd,
  133. UINT& msg,
  134. WPARAM& wParam,
  135. LPARAM& lParam,
  136. bool& fPassMessageOn)
  137. {
  138. switch (msg)
  139. {
  140. case WM_SYSCOMMAND:
  141. if ((wParam & 0xFFF0) == SC_CLOSE)
  142. {
  143. /*
  144. * tracking? stop now.
  145. * or else close will not go thru,
  146. * since we hold the capture
  147. */
  148. if ((m_pTracker != NULL) && (m_pTracker->IsTracking ()))
  149. m_pTracker->EndTracking ();
  150. }
  151. else if ((wParam & 0xFFF0) == SC_KEYMENU)
  152. {
  153. /*
  154. * tracking? stop now.
  155. */
  156. if (m_pTracker->IsTracking ())
  157. m_pTracker->EndTracking ();
  158. /*
  159. * not tracking and this was a simple Alt,
  160. * (not Alt+Space or Alt+-)? start now
  161. */
  162. else if (lParam == 0)
  163. m_pTracker->BeginTracking ();
  164. /*
  165. * don't let simple Alt through, regardless of whether
  166. * we started or ended tracking
  167. */
  168. if (lParam == 0)
  169. fPassMessageOn = false;
  170. }
  171. break;
  172. case WM_ACTIVATE:
  173. case WM_ACTIVATEAPP:
  174. case WM_ACTIVATETOPLEVEL:
  175. // case WM_ENTERMENULOOP:
  176. case WM_CANCELMODE:
  177. if (m_pTracker->IsTracking ())
  178. m_pTracker->EndTracking ();
  179. break;
  180. }
  181. return (0);
  182. }
  183. /////////////////////////////////////////////////////////////////////////////
  184. // CToolbarTrackerAuxWnd
  185. BEGIN_MESSAGE_MAP(CToolbarTrackerAuxWnd, CWnd)
  186. //{{AFX_MSG_MAP(CToolbarTrackerAuxWnd)
  187. ON_COMMAND(ID_CMD_NEXT_TOOLBAR, OnNextToolbar)
  188. ON_COMMAND(ID_CMD_PREV_TOOLBAR, OnPrevToolbar)
  189. ON_COMMAND(ID_CMD_NOP, OnNop)
  190. //}}AFX_MSG_MAP
  191. END_MESSAGE_MAP()
  192. /*--------------------------------------------------------------------------*
  193. * CToolbarTrackerAuxWnd::CToolbarTrackerAuxWnd
  194. *
  195. *
  196. *--------------------------------------------------------------------------*/
  197. CToolbarTrackerAuxWnd::CToolbarTrackerAuxWnd(CToolbarTracker* pTracker)
  198. : m_pTracker (pTracker),
  199. m_pTrackedToolbar (NULL),
  200. m_fMessagesHooked (false)
  201. {
  202. }
  203. /*--------------------------------------------------------------------------*
  204. * CToolbarTrackerAuxWnd::~CToolbarTrackerAuxWnd
  205. *
  206. *
  207. *--------------------------------------------------------------------------*/
  208. CToolbarTrackerAuxWnd::~CToolbarTrackerAuxWnd()
  209. {
  210. /*
  211. * if any of these fail, EndTracking hasn't been called
  212. */
  213. ASSERT (m_pTrackedToolbar == NULL);
  214. ASSERT (m_hWnd == NULL);
  215. }
  216. /*--------------------------------------------------------------------------*
  217. * CToolbarTrackerAuxWnd::BeginTracking
  218. *
  219. *
  220. *--------------------------------------------------------------------------*/
  221. bool CToolbarTrackerAuxWnd::BeginTracking ()
  222. {
  223. CMainFrame* pMainFrame = AMCGetMainWnd();
  224. if (pMainFrame == NULL)
  225. return (false);
  226. /*
  227. * create a dummy window to be the target of WM_COMMANDs from accelerators
  228. */
  229. if (!Create (NULL, NULL, WS_DISABLED, g_rectEmpty, pMainFrame, 0))
  230. return (false);
  231. /*
  232. * enumerate the toolbars for the main frame
  233. */
  234. EnumerateToolbars (pMainFrame->GetRebar());
  235. /*
  236. * if there aren't any toolbars, don't track
  237. */
  238. if (m_vToolbars.empty())
  239. {
  240. DestroyWindow ();
  241. return (false);
  242. }
  243. /*
  244. * track the first toolbar
  245. */
  246. TrackToolbar (m_vToolbars[0]);
  247. /*
  248. * hook into the translate message chain
  249. */
  250. AMCGetApp()->HookPreTranslateMessage (this);
  251. m_fMessagesHooked = true;
  252. return (true);
  253. }
  254. /*--------------------------------------------------------------------------*
  255. * CToolbarTrackerAuxWnd::EndTracking
  256. *
  257. *
  258. *--------------------------------------------------------------------------*/
  259. void CToolbarTrackerAuxWnd::EndTracking ()
  260. {
  261. /*
  262. * stop tracking the tracked toolbar, if there is one
  263. */
  264. if (m_pTrackedToolbar != NULL)
  265. m_pTrackedToolbar->EndTracking2 (this);
  266. /*
  267. * get out of the translate message chain
  268. */
  269. if (m_fMessagesHooked)
  270. {
  271. AMCGetApp()->UnhookPreTranslateMessage (this);
  272. m_fMessagesHooked = false;
  273. }
  274. /*
  275. * destroy the auxilliary window
  276. */
  277. DestroyWindow();
  278. }
  279. /*--------------------------------------------------------------------------*
  280. * CToolbarTrackerAuxWnd::GetTrackAccel
  281. *
  282. * Manages the accelerator table singleton for CToolbarTrackerAuxWnd
  283. *--------------------------------------------------------------------------*/
  284. const CAccel& CToolbarTrackerAuxWnd::GetTrackAccel ()
  285. {
  286. static ACCEL aaclTrack[] = {
  287. { FVIRTKEY | FCONTROL, VK_TAB, ID_CMD_NEXT_TOOLBAR },
  288. { FVIRTKEY | FCONTROL | FSHIFT, VK_TAB, ID_CMD_PREV_TOOLBAR },
  289. /*
  290. * These keys are used by MMC.
  291. * We need to eat them when we're tracking toolbars.
  292. */
  293. { FVIRTKEY | FSHIFT, VK_F10, ID_CMD_NOP },
  294. };
  295. static const CAccel TrackAccel (aaclTrack, countof (aaclTrack));
  296. return (TrackAccel);
  297. }
  298. /*--------------------------------------------------------------------------*
  299. * CToolbarTrackerAuxWnd::PreTranslateMessage
  300. *
  301. *
  302. *--------------------------------------------------------------------------*/
  303. BOOL CToolbarTrackerAuxWnd::PreTranslateMessage(MSG* pMsg)
  304. {
  305. if (m_pTrackedToolbar != NULL)
  306. {
  307. if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))
  308. {
  309. // give the tracked toolbar a crack
  310. if (m_pTrackedToolbar->PreTranslateMessage (pMsg))
  311. return (true);
  312. const CAccel& TrackAccel = GetTrackAccel();
  313. ASSERT (TrackAccel != NULL);
  314. // ...or try to handle it here.
  315. if (TrackAccel.TranslateAccelerator (m_hWnd, pMsg))
  316. return (true);
  317. /*
  318. * eat keystrokes that might be used by the tree or list controls
  319. */
  320. switch (pMsg->wParam)
  321. {
  322. case VK_UP:
  323. case VK_DOWN:
  324. case VK_LEFT:
  325. case VK_RIGHT:
  326. case VK_NEXT:
  327. case VK_PRIOR:
  328. case VK_RETURN:
  329. case VK_BACK:
  330. case VK_HOME:
  331. case VK_END:
  332. case VK_ADD:
  333. case VK_SUBTRACT:
  334. case VK_MULTIPLY:
  335. return (true);
  336. default:
  337. break;
  338. }
  339. }
  340. // swallow WM_CONTEXTMENU, too
  341. if (pMsg->message == WM_CONTEXTMENU)
  342. return (true);
  343. }
  344. // bypass the base class
  345. return (false);
  346. }
  347. /*--------------------------------------------------------------------------*
  348. * CToolbarTrackerAuxWnd::TrackToolbar
  349. *
  350. *
  351. *--------------------------------------------------------------------------*/
  352. void CToolbarTrackerAuxWnd::TrackToolbar (CMMCToolBarCtrlEx* pwndNewToolbar)
  353. {
  354. if (pwndNewToolbar == m_pTrackedToolbar)
  355. return;
  356. // protect against recursion via EndTracking
  357. CMMCToolBarCtrlEx* pwndOldToolbar = m_pTrackedToolbar;
  358. m_pTrackedToolbar = NULL;
  359. // if we were tracking one, quit tracking it
  360. if (pwndOldToolbar != NULL)
  361. {
  362. pwndOldToolbar->EndTracking2 (this);
  363. /*
  364. * if we're ending tracking entirely, not just tracking a different
  365. * toolbar, remove this window from the translate message hook chain
  366. */
  367. if (pwndNewToolbar == NULL)
  368. {
  369. m_pTracker->EndTracking ();
  370. /*
  371. * CToolbarTracker::EndTracking will delete this
  372. * object, so we need to get outta here -- now!
  373. */
  374. return;
  375. }
  376. }
  377. // now track the new one (and let it know about it)
  378. m_pTrackedToolbar = pwndNewToolbar;
  379. if (m_pTrackedToolbar != NULL)
  380. m_pTrackedToolbar->BeginTracking2 (this);
  381. }
  382. /*--------------------------------------------------------------------------*
  383. * CToolbarTrackerAuxWnd::OnNextToolbar
  384. *
  385. *
  386. *--------------------------------------------------------------------------*/
  387. void CToolbarTrackerAuxWnd::OnNextToolbar ()
  388. {
  389. ASSERT (m_pTrackedToolbar);
  390. CMMCToolBarCtrlEx* pwndNextToolbar = GetToolbar (m_pTrackedToolbar, true);
  391. if (m_pTrackedToolbar != pwndNextToolbar)
  392. TrackToolbar (pwndNextToolbar);
  393. ASSERT (m_pTrackedToolbar == pwndNextToolbar);
  394. }
  395. /*--------------------------------------------------------------------------*
  396. * CToolbarTrackerAuxWnd::OnPrevToolbar
  397. *
  398. *
  399. *--------------------------------------------------------------------------*/
  400. void CToolbarTrackerAuxWnd::OnPrevToolbar ()
  401. {
  402. ASSERT (m_pTrackedToolbar);
  403. CMMCToolBarCtrlEx* pwndPrevToolbar = GetToolbar (m_pTrackedToolbar, false);
  404. if (m_pTrackedToolbar != pwndPrevToolbar)
  405. TrackToolbar (pwndPrevToolbar);
  406. ASSERT (m_pTrackedToolbar == pwndPrevToolbar);
  407. }
  408. /*--------------------------------------------------------------------------*
  409. * CToolbarTrackerAuxWnd::OnNop
  410. *
  411. *
  412. *--------------------------------------------------------------------------*/
  413. void CToolbarTrackerAuxWnd::OnNop ()
  414. {
  415. // do nothing
  416. }
  417. /*--------------------------------------------------------------------------*
  418. * CToolbarTrackerAuxWnd::EnumerateToolbars
  419. *
  420. *
  421. *--------------------------------------------------------------------------*/
  422. void CToolbarTrackerAuxWnd::EnumerateToolbars (
  423. CRebarWnd* pRebar)
  424. {
  425. int cBands = pRebar->GetBandCount ();
  426. REBARBANDINFO rbi;
  427. ZeroMemory (&rbi, sizeof (rbi));
  428. rbi.cbSize = sizeof (rbi);
  429. rbi.fMask = RBBIM_CHILD;
  430. /*
  431. * enumerate children of the rebar looking for toolbars
  432. */
  433. for (int i = 0; i < cBands; i++)
  434. {
  435. pRebar->GetBandInfo (i, &rbi);
  436. /*
  437. * ignore this window if it's hidden or disabled
  438. */
  439. DWORD dwStyle = ::GetWindowLong (rbi.hwndChild, GWL_STYLE);
  440. if (!(dwStyle & WS_VISIBLE) || (dwStyle & WS_DISABLED))
  441. continue;
  442. /*
  443. * get the (permanent) CMMCToolBarCtrlEx pointer for the child
  444. */
  445. CMMCToolBarCtrlEx* pwndToolbar =
  446. dynamic_cast<CMMCToolBarCtrlEx *> (
  447. CWnd::FromHandlePermanent (rbi.hwndChild));
  448. /*
  449. * if we got a toolbar, save it in our list of toolbars to track
  450. */
  451. if (pwndToolbar != NULL)
  452. {
  453. m_vToolbars.push_back (pwndToolbar);
  454. /*
  455. * make sure this toolbar doesn't have a hot item
  456. */
  457. pwndToolbar->SetHotItem (-1);
  458. }
  459. }
  460. }
  461. /*--------------------------------------------------------------------------*
  462. * CToolbarTrackerAuxWnd::GetToolbar
  463. *
  464. *
  465. *--------------------------------------------------------------------------*/
  466. CMMCToolBarCtrlEx* CToolbarTrackerAuxWnd::GetToolbar (
  467. CMMCToolBarCtrlEx* pCurrentToolbar,
  468. bool fNext)
  469. {
  470. CMMCToolBarCtrlEx* pTargetToolbar = NULL;
  471. int cToolbars = m_vToolbars.size();
  472. if (cToolbars > 0)
  473. {
  474. // find the current toolbar in the vector
  475. ToolbarVector::iterator itCurrent =
  476. std::find (m_vToolbars.begin(), m_vToolbars.end(), pCurrentToolbar);
  477. ASSERT ( itCurrent != m_vToolbars.end());
  478. ASSERT (*itCurrent == pCurrentToolbar);
  479. int nCurrentIndex = itCurrent - m_vToolbars.begin();
  480. // now find the target toolbar
  481. ASSERT ((fNext == 0) || (fNext == 1));
  482. int nTargetIndex = (nCurrentIndex + (fNext * 2 - 1) + cToolbars) % cToolbars;
  483. ASSERT ((nTargetIndex >= 0) && (nTargetIndex < cToolbars));
  484. ASSERT ((cToolbars == 1) || (nTargetIndex != nCurrentIndex));
  485. pTargetToolbar = m_vToolbars[nTargetIndex];
  486. ASSERT (pTargetToolbar != NULL);
  487. }
  488. return (pTargetToolbar);
  489. }