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.

1587 lines
43 KiB

  1. #include "shellprv.h"
  2. #include "ids.h"
  3. #include <oleacc.h>
  4. #ifndef POINTSPERRECT
  5. #define POINTSPERRECT (sizeof(RECT)/sizeof(POINT))
  6. #endif
  7. #define TESTKEYSTATE(vk) ((GetKeyState(vk) & 0x8000)!=0)
  8. #define LINKCOLOR_BKGND COLOR_WINDOW
  9. #define LINKCOLOR_ENABLED GetSysColor(COLOR_HOTLIGHT)
  10. #define LINKCOLOR_DISABLED GetSysColor(COLOR_GRAYTEXT)
  11. #define CF_SETCAPTURE 0x0001
  12. #define CF_SETFOCUS 0x0002
  13. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags);
  14. BOOL _HandleWM_UPDATEUISTATE(IN WPARAM wParam, IN LPARAM lParam, IN OUT UINT* puFlags);
  15. // common IAccessible implementation.
  16. class CAccessibleBase : public IAccessible, public IOleWindow
  17. {
  18. public:
  19. CAccessibleBase(const HWND& hwnd)
  20. : _cRef(1), _ptiAcc(NULL), _hwnd(hwnd)
  21. {
  22. DllAddRef();
  23. }
  24. virtual ~CAccessibleBase()
  25. {
  26. DllRelease();
  27. ATOMICRELEASE(_ptiAcc);
  28. }
  29. // IUnknown
  30. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  31. STDMETHODIMP_(ULONG) AddRef();
  32. STDMETHODIMP_(ULONG) Release();
  33. // IOleWindow
  34. STDMETHODIMP GetWindow(HWND* phwnd);
  35. STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; }
  36. // IDispatch
  37. STDMETHODIMP GetTypeInfoCount(UINT * pctinfo);
  38. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  39. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames,
  40. LCID lcid, DISPID * rgdispid);
  41. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  42. DISPPARAMS * pdispparams, VARIANT * pvarResult,
  43. EXCEPINFO * pexcepinfo, UINT * puArgErr);
  44. // IAccessible
  45. STDMETHODIMP get_accParent(IDispatch ** ppdispParent);
  46. STDMETHODIMP get_accChildCount(long * pcChildren);
  47. STDMETHODIMP get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild);
  48. STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pbstrValue);
  49. STDMETHODIMP get_accDescription(VARIANT varChild, BSTR * pbstrDescription);
  50. STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
  51. STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
  52. STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pbstrHelp);
  53. STDMETHODIMP get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic);
  54. STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut);
  55. STDMETHODIMP get_accFocus(VARIANT FAR * pvarFocusChild);
  56. STDMETHODIMP get_accSelection(VARIANT FAR * pvarSelectedChildren);
  57. STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction);
  58. STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild);
  59. STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild);
  60. STDMETHODIMP accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt);
  61. STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint);
  62. STDMETHODIMP put_accName(VARIANT varChild, BSTR bstrName);
  63. STDMETHODIMP put_accValue(VARIANT varChild, BSTR bstrValue);
  64. protected:
  65. virtual UINT GetDefaultActionStringID() const = 0;
  66. private:
  67. LONG _cRef;
  68. ITypeInfo* _ptiAcc;
  69. const HWND& _hwnd;
  70. #define VALIDATEACCCHILD(varChild, idChild, hrFail) \
  71. if (!(VT_I4 == varChild.vt && idChild == varChild.lVal)) {return hrFail;}
  72. };
  73. #define TEST_CAPTURE(fTest) ((_fCapture & fTest) != 0)
  74. #define MODIFY_CAPTURE(fSet, fRemove) {if (fSet){_fCapture |= fSet;} if (fRemove){_fCapture &= ~fRemove;}}
  75. #define RESET_CAPTURE() {_fCapture=0;}
  76. // this API for compat with old clients of the shell32 link window. that is now
  77. // in comctl32.dll
  78. BOOL WINAPI LinkWindow_RegisterClass()
  79. {
  80. // get the comctl32 linkwindow, and point the old classname at it
  81. INITCOMMONCONTROLSEX iccs = {sizeof(iccs), ICC_LINK_CLASS};
  82. InitCommonControlsEx(&iccs);
  83. WNDCLASS wc;
  84. ULONG_PTR dwCookie = 0;
  85. SHActivateContext(&dwCookie);
  86. BOOL bRet = GetClassInfo(NULL, WC_LINK, &wc);
  87. SHDeactivateContext(dwCookie);
  88. if (bRet)
  89. {
  90. wc.lpszClassName = TEXT("Link Window"); // old class name for old clients
  91. RegisterClass(&wc);
  92. }
  93. return bRet;
  94. }
  95. BOOL WINAPI LinkWindow_UnregisterClass(HINSTANCE)
  96. {
  97. return TRUE;
  98. }
  99. #define GROUPBTN_BKCOLOR COLOR_WINDOW
  100. #define CAPTION_VPADDING 3
  101. #define CAPTION_HPADDING 2
  102. #define GBM_SENDNOTIFY (GBM_LAST + 1)
  103. // class CGroupBtn
  104. class CGroupBtn : public CAccessibleBase
  105. { // all members private:
  106. CGroupBtn(HWND hwnd);
  107. ~CGroupBtn();
  108. // IAccessible specialization
  109. STDMETHODIMP get_accName(VARIANT varChild, BSTR* pbstrName);
  110. STDMETHODIMP accDoDefaultAction(VARIANT varChild);
  111. // CAccessibleBase overrides
  112. UINT GetDefaultActionStringID() const { return IDS_GROUPBTN_DEFAULTACTION; }
  113. // window procedures
  114. static LRESULT WINAPI s_GroupBtnWndProc(HWND, UINT, WPARAM, LPARAM);
  115. LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
  116. static LRESULT WINAPI s_BuddyProc(HWND, UINT, WPARAM, LPARAM);
  117. // message handlers
  118. void NcCreate(LPCREATESTRUCT lpcs);
  119. LRESULT NcCalcSize(BOOL, LPNCCALCSIZE_PARAMS);
  120. void NcPaint(HRGN);
  121. LRESULT NcMouseMove(WPARAM, LONG, LONG);
  122. LRESULT NcHitTest(LONG, LONG);
  123. LRESULT NcButtonDown(UINT nMsg, WPARAM nHittest, const POINTS& pts);
  124. LRESULT NcDblClick(UINT nMsg, WPARAM nHittest, LPARAM lParam);
  125. LRESULT ButtonUp(UINT nMsg, WPARAM nHittest, const POINTS& pts);
  126. void OnCaptureLost(HWND hwndNew) {RESET_CAPTURE();}
  127. LRESULT WindowPosChanging(LPWINDOWPOS);
  128. LRESULT OnSize(WPARAM, LONG, LONG);
  129. BOOL SetPlacement(PGBPLACEMENT);
  130. BOOL SetBuddy(HWND, ULONG);
  131. BOOL SetDropState(BOOL);
  132. void SetText(LPCTSTR);
  133. int GetText(LPTSTR, int);
  134. int GetTextW(LPWSTR, int);
  135. int GetTextLength();
  136. void SetFont(HFONT);
  137. HFONT GetFont();
  138. // utility methods
  139. static void _MapWindowRect(HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow);
  140. void _MapWindowRect(HWND hwndRelative, OUT LPRECT prcWindow);
  141. HCURSOR GetHandCursor();
  142. void CalcCaptionSize();
  143. BOOL CalcClientRect(IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient);
  144. BOOL CalcWindowSizeForClient(IN OPTIONAL LPCRECT prcClient,
  145. IN OPTIONAL LPCRECT prcWindow,
  146. IN LPCRECT prcNewClient,
  147. OUT LPSIZE psizeWindow);
  148. void DoLayout(BOOL bNewBuddy = FALSE);
  149. LONG EnableNotifications(BOOL bEnable);
  150. LRESULT SendNotify(int nCode, IN OPTIONAL NMHDR* pnmh = NULL);
  151. void PostNotify(int nCode);
  152. // instance and static data
  153. HWND _hwnd;
  154. HWND _hwndBuddy;
  155. WNDPROC _pfnBuddy;
  156. ULONG _dwBuddyFlags;
  157. SIZE _sizeBuddyMargin;
  158. HFONT _hf;
  159. static ATOM _atom;
  160. LPTSTR _pszCaption;
  161. SIZE _sizeCaption;
  162. int _yDrop;
  163. BOOL _fDropped : 1,
  164. _fInLayout : 1;
  165. UINT _fCapture;
  166. UINT _fKeyboardCues;
  167. HCURSOR _hcurHand;
  168. LONG _cNotifyLocks;
  169. friend ATOM GroupButton_RegisterClass();
  170. friend HWND CreateGroupBtn(DWORD, LPCTSTR, DWORD,
  171. int x, int y, HWND hwndParent, UINT nID);
  172. };
  173. ATOM WINAPI GroupButton_RegisterClass()
  174. {
  175. WNDCLASSEX wc = {0};
  176. wc.cbSize = sizeof(wc);
  177. wc.style = CS_GLOBALCLASS;
  178. wc.lpfnWndProc = CGroupBtn::s_GroupBtnWndProc;
  179. wc.hInstance = HINST_THISDLL;
  180. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  181. wc.hbrBackground = (HBRUSH)(GROUPBTN_BKCOLOR+1);
  182. wc.lpszClassName = GROUPBUTTON_CLASS;
  183. RegisterClassEx(&wc);
  184. return (ATOM)TRUE;
  185. }
  186. CGroupBtn::CGroupBtn(HWND hwnd)
  187. : CAccessibleBase(_hwnd),
  188. _hwnd(hwnd),
  189. _hwndBuddy(NULL),
  190. _pfnBuddy(NULL),
  191. _dwBuddyFlags(GBBF_HRESIZE|GBBF_VRESIZE),
  192. _fInLayout(FALSE),
  193. _hf(NULL),
  194. _pszCaption(NULL),
  195. _fDropped(TRUE),
  196. _fKeyboardCues(0),
  197. _yDrop(0),
  198. _fCapture(0),
  199. _hcurHand(NULL),
  200. _cNotifyLocks(0)
  201. {
  202. _sizeCaption.cx = _sizeCaption.cy = 0;
  203. _sizeBuddyMargin.cx = _sizeBuddyMargin.cy = 0;
  204. }
  205. ATOM CGroupBtn::_atom = 0;
  206. CGroupBtn::~CGroupBtn()
  207. {
  208. SetFont(NULL);
  209. SetText(NULL);
  210. }
  211. // CGroupBtn IAccessible impl
  212. STDMETHODIMP CGroupBtn::get_accName(VARIANT varChild, BSTR* pbstrName)
  213. {
  214. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  215. if (NULL == pbstrName)
  216. return E_POINTER;
  217. *pbstrName = 0;
  218. int cch = GetTextLength();
  219. if ((*pbstrName = SysAllocStringLen(NULL, cch + 1)) != NULL)
  220. {
  221. GetTextW(*pbstrName, cch + 1);
  222. return S_OK;
  223. }
  224. return E_OUTOFMEMORY;
  225. }
  226. STDMETHODIMP CGroupBtn::accDoDefaultAction(VARIANT varChild)
  227. {
  228. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  229. SendNotify(NM_RETURN);
  230. return S_OK;
  231. }
  232. // CGroupBtn window impl
  233. // WM_SETTEXT handler
  234. void CGroupBtn::SetText(LPCTSTR pszText)
  235. {
  236. if (_pszCaption)
  237. {
  238. if (pszText && 0==lstrcmp(_pszCaption, pszText))
  239. return;
  240. delete [] _pszCaption;
  241. _pszCaption = NULL;
  242. }
  243. if (pszText && *pszText)
  244. {
  245. if ((_pszCaption = new TCHAR[lstrlen(pszText)+1]) != NULL)
  246. lstrcpy(_pszCaption, pszText);
  247. }
  248. if (IsWindow(_hwnd))
  249. CalcCaptionSize();
  250. }
  251. // WM_GETTEXT handler
  252. int CGroupBtn::GetText(LPTSTR pszText, int cchText)
  253. {
  254. int cch = 0;
  255. if (pszText && cchText > 0)
  256. {
  257. *pszText = 0;
  258. if (_pszCaption && lstrcpyn(pszText, _pszCaption, cchText))
  259. cch = min(lstrlen(_pszCaption), cchText);
  260. }
  261. return cch;
  262. }
  263. int CGroupBtn::GetTextW(LPWSTR pwszText, int cchText)
  264. {
  265. #ifdef UNICODE
  266. return GetText(pwszText, cchText);
  267. #else //UNICODE
  268. int cchRet = 0;
  269. LPSTR pszText = new CHAR[cchText];
  270. if (pszText)
  271. {
  272. cchRet = GetText(pszText, cchText);
  273. if (cchRet)
  274. {
  275. SHAnsiToUnicode(pszText, pwszText, cchText);
  276. }
  277. delete [] pszText;
  278. }
  279. return cchRet;
  280. #endif //UNICODE
  281. }
  282. // WM_GETTEXTLENGTH handler
  283. int CGroupBtn::GetTextLength()
  284. {
  285. return (_pszCaption && *_pszCaption) ? lstrlen(_pszCaption) : 0 ;
  286. }
  287. // WM_SETFONT handler
  288. void CGroupBtn::SetFont(HFONT hf)
  289. {
  290. if (_hf)
  291. {
  292. DeleteObject(_hf);
  293. _hf = NULL;
  294. }
  295. _hf = hf;
  296. }
  297. // WM_GETFONT handler
  298. HFONT CGroupBtn::GetFont()
  299. {
  300. if (_hf == NULL)
  301. {
  302. // if we don't have a font, use the parent's font
  303. HFONT hfParent = (HFONT)SendMessage(GetParent(_hwnd), WM_GETFONT, 0, 0);
  304. if (hfParent)
  305. {
  306. LOGFONT lf;
  307. if (GetObject(hfParent, sizeof(LOGFONT), &lf) >0)
  308. _hf = CreateFontIndirect(&lf);
  309. }
  310. }
  311. return _hf;
  312. }
  313. // Hand cursor load
  314. HCURSOR CGroupBtn::GetHandCursor()
  315. {
  316. if (!_hcurHand)
  317. _hcurHand = LoadCursor(NULL, IDC_HAND);
  318. return _hcurHand;
  319. }
  320. // Retrieves the window rect in relative coords.
  321. void CGroupBtn::_MapWindowRect(HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow)
  322. {
  323. ASSERT(IsWindow(hwnd));
  324. GetWindowRect(hwnd, prcWindow);
  325. MapWindowPoints(HWND_DESKTOP, hwndRelative, (LPPOINT)prcWindow, 2);
  326. }
  327. // Retrieves the window rect in relative coords.
  328. inline void CGroupBtn::_MapWindowRect(HWND hwndRelative, OUT LPRECT prcWindow)
  329. {
  330. _MapWindowRect(_hwnd, hwndRelative, prcWindow);
  331. }
  332. // Caches the size of the caption 'bar'.
  333. void CGroupBtn::CalcCaptionSize()
  334. {
  335. SIZE sizeCaption = {0,0};
  336. LPCTSTR pszCaption = (_pszCaption && *_pszCaption) ? _pszCaption : TEXT("|");
  337. HDC hdc;
  338. // compute caption size based on window text:
  339. if ((hdc = GetDC(_hwnd)))
  340. {
  341. HFONT hf = GetFont(),
  342. hfPrev = (HFONT)SelectObject(hdc, hf);
  343. if (GetTextExtentPoint32(hdc, pszCaption, lstrlen(pszCaption),
  344. &sizeCaption))
  345. sizeCaption.cy += CAPTION_VPADDING; // add some vertical padding
  346. SelectObject(hdc, hfPrev);
  347. ReleaseDC(_hwnd, hdc);
  348. }
  349. _sizeCaption = sizeCaption;
  350. }
  351. // Computes the size and position of the client area
  352. BOOL CGroupBtn::CalcClientRect(IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient)
  353. {
  354. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  355. RECT rcWindow;
  356. if (!prcWindow)
  357. {
  358. // Get parent-relative coords
  359. _MapWindowRect(GetParent(_hwnd), &rcWindow);
  360. prcWindow = &rcWindow;
  361. }
  362. *prcClient = *prcWindow;
  363. // compute client rectangle:
  364. // allow for border
  365. if (dwStyle & WS_BORDER)
  366. InflateRect(prcClient, -1, -1);
  367. // allow for caption 'bar'
  368. prcClient->top += _sizeCaption.cy;
  369. // Normalize for NULL rect.
  370. if (RECTWIDTH(*prcWindow) <=0)
  371. prcClient->left = prcClient->right = prcWindow->left;
  372. if (RECTHEIGHT(*prcWindow) <=0)
  373. prcClient->bottom = prcClient->top = prcWindow->top;
  374. return TRUE;
  375. }
  376. BOOL CGroupBtn::CalcWindowSizeForClient(
  377. IN OPTIONAL LPCRECT prcClient,
  378. IN OPTIONAL LPCRECT prcWindow,
  379. IN LPCRECT prcNewClient,
  380. OUT LPSIZE psizeWindow)
  381. {
  382. if (!(prcNewClient && psizeWindow))
  383. {
  384. ASSERT(FALSE);
  385. return FALSE;
  386. }
  387. RECT rcWindow, rcClient;
  388. if (NULL == prcWindow)
  389. {
  390. GetWindowRect(_hwnd, &rcWindow);
  391. prcWindow = &rcWindow;
  392. }
  393. if (NULL == prcClient)
  394. {
  395. GetClientRect(_hwnd, &rcClient);
  396. prcClient = &rcClient;
  397. }
  398. SIZE sizeDelta;
  399. sizeDelta.cx = RECTWIDTH(*prcWindow) - RECTWIDTH(*prcClient);
  400. sizeDelta.cy = RECTHEIGHT(*prcWindow) - RECTHEIGHT(*prcClient);
  401. psizeWindow->cx = RECTWIDTH(*prcNewClient) + sizeDelta.cx;
  402. psizeWindow->cy = RECTHEIGHT(*prcNewClient) + sizeDelta.cy;
  403. return TRUE;
  404. }
  405. // WM_WINDOWPOSCHANGING handler
  406. LRESULT CGroupBtn::WindowPosChanging(LPWINDOWPOS pwp)
  407. {
  408. if (pwp->flags & SWP_NOSIZE)
  409. return DefWindowProc(_hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pwp);
  410. // disallow sizing in buddy slave dimension(s).
  411. if (IsWindow(_hwndBuddy) && _dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE) && !_fInLayout)
  412. {
  413. RECT rcWindow, rcClient;
  414. BOOL fResizeBuddy = FALSE;
  415. GetWindowRect(_hwnd, &rcWindow);
  416. GetClientRect(_hwnd, &rcClient);
  417. // Prepare a buddy size data block
  418. GBNQUERYBUDDYSIZE qbs;
  419. qbs.cy = pwp->cy - (RECTHEIGHT(rcWindow) - RECTHEIGHT(rcClient));
  420. qbs.cx = pwp->cx - (RECTWIDTH(rcWindow) - RECTWIDTH(rcClient));
  421. if (_dwBuddyFlags & GBBF_HSLAVE) // prevent external horz resizing
  422. {
  423. pwp->cx = RECTWIDTH(rcWindow);
  424. // If we're being resized in the vert dir, query for
  425. // optimal buddy width for this height and adjust
  426. if (_dwBuddyFlags & GBBF_VRESIZE && RECTHEIGHT(rcWindow) != pwp->cy)
  427. {
  428. if (SendNotify(GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs) && qbs.cx >= 0)
  429. {
  430. // if the owner wants the buddy width to change, do it now.
  431. LONG cxNew = qbs.cx + (RECTWIDTH(rcWindow) - RECTWIDTH(rcClient));
  432. fResizeBuddy = cxNew != pwp->cx;
  433. pwp->cx = cxNew;
  434. }
  435. }
  436. }
  437. if (_dwBuddyFlags & GBBF_VSLAVE) // prevent external vert resizing
  438. {
  439. pwp->cy = RECTHEIGHT(rcWindow);
  440. // If we're being resized in the horz dir, query for
  441. // optimal buddy height for this horizontal and adjust
  442. if (_dwBuddyFlags & GBBF_HRESIZE && RECTWIDTH(rcWindow) != pwp->cx)
  443. {
  444. if (SendNotify(GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs) && qbs.cy >= 0)
  445. {
  446. LONG cyNew = qbs.cy + (RECTHEIGHT(rcWindow) - RECTHEIGHT(rcClient));
  447. fResizeBuddy = cyNew != pwp->cy;
  448. pwp->cy = cyNew;
  449. }
  450. }
  451. }
  452. if (fResizeBuddy)
  453. {
  454. _fInLayout = TRUE;
  455. SetWindowPos(_hwndBuddy, NULL, 0, 0, qbs.cx, qbs.cy,
  456. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  457. _fInLayout = FALSE;
  458. }
  459. }
  460. // enforce minimum height:
  461. if (pwp->cy < _sizeCaption.cy)
  462. pwp->cy = _sizeCaption.cy;
  463. return 0;
  464. }
  465. LRESULT CGroupBtn::OnSize(WPARAM flags, LONG cx, LONG cy)
  466. {
  467. DoLayout();
  468. return 0;
  469. }
  470. void CGroupBtn::DoLayout(BOOL bNewBuddy)
  471. {
  472. if (!_fInLayout && IsWindow(_hwndBuddy))
  473. {
  474. RECT rcWindow, rcThis, rcBuddy;
  475. DWORD dwSwpBuddy = SWP_NOACTIVATE,
  476. dwSwpThis = SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE;
  477. BOOL fReposThis = FALSE;
  478. SIZE sizeNew;
  479. GetClientRect(_hwnd, &rcThis);
  480. GetWindowRect(_hwnd, &rcWindow);
  481. // get rectangles in parent coords
  482. MapWindowPoints(_hwnd, GetParent(_hwnd), (LPPOINT)&rcThis, POINTSPERRECT);
  483. MapWindowPoints(HWND_DESKTOP, GetParent(_hwnd), (LPPOINT)&rcWindow, POINTSPERRECT);
  484. _MapWindowRect(_hwndBuddy, GetParent(_hwnd), &rcBuddy);
  485. // If we need to reposition ourself to the buddy,
  486. // calculate the new size now.
  487. if (_dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE))
  488. CalcWindowSizeForClient(&rcThis, &rcWindow, &rcBuddy, &sizeNew);
  489. // Resize buddy according to size.
  490. if (_dwBuddyFlags & GBBF_HRESIZE)
  491. {
  492. rcBuddy.right = rcBuddy.left + RECTWIDTH(rcThis);
  493. if (bNewBuddy && 0 == (_dwBuddyFlags & GBBF_VRESIZE))
  494. {
  495. // query height
  496. GBNQUERYBUDDYSIZE qbs;
  497. qbs.cx = RECTWIDTH(rcThis);
  498. qbs.cy = -1;
  499. if (SendNotify(GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs) && qbs.cy >= 0)
  500. rcBuddy.bottom = rcBuddy.top + qbs.cy;
  501. }
  502. }
  503. else if (_dwBuddyFlags & GBBF_HSLAVE)
  504. {
  505. rcWindow.right = rcWindow.left + sizeNew.cx;
  506. fReposThis = TRUE;
  507. }
  508. if (_dwBuddyFlags & GBBF_VRESIZE)
  509. {
  510. rcBuddy.bottom = rcBuddy.top + RECTHEIGHT(rcThis);
  511. if (bNewBuddy && 0 == (_dwBuddyFlags & GBBF_HRESIZE))
  512. {
  513. // query width
  514. GBNQUERYBUDDYSIZE qbs;
  515. qbs.cx = -1;
  516. qbs.cy = RECTHEIGHT(rcThis);
  517. if (SendNotify(GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs) && qbs.cx >= 0)
  518. rcBuddy.right = rcBuddy.left + qbs.cx;
  519. }
  520. }
  521. else if (_dwBuddyFlags & GBBF_VSLAVE)
  522. {
  523. rcWindow.bottom = rcWindow.top + sizeNew.cy;
  524. fReposThis = TRUE;
  525. }
  526. if (_dwBuddyFlags & GBBF_HSCROLL)
  527. {
  528. /* not implemented */
  529. }
  530. if (_dwBuddyFlags & GBBF_VSCROLL)
  531. {
  532. /* not implemented */
  533. }
  534. // reposition ourself and update our client rect.
  535. if (fReposThis)
  536. {
  537. _fInLayout = TRUE;
  538. SetWindowPos(_hwnd, NULL, 0, 0,
  539. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow), dwSwpThis);
  540. _fInLayout = FALSE;
  541. GetClientRect(_hwnd, &rcThis);
  542. MapWindowPoints(_hwnd, GetParent(_hwnd), (LPPOINT)&rcThis, POINTSPERRECT);
  543. }
  544. // slide buddy into client area and reposition
  545. OffsetRect(&rcBuddy, rcThis.left - rcBuddy.left, rcThis.top - rcBuddy.top);
  546. _fInLayout = TRUE;
  547. SetWindowPos(_hwndBuddy, _hwnd, rcBuddy.left, rcBuddy.top,
  548. RECTWIDTH(rcBuddy), RECTHEIGHT(rcBuddy), dwSwpBuddy);
  549. _fInLayout = FALSE;
  550. }
  551. }
  552. // GBM_SETPLACEMENT handler
  553. BOOL CGroupBtn::SetPlacement(PGBPLACEMENT pgbp)
  554. {
  555. RECT rcWindow, rcClient;
  556. SIZE sizeDelta = {0};
  557. DWORD dwFlags = SWP_NOZORDER|SWP_NOACTIVATE;
  558. _MapWindowRect(GetParent(_hwnd), &rcWindow);
  559. CalcClientRect(&rcWindow, &rcClient);
  560. // establish whether we need to resize
  561. if ((pgbp->x < 0 || pgbp->x == rcWindow.left) &&
  562. (pgbp->y < 0 || pgbp->y == rcWindow.top))
  563. dwFlags |= SWP_NOMOVE;
  564. // compute horizontal placement
  565. if (pgbp->x >= 0) // fixed horz origin requested
  566. OffsetRect(&rcWindow, pgbp->x - rcWindow.left, 0);
  567. if (pgbp->cx >= 0) // fixed width requested
  568. rcWindow.right = rcWindow.left + pgbp->cx;
  569. else
  570. {
  571. if (pgbp->cxBuddy >= 0) // client width requested
  572. sizeDelta.cx = pgbp->cxBuddy - RECTWIDTH(rcClient);
  573. rcWindow.right += sizeDelta.cx;
  574. }
  575. // compute vertical placement
  576. if (pgbp->y >= 0) // fixed vert origin requested
  577. OffsetRect(&rcWindow, 0, pgbp->y - rcWindow.top);
  578. if (pgbp->cy >= 0) // fixed height requested
  579. rcWindow.bottom = rcWindow.top + pgbp->cy;
  580. else
  581. {
  582. if (pgbp->cyBuddy >= 0) // client height requested
  583. sizeDelta.cy = pgbp->cyBuddy - RECTHEIGHT(rcClient);
  584. rcWindow.bottom += sizeDelta.cy;
  585. }
  586. if (pgbp->hdwp && (-1 != (LONG_PTR)pgbp->hdwp))
  587. DeferWindowPos(pgbp->hdwp, _hwnd, NULL, rcWindow.left, rcWindow.top,
  588. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow),
  589. dwFlags);
  590. else
  591. SetWindowPos(_hwnd, NULL, rcWindow.left, rcWindow.top,
  592. RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow),
  593. dwFlags);
  594. // stuff resulting rects
  595. pgbp->rcWindow = rcWindow;
  596. return CalcClientRect(&rcWindow, &pgbp->rcBuddy);
  597. }
  598. BOOL CGroupBtn::SetBuddy(HWND hwnd, ULONG dwFlags)
  599. {
  600. // If we already have a buddy, unhook ourselves
  601. //
  602. if (_hwndBuddy)
  603. {
  604. if (IsWindow(_hwndBuddy) && _pfnBuddy)
  605. {
  606. SetWindowLongPtr(_hwndBuddy, GWLP_USERDATA, (LONG_PTR)NULL);
  607. SetWindowLongPtr(_hwndBuddy, GWLP_WNDPROC, (LONG_PTR)_pfnBuddy);
  608. }
  609. _hwndBuddy = NULL;
  610. _pfnBuddy = NULL;
  611. }
  612. // Handle an invalid window...
  613. if (!IsWindow(hwnd))
  614. hwnd = NULL;
  615. // If we're being buddy'd with a window, hook it
  616. //
  617. if (hwnd)
  618. {
  619. if (dwFlags & (GBBF_HSLAVE|GBBF_VSLAVE))
  620. {
  621. // subclass the buddy
  622. _pfnBuddy = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)s_BuddyProc);
  623. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
  624. }
  625. _hwndBuddy = hwnd;
  626. _dwBuddyFlags = dwFlags;
  627. DoLayout(TRUE);
  628. }
  629. return TRUE;
  630. }
  631. BOOL CGroupBtn::SetDropState(BOOL bDropped)
  632. {
  633. _fDropped = bDropped;
  634. return TRUE;
  635. }
  636. // WM_NCCREATE handler
  637. void CGroupBtn::NcCreate(LPCREATESTRUCT lpcs)
  638. {
  639. // assign user data
  640. SetWindowLongPtr(_hwnd, GWLP_USERDATA, (LONG_PTR)this);
  641. // enforce window style bits
  642. lpcs->style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
  643. lpcs->dwExStyle |= WS_EX_TRANSPARENT;
  644. SetWindowLong(_hwnd, GWL_STYLE, lpcs->style);
  645. SetWindowLong(_hwnd, GWL_EXSTYLE, lpcs->dwExStyle);
  646. // enforce min height
  647. SetText(lpcs->lpszName);
  648. if (lpcs->cy < _sizeCaption.cy)
  649. {
  650. lpcs->cy = _sizeCaption.cy;
  651. SetWindowPos(_hwnd, NULL, 0,0, lpcs->cx, lpcs->cy,
  652. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  653. }
  654. }
  655. // WM_NCCALCSIZE handler
  656. LRESULT CGroupBtn::NcCalcSize(BOOL fCalcValidRects, LPNCCALCSIZE_PARAMS pnccs)
  657. {
  658. LRESULT lRet = FALSE;
  659. RECT rcClient;
  660. if (fCalcValidRects && CalcClientRect(&pnccs->rgrc[0], &rcClient))
  661. {
  662. pnccs->rgrc[1] = pnccs->rgrc[2];
  663. pnccs->rgrc[0] = pnccs->rgrc[2] = rcClient;
  664. return WVR_VALIDRECTS;
  665. }
  666. return lRet;
  667. }
  668. // WM_NCPAINT handler
  669. void CGroupBtn::NcPaint(HRGN hrgn)
  670. {
  671. RECT rcWindow;
  672. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  673. HDC hdc;
  674. GetWindowRect(_hwnd, &rcWindow);
  675. OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
  676. if ((hdc = GetWindowDC(_hwnd)) != NULL)
  677. {
  678. if (dwStyle & WS_BORDER)
  679. {
  680. HBRUSH hbr = CreateSolidBrush(COLOR_WINDOWFRAME);
  681. if (hbr)
  682. {
  683. FrameRect(hdc, &rcWindow, hbr);
  684. DeleteObject(hbr);
  685. }
  686. }
  687. rcWindow.bottom = rcWindow.top + _sizeCaption.cy;
  688. SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  689. SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  690. ExtTextOut(hdc, rcWindow.left, rcWindow.top,
  691. ETO_OPAQUE, &rcWindow, NULL, 0, NULL);
  692. InflateRect(&rcWindow, -CAPTION_HPADDING, -(CAPTION_VPADDING/2));
  693. HFONT hfPrev = (HFONT)SelectObject(hdc, GetFont());
  694. ExtTextOut(hdc, rcWindow.left, rcWindow.top,
  695. ETO_OPAQUE, &rcWindow, _pszCaption,
  696. _pszCaption ? lstrlen(_pszCaption) : 0, NULL);
  697. SelectObject(hdc, hfPrev);
  698. if (0 == (_fKeyboardCues & UISF_HIDEFOCUS))
  699. {
  700. if (GetFocus() == _hwnd)
  701. {
  702. rcWindow.right = rcWindow.left + _sizeCaption.cx + 1;
  703. InflateRect(&rcWindow, 1, 0);
  704. DrawFocusRect(hdc, &rcWindow);
  705. }
  706. }
  707. ReleaseDC(_hwnd, hdc);
  708. }
  709. }
  710. // WM_NCMOUSEMOVE handler
  711. LRESULT CGroupBtn::NcMouseMove(WPARAM nHittest, LONG x, LONG y)
  712. {
  713. if (HTCAPTION == nHittest)
  714. {
  715. RECT rc;
  716. POINT pt;
  717. GetWindowRect(_hwnd, &rc);
  718. rc.bottom = rc.top + _sizeCaption.cy;
  719. rc.right = rc.left + _sizeCaption.cx;
  720. InflateRect(&rc, 0, -(CAPTION_VPADDING/2));
  721. pt.x = x;
  722. pt.y = y;
  723. if (PtInRect(&rc, pt))
  724. {
  725. HCURSOR hc = GetHandCursor();
  726. if (hc != NULL)
  727. {
  728. SetCursor(hc);
  729. return 0;
  730. }
  731. }
  732. }
  733. return DefWindowProc(_hwnd, WM_NCMOUSEMOVE, nHittest, MAKELPARAM(x, y));
  734. }
  735. // WM_NCHITTEST handler
  736. LRESULT CGroupBtn::NcHitTest(LONG x, LONG y)
  737. {
  738. POINT pt;
  739. RECT rc, rcClient;
  740. DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  741. pt.x = x;
  742. pt.y = y;
  743. GetWindowRect(_hwnd, &rc);
  744. CalcClientRect(&rc, &rcClient);
  745. if (PtInRect(&rcClient, pt))
  746. return HTTRANSPARENT;
  747. if (PtInRect(&rc, pt))
  748. {
  749. if (dwStyle & WS_BORDER)
  750. {
  751. if (pt.x == rc.left ||
  752. pt.x == rc.right ||
  753. pt.y == rc.bottom)
  754. return HTBORDER;
  755. }
  756. return HTCAPTION;
  757. }
  758. return HTNOWHERE;
  759. }
  760. LRESULT CGroupBtn::NcButtonDown(UINT nMsg, WPARAM nHittest, const POINTS& pts)
  761. {
  762. LRESULT lRet = 0;
  763. if (HTCAPTION == nHittest)
  764. {
  765. SetCursor(GetHandCursor());
  766. MODIFY_CAPTURE(CF_SETCAPTURE, 0);
  767. if (GetFocus() != _hwnd)
  768. {
  769. MODIFY_CAPTURE(CF_SETFOCUS, 0);
  770. EnableNotifications(FALSE); // so the host doesn't reposition the link.
  771. SetFocus(_hwnd);
  772. EnableNotifications(TRUE);
  773. }
  774. SetCapture(_hwnd);
  775. }
  776. else
  777. lRet = DefWindowProc(_hwnd, nMsg, nHittest, MAKELONG(pts.x, pts.y));
  778. return lRet;
  779. }
  780. LRESULT CGroupBtn::ButtonUp(UINT nMsg, WPARAM nHittest, const POINTS& pts)
  781. {
  782. if (TEST_CAPTURE(CF_SETCAPTURE))
  783. {
  784. ReleaseCapture();
  785. MODIFY_CAPTURE(0, CF_SETCAPTURE);
  786. POINT ptScrn;
  787. ptScrn.x = pts.x;
  788. ptScrn.y = pts.y;
  789. MapWindowPoints(_hwnd, HWND_DESKTOP, &ptScrn, 1);
  790. LRESULT nHittest = SendMessage(_hwnd, WM_NCHITTEST, 0, MAKELONG(ptScrn.x, ptScrn.y));
  791. if (HTCAPTION == nHittest)
  792. {
  793. switch (nMsg)
  794. {
  795. case WM_LBUTTONUP:
  796. SendNotify(NM_CLICK);
  797. break;
  798. case WM_RBUTTONUP:
  799. SendNotify(NM_RCLICK);
  800. break;
  801. }
  802. }
  803. }
  804. if (TEST_CAPTURE(CF_SETFOCUS))
  805. {
  806. MODIFY_CAPTURE(0, CF_SETFOCUS);
  807. if (GetFocus() == _hwnd) // if we still have the focus...
  808. SendNotify(NM_SETFOCUS);
  809. }
  810. return 0;
  811. }
  812. // Non-client mouse click/dblclk handler
  813. LRESULT CGroupBtn::NcDblClick(UINT nMsg, WPARAM nHittest, LPARAM lParam)
  814. {
  815. LRESULT lRet = 0;
  816. if (HTCAPTION == nHittest)
  817. {
  818. SetFocus(_hwnd);
  819. lRet = DefWindowProc(_hwnd, nMsg, HTCLIENT, lParam);
  820. switch (nMsg)
  821. {
  822. case WM_NCLBUTTONDBLCLK:
  823. SendNotify(NM_DBLCLK);
  824. break;
  825. case WM_NCRBUTTONDBLCLK:
  826. SendNotify(NM_RDBLCLK);
  827. break;
  828. }
  829. }
  830. else
  831. lRet = DefWindowProc(_hwnd, nMsg, nHittest, lParam);
  832. return lRet;
  833. }
  834. LONG CGroupBtn::EnableNotifications(BOOL bEnable)
  835. {
  836. if (bEnable)
  837. {
  838. if (_cNotifyLocks > 0)
  839. _cNotifyLocks--;
  840. }
  841. else
  842. _cNotifyLocks++;
  843. return _cNotifyLocks;
  844. }
  845. // WM_NOTIFY transmit helper
  846. LRESULT CGroupBtn::SendNotify(int nCode, IN OPTIONAL NMHDR* pnmh)
  847. {
  848. if (0 == _cNotifyLocks)
  849. {
  850. NMHDR hdr;
  851. if (NULL == pnmh)
  852. pnmh = &hdr;
  853. pnmh->hwndFrom = _hwnd;
  854. pnmh->idFrom = GetDlgCtrlID(_hwnd);
  855. pnmh->code = nCode;
  856. return SendMessage(GetParent(_hwnd), WM_NOTIFY, hdr.idFrom, (LPARAM)pnmh);
  857. }
  858. return 0;
  859. }
  860. // WM_NOTIFY transmit helper
  861. void CGroupBtn::PostNotify(int nCode)
  862. {
  863. if (0 == _cNotifyLocks)
  864. PostMessage(_hwnd, GBM_SENDNOTIFY, nCode, 0);
  865. }
  866. LRESULT CALLBACK CGroupBtn::s_GroupBtnWndProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  867. {
  868. CGroupBtn *pThis = (CGroupBtn *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
  869. if (!pThis && (WM_NCCREATE == wMsg))
  870. {
  871. pThis = new CGroupBtn(hDlg);
  872. SetWindowLongPtr(hDlg, GWLP_USERDATA, (LPARAM)pThis);
  873. }
  874. if (pThis)
  875. return pThis->WndProc(hDlg, wMsg, wParam, lParam);
  876. return DefWindowProc(hDlg, wMsg, wParam, lParam);
  877. }
  878. LRESULT CGroupBtn::WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  879. {
  880. LRESULT lRet = 0;
  881. switch (nMsg)
  882. {
  883. case WM_NCHITTEST:
  884. {
  885. POINTS pts = MAKEPOINTS(lParam);
  886. return NcHitTest(pts.x, pts.y);
  887. }
  888. case WM_NCMOUSEMOVE:
  889. {
  890. POINTS pts = MAKEPOINTS(lParam);
  891. return NcMouseMove(wParam, pts.x, pts.y);
  892. }
  893. case WM_NCCALCSIZE:
  894. return NcCalcSize((BOOL)wParam, (LPNCCALCSIZE_PARAMS)lParam);
  895. case WM_NCPAINT:
  896. NcPaint((HRGN)wParam);
  897. return 0;
  898. case WM_WINDOWPOSCHANGING:
  899. return WindowPosChanging((LPWINDOWPOS)lParam);
  900. case WM_SIZE:
  901. {
  902. POINTS pts = MAKEPOINTS(lParam);
  903. return OnSize(wParam, pts.x, pts.y);
  904. }
  905. case WM_DESTROY:
  906. if (IsWindow(_hwndBuddy))
  907. DestroyWindow(_hwndBuddy);
  908. break;
  909. case WM_ERASEBKGND:
  910. return TRUE; // transparent: no erase bkgnd
  911. case WM_NCLBUTTONDOWN:
  912. case WM_NCRBUTTONDOWN:
  913. {
  914. POINTS pts = MAKEPOINTS(lParam);
  915. return NcButtonDown(nMsg, wParam, pts);
  916. }
  917. case WM_LBUTTONUP:
  918. case WM_RBUTTONUP:
  919. {
  920. POINTS pts = MAKEPOINTS(lParam);
  921. return ButtonUp(nMsg, wParam, pts);
  922. }
  923. case WM_NCLBUTTONDBLCLK:
  924. case WM_NCRBUTTONDBLCLK:
  925. return NcDblClick(nMsg, wParam, lParam);
  926. case WM_SHOWWINDOW:
  927. if (IsWindow(_hwndBuddy))
  928. ShowWindow(_hwndBuddy, wParam ? SW_SHOW : SW_HIDE);
  929. break;
  930. case WM_SETTEXT:
  931. SetText((LPCTSTR)lParam);
  932. return TRUE;
  933. case WM_GETTEXT:
  934. return GetText((LPTSTR)lParam, (int)wParam);
  935. case WM_SETFONT:
  936. SetFont((HFONT)wParam);
  937. if (lParam /* fRedraw */)
  938. InvalidateRect(hwnd, NULL, TRUE);
  939. break;
  940. case WM_CAPTURECHANGED:
  941. if (lParam /* NULL if we called ReleaseCapture() */)
  942. OnCaptureLost((HWND)lParam);
  943. break;
  944. case WM_SETFOCUS:
  945. NcPaint((HRGN)1);
  946. SendNotify(NM_SETFOCUS);
  947. break;
  948. case WM_KILLFOCUS:
  949. NcPaint((HRGN)1);
  950. SendNotify(NM_KILLFOCUS);
  951. break;
  952. case WM_GETDLGCODE:
  953. {
  954. MSG* pmsg;
  955. lRet = DLGC_BUTTON|DLGC_UNDEFPUSHBUTTON;
  956. if ((pmsg = (MSG*)lParam))
  957. {
  958. if ((WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message))
  959. {
  960. switch (pmsg->wParam)
  961. {
  962. case VK_RETURN:
  963. case VK_SPACE:
  964. lRet |= DLGC_WANTALLKEYS;
  965. break;
  966. }
  967. }
  968. else if (WM_CHAR == pmsg->message && VK_RETURN == pmsg->wParam)
  969. {
  970. // Eat VK_RETURN WM_CHARs; we don't want
  971. // Dialog manager to beep when IsDialogMessage gets it.
  972. return lRet |= DLGC_WANTMESSAGE;
  973. }
  974. }
  975. return lRet;
  976. }
  977. case WM_KEYDOWN:
  978. case WM_KEYUP:
  979. case WM_CHAR:
  980. switch (wParam)
  981. {
  982. case VK_RETURN:
  983. case VK_SPACE:
  984. if (WM_KEYDOWN == nMsg)
  985. SendNotify(NM_RETURN);
  986. return 0;
  987. }
  988. break;
  989. case WM_UPDATEUISTATE:
  990. if (_HandleWM_UPDATEUISTATE(wParam, lParam, &_fKeyboardCues))
  991. SendMessage(hwnd, WM_NCPAINT, 1, 0);
  992. break;
  993. case GBM_SETPLACEMENT:
  994. if (lParam)
  995. return SetPlacement((PGBPLACEMENT)lParam);
  996. return 0;
  997. case GBM_SETDROPSTATE: // WPARAM: BOOL fDropped, LPARAM: n/a, return: BOOL
  998. return 0;
  999. case GBM_GETDROPSTATE: // WPARAM: n/a, LPARAM: n/a, return: BOOL fDropped
  1000. return 0;
  1001. case GBM_SENDNOTIFY:
  1002. SendNotify((int)wParam);
  1003. break;
  1004. case WM_NCCREATE:
  1005. NcCreate((LPCREATESTRUCT)lParam);
  1006. break;
  1007. case WM_NCDESTROY:
  1008. lRet = DefWindowProc(hwnd, nMsg, wParam, lParam);
  1009. SetWindowPtr(hwnd, GWLP_USERDATA, NULL);
  1010. _hwnd = NULL;
  1011. Release();
  1012. return lRet;
  1013. case WM_CREATE:
  1014. _InitializeUISTATE(hwnd, &_fKeyboardCues);
  1015. SetText(((LPCREATESTRUCT)lParam)->lpszName);
  1016. break;
  1017. case GBM_SETBUDDY: // WPARAM: HWND hwndBuddy, LPARAM: MAKELPARAM(cxMargin, cyMargin), return: BOOL
  1018. return SetBuddy((HWND)wParam, (ULONG)lParam);
  1019. case GBM_GETBUDDY: // WPARAM: n/a, LPARAM: n/a, return: HWND
  1020. return (LRESULT)_hwndBuddy;
  1021. default:
  1022. // oleacc defs thunked for WINVER < 0x0500
  1023. if ((WM_GETOBJECT == nMsg) && (OBJID_CLIENT == lParam || OBJID_TITLEBAR == lParam))
  1024. return LresultFromObject(IID_IAccessible, wParam, SAFECAST(this, IAccessible*));
  1025. break;
  1026. }
  1027. return DefWindowProc(hwnd, nMsg, wParam, lParam);
  1028. }
  1029. LRESULT CGroupBtn::s_BuddyProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
  1030. {
  1031. CGroupBtn *pBtn = (CGroupBtn*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1032. switch (nMsg)
  1033. {
  1034. case WM_SIZE:
  1035. {
  1036. LRESULT lRet = CallWindowProc(pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam);
  1037. if (!pBtn->_fInLayout)
  1038. pBtn->DoLayout();
  1039. return lRet;
  1040. }
  1041. case WM_DESTROY:
  1042. {
  1043. WNDPROC pfn = pBtn->_pfnBuddy;
  1044. pBtn->SetBuddy(NULL, 0);
  1045. return CallWindowProc(pfn, hwnd, nMsg, wParam, lParam);
  1046. }
  1047. }
  1048. return pBtn->_pfnBuddy ? CallWindowProc(pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam) : 0;
  1049. }
  1050. // CAccessibleBase IUnknown impl
  1051. STDMETHODIMP CAccessibleBase::QueryInterface(REFIID riid, void** ppvObj)
  1052. {
  1053. static const QITAB qit[] =
  1054. {
  1055. QITABENT(CAccessibleBase, IDispatch),
  1056. QITABENT(CAccessibleBase, IAccessible),
  1057. QITABENT(CAccessibleBase, IOleWindow),
  1058. { 0 },
  1059. };
  1060. return QISearch(this, qit, riid, ppvObj);
  1061. }
  1062. STDMETHODIMP_(ULONG) CAccessibleBase::AddRef()
  1063. {
  1064. return InterlockedIncrement(&_cRef);
  1065. }
  1066. STDMETHODIMP_(ULONG) CAccessibleBase::Release()
  1067. {
  1068. if (InterlockedDecrement(&_cRef))
  1069. return _cRef;
  1070. delete this;
  1071. return 0;
  1072. }
  1073. // CAccessibleBase IOleWindow impl
  1074. STDMETHODIMP CAccessibleBase::GetWindow(HWND* phwnd)
  1075. {
  1076. *phwnd = _hwnd;
  1077. return IsWindow(_hwnd) ? S_OK : S_FALSE;
  1078. }
  1079. // CAccessibleBase IDispatch impl
  1080. static HRESULT _accLoadTypeInfo(ITypeInfo** ppti)
  1081. {
  1082. ITypeLib* ptl;
  1083. HRESULT hr = LoadTypeLib(L"oleacc.dll", &ptl);
  1084. if (SUCCEEDED(hr))
  1085. {
  1086. hr = ptl->GetTypeInfoOfGuid(IID_IAccessible, ppti);
  1087. ATOMICRELEASE(ptl);
  1088. }
  1089. return hr;
  1090. }
  1091. STDMETHODIMP CAccessibleBase::GetTypeInfoCount(UINT * pctinfo)
  1092. {
  1093. *pctinfo = 1;
  1094. return S_OK;
  1095. }
  1096. STDMETHODIMP CAccessibleBase::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  1097. {
  1098. HRESULT hr = E_FAIL;
  1099. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1100. return hr;
  1101. *pptinfo = _ptiAcc;
  1102. (*pptinfo)->AddRef();
  1103. return S_OK;
  1104. }
  1105. STDMETHODIMP CAccessibleBase::GetIDsOfNames(
  1106. REFIID riid,
  1107. OLECHAR** rgszNames,
  1108. UINT cNames,
  1109. LCID lcid, DISPID * rgdispid)
  1110. {
  1111. HRESULT hr = E_FAIL;
  1112. if (IID_NULL != riid && IID_IAccessible != riid)
  1113. return DISP_E_UNKNOWNINTERFACE;
  1114. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1115. return hr;
  1116. return _ptiAcc->GetIDsOfNames(rgszNames, cNames, rgdispid);
  1117. }
  1118. STDMETHODIMP CAccessibleBase::Invoke(
  1119. DISPID dispidMember,
  1120. REFIID riid,
  1121. LCID lcid,
  1122. WORD wFlags,
  1123. DISPPARAMS * pdispparams,
  1124. VARIANT * pvarResult,
  1125. EXCEPINFO * pexcepinfo,
  1126. UINT * puArgErr)
  1127. {
  1128. HRESULT hr = E_FAIL;
  1129. if (IID_NULL != riid && IID_IAccessible != riid)
  1130. return DISP_E_UNKNOWNINTERFACE;
  1131. if (NULL == _ptiAcc && FAILED((hr = _accLoadTypeInfo(&_ptiAcc))))
  1132. return hr;
  1133. return _ptiAcc->Invoke(this, dispidMember, wFlags, pdispparams,
  1134. pvarResult, pexcepinfo, puArgErr);
  1135. }
  1136. STDMETHODIMP CAccessibleBase::get_accParent(IDispatch ** ppdispParent)
  1137. {
  1138. *ppdispParent = NULL;
  1139. if (IsWindow(_hwnd))
  1140. return AccessibleObjectFromWindow(_hwnd, OBJID_WINDOW,
  1141. IID_PPV_ARG(IDispatch, ppdispParent));
  1142. return S_FALSE;
  1143. }
  1144. STDMETHODIMP CAccessibleBase::get_accChildCount(long * pcChildren)
  1145. {
  1146. *pcChildren = 0;
  1147. return S_OK;
  1148. }
  1149. STDMETHODIMP CAccessibleBase::get_accChild(VARIANT varChildIndex, IDispatch ** ppdispChild)
  1150. {
  1151. *ppdispChild = NULL;
  1152. return S_FALSE;
  1153. }
  1154. STDMETHODIMP CAccessibleBase::get_accValue(VARIANT varChild, BSTR* pbstrValue)
  1155. {
  1156. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1157. *pbstrValue = NULL;
  1158. return S_FALSE;
  1159. }
  1160. STDMETHODIMP CAccessibleBase::get_accDescription(VARIANT varChild, BSTR * pbstrDescription)
  1161. {
  1162. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1163. *pbstrDescription = NULL;
  1164. return S_FALSE;
  1165. }
  1166. STDMETHODIMP CAccessibleBase::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  1167. {
  1168. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1169. pvarRole->vt = VT_I4;
  1170. pvarRole->lVal = ROLE_SYSTEM_LINK;
  1171. return S_OK;
  1172. }
  1173. STDMETHODIMP CAccessibleBase::get_accState(VARIANT varChild, VARIANT *pvarState)
  1174. {
  1175. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1176. pvarState->vt = VT_I4;
  1177. pvarState->lVal = STATE_SYSTEM_DEFAULT ;
  1178. if (GetFocus() == _hwnd)
  1179. pvarState->lVal |= STATE_SYSTEM_FOCUSED;
  1180. else if (IsWindowEnabled(_hwnd))
  1181. pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
  1182. if (!IsWindowVisible(_hwnd))
  1183. pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
  1184. return S_OK;
  1185. }
  1186. STDMETHODIMP CAccessibleBase::get_accHelp(VARIANT varChild, BSTR* pbstrHelp)
  1187. {
  1188. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1189. *pbstrHelp = NULL;
  1190. return S_FALSE;
  1191. }
  1192. STDMETHODIMP CAccessibleBase::get_accHelpTopic(BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic)
  1193. {
  1194. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1195. *pbstrHelpFile = NULL;
  1196. *pidTopic = -1;
  1197. return S_FALSE;
  1198. }
  1199. STDMETHODIMP CAccessibleBase::get_accKeyboardShortcut(VARIANT varChild, BSTR* pbstrKeyboardShortcut)
  1200. {
  1201. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1202. *pbstrKeyboardShortcut = NULL;
  1203. return S_FALSE;
  1204. }
  1205. STDMETHODIMP CAccessibleBase::get_accFocus(VARIANT FAR * pvarFocusChild)
  1206. {
  1207. HWND hwndFocus;
  1208. if ((hwndFocus = GetFocus()) == _hwnd || IsChild(_hwnd, hwndFocus))
  1209. {
  1210. pvarFocusChild->vt = VT_I4;
  1211. pvarFocusChild->lVal = CHILDID_SELF;
  1212. return S_OK;
  1213. }
  1214. return S_FALSE;
  1215. }
  1216. STDMETHODIMP CAccessibleBase::get_accSelection(VARIANT FAR * pvarSelectedChildren)
  1217. {
  1218. return get_accFocus(pvarSelectedChildren); // implemented same as focus.
  1219. }
  1220. STDMETHODIMP CAccessibleBase::get_accDefaultAction(VARIANT varChild, BSTR* pbstrDefaultAction)
  1221. {
  1222. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1223. WCHAR wsz[128];
  1224. if (LoadStringW(HINST_THISDLL, GetDefaultActionStringID(), wsz, ARRAYSIZE(wsz)))
  1225. {
  1226. if (NULL == (*pbstrDefaultAction = SysAllocString(wsz)))
  1227. return E_OUTOFMEMORY;
  1228. return S_OK;
  1229. }
  1230. return E_FAIL;
  1231. }
  1232. STDMETHODIMP CAccessibleBase::accSelect(long flagsSelect, VARIANT varChild)
  1233. {
  1234. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1235. if (flagsSelect & SELFLAG_TAKEFOCUS)
  1236. {
  1237. SetFocus(_hwnd);
  1238. return S_OK;
  1239. }
  1240. return S_FALSE;
  1241. }
  1242. STDMETHODIMP CAccessibleBase::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  1243. {
  1244. RECT rc;
  1245. GetWindowRect(_hwnd, &rc);
  1246. *pxLeft = rc.left;
  1247. *pyTop = rc.top;
  1248. *pcxWidth = RECTWIDTH(rc);
  1249. *pcyHeight = RECTHEIGHT(rc);
  1250. varChild.vt = VT_I4;
  1251. varChild.lVal = CHILDID_SELF;
  1252. return S_OK;
  1253. }
  1254. STDMETHODIMP CAccessibleBase::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  1255. {
  1256. return S_FALSE;
  1257. }
  1258. STDMETHODIMP CAccessibleBase::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  1259. {
  1260. pvarChildAtPoint->vt = VT_I4;
  1261. pvarChildAtPoint->lVal = CHILDID_SELF;
  1262. return S_OK;
  1263. }
  1264. STDMETHODIMP CAccessibleBase::put_accName(VARIANT varChild, BSTR bstrName)
  1265. {
  1266. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1267. return S_FALSE;
  1268. }
  1269. STDMETHODIMP CAccessibleBase::put_accValue(VARIANT varChild, BSTR bstrValue)
  1270. {
  1271. VALIDATEACCCHILD(varChild, CHILDID_SELF, E_INVALIDARG);
  1272. return S_FALSE;
  1273. }
  1274. BOOL _HandleWM_UPDATEUISTATE(WPARAM wParam, LPARAM lParam, OUT UINT* puFlags)
  1275. {
  1276. UINT uFlags = *puFlags;
  1277. switch (LOWORD(wParam))
  1278. {
  1279. case UIS_CLEAR:
  1280. *puFlags &= ~(HIWORD(wParam));
  1281. break;
  1282. case UIS_SET:
  1283. *puFlags |= HIWORD(wParam);
  1284. break;
  1285. }
  1286. return uFlags != *puFlags;
  1287. }
  1288. void _InitializeUISTATE(IN HWND hwnd, IN OUT UINT* puFlags)
  1289. {
  1290. HWND hwndParent = GetParent(hwnd);
  1291. *puFlags = (UINT)SendMessage(hwndParent, WM_QUERYUISTATE, 0, 0);
  1292. }