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.

2933 lines
88 KiB

  1. #include "ctlspriv.h"
  2. #include "flat_sb.h"
  3. // Following interfaces are imported from newwsbctl.c and newsb.c. These
  4. // functions are for internal use only.
  5. void FlatSB_Internal_CalcSBStuff(WSBState *, BOOL);
  6. void FlatSB_Internal_DoScroll(WSBState *, int, int, BOOL);
  7. void FlatSB_Internal_EndScroll(WSBState *, BOOL);
  8. void FlatSB_Internal_DrawArrow(WSBState *, HDC, CONST RECT *, int, int);
  9. void FlatSB_Internal_DrawElevator(WSBState *, HDC, LPRECT, BOOL);
  10. void FlatSB_Internal_DrawGroove(WSBState *, HDC, LPRECT, BOOL);
  11. void FlatSB_Internal_DrawSize(WSBState *, HDC, int, int);
  12. void FlatSB_Internal_DrawScrollBar(WSBState *, HDC, BOOL, BOOL);
  13. void FlatSB_Internal_DrawThumb(WSBState *, BOOL);
  14. void FlatSB_Internal_DrawThumb2(WSBState *, HDC, BOOL, UINT);
  15. UINT FlatSB_Internal_GetSBFlags(WSBState *, BOOL);
  16. BOOL FlatSB_Internal_EnableScrollBar(WSBState *, int, UINT);
  17. WSBState * FlatSB_Internal_InitPwSB(HWND);
  18. void FlatSB_Internal_RedrawScrollBar(WSBState *, BOOL);
  19. void FlatSB_Internal_SBTrackInit(WSBState *, HWND, LPARAM, int, BOOL);
  20. void FlatSB_Internal_TrackBox(WSBState *, int message, WPARAM, LPARAM);
  21. void FlatSB_Internal_TrackThumb(WSBState *, int message, WPARAM, LPARAM);
  22. BOOL FlatSB_Internal_IsSizeBox(HWND);
  23. LRESULT FlatSB_Internal_SetScrollBar(WSBState *, int, LPSCROLLINFO, BOOL);
  24. LRESULT CALLBACK FlatSB_SubclassWndProc(HWND, UINT, WPARAM, LPARAM, WPARAM, ULONG_PTR);
  25. void FlatSB_Internal_NotifyWinEvent(WSBState *pWState, UINT event, LONG_PTR idChild)
  26. {
  27. MyNotifyWinEvent(event, pWState->sbHwnd,
  28. pWState->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL,
  29. idChild);
  30. }
  31. #define IsHottrackable(STYLE) ((STYLE == FSB_FLAT_MODE) || (STYLE == FSB_ENCARTA_MODE))
  32. HRESULT WINAPI UninitializeFlatSB(HWND hwnd)
  33. {
  34. SCROLLINFO hsi, vsi;
  35. WSBState * pWState;
  36. int style, vFlags, hFlags;
  37. BOOL hValid = FALSE, vValid = FALSE;
  38. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  39. if (pWState == (WSBState *)NULL)
  40. return S_FALSE;
  41. else if (pWState == WSB_UNINIT_HANDLE) {
  42. RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
  43. return S_FALSE;
  44. }
  45. if (pWState->fTracking)
  46. return E_FAIL; // Can't do this!
  47. style = pWState->style;
  48. vsi.cbSize = hsi.cbSize = sizeof(SCROLLINFO);
  49. vsi.fMask = hsi.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
  50. hValid = FlatSB_GetScrollInfo(hwnd, SB_HORZ, &hsi);
  51. hFlags = FlatSB_Internal_GetSBFlags(pWState, SB_HORZ);
  52. vValid = FlatSB_GetScrollInfo(hwnd, SB_VERT, &vsi);
  53. vFlags = FlatSB_Internal_GetSBFlags(pWState, SB_VERT);
  54. DeleteObject(pWState->hbm_Bkg);
  55. DeleteObject(pWState->hbr_Bkg);
  56. LocalFree((HLOCAL)pWState);
  57. RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
  58. if (vValid) {
  59. SetScrollInfo(hwnd, SB_VERT, &vsi, FALSE);
  60. EnableScrollBar(hwnd, SB_VERT, vFlags);
  61. }
  62. if (hValid) {
  63. SetScrollInfo(hwnd, SB_HORZ, &hsi, FALSE);
  64. EnableScrollBar(hwnd, SB_HORZ, hFlags);
  65. }
  66. SetWindowBits(hwnd, GWL_STYLE, WS_HSCROLL | WS_VSCROLL, style & (WS_HSCROLL | WS_VSCROLL));
  67. // Force the WM_NCCALCSIZE/WM_NCPAINT to be sent.
  68. CCInvalidateFrame(hwnd);
  69. return S_OK;
  70. }
  71. //
  72. // For accessibility - We keep the original USER scrollbars around and
  73. // keep USER's view of the scrollbar in sync with the flat view. This
  74. // means keeping the WS_[HV]SCROLL styles on the window, forwarding
  75. // all scrollbar APIs into USER, etc. That way, when OLEACC asks USER
  76. // for the scrollbar state, USER returns values that match the flat_sb
  77. // values.
  78. //
  79. // Even though the styles are enabled, the UI isn't affected since we
  80. // take over all nonclient painting and hit-testing so USER never gets
  81. // a chance to paint or hit-test the scrollbars that we took over.
  82. //
  83. BOOL WINAPI InitializeFlatSB(HWND hwnd)
  84. {
  85. int newStyle, style;
  86. SCROLLINFO hsi, vsi, siTmp;
  87. WSBState * pWState;
  88. BOOL hValid = FALSE, vValid = FALSE;
  89. style = GetWindowLong(hwnd, GWL_STYLE);
  90. siTmp.cbSize = vsi.cbSize = hsi.cbSize = sizeof(SCROLLINFO);
  91. vsi.fMask = hsi.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
  92. if (style & WS_HSCROLL)
  93. hValid = GetScrollInfo(hwnd, SB_HORZ, &hsi);
  94. if (style & WS_VSCROLL)
  95. vValid = GetScrollInfo(hwnd, SB_VERT, &vsi);
  96. newStyle = style & (WS_VSCROLL | WS_HSCROLL);
  97. style &= ~(WS_VSCROLL | WS_HSCROLL);
  98. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  99. if (!vValid && !hValid) {
  100. if (NULL == pWState) {
  101. if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)WSB_UNINIT_HANDLE))
  102. return FALSE;
  103. } else {
  104. // It seems to me unreasonable to do nothing while the caller wants
  105. // to init again the flat SB we are already using.
  106. }
  107. return TRUE;
  108. }
  109. if ((NULL == pWState) || (WSB_UNINIT_HANDLE == pWState)) {
  110. pWState = FlatSB_Internal_InitPwSB(hwnd);
  111. if ((WSBState *)NULL == pWState)
  112. return FALSE;
  113. if (!SetWindowSubclass(hwnd,FlatSB_SubclassWndProc, 0,(ULONG_PTR)pWState)) {
  114. DeleteObject(pWState->hbm_Bkg);
  115. DeleteObject(pWState->hbr_Bkg);
  116. LocalFree((HLOCAL)pWState);
  117. return FALSE;
  118. }
  119. }
  120. pWState->style = newStyle;
  121. if (hValid)
  122. FlatSB_Internal_SetScrollBar(pWState, SB_HORZ, &hsi, FALSE);
  123. if (vValid)
  124. FlatSB_Internal_SetScrollBar(pWState, SB_VERT, &vsi, FALSE);
  125. // Force the WM_NCCALCSIZE/WM_NCPAINT to be sent.
  126. CCInvalidateFrame(hwnd);
  127. return TRUE;
  128. }
  129. LRESULT FlatSB_NCDestroyProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  130. {
  131. ASSERT(pWState);
  132. if (pWState != WSB_UNINIT_HANDLE) {
  133. DeleteObject(pWState->hbm_Bkg);
  134. DeleteObject(pWState->hbr_Bkg);
  135. LocalFree((HLOCAL)pWState);
  136. }
  137. RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
  138. return DefSubclassProc(hwnd, WM_NCDESTROY, wParam, lParam);
  139. }
  140. LRESULT FlatSB_NCCalcProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  141. {
  142. RECT * rc = (RECT *) lParam;
  143. NCCALCSIZE_PARAMS * pnc = (NCCALCSIZE_PARAMS *)lParam;
  144. RECT rcClient, rcWin;
  145. LRESULT lres;
  146. DWORD dwStyle;
  147. // ZDC:
  148. //
  149. // Note:
  150. // It's said that if wParam is true, new rgrc[1|2] are also
  151. // computed. Since I didn't see the implementation in the 'user'
  152. // code, I leave it unimplemented.
  153. if ((BOOL)wParam == TRUE)
  154. CopyRect(&rcWin, &(pnc->rgrc[0]));
  155. else
  156. CopyRect(&rcWin, rc);
  157. dwStyle = SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, 0);
  158. // Save pnc->rgrc[0] to keep USER happy (see below)
  159. CopyRect(&rcClient, &pnc->rgrc[0]);
  160. lres = DefSubclassProc(hwnd, WM_NCCALCSIZE, wParam, lParam);
  161. SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, dwStyle);
  162. // USER does funky internal state munging during the WM_NCCALCSIZE
  163. // and we want USER's internal state to see the scrollbars even though
  164. // we're drawing them. So give USER one last look at the original
  165. // values so he will think the scroll bars are really there. This
  166. // sets internal WFVPRESENT and WFHPRESENT flags that OLEACC secretly
  167. // looks at via the undocumented GetScrollBarInfo().
  168. DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
  169. if ((BOOL)wParam == TRUE)
  170. CopyRect(&rcClient, &(pnc->rgrc[0]));
  171. else
  172. CopyRect(&rcClient, rc);
  173. pWState->style &= ~(WFVPRESENT | WFHPRESENT);
  174. if (TestSTYLE(pWState->style, WS_VSCROLL)
  175. && (rcClient.right - rcClient.left >= pWState->x_VSBArrow)) {
  176. pWState->style |= WFVPRESENT;
  177. rcClient.right -= pWState->x_VSBArrow;
  178. }
  179. if (TestSTYLE(pWState->style, WS_HSCROLL)
  180. && (rcClient.bottom - rcClient.top > pWState->y_HSBArrow)) {
  181. pWState->style |= WFHPRESENT;
  182. rcClient.bottom -= pWState->y_HSBArrow;
  183. }
  184. if ((BOOL)wParam == TRUE)
  185. CopyRect(&(pnc->rgrc[0]), &rcClient);
  186. else
  187. CopyRect(rc, &rcClient);
  188. pWState->rcClient.top = rcClient.top - rcWin.top;
  189. pWState->rcClient.bottom = rcClient.bottom - rcWin.top;
  190. pWState->rcClient.left = rcClient.left - rcWin.left;
  191. pWState->rcClient.right = rcClient.right - rcWin.left;
  192. return lres;
  193. }
  194. LRESULT FlatSB_NCPaintProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  195. {
  196. HDC hdc;
  197. int oldLoc, newLoc;
  198. LRESULT lres;
  199. DWORD dwStyle;
  200. RECT rcClient;
  201. ASSERT(pWState);
  202. ASSERT(pWState != WSB_UNINIT_HANDLE);
  203. //
  204. // DefWindowProc(WM_NCPAINT) is going to try to draw USER's scrollbars,
  205. // and will draw them in the wrong place if our scrollbar width is
  206. // different from the system default width. (Argh.)
  207. //
  208. // So remove the scrollbar styles, do the paint, then put them back.
  209. //
  210. dwStyle = SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, 0);
  211. GetWindowRect(hwnd, &rcClient);
  212. DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
  213. lres = DefSubclassProc(hwnd, WM_NCPAINT, wParam, lParam);
  214. SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, dwStyle);
  215. GetWindowRect(hwnd, &rcClient);
  216. DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
  217. // hdc = GetDCEx(hwnd, (HRGN) wParam, DCX_WINDOW |
  218. // DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
  219. // ZDC:
  220. //
  221. // Note:
  222. // For some reason(wParam == 1) the statements above did not give
  223. // the result we expected. I am not sure if it's the only case that
  224. // GetDCEx will disappoint us.
  225. hdc = GetWindowDC(hwnd);
  226. newLoc = WSB_MOUSELOC_OUTSIDE;
  227. oldLoc = pWState->locMouse;
  228. if (TestSTYLE(pWState->style, WFHPRESENT)
  229. && TestSTYLE(pWState->style, WFVPRESENT)) {
  230. int cxFrame, cyFrame;
  231. cxFrame = pWState->rcClient.right;
  232. cyFrame = pWState->rcClient.bottom;
  233. FlatSB_Internal_DrawSize(pWState, hdc, cxFrame, cyFrame);
  234. }
  235. if (TestSTYLE(pWState->style, WFHPRESENT)) {
  236. FlatSB_Internal_DrawScrollBar(pWState, hdc, FALSE, FALSE);
  237. if (pWState->fHActive)
  238. newLoc = pWState->locMouse;
  239. }
  240. if (TestSTYLE(pWState->style, WFVPRESENT)) {
  241. pWState->locMouse = oldLoc;
  242. FlatSB_Internal_DrawScrollBar(pWState, hdc, TRUE, FALSE);
  243. if (pWState->fVActive)
  244. newLoc = pWState->locMouse;
  245. }
  246. pWState->locMouse = newLoc;
  247. ReleaseDC(hwnd, hdc);
  248. return lres;
  249. }
  250. LRESULT FlatSB_NCHitTestProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fTrack);
  251. VOID CALLBACK TimerMouseLeave(
  252. HWND hwnd, // handle of window for timer messages
  253. UINT uMsg, // WM_TIMER message
  254. UINT_PTR idEvent, // timer identifier
  255. DWORD dwTime // current system time
  256. )
  257. {
  258. WSBState * pWState;
  259. if (idEvent != IDWSB_TRACK)
  260. return;
  261. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  262. if ((pWState == (WSBState *)NULL) || (pWState == WSB_UNINIT_HANDLE)) {
  263. KillTimer(hwnd, IDWSB_TRACK);
  264. return;
  265. }
  266. if (pWState->fTracking) {
  267. return;
  268. }
  269. FlatSB_NCHitTestProc(pWState, hwnd, 0, 0, TRUE);
  270. return;
  271. }
  272. LRESULT FlatSB_NCHitTestProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fTTrack)
  273. {
  274. LRESULT lres, lHTCode=HTBOTTOMRIGHT;
  275. RECT rcTest, rcWindow;
  276. POINT pt;
  277. BOOL fVChanged = FALSE, fHChanged = FALSE;
  278. BOOL fWinActive = ChildOfActiveWindow(hwnd);
  279. int newLoc, oldLoc;
  280. ASSERT(pWState);
  281. ASSERT(pWState != WSB_UNINIT_HANDLE);
  282. GetWindowRect(hwnd, &rcWindow);
  283. if (fTTrack) {
  284. lres = HTNOWHERE;
  285. if (fWinActive)
  286. GetCursorPos(&pt);
  287. else {
  288. pt.x = rcWindow.left - 1; // NOWHERE --- to fool CalcSBtuff2
  289. pt.y = rcWindow.top - 1;
  290. }
  291. } else {
  292. lres = DefSubclassProc(hwnd, WM_NCHITTEST, wParam, lParam);
  293. pt.x = GET_X_LPARAM(lParam);
  294. pt.y = GET_Y_LPARAM(lParam);
  295. }
  296. //
  297. // If this is a RTL mirrored window, then measure
  298. // the client coordinates from the visual right edge.
  299. // [samera]
  300. //
  301. if (IS_WINDOW_RTL_MIRRORED(hwnd)) {
  302. pt.x = rcWindow.right - pt.x;
  303. lHTCode = HTBOTTOMLEFT;
  304. } else {
  305. pt.x -= rcWindow.left;
  306. }
  307. pt.y -= rcWindow.top;
  308. if (fTTrack && fWinActive && (pt.x == pWState->ptMouse.x) && (pt.y == pWState->ptMouse.y))
  309. return lres /* Meaningless result*/;
  310. // We shouldn't get HTVSCROLL / HTHSCROLL for system scrollbar here.
  311. if (lres != HTNOWHERE) {
  312. goto Redraw;
  313. }
  314. if (TestSTYLE(pWState->style, WFVPRESENT)) {
  315. rcTest.left = pWState->rcClient.right;
  316. rcTest.right = pWState->rcClient.right + pWState->x_VSBArrow;
  317. rcTest.top = pWState->rcClient.top;
  318. rcTest.bottom = pWState->rcClient.bottom;
  319. if (PtInRect(&rcTest, pt)) {
  320. lres = HTVSCROLL;
  321. goto Redraw;
  322. }
  323. }
  324. if (TestSTYLE(pWState->style, WFHPRESENT)) {
  325. rcTest.left = pWState->rcClient.left;
  326. rcTest.right = pWState->rcClient.right;
  327. rcTest.top = pWState->rcClient.bottom;
  328. rcTest.bottom = pWState->rcClient.bottom + pWState->y_HSBArrow;
  329. if (PtInRect(&rcTest, pt)) {
  330. lres = HTHSCROLL;
  331. goto Redraw;
  332. }
  333. }
  334. if (TestSTYLE(pWState->style, WFHPRESENT) && TestSTYLE(pWState->style, WFVPRESENT))
  335. {
  336. rcTest.left = pWState->rcClient.right;
  337. rcTest.right = pWState->rcClient.right + pWState->x_VSBArrow;
  338. rcTest.top = pWState->rcClient.bottom;
  339. rcTest.bottom = pWState->rcClient.bottom + pWState->y_HSBArrow;
  340. if (PtInRect(&rcTest, pt)) {
  341. if (!FlatSB_Internal_IsSizeBox(hwnd))
  342. lres = HTSIZE;
  343. else
  344. lres = lHTCode;
  345. goto Redraw;
  346. }
  347. }
  348. lres = HTNOWHERE;
  349. Redraw:
  350. if(pWState->fTracking)
  351. return lres;
  352. if (!fWinActive) {
  353. fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
  354. fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
  355. } else {
  356. switch (lres) {
  357. case HTVSCROLL:
  358. fVChanged = TRUE; pWState->fVActive = TRUE;
  359. fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
  360. break;
  361. case HTHSCROLL:
  362. fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
  363. fHChanged = TRUE; pWState->fHActive = TRUE;
  364. break;
  365. default:
  366. fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
  367. fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
  368. break;
  369. }
  370. }
  371. pWState->ptMouse.x = pt.x;
  372. pWState->ptMouse.y = pt.y;
  373. newLoc = WSB_MOUSELOC_OUTSIDE;
  374. oldLoc = pWState->locMouse;
  375. if (fVChanged && IsHottrackable(pWState->vStyle)) {
  376. FlatSB_Internal_RedrawScrollBar(pWState, TRUE);
  377. if (pWState->fVActive)
  378. newLoc = pWState->locMouse;
  379. }
  380. if (fHChanged && IsHottrackable(pWState->hStyle)) {
  381. pWState->locMouse = oldLoc;
  382. FlatSB_Internal_RedrawScrollBar(pWState, FALSE);
  383. if (pWState->fHActive)
  384. newLoc = pWState->locMouse;
  385. }
  386. pWState->locMouse = newLoc;
  387. if (pWState->fVActive || pWState->fHActive) {
  388. if (pWState->hTrackSB == 0)
  389. pWState->hTrackSB = SetTimer(hwnd, IDWSB_TRACK,
  390. GetDoubleClickTime()/2,
  391. TimerMouseLeave);
  392. } else {
  393. if (pWState->hTrackSB) {
  394. KillTimer(hwnd, IDWSB_TRACK);
  395. pWState->hTrackSB = 0;
  396. }
  397. }
  398. return lres;
  399. }
  400. LRESULT FlatSB_SysCommandProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  401. {
  402. LRESULT lres;
  403. unsigned uCmdType;
  404. int hitArea;
  405. ASSERT(pWState);
  406. ASSERT(pWState != WSB_UNINIT_HANDLE);
  407. uCmdType = (unsigned) wParam & 0xFFF0; // type of system command requested
  408. hitArea = (int) wParam & 0x000F;
  409. if (uCmdType != SC_HSCROLL && uCmdType != SC_VSCROLL)
  410. return DefSubclassProc(hwnd, WM_SYSCOMMAND, wParam, lParam);
  411. else
  412. // There are some initialization we may need.
  413. #define SC_INVALID 0
  414. lres = DefSubclassProc(hwnd, WM_SYSCOMMAND, (WPARAM)SC_INVALID, lParam);
  415. #undef SC_INVALID
  416. FlatSB_Internal_SBTrackInit(pWState, hwnd, lParam, hitArea, GetKeyState(VK_SHIFT) < 0);
  417. return 0;
  418. }
  419. LRESULT FlatSB_CancelModeProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  420. {
  421. LRESULT lres;
  422. ASSERT(pWState);
  423. ASSERT(pWState != WSB_UNINIT_HANDLE);
  424. lres = DefSubclassProc(hwnd, WM_CANCELMODE, wParam, lParam);
  425. // A good citizen of Subclass, we have to wait the DefSubclassProc
  426. // release capture first!
  427. if (pWState->pfnSB)
  428. FlatSB_Internal_EndScroll(pWState, TRUE);
  429. return lres;
  430. }
  431. //
  432. // This updates the system metrics and points pPWState->pwmet at the
  433. // application metrics or system metrics, depending on whether a
  434. // screenreader is running.
  435. //
  436. void FlatSB_InitWSBMetrics(WSBState *pWState)
  437. {
  438. BOOL fScreenRead;
  439. pWState->metSys.cxHSBThumb = GetSystemMetrics(SM_CXHTHUMB);
  440. pWState->metSys.cyVSBThumb = GetSystemMetrics(SM_CYVTHUMB);
  441. pWState->metSys.cxVSBArrow = GetSystemMetrics(SM_CXVSCROLL);
  442. pWState->metSys.cyVSBArrow = GetSystemMetrics(SM_CYVSCROLL);
  443. pWState->metSys.cxHSBArrow = GetSystemMetrics(SM_CXHSCROLL);
  444. pWState->metSys.cyHSBArrow = GetSystemMetrics(SM_CYHSCROLL);
  445. fScreenRead = FALSE;
  446. SystemParametersInfo(SPI_GETSCREENREADER, 0, &fScreenRead, 0);
  447. // If a screen reader is running, then the active metrics are the
  448. // system metrics; otherwise, it's the app metrics.
  449. pWState->pmet = fScreenRead ? &pWState->metSys : &pWState->metApp;
  450. }
  451. LRESULT FlatSB_OnSettingChangeProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
  452. {
  453. ASSERT(pWState);
  454. ASSERT(pWState != WSB_UNINIT_HANDLE);
  455. FlatSB_InitWSBMetrics(pWState);
  456. // These new metrics will most likely have altered our frame, so
  457. // recompute our frame stuff too
  458. CCInvalidateFrame(hwnd);
  459. return DefSubclassProc(hwnd, WM_SETTINGCHANGE, wParam, lParam);
  460. }
  461. LRESULT FlatSB_OnScrollProc(WSBState *pWState, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  462. {
  463. if (GET_WM_HSCROLL_HWND(wParam, lParam) == NULL && !pWState->fInDoScroll) {
  464. // Somebody on the outside (probably USER) changed our scroll stuff,
  465. // so re-sync with the USER values.
  466. if (GET_WM_HSCROLL_CODE(wParam, lParam) == SB_ENDSCROLL)
  467. FlatSB_NCPaintProc(pWState, hwnd, (WPARAM)1, 0);
  468. }
  469. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  470. }
  471. LRESULT CALLBACK FlatSB_SubclassWndProc
  472. (
  473. HWND hwnd,
  474. UINT uMsg,
  475. WPARAM wParam,
  476. LPARAM lParam,
  477. WPARAM uIdSubclass,
  478. ULONG_PTR dwRefData
  479. )
  480. {
  481. WSBState * pWState = (WSBState *)dwRefData;
  482. ASSERT (dwRefData);
  483. if (pWState == (WSBState *)NULL)
  484. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  485. else if (pWState == WSB_UNINIT_HANDLE && uMsg != WM_NCDESTROY)
  486. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  487. switch (uMsg)
  488. {
  489. case WM_NCDESTROY:
  490. return FlatSB_NCDestroyProc(pWState, hwnd, wParam, lParam);
  491. case WM_NCCALCSIZE:
  492. return FlatSB_NCCalcProc(pWState, hwnd, wParam, lParam);
  493. case WM_NCPAINT:
  494. return FlatSB_NCPaintProc(pWState, hwnd, wParam, lParam);
  495. case WM_NCHITTEST:
  496. return FlatSB_NCHitTestProc(pWState, hwnd, wParam, lParam, FALSE);
  497. case WM_SYSCOMMAND:
  498. return FlatSB_SysCommandProc(pWState, hwnd, wParam, lParam);
  499. case WM_CANCELMODE:
  500. return FlatSB_CancelModeProc(pWState, hwnd, wParam, lParam);
  501. case WM_SETTINGCHANGE:
  502. return FlatSB_OnSettingChangeProc(pWState, hwnd, wParam, lParam);
  503. case WM_VSCROLL:
  504. case WM_HSCROLL:
  505. return FlatSB_OnScrollProc(pWState, hwnd, uMsg, wParam, lParam);
  506. }
  507. return DefSubclassProc(hwnd, uMsg, wParam, lParam);
  508. }
  509. //=------------------------------------------------------------------
  510. // Start of drawing functions.
  511. //=-------------------------------------------------------------------
  512. #define WSB_BUTTON_UPARROW DFCS_SCROLLUP
  513. #define WSB_BUTTON_DOWNARROW DFCS_SCROLLDOWN
  514. #define WSB_BUTTON_LEFTARROW DFCS_SCROLLLEFT
  515. #define WSB_BUTTON_RIGHTARROW DFCS_SCROLLRIGHT
  516. #define WSB_RESTING_MODE 0
  517. #define WSB_HOTTRACKED_MODE 1
  518. #define WSB_MOUSEDOWN_MODE 2
  519. #define WSB_DISABLED_MODE 3
  520. void FlatSB_Internal_DrawBox(HDC hdc, CONST RECT * prct, int mode)
  521. {
  522. HBRUSH hbrOld, hbrEdge, hbrFace;
  523. int w, h, l, t;
  524. if (prct->left > prct->right)
  525. return;
  526. else if (prct->top > prct->bottom)
  527. return;
  528. l = prct->left;
  529. t = prct->top;
  530. w = prct->right - prct->left;
  531. h = prct->bottom - prct->top;
  532. switch (mode) {
  533. case WSB_HOTTRACKED_MODE:
  534. hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
  535. hbrFace = hbrEdge;
  536. break;
  537. case WSB_MOUSEDOWN_MODE:
  538. hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
  539. hbrFace = (HBRUSH)GetStockObject(BLACK_BRUSH);
  540. break;
  541. case WSB_DISABLED_MODE:
  542. hbrEdge = GetSysColorBrush(COLOR_3DHILIGHT);
  543. hbrFace = GetSysColorBrush(COLOR_3DFACE);
  544. break;
  545. case WSB_RESTING_MODE:
  546. default:
  547. hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
  548. hbrFace = GetSysColorBrush(COLOR_3DFACE);
  549. break;
  550. }
  551. hbrOld = SelectObject(hdc, hbrEdge);
  552. PatBlt(hdc, l, t, w, 1, PATCOPY);
  553. PatBlt(hdc, l, t, 1, h, PATCOPY);
  554. PatBlt(hdc, l, t + h - 1, w, 1, PATCOPY);
  555. PatBlt(hdc, l + w - 1, t, 1, h, PATCOPY);
  556. SelectObject(hdc, hbrFace);
  557. PatBlt(hdc, l + 1, t + 1, w - 2, h - 2, PATCOPY);
  558. SelectObject(hdc, hbrOld);
  559. }
  560. void FlatSB_Internal_DrawEncartaBox(HDC hdc, CONST RECT * prct, int mode)
  561. {
  562. HBRUSH hbrOld, hbrLite, hbrDark, hbrFace;
  563. int w, h, l, t;
  564. if (prct->left > prct->right)
  565. return;
  566. else if (prct->top > prct->bottom)
  567. return;
  568. l = prct->left;
  569. t = prct->top;
  570. w = prct->right - prct->left;
  571. h = prct->bottom - prct->top;
  572. switch (mode) {
  573. case WSB_HOTTRACKED_MODE:
  574. hbrLite = GetSysColorBrush(COLOR_3DHILIGHT);
  575. hbrDark = GetSysColorBrush(COLOR_3DSHADOW);
  576. break;
  577. case WSB_MOUSEDOWN_MODE:
  578. hbrDark = GetSysColorBrush(COLOR_3DHILIGHT);
  579. hbrLite = GetSysColorBrush(COLOR_3DSHADOW);
  580. break;
  581. case WSB_DISABLED_MODE:
  582. hbrDark = hbrLite = GetSysColorBrush(COLOR_3DHILIGHT);
  583. break;
  584. case WSB_RESTING_MODE:
  585. default:
  586. hbrDark = hbrLite = GetSysColorBrush(COLOR_3DSHADOW);
  587. break;
  588. }
  589. hbrFace = GetSysColorBrush(COLOR_3DFACE);
  590. hbrOld = SelectObject(hdc, hbrLite);
  591. PatBlt(hdc, l, t, w, 1, PATCOPY);
  592. PatBlt(hdc, l, t, 1, h, PATCOPY);
  593. SelectObject(hdc, hbrDark);
  594. PatBlt(hdc, l, t + h - 1, w, 1, PATCOPY);
  595. PatBlt(hdc, l + w - 1, t, 1, h, PATCOPY);
  596. SelectObject(hdc, hbrFace);
  597. PatBlt(hdc, l + 1, t + 1, w - 2, h - 2, PATCOPY);
  598. SelectObject(hdc, hbrOld);
  599. }
  600. void FlatSB_Internal_DrawArrow(WSBState * pWState, HDC hdc, CONST RECT * rcArrow, int buttonIndex, int extraModeBits)
  601. {
  602. COLORREF rgb;
  603. LPCTSTR strIndex;
  604. HFONT hFont, hOldFont;
  605. int x, y, cx, cy, iOldBk, c;
  606. BOOL fDisabled = extraModeBits & DFCS_INACTIVE;
  607. BOOL fMouseDown = extraModeBits & DFCS_PUSHED;
  608. BOOL fHotTracked;
  609. int mode, style;
  610. if (rcArrow->left >= rcArrow->right)
  611. return;
  612. else if (rcArrow->top >= rcArrow->bottom)
  613. return;
  614. if (buttonIndex == WSB_BUTTON_LEFTARROW || buttonIndex == WSB_BUTTON_RIGHTARROW)
  615. style = pWState->hStyle;
  616. else
  617. style = pWState->vStyle;
  618. switch (buttonIndex) {
  619. case WSB_BUTTON_LEFTARROW:
  620. fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWLF);
  621. strIndex = TEXT("3");
  622. break;
  623. case WSB_BUTTON_RIGHTARROW:
  624. fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWRG);
  625. strIndex = TEXT("4");
  626. break;
  627. case WSB_BUTTON_UPARROW:
  628. fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWUP);
  629. strIndex = TEXT("5");
  630. break;
  631. case WSB_BUTTON_DOWNARROW:
  632. fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWDN);
  633. strIndex = TEXT("6");
  634. break;
  635. default:
  636. return;
  637. }
  638. if (!fDisabled && fHotTracked && pWState->fHitOld)
  639. fMouseDown = TRUE;
  640. if (style == FSB_REGULAR_MODE) {
  641. RECT rc;
  642. CopyRect(&rc, rcArrow);
  643. if (fDisabled)
  644. DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex | DFCS_INACTIVE);
  645. else if (fMouseDown)
  646. DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex | DFCS_FLAT);
  647. else
  648. DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex);
  649. return;
  650. }
  651. if (fDisabled)
  652. mode = WSB_DISABLED_MODE;
  653. else if (fMouseDown)
  654. mode = WSB_MOUSEDOWN_MODE;
  655. else if (fHotTracked)
  656. mode = WSB_HOTTRACKED_MODE;
  657. else
  658. mode = WSB_RESTING_MODE;
  659. if (style == FSB_ENCARTA_MODE) {
  660. FlatSB_Internal_DrawEncartaBox(hdc, rcArrow, mode);
  661. } else {
  662. FlatSB_Internal_DrawBox(hdc, rcArrow, mode);
  663. }
  664. cx = rcArrow->right - rcArrow->left;
  665. cy = rcArrow->bottom - rcArrow->top;
  666. c = min(cx, cy);
  667. if (c < 4) // Couldn't fill in a char after drawing the edges.
  668. return;
  669. x = rcArrow->left + ((cx - c) / 2) + 2;
  670. y = rcArrow->top + ((cy - c) / 2) + 2;
  671. c -= 4;
  672. if (style == FSB_FLAT_MODE) {
  673. switch (mode) {
  674. case WSB_RESTING_MODE:
  675. rgb = RGB(0, 0, 0);
  676. break;
  677. case WSB_HOTTRACKED_MODE:
  678. case WSB_MOUSEDOWN_MODE:
  679. rgb = RGB(255, 255, 255);
  680. break;
  681. case WSB_DISABLED_MODE:
  682. rgb = GetSysColor(COLOR_3DSHADOW);
  683. break;
  684. default:
  685. rgb = RGB(0, 0, 0);
  686. break;
  687. }
  688. } else { // FSB_ENCARTA_MODE
  689. switch (mode) {
  690. case WSB_DISABLED_MODE:
  691. rgb = GetSysColor(COLOR_3DSHADOW);
  692. break;
  693. case WSB_RESTING_MODE:
  694. case WSB_HOTTRACKED_MODE:
  695. case WSB_MOUSEDOWN_MODE:
  696. default:
  697. rgb = RGB(0, 0, 0);
  698. break;
  699. }
  700. }
  701. hFont = CreateFont(c, 0, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, WSB_SYS_FONT);
  702. iOldBk = SetBkMode(hdc, TRANSPARENT);
  703. hOldFont = SelectObject(hdc, hFont);
  704. rgb = SetTextColor(hdc, rgb);
  705. TextOut(hdc, x, y, strIndex, 1);
  706. SetBkMode(hdc, iOldBk);
  707. SelectObject(hdc, hOldFont);
  708. DeleteObject(hFont);
  709. return;
  710. }
  711. void FlatSB_Internal_DrawElevator(WSBState * pWState, HDC hdc, LPRECT lprc, BOOL fVert)
  712. {
  713. BOOL fHit;
  714. int mode;
  715. int style;
  716. fHit = (fVert)?(pWState->locMouse == WSB_MOUSELOC_V_THUMB)
  717. :(pWState->locMouse == WSB_MOUSELOC_H_THUMB);
  718. style = (fVert)?pWState->vStyle:pWState->hStyle;
  719. switch (style) {
  720. case FSB_FLAT_MODE:
  721. case FSB_ENCARTA_MODE:
  722. if ((pWState->cmdSB == SB_THUMBPOSITION) && (fVert == pWState->fTrackVert))
  723. mode = WSB_HOTTRACKED_MODE;
  724. else
  725. mode = (fHit)?WSB_HOTTRACKED_MODE:WSB_RESTING_MODE;
  726. if (style == FSB_FLAT_MODE)
  727. FlatSB_Internal_DrawBox(hdc, lprc, mode);
  728. else
  729. FlatSB_Internal_DrawEncartaBox(hdc, lprc, mode);
  730. break;
  731. case FSB_REGULAR_MODE:
  732. default:
  733. {
  734. RECT rc;
  735. CopyRect(&rc, lprc);
  736. DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH);
  737. }
  738. break;
  739. }
  740. }
  741. //=-------------------------------------------------------------
  742. // FlatSB_Internal_DrawSize
  743. // Draw the size grip if needed.
  744. //=-------------------------------------------------------------
  745. void FlatSB_Internal_DrawSize(WSBState * pWState, HDC hdc, int x, int y)
  746. {
  747. HBRUSH hbrSave, hbr3DFACE;
  748. RECT rcWindow;
  749. HWND hwnd = pWState->sbHwnd;
  750. int style;
  751. style = GetWindowLong(hwnd, GWL_STYLE);
  752. if (!FlatSB_Internal_IsSizeBox(hwnd))
  753. {
  754. hbr3DFACE = GetSysColorBrush(COLOR_3DFACE);
  755. hbrSave = SelectObject(hdc, hbr3DFACE);
  756. PatBlt(hdc, x, y, pWState->x_VSBArrow, pWState->y_HSBArrow, PATCOPY);
  757. SelectBrush(hdc, hbrSave);
  758. }
  759. else
  760. {
  761. rcWindow.left = x;
  762. rcWindow.right = x + pWState->x_VSBArrow;
  763. rcWindow.top = y;
  764. rcWindow.bottom = y + pWState->y_HSBArrow;
  765. DrawFrameControl(hdc, &rcWindow, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
  766. }
  767. }
  768. //=-------------------------------------------------------------
  769. // FlatSB_Internal_DrawGroove
  770. // Draw lines & middle of the thumb groove
  771. //=-------------------------------------------------------------
  772. void FlatSB_Internal_DrawGroove(WSBState * pWState, HDC hdc, LPRECT prct, BOOL fVert)
  773. {
  774. HBRUSH hbrLight;
  775. COLORREF cBkg, cFg;
  776. HPALETTE oldPal = 0;
  777. if (fVert) {
  778. hbrLight = pWState->hbr_VSBBkg;
  779. cBkg = pWState->col_VSBBkg;
  780. } else {
  781. hbrLight = pWState->hbr_HSBBkg;
  782. cBkg = pWState->col_HSBBkg;
  783. }
  784. if (hbrLight == (HBRUSH)NULL) {
  785. hbrLight = GetSysColorBrush(COLOR_3DLIGHT);
  786. FillRect(hdc, prct, hbrLight);
  787. return;
  788. }
  789. if (pWState->hPalette != (HPALETTE)NULL) {
  790. oldPal = SelectPalette(hdc, pWState->hPalette, TRUE);
  791. RealizePalette(hdc);
  792. }
  793. cFg = SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
  794. cBkg = SetBkColor(hdc, cBkg);
  795. FillRect(hdc, prct, hbrLight);
  796. if (oldPal != (HPALETTE)NULL)
  797. SelectPalette(hdc, oldPal, TRUE);
  798. SetTextColor(hdc, cFg);
  799. SetBkColor(hdc, cBkg);
  800. }
  801. //=-------------------------------------------------------------------
  802. // Following functions are ported from winsbctl.c in user code.
  803. //=-------------------------------------------------------------------
  804. //=-------------------------------------------------------------------------
  805. // SBPosFromPx() -
  806. //=-------------------------------------------------------------------------
  807. int FlatSB_Internal_SBPosFromPx(WSBState * pWState, int px)
  808. {
  809. int * pw;
  810. if (pWState->fTrackVert)
  811. pw = &(pWState->sbVMinPos);
  812. else
  813. pw = &(pWState->sbHMinPos);
  814. if (px < pWState->pxUpArrow)
  815. return pw[SBO_MIN];
  816. if (px >= pWState->pxDownArrow)
  817. return (pw[SBO_MAX] - (pw[SBO_PAGE]?pw[SBO_PAGE] - 1 : 0));
  818. return (pw[SBO_MIN] + DMultDiv(pw[SBO_MAX] - pw[SBO_MIN] - (pw[SBO_PAGE]?pw[SBO_PAGE] - 1 : 0),
  819. px - pWState->pxUpArrow,
  820. pWState->cpxSpace)
  821. );
  822. }
  823. //=-------------------------------------------------------------------------
  824. // InvertScrollHilite()
  825. //=-------------------------------------------------------------------------
  826. void FlatSB_Internal_InvertScrollHilite(WSBState * pWState)
  827. {
  828. HWND hwnd = pWState->sbHwnd;
  829. HDC hdc;
  830. // Don't invert if the thumb is all the way at the top or bottom
  831. // or you will end up inverting the line between the arrow and the thumb.
  832. if (!IsRectEmpty(&(pWState->rcTrack)))
  833. {
  834. hdc = GetWindowDC(hwnd);
  835. InvertRect(hdc, &(pWState->rcTrack));
  836. ReleaseDC(hwnd, hdc);
  837. }
  838. }
  839. //=-------------------------------------------------------------------------
  840. // FlatSB_Internal_MoveThumb()
  841. //=-------------------------------------------------------------------------
  842. void FlatSB_Internal_MoveThumb(WSBState * pWState, int px)
  843. {
  844. HWND hwnd = pWState->sbHwnd;
  845. HDC hdc;
  846. if (px == pWState->pxOld)
  847. return;
  848. pxReCalc:
  849. pWState->posNew = FlatSB_Internal_SBPosFromPx(pWState, px);
  850. /* Tentative position changed -- notify the guy. */
  851. if (pWState->posNew != pWState->posOld) {
  852. FlatSB_Internal_DoScroll(pWState, SB_THUMBTRACK, pWState->posNew, pWState->fTrackVert);
  853. if (!pWState->fTracking)
  854. return;
  855. pWState->posOld = pWState->posNew;
  856. //
  857. // Anything can happen after the SendMessage above in DoScroll!
  858. // Make sure that the SBINFO structure contains data for the
  859. // window being tracked -- if not, recalculate data in SBINFO
  860. // If fVertSB is TRUE, the last CalcSBStuff call is for SB_VERT.
  861. // If fTrackVert != fVertSB, we got garbage in pWState.
  862. //
  863. if (pWState->fTrackVert != pWState->fVertSB)
  864. FlatSB_Internal_CalcSBStuff(pWState, pWState->fTrackVert);
  865. // when we yield, our range can get messed with
  866. // so make sure we handle this
  867. if (px >= pWState->pxDownArrow - pWState->cpxThumb) {
  868. px = pWState->pxDownArrow - pWState->cpxThumb;
  869. goto pxReCalc;
  870. }
  871. }
  872. hdc = GetWindowDC(hwnd);
  873. pWState->pxThumbTop = px;
  874. pWState->pxThumbBottom = pWState->pxThumbTop + pWState->cpxThumb;
  875. // At this point, the disable flags are always going to be 0 --
  876. // we're in the middle of tracking.
  877. // We are Okay in this case, since in DrawElevator we decide the mode by
  878. // cmd == SB_THUMBPOSITION.
  879. FlatSB_Internal_DrawThumb2(pWState, hdc, pWState->fTrackVert, 0);
  880. ReleaseDC(hwnd, hdc);
  881. pWState->pxOld = px;
  882. }
  883. //=-------------------------------------------------------------------------
  884. // DrawInvertScrollArea() -
  885. //=-------------------------------------------------------------------------
  886. void FlatSB_Internal_DrawInvertScrollArea(WSBState * pWState, BOOL fHit, int cmd)
  887. {
  888. HWND hwnd = pWState->sbHwnd;
  889. HDC hdc;
  890. if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN))
  891. {
  892. FlatSB_Internal_InvertScrollHilite(pWState);
  893. FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_STATECHANGE,
  894. cmd == SB_PAGEUP ? INDEX_SCROLLBAR_UPPAGE
  895. : INDEX_SCROLLBAR_DOWNPAGE);
  896. return;
  897. }
  898. hdc = GetWindowDC(hwnd);
  899. if (cmd == SB_LINEUP) {
  900. if (pWState->fTrackVert) {
  901. FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLUP, (fHit) ? DFCS_PUSHED : 0);
  902. } else {
  903. FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLLEFT, (fHit) ? DFCS_PUSHED : 0);
  904. }
  905. } else {
  906. if (pWState->fTrackVert) {
  907. FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLDOWN, (fHit) ? DFCS_PUSHED : 0);
  908. } else {
  909. FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLRIGHT, (fHit) ? DFCS_PUSHED : 0);
  910. }
  911. }
  912. FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_STATECHANGE,
  913. cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN);
  914. ReleaseDC(hwnd, hdc);
  915. }
  916. //=-------------------------------------------------------------------------
  917. // FlatSB_Internal_EndScroll() -
  918. //=-------------------------------------------------------------------------
  919. void FlatSB_Internal_EndScroll(WSBState * pWState, BOOL fCancel)
  920. {
  921. HWND hwnd = pWState->sbHwnd;
  922. BOOL fVert = pWState->fTrackVert;
  923. int oldcmd;
  924. if (pWState->fTracking)
  925. {
  926. oldcmd = pWState->cmdSB;
  927. pWState->cmdSB = 0;
  928. // will not have capture if called by CancelModeProc
  929. if (GetCapture() == hwnd)
  930. ReleaseCapture();
  931. if (pWState->pfnSB == FlatSB_Internal_TrackThumb)
  932. {
  933. if (fCancel) {
  934. pWState->posOld = pWState->posStart;
  935. }
  936. FlatSB_Internal_DoScroll(pWState, SB_THUMBPOSITION, pWState->posOld, fVert);
  937. FlatSB_Internal_DrawThumb(pWState, fVert);
  938. }
  939. else if (pWState->pfnSB == FlatSB_Internal_TrackBox)
  940. {
  941. DWORD lpt;
  942. RECT rcWindow;
  943. POINT pt;
  944. if (pWState->hTimerSB)
  945. KillTimer(hwnd, IDSYS_SCROLL);
  946. lpt = GetMessagePos();
  947. ASSERT(hwnd != GetDesktopWindow());
  948. GetWindowRect(hwnd, &rcWindow);
  949. pt.x = GET_X_LPARAM(lpt) - rcWindow.left;
  950. pt.y = GET_Y_LPARAM(lpt) - rcWindow.top;
  951. if (PtInRect(&(pWState->rcTrack), pt)) {
  952. pWState->fHitOld = FALSE;
  953. FlatSB_Internal_DrawInvertScrollArea(pWState, FALSE, oldcmd);
  954. }
  955. }
  956. // Always send SB_ENDSCROLL message.
  957. pWState->pfnSB = NULL;
  958. // Anything can happen here. Client can call GetScrollInfo for THUMBPOSITION, and we
  959. // should return 0, so we should set pfnSB to NULL first.
  960. FlatSB_Internal_DoScroll(pWState, SB_ENDSCROLL, 0, fVert);
  961. pWState->fTracking = FALSE;
  962. pWState->fHitOld = FALSE;
  963. FlatSB_Internal_NotifyWinEvent(pWState, EVENT_SYSTEM_SCROLLINGEND,
  964. INDEXID_CONTAINER);
  965. // Redraw the components.
  966. FlatSB_NCHitTestProc(pWState, hwnd, 0, 0, TRUE);
  967. }
  968. }
  969. //=-------------------------------------------------------------------------
  970. // FlatSB_Internal_DoScroll() -
  971. //=-------------------------------------------------------------------------
  972. void FlatSB_Internal_DoScroll(WSBState *pWState, int cmd, int pos, BOOL fVert)
  973. {
  974. if (pWState->sbHwnd)
  975. {
  976. pWState->fInDoScroll++;
  977. SendMessage(pWState->sbHwnd, (fVert ? WM_VSCROLL : WM_HSCROLL), (WPARAM)(LOWORD(pos) << 16 | (cmd & 0xffff)), (LPARAM)NULL);
  978. pWState->fInDoScroll--;
  979. }
  980. }
  981. //=-------------------------------------------------------------------------
  982. // TimerScroll()
  983. //=--------------------------------------------------------------------------
  984. VOID CALLBACK TimerScroll(HWND hwnd, UINT message, UINT_PTR id, DWORD time)
  985. {
  986. LONG pos;
  987. POINT pt;
  988. UINT dblClkTime, dtScroll;
  989. WSBState * pWState;
  990. RECT rcWindow;
  991. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  992. if ((pWState == (WSBState *)NULL) || (pWState == WSB_UNINIT_HANDLE)) {
  993. KillTimer(hwnd, IDSYS_SCROLL);
  994. return;
  995. }
  996. ASSERT(hwnd != GetDesktopWindow());
  997. pos = GetMessagePos();
  998. pt.x = GET_X_LPARAM(pos), pt.y = GET_Y_LPARAM(pos);
  999. dblClkTime = GetDoubleClickTime();
  1000. dtScroll = (dblClkTime * 4) / 5;
  1001. GetWindowRect(hwnd, &rcWindow);
  1002. pt.x -= rcWindow.left;
  1003. pt.y -= rcWindow.top;
  1004. pos = LOWORD(pt.y) << 16 | LOWORD(pt.x);
  1005. FlatSB_Internal_TrackBox(pWState, WM_NULL, 0, (LPARAM) pos);
  1006. if (pWState->fHitOld)
  1007. {
  1008. pWState->hTimerSB = SetTimer(hwnd, IDSYS_SCROLL, dtScroll / 8, TimerScroll);
  1009. FlatSB_Internal_DoScroll(pWState, pWState->cmdSB, 0, pWState->fTrackVert);
  1010. }
  1011. return;
  1012. }
  1013. //=-------------------------------------------------------------------------
  1014. // FlatSB_Internal_TrackBox() -
  1015. //=-------------------------------------------------------------------------
  1016. void FlatSB_Internal_TrackBox(WSBState * pWState, int message, WPARAM wParam, LPARAM lParam)
  1017. {
  1018. HWND hwnd = pWState->sbHwnd;
  1019. BOOL fHit, fVert = pWState->fTrackVert;
  1020. BOOL fHitOld = pWState->fHitOld;
  1021. POINT pt;
  1022. int cmsTimer;
  1023. UINT dblClkTime, dtScroll;
  1024. if (message && (message < WM_MOUSEFIRST || message > WM_MOUSELAST))
  1025. return;
  1026. dblClkTime = GetDoubleClickTime();
  1027. dtScroll = (dblClkTime * 4) / 5;
  1028. pt.x = GET_X_LPARAM(lParam);
  1029. pt.y = GET_Y_LPARAM(lParam);
  1030. fHit = PtInRect(&(pWState->rcTrack), pt);
  1031. if (fHit != fHitOld) {
  1032. pWState->fHitOld = fHit;
  1033. FlatSB_Internal_DrawInvertScrollArea(pWState, fHit, pWState->cmdSB);
  1034. }
  1035. cmsTimer = dtScroll / 8;
  1036. switch (message)
  1037. {
  1038. case WM_LBUTTONUP:
  1039. FlatSB_Internal_EndScroll(pWState, FALSE);
  1040. break;
  1041. case WM_LBUTTONDOWN:
  1042. pWState->hTimerSB = 0;
  1043. cmsTimer = dtScroll;
  1044. /*** FALL THRU ***/
  1045. case WM_MOUSEMOVE:
  1046. if (fHit && (fHit != fHitOld))
  1047. {
  1048. /* We moved back into the normal rectangle: reset timer */
  1049. pWState->hTimerSB = SetTimer(hwnd, IDSYS_SCROLL, cmsTimer, TimerScroll);
  1050. FlatSB_Internal_DoScroll(pWState, pWState->cmdSB, 0, fVert);
  1051. }
  1052. }
  1053. }
  1054. //=-------------------------------------------------------------------------
  1055. // FlatSB_Internal_TrackThumb() -
  1056. //=-------------------------------------------------------------------------
  1057. void FlatSB_Internal_TrackThumb(WSBState * pWState, int message, WPARAM wParam, LPARAM lParam)
  1058. {
  1059. HWND hwnd = pWState->sbHwnd;
  1060. BOOL fVert = pWState->fTrackVert;
  1061. POINT pt;
  1062. if (message < WM_MOUSEFIRST || message > WM_MOUSELAST)
  1063. return;
  1064. // Make sure that the SBINFO structure contains data for the
  1065. // window being tracked -- if not, recalculate data in SBINFO
  1066. if (pWState->fTrackVert != pWState->fVertSB)
  1067. FlatSB_Internal_CalcSBStuff(pWState, pWState->fTrackVert);
  1068. pt.x = GET_X_LPARAM(lParam);
  1069. pt.y = GET_Y_LPARAM(lParam);
  1070. if (!PtInRect(&(pWState->rcTrack), pt))
  1071. pWState->px = pWState->pxStart;
  1072. else
  1073. {
  1074. pWState->px = (fVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam)) + pWState->dpxThumb;
  1075. if (pWState->px < pWState->pxUpArrow)
  1076. pWState->px = pWState->pxUpArrow;
  1077. else if (pWState->px >= (pWState->pxDownArrow - pWState->cpxThumb))
  1078. pWState->px = pWState->pxDownArrow - pWState->cpxThumb;
  1079. }
  1080. FlatSB_Internal_MoveThumb(pWState, pWState->px);
  1081. if (message == WM_LBUTTONUP)
  1082. FlatSB_Internal_EndScroll(pWState, FALSE);
  1083. }
  1084. //=-------------------------------------------------------------------------
  1085. // FlatSB_Internal_SBTrackLoop() -
  1086. //=-------------------------------------------------------------------------
  1087. void FlatSB_Internal_SBTrackLoop(WSBState * pWState, LPARAM lParam)
  1088. {
  1089. HWND hwnd = pWState->sbHwnd;
  1090. MSG msg;
  1091. int cmd, newlParam;
  1092. POINT pt;
  1093. if (!pWState->fTracking)
  1094. return;
  1095. FlatSB_Internal_NotifyWinEvent(pWState, EVENT_SYSTEM_SCROLLINGSTART,
  1096. INDEXID_CONTAINER);
  1097. (*(pWState->pfnSB))(pWState, WM_LBUTTONDOWN, 0, lParam);
  1098. while (GetCapture() == hwnd)
  1099. {
  1100. if (!GetMessage(&msg, NULL, 0, 0))
  1101. break;
  1102. if (!CallMsgFilter(&msg, MSGF_SCROLLBAR)) {
  1103. cmd = msg.message;
  1104. if (msg.hwnd == hwnd &&
  1105. ((cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST) ||
  1106. (cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST ) ))
  1107. {
  1108. // Process Key
  1109. #define ALT_PRESSED 0x20000000L
  1110. if (cmd >= WM_SYSKEYDOWN
  1111. && cmd <= WM_SYSDEADCHAR
  1112. && msg.lParam & ALT_PRESSED)
  1113. cmd -= (WM_SYSKEYDOWN - WM_KEYDOWN);
  1114. #undef ALT_PRESSED
  1115. if (!pWState->fTracking)
  1116. return;
  1117. // Change to coordinates according to left-top corner of the window.
  1118. pt.x = GET_X_LPARAM(msg.lParam) + pWState->rcClient.left;
  1119. pt.y = GET_Y_LPARAM(msg.lParam) + pWState->rcClient.top;
  1120. newlParam = LOWORD(pt.y) << 16 | LOWORD(pt.x);
  1121. (*(pWState->pfnSB))(pWState, cmd, msg.wParam, (LPARAM)newlParam);
  1122. } else {
  1123. TranslateMessage(&msg);
  1124. DispatchMessage(&msg);
  1125. }
  1126. }
  1127. }
  1128. }
  1129. //=-------------------------------------------------------------------------
  1130. // FlatSB_Internal_SBTrackInit() -
  1131. //=-------------------------------------------------------------------------
  1132. void FlatSB_Internal_SBTrackInit(WSBState * pWState, HWND hwnd, LPARAM lParam, int hitArea, BOOL fDirect)
  1133. {
  1134. int hitX = GET_X_LPARAM(lParam);
  1135. int hitY = GET_Y_LPARAM(lParam);
  1136. int px;
  1137. int *pwX;
  1138. int *pwY;
  1139. int wDisable; // Scroll bar disable flags;
  1140. RECT rcWindow;
  1141. BOOL fVert;
  1142. POINT pt;
  1143. // hitArea = 0 indicates a scroll bar control
  1144. // otherwise, curArea will have the hit test area
  1145. if (hitArea == HTHSCROLL)
  1146. fVert = FALSE;
  1147. else if (hitArea == HTVSCROLL)
  1148. fVert = TRUE;
  1149. else
  1150. return;
  1151. ASSERT(hwnd != GetDesktopWindow());
  1152. GetWindowRect(hwnd, &rcWindow);
  1153. pt.x = GET_X_LPARAM(lParam) - rcWindow.left;
  1154. pt.y = GET_Y_LPARAM(lParam) - rcWindow.top;
  1155. lParam = LOWORD(pt.y) << 16 | LOWORD(pt.x);
  1156. wDisable = FlatSB_Internal_GetSBFlags(pWState, fVert);
  1157. if ((wDisable & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) {
  1158. // Whole Scroll Bar is disabled -- do not respond
  1159. pWState->pfnSB = NULL;
  1160. pWState->fTracking = FALSE;
  1161. return;
  1162. }
  1163. pWState->hTimerSB = 0;
  1164. pWState->fHitOld = FALSE;
  1165. pWState->fTracking = FALSE;
  1166. // For the case we click on scroll bar of a nonactive window. The mode is set to FLAT
  1167. // by HitTestProc. This will work because we set the tracking flag right away.
  1168. if (fVert) {
  1169. pWState->fVActive = TRUE; pWState->fHActive = FALSE;
  1170. } else {
  1171. pWState->fHActive = TRUE; pWState->fVActive = FALSE;
  1172. }
  1173. // This will give us the right locMouse. We will keep it till EndScroll.
  1174. FlatSB_Internal_CalcSBStuff(pWState, fVert);
  1175. // From now till EndScroll, CalcSBStuff won't compute new locMouse.
  1176. pWState->pfnSB = FlatSB_Internal_TrackBox;
  1177. pWState->fTracking = TRUE;
  1178. // Initialize rcSB to the Rectangle of the Entire Scroll Bar
  1179. pwX = (int *)&(pWState->rcSB);
  1180. pwY = pwX + 1;
  1181. if (!fVert)
  1182. pwX = pwY--;
  1183. pwX[0] = pWState->pxLeft;
  1184. pwY[0] = pWState->pxTop;
  1185. pwX[2] = pWState->pxRight;
  1186. pwY[2] = pWState->pxBottom;
  1187. px = (fVert ? pt.y : pt.x);
  1188. pWState->px = px;
  1189. if (px < pWState->pxUpArrow)
  1190. { // The click occurred on Left/Up arrow
  1191. if(wDisable & LTUPFLAG)
  1192. { // Disabled -- do not respond
  1193. pWState->pfnSB = NULL;
  1194. pWState->fTracking = FALSE;
  1195. return;
  1196. }
  1197. // LINEUP -- make rcSB the Up Arrow's Rectangle
  1198. pWState->cmdSB = SB_LINEUP;
  1199. pwY[2] = pWState->pxUpArrow;
  1200. }
  1201. else if (px >= pWState->pxDownArrow)
  1202. { // The click occurred on Right/Down arrow
  1203. if(wDisable & RTDNFLAG)
  1204. { // Disabled -- do not respond
  1205. pWState->pfnSB = NULL;
  1206. pWState->fTracking = FALSE;
  1207. return;
  1208. }
  1209. // LINEDOWN -- make rcSB the Down Arrow's Rectangle
  1210. pWState->cmdSB = SB_LINEDOWN;
  1211. pwY[0] = pWState->pxDownArrow;
  1212. }
  1213. else if (px < pWState->pxThumbTop)
  1214. {
  1215. // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
  1216. pWState->cmdSB = SB_PAGEUP;
  1217. pwY[0] = pWState->pxUpArrow;
  1218. pwY[2] = pWState->pxThumbTop;
  1219. }
  1220. else if (px < pWState->pxThumbBottom)
  1221. {
  1222. DoThumbPos:
  1223. if (pWState->pxDownArrow - pWState->pxUpArrow <= pWState->cpxThumb) {
  1224. // Not enough room -- elevator isn't there
  1225. pWState->pfnSB = NULL;
  1226. pWState->fTracking = FALSE;
  1227. return;
  1228. }
  1229. // THUMBPOSITION -- we're tracking with the thumb
  1230. pWState->cmdSB = SB_THUMBPOSITION;
  1231. pWState->fTrackVert = fVert;
  1232. CopyRect(&(pWState->rcTrack), &(pWState->rcSB));
  1233. if (pWState->sbGutter < 0) {
  1234. // Negative gutter means "infinite size"
  1235. pWState->rcTrack.top = MINLONG;
  1236. pWState->rcTrack.left = MINLONG;
  1237. pWState->rcTrack.right = MAXLONG;
  1238. pWState->rcTrack.bottom = MAXLONG;
  1239. } else
  1240. if (fVert)
  1241. InflateRect(&(pWState->rcTrack),
  1242. (pWState->rcTrack.right - pWState->rcTrack.left) * pWState->sbGutter,
  1243. pWState->y_VSBThumb * pWState->sbGutter);
  1244. else
  1245. InflateRect(&(pWState->rcTrack),
  1246. pWState->x_HSBThumb * pWState->sbGutter,
  1247. (pWState->rcTrack.bottom - pWState->rcTrack.top) * pWState->sbGutter);
  1248. pWState->pfnSB = FlatSB_Internal_TrackThumb;
  1249. pWState->pxOld = pWState->pxStart = pWState->pxThumbTop;
  1250. pWState->posOld = pWState->posNew = pWState->posStart = fVert?pWState->sbVThumbPos:pWState->sbHThumbPos;
  1251. pWState->dpxThumb = pWState->pxThumbTop - pWState->px;
  1252. SetCapture(hwnd);
  1253. FlatSB_Internal_DoScroll(pWState, SB_THUMBTRACK, pWState->posOld, fVert);
  1254. FlatSB_Internal_DrawThumb(pWState, fVert);
  1255. }
  1256. else if (px < pWState->pxDownArrow)
  1257. {
  1258. // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
  1259. pWState->cmdSB = SB_PAGEDOWN;
  1260. pwY[0] = pWState->pxThumbBottom;
  1261. pwY[2] = pWState->pxDownArrow;
  1262. }
  1263. // NT5-style tracking: Shift+Click = "Go here"
  1264. if (g_bRunOnNT5 && fDirect && pWState->cmdSB != SB_LINEUP && pWState->cmdSB != SB_LINEDOWN) {
  1265. if (pWState->cmdSB != SB_THUMBPOSITION) {
  1266. goto DoThumbPos;
  1267. }
  1268. pWState->dpxThumb = -(pWState->cpxThumb / 2);
  1269. }
  1270. if (pWState->cmdSB != SB_THUMBPOSITION) {
  1271. pWState->fTrackVert = fVert;
  1272. SetCapture(hwnd);
  1273. CopyRect(&(pWState->rcTrack), &(pWState->rcSB));
  1274. }
  1275. FlatSB_Internal_SBTrackLoop(pWState, lParam);
  1276. }
  1277. //=-------------------------------------------------------------------------
  1278. // GetScroll...() -
  1279. //=-------------------------------------------------------------------------
  1280. int WINAPI FlatSB_GetScrollPos(HWND hwnd, int code)
  1281. {
  1282. WSBState * pWState;
  1283. ASSERT (code != SB_CTL);
  1284. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1285. if (pWState == (WSBState *)NULL) {
  1286. return GetScrollPos(hwnd, code);
  1287. } else if (pWState == WSB_UNINIT_HANDLE) {
  1288. return 0;
  1289. } else if (pWState->sbHwnd != hwnd) {
  1290. return 0;
  1291. } else {
  1292. return ((code == SB_VERT)?pWState->sbVThumbPos:pWState->sbHThumbPos);
  1293. }
  1294. }
  1295. BOOL WINAPI FlatSB_GetScrollPropPtr(HWND hwnd, int propIndex, PINT_PTR pValue)
  1296. {
  1297. WSBState * pWState;
  1298. if (!pValue)
  1299. return FALSE;
  1300. else
  1301. *pValue = 0; // If we can't set it, we reset it.
  1302. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1303. if (pWState == (WSBState *)NULL) {
  1304. return FALSE;
  1305. } else if (pWState == WSB_UNINIT_HANDLE) {
  1306. pWState = FlatSB_Internal_InitPwSB(hwnd);
  1307. if (pWState == (WSBState *)NULL)
  1308. return FALSE;
  1309. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  1310. DeleteObject(pWState->hbm_Bkg);
  1311. DeleteObject(pWState->hbr_Bkg);
  1312. LocalFree((HLOCAL)pWState);
  1313. return FALSE;
  1314. } else {
  1315. // Fall through.
  1316. }
  1317. } else if (pWState->sbHwnd != hwnd) {
  1318. return FALSE;
  1319. }
  1320. switch (propIndex) {
  1321. case WSB_PROP_CYVSCROLL:
  1322. *pValue = pWState->metApp.cyVSBArrow;
  1323. break;
  1324. case WSB_PROP_CXVSCROLL:
  1325. *pValue = pWState->metApp.cxVSBArrow;
  1326. break;
  1327. case WSB_PROP_CYHSCROLL:
  1328. *pValue = pWState->metApp.cyHSBArrow;
  1329. break;
  1330. case WSB_PROP_CXHSCROLL:
  1331. *pValue = pWState->metApp.cxHSBArrow;
  1332. break;
  1333. case WSB_PROP_CXHTHUMB:
  1334. *pValue = pWState->metApp.cxHSBThumb;
  1335. break;
  1336. case WSB_PROP_CYVTHUMB:
  1337. *pValue = pWState->metApp.cyVSBThumb;
  1338. break;
  1339. case WSB_PROP_WINSTYLE:
  1340. // To check if a scrollbar is present, the WF(HV)PRESENT bits may
  1341. // be more useful than WS_(HV)SCROLL bits.
  1342. *pValue = pWState->style;
  1343. break;
  1344. case WSB_PROP_HSTYLE:
  1345. *pValue = pWState->hStyle;
  1346. break;
  1347. case WSB_PROP_VSTYLE:
  1348. *pValue = pWState->vStyle;
  1349. break;
  1350. case WSB_PROP_HBKGCOLOR:
  1351. *pValue = pWState->col_HSBBkg;
  1352. break;
  1353. case WSB_PROP_VBKGCOLOR:
  1354. *pValue = pWState->col_VSBBkg;
  1355. break;
  1356. case WSB_PROP_PALETTE:
  1357. *pValue = (INT_PTR)pWState->hPalette;
  1358. break;
  1359. case WSB_PROP_GUTTER:
  1360. *pValue = pWState->sbGutter;
  1361. break;
  1362. default:
  1363. return FALSE;
  1364. }
  1365. return TRUE;
  1366. }
  1367. #ifdef _WIN64
  1368. BOOL WINAPI FlatSB_GetScrollProp(HWND hwnd, int propIndex, LPINT pValue)
  1369. {
  1370. INT_PTR iValue;
  1371. BOOL fRc;
  1372. if (!pValue)
  1373. return FALSE;
  1374. #ifdef DEBUG
  1375. if (propIndex == WSB_PROP_PALETTE)
  1376. {
  1377. TraceMsg(TF_ERROR, "FlatSB_GetScrollProp(WSB_PROP_PALETTE): Use GetScrollPropPtr for Win64 compat");
  1378. }
  1379. #endif
  1380. fRc = FlatSB_GetScrollPropPtr(hwnd, propIndex, &iValue);
  1381. *pValue = (int)iValue;
  1382. return fRc;
  1383. }
  1384. #endif
  1385. BOOL WINAPI FlatSB_GetScrollRange(HWND hwnd, int code, LPINT lpposMin, LPINT lpposMax)
  1386. {
  1387. int *pw;
  1388. WSBState * pWState;
  1389. ASSERT(code != SB_CTL);
  1390. if (!lpposMin || !lpposMax)
  1391. return FALSE;
  1392. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1393. if (pWState == (WSBState *)NULL) {
  1394. return GetScrollRange(hwnd, code, lpposMin, lpposMax);
  1395. // *lpposMin = 0;
  1396. // *lpposMax = 0;
  1397. } else if (pWState == WSB_UNINIT_HANDLE) {
  1398. *lpposMin = 0;
  1399. *lpposMax = 0;
  1400. } else if (pWState->sbHwnd != hwnd) {
  1401. return FALSE;
  1402. } else {
  1403. pw = (code == SB_VERT) ? &(pWState->sbVMinPos) : &(pWState->sbHMinPos);
  1404. *lpposMin = pw[SBO_MIN];
  1405. *lpposMax = pw[SBO_MAX];
  1406. }
  1407. return TRUE;
  1408. }
  1409. BOOL WINAPI FlatSB_GetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
  1410. {
  1411. int *pw;
  1412. WSBState * pWState;
  1413. ASSERT(fnBar != SB_CTL);
  1414. // ZDC@Oct. 10, Detect GP faults here.
  1415. if ((LPSCROLLINFO)NULL == lpsi)
  1416. return FALSE;
  1417. if (lpsi->cbSize < sizeof (SCROLLINFO))
  1418. return FALSE;
  1419. // ZDC@Oct. 11, Don't zero out buffer anymore.
  1420. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1421. if (pWState == (WSBState *)NULL) {
  1422. return GetScrollInfo(hwnd, fnBar, lpsi);
  1423. } else if (pWState == WSB_UNINIT_HANDLE) {
  1424. return FALSE;
  1425. } else if (pWState->sbHwnd != hwnd) {
  1426. return FALSE;
  1427. } else if (fnBar == SB_VERT) {
  1428. pw = &(pWState->sbVMinPos);
  1429. } else if (fnBar == SB_HORZ) {
  1430. pw = &(pWState->sbHMinPos);
  1431. } else {
  1432. return FALSE;
  1433. }
  1434. if (lpsi->fMask & SIF_RANGE)
  1435. lpsi->nMin = pw[SBO_MIN], lpsi->nMax = pw[SBO_MAX];
  1436. if (lpsi->fMask & SIF_POS)
  1437. lpsi->nPos = pw[SBO_POS];
  1438. if (lpsi->fMask & SIF_PAGE)
  1439. lpsi->nPage = pw[SBO_PAGE];
  1440. // ZDC@Oct 9, Add support for SIF_TRACKPOS
  1441. if (lpsi->fMask & SIF_TRACKPOS) {
  1442. // This is the olny place that pfnSB is used instead of fTracking.
  1443. if (pWState->pfnSB != NULL) {
  1444. if ((fnBar == SB_VERT) && pWState->fTrackVert)
  1445. lpsi->nTrackPos = pWState->posNew;
  1446. else if ((fnBar == SB_HORZ) && !(pWState->fTrackVert))
  1447. lpsi->nTrackPos = pWState->posNew;
  1448. else
  1449. lpsi->nTrackPos = pw[SBO_POS];
  1450. } else
  1451. lpsi->nTrackPos = pw[SBO_POS];
  1452. }
  1453. return TRUE;
  1454. }
  1455. BOOL WINAPI FlatSB_ShowScrollBar(HWND hwnd, int fnBar, BOOL fShow)
  1456. {
  1457. BOOL fChanged = FALSE;
  1458. int newStyle = 0;
  1459. WSBState * pWState;
  1460. ASSERT(fnBar != SB_CTL);
  1461. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1462. if (pWState == (WSBState *)NULL)
  1463. return ShowScrollBar(hwnd, fnBar, fShow);
  1464. switch (fnBar) {
  1465. case SB_VERT:
  1466. newStyle = WS_VSCROLL;
  1467. break;
  1468. case SB_HORZ:
  1469. newStyle = WS_HSCROLL;
  1470. break;
  1471. case SB_BOTH:
  1472. newStyle = WS_VSCROLL | WS_HSCROLL;
  1473. break;
  1474. default:
  1475. return FALSE;
  1476. }
  1477. if (pWState == WSB_UNINIT_HANDLE) {
  1478. if (fShow) {
  1479. pWState = FlatSB_Internal_InitPwSB(hwnd);
  1480. if (pWState == (WSBState *)NULL)
  1481. return FALSE;
  1482. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  1483. DeleteObject(pWState->hbm_Bkg);
  1484. DeleteObject(pWState->hbr_Bkg);
  1485. LocalFree((HLOCAL)pWState);
  1486. return FALSE;
  1487. }
  1488. } else {
  1489. return FALSE;
  1490. }
  1491. }
  1492. if (!fShow) {
  1493. if (pWState->style & newStyle) {
  1494. fChanged = TRUE;
  1495. pWState->style &= ~newStyle;
  1496. }
  1497. } else {
  1498. if ((pWState->style & newStyle) != newStyle) {
  1499. fChanged = TRUE;
  1500. pWState->style |= newStyle;
  1501. }
  1502. }
  1503. if (fChanged) {
  1504. // Keep USER scrollbars in sync for accessibility
  1505. ShowScrollBar(hwnd, fnBar, fShow);
  1506. CCInvalidateFrame(hwnd);
  1507. }
  1508. return TRUE;
  1509. }
  1510. //=------------------------------------------------------------------
  1511. // Following functions are ported from winsb.c in user code.
  1512. //=------------------------------------------------------------------
  1513. //=--------------------------------------------------------------
  1514. // InitPwSB
  1515. // [in] hwnd
  1516. // Note:
  1517. // This function is only a memory allocating func. It won't
  1518. // do any check. On the other hand, this function should be
  1519. // called before any consequent functions are used.
  1520. //=--------------------------------------------------------------
  1521. WSBState * FlatSB_Internal_InitPwSB(HWND hwnd)
  1522. {
  1523. int patGray[4];
  1524. HBITMAP hbm;
  1525. WSBState * pw;
  1526. pw = (WSBState *)LocalAlloc(LPTR, sizeof(WSBState));
  1527. // The buffer should already be zero-out.
  1528. if (pw == (WSBState *)NULL)
  1529. return pw;
  1530. patGray[0] = 0x005500AA;
  1531. patGray[1] = 0x005500AA;
  1532. patGray[2] = 0x005500AA;
  1533. patGray[3] = 0x005500AA;
  1534. pw->sbVMaxPos = pw->sbHMaxPos = 100;
  1535. pw->sbHwnd = hwnd;
  1536. // We start out with app metrics equal to system metrics
  1537. FlatSB_InitWSBMetrics(pw);
  1538. pw->metApp = pw->metSys;
  1539. //
  1540. // NT5's gutter is 8; Win9x's and NT4's gutter is 2.
  1541. //
  1542. pw->sbGutter = g_bRunOnNT5 ? 8 : 2;
  1543. // ZDC
  1544. // make sure get hbm_Bkg and hbr_Bkg deleted.
  1545. hbm = CreateBitmap(8, 8, 1, 1, (LPSTR)patGray);
  1546. if ((HBITMAP)NULL == hbm) {
  1547. LocalFree((HLOCAL)pw);
  1548. return NULL;
  1549. }
  1550. pw->hbr_VSBBkg = CreatePatternBrush(hbm);
  1551. if ((HBRUSH)NULL == pw->hbr_VSBBkg) {
  1552. DeleteObject(hbm);
  1553. LocalFree((HLOCAL)pw);
  1554. return NULL;
  1555. }
  1556. pw->hbr_Bkg = pw->hbr_HSBBkg = pw->hbr_VSBBkg;
  1557. pw->col_VSBBkg = pw->col_HSBBkg = RGB(255, 255, 255);
  1558. pw->hbm_Bkg = hbm;
  1559. pw->hStyle = pw->vStyle = FSB_FLAT_MODE; // Default state: Flat.
  1560. pw->ptMouse.x = -1;
  1561. pw->ptMouse.y = -1;
  1562. return(pw);
  1563. }
  1564. void FlatSB_Internal_RedrawScrollBar(WSBState * pWState, BOOL fVert)
  1565. {
  1566. HDC hdc;
  1567. hdc = GetWindowDC(pWState->sbHwnd);
  1568. FlatSB_Internal_DrawScrollBar(pWState, hdc, fVert, TRUE);
  1569. ReleaseDC(pWState->sbHwnd, hdc);
  1570. }
  1571. //=-------------------------------------------------------------
  1572. // FlatSB_Internal_GetSBFlags
  1573. //=-------------------------------------------------------------
  1574. UINT FlatSB_Internal_GetSBFlags(WSBState * pWState, BOOL fVert)
  1575. {
  1576. int wFlags;
  1577. if (pWState == (WSBState *)NULL) {
  1578. return(0);
  1579. }
  1580. wFlags = pWState->sbFlags;
  1581. return(fVert ? (wFlags & WSB_VERT) >> 2 : wFlags & WSB_HORZ);
  1582. }
  1583. //=--------------------------------------------------------------
  1584. // return TRUE if there is a change.
  1585. //=--------------------------------------------------------------
  1586. BOOL WINAPI FlatSB_EnableScrollBar(HWND hwnd, int wSBflags, UINT wArrows)
  1587. {
  1588. WSBState * pWState;
  1589. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  1590. if (pWState == (WSBState *)NULL) {
  1591. return EnableScrollBar(hwnd, wSBflags, wArrows);
  1592. } else if (pWState == WSB_UNINIT_HANDLE) {
  1593. if (wArrows == ESB_ENABLE_BOTH)
  1594. // Leave it to later calls.
  1595. return FALSE;
  1596. else {
  1597. pWState = FlatSB_Internal_InitPwSB(hwnd);
  1598. if (pWState == (WSBState *)NULL)
  1599. return FALSE;
  1600. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  1601. DeleteObject(pWState->hbm_Bkg);
  1602. DeleteObject(pWState->hbr_Bkg);
  1603. LocalFree((HLOCAL)pWState);
  1604. return FALSE;
  1605. }
  1606. }
  1607. } else if (hwnd != pWState->sbHwnd) {
  1608. return FALSE;
  1609. }
  1610. return FlatSB_Internal_EnableScrollBar(pWState, wSBflags, wArrows);
  1611. }
  1612. //=-------------------------------------------------------------
  1613. // FlatSB_Internal_EnableScrollBar
  1614. //
  1615. // Note:
  1616. // The func will simply fail in case of uninitialized pointer
  1617. // pWState is passed.
  1618. // Since we now use WSBState * as handle, we always hope it's
  1619. // valid already.
  1620. //
  1621. // The following func is implemented following the comments in
  1622. // winsbctl.c and the comment of the in MSDN library. In
  1623. // access\inc16\windows.h you can find:
  1624. // #define SB_DISABLE_MASK ESB_DISABLE_BOTH // 0x03
  1625. //
  1626. // The sbFlags is slightly different with rgwScroll[SB_FLAGS].
  1627. //=-------------------------------------------------------------
  1628. BOOL FlatSB_Internal_EnableScrollBar(WSBState * pWState, int wSBflags, UINT wArrows)
  1629. {
  1630. int wOldFlags;
  1631. int style;
  1632. BOOL bRetValue = FALSE;
  1633. BOOL bDrawHBar = FALSE;
  1634. BOOL bDrawVBar = FALSE;
  1635. HDC hdc;
  1636. HWND hwnd;
  1637. ASSERT (wSBflags != SB_CTL);
  1638. wOldFlags = pWState->sbFlags;
  1639. hwnd = pWState->sbHwnd;
  1640. style = GetWindowLong(hwnd, GWL_STYLE);
  1641. switch (wSBflags) {
  1642. case SB_HORZ:
  1643. case SB_BOTH:
  1644. if (wArrows == ESB_ENABLE_BOTH)
  1645. pWState->sbFlags &= ~WSB_HORZ;
  1646. else
  1647. pWState->sbFlags |= wArrows;
  1648. if (wOldFlags != pWState->sbFlags)
  1649. {
  1650. bRetValue = TRUE;
  1651. if (TestSTYLE(pWState->style, WFHPRESENT)
  1652. && !TestSTYLE(style, WS_MINIMIZE)
  1653. && IsWindowVisible(hwnd))
  1654. bDrawHBar = TRUE;
  1655. }
  1656. if (wSBflags == SB_HORZ)
  1657. break;
  1658. else
  1659. wOldFlags = pWState->sbFlags; // Fall through
  1660. case SB_VERT:
  1661. if (wArrows == ESB_ENABLE_BOTH)
  1662. pWState->sbFlags &= ~WSB_VERT;
  1663. else
  1664. pWState->sbFlags |= (wArrows<<2);
  1665. if (wOldFlags != pWState->sbFlags)
  1666. {
  1667. bRetValue = TRUE;
  1668. if (TestSTYLE(pWState->style, WFVPRESENT)
  1669. && !TestSTYLE(style, WS_MINIMIZE)
  1670. && IsWindowVisible(hwnd))
  1671. bDrawVBar = TRUE;
  1672. }
  1673. break;
  1674. default:
  1675. return FALSE;
  1676. }
  1677. if (bDrawVBar || bDrawHBar) {
  1678. int oldLoc = pWState->locMouse;
  1679. int newLoc;
  1680. if (!(hdc = GetWindowDC(hwnd)))
  1681. return(FALSE);
  1682. newLoc = oldLoc;
  1683. if (bDrawHBar) {
  1684. FlatSB_Internal_DrawScrollBar(pWState, hdc, FALSE, FALSE);
  1685. if (pWState->fHActive)
  1686. newLoc = pWState->locMouse;
  1687. }
  1688. if (bDrawVBar) {
  1689. pWState->locMouse = oldLoc;
  1690. FlatSB_Internal_DrawScrollBar(pWState, hdc, TRUE, FALSE);
  1691. if (pWState->fVActive)
  1692. newLoc = pWState->locMouse;
  1693. }
  1694. pWState->locMouse = newLoc;
  1695. ReleaseDC(hwnd, hdc);
  1696. }
  1697. // Keep USER scrollbar in sync for accessibility
  1698. if (bRetValue)
  1699. EnableScrollBar(hwnd, wSBflags, wArrows);
  1700. return bRetValue;
  1701. }
  1702. //=-------------------------------------------------------------
  1703. // FlatSB_Internal_DrawThumb2
  1704. //=-------------------------------------------------------------
  1705. void FlatSB_Internal_DrawThumb2(WSBState * pWState, HDC hdc, BOOL fVert, UINT wDisable)
  1706. {
  1707. int *pLength;
  1708. int *pWidth;
  1709. HWND hwnd;
  1710. HBRUSH hbr;
  1711. hwnd = pWState->sbHwnd;
  1712. hbr = (fVert)?pWState->hbr_VSBBkg:pWState->hbr_HSBBkg;
  1713. // Bail out if the scrollbar has an empty rect
  1714. if ((pWState->pxTop >= pWState->pxBottom)
  1715. || (pWState->pxLeft >= pWState->pxRight))
  1716. return;
  1717. pLength = (int *) &(pWState->rcSB);
  1718. if (fVert)
  1719. pWidth = pLength++;
  1720. else
  1721. pWidth = pLength + 1;
  1722. pWidth[0] = pWState->pxLeft;
  1723. pWidth[2] = pWState->pxRight;
  1724. // If both scroll arrows are disabled or if there isn't enough room for
  1725. // the thumb, just erase the whole slide area and return
  1726. if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
  1727. ((pWState->pxDownArrow - pWState->pxUpArrow) < pWState->cpxThumb))
  1728. {
  1729. pLength[0] = pWState->pxUpArrow;
  1730. pLength[2] = pWState->pxDownArrow;
  1731. FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
  1732. return;
  1733. }
  1734. // UI designers want a at least 1 pixel gap between arrow and thumb.
  1735. // Have to do this :(
  1736. if (pWState->pxUpArrow <= pWState->pxThumbTop)
  1737. {
  1738. // Fill in space above Thumb
  1739. pLength[0] = pWState->pxUpArrow;
  1740. pLength[2] = pWState->pxThumbTop;
  1741. FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
  1742. }
  1743. if (pWState->pxThumbBottom <= pWState->pxDownArrow)
  1744. {
  1745. // Fill in space below Thumb
  1746. pLength[0] = pWState->pxThumbBottom;
  1747. pLength[2] = pWState->pxDownArrow;
  1748. FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
  1749. }
  1750. // Draw elevator
  1751. pLength[0] = pWState->pxThumbTop;
  1752. pLength[2] = pWState->pxThumbBottom;
  1753. FlatSB_Internal_DrawElevator(pWState, hdc, &(pWState->rcSB), fVert);
  1754. // If we're tracking a page scroll, then we've obliterated the hilite.
  1755. // We need to correct the hiliting rectangle, and rehilite it.
  1756. if ((pWState->cmdSB == SB_PAGEUP || pWState->cmdSB == SB_PAGEDOWN)
  1757. && pWState->fTrackVert == fVert)
  1758. {
  1759. pLength = (int *) &pWState->rcTrack;
  1760. if (fVert)
  1761. pLength++;
  1762. if (pWState->cmdSB == SB_PAGEUP)
  1763. pLength[2] = pWState->pxThumbTop;
  1764. else
  1765. pLength[0] = pWState->pxThumbBottom;
  1766. if (pLength[0] < pLength[2])
  1767. InvertRect(hdc, &(pWState->rcTrack));
  1768. }
  1769. }
  1770. //=-------------------------------------------------------------
  1771. // DrawSB2
  1772. //=-------------------------------------------------------------
  1773. void FlatSB_Internal_DrawSB2(WSBState * pWState, HDC hdc, BOOL fVert, BOOL fRedraw, int oldLoc)
  1774. {
  1775. int cLength;
  1776. int cWidth;
  1777. int cpxArrow;
  1778. int *pwX;
  1779. int *pwY;
  1780. int newLoc = pWState->locMouse;
  1781. UINT wDisable = FlatSB_Internal_GetSBFlags(pWState, fVert);
  1782. HBRUSH hbrSave;
  1783. HWND hwnd;
  1784. RECT rc, * prcSB;
  1785. hwnd = pWState->sbHwnd;
  1786. cLength = (pWState->pxBottom - pWState->pxTop) / 2;
  1787. cWidth = (pWState->pxRight - pWState->pxLeft);
  1788. if ((cLength <= 0) || (cWidth <= 0))
  1789. return;
  1790. cpxArrow = (fVert) ? pWState->y_VSBArrow : pWState->x_HSBArrow;
  1791. if (cLength > cpxArrow)
  1792. cLength = cpxArrow;
  1793. prcSB = &(pWState->rcSB);
  1794. pwX = (int *)prcSB;
  1795. pwY = pwX + 1;
  1796. if (!fVert)
  1797. pwX = pwY--;
  1798. pwX[0] = pWState->pxLeft;
  1799. pwY[0] = pWState->pxTop;
  1800. pwX[2] = pWState->pxRight;
  1801. pwY[2] = pWState->pxBottom;
  1802. hbrSave = SelectObject(hdc, GetSysColorBrush(COLOR_BTNTEXT));
  1803. CopyRect(&rc, prcSB);
  1804. if (fVert)
  1805. {
  1806. rc.bottom = rc.top + cLength;
  1807. if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWUP
  1808. || oldLoc == WSB_MOUSELOC_ARROWUP)
  1809. FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLUP,
  1810. ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1811. rc.bottom = prcSB->bottom;
  1812. rc.top = prcSB->bottom - cLength;
  1813. if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWDN
  1814. || oldLoc == WSB_MOUSELOC_ARROWDN)
  1815. FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLDOWN,
  1816. ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1817. }
  1818. else
  1819. {
  1820. rc.right = rc.left + cLength;
  1821. if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWLF
  1822. || oldLoc == WSB_MOUSELOC_ARROWLF)
  1823. FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLLEFT,
  1824. ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  1825. rc.right = prcSB->right;
  1826. rc.left = prcSB->right - cLength;
  1827. if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWRG
  1828. || oldLoc == WSB_MOUSELOC_ARROWRG)
  1829. FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLRIGHT,
  1830. ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  1831. }
  1832. SelectObject(hdc, hbrSave);
  1833. if (!fRedraw)
  1834. FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
  1835. else if (!fVert || newLoc == WSB_MOUSELOC_H_THUMB
  1836. || oldLoc == WSB_MOUSELOC_H_THUMB)
  1837. FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
  1838. else if (fVert || newLoc == WSB_MOUSELOC_V_THUMB
  1839. || oldLoc == WSB_MOUSELOC_V_THUMB)
  1840. FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
  1841. else
  1842. return;
  1843. }
  1844. //=-------------------------------------------------------------
  1845. // FlatSB_Internal_CalcSBStuff2
  1846. //=-------------------------------------------------------------
  1847. void FlatSB_Internal_CalcSBStuff2(WSBState * pWState, LPRECT lprc, BOOL fVert)
  1848. {
  1849. int cpxThumb; // Height of (V)scroll bar thumb.
  1850. int cpxArrow; // Height of (V)scroll bar arrow.
  1851. int cpxSpace; // The space in scroll bar;
  1852. int pxTop;
  1853. int pxBottom;
  1854. int pxLeft;
  1855. int pxRight;
  1856. int pxUpArrow;
  1857. int pxDownArrow;
  1858. int pxThumbTop;
  1859. int pxThumbBottom;
  1860. int pxMouse;
  1861. int locMouse;
  1862. int dwRange, page, relPos;
  1863. BOOL fSBActive;
  1864. if (fVert) {
  1865. pxTop = lprc->top;
  1866. pxBottom = lprc->bottom;
  1867. pxLeft = lprc->left;
  1868. pxRight = lprc->right;
  1869. cpxArrow = pWState->y_VSBArrow;
  1870. cpxThumb = pWState->y_VSBThumb;
  1871. relPos = pWState->sbVThumbPos - pWState->sbVMinPos;
  1872. page = pWState->sbVPage;
  1873. dwRange = pWState->sbVMaxPos - pWState->sbVMinPos + 1;
  1874. pxMouse = pWState->ptMouse.y;
  1875. fSBActive = pWState->fVActive;
  1876. } else {
  1877. // For horiz scroll bars, "left" & "right" are "top" and "bottom",
  1878. // and vice versa.
  1879. pxTop = lprc->left;
  1880. pxBottom = lprc->right;
  1881. pxLeft = lprc->top;
  1882. pxRight = lprc->bottom;
  1883. cpxArrow = pWState->x_HSBArrow;
  1884. cpxThumb = pWState->x_HSBThumb;
  1885. relPos = pWState->sbHThumbPos - pWState->sbHMinPos;
  1886. page = pWState->sbHPage;
  1887. dwRange = pWState->sbHMaxPos - pWState->sbHMinPos + 1;
  1888. pxMouse = pWState->ptMouse.x;
  1889. fSBActive = pWState->fHActive;
  1890. }
  1891. // For the case of short scroll bars that don't have enough
  1892. // room to fit the full-sized up and down arrows, shorten
  1893. // their sizes to make 'em fit
  1894. cpxArrow = min((pxBottom - pxTop) >> 1, cpxArrow);
  1895. pxUpArrow = pxTop + cpxArrow;
  1896. pxDownArrow = pxBottom - cpxArrow;
  1897. cpxSpace = pxDownArrow - pxUpArrow;
  1898. if (page)
  1899. {
  1900. // JEFFBOG -- This is the one and only place where we should
  1901. // see 'range'. Elsewhere it should be 'range - page'.
  1902. cpxThumb = max(DMultDiv(cpxSpace, page, dwRange),
  1903. min(cpxThumb, MINITHUMBSIZE));
  1904. }
  1905. cpxSpace -= cpxThumb;
  1906. pxThumbTop = DMultDiv(relPos, cpxSpace, dwRange - (page ? page : 1)) + pxUpArrow;
  1907. pxThumbBottom = pxThumbTop + cpxThumb;
  1908. // Save it to local structure
  1909. pWState->pxLeft = pxLeft;
  1910. pWState->pxRight = pxRight;
  1911. pWState->pxTop = pxTop;
  1912. pWState->pxBottom = pxBottom;
  1913. pWState->pxUpArrow = pxUpArrow;
  1914. pWState->pxDownArrow = pxDownArrow;
  1915. pWState->pxThumbTop = pxThumbTop;
  1916. pWState->pxThumbBottom = pxThumbBottom;
  1917. pWState->cpxArrow = cpxArrow;
  1918. pWState->cpxThumb = cpxThumb;
  1919. pWState->cpxSpace = cpxSpace;
  1920. pWState->fVertSB = fVert;
  1921. if (pWState->fTracking) {
  1922. return;
  1923. } else if (!fSBActive) {
  1924. locMouse = WSB_MOUSELOC_OUTSIDE;
  1925. } else if (pxMouse < pxTop) {
  1926. locMouse = WSB_MOUSELOC_OUTSIDE;
  1927. } else if (pxMouse < pxUpArrow) {
  1928. locMouse = WSB_MOUSELOC_ARROWUP;
  1929. } else if (pxMouse < pxThumbTop) {
  1930. locMouse = WSB_MOUSELOC_V_GROOVE;
  1931. } else if (pxMouse >= pxBottom) {
  1932. locMouse = WSB_MOUSELOC_OUTSIDE;
  1933. } else if (pxMouse >= pxDownArrow) {
  1934. locMouse = WSB_MOUSELOC_ARROWDN;
  1935. } else if (pxMouse >= pxThumbBottom) {
  1936. locMouse = WSB_MOUSELOC_V_GROOVE;
  1937. } else { // pxThumbTop <= pxMouse < pxThumbBottom
  1938. if (pxDownArrow - pxUpArrow <= cpxThumb) { // No space for thumnb.
  1939. locMouse = WSB_MOUSELOC_V_GROOVE;
  1940. } else {
  1941. locMouse = WSB_MOUSELOC_V_THUMB;
  1942. }
  1943. }
  1944. if ((!fVert) && locMouse)
  1945. locMouse += 4;
  1946. pWState->locMouse = locMouse;
  1947. }
  1948. //=-------------------------------------------------------------
  1949. // FlatSB_Internal_CalcSBStuff
  1950. //
  1951. // Note:
  1952. // We won't call InitPwSB in this func.
  1953. //=-------------------------------------------------------------
  1954. void FlatSB_Internal_CalcSBStuff(WSBState * pWState, BOOL fVert)
  1955. {
  1956. HWND hwnd;
  1957. RECT rcT;
  1958. int style;
  1959. if (pWState == (WSBState *)NULL)
  1960. return;
  1961. hwnd = pWState->sbHwnd;
  1962. style = GetWindowLong(hwnd, GWL_STYLE);
  1963. if (fVert)
  1964. {
  1965. // Only add on space if vertical scrollbar is really there.
  1966. rcT.right = rcT.left = pWState->rcClient.right;
  1967. if (TestSTYLE(pWState->style, WFVPRESENT))
  1968. rcT.right += pWState->x_VSBArrow;
  1969. rcT.top = pWState->rcClient.top;
  1970. rcT.bottom = pWState->rcClient.bottom;
  1971. }
  1972. else
  1973. {
  1974. // Only add on space if horizontal scrollbar is really there.
  1975. rcT.bottom = rcT.top = pWState->rcClient.bottom;
  1976. if (TestSTYLE(pWState->style, WFHPRESENT))
  1977. rcT.bottom += pWState->y_HSBArrow;
  1978. rcT.left = pWState->rcClient.left;
  1979. rcT.right = pWState->rcClient.right;
  1980. }
  1981. FlatSB_Internal_CalcSBStuff2(pWState, &rcT, fVert);
  1982. }
  1983. //=-------------------------------------------------------------
  1984. // FlatSB_Internal_DrawThumb
  1985. //=-------------------------------------------------------------
  1986. void FlatSB_Internal_DrawThumb(WSBState * pWState, BOOL fVert)
  1987. {
  1988. HWND hwnd = pWState->sbHwnd;
  1989. HDC hdc;
  1990. UINT wDisableFlags;
  1991. hdc = (HDC) GetWindowDC(hwnd);
  1992. FlatSB_Internal_CalcSBStuff(pWState, fVert);
  1993. wDisableFlags = FlatSB_Internal_GetSBFlags(pWState, fVert);
  1994. FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisableFlags);
  1995. ReleaseDC(hwnd, hdc);
  1996. }
  1997. BOOL FlatSB_Internal_SBSetParms(int * pw, SCROLLINFO si, BOOL * lpfScroll, LRESULT * lplres, BOOL bOldPos)
  1998. {
  1999. // pass the struct because we modify the struct but don't want that
  2000. // modified version to get back to the calling app
  2001. BOOL fChanged = FALSE;
  2002. if (bOldPos)
  2003. // save previous position
  2004. *lplres = pw[SBO_POS];
  2005. if (si.fMask & SIF_RANGE)
  2006. {
  2007. // if the range MAX is below the range MIN -- then treat is as a
  2008. // zero range starting at the range MIN.
  2009. if (si.nMax < si.nMin)
  2010. si.nMax = si.nMin;
  2011. if ((pw[SBO_MIN] != si.nMin) || (pw[SBO_MAX] != si.nMax))
  2012. {
  2013. pw[SBO_MIN] = si.nMin;
  2014. pw[SBO_MAX] = si.nMax;
  2015. if (!(si.fMask & SIF_PAGE))
  2016. {
  2017. si.fMask |= SIF_PAGE;
  2018. si.nPage = pw[SBO_PAGE];
  2019. }
  2020. if (!(si.fMask & SIF_POS))
  2021. {
  2022. si.fMask |= SIF_POS;
  2023. si.nPos = pw[SBO_POS];
  2024. }
  2025. fChanged = TRUE;
  2026. }
  2027. }
  2028. if (si.fMask & SIF_PAGE)
  2029. {
  2030. unsigned dwMaxPage = abs(pw[SBO_MAX] - pw[SBO_MIN]) + 1;
  2031. if (si.nPage > dwMaxPage)
  2032. si.nPage = dwMaxPage;
  2033. if (pw[SBO_PAGE] != (int) si.nPage)
  2034. {
  2035. pw[SBO_PAGE] = (int) si.nPage;
  2036. if (!(si.fMask & SIF_POS))
  2037. {
  2038. si.fMask |= SIF_POS;
  2039. si.nPos = pw[SBO_POS];
  2040. }
  2041. fChanged = TRUE;
  2042. }
  2043. }
  2044. if (si.fMask & SIF_POS)
  2045. {
  2046. // Clip pos to posMin, posMax - (page - 1).
  2047. int lMaxPos = pw[SBO_MAX] - ((pw[SBO_PAGE]) ? pw[SBO_PAGE] - 1 : 0);
  2048. // * BOGUS -- show this to SIMONK -- the following doesn't generate *
  2049. // * proper code so I had to use the longer form *
  2050. // * si.nPos = min(max(si.nPos, pw[SBO_MIN]), lMaxPos); *
  2051. if (si.nPos < pw[SBO_MIN])
  2052. si.nPos = pw[SBO_MIN];
  2053. else if (si.nPos > lMaxPos)
  2054. si.nPos = lMaxPos;
  2055. if (pw[SBO_POS] != si.nPos)
  2056. {
  2057. pw[SBO_POS] = si.nPos;
  2058. fChanged = TRUE;
  2059. }
  2060. }
  2061. if (!(bOldPos))
  2062. // Return the new position
  2063. *lplres = pw[SBO_POS];
  2064. if (si.fMask & SIF_RANGE)
  2065. {
  2066. if (*lpfScroll = (pw[SBO_MIN] != pw[SBO_MAX]))
  2067. goto checkPage;
  2068. }
  2069. else if (si.fMask & SIF_PAGE)
  2070. checkPage:
  2071. *lpfScroll = (pw[SBO_PAGE] <= (pw[SBO_MAX] - pw[SBO_MIN]));
  2072. return(fChanged);
  2073. }
  2074. //=-------------------------------------------------------------
  2075. // FlatSB_Internal_SetScrollBar
  2076. //
  2077. // Note:
  2078. // This func is called by SetScrollPos/Range/Info. We let
  2079. // the callers take care of checking pWState.
  2080. // Return 0 if failed.
  2081. //=-------------------------------------------------------------
  2082. LRESULT FlatSB_Internal_SetScrollBar(WSBState *pWState, int code, LPSCROLLINFO lpsi, BOOL fRedraw)
  2083. {
  2084. BOOL fVert;
  2085. int *pw;
  2086. BOOL fOldScroll;
  2087. BOOL fScroll;
  2088. BOOL bReturnOldPos = TRUE;
  2089. LRESULT lres;
  2090. int wfScroll;
  2091. HWND hwnd = pWState->sbHwnd;
  2092. ASSERT (code != SB_CTL);
  2093. // window must be visible to redraw
  2094. if (fRedraw)
  2095. fRedraw = IsWindowVisible(hwnd);
  2096. fVert = (code != SB_HORZ);
  2097. bReturnOldPos = (lpsi->fMask == SIF_POS);
  2098. wfScroll = (fVert) ? WS_VSCROLL : WS_HSCROLL;
  2099. fScroll = fOldScroll = (TestSTYLE(pWState->style, wfScroll)) ? TRUE : FALSE;
  2100. // Don't do anything if we're NOT setting the range and the scroll doesn't
  2101. // exist.
  2102. if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll)
  2103. {
  2104. return(0);
  2105. }
  2106. pw = &(pWState->sbFlags);
  2107. // user.h: SBO_VERT = 5, SBO_HORZ = 1;
  2108. // pw += (fVert) ? SBO_VERT : SBO_HORZ;
  2109. pw += (fVert)? 5 : 1;
  2110. // Keep USER scrollbars in sync for accessibility
  2111. SetScrollInfo(hwnd, code, lpsi, FALSE);
  2112. if (!FlatSB_Internal_SBSetParms(pw, *lpsi, &fScroll, &lres, bReturnOldPos))
  2113. {
  2114. // no change -- but if REDRAW is specified and there's a scrollbar,
  2115. // redraw the thumb
  2116. if (fOldScroll && fRedraw)
  2117. goto redrawAfterSet;
  2118. return(lres);
  2119. }
  2120. if (fScroll)
  2121. pWState->style |= wfScroll;
  2122. else
  2123. pWState->style &= ~wfScroll;
  2124. // Keep style bits in sync so OLEACC can read them
  2125. SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, pWState->style);
  2126. if (lpsi->fMask & SIF_DISABLENOSCROLL)
  2127. {
  2128. if (fOldScroll)
  2129. {
  2130. pWState->style |= wfScroll;
  2131. // Keep style bits in sync so OLEACC can read them
  2132. SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, pWState->style);
  2133. FlatSB_Internal_EnableScrollBar(pWState, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
  2134. }
  2135. }
  2136. else if (fOldScroll ^ fScroll)
  2137. {
  2138. CCInvalidateFrame(hwnd);
  2139. return(lres);
  2140. }
  2141. if (fScroll && fRedraw && (fVert ? TestSTYLE(pWState->style, WFVPRESENT) : TestSTYLE(pWState->style, WFHPRESENT)))
  2142. {
  2143. redrawAfterSet:
  2144. // Don't send this, since USER already sent one for us when we
  2145. // called SetScrollBar.
  2146. // FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_VALUECHANGE, INDEX_SCROLLBAR_SELF);
  2147. // Bail out if the caller is trying to change a scrollbar which is
  2148. // in the middle of tracking. We'll hose FlatSB_Internal_TrackThumb() otherwise.
  2149. // BUGBUG: CalcSBStuff will change locMouse!
  2150. if (pWState->pfnSB == FlatSB_Internal_TrackThumb)
  2151. {
  2152. FlatSB_Internal_CalcSBStuff(pWState, fVert);
  2153. return(lres);
  2154. }
  2155. FlatSB_Internal_DrawThumb(pWState, fVert);
  2156. }
  2157. return(lres);
  2158. }
  2159. //=-------------------------------------------------------------
  2160. // SetScrollPos()
  2161. //=-------------------------------------------------------------
  2162. int WINAPI FlatSB_SetScrollPos(HWND hwnd, int code, int pos, BOOL fRedraw)
  2163. {
  2164. SCROLLINFO si;
  2165. WSBState * pWState;
  2166. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  2167. if (pWState == (WSBState *)NULL) {
  2168. return SetScrollPos(hwnd, code, pos, fRedraw);
  2169. } else if (pWState == WSB_UNINIT_HANDLE) {
  2170. return 0;
  2171. } else if (hwnd != pWState->sbHwnd) {
  2172. return 0;
  2173. }
  2174. si.cbSize = sizeof(si);
  2175. si.fMask = SIF_POS;
  2176. si.nPos = pos;
  2177. return (int)FlatSB_Internal_SetScrollBar(pWState, code, &si, fRedraw);
  2178. }
  2179. //=-------------------------------------------------------------
  2180. // SetScrollRange()
  2181. //=-------------------------------------------------------------
  2182. BOOL WINAPI FlatSB_SetScrollRange(HWND hwnd, int code, int nMin, int nMax, BOOL fRedraw)
  2183. {
  2184. SCROLLINFO si;
  2185. WSBState * pWState;
  2186. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  2187. if (pWState == (WSBState *)NULL) {
  2188. return SetScrollRange(hwnd, code, nMin, nMax, fRedraw);
  2189. } else if (pWState == WSB_UNINIT_HANDLE) {
  2190. pWState = FlatSB_Internal_InitPwSB(hwnd);
  2191. if (pWState == (WSBState *)NULL)
  2192. return FALSE;
  2193. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  2194. DeleteObject(pWState->hbm_Bkg);
  2195. DeleteObject(pWState->hbr_Bkg);
  2196. LocalFree((HLOCAL)pWState);
  2197. return FALSE;
  2198. }
  2199. // In this case we always need to (re)draw the scrollbar.
  2200. fRedraw = TRUE;
  2201. } else if (hwnd != pWState->sbHwnd) {
  2202. return FALSE;
  2203. }
  2204. //
  2205. // Still need MAXINT check for PackRat 4. 32-bit apps don't
  2206. // go thru this--we wrap 'em to SetScrollInfo() on the 32-bit side,
  2207. // so DWORD precision is preserved.
  2208. //
  2209. if ((UINT)(nMax - nMin) > 0x7FFF)
  2210. return FALSE;
  2211. si.cbSize = sizeof(si);
  2212. si.fMask = SIF_RANGE;
  2213. si.nMin = nMin;
  2214. si.nMax = nMax;
  2215. FlatSB_Internal_SetScrollBar(pWState, code, &si, fRedraw);
  2216. return(TRUE);
  2217. }
  2218. //=-------------------------------------------------------------
  2219. // SetScrollInfo()
  2220. //
  2221. // Note:
  2222. // Inconsistent with 'user' code. Under no circumstance will
  2223. // we create a new scrollbar(by allocate a new buffer).
  2224. //=-------------------------------------------------------------
  2225. int WINAPI FlatSB_SetScrollInfo(HWND hwnd, int code, LPSCROLLINFO lpsi, BOOL fRedraw)
  2226. {
  2227. WSBState * pWState;
  2228. // ZDC@Oct. 10, Detect GP faults here.
  2229. if ((LPSCROLLINFO)NULL == lpsi)
  2230. return FALSE;
  2231. if (lpsi->cbSize < sizeof (SCROLLINFO))
  2232. return FALSE;
  2233. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  2234. if (pWState == (WSBState *)NULL) {
  2235. return SetScrollInfo(hwnd, code, lpsi, fRedraw);
  2236. } else if (pWState == WSB_UNINIT_HANDLE) {
  2237. if (!(lpsi->fMask & SIF_RANGE))
  2238. return 0;
  2239. pWState = FlatSB_Internal_InitPwSB(hwnd);
  2240. if (pWState == (WSBState *)NULL)
  2241. return 0;
  2242. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  2243. DeleteObject(pWState->hbm_Bkg);
  2244. DeleteObject(pWState->hbr_Bkg);
  2245. LocalFree((HLOCAL)pWState);
  2246. return 0;
  2247. }
  2248. // In this case we always need to (re)draw the scrollbar.
  2249. fRedraw = TRUE;
  2250. } else if (hwnd != pWState->sbHwnd) {
  2251. return 0;
  2252. }
  2253. // ZDC@Oct 9, We should always return new pos. How ever, if the fMask
  2254. // is SIF_POS, SetScrollBar returns the old pos.
  2255. if (lpsi->fMask == SIF_POS)
  2256. lpsi->fMask = SIF_POS | SIF_TRACKPOS;
  2257. return (int)FlatSB_Internal_SetScrollBar(pWState, code, lpsi, fRedraw);
  2258. }
  2259. //=-------------------------------------------------------------
  2260. // FlatSB_SetScrollProp
  2261. // This functions shouldn't be called we we are tracking.
  2262. //=-------------------------------------------------------------
  2263. BOOL WINAPI FlatSB_SetScrollProp(HWND hwnd, UINT index, INT_PTR newValue, BOOL fRedraw)
  2264. {
  2265. BOOL fResize = FALSE;
  2266. BOOL fVert = FALSE;
  2267. WSBState * pWState;
  2268. GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
  2269. if (pWState == (WSBState *)NULL)
  2270. return FALSE;
  2271. else if (pWState == WSB_UNINIT_HANDLE) {
  2272. pWState = FlatSB_Internal_InitPwSB(hwnd);
  2273. if (pWState == (WSBState *)NULL)
  2274. return 0;
  2275. else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
  2276. DeleteObject(pWState->hbm_Bkg);
  2277. DeleteObject(pWState->hbr_Bkg);
  2278. LocalFree((HLOCAL)pWState);
  2279. return 0;
  2280. }
  2281. // In this case we don't want to (re)draw the scrollbar.
  2282. fRedraw = FALSE;
  2283. }
  2284. if (pWState->fTracking)
  2285. return FALSE;
  2286. switch (index) {
  2287. case WSB_PROP_CXVSCROLL:
  2288. if ((int)newValue == pWState->metApp.cxVSBArrow)
  2289. return TRUE;
  2290. pWState->metApp.cxVSBArrow = (int)newValue;
  2291. fResize = TRUE;
  2292. break;
  2293. case WSB_PROP_CXHSCROLL:
  2294. if ((int)newValue == pWState->metApp.cxHSBArrow)
  2295. return TRUE;
  2296. pWState->metApp.cxHSBArrow = (int)newValue;
  2297. fResize = TRUE;
  2298. break;
  2299. case WSB_PROP_CYVSCROLL:
  2300. if ((int)newValue == pWState->metApp.cyVSBArrow)
  2301. return TRUE;
  2302. pWState->metApp.cyVSBArrow = (int)newValue;
  2303. fResize = TRUE;
  2304. break;
  2305. case WSB_PROP_CYHSCROLL:
  2306. if ((int)newValue == pWState->metApp.cyHSBArrow)
  2307. return TRUE;
  2308. pWState->metApp.cyHSBArrow = (int)newValue;
  2309. fResize = TRUE;
  2310. break;
  2311. case WSB_PROP_CXHTHUMB:
  2312. if ((int)newValue == pWState->metApp.cxHSBThumb)
  2313. return TRUE;
  2314. pWState->metApp.cxHSBThumb = (int)newValue;
  2315. fResize = TRUE;
  2316. break;
  2317. case WSB_PROP_CYVTHUMB:
  2318. if ((int)newValue == pWState->metApp.cyVSBThumb)
  2319. return TRUE;
  2320. pWState->metApp.cyVSBThumb = (int)newValue;
  2321. fResize = TRUE;
  2322. break;
  2323. case WSB_PROP_VBKGCOLOR:
  2324. if ((COLORREF)newValue == pWState->col_VSBBkg)
  2325. return TRUE;
  2326. pWState->col_VSBBkg = (COLORREF)newValue;
  2327. fVert = TRUE;
  2328. break;
  2329. case WSB_PROP_HBKGCOLOR:
  2330. if ((COLORREF)newValue == pWState->col_HSBBkg)
  2331. return TRUE;
  2332. pWState->col_HSBBkg = (COLORREF)newValue;
  2333. break;
  2334. case WSB_PROP_PALETTE:
  2335. if ((HPALETTE)newValue == pWState->hPalette)
  2336. return TRUE;
  2337. pWState->hPalette = (HPALETTE)newValue;
  2338. break;
  2339. case WSB_PROP_VSTYLE:
  2340. if ((int)newValue == pWState->vStyle)
  2341. return TRUE;
  2342. pWState->vStyle = (int)newValue;
  2343. fVert = TRUE;
  2344. break;
  2345. case WSB_PROP_HSTYLE:
  2346. if ((int)newValue == pWState->hStyle)
  2347. return TRUE;
  2348. pWState->hStyle = (int)newValue;
  2349. break;
  2350. case WSB_PROP_GUTTER:
  2351. if ((int)newValue == pWState->sbGutter)
  2352. return TRUE;
  2353. pWState->sbGutter = (int)newValue;
  2354. break;
  2355. default:
  2356. return FALSE;
  2357. }
  2358. if (fResize) {
  2359. // Always redraw after we change the size.
  2360. CCInvalidateFrame(hwnd);
  2361. } else if (fRedraw) {
  2362. HDC hdc;
  2363. int oldLoc = pWState->locMouse;
  2364. int fSBActive = (fVert)?pWState->fVActive:pWState->fHActive;
  2365. hdc = GetWindowDC(hwnd);
  2366. FlatSB_Internal_DrawScrollBar(pWState, hdc, fVert, FALSE /* Not redraw*/);
  2367. if (!fSBActive)
  2368. pWState->locMouse = oldLoc;
  2369. ReleaseDC(hwnd, hdc);
  2370. }
  2371. return TRUE;
  2372. }
  2373. //=-------------------------------------------------------------
  2374. // FlatSB_Internal_DrawScrollBar()
  2375. //=-------------------------------------------------------------
  2376. void FlatSB_Internal_DrawScrollBar(WSBState * pWState, HDC hdc, BOOL fVert, BOOL fRedraw)
  2377. {
  2378. int oldLoc = pWState->locMouse;
  2379. FlatSB_Internal_CalcSBStuff(pWState, fVert);
  2380. if ((!fRedraw) || oldLoc != pWState->locMouse)
  2381. FlatSB_Internal_DrawSB2(pWState, hdc, fVert, fRedraw, oldLoc);
  2382. }
  2383. //=------------------------------------------------------------
  2384. // FlatSB_Internal_IsSizeBox
  2385. // It's still an incomplete mimic of SizeBoxWnd in user/winwhere.c
  2386. //=------------------------------------------------------------
  2387. BOOL FlatSB_Internal_IsSizeBox(HWND hwndStart)
  2388. {
  2389. int style;
  2390. HWND hwnd, hwndDesktop;
  2391. int cxEdge, cyEdge;
  2392. RECT rcChild, rcParent;
  2393. ASSERT(hwndStart);
  2394. hwnd = hwndStart;
  2395. hwndDesktop = GetDesktopWindow();
  2396. cxEdge = GetSystemMetrics(SM_CXEDGE);
  2397. cyEdge = GetSystemMetrics(SM_CYEDGE);
  2398. if (!GetWindowRect(hwnd, &rcChild))
  2399. return FALSE;
  2400. do {
  2401. style = GetWindowStyle(hwnd);
  2402. if (TestSTYLE(style, WS_SIZEBOX)) {
  2403. if (IsZoomed(hwnd))
  2404. return FALSE;
  2405. else {
  2406. POINT pt;
  2407. GetClientRect(hwnd, &rcParent);
  2408. pt.x = rcParent.right;
  2409. pt.y = rcParent.bottom;
  2410. ClientToScreen(hwnd, &pt);
  2411. if (rcChild.right + cxEdge < pt.x)
  2412. return FALSE;
  2413. if (rcChild.bottom + cyEdge < pt.y)
  2414. return FALSE;
  2415. return TRUE;
  2416. }
  2417. } else {
  2418. hwnd = GetParent(hwnd);
  2419. }
  2420. }
  2421. while ((hwnd) && (hwnd != hwndDesktop));
  2422. return FALSE;
  2423. }