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.

506 lines
11 KiB

  1. #include "priv.h"
  2. #include "apithk.h"
  3. #include "mshtmhst.h"
  4. #include "basebar.h"
  5. #ifdef MAINWIN
  6. #include <mainwin.h>
  7. EXTERN_C MwPaintSpecialEOBorder( HWND hWnd, HDC hDC );
  8. #endif
  9. #define DBM_ONPOSRECTCHANGE (WM_USER)
  10. //*** CBaseBar::IDeskBar::* {
  11. //
  12. /*----------------------------------------------------------
  13. Purpose: IDeskBar::SetClient
  14. Usually the function that composes a bar/bandsite/band
  15. union is responsible for calling this method to inform
  16. the bar what the client (bandsite) is.
  17. */
  18. HRESULT CBaseBar::SetClient(IUnknown *punkChild)
  19. {
  20. if (_punkChild != NULL)
  21. {
  22. // 4, 3, 2, 1 Release
  23. _hwndChild = NULL;
  24. if (_pDBC)
  25. {
  26. // This must happen first, before _pWEH becomes NULL so cleanup
  27. // notifications can still go thru
  28. _pDBC->SetDeskBarSite(NULL);
  29. }
  30. ATOMICRELEASE(_pDBC);
  31. ATOMICRELEASE(_pWEH);
  32. ATOMICRELEASE(_punkChild);
  33. }
  34. _punkChild = punkChild;
  35. HRESULT hr = S_OK;
  36. if (_punkChild != NULL)
  37. {
  38. // 1, 2, 3, 4 QI/AddRef/etc.
  39. _punkChild->AddRef();
  40. if (!_hwnd)
  41. {
  42. _RegisterDeskBarClass();
  43. _CreateDeskBarWindow();
  44. if (!_hwnd)
  45. {
  46. return E_OUTOFMEMORY;
  47. }
  48. // can't do CBaseBar::_Initialize yet (haven't done SetSite yet)
  49. }
  50. hr = _punkChild->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pWEH));
  51. if (SUCCEEDED(hr))
  52. {
  53. hr = _punkChild->QueryInterface(IID_PPV_ARG(IDeskBarClient, &_pDBC));
  54. if (SUCCEEDED(hr))
  55. {
  56. // nothing to cache yet due to lazy CreateWindow
  57. hr = _pDBC->SetDeskBarSite(SAFECAST(this, IDeskBar*));
  58. IUnknown_GetWindow(_punkChild, &_hwndChild);
  59. }
  60. }
  61. }
  62. return hr;
  63. }
  64. HRESULT CBaseBar::GetClient(IUnknown **ppunk)
  65. {
  66. *ppunk = _punkChild;
  67. if (_punkChild)
  68. _punkChild->AddRef();
  69. return _punkChild ? S_OK : E_FAIL;
  70. }
  71. HRESULT CBaseBar::OnPosRectChangeDB(LPRECT prc)
  72. {
  73. _szChild.cx = RECTWIDTH(*prc);
  74. _szChild.cy = RECTHEIGHT(*prc);
  75. // We can't change our size right away because we haven't returned from processing
  76. // this WM_SIZE message. If we resize right now, USER gets confused...
  77. //
  78. // We cannot use PeekMessage to determine if there is already a pending
  79. // DBM_ONPOSRECTCHANGE because that allows incoming SendMessage's to
  80. // arrive, and then we can get into a bad recursive situation when there
  81. // are a lot of SHChangeNotify's arriving in rapid succession.
  82. //
  83. if (!_fPosRectChangePending)
  84. {
  85. _fPosRectChangePending = TRUE;
  86. PostMessage(_hwnd, DBM_ONPOSRECTCHANGE, 0, 0);
  87. }
  88. return S_OK;
  89. }
  90. // Derived classes are expected to implement this method and do something
  91. // interesting...
  92. void CBaseBar::_OnPostedPosRectChange()
  93. {
  94. }
  95. // }
  96. HRESULT CBaseBar::ShowDW(BOOL fShow)
  97. {
  98. fShow = BOOLIFY(fShow);
  99. if (BOOLIFY(_fShow) == fShow)
  100. return S_OK;
  101. _fShow = fShow;
  102. if (_pDBC)
  103. return _pDBC->UIActivateDBC(fShow ? DBC_SHOW : DBC_HIDE);
  104. else
  105. return E_UNEXPECTED;
  106. }
  107. void CBaseBar::_OnCreate()
  108. {
  109. SendMessage(_hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
  110. }
  111. LRESULT CBaseBar::_OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam)
  112. {
  113. LRESULT lres = 0;
  114. _CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
  115. return lres;
  116. }
  117. /***
  118. */
  119. LRESULT CBaseBar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  120. {
  121. LRESULT lres = 0;
  122. switch (uMsg) {
  123. case WM_CREATE:
  124. _OnCreate();
  125. break;
  126. case WM_COMMAND:
  127. return _OnCommand(uMsg, wParam, lParam);
  128. case WM_SIZE:
  129. _OnSize();
  130. break;
  131. case WM_NOTIFY:
  132. return _OnNotify(uMsg, wParam, lParam);
  133. #if 0
  134. // we'd like to set focus to the 1st band when somebody clicks in
  135. // 'dead space' on the bar (i.e. make it look like they TABed in).
  136. // however for some reason the below code has the bad effect of
  137. // de-selecting text in (e.g.) the addr edit control (it's as if
  138. // the control thinks we've clicked there 2x rather than 1x).
  139. case WM_SETFOCUS:
  140. if (IUnknown_HasFocusIO(_pDBC) == S_FALSE)
  141. IUnknown_UIActivateIO(_pDBC, TRUE, NULL);
  142. break;
  143. #endif
  144. case WM_SYSCOLORCHANGE:
  145. case WM_WININICHANGE:
  146. case WM_CONTEXTMENU:
  147. case WM_INITMENUPOPUP:
  148. case WM_MEASUREITEM:
  149. case WM_DRAWITEM:
  150. case WM_MENUCHAR:
  151. case WM_PALETTECHANGED:
  152. _CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
  153. break;
  154. case DBM_ONPOSRECTCHANGE:
  155. _fPosRectChangePending = FALSE;
  156. _OnPostedPosRectChange();
  157. break;
  158. #ifdef MAINWIN
  159. case WM_NCPAINTSPECIALFRAME:
  160. // In case of motif look the MwPaintBorder paints a Etched In
  161. // border if WM_NCPAINTSPECIALFRAME returns FALSE. We are handling
  162. // this message here and drawing the Etched Out frame explicitly.
  163. // wParam - HDC
  164. if (MwCurrentLook() == LOOK_MOTIF)
  165. {
  166. MwPaintSpecialEOBorder( hwnd, (HDC)wParam );
  167. return TRUE;
  168. }
  169. #endif
  170. default:
  171. return DefWindowProcWrap(hwnd, uMsg, wParam, lParam);
  172. }
  173. return lres;
  174. }
  175. /***
  176. */
  177. CBaseBar::CBaseBar() : _cRef(1)
  178. {
  179. DllAddRef();
  180. }
  181. /***
  182. */
  183. CBaseBar::~CBaseBar()
  184. {
  185. // see Release, where we call virtuals (which can't be called from dtor)
  186. DllRelease();
  187. }
  188. /***
  189. */
  190. void CBaseBar::_RegisterDeskBarClass()
  191. {
  192. WNDCLASS wc = {0};
  193. wc.style = _GetClassStyle();
  194. wc.lpfnWndProc = s_WndProc;
  195. //wc.cbClsExtra = 0;
  196. wc.cbWndExtra = SIZEOF(CBaseBar*);
  197. wc.hInstance = HINST_THISDLL;
  198. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  199. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE+1);
  200. //wc.lpszMenuName = NULL;
  201. wc.lpszClassName = TEXT("BaseBar");
  202. //wc.hIcon = NULL;
  203. SHRegisterClass(&wc);
  204. }
  205. DWORD CBaseBar::_GetExStyle()
  206. {
  207. return WS_EX_TOOLWINDOW;
  208. }
  209. DWORD CBaseBar::_GetClassStyle()
  210. {
  211. return CS_HREDRAW | CS_VREDRAW;
  212. }
  213. void CBaseBar::_CreateDeskBarWindow()
  214. {
  215. #ifndef UNIX
  216. // _hwnd is set in s_WndProc
  217. DWORD dwExStyle = _GetExStyle();
  218. dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L;
  219. HWND hwndDummy = CreateWindowEx(
  220. dwExStyle,
  221. TEXT("BaseBar"), NULL,
  222. _hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN,
  223. 0,0,100,100,
  224. _hwndSite, NULL, HINST_THISDLL,
  225. (LPVOID)SAFECAST(this, CImpWndProc*));
  226. #else
  227. // This change removes a flash at the corner of the
  228. // screen. We create a small 1,1 window.
  229. HWND hwndDummy = CreateWindowEx(
  230. _GetExStyle(),
  231. TEXT("BaseBar"), NULL,
  232. _hwndSite ? WS_CHILD | WS_CLIPCHILDREN : WS_POPUP | WS_CLIPCHILDREN,
  233. -100,-100,1,1,
  234. _hwndSite, NULL, HINST_THISDLL,
  235. (LPVOID)SAFECAST(this, CImpWndProc*));
  236. #endif
  237. }
  238. void CBaseBar::_OnSize(void)
  239. {
  240. RECT rc;
  241. if (!_hwndChild)
  242. return;
  243. GetClientRect(_hwnd, &rc);
  244. SetWindowPos(_hwndChild, 0,
  245. rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
  246. SWP_NOACTIVATE|SWP_NOZORDER);
  247. }
  248. void CBaseBar::_NotifyModeChange(DWORD dwMode)
  249. {
  250. if (_pDBC) {
  251. _dwMode = dwMode;
  252. // FEATURE: should we add an STBBIF_VIEWMODE_FLOAT?
  253. _pDBC->SetModeDBC(_dwMode);
  254. }
  255. }
  256. BOOL CBaseBar::_CheckForwardWinEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  257. {
  258. HWND hwnd = NULL;
  259. *plres = 0;
  260. switch (uMsg)
  261. {
  262. case WM_CONTEXTMENU:
  263. case WM_INITMENUPOPUP:
  264. case WM_MEASUREITEM:
  265. case WM_DRAWITEM:
  266. case WM_MENUCHAR:
  267. hwnd = _hwndChild;
  268. break;
  269. case WM_NOTIFY:
  270. hwnd = ((LPNMHDR)lParam)->hwndFrom;
  271. break;
  272. case WM_COMMAND:
  273. hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
  274. break;
  275. case WM_SYSCOLORCHANGE:
  276. case WM_WININICHANGE:
  277. case WM_PALETTECHANGED:
  278. hwnd = _hwndChild;
  279. break;
  280. }
  281. if (hwnd && _pWEH && _pWEH->IsWindowOwner(hwnd) == S_OK)
  282. {
  283. _pWEH->OnWinEvent(_hwnd, uMsg, wParam, lParam, plres);
  284. return TRUE;
  285. }
  286. return FALSE;
  287. }
  288. /***
  289. */
  290. LRESULT CBaseBar::_OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam)
  291. {
  292. LRESULT lres = 0;
  293. _CheckForwardWinEvent(uMsg, wParam, lParam, &lres);
  294. return lres;
  295. }
  296. HRESULT CBaseBar::CloseDW(DWORD dwReserved)
  297. {
  298. SetClient(NULL);
  299. if (_hwnd) {
  300. DestroyWindow(_hwnd);
  301. _hwnd = NULL;
  302. }
  303. return S_OK;
  304. }
  305. HRESULT CBaseBar::QueryInterface(REFIID riid, LPVOID * ppvObj)
  306. {
  307. static const QITAB qit[] = {
  308. QITABENT(CBaseBar, IOleWindow),
  309. QITABENT(CBaseBar, IDeskBar),
  310. QITABENT(CBaseBar, IInputObject),
  311. QITABENT(CBaseBar, IInputObjectSite),
  312. QITABENT(CBaseBar, IServiceProvider),
  313. QITABENT(CBaseBar, IOleCommandTarget),
  314. { 0 },
  315. };
  316. return QISearch(this, (LPCQITAB)qit, riid, ppvObj);
  317. }
  318. ULONG CBaseBar::AddRef()
  319. {
  320. _cRef++;
  321. return _cRef;
  322. }
  323. ULONG CBaseBar::Release()
  324. {
  325. ASSERT(_cRef > 0);
  326. _cRef--;
  327. if (_cRef > 0)
  328. return _cRef;
  329. // 'virtual dtor'
  330. // gotta do virtual stuff here (not in dtor) because can't call
  331. // any virtuals in the dtor
  332. // CBaseBar::Destroy() {
  333. CloseDW(0);
  334. // }
  335. delete this;
  336. return 0;
  337. }
  338. //*** CBaseBar::IOleWindow::* {
  339. //
  340. HRESULT CBaseBar::GetWindow(HWND * lphwnd)
  341. {
  342. *lphwnd = _hwnd;
  343. return (_hwnd) ? S_OK : E_FAIL;
  344. }
  345. HRESULT CBaseBar::ContextSensitiveHelp(BOOL fEnterMode)
  346. {
  347. // FEATURE: Visit here later.
  348. return E_NOTIMPL;
  349. }
  350. // }
  351. // }
  352. // some helpers... {
  353. // What's the point of having
  354. // these empty implementations in the base class?
  355. //
  356. //*** CBaseBar::IServiceProvider::*
  357. //
  358. HRESULT CBaseBar::QueryService(REFGUID guidService,
  359. REFIID riid, void **ppvObj)
  360. {
  361. HRESULT hres = E_FAIL;
  362. *ppvObj = NULL;
  363. return hres;
  364. }
  365. //*** CBaseBar::IOleCommandTarget::*
  366. //
  367. HRESULT CBaseBar::QueryStatus(const GUID *pguidCmdGroup,
  368. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  369. {
  370. return MayQSForward(_pDBC, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  371. }
  372. HRESULT CBaseBar::Exec(const GUID *pguidCmdGroup,
  373. DWORD nCmdID, DWORD nCmdexecopt,
  374. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  375. {
  376. return MayExecForward(_pDBC, OCTD_DOWN, pguidCmdGroup, nCmdID, nCmdexecopt,
  377. pvarargIn, pvarargOut);
  378. }
  379. // }
  380. //*** CDeskBar::IInputObject::* {
  381. HRESULT CBaseBar::HasFocusIO()
  382. {
  383. HRESULT hres;
  384. hres = IUnknown_HasFocusIO(_pDBC);
  385. return hres;
  386. }
  387. HRESULT CBaseBar::TranslateAcceleratorIO(LPMSG lpMsg)
  388. {
  389. HRESULT hres;
  390. hres = IUnknown_TranslateAcceleratorIO(_pDBC, lpMsg);
  391. return hres;
  392. }
  393. HRESULT CBaseBar::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  394. {
  395. HRESULT hres;
  396. hres = IUnknown_UIActivateIO(_pDBC, fActivate, lpMsg);
  397. return hres;
  398. }
  399. // }
  400. //*** CDeskBar::IInputObjectSite::* {
  401. HRESULT CBaseBar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  402. {
  403. return NOERROR;
  404. }
  405. // }