Leaked source code of windows server 2003
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.

3011 lines
90 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: sbctl.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Scroll bar internal routines
  7. *
  8. * History:
  9. * 11/21/90 JimA Created.
  10. * 02-04-91 IanJa Revalidaion added
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. void CalcSBStuff(
  15. PWND pwnd,
  16. PSBCALC pSBCalc,
  17. BOOL fVert);
  18. #define IsScrollBarControl(h) (GETFNID(h) == FNID_SCROLLBAR)
  19. /*
  20. * Now it is possible to selectively Enable/Disable just one arrow of a Window
  21. * scroll bar; Various bits in the 7th word in the rgwScroll array indicates which
  22. * one of these arrows are disabled; The following masks indicate which bit of the
  23. * word indicates which arrow;
  24. */
  25. #define WSB_HORZ_LF 0x0001 // Represents the Left arrow of the horizontal scroll bar.
  26. #define WSB_HORZ_RT 0x0002 // Represents the Right arrow of the horizontal scroll bar.
  27. #define WSB_VERT_UP 0x0004 // Represents the Up arrow of the vert scroll bar.
  28. #define WSB_VERT_DN 0x0008 // Represents the Down arrow of the vert scroll bar.
  29. #define WSB_VERT (WSB_VERT_UP | WSB_VERT_DN)
  30. #define WSB_HORZ (WSB_HORZ_LF | WSB_HORZ_RT)
  31. void DrawCtlThumb(PSBWND);
  32. /*
  33. * RETURN_IF_PSBTRACK_INVALID:
  34. * This macro tests whether the pSBTrack we have is invalid, which can happen
  35. * if it gets freed during a callback.
  36. * This protects agains the original pSBTrack being freed and no new one
  37. * being allocated or a new one being allocated at a different address.
  38. * This does not protect against the original pSBTrack being freed and a new
  39. * one being allocated at the same address.
  40. * If pSBTrack has changed, we assert that there is not already a new one
  41. * because we are really not expecting this.
  42. */
  43. #define RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd) \
  44. if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \
  45. UserAssert(PWNDTOPSBTRACK(pwnd) == NULL); \
  46. return; \
  47. }
  48. /*
  49. * REEVALUATE_PSBTRACK
  50. * This macro just refreshes the local variable pSBTrack, in case it has
  51. * been changed during a callback. After performing this operation, pSBTrack
  52. * should be tested to make sure it is not now NULL.
  53. */
  54. #if DBG
  55. #define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
  56. if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \
  57. RIPMSG3(RIP_VERBOSE, \
  58. "%s: pSBTrack changed from %#p to %#p", \
  59. (str), (pSBTrack), PWNDTOPSBTRACK(pwnd)); \
  60. } \
  61. (pSBTrack) = PWNDTOPSBTRACK(pwnd)
  62. #else
  63. #define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
  64. (pSBTrack) = PWNDTOPSBTRACK(pwnd)
  65. #endif
  66. /***************************************************************************\
  67. * HitTestScrollBar
  68. *
  69. * 11/15/96 vadimg ported from Memphis sources
  70. \***************************************************************************/
  71. int HitTestScrollBar(PWND pwnd, BOOL fVert, POINT pt)
  72. {
  73. UINT wDisable;
  74. int px;
  75. BOOL fCtl = IsScrollBarControl(pwnd);
  76. SBCALC SBCalc, *pSBCalc;
  77. if (fCtl) {
  78. wDisable = ((PSBWND)pwnd)->wDisableFlags;
  79. } else {
  80. //
  81. // Reflect the click coordinates on the horizontal
  82. // scroll bar if the window is mirrored
  83. //
  84. if (TestWF(pwnd,WEFLAYOUTRTL) && !fVert) {
  85. pt.x = pwnd->rcWindow.right - pt.x;
  86. } else {
  87. pt.x -= pwnd->rcWindow.left;
  88. }
  89. pt.y -= pwnd->rcWindow.top;
  90. wDisable = GetWndSBDisableFlags(pwnd, fVert);
  91. }
  92. if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  93. return HTERROR;
  94. }
  95. if (fCtl) {
  96. pSBCalc = &(((PSBWND)pwnd)->SBCalc);
  97. } else {
  98. pSBCalc = &SBCalc;
  99. CalcSBStuff(pwnd, pSBCalc, fVert);
  100. }
  101. px = fVert ? pt.y : pt.x;
  102. if (px < pSBCalc->pxUpArrow) {
  103. if (wDisable & LTUPFLAG) {
  104. return HTERROR;
  105. }
  106. return HTSCROLLUP;
  107. } else if (px >= pSBCalc->pxDownArrow) {
  108. if (wDisable & RTDNFLAG) {
  109. return HTERROR;
  110. }
  111. return HTSCROLLDOWN;
  112. } else if (px < pSBCalc->pxThumbTop) {
  113. return HTSCROLLUPPAGE;
  114. } else if (px < pSBCalc->pxThumbBottom) {
  115. return HTSCROLLTHUMB;
  116. } else if (px < pSBCalc->pxDownArrow) {
  117. return HTSCROLLDOWNPAGE;
  118. }
  119. return HTERROR;
  120. }
  121. BOOL _SBGetParms(
  122. PWND pwnd,
  123. int code,
  124. PSBDATA pw,
  125. LPSCROLLINFO lpsi)
  126. {
  127. PSBTRACK pSBTrack;
  128. pSBTrack = PWNDTOPSBTRACK(pwnd);
  129. if (lpsi->fMask & SIF_RANGE) {
  130. lpsi->nMin = pw->posMin;
  131. lpsi->nMax = pw->posMax;
  132. }
  133. if (lpsi->fMask & SIF_PAGE)
  134. lpsi->nPage = pw->page;
  135. if (lpsi->fMask & SIF_POS) {
  136. lpsi->nPos = pw->pos;
  137. }
  138. if (lpsi->fMask & SIF_TRACKPOS)
  139. {
  140. if (pSBTrack && (pSBTrack->nBar == code) && (pSBTrack->spwndTrack == pwnd)) {
  141. // posNew is in the context of psbiSB's window and bar code
  142. lpsi->nTrackPos = pSBTrack->posNew;
  143. } else {
  144. lpsi->nTrackPos = pw->pos;
  145. }
  146. }
  147. return ((lpsi->fMask & SIF_ALL) ? TRUE : FALSE);
  148. }
  149. /***************************************************************************\
  150. * GetWndSBDisableFlags
  151. *
  152. * This returns the scroll bar Disable flags of the scroll bars of a
  153. * given Window.
  154. *
  155. *
  156. * History:
  157. * 4-18-91 MikeHar Ported for the 31 merge
  158. \***************************************************************************/
  159. UINT GetWndSBDisableFlags(
  160. PWND pwnd, // The window whose scroll bar Disable Flags are to be returned;
  161. BOOL fVert) // If this is TRUE, it means Vertical scroll bar.
  162. {
  163. PSBINFO pw;
  164. if ((pw = pwnd->pSBInfo) == NULL) {
  165. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  166. return 0;
  167. }
  168. return (fVert ? (pw->WSBflags & WSB_VERT) >> 2 : pw->WSBflags & WSB_HORZ);
  169. }
  170. /***************************************************************************\
  171. * xxxEnableSBCtlArrows()
  172. *
  173. * This function can be used to selectively Enable/Disable
  174. * the arrows of a scroll bar Control
  175. *
  176. * History:
  177. * 04-18-91 MikeHar Ported for the 31 merge
  178. \***************************************************************************/
  179. BOOL xxxEnableSBCtlArrows(
  180. PWND pwnd,
  181. UINT wArrows)
  182. {
  183. UINT wOldFlags;
  184. UINT wNewFlags;
  185. CheckLock(pwnd);
  186. UserAssert(IsWinEventNotifyDeferredOK());
  187. wOldFlags = ((PSBWND)pwnd)->wDisableFlags; // Get the original status
  188. if (wArrows == ESB_ENABLE_BOTH) { // Enable both the arrows
  189. ((PSBWND)pwnd)->wDisableFlags &= ~SB_DISABLE_MASK;
  190. } else {
  191. ((PSBWND)pwnd)->wDisableFlags |= wArrows;
  192. }
  193. /*
  194. * Check if the status has changed because of this call
  195. */
  196. if (wOldFlags == ((PSBWND)pwnd)->wDisableFlags)
  197. return FALSE;
  198. /*
  199. * Else, redraw the scroll bar control to reflect the new state
  200. */
  201. if (IsVisible(pwnd))
  202. xxxInvalidateRect(pwnd, NULL, TRUE);
  203. wNewFlags = ((PSBWND)pwnd)->wDisableFlags;
  204. /*
  205. * state change notifications
  206. */
  207. if ((wOldFlags & ESB_DISABLE_UP) != (wNewFlags & ESB_DISABLE_UP)) {
  208. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
  209. INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
  210. }
  211. if ((wOldFlags & ESB_DISABLE_DOWN) != (wNewFlags & ESB_DISABLE_DOWN)) {
  212. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
  213. INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
  214. }
  215. return TRUE;
  216. }
  217. /***************************************************************************\
  218. * xxxEnableWndSBArrows()
  219. *
  220. * This function can be used to selectively Enable/Disable
  221. * the arrows of a Window Scroll bar(s)
  222. *
  223. * History:
  224. * 4-18-91 MikeHar Ported for the 31 merge
  225. \***************************************************************************/
  226. BOOL xxxEnableWndSBArrows(
  227. PWND pwnd,
  228. UINT wSBflags,
  229. UINT wArrows)
  230. {
  231. INT wOldFlags;
  232. PSBINFO pw;
  233. BOOL bRetValue = FALSE;
  234. HDC hdc;
  235. CheckLock(pwnd);
  236. UserAssert(IsWinEventNotifyDeferredOK());
  237. if ((pw = pwnd->pSBInfo) != NULL) {
  238. wOldFlags = pw->WSBflags;
  239. } else {
  240. /*
  241. * Originally everything is enabled; Check to see if this function is
  242. * asked to disable anything; Otherwise, no change in status; So, must
  243. * return immediately;
  244. */
  245. if(!wArrows)
  246. return FALSE; // No change in status!
  247. wOldFlags = 0; // Both are originally enabled;
  248. if((pw = _InitPwSB(pwnd)) == NULL) // Allocate the pSBInfo for hWnd
  249. return FALSE;
  250. }
  251. if((hdc = _GetWindowDC(pwnd)) == NULL)
  252. return FALSE;
  253. /*
  254. * First Take care of the Horizontal Scroll bar, if one exists.
  255. */
  256. if((wSBflags == SB_HORZ) || (wSBflags == SB_BOTH)) {
  257. if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
  258. pw->WSBflags &= ~SB_DISABLE_MASK;
  259. else
  260. pw->WSBflags |= wArrows;
  261. /*
  262. * Update the display of the Horizontal Scroll Bar;
  263. */
  264. if(pw->WSBflags != wOldFlags) {
  265. bRetValue = TRUE;
  266. wOldFlags = pw->WSBflags;
  267. if (TestWF(pwnd, WFHPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
  268. IsVisible(pwnd)) {
  269. xxxDrawScrollBar(pwnd, hdc, FALSE); // Horizontal Scroll Bar.
  270. }
  271. }
  272. // Left button
  273. if ((wOldFlags & ESB_DISABLE_LEFT) != (pw->WSBflags & ESB_DISABLE_LEFT)) {
  274. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
  275. INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
  276. }
  277. // Right button
  278. if ((wOldFlags & ESB_DISABLE_RIGHT) != (pw->WSBflags & ESB_DISABLE_RIGHT)) {
  279. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
  280. INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
  281. }
  282. }
  283. /*
  284. * Then take care of the Vertical Scroll bar, if one exists.
  285. */
  286. if((wSBflags == SB_VERT) || (wSBflags == SB_BOTH)) {
  287. if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
  288. pw->WSBflags &= ~(SB_DISABLE_MASK << 2);
  289. else
  290. pw->WSBflags |= (wArrows << 2);
  291. /*
  292. * Update the display of the Vertical Scroll Bar;
  293. */
  294. if(pw->WSBflags != wOldFlags) {
  295. bRetValue = TRUE;
  296. if (TestWF(pwnd, WFVPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
  297. IsVisible(pwnd)) {
  298. xxxDrawScrollBar(pwnd, hdc, TRUE); // Vertical Scroll Bar
  299. }
  300. // Up button
  301. if ((wOldFlags & (ESB_DISABLE_UP << 2)) != (pw->WSBflags & (ESB_DISABLE_UP << 2))) {
  302. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
  303. INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
  304. }
  305. // Down button
  306. if ((wOldFlags & (ESB_DISABLE_DOWN << 2)) != (pw->WSBflags & (ESB_DISABLE_DOWN << 2))) {
  307. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
  308. INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
  309. }
  310. }
  311. }
  312. _ReleaseDC(hdc);
  313. return bRetValue;
  314. }
  315. /***************************************************************************\
  316. * EnableScrollBar()
  317. *
  318. * This function can be used to selectively Enable/Disable
  319. * the arrows of a scroll bar; It could be used with Windows Scroll
  320. * bars as well as scroll bar controls
  321. *
  322. * History:
  323. * 4-18-91 MikeHar Ported for the 31 merge
  324. \***************************************************************************/
  325. BOOL xxxEnableScrollBar(
  326. PWND pwnd,
  327. UINT wSBflags, // Whether it is a Window Scroll Bar; if so, HORZ or VERT?
  328. // Possible values are SB_HORZ, SB_VERT, SB_CTL or SB_BOTH
  329. UINT wArrows) // Which arrows must be enabled/disabled:
  330. // ESB_ENABLE_BOTH = > Enable both arrows.
  331. // ESB_DISABLE_LTUP = > Disable Left/Up arrow;
  332. // ESB_DISABLE_RTDN = > DIsable Right/Down arrow;
  333. // ESB_DISABLE_BOTH = > Disable both the arrows;
  334. {
  335. #define ES_NOTHING 0
  336. #define ES_DISABLE 1
  337. #define ES_ENABLE 2
  338. UINT wOldFlags;
  339. UINT wEnableWindow;
  340. CheckLock(pwnd);
  341. if(wSBflags != SB_CTL) {
  342. return xxxEnableWndSBArrows(pwnd, wSBflags, wArrows);
  343. }
  344. /*
  345. * Let us assume that we don't have to call EnableWindow
  346. */
  347. wEnableWindow = ES_NOTHING;
  348. wOldFlags = ((PSBWND)pwnd)->wDisableFlags & (UINT)SB_DISABLE_MASK;
  349. /*
  350. * Check if the present state of the arrows is exactly the same
  351. * as what the caller wants:
  352. */
  353. if (wOldFlags == wArrows)
  354. return FALSE ; // If so, nothing needs to be done;
  355. /*
  356. * Check if the caller wants to disable both the arrows
  357. */
  358. if (wArrows == ESB_DISABLE_BOTH) {
  359. wEnableWindow = ES_DISABLE; // Yes! So, disable the whole SB Ctl.
  360. } else {
  361. /*
  362. * Check if the caller wants to enable both the arrows
  363. */
  364. if(wArrows == ESB_ENABLE_BOTH) {
  365. /*
  366. * We need to enable the SB Ctl only if it was already disabled.
  367. */
  368. if(wOldFlags == ESB_DISABLE_BOTH)
  369. wEnableWindow = ES_ENABLE;// EnableWindow(.., TRUE);
  370. } else {
  371. /*
  372. * Now, Caller wants to disable only one arrow;
  373. * Check if one of the arrows was already disabled and we want
  374. * to disable the other;If so, the whole SB Ctl will have to be
  375. * disabled; Check if this is the case:
  376. */
  377. if((wOldFlags | wArrows) == ESB_DISABLE_BOTH)
  378. wEnableWindow = ES_DISABLE; // EnableWindow(, FALSE);
  379. }
  380. }
  381. if(wEnableWindow != ES_NOTHING) {
  382. /*
  383. * EnableWindow returns old state of the window; We must return
  384. * TRUE only if the Old state is different from new state.
  385. */
  386. if(xxxEnableWindow(pwnd, (BOOL)(wEnableWindow == ES_ENABLE))) {
  387. return !(TestWF(pwnd, WFDISABLED));
  388. } else {
  389. return TestWF(pwnd, WFDISABLED);
  390. }
  391. }
  392. return (BOOL)xxxSendMessage(pwnd, SBM_ENABLE_ARROWS, (DWORD)wArrows, 0);
  393. #undef ES_NOTHING
  394. #undef ES_DISABLE
  395. #undef ES_ENABLE
  396. }
  397. /***************************************************************************\
  398. *
  399. * DrawSize() -
  400. *
  401. \***************************************************************************/
  402. void FAR DrawSize(PWND pwnd, HDC hdc, int cxFrame,int cyFrame)
  403. {
  404. int x, y;
  405. //HBRUSH hbrSave;
  406. if (TestWF(pwnd, WEFLEFTSCROLL)) {
  407. x = cxFrame;
  408. } else {
  409. x = pwnd->rcWindow.right - pwnd->rcWindow.left - cxFrame - SYSMET(CXVSCROLL);
  410. }
  411. y = pwnd->rcWindow.bottom - pwnd->rcWindow.top - cyFrame - SYSMET(CYHSCROLL);
  412. // If we have a scrollbar control, or the sizebox is not associated with
  413. // a sizeable window, draw the flat gray sizebox. Otherwise, use the
  414. // sizing grip.
  415. if (IsScrollBarControl(pwnd))
  416. {
  417. if (TestWF(pwnd, SBFSIZEGRIP))
  418. goto DrawSizeGrip;
  419. else
  420. goto DrawBox;
  421. }
  422. else if (!SizeBoxHwnd(pwnd))
  423. {
  424. DrawBox:
  425. {
  426. //hbrSave = GreSelectBrush(hdc, SYSHBR(3DFACE));
  427. //GrePatBlt(hdc, x, y, SYSMET(CXVSCROLL), SYSMET(CYHSCROLL), PATCOPY);
  428. //GreSelectBrush(hdc, hbrSave);
  429. POLYPATBLT PolyData;
  430. PolyData.x = x;
  431. PolyData.y = y;
  432. PolyData.cx = SYSMET(CXVSCROLL);
  433. PolyData.cy = SYSMET(CYHSCROLL);
  434. PolyData.BrClr.hbr = SYSHBR(3DFACE);
  435. GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
  436. }
  437. }
  438. else
  439. {
  440. DrawSizeGrip:
  441. // Blt out the grip bitmap.
  442. BitBltSysBmp(hdc, x, y, TestWF(pwnd, WEFLEFTSCROLL) ? OBI_NCGRIP_L : OBI_NCGRIP);
  443. }
  444. }
  445. /***************************************************************************\
  446. * xxxSelectColorObjects
  447. *
  448. *
  449. *
  450. * History:
  451. \***************************************************************************/
  452. HBRUSH xxxGetColorObjects(
  453. PWND pwnd,
  454. HDC hdc)
  455. {
  456. HBRUSH hbrRet;
  457. CheckLock(pwnd);
  458. // Use the scrollbar color even if the scrollbar is disabeld.
  459. if (!IsScrollBarControl(pwnd))
  460. hbrRet = (HBRUSH)xxxDefWindowProc(pwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(pwnd));
  461. else {
  462. // B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
  463. // owner. If the app doesn't process the message, DefWindowProc32
  464. // will always return the appropriate system brush. If the app.
  465. // returns an invalid object, GetControlBrush will call DWP for
  466. // the default brush. Thus hbrRet doesn't need any validation
  467. // here.
  468. hbrRet = xxxGetControlBrush(pwnd, hdc, WM_CTLCOLORSCROLLBAR);
  469. }
  470. return hbrRet;
  471. }
  472. /***************************************************************************\
  473. *
  474. * DrawGroove()
  475. *
  476. * Draws lines & middle of thumb groove
  477. * Note that pw points into prc. Moreover, note that both pw & prc are
  478. * NEAR pointers, so *prc better not be on the stack.
  479. *
  480. \***************************************************************************/
  481. void NEAR DrawGroove(HDC hdc, HBRUSH hbr, LPRECT prc, BOOL fVert)
  482. {
  483. if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == gpsi->hbrGray))
  484. FillRect(hdc, prc, hbr);
  485. else
  486. {
  487. RECT rc;
  488. // Draw sides
  489. CopyRect(&rc, prc);
  490. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT |
  491. (fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
  492. // Fill middle
  493. FillRect(hdc, &rc, hbr);
  494. }
  495. }
  496. /***************************************************************************\
  497. * CalcTrackDragRect
  498. *
  499. * Give the rectangle for a scrollbar in pSBTrack->pSBCalc,
  500. * calculate pSBTrack->rcTrack, the rectangle where tracking
  501. * may occur without cancelling the thumbdrag operation.
  502. *
  503. \***************************************************************************/
  504. void CalcTrackDragRect(PSBTRACK pSBTrack) {
  505. int cx;
  506. int cy;
  507. LPINT pwX, pwY;
  508. //
  509. // Point pwX and pwY at the parts of the rectangle
  510. // corresponding to pSBCalc->pxLeft, pxTop, etc.
  511. //
  512. // pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
  513. // scrollbar and the top edge of horizontal one.
  514. // pSBTrack->pSBCalc->pxTop is the top of a vertical
  515. // scrollbar and the left of horizontal one.
  516. // etc...
  517. //
  518. // Point pwX and pwY to the corresponding parts
  519. // of pSBTrack->rcTrack.
  520. //
  521. pwX = pwY = (LPINT)&pSBTrack->rcTrack;
  522. if (pSBTrack->fTrackVert) {
  523. cy = SYSMET(CYVTHUMB);
  524. pwY++;
  525. } else {
  526. cy = SYSMET(CXHTHUMB);
  527. pwX++;
  528. }
  529. /*
  530. * Later5.0 GerardoB: People keep complaining about this tracking region
  531. * being too narrow so let's make it wider while PM decides what to do
  532. * about it.
  533. * We also used to have some hard coded min and max values but that should
  534. * depend on some metric, if at all needed.
  535. */
  536. cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8;
  537. cy *= 2;
  538. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx;
  539. *(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy;
  540. *(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx;
  541. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy;
  542. }
  543. void RecalcTrackRect(PSBTRACK pSBTrack) {
  544. LPINT pwX, pwY;
  545. RECT rcSB;
  546. if (!pSBTrack->fCtlSB)
  547. CalcSBStuff(pSBTrack->spwndTrack, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
  548. pwX = (LPINT)&rcSB;
  549. pwY = pwX + 1;
  550. if (!pSBTrack->fTrackVert)
  551. pwX = pwY--;
  552. *(pwX + 0) = pSBTrack->pSBCalc->pxLeft;
  553. *(pwY + 0) = pSBTrack->pSBCalc->pxTop;
  554. *(pwX + 2) = pSBTrack->pSBCalc->pxRight;
  555. *(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
  556. switch(pSBTrack->cmdSB) {
  557. case SB_LINEUP:
  558. *(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow;
  559. break;
  560. case SB_LINEDOWN:
  561. *(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow;
  562. break;
  563. case SB_PAGEUP:
  564. *(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow;
  565. *(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop;
  566. break;
  567. case SB_THUMBPOSITION:
  568. CalcTrackDragRect(pSBTrack);
  569. break;
  570. case SB_PAGEDOWN:
  571. *(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom;
  572. *(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow;
  573. break;
  574. }
  575. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  576. CopyRect(&pSBTrack->rcTrack, &rcSB);
  577. }
  578. }
  579. /***************************************************************************\
  580. * DrawThumb2
  581. *
  582. *
  583. *
  584. * History:
  585. * 01-03-94 FritzS Chicago changes
  586. \***************************************************************************/
  587. void DrawThumb2(
  588. PWND pwnd,
  589. PSBCALC pSBCalc,
  590. HDC hdc,
  591. HBRUSH hbr,
  592. BOOL fVert,
  593. UINT wDisable) /* Disabled flags for the scroll bar */
  594. {
  595. int *pLength;
  596. int *pWidth;
  597. RECT rcSB;
  598. PSBTRACK pSBTrack;
  599. //
  600. // Bail out if the scrollbar has an empty rect
  601. //
  602. if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight))
  603. return;
  604. pLength = (LPINT)&rcSB;
  605. if (fVert)
  606. pWidth = pLength++;
  607. else
  608. pWidth = pLength + 1;
  609. pWidth[0] = pSBCalc->pxLeft;
  610. pWidth[2] = pSBCalc->pxRight;
  611. /*
  612. * If both scroll bar arrows are disabled, then we should not draw
  613. * the thumb. So, quit now!
  614. */
  615. if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
  616. ((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb)) {
  617. pLength[0] = pSBCalc->pxUpArrow;
  618. pLength[2] = pSBCalc->pxDownArrow;
  619. DrawGroove(hdc, hbr, &rcSB, fVert);
  620. return;
  621. }
  622. if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop) {
  623. // Fill in space above Thumb
  624. pLength[0] = pSBCalc->pxUpArrow;
  625. pLength[2] = pSBCalc->pxThumbTop;
  626. DrawGroove(hdc, hbr, &rcSB, fVert);
  627. }
  628. if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow) {
  629. // Fill in space below Thumb
  630. pLength[0] = pSBCalc->pxThumbBottom;
  631. pLength[2] = pSBCalc->pxDownArrow;
  632. DrawGroove(hdc, hbr, &rcSB, fVert);
  633. }
  634. //
  635. // Draw elevator
  636. //
  637. pLength[0] = pSBCalc->pxThumbTop;
  638. pLength[2] = pSBCalc->pxThumbBottom;
  639. // Not soft!
  640. DrawPushButton(hdc, &rcSB, 0, 0);
  641. /*
  642. * If we're tracking a page scroll, then we've obliterated the hilite.
  643. * We need to correct the hiliting rectangle, and rehilite it.
  644. */
  645. pSBTrack = PWNDTOPSBTRACK(pwnd);
  646. if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) &&
  647. (pwnd == pSBTrack->spwndTrack) &&
  648. (BOOL)pSBTrack->fTrackVert == fVert) {
  649. if (pSBTrack->fTrackRecalc) {
  650. RecalcTrackRect(pSBTrack);
  651. pSBTrack->fTrackRecalc = FALSE;
  652. }
  653. pLength = (int *)&pSBTrack->rcTrack;
  654. if (fVert)
  655. pLength++;
  656. if (pSBTrack->cmdSB == SB_PAGEUP)
  657. pLength[2] = pSBCalc->pxThumbTop;
  658. else
  659. pLength[0] = pSBCalc->pxThumbBottom;
  660. if (pLength[0] < pLength[2])
  661. InvertRect(hdc, &pSBTrack->rcTrack);
  662. }
  663. }
  664. /***************************************************************************\
  665. * xxxDrawSB2
  666. *
  667. *
  668. *
  669. * History:
  670. \***************************************************************************/
  671. void xxxDrawSB2(
  672. PWND pwnd,
  673. PSBCALC pSBCalc,
  674. HDC hdc,
  675. BOOL fVert,
  676. UINT wDisable)
  677. {
  678. int cLength;
  679. int cWidth;
  680. int *pwX;
  681. int *pwY;
  682. HBRUSH hbr;
  683. HBRUSH hbrSave;
  684. int cpxArrow;
  685. RECT rc, rcSB;
  686. COLORREF crText, crBk;
  687. CheckLock(pwnd);
  688. cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2;
  689. cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
  690. if ((cLength <= 0) || (cWidth <= 0)) {
  691. return;
  692. }
  693. if (fVert)
  694. cpxArrow = SYSMET(CYVSCROLL);
  695. else
  696. cpxArrow = SYSMET(CXHSCROLL);
  697. /*
  698. * Save background and DC color, since they get changed in
  699. * xxxGetColorObjects. Restore before we return.
  700. */
  701. crBk = GreGetBkColor(hdc);
  702. crText = GreGetTextColor(hdc);
  703. hbr = xxxGetColorObjects(pwnd, hdc);
  704. if (cLength > cpxArrow)
  705. cLength = cpxArrow;
  706. pwX = (int *)&rcSB;
  707. pwY = pwX + 1;
  708. if (!fVert)
  709. pwX = pwY--;
  710. pwX[0] = pSBCalc->pxLeft;
  711. pwY[0] = pSBCalc->pxTop;
  712. pwX[2] = pSBCalc->pxRight;
  713. pwY[2] = pSBCalc->pxBottom;
  714. hbrSave = GreSelectBrush(hdc, SYSHBR(BTNTEXT));
  715. //
  716. // BOGUS
  717. // Draw scrollbar arrows as disabled if the scrollbar itself is
  718. // disabled OR if the window it is a part of is disabled?
  719. //
  720. if (fVert) {
  721. if ((cLength == SYSMET(CYVSCROLL)) && (cWidth == SYSMET(CXVSCROLL))) {
  722. BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_UPARROW_I : OBI_UPARROW);
  723. BitBltSysBmp(hdc, rcSB.left, rcSB.bottom - cLength, (wDisable & RTDNFLAG) ? OBI_DNARROW_I : OBI_DNARROW);
  724. } else {
  725. CopyRect(&rc, &rcSB);
  726. rc.bottom = rc.top + cLength;
  727. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  728. DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  729. rc.bottom = rcSB.bottom;
  730. rc.top = rcSB.bottom - cLength;
  731. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  732. DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  733. }
  734. } else {
  735. if ((cLength == SYSMET(CXHSCROLL)) && (cWidth == SYSMET(CYHSCROLL))) {
  736. BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_LFARROW_I : OBI_LFARROW);
  737. BitBltSysBmp(hdc, rcSB.right - cLength, rcSB.top, (wDisable & RTDNFLAG) ? OBI_RGARROW_I : OBI_RGARROW);
  738. } else {
  739. CopyRect(&rc, &rcSB);
  740. rc.right = rc.left + cLength;
  741. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  742. DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
  743. rc.right = rcSB.right;
  744. rc.left = rcSB.right - cLength;
  745. DrawFrameControl(hdc, &rc, DFC_SCROLL,
  746. DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
  747. }
  748. }
  749. hbrSave = GreSelectBrush(hdc, hbrSave);
  750. DrawThumb2(pwnd, pSBCalc, hdc, hbr, fVert, wDisable);
  751. GreSelectBrush(hdc, hbrSave);
  752. GreSetBkColor(hdc, crBk);
  753. GreSetTextColor(hdc, crText);
  754. }
  755. /***************************************************************************\
  756. * zzzSetSBCaretPos
  757. *
  758. *
  759. *
  760. * History:
  761. \***************************************************************************/
  762. void zzzSetSBCaretPos(
  763. PSBWND psbwnd)
  764. {
  765. if ((PWND)psbwnd == PtiCurrent()->pq->spwndFocus) {
  766. zzzSetCaretPos((psbwnd->fVert ? psbwnd->SBCalc.pxLeft : psbwnd->SBCalc.pxThumbTop) + SYSMET(CXEDGE),
  767. (psbwnd->fVert ? psbwnd->SBCalc.pxThumbTop : psbwnd->SBCalc.pxLeft) + SYSMET(CYEDGE));
  768. }
  769. }
  770. /***************************************************************************\
  771. * CalcSBStuff2
  772. *
  773. *
  774. *
  775. * History:
  776. \***************************************************************************/
  777. void CalcSBStuff2(
  778. PSBCALC pSBCalc,
  779. LPRECT lprc,
  780. CONST PSBDATA pw,
  781. BOOL fVert)
  782. {
  783. int cpx;
  784. DWORD dwRange;
  785. int denom;
  786. if (fVert) {
  787. pSBCalc->pxTop = lprc->top;
  788. pSBCalc->pxBottom = lprc->bottom;
  789. pSBCalc->pxLeft = lprc->left;
  790. pSBCalc->pxRight = lprc->right;
  791. pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
  792. } else {
  793. /*
  794. * For horiz scroll bars, "left" & "right" are "top" and "bottom",
  795. * and vice versa.
  796. */
  797. pSBCalc->pxTop = lprc->left;
  798. pSBCalc->pxBottom = lprc->right;
  799. pSBCalc->pxLeft = lprc->top;
  800. pSBCalc->pxRight = lprc->bottom;
  801. pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
  802. }
  803. pSBCalc->pos = pw->pos;
  804. pSBCalc->page = pw->page;
  805. pSBCalc->posMin = pw->posMin;
  806. pSBCalc->posMax = pw->posMax;
  807. dwRange = ((DWORD)(pSBCalc->posMax - pSBCalc->posMin)) + 1;
  808. //
  809. // For the case of short scroll bars that don't have enough
  810. // room to fit the full-sized up and down arrows, shorten
  811. // their sizes to make 'em fit
  812. //
  813. cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
  814. pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx;
  815. pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
  816. if ((pw->page != 0) && (dwRange != 0)) {
  817. // JEFFBOG -- This is the one and only place where we should
  818. // see 'range'. Elsewhere it should be 'range - page'.
  819. /*
  820. * The minimun thumb size used to depend on the frame/edge metrics.
  821. * People that increase the scrollbar width/height expect the minimun
  822. * to grow with proportianally. So NT5 bases the minimun on
  823. * CXH/YVSCROLL, which is set by default in cpxThumb.
  824. */
  825. /*
  826. * i is used to keep the macro "max" from executing EngMulDiv twice.
  827. */
  828. int i = EngMulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
  829. pw->page, dwRange);
  830. pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
  831. }
  832. pSBCalc->pxMin = pSBCalc->pxTop + cpx;
  833. pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
  834. denom = dwRange - (pw->page ? pw->page : 1);
  835. if (denom)
  836. pSBCalc->pxThumbTop = EngMulDiv(pw->pos - pw->posMin,
  837. pSBCalc->cpx, denom) +
  838. pSBCalc->pxMin;
  839. else
  840. pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
  841. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  842. }
  843. /***************************************************************************\
  844. * SBCtlSetup
  845. *
  846. *
  847. *
  848. * History:
  849. \***************************************************************************/
  850. void SBCtlSetup(
  851. PSBWND psbwnd)
  852. {
  853. RECT rc;
  854. GetRect((PWND)psbwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS);
  855. CalcSBStuff2(&psbwnd->SBCalc, &rc, (PSBDATA)&psbwnd->SBCalc, psbwnd->fVert);
  856. }
  857. /***************************************************************************\
  858. * HotTrackSB
  859. *
  860. \***************************************************************************/
  861. #ifdef COLOR_HOTTRACKING
  862. DWORD GetTrackFlags(int ht, BOOL fDraw)
  863. {
  864. if (fDraw) {
  865. switch(ht) {
  866. case HTSCROLLUP:
  867. case HTSCROLLUPPAGE:
  868. return LTUPFLAG;
  869. case HTSCROLLDOWN:
  870. case HTSCROLLDOWNPAGE:
  871. return RTDNFLAG;
  872. case HTSCROLLTHUMB:
  873. return LTUPFLAG | RTDNFLAG;
  874. default:
  875. return 0;
  876. }
  877. } else {
  878. return 0;
  879. }
  880. }
  881. BOOL xxxHotTrackSB(PWND pwnd, int htEx, BOOL fDraw)
  882. {
  883. SBCALC SBCalc;
  884. HDC hdc;
  885. BOOL fVert = HIWORD(htEx);
  886. int ht = LOWORD(htEx);
  887. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  888. CheckLock(pwnd);
  889. /*
  890. * xxxDrawSB2 does not callback or leave the critical section when it's
  891. * not a SB control and the window belongs to a different thread. It
  892. * calls xxxDefWindowProc which simply returns the brush color.
  893. */
  894. CalcSBStuff(pwnd, &SBCalc, fVert);
  895. hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  896. xxxDrawSB2(pwnd, &SBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert), dwTrack);
  897. _ReleaseDC(hdc);
  898. return TRUE;
  899. }
  900. void xxxHotTrackSBCtl(PSBWND psbwnd, int ht, BOOL fDraw)
  901. {
  902. DWORD dwTrack = GetTrackFlags(ht, fDraw);
  903. HDC hdc;
  904. CheckLock(psbwnd);
  905. SBCtlSetup(psbwnd);
  906. hdc = _GetDCEx((PWND)psbwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
  907. xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags, dwTrack);
  908. _ReleaseDC(hdc);
  909. }
  910. #endif // COLOR_HOTTRACKING
  911. BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres)
  912. {
  913. // pass the struct because we modify the struct but don't want that
  914. // modified version to get back to the calling app
  915. BOOL fChanged = FALSE;
  916. if (lpsi->fMask & SIF_RETURNOLDPOS)
  917. // save previous position
  918. *lplres = pw->pos;
  919. if (lpsi->fMask & SIF_RANGE) {
  920. // if the range MAX is below the range MIN -- then treat is as a
  921. // zero range starting at the range MIN.
  922. if (lpsi->nMax < lpsi->nMin)
  923. lpsi->nMax = lpsi->nMin;
  924. if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) {
  925. pw->posMin = lpsi->nMin;
  926. pw->posMax = lpsi->nMax;
  927. if (!(lpsi->fMask & SIF_PAGE)) {
  928. lpsi->fMask |= SIF_PAGE;
  929. lpsi->nPage = pw->page;
  930. }
  931. if (!(lpsi->fMask & SIF_POS)) {
  932. lpsi->fMask |= SIF_POS;
  933. lpsi->nPos = pw->pos;
  934. }
  935. fChanged = TRUE;
  936. }
  937. }
  938. if (lpsi->fMask & SIF_PAGE) {
  939. DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
  940. // Clip page to 0, posMax - posMin + 1
  941. if (lpsi->nPage > dwMaxPage)
  942. lpsi->nPage = dwMaxPage;
  943. if (pw->page != (int)(lpsi->nPage)) {
  944. pw->page = lpsi->nPage;
  945. if (!(lpsi->fMask & SIF_POS)) {
  946. lpsi->fMask |= SIF_POS;
  947. lpsi->nPos = pw->pos;
  948. }
  949. fChanged = TRUE;
  950. }
  951. }
  952. if (lpsi->fMask & SIF_POS) {
  953. int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0);
  954. // Clip pos to posMin, posMax - (page - 1).
  955. if (lpsi->nPos < pw->posMin)
  956. lpsi->nPos = pw->posMin;
  957. else if (lpsi->nPos > iMaxPos)
  958. lpsi->nPos = iMaxPos;
  959. if (pw->pos != lpsi->nPos) {
  960. pw->pos = lpsi->nPos;
  961. fChanged = TRUE;
  962. }
  963. }
  964. if (!(lpsi->fMask & SIF_RETURNOLDPOS)) {
  965. // Return the new position
  966. *lplres = pw->pos;
  967. }
  968. /*
  969. * This was added by JimA as Cairo merge but will conflict
  970. * with the documentation for SetScrollPos
  971. */
  972. /*
  973. else if (*lplres == pw->pos)
  974. *lplres = 0;
  975. */
  976. if (lpsi->fMask & SIF_RANGE) {
  977. if (*lpfScroll = (pw->posMin != pw->posMax))
  978. goto checkPage;
  979. } else if (lpsi->fMask & SIF_PAGE)
  980. checkPage:
  981. *lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
  982. return fChanged;
  983. }
  984. /***************************************************************************\
  985. * CalcSBStuff
  986. *
  987. *
  988. *
  989. * History:
  990. \***************************************************************************/
  991. void CalcSBStuff(
  992. PWND pwnd,
  993. PSBCALC pSBCalc,
  994. BOOL fVert)
  995. {
  996. RECT rcT;
  997. RECT rcClient;
  998. int cx, iTemp;
  999. //
  1000. // Get client rectangle. We know that scrollbars always align to the right
  1001. // and to the bottom of the client area.
  1002. //
  1003. GetRect(pwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS);
  1004. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  1005. cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  1006. iTemp = rcClient.left;
  1007. rcClient.left = cx - rcClient.right;
  1008. rcClient.right = cx - iTemp;
  1009. }
  1010. if (fVert) {
  1011. // Only add on space if vertical scrollbar is really there.
  1012. if (TestWF(pwnd, WEFLEFTSCROLL)) {
  1013. rcT.right = rcT.left = rcClient.left;
  1014. if (TestWF(pwnd, WFVPRESENT))
  1015. rcT.left -= SYSMET(CXVSCROLL);
  1016. } else {
  1017. rcT.right = rcT.left = rcClient.right;
  1018. if (TestWF(pwnd, WFVPRESENT))
  1019. rcT.right += SYSMET(CXVSCROLL);
  1020. }
  1021. rcT.top = rcClient.top;
  1022. rcT.bottom = rcClient.bottom;
  1023. } else {
  1024. // Only add on space if horizontal scrollbar is really there.
  1025. rcT.bottom = rcT.top = rcClient.bottom;
  1026. if (TestWF(pwnd, WFHPRESENT))
  1027. rcT.bottom += SYSMET(CYHSCROLL);
  1028. rcT.left = rcClient.left;
  1029. rcT.right = rcClient.right;
  1030. }
  1031. // If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
  1032. // we can do here, so just let it go through. We won't fault but the scrollbar won't work
  1033. // properly either...
  1034. if (_InitPwSB(pwnd))
  1035. CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &pwnd->pSBInfo->Vert : &pwnd->pSBInfo->Horz, fVert);
  1036. }
  1037. /***************************************************************************\
  1038. *
  1039. * DrawCtlThumb()
  1040. *
  1041. \***************************************************************************/
  1042. void DrawCtlThumb(PSBWND psb)
  1043. {
  1044. HBRUSH hbr, hbrSave;
  1045. HDC hdc = (HDC) _GetWindowDC((PWND) psb);
  1046. SBCtlSetup(psb);
  1047. hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects((PWND) psb, hdc));
  1048. DrawThumb2((PWND) psb, &psb->SBCalc, hdc, hbr, psb->fVert, psb->wDisableFlags);
  1049. GreSelectBrush(hdc, hbrSave);
  1050. _ReleaseDC(hdc);
  1051. }
  1052. /***************************************************************************\
  1053. * xxxDrawThumb
  1054. *
  1055. *
  1056. *
  1057. * History:
  1058. \***************************************************************************/
  1059. void xxxDrawThumb(
  1060. PWND pwnd,
  1061. PSBCALC pSBCalc,
  1062. BOOL fVert)
  1063. {
  1064. HBRUSH hbr, hbrSave;
  1065. HDC hdc;
  1066. UINT wDisableFlags;
  1067. SBCALC SBCalc;
  1068. CheckLock(pwnd);
  1069. if (!pSBCalc) pSBCalc = &SBCalc;
  1070. hdc = (HDC)_GetWindowDC(pwnd);
  1071. CalcSBStuff(pwnd, &SBCalc, fVert);
  1072. wDisableFlags = GetWndSBDisableFlags(pwnd, fVert);
  1073. hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
  1074. DrawThumb2(pwnd, &SBCalc, hdc, hbr, fVert, wDisableFlags);
  1075. GreSelectBrush(hdc, hbrSave);
  1076. /*
  1077. * Won't hurt even if DC is already released (which happens automatically
  1078. * if window is destroyed during xxxSelectColorObjects)
  1079. */
  1080. _ReleaseDC(hdc);
  1081. }
  1082. /***************************************************************************\
  1083. * xxxSetScrollBar
  1084. *
  1085. *
  1086. *
  1087. * History:
  1088. \***************************************************************************/
  1089. LONG xxxSetScrollBar(
  1090. PWND pwnd,
  1091. int code,
  1092. LPSCROLLINFO lpsi,
  1093. BOOL fRedraw)
  1094. {
  1095. BOOL fVert;
  1096. PSBDATA pw;
  1097. PSBINFO pSBInfo;
  1098. BOOL fOldScroll;
  1099. BOOL fScroll;
  1100. WORD wfScroll;
  1101. LONG lres;
  1102. BOOL fNewScroll;
  1103. CheckLock(pwnd);
  1104. UserAssert(IsWinEventNotifyDeferredOK());
  1105. if (fRedraw)
  1106. // window must be visible to redraw
  1107. fRedraw = IsVisible(pwnd);
  1108. if (code == SB_CTL)
  1109. #ifdef FE_SB // xxxSetScrollBar()
  1110. // scroll bar control; send the control a message
  1111. if(GETPTI(pwnd)->TIF_flags & TIF_16BIT) {
  1112. //
  1113. // If the target application is 16bit apps, we don't pass win40's message.
  1114. // This fix for Ichitaro v6.3. It eats the message. It never forwards
  1115. // the un-processed messages to original windows procedure via
  1116. // CallWindowProc().
  1117. //
  1118. // Is this from xxxSetScrollPos() ?
  1119. if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) {
  1120. return (int)xxxSendMessage(pwnd, SBM_SETPOS, lpsi->nPos, fRedraw);
  1121. // Is this from xxxSetScrollRange() ?
  1122. } else if(lpsi->fMask == SIF_RANGE) {
  1123. xxxSendMessage(pwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax);
  1124. return TRUE;
  1125. // Others...
  1126. } else {
  1127. return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1128. }
  1129. } else {
  1130. return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1131. }
  1132. #else
  1133. // scroll bar control; send the control a message
  1134. return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
  1135. #endif // FE_SB
  1136. fVert = (code != SB_HORZ);
  1137. wfScroll = (fVert) ? WFVSCROLL : WFHSCROLL;
  1138. fScroll = fOldScroll = (TestWF(pwnd, wfScroll)) ? TRUE : FALSE;
  1139. /*
  1140. * Don't do anything if we're setting position of a nonexistent scroll bar.
  1141. */
  1142. if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (pwnd->pSBInfo == NULL)) {
  1143. RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
  1144. return 0;
  1145. }
  1146. if (fNewScroll = !(pSBInfo = pwnd->pSBInfo)) {
  1147. if ((pSBInfo = _InitPwSB(pwnd)) == NULL)
  1148. return 0;
  1149. }
  1150. pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
  1151. if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll) {
  1152. // no change -- but if REDRAW is specified and there's a scrollbar,
  1153. // redraw the thumb
  1154. if (fOldScroll && fRedraw)
  1155. goto redrawAfterSet;
  1156. return lres;
  1157. }
  1158. ClrWF(pwnd, wfScroll);
  1159. if (fScroll)
  1160. SetWF(pwnd, wfScroll);
  1161. else if (!TestWF(pwnd, (WFHSCROLL | WFVSCROLL))) {
  1162. // if neither scroll bar is set and both ranges are 0, then free up the
  1163. // scroll info
  1164. pSBInfo = pwnd->pSBInfo;
  1165. if ((pSBInfo->Horz.posMin == pSBInfo->Horz.posMax) &&
  1166. (pSBInfo->Vert.posMin == pSBInfo->Vert.posMax)) {
  1167. DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo));
  1168. pwnd->pSBInfo = NULL;
  1169. }
  1170. }
  1171. if (lpsi->fMask & SIF_DISABLENOSCROLL) {
  1172. if (fOldScroll) {
  1173. SetWF(pwnd, wfScroll);
  1174. xxxEnableWndSBArrows(pwnd, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
  1175. }
  1176. } else if (fOldScroll ^ fScroll) {
  1177. PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
  1178. if (pSBTrack && (pwnd == pSBTrack->spwndTrack)) {
  1179. pSBTrack->fTrackRecalc = TRUE;
  1180. }
  1181. xxxRedrawFrame(pwnd);
  1182. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  1183. return lres;
  1184. }
  1185. if (fScroll && fRedraw && (fVert ? TestWF(pwnd, WFVPRESENT) : TestWF(pwnd, WFHPRESENT))) {
  1186. PSBTRACK pSBTrack;
  1187. redrawAfterSet:
  1188. xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, pwnd, (fVert ? OBJID_VSCROLL : OBJID_HSCROLL),
  1189. INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
  1190. pSBTrack = PWNDTOPSBTRACK(pwnd);
  1191. // Bail out if the caller is trying to change the position of
  1192. // a scrollbar that is in the middle of tracking. We'll hose
  1193. // TrackThumb() otherwise.
  1194. if (pSBTrack && (pwnd == pSBTrack->spwndTrack) &&
  1195. ((BOOL)(pSBTrack->fTrackVert) == fVert) &&
  1196. (pSBTrack->xxxpfnSB == xxxTrackThumb)) {
  1197. return lres;
  1198. }
  1199. xxxDrawThumb(pwnd, NULL, fVert);
  1200. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  1201. }
  1202. return lres;
  1203. }
  1204. /***************************************************************************\
  1205. * xxxDrawScrollBar
  1206. *
  1207. *
  1208. *
  1209. * History:
  1210. \***************************************************************************/
  1211. void xxxDrawScrollBar(
  1212. PWND pwnd,
  1213. HDC hdc,
  1214. BOOL fVert)
  1215. {
  1216. SBCALC SBCalc;
  1217. PSBCALC pSBCalc;
  1218. PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
  1219. CheckLock(pwnd);
  1220. if (pSBTrack && (pwnd == pSBTrack->spwndTrack) && (pSBTrack->fCtlSB == FALSE)
  1221. && (fVert == (BOOL)pSBTrack->fTrackVert)) {
  1222. pSBCalc = pSBTrack->pSBCalc;
  1223. } else {
  1224. pSBCalc = &SBCalc;
  1225. }
  1226. CalcSBStuff(pwnd, pSBCalc, fVert);
  1227. xxxDrawSB2(pwnd, pSBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert));
  1228. }
  1229. /***************************************************************************\
  1230. * SBPosFromPx
  1231. *
  1232. * Compute scroll bar position from pixel location
  1233. *
  1234. * History:
  1235. \***************************************************************************/
  1236. int SBPosFromPx(
  1237. PSBCALC pSBCalc,
  1238. int px)
  1239. {
  1240. if (px < pSBCalc->pxMin) {
  1241. return pSBCalc->posMin;
  1242. }
  1243. if (px >= pSBCalc->pxMin + pSBCalc->cpx) {
  1244. return (pSBCalc->posMax - (pSBCalc->page ? pSBCalc->page - 1 : 0));
  1245. }
  1246. if (pSBCalc->cpx)
  1247. return (pSBCalc->posMin + EngMulDiv(pSBCalc->posMax - pSBCalc->posMin -
  1248. (pSBCalc->page ? pSBCalc->page - 1 : 0),
  1249. px - pSBCalc->pxMin, pSBCalc->cpx));
  1250. else
  1251. return (pSBCalc->posMin - 1);
  1252. }
  1253. /***************************************************************************\
  1254. * InvertScrollHilite
  1255. *
  1256. *
  1257. *
  1258. * History:
  1259. \***************************************************************************/
  1260. void InvertScrollHilite(
  1261. PWND pwnd,
  1262. PSBTRACK pSBTrack)
  1263. {
  1264. HDC hdc;
  1265. /*
  1266. * Don't invert if the thumb is all the way at the top or bottom
  1267. * or you will end up inverting the line between the arrow and the thumb.
  1268. */
  1269. if (!IsRectEmpty(&pSBTrack->rcTrack)) {
  1270. if (pSBTrack->fTrackRecalc) {
  1271. RecalcTrackRect(pSBTrack);
  1272. pSBTrack->fTrackRecalc = FALSE;
  1273. }
  1274. hdc = (HDC)_GetWindowDC(pwnd);
  1275. InvertRect(hdc, &pSBTrack->rcTrack);
  1276. _ReleaseDC(hdc);
  1277. }
  1278. }
  1279. /***************************************************************************\
  1280. * xxxDoScroll
  1281. *
  1282. * Sends scroll notification to the scroll bar owner
  1283. *
  1284. * History:
  1285. \***************************************************************************/
  1286. void xxxDoScroll(
  1287. PWND pwnd,
  1288. PWND pwndNotify,
  1289. int cmd,
  1290. int pos,
  1291. BOOL fVert
  1292. )
  1293. {
  1294. TL tlpwndNotify;
  1295. /*
  1296. * Special case!!!! this routine is always passed pwnds that are
  1297. * not thread locked, so they need to be thread locked here. The
  1298. * callers always know that by the time DoScroll() returns,
  1299. * pwnd and pwndNotify could be invalid.
  1300. */
  1301. ThreadLock(pwndNotify, &tlpwndNotify);
  1302. xxxSendMessage(pwndNotify, (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
  1303. MAKELONG(cmd, pos), (LPARAM)HW(pwnd));
  1304. ThreadUnlock(&tlpwndNotify);
  1305. }
  1306. // -------------------------------------------------------------------------
  1307. //
  1308. // CheckScrollRecalc()
  1309. //
  1310. // -------------------------------------------------------------------------
  1311. //void CheckScrollRecalc(PWND pwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
  1312. //{
  1313. // if ((pSBState->pwndCalc != pwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
  1314. // {
  1315. // // Calculate SB stuff based on whether it's a control or in a window
  1316. // if (pSBState->fCtlSB)
  1317. // SBCtlSetup((PSBWND) pwnd);
  1318. // else
  1319. // CalcSBStuff(pwnd, pSBCalc, pSBState->fVertSB);
  1320. // }
  1321. //}
  1322. /***************************************************************************\
  1323. * xxxMoveThumb
  1324. *
  1325. * History:
  1326. \***************************************************************************/
  1327. void xxxMoveThumb(
  1328. PWND pwnd,
  1329. PSBCALC pSBCalc,
  1330. int px)
  1331. {
  1332. HBRUSH hbr, hbrSave;
  1333. HDC hdc;
  1334. PSBTRACK pSBTrack;
  1335. CheckLock(pwnd);
  1336. pSBTrack = PWNDTOPSBTRACK(pwnd);
  1337. if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
  1338. return;
  1339. pxReCalc:
  1340. pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
  1341. /* Tentative position changed -- notify the guy. */
  1342. if (pSBTrack->posNew != pSBTrack->posOld) {
  1343. if (pSBTrack->spwndSBNotify != NULL) {
  1344. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert
  1345. );
  1346. }
  1347. // After xxxDoScroll, re-evaluate pSBTrack
  1348. REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(1)");
  1349. if ((pSBTrack == NULL) || (pSBTrack->xxxpfnSB == NULL))
  1350. return;
  1351. pSBTrack->posOld = pSBTrack->posNew;
  1352. //
  1353. // Anything can happen after the SendMessage above!
  1354. // Make sure that the SBINFO structure contains data for the
  1355. // window being tracked -- if not, recalculate data in SBINFO
  1356. //
  1357. // CheckScrollRecalc(pwnd, pSBState, pSBCalc);
  1358. // when we yield, our range can get messed with
  1359. // so make sure we handle this
  1360. if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  1361. {
  1362. px = pSBCalc->pxMin + pSBCalc->cpx;
  1363. goto pxReCalc;
  1364. }
  1365. }
  1366. hdc = _GetWindowDC(pwnd);
  1367. pSBCalc->pxThumbTop = px;
  1368. pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
  1369. // at this point, the disable flags are always going to be 0 --
  1370. // we're in the middle of tracking.
  1371. hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
  1372. // After xxxGetColorObjects, re-evaluate pSBTrack
  1373. REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(2)");
  1374. if (pSBTrack == NULL) {
  1375. RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ;
  1376. _ReleaseDC(hdc);
  1377. return;
  1378. }
  1379. DrawThumb2(pwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0);
  1380. GreSelectBrush(hdc, hbrSave);
  1381. _ReleaseDC(hdc);
  1382. pSBTrack->pxOld = px;
  1383. }
  1384. /***************************************************************************\
  1385. * zzzDrawInvertScrollArea
  1386. *
  1387. *
  1388. *
  1389. * History:
  1390. \***************************************************************************/
  1391. void zzzDrawInvertScrollArea(
  1392. PWND pwnd,
  1393. PSBTRACK pSBTrack,
  1394. BOOL fHit,
  1395. UINT cmd)
  1396. {
  1397. HDC hdc;
  1398. RECT rcTemp;
  1399. int cx, cy;
  1400. UINT bm;
  1401. if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN)) {
  1402. // not hitting on arrow -- just invert the area and return
  1403. InvertScrollHilite(pwnd, pSBTrack);
  1404. if (cmd == SB_PAGEUP) {
  1405. if (fHit)
  1406. SetWF(pwnd, WFPAGEUPBUTTONDOWN);
  1407. else
  1408. ClrWF(pwnd, WFPAGEUPBUTTONDOWN);
  1409. } else {
  1410. if (fHit)
  1411. SetWF(pwnd, WFPAGEDNBUTTONDOWN);
  1412. else
  1413. ClrWF(pwnd, WFPAGEDNBUTTONDOWN);
  1414. }
  1415. zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
  1416. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  1417. ((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE),
  1418. WEF_USEPWNDTHREAD);
  1419. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  1420. return;
  1421. }
  1422. if (pSBTrack->fTrackRecalc) {
  1423. RecalcTrackRect(pSBTrack);
  1424. pSBTrack->fTrackRecalc = FALSE;
  1425. }
  1426. CopyRect(&rcTemp, &pSBTrack->rcTrack);
  1427. hdc = _GetWindowDC(pwnd);
  1428. if (pSBTrack->fTrackVert) {
  1429. cx = SYSMET(CXVSCROLL);
  1430. cy = SYSMET(CYVSCROLL);
  1431. } else {
  1432. cx = SYSMET(CXHSCROLL);
  1433. cy = SYSMET(CYHSCROLL);
  1434. }
  1435. if ((cx == (rcTemp.right - rcTemp.left)) &&
  1436. (cy == (rcTemp.bottom - rcTemp.top))) {
  1437. if (cmd == SB_LINEUP)
  1438. bm = (pSBTrack->fTrackVert) ? OBI_UPARROW : OBI_LFARROW;
  1439. else // SB_LINEDOWN
  1440. bm = (pSBTrack->fTrackVert) ? OBI_DNARROW : OBI_RGARROW;
  1441. if (fHit)
  1442. bm += DOBI_PUSHED;
  1443. BitBltSysBmp(hdc, rcTemp.left, rcTemp.top, bm);
  1444. } else {
  1445. DrawFrameControl(hdc, &rcTemp, DFC_SCROLL,
  1446. ((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) |
  1447. ((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) |
  1448. ((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX));
  1449. }
  1450. _ReleaseDC(hdc);
  1451. if (cmd == SB_LINEUP) {
  1452. if (fHit)
  1453. SetWF(pwnd, WFLINEUPBUTTONDOWN);
  1454. else
  1455. ClrWF(pwnd, WFLINEUPBUTTONDOWN);
  1456. } else {
  1457. if (fHit)
  1458. SetWF(pwnd, WFLINEDNBUTTONDOWN);
  1459. else
  1460. ClrWF(pwnd, WFLINEDNBUTTONDOWN);
  1461. }
  1462. zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
  1463. (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  1464. (cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN),
  1465. WEF_USEPWNDTHREAD);
  1466. // Note: after zzz, pSBTrack may no longer be valid (but we return now)
  1467. }
  1468. /***************************************************************************\
  1469. * xxxEndScroll
  1470. *
  1471. *
  1472. *
  1473. * History:
  1474. \***************************************************************************/
  1475. void xxxEndScroll(
  1476. PWND pwnd,
  1477. BOOL fCancel)
  1478. {
  1479. UINT oldcmd;
  1480. PSBTRACK pSBTrack;
  1481. CheckLock(pwnd);
  1482. UserAssert(!IsWinEventNotifyDeferred());
  1483. pSBTrack = PWNDTOPSBTRACK(pwnd);
  1484. if (pSBTrack && PtiCurrent()->pq->spwndCapture == pwnd && pSBTrack->xxxpfnSB != NULL) {
  1485. oldcmd = pSBTrack->cmdSB;
  1486. pSBTrack->cmdSB = 0;
  1487. xxxReleaseCapture();
  1488. // After xxxReleaseCapture, revalidate pSBTrack
  1489. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1490. if (pSBTrack->xxxpfnSB == xxxTrackThumb) {
  1491. if (fCancel) {
  1492. pSBTrack->posOld = pSBTrack->pSBCalc->pos;
  1493. }
  1494. /*
  1495. * DoScroll does thread locking on these two pwnds -
  1496. * this is ok since they are not used after this
  1497. * call.
  1498. */
  1499. if (pSBTrack->spwndSBNotify != NULL) {
  1500. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
  1501. SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert
  1502. );
  1503. // After xxxDoScroll, revalidate pSBTrack
  1504. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1505. }
  1506. if (pSBTrack->fCtlSB) {
  1507. DrawCtlThumb((PSBWND) pwnd);
  1508. } else {
  1509. xxxDrawThumb(pwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
  1510. // Note: after xxx, pSBTrack may no longer be valid
  1511. }
  1512. } else if (pSBTrack->xxxpfnSB == xxxTrackBox) {
  1513. DWORD lParam;
  1514. POINT ptMsg;
  1515. if (pSBTrack->hTimerSB != 0) {
  1516. _KillSystemTimer(pwnd, IDSYS_SCROLL);
  1517. pSBTrack->hTimerSB = 0;
  1518. }
  1519. lParam = _GetMessagePos();
  1520. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  1521. ptMsg.x = pwnd->rcWindow.right - GET_X_LPARAM(lParam);
  1522. } else {
  1523. ptMsg.x = GET_X_LPARAM(lParam) - pwnd->rcWindow.left;
  1524. }
  1525. ptMsg.y = GET_Y_LPARAM(lParam) - pwnd->rcWindow.top;
  1526. if (PtInRect(&pSBTrack->rcTrack, ptMsg)) {
  1527. zzzDrawInvertScrollArea(pwnd, pSBTrack, FALSE, oldcmd);
  1528. // Note: after zzz, pSBTrack may no longer be valid
  1529. }
  1530. }
  1531. /*
  1532. * Always send SB_ENDSCROLL message.
  1533. *
  1534. * DoScroll does thread locking on these two pwnds -
  1535. * this is ok since they are not used after this
  1536. * call.
  1537. */
  1538. // After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
  1539. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1540. if (pSBTrack->spwndSBNotify != NULL) {
  1541. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
  1542. SB_ENDSCROLL, 0, pSBTrack->fTrackVert);
  1543. // After xxxDoScroll, revalidate pSBTrack
  1544. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1545. }
  1546. ClrWF(pwnd, WFSCROLLBUTTONDOWN);
  1547. ClrWF(pwnd, WFVERTSCROLLTRACK);
  1548. xxxWindowEvent(EVENT_SYSTEM_SCROLLINGEND, pwnd,
  1549. (pSBTrack->fCtlSB ? OBJID_CLIENT :
  1550. (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  1551. INDEXID_CONTAINER, 0);
  1552. // After xxxWindowEvent, revalidate pSBTrack
  1553. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1554. /*
  1555. * If this is a Scroll Bar Control, turn the caret back on.
  1556. */
  1557. if (pSBTrack->spwndSB != NULL) {
  1558. zzzShowCaret(pSBTrack->spwndSB);
  1559. // After zzz, revalidate pSBTrack
  1560. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1561. }
  1562. pSBTrack->xxxpfnSB = NULL;
  1563. /*
  1564. * Unlock structure members so they are no longer holding down windows.
  1565. */
  1566. Unlock(&pSBTrack->spwndSB);
  1567. Unlock(&pSBTrack->spwndSBNotify);
  1568. Unlock(&pSBTrack->spwndTrack);
  1569. UserFreePool(pSBTrack);
  1570. PWNDTOPSBTRACK(pwnd) = NULL;
  1571. }
  1572. }
  1573. /***************************************************************************\
  1574. * xxxContScroll
  1575. *
  1576. *
  1577. *
  1578. * History:
  1579. \***************************************************************************/
  1580. VOID xxxContScroll(
  1581. PWND pwnd,
  1582. UINT message,
  1583. UINT_PTR ID,
  1584. LPARAM lParam)
  1585. {
  1586. LONG pt;
  1587. PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
  1588. UNREFERENCED_PARAMETER(message);
  1589. UNREFERENCED_PARAMETER(ID);
  1590. UNREFERENCED_PARAMETER(lParam);
  1591. if (pSBTrack == NULL)
  1592. return;
  1593. CheckLock(pwnd);
  1594. pt = _GetMessagePos();
  1595. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  1596. pt = MAKELONG(pwnd->rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
  1597. } else {
  1598. pt = MAKELONG( GET_X_LPARAM(pt) - pwnd->rcWindow.left, GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
  1599. }
  1600. xxxTrackBox(pwnd, WM_NULL, 0, pt, NULL);
  1601. // After xxxTrackBox, revalidate pSBTrack
  1602. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1603. if (pSBTrack->fHitOld) {
  1604. pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
  1605. gpsi->dtScroll / 8, xxxContScroll);
  1606. /*
  1607. * DoScroll does thread locking on these two pwnds -
  1608. * this is ok since they are not used after this
  1609. * call.
  1610. */
  1611. if (pSBTrack->spwndSBNotify != NULL) {
  1612. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
  1613. pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
  1614. // Note: after xxx, pSBTrack may no longer be valid (but we return now)
  1615. }
  1616. }
  1617. return;
  1618. }
  1619. /***************************************************************************\
  1620. * xxxTrackBox
  1621. *
  1622. *
  1623. *
  1624. * History:
  1625. \***************************************************************************/
  1626. void xxxTrackBox(
  1627. PWND pwnd,
  1628. UINT message,
  1629. WPARAM wParam,
  1630. LPARAM lParam,
  1631. PSBCALC pSBCalc)
  1632. {
  1633. BOOL fHit;
  1634. POINT ptHit;
  1635. PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
  1636. int cmsTimer;
  1637. UNREFERENCED_PARAMETER(wParam);
  1638. UNREFERENCED_PARAMETER(pSBCalc);
  1639. CheckLock(pwnd);
  1640. UserAssert(IsWinEventNotifyDeferredOK());
  1641. if (pSBTrack == NULL)
  1642. return;
  1643. if (message != WM_NULL && HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
  1644. return;
  1645. if (pSBTrack->fTrackRecalc) {
  1646. RecalcTrackRect(pSBTrack);
  1647. pSBTrack->fTrackRecalc = FALSE;
  1648. }
  1649. ptHit.x = GET_X_LPARAM(lParam);
  1650. ptHit.y = GET_Y_LPARAM(lParam);
  1651. fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
  1652. if (fHit != (BOOL)pSBTrack->fHitOld) {
  1653. zzzDrawInvertScrollArea(pwnd, pSBTrack, fHit, pSBTrack->cmdSB);
  1654. // After zzz, pSBTrack may no longer be valid
  1655. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1656. }
  1657. cmsTimer = gpsi->dtScroll / 8;
  1658. switch (message) {
  1659. case WM_LBUTTONUP:
  1660. xxxEndScroll(pwnd, FALSE);
  1661. // Note: after xxx, pSBTrack may no longer be valid
  1662. break;
  1663. case WM_LBUTTONDOWN:
  1664. pSBTrack->hTimerSB = 0;
  1665. cmsTimer = gpsi->dtScroll;
  1666. /*
  1667. *** FALL THRU **
  1668. */
  1669. case WM_MOUSEMOVE:
  1670. if (fHit && fHit != (BOOL)pSBTrack->fHitOld) {
  1671. /*
  1672. * We moved back into the normal rectangle: reset timer
  1673. */
  1674. pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
  1675. cmsTimer, xxxContScroll);
  1676. /*
  1677. * DoScroll does thread locking on these two pwnds -
  1678. * this is ok since they are not used after this
  1679. * call.
  1680. */
  1681. if (pSBTrack->spwndSBNotify != NULL) {
  1682. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
  1683. pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
  1684. // Note: after xxx, pSBTrack may no longer be valid
  1685. }
  1686. }
  1687. }
  1688. // After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
  1689. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1690. pSBTrack->fHitOld = fHit;
  1691. }
  1692. /***************************************************************************\
  1693. * xxxTrackThumb
  1694. *
  1695. *
  1696. *
  1697. * History:
  1698. \***************************************************************************/
  1699. void xxxTrackThumb(
  1700. PWND pwnd,
  1701. UINT message,
  1702. WPARAM wParam,
  1703. LPARAM lParam,
  1704. PSBCALC pSBCalc)
  1705. {
  1706. int px;
  1707. PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
  1708. POINT pt;
  1709. UNREFERENCED_PARAMETER(wParam);
  1710. CheckLock(pwnd);
  1711. if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
  1712. return;
  1713. if (pSBTrack == NULL)
  1714. return;
  1715. // Make sure that the SBINFO structure contains data for the
  1716. // window being tracked -- if not, recalculate data in SBINFO
  1717. // CheckScrollRecalc(pwnd, pSBState, pSBCalc);
  1718. if (pSBTrack->fTrackRecalc) {
  1719. RecalcTrackRect(pSBTrack);
  1720. pSBTrack->fTrackRecalc = FALSE;
  1721. }
  1722. pt.y = GET_Y_LPARAM(lParam);
  1723. pt.x = GET_X_LPARAM(lParam);
  1724. if (!PtInRect(&pSBTrack->rcTrack, pt))
  1725. px = pSBCalc->pxStart;
  1726. else {
  1727. px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
  1728. if (px < pSBCalc->pxMin)
  1729. px = pSBCalc->pxMin;
  1730. else if (px >= pSBCalc->pxMin + pSBCalc->cpx)
  1731. px = pSBCalc->pxMin + pSBCalc->cpx;
  1732. }
  1733. xxxMoveThumb(pwnd, pSBCalc, px);
  1734. /*
  1735. * We won't get the WM_LBUTTONUP message if we got here through
  1736. * the scroll menu, so test the button state directly.
  1737. */
  1738. if (message == WM_LBUTTONUP || _GetKeyState(VK_LBUTTON) >= 0) {
  1739. xxxEndScroll(pwnd, FALSE);
  1740. }
  1741. }
  1742. /***************************************************************************\
  1743. * xxxSBTrackLoop
  1744. *
  1745. *
  1746. *
  1747. * History:
  1748. \***************************************************************************/
  1749. void xxxSBTrackLoop(
  1750. PWND pwnd,
  1751. LPARAM lParam,
  1752. PSBCALC pSBCalc)
  1753. {
  1754. MSG msg;
  1755. UINT cmd;
  1756. PTHREADINFO ptiCurrent;
  1757. VOID (*xxxpfnSB)(PWND, UINT, WPARAM, LPARAM, PSBCALC);
  1758. PSBTRACK pSBTrack;
  1759. CheckLock(pwnd);
  1760. UserAssert(IsWinEventNotifyDeferredOK());
  1761. pSBTrack = PWNDTOPSBTRACK(pwnd);
  1762. if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
  1763. // mode cancelled -- exit track loop
  1764. return;
  1765. if (pSBTrack->fTrackVert)
  1766. SetWF(pwnd, WFVERTSCROLLTRACK);
  1767. xxxWindowEvent(EVENT_SYSTEM_SCROLLINGSTART, pwnd,
  1768. (pSBTrack->fCtlSB ? OBJID_CLIENT :
  1769. (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
  1770. INDEXID_CONTAINER, 0);
  1771. // Note: after xxx, pSBTrack may no longer be valid
  1772. (*xxxpfnSB)(pwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc);
  1773. // Note: after xxx, pSBTrack may no longer be valid
  1774. ptiCurrent = PtiCurrent();
  1775. while (ptiCurrent->pq->spwndCapture == pwnd) {
  1776. if (!xxxGetMessage(&msg, NULL, 0, 0)) {
  1777. // Note: after xxx, pSBTrack may no longer be valid
  1778. break;
  1779. }
  1780. if (!_CallMsgFilter(&msg, MSGF_SCROLLBAR)) {
  1781. cmd = msg.message;
  1782. if (msg.hwnd == HWq(pwnd) && ((cmd >= WM_MOUSEFIRST && cmd <=
  1783. WM_MOUSELAST) || (cmd >= WM_KEYFIRST &&
  1784. cmd <= WM_KEYLAST))) {
  1785. cmd = SystoChar(cmd, msg.lParam);
  1786. // After xxxWindowEvent, xxxpfnSB, xxxTranslateMessage or
  1787. // xxxDispatchMessage, re-evaluate pSBTrack.
  1788. REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
  1789. if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
  1790. // mode cancelled -- exit track loop
  1791. return;
  1792. (*xxxpfnSB)(pwnd, cmd, msg.wParam, msg.lParam, pSBCalc);
  1793. } else {
  1794. xxxTranslateMessage(&msg, 0);
  1795. xxxDispatchMessage(&msg);
  1796. }
  1797. }
  1798. }
  1799. }
  1800. /***************************************************************************\
  1801. * xxxSBTrackInit
  1802. *
  1803. * History:
  1804. \***************************************************************************/
  1805. void xxxSBTrackInit(
  1806. PWND pwnd,
  1807. LPARAM lParam,
  1808. int curArea,
  1809. UINT uType)
  1810. {
  1811. int px;
  1812. LPINT pwX;
  1813. LPINT pwY;
  1814. UINT wDisable; // Scroll bar disable flags;
  1815. SBCALC SBCalc;
  1816. PSBCALC pSBCalc;
  1817. RECT rcSB;
  1818. PSBTRACK pSBTrack;
  1819. CheckLock(pwnd);
  1820. if (PWNDTOPSBTRACK(pwnd)) {
  1821. RIPMSG1(RIP_WARNING, "xxxSBTrackInit: PWNDTOPSBTRACK(pwnd) == %#p",
  1822. PWNDTOPSBTRACK(pwnd));
  1823. return;
  1824. }
  1825. pSBTrack = (PSBTRACK)UserAllocPoolWithQuota(sizeof(*pSBTrack), TAG_SCROLLTRACK);
  1826. if (pSBTrack == NULL)
  1827. return;
  1828. pSBTrack->hTimerSB = 0;
  1829. pSBTrack->fHitOld = FALSE;
  1830. pSBTrack->xxxpfnSB = xxxTrackBox;
  1831. pSBTrack->spwndTrack = NULL;
  1832. pSBTrack->spwndSB = NULL;
  1833. pSBTrack->spwndSBNotify = NULL;
  1834. Lock(&pSBTrack->spwndTrack, pwnd);
  1835. PWNDTOPSBTRACK(pwnd) = pSBTrack;
  1836. pSBTrack->fCtlSB = (!curArea);
  1837. if (pSBTrack->fCtlSB) {
  1838. /*
  1839. * This is a scroll bar control.
  1840. */
  1841. Lock(&pSBTrack->spwndSB, pwnd);
  1842. pSBTrack->fTrackVert = ((PSBWND)pwnd)->fVert;
  1843. Lock(&pSBTrack->spwndSBNotify, pwnd->spwndParent);
  1844. wDisable = ((PSBWND)pwnd)->wDisableFlags;
  1845. pSBCalc = &((PSBWND)pwnd)->SBCalc;
  1846. pSBTrack->nBar = SB_CTL;
  1847. } else {
  1848. /*
  1849. * This is a scroll bar that is part of the window frame.
  1850. */
  1851. //
  1852. // Mirror the window coord of the scroll bar,
  1853. // if it is a mirrored one
  1854. //
  1855. if (TestWF(pwnd,WEFLAYOUTRTL)) {
  1856. lParam = MAKELONG(
  1857. pwnd->rcWindow.right - GET_X_LPARAM(lParam),
  1858. GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
  1859. } else {
  1860. lParam = MAKELONG(
  1861. GET_X_LPARAM(lParam) - pwnd->rcWindow.left,
  1862. GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
  1863. }
  1864. Lock(&pSBTrack->spwndSBNotify, pwnd);
  1865. Lock(&pSBTrack->spwndSB, NULL);
  1866. pSBTrack->fTrackVert = (curArea - HTHSCROLL);
  1867. wDisable = GetWndSBDisableFlags(pwnd, pSBTrack->fTrackVert);
  1868. pSBCalc = &SBCalc;
  1869. pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ;
  1870. }
  1871. pSBTrack->pSBCalc = pSBCalc;
  1872. /*
  1873. * Check if the whole scroll bar is disabled
  1874. */
  1875. if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  1876. Unlock(&pSBTrack->spwndSBNotify);
  1877. Unlock(&pSBTrack->spwndSB);
  1878. Unlock(&pSBTrack->spwndTrack);
  1879. UserFreePool(pSBTrack);
  1880. PWNDTOPSBTRACK(pwnd) = NULL;
  1881. return; // It is a disabled scroll bar; So, do not respond.
  1882. }
  1883. if (!pSBTrack->fCtlSB) {
  1884. CalcSBStuff(pwnd, pSBCalc, pSBTrack->fTrackVert);
  1885. }
  1886. pwX = (LPINT)&rcSB;
  1887. pwY = pwX + 1;
  1888. if (!pSBTrack->fTrackVert)
  1889. pwX = pwY--;
  1890. px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
  1891. *(pwX + 0) = pSBCalc->pxLeft;
  1892. *(pwY + 0) = pSBCalc->pxTop;
  1893. *(pwX + 2) = pSBCalc->pxRight;
  1894. *(pwY + 2) = pSBCalc->pxBottom;
  1895. pSBTrack->cmdSB = (UINT)-1;
  1896. if (px < pSBCalc->pxUpArrow) {
  1897. /*
  1898. * The click occurred on Left/Up arrow; Check if it is disabled
  1899. */
  1900. if(wDisable & LTUPFLAG) {
  1901. if(pSBTrack->fCtlSB) { // If this is a scroll bar control,
  1902. zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
  1903. // After zzzShowCaret, revalidate pSBTrack
  1904. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1905. }
  1906. Unlock(&pSBTrack->spwndSBNotify);
  1907. Unlock(&pSBTrack->spwndSB);
  1908. Unlock(&pSBTrack->spwndTrack);
  1909. UserFreePool(pSBTrack);
  1910. PWNDTOPSBTRACK(pwnd) = NULL;
  1911. return; // Yes! disabled. Do not respond.
  1912. }
  1913. // LINEUP -- make rcSB the Up Arrow's Rectangle
  1914. pSBTrack->cmdSB = SB_LINEUP;
  1915. *(pwY + 2) = pSBCalc->pxUpArrow;
  1916. } else if (px >= pSBCalc->pxDownArrow) {
  1917. /*
  1918. * The click occurred on Right/Down arrow; Check if it is disabled
  1919. */
  1920. if (wDisable & RTDNFLAG) {
  1921. if (pSBTrack->fCtlSB) { // If this is a scroll bar control,
  1922. zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
  1923. // After zzzShowCaret, revalidate pSBTrack
  1924. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1925. }
  1926. Unlock(&pSBTrack->spwndSBNotify);
  1927. Unlock(&pSBTrack->spwndSB);
  1928. Unlock(&pSBTrack->spwndTrack);
  1929. UserFreePool(pSBTrack);
  1930. PWNDTOPSBTRACK(pwnd) = NULL;
  1931. return;// Yes! disabled. Do not respond.
  1932. }
  1933. // LINEDOWN -- make rcSB the Down Arrow's Rectangle
  1934. pSBTrack->cmdSB = SB_LINEDOWN;
  1935. *(pwY + 0) = pSBCalc->pxDownArrow;
  1936. } else if (px < pSBCalc->pxThumbTop) {
  1937. // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
  1938. pSBTrack->cmdSB = SB_PAGEUP;
  1939. *(pwY + 0) = pSBCalc->pxUpArrow;
  1940. *(pwY + 2) = pSBCalc->pxThumbTop;
  1941. } else if (px < pSBCalc->pxThumbBottom) {
  1942. DoThumbPos:
  1943. /*
  1944. * Elevator isn't there if there's no room.
  1945. */
  1946. if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) {
  1947. Unlock(&pSBTrack->spwndSBNotify);
  1948. Unlock(&pSBTrack->spwndSB);
  1949. Unlock(&pSBTrack->spwndTrack);
  1950. UserFreePool(pSBTrack);
  1951. PWNDTOPSBTRACK(pwnd) = NULL;
  1952. return;
  1953. }
  1954. // THUMBPOSITION -- we're tracking with the thumb
  1955. pSBTrack->cmdSB = SB_THUMBPOSITION;
  1956. CalcTrackDragRect(pSBTrack);
  1957. pSBTrack->xxxpfnSB = xxxTrackThumb;
  1958. pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop;
  1959. pSBTrack->posNew = pSBTrack->posOld = pSBCalc->pos;
  1960. pSBTrack->dpxThumb = pSBCalc->pxStart - px;
  1961. xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
  1962. // After xxxCapture, revalidate pSBTrack
  1963. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1964. /*
  1965. * DoScroll does thread locking on these two pwnds -
  1966. * this is ok since they are not used after this
  1967. * call.
  1968. */
  1969. if (pSBTrack->spwndSBNotify != NULL) {
  1970. xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
  1971. SB_THUMBTRACK, pSBTrack->posOld, pSBTrack->fTrackVert
  1972. );
  1973. // Note: after xxx, pSBTrack may no longer be valid
  1974. }
  1975. } else if (px < pSBCalc->pxDownArrow) {
  1976. // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
  1977. pSBTrack->cmdSB = SB_PAGEDOWN;
  1978. *(pwY + 0) = pSBCalc->pxThumbBottom;
  1979. *(pwY + 2) = pSBCalc->pxDownArrow;
  1980. }
  1981. /*
  1982. * If the shift key is down, we'll position the thumb directly so it's
  1983. * centered on the click point.
  1984. */
  1985. if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) ||
  1986. (uType == SCROLL_MENU)) {
  1987. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  1988. goto DoThumbPos;
  1989. }
  1990. pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2);
  1991. }
  1992. xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
  1993. // After xxxCapture, revalidate pSBTrack
  1994. RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
  1995. if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
  1996. CopyRect(&pSBTrack->rcTrack, &rcSB);
  1997. }
  1998. xxxSBTrackLoop(pwnd, lParam, pSBCalc);
  1999. // After xxx, re-evaluate pSBTrack
  2000. REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
  2001. if (pSBTrack) {
  2002. Unlock(&pSBTrack->spwndSBNotify);
  2003. Unlock(&pSBTrack->spwndSB);
  2004. Unlock(&pSBTrack->spwndTrack);
  2005. UserFreePool(pSBTrack);
  2006. PWNDTOPSBTRACK(pwnd) = NULL;
  2007. }
  2008. }
  2009. /***************************************************************************\
  2010. * GetScrollMenu
  2011. *
  2012. * History:
  2013. \***************************************************************************/
  2014. PMENU xxxGetScrollMenu(
  2015. PWND pwnd,
  2016. BOOL fVert)
  2017. {
  2018. PMENU pMenu;
  2019. PMENU *ppDesktopMenu;
  2020. /*
  2021. * Grab the menu from the desktop. If the desktop menu
  2022. * has not been loaded and this is not a system thread,
  2023. * load it now. Callbacks cannot be made from a system
  2024. * thread or when a thread is in cleanup.
  2025. */
  2026. if (fVert) {
  2027. ppDesktopMenu = &pwnd->head.rpdesk->spmenuVScroll;
  2028. } else {
  2029. ppDesktopMenu = &pwnd->head.rpdesk->spmenuHScroll;
  2030. }
  2031. pMenu = *ppDesktopMenu;
  2032. if (pMenu == NULL && !(PtiCurrent()->TIF_flags & (TIF_SYSTEMTHREAD | TIF_INCLEANUP))) {
  2033. UNICODE_STRING strMenuName;
  2034. RtlInitUnicodeStringOrId(&strMenuName,
  2035. fVert ? MAKEINTRESOURCE(ID_VSCROLLMENU) : MAKEINTRESOURCE(ID_HSCROLLMENU));
  2036. pMenu = xxxClientLoadMenu(NULL, &strMenuName);
  2037. LockDesktopMenu(ppDesktopMenu, pMenu);
  2038. }
  2039. /*
  2040. * Return the handle to the scroll menu.
  2041. */
  2042. if (pMenu != NULL) {
  2043. return _GetSubMenu(pMenu, 0);
  2044. }
  2045. return NULL;
  2046. }
  2047. /***************************************************************************\
  2048. * xxxDoScrollMenu
  2049. *
  2050. * History:
  2051. \***************************************************************************/
  2052. VOID
  2053. xxxDoScrollMenu(
  2054. PWND pwndNotify,
  2055. PWND pwndSB,
  2056. BOOL fVert,
  2057. LPARAM lParam)
  2058. {
  2059. PMENU pMenu;
  2060. SBCALC SBCalc, *pSBCalc;
  2061. UINT cmd;
  2062. POINT pt;
  2063. TL tlpmenu;
  2064. UINT wDisable;
  2065. /*
  2066. * Check the compatibility flag. Word 6.0 AV's when selecting an item
  2067. * in this menu.
  2068. * NOTE: If this hack is to be extended for other apps we should use
  2069. * another bit for GACF_NOSCROLLBARCTXMENU as the current one is re-used
  2070. * MCostea #119380
  2071. */
  2072. if (GetAppCompatFlags(NULL) & GACF_NOSCROLLBARCTXMENU) {
  2073. return;
  2074. }
  2075. /*
  2076. * Initialize some stuff.
  2077. */
  2078. POINTSTOPOINT(pt, lParam);
  2079. if (pwndSB) {
  2080. SBCtlSetup((PSBWND)pwndSB);
  2081. pSBCalc = &(((PSBWND)pwndSB)->SBCalc);
  2082. wDisable = ((PSBWND)pwndSB)->wDisableFlags;
  2083. pt.x -= pwndSB->rcWindow.left;
  2084. pt.y -= pwndSB->rcWindow.top;
  2085. } else {
  2086. pSBCalc = &SBCalc;
  2087. CalcSBStuff(pwndNotify, pSBCalc, fVert);
  2088. wDisable = GetWndSBDisableFlags(pwndNotify, fVert);
  2089. pt.x -= pwndNotify->rcWindow.left;
  2090. pt.y -= pwndNotify->rcWindow.top;
  2091. }
  2092. /*
  2093. * Make sure the scrollbar isn't disabled.
  2094. */
  2095. if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
  2096. return;
  2097. }
  2098. /*
  2099. * Put up a menu and scroll accordingly.
  2100. */
  2101. if ((pMenu = xxxGetScrollMenu(pwndNotify, fVert)) != NULL) {
  2102. ThreadLockAlways(pMenu, &tlpmenu);
  2103. cmd = xxxTrackPopupMenuEx(pMenu,
  2104. TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
  2105. GET_X_LPARAM(lParam),
  2106. GET_Y_LPARAM(lParam),
  2107. pwndNotify,
  2108. NULL);
  2109. ThreadUnlock(&tlpmenu);
  2110. if (cmd) {
  2111. if ((cmd & 0x00FF) == SB_THUMBPOSITION) {
  2112. if (pwndSB) {
  2113. xxxSBTrackInit(pwndSB, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU);
  2114. } else {
  2115. xxxSBTrackInit(pwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU);
  2116. }
  2117. } else {
  2118. xxxDoScroll(pwndSB,
  2119. pwndNotify,
  2120. cmd & 0x00FF,
  2121. 0,
  2122. fVert
  2123. );
  2124. xxxDoScroll(pwndSB,
  2125. pwndNotify,
  2126. SB_ENDSCROLL,
  2127. 0,
  2128. fVert
  2129. );
  2130. }
  2131. }
  2132. }
  2133. }
  2134. /***************************************************************************\
  2135. * xxxSBWndProc
  2136. *
  2137. * History:
  2138. * 08-15-95 jparsons Added guard against NULL lParam [51986]
  2139. \***************************************************************************/
  2140. LRESULT xxxSBWndProc(
  2141. PSBWND psbwnd,
  2142. UINT message,
  2143. WPARAM wParam,
  2144. LPARAM lParam)
  2145. {
  2146. LONG l;
  2147. LONG lres;
  2148. int cx;
  2149. int cy;
  2150. UINT cmd;
  2151. UINT uSide;
  2152. HDC hdc;
  2153. RECT rc;
  2154. POINT pt;
  2155. BOOL fSizeReal;
  2156. HBRUSH hbrSave;
  2157. BOOL fSize;
  2158. PAINTSTRUCT ps;
  2159. UINT style;
  2160. TL tlpwndParent;
  2161. SCROLLINFO si;
  2162. LPSCROLLINFO lpsi = &si;
  2163. BOOL fRedraw = FALSE;
  2164. BOOL fScroll;
  2165. CheckLock(psbwnd);
  2166. UserAssert(IsWinEventNotifyDeferredOK());
  2167. VALIDATECLASSANDSIZE(((PWND)psbwnd), message, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
  2168. style = LOBYTE(psbwnd->wnd.style);
  2169. fSize = ((style & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
  2170. switch (message) {
  2171. case WM_CREATE:
  2172. /*
  2173. * Guard against lParam being NULL since the thunk allows it [51986]
  2174. */
  2175. if (lParam) {
  2176. rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) +
  2177. ((LPCREATESTRUCT)lParam)->cx;
  2178. rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) +
  2179. ((LPCREATESTRUCT)lParam)->cy;
  2180. // This is because we can't just rev CardFile -- we should fix the
  2181. // problem here in case anyone else happened to have some EXTRA
  2182. // scroll styles on their scroll bar controls (jeffbog 03/21/94)
  2183. if (!TestWF((PWND)psbwnd, WFWIN40COMPAT))
  2184. psbwnd->wnd.style &= ~(WS_HSCROLL | WS_VSCROLL);
  2185. if (!fSize) {
  2186. l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams);
  2187. psbwnd->SBCalc.pos = psbwnd->SBCalc.posMin = LOWORD(l);
  2188. psbwnd->SBCalc.posMax = HIWORD(l);
  2189. psbwnd->fVert = ((LOBYTE(psbwnd->wnd.style) & SBS_VERT) != 0);
  2190. psbwnd->SBCalc.page = 0;
  2191. }
  2192. if (psbwnd->wnd.style & WS_DISABLED)
  2193. psbwnd->wDisableFlags = SB_DISABLE_MASK;
  2194. if (style & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) {
  2195. if (fSize) {
  2196. if (style & SBS_SIZEBOXBOTTOMRIGHTALIGN) {
  2197. rc.left = rc.right - SYSMET(CXVSCROLL);
  2198. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  2199. }
  2200. rc.right = rc.left + SYSMET(CXVSCROLL);
  2201. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  2202. } else {
  2203. if (style & SBS_VERT) {
  2204. if (style & SBS_LEFTALIGN)
  2205. rc.right = rc.left + SYSMET(CXVSCROLL);
  2206. else
  2207. rc.left = rc.right - SYSMET(CXVSCROLL);
  2208. } else {
  2209. if (style & SBS_TOPALIGN)
  2210. rc.bottom = rc.top + SYSMET(CYHSCROLL);
  2211. else
  2212. rc.top = rc.bottom - SYSMET(CYHSCROLL);
  2213. }
  2214. }
  2215. xxxMoveWindow((PWND)psbwnd, rc.left, rc.top, rc.right - rc.left,
  2216. rc.bottom - rc.top, FALSE);
  2217. }
  2218. } /* if */
  2219. else {
  2220. RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING,
  2221. "xxxSBWndProc - NULL lParam for WM_CREATE\n") ;
  2222. } /* else */
  2223. break;
  2224. case WM_SIZE:
  2225. if (PtiCurrent()->pq->spwndFocus != (PWND)psbwnd)
  2226. break;
  2227. // scroll bar has the focus -- recalc it's thumb caret size
  2228. // no need to DeferWinEventNotify() - see xxxCreateCaret below.
  2229. zzzDestroyCaret();
  2230. // | |
  2231. // | FALL THRU |
  2232. // V V
  2233. case WM_SETFOCUS:
  2234. SBCtlSetup(psbwnd);
  2235. cx = (psbwnd->fVert ? psbwnd->wnd.rcWindow.right - psbwnd->wnd.rcWindow.left
  2236. : psbwnd->SBCalc.cpxThumb) - 2 * SYSMET(CXEDGE);
  2237. cy = (psbwnd->fVert ? psbwnd->SBCalc.cpxThumb
  2238. : psbwnd->wnd.rcWindow.bottom - psbwnd->wnd.rcWindow.top) - 2 * SYSMET(CYEDGE);
  2239. xxxCreateCaret((PWND)psbwnd, (HBITMAP)1, cx, cy);
  2240. zzzSetSBCaretPos(psbwnd);
  2241. zzzShowCaret((PWND)psbwnd);
  2242. break;
  2243. case WM_KILLFOCUS:
  2244. zzzDestroyCaret();
  2245. break;
  2246. case WM_ERASEBKGND:
  2247. /*
  2248. * Do nothing, but don't let DefWndProc() do it either.
  2249. * It will be erased when its painted.
  2250. */
  2251. return (LONG)TRUE;
  2252. case WM_PRINTCLIENT:
  2253. case WM_PAINT:
  2254. if ((hdc = (HDC)wParam) == NULL) {
  2255. hdc = xxxBeginPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
  2256. }
  2257. if (!fSize) {
  2258. SBCtlSetup(psbwnd);
  2259. xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags);
  2260. } else {
  2261. fSizeReal = TestWF((PWND)psbwnd, WFSIZEBOX);
  2262. if (!fSizeReal)
  2263. SetWF((PWND)psbwnd, WFSIZEBOX);
  2264. DrawSize((PWND)psbwnd, hdc, 0, 0);
  2265. if (!fSizeReal)
  2266. ClrWF((PWND)psbwnd, WFSIZEBOX);
  2267. }
  2268. if (wParam == 0L)
  2269. xxxEndPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
  2270. break;
  2271. case WM_GETDLGCODE:
  2272. return DLGC_WANTARROWS;
  2273. case WM_CONTEXTMENU:
  2274. ThreadLock(psbwnd->wnd.spwndParent, &tlpwndParent);
  2275. xxxDoScrollMenu(psbwnd->wnd.spwndParent, (PWND)psbwnd, psbwnd->fVert, lParam);
  2276. ThreadUnlock(&tlpwndParent);
  2277. break;
  2278. case WM_NCHITTEST:
  2279. if (style & SBS_SIZEGRIP) {
  2280. /*
  2281. * If the scroll bar is RTL mirrored, then
  2282. * mirror the hittest of the grip location.
  2283. */
  2284. if (TestWF((PWND)psbwnd, WEFLAYOUTRTL)) {
  2285. return HTBOTTOMLEFT;
  2286. } else {
  2287. return HTBOTTOMRIGHT;
  2288. }
  2289. } else {
  2290. goto DoDefault;
  2291. }
  2292. break;
  2293. #ifdef COLOR_HOTTRACKING
  2294. case WM_MOUSELEAVE:
  2295. xxxHotTrackSBCtl(psbwnd, 0, FALSE);
  2296. psbwnd->ht = 0;
  2297. break;
  2298. case WM_MOUSEMOVE:
  2299. {
  2300. int ht;
  2301. if (psbwnd->ht == 0) {
  2302. TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, HWq(psbwnd), 0};
  2303. TrackMouseEvent(&tme);
  2304. }
  2305. pt.x = GET_X_LPARAM(lParam);
  2306. pt.y = GET_Y_LPARAM(lParam);
  2307. ht = HitTestScrollBar((PWND)psbwnd, psbwnd->fVert, pt);
  2308. if (psbwnd->ht != ht) {
  2309. xxxHotTrackSBCtl(psbwnd, ht, TRUE);
  2310. psbwnd->ht = ht;
  2311. }
  2312. }
  2313. break;
  2314. #endif // COLOR_HOTTRACKING
  2315. case WM_LBUTTONDBLCLK:
  2316. cmd = SC_ZOOM;
  2317. if (fSize)
  2318. goto postmsg;
  2319. /*
  2320. *** FALL THRU **
  2321. */
  2322. case WM_LBUTTONDOWN:
  2323. //
  2324. // Note that SBS_SIZEGRIP guys normally won't ever see button
  2325. // downs. This is because they return HTBOTTOMRIGHT to
  2326. // WindowHitTest handling. This will walk up the parent chain
  2327. // to the first sizeable ancestor, bailing out at caption windows
  2328. // of course. That dude, if he exists, will handle the sizing
  2329. // instead.
  2330. //
  2331. if (!fSize) {
  2332. if (TestWF((PWND)psbwnd, WFTABSTOP)) {
  2333. xxxSetFocus((PWND)psbwnd);
  2334. }
  2335. zzzHideCaret((PWND)psbwnd);
  2336. SBCtlSetup(psbwnd);
  2337. /*
  2338. * SBCtlSetup enters SEM_SB, and xxxSBTrackInit leaves it.
  2339. */
  2340. xxxSBTrackInit((PWND)psbwnd, lParam, 0, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
  2341. break;
  2342. } else {
  2343. cmd = SC_SIZE;
  2344. postmsg:
  2345. pt.x = GET_X_LPARAM(lParam);
  2346. pt.y = GET_Y_LPARAM(lParam);
  2347. _ClientToScreen((PWND)psbwnd, &pt);
  2348. lParam = MAKELONG(pt.x, pt.y);
  2349. /*
  2350. * convert HT value into a move value. This is bad,
  2351. * but this is purely temporary.
  2352. */
  2353. if (TestWF(((PWND)psbwnd)->spwndParent,WEFLAYOUTRTL)) {
  2354. uSide = HTBOTTOMLEFT;
  2355. } else {
  2356. uSide = HTBOTTOMRIGHT;
  2357. }
  2358. ThreadLock(((PWND)psbwnd)->spwndParent, &tlpwndParent);
  2359. xxxSendMessage(((PWND)psbwnd)->spwndParent, WM_SYSCOMMAND,
  2360. (cmd | (uSide - HTSIZEFIRST + 1)), lParam);
  2361. ThreadUnlock(&tlpwndParent);
  2362. }
  2363. break;
  2364. case WM_KEYUP:
  2365. switch (wParam) {
  2366. case VK_HOME:
  2367. case VK_END:
  2368. case VK_PRIOR:
  2369. case VK_NEXT:
  2370. case VK_LEFT:
  2371. case VK_UP:
  2372. case VK_RIGHT:
  2373. case VK_DOWN:
  2374. /*
  2375. * Send end scroll message when user up clicks on keyboard
  2376. * scrolling.
  2377. *
  2378. * DoScroll does thread locking on these two pwnds -
  2379. * this is ok since they are not used after this
  2380. * call.
  2381. */
  2382. xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent,
  2383. SB_ENDSCROLL, 0, psbwnd->fVert
  2384. );
  2385. break;
  2386. default:
  2387. break;
  2388. }
  2389. break;
  2390. case WM_KEYDOWN:
  2391. switch (wParam) {
  2392. case VK_HOME:
  2393. wParam = SB_TOP;
  2394. goto KeyScroll;
  2395. case VK_END:
  2396. wParam = SB_BOTTOM;
  2397. goto KeyScroll;
  2398. case VK_PRIOR:
  2399. wParam = SB_PAGEUP;
  2400. goto KeyScroll;
  2401. case VK_NEXT:
  2402. wParam = SB_PAGEDOWN;
  2403. goto KeyScroll;
  2404. case VK_LEFT:
  2405. case VK_UP:
  2406. wParam = SB_LINEUP;
  2407. goto KeyScroll;
  2408. case VK_RIGHT:
  2409. case VK_DOWN:
  2410. wParam = SB_LINEDOWN;
  2411. KeyScroll:
  2412. /*
  2413. * DoScroll does thread locking on these two pwnds -
  2414. * this is ok since they are not used after this
  2415. * call.
  2416. */
  2417. xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent, (int)wParam,
  2418. 0, psbwnd->fVert
  2419. );
  2420. break;
  2421. default:
  2422. break;
  2423. }
  2424. break;
  2425. case WM_ENABLE:
  2426. return xxxSendMessage((PWND)psbwnd, SBM_ENABLE_ARROWS,
  2427. (wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
  2428. case SBM_ENABLE_ARROWS:
  2429. /*
  2430. * This is used to enable/disable the arrows in a SB ctrl
  2431. */
  2432. return (LONG)xxxEnableSBCtlArrows((PWND)psbwnd, (UINT)wParam);
  2433. case SBM_GETPOS:
  2434. return (LONG)psbwnd->SBCalc.pos;
  2435. case SBM_GETRANGE:
  2436. *((LPINT)wParam) = psbwnd->SBCalc.posMin;
  2437. *((LPINT)lParam) = psbwnd->SBCalc.posMax;
  2438. return MAKELRESULT(LOWORD(psbwnd->SBCalc.posMin), LOWORD(psbwnd->SBCalc.posMax));
  2439. case SBM_GETSCROLLINFO:
  2440. return (LONG)_SBGetParms((PWND)psbwnd, SB_CTL, (PSBDATA)&psbwnd->SBCalc, (LPSCROLLINFO) lParam);
  2441. case SBM_SETRANGEREDRAW:
  2442. fRedraw = TRUE;
  2443. case SBM_SETRANGE:
  2444. // Save the old values of Min and Max for return value
  2445. si.cbSize = sizeof(si);
  2446. // si.nMin = LOWORD(lParam);
  2447. // si.nMax = HIWORD(lParam);
  2448. si.nMin = (int)wParam;
  2449. si.nMax = (int)lParam;
  2450. si.fMask = SIF_RANGE | SIF_RETURNOLDPOS;
  2451. goto SetInfo;
  2452. case SBM_SETPOS:
  2453. fRedraw = (BOOL) lParam;
  2454. si.cbSize = sizeof(si);
  2455. si.fMask = SIF_POS | SIF_RETURNOLDPOS;
  2456. si.nPos = (int)wParam;
  2457. goto SetInfo;
  2458. case SBM_SETSCROLLINFO:
  2459. lpsi = (LPSCROLLINFO) lParam;
  2460. fRedraw = (BOOL) wParam;
  2461. SetInfo:
  2462. fScroll = TRUE;
  2463. if (SBSetParms((PSBDATA)&psbwnd->SBCalc, lpsi, &fScroll, &lres)) {
  2464. xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, (PWND)psbwnd, OBJID_CLIENT,
  2465. INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
  2466. }
  2467. if (!fRedraw)
  2468. return lres;
  2469. /*
  2470. * We must set the new position of the caret irrespective of
  2471. * whether the window is visible or not;
  2472. * Still, this will work only if the app has done a xxxSetScrollPos
  2473. * with fRedraw = TRUE;
  2474. * Fix for Bug #5188 --SANKAR-- 10-15-89
  2475. * No need to DeferWinEventNotify since psbwnd is locked.
  2476. */
  2477. zzzHideCaret((PWND)psbwnd);
  2478. SBCtlSetup(psbwnd);
  2479. zzzSetSBCaretPos(psbwnd);
  2480. /*
  2481. ** The following zzzShowCaret() must be done after the DrawThumb2(),
  2482. ** otherwise this caret will be erased by DrawThumb2() resulting
  2483. ** in this bug:
  2484. ** Fix for Bug #9263 --SANKAR-- 02-09-90
  2485. *
  2486. */
  2487. /*
  2488. *********** zzzShowCaret((PWND)psbwnd); ******
  2489. */
  2490. if (_FChildVisible((PWND)psbwnd) && fRedraw) {
  2491. UINT wDisable;
  2492. HBRUSH hbrUse;
  2493. if (!fScroll)
  2494. fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
  2495. wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
  2496. xxxEnableScrollBar((PWND) psbwnd, SB_CTL, wDisable);
  2497. hdc = _GetWindowDC((PWND)psbwnd);
  2498. hbrSave = GreSelectBrush(hdc, hbrUse = xxxGetColorObjects((PWND)psbwnd, hdc));
  2499. /*
  2500. * Before we used to only hideshowthumb() if the mesage was
  2501. * not SBM_SETPOS. I am not sure why but this case was ever
  2502. * needed for win 3.x but on NT it resulted in trashing the border
  2503. * of the scrollbar when the app called SetScrollPos() during
  2504. * scrollbar tracking. - mikehar 8/26
  2505. */
  2506. DrawThumb2((PWND)psbwnd, &psbwnd->SBCalc, hdc, hbrUse, psbwnd->fVert,
  2507. psbwnd->wDisableFlags);
  2508. GreSelectBrush(hdc, hbrSave);
  2509. _ReleaseDC(hdc);
  2510. }
  2511. /*
  2512. * This zzzShowCaret() has been moved to this place from above
  2513. * Fix for Bug #9263 --SANKAR-- 02-09-90
  2514. */
  2515. zzzShowCaret((PWND)psbwnd);
  2516. return lres;
  2517. case SBM_GETSCROLLBARINFO:
  2518. return (LONG)xxxGetScrollBarInfo((PWND)psbwnd, OBJID_CLIENT, (PSCROLLBARINFO)lParam);
  2519. default:
  2520. DoDefault:
  2521. return xxxDefWindowProc((PWND)psbwnd, message, wParam, lParam);
  2522. }
  2523. return 0L;
  2524. }