test: sbctl.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# sbctl.c

Go to the documentation of this file.

    00001 /**************************** Module Header ********************************\
    00002 * Module Name: sbctl.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Scroll bar internal routines
    00007 *
    00008 * History:
    00009 *   11/21/90 JimA      Created.
    00010 *   02-04-91 IanJa     Revalidaion added
    00011 \***************************************************************************/
    00012
    00013 #include "precomp.h"
    00014 #pragma hdrstop
    00015
    00016 void CalcSBStuff(
    00017     PWND pwnd,
    00018     PSBCALC pSBCalc,
    00019     BOOL fVert);
    00020
    00021 #define IsScrollBarControl(h) (GETFNID(h) == FNID_SCROLLBAR)
    00022
    00023 /*
    00024  * Now it is possible to selectively Enable/Disable just one arrow of a Window
    00025  * scroll bar; Various bits in the 7th word in the rgwScroll array indicates which
    00026  * one of these arrows are disabled; The following masks indicate which bit of the
    00027  * word indicates which arrow;
    00028  */
    00029 #define WSB_HORZ_LF  0x0001  // Represents the Left arrow of the horizontal scroll bar.
    00030 #define WSB_HORZ_RT  0x0002  // Represents the Right arrow of the horizontal scroll bar.
    00031 #define WSB_VERT_UP  0x0004  // Represents the Up arrow of the vert scroll bar.
    00032 #define WSB_VERT_DN  0x0008  // Represents the Down arrow of the vert scroll bar.
    00033
    00034 #define WSB_VERT (WSB_VERT_UP | WSB_VERT_DN)
    00035 #define WSB_HORZ   (WSB_HORZ_LF | WSB_HORZ_RT)
    00036
    00037 void DrawCtlThumb(PSBWND);
    00038
    00039 /*
    00040  * RETURN_IF_PSBTRACK_INVALID:
    00041  * This macro tests whether the pSBTrack we have is invalid, which can happen
    00042  * if it gets freed during a callback.
    00043  * This protects agains the original pSBTrack being freed and no new one
    00044  * being allocated or a new one being allocated at a different address.
    00045  * This does not protect against the original pSBTrack being freed and a new
    00046  * one being allocated at the same address.
    00047  * If pSBTrack has changed, we assert that there is not already a new one
    00048  * because we are really not expecting this.
    00049  */
    00050 #define RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd) \
    00051     if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) {      \
    00052         UserAssert(PWNDTOPSBTRACK(pwnd) == NULL);  \
    00053         return;                                    \
    00054     }
    00055
    00056 /*
    00057  * REEVALUATE_PSBTRACK
    00058  * This macro just refreshes the local variable pSBTrack, in case it has
    00059  * been changed during a callback.  After performing this operation, pSBTrack
    00060  * should be tested to make sure it is not now NULL.
    00061  */
    00062 #if DBG
    00063 #define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str)          \
    00064     if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) {             \
    00065         RIPMSG3(RIP_WARNING,                              \
    00066                 "%s: pSBTrack changed from %#p to %#p",   \
    00067                 (str), (pSBTrack), PWNDTOPSBTRACK(pwnd)); \
    00068     }                                                     \
    00069     (pSBTrack) = PWNDTOPSBTRACK(pwnd)
    00070 #else
    00071 #define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str)          \
    00072     (pSBTrack) = PWNDTOPSBTRACK(pwnd)
    00073 #endif
    00074
    00075 /***************************************************************************\
    00076 * HitTestScrollBar
    00077 *
    00078 * 11/15/96      vadimg          ported from Memphis sources
    00079 \***************************************************************************/
    00080
    00081 int HitTestScrollBar(PWND pwnd, BOOL fVert, POINT pt)
    00082 {
    00083     UINT wDisable;
    00084     int px;
    00085     BOOL fCtl = IsScrollBarControl(pwnd);
    00086     SBCALC SBCalc, *pSBCalc;
    00087
    00088     if (fCtl) {
    00089         wDisable = ((PSBWND)pwnd)->wDisableFlags;
    00090     } else {
    00091 #ifdef USE_MIRRORING
    00092         //
    00093         // Reflect the click coordinates on the horizontal
    00094         // scroll bar if the window is mirrored
    00095         //
    00096         if (TestWF(pwnd,WEFLAYOUTRTL) && !fVert) {
    00097             pt.x = pwnd->rcWindow.right - pt.x;
    00098         }
    00099         else
    00100 #endif
    00101         pt.x -= pwnd->rcWindow.left;
    00102
    00103         pt.y -= pwnd->rcWindow.top;
    00104         wDisable = GetWndSBDisableFlags(pwnd, fVert);
    00105     }
    00106
    00107     if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
    00108         return HTERROR;
    00109     }
    00110
    00111     if (fCtl) {
    00112         pSBCalc = &(((PSBWND)pwnd)->SBCalc);
    00113     } else {
    00114         pSBCalc = &SBCalc;
    00115         CalcSBStuff(pwnd, pSBCalc, fVert);
    00116     }
    00117
    00118     px = fVert ? pt.y : pt.x;
    00119
    00120     if (px < pSBCalc->pxUpArrow) {
    00121         if (wDisable & LTUPFLAG) {
    00122             return HTERROR;
    00123         }
    00124         return HTSCROLLUP;
    00125     } else if (px >= pSBCalc->pxDownArrow) {
    00126         if (wDisable & RTDNFLAG) {
    00127             return HTERROR;
    00128         }
    00129         return HTSCROLLDOWN;
    00130     } else if (px < pSBCalc->pxThumbTop) {
    00131         return HTSCROLLUPPAGE;
    00132     } else if (px < pSBCalc->pxThumbBottom) {
    00133         return HTSCROLLTHUMB;
    00134     } else if (px < pSBCalc->pxDownArrow) {
    00135         return HTSCROLLDOWNPAGE;
    00136     }
    00137     return HTERROR;
    00138 }
    00139
    00140 BOOL _SBGetParms(
    00141     PWND pwnd,
    00142     int code,
    00143     PSBDATA pw,
    00144     LPSCROLLINFO lpsi)
    00145 {
    00146     PSBTRACK pSBTrack;
    00147
    00148     pSBTrack = PWNDTOPSBTRACK(pwnd);
    00149
    00150
    00151     if (lpsi->fMask & SIF_RANGE) {
    00152         lpsi->nMin = pw->posMin;
    00153         lpsi->nMax = pw->posMax;
    00154     }
    00155
    00156     if (lpsi->fMask & SIF_PAGE)
    00157         lpsi->nPage = pw->page;
    00158
    00159     if (lpsi->fMask & SIF_POS) {
    00160         lpsi->nPos = pw->pos;
    00161     }
    00162
    00163     if (lpsi->fMask & SIF_TRACKPOS)
    00164     {
    00165         if (pSBTrack && (pSBTrack->nBar == code) && (pSBTrack->spwndTrack == pwnd)) {
    00166             // posNew is in the context of psbiSB's window and bar code
    00167             lpsi->nTrackPos = pSBTrack->posNew;
    00168         } else {
    00169             lpsi->nTrackPos = pw->pos;
    00170         }
    00171     }
    00172     return ((lpsi->fMask & SIF_ALL) ? TRUE : FALSE);
    00173 }
    00174
    00175 /***************************************************************************\
    00176 * GetWndSBDisableFlags
    00177 *
    00178 * This returns the scroll bar Disable flags of the scroll bars of a
    00179 *  given Window.
    00180 *
    00181 *
    00182 * History:
    00183 *  4-18-91 MikeHar Ported for the 31 merge
    00184 \***************************************************************************/
    00185
    00186 UINT GetWndSBDisableFlags(
    00187     PWND pwnd,  // The window whose scroll bar Disable Flags are to be returned;
    00188     BOOL fVert)  // If this is TRUE, it means Vertical scroll bar.
    00189 {
    00190     PSBINFO pw;
    00191
    00192     if ((pw = pwnd->pSBInfo) == NULL) {
    00193         RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
    00194         return 0;
    00195     }
    00196
    00197     return (fVert ? (pw->WSBflags & WSB_VERT) >> 2 : pw->WSBflags & WSB_HORZ);
    00198 }
    00199
    00200
    00201 /***************************************************************************\
    00202 *  xxxEnableSBCtlArrows()
    00203 *
    00204 *  This function can be used to selectively Enable/Disable
    00205 *     the arrows of a scroll bar Control
    00206 *
    00207 * History:
    00208 * 04-18-91 MikeHar      Ported for the 31 merge
    00209 \***************************************************************************/
    00210
    00211 BOOL xxxEnableSBCtlArrows(
    00212     PWND pwnd,
    00213     UINT wArrows)
    00214 {
    00215     UINT wOldFlags;
    00216
    00217     CheckLock(pwnd);
    00218     UserAssert(IsWinEventNotifyDeferredOK());
    00219
    00220     wOldFlags = ((PSBWND)pwnd)->wDisableFlags; // Get the original status
    00221
    00222     if (wArrows == ESB_ENABLE_BOTH) {      // Enable both the arrows
    00223         ((PSBWND)pwnd)->wDisableFlags &= ~SB_DISABLE_MASK;
    00224     } else {
    00225         ((PSBWND)pwnd)->wDisableFlags |= wArrows;
    00226     }
    00227
    00228     /*
    00229      * Check if the status has changed because of this call
    00230      */
    00231     if (wOldFlags == ((PSBWND)pwnd)->wDisableFlags)
    00232         return FALSE;
    00233
    00234     /*
    00235      * Else, redraw the scroll bar control to reflect the new state
    00236      */
    00237     if (IsVisible(pwnd))
    00238         xxxInvalidateRect(pwnd, NULL, TRUE);
    00239
    00240     if (FWINABLE()) {
    00241         UINT wNewFlags = ((PSBWND)pwnd)->wDisableFlags;
    00242
    00243         /*
    00244          * state change notifications
    00245          */
    00246         if ((wOldFlags & ESB_DISABLE_UP) != (wNewFlags & ESB_DISABLE_UP)) {
    00247             xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
    00248                     INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
    00249         }
    00250
    00251         if ((wOldFlags & ESB_DISABLE_DOWN) != (wNewFlags & ESB_DISABLE_DOWN)) {
    00252             xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
    00253                     INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
    00254         }
    00255     }
    00256
    00257     return TRUE;
    00258 }
    00259
    00260
    00261 /***************************************************************************\
    00262 * xxxEnableWndSBArrows()
    00263 *
    00264 *  This function can be used to selectively Enable/Disable
    00265 *     the arrows of a Window Scroll bar(s)
    00266 *
    00267 * History:
    00268 *  4-18-91 MikeHar      Ported for the 31 merge
    00269 \***************************************************************************/
    00270
    00271 BOOL xxxEnableWndSBArrows(
    00272     PWND pwnd,
    00273     UINT wSBflags,
    00274     UINT wArrows)
    00275 {
    00276     INT wOldFlags;
    00277     PSBINFO pw;
    00278     BOOL bRetValue = FALSE;
    00279     HDC hdc;
    00280
    00281     CheckLock(pwnd);
    00282     UserAssert(IsWinEventNotifyDeferredOK());
    00283
    00284     if ((pw = pwnd->pSBInfo) != NULL) {
    00285         wOldFlags = pw->WSBflags;
    00286     } else {
    00287
    00288         /*
    00289          * Originally everything is enabled; Check to see if this function is
    00290          * asked to disable anything; Otherwise, no change in status; So, must
    00291          * return immediately;
    00292          */
    00293         if(!wArrows)
    00294             return FALSE;          // No change in status!
    00295
    00296         wOldFlags = 0;    // Both are originally enabled;
    00297         if((pw = _InitPwSB(pwnd)) == NULL)  // Allocate the pSBInfo for hWnd
    00298             return FALSE;
    00299     }
    00300
    00301
    00302     if((hdc = _GetWindowDC(pwnd)) == NULL)
    00303         return FALSE;
    00304
    00305     /*
    00306      *  First Take care of the Horizontal Scroll bar, if one exists.
    00307      */
    00308     if((wSBflags == SB_HORZ) || (wSBflags == SB_BOTH)) {
    00309         if(wArrows == ESB_ENABLE_BOTH)      // Enable both the arrows
    00310             pw->WSBflags &= ~SB_DISABLE_MASK;
    00311         else
    00312             pw->WSBflags |= wArrows;
    00313
    00314         /*
    00315          * Update the display of the Horizontal Scroll Bar;
    00316          */
    00317         if(pw->WSBflags != wOldFlags) {
    00318             bRetValue = TRUE;
    00319             wOldFlags = pw->WSBflags;
    00320             if (TestWF(pwnd, WFHPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
    00321                     IsVisible(pwnd)) {
    00322                 xxxDrawScrollBar(pwnd, hdc, FALSE);  // Horizontal Scroll Bar.
    00323             }
    00324         }
    00325         if (FWINABLE()) {
    00326             // Left button
    00327             if ((wOldFlags & ESB_DISABLE_LEFT) != (pw->WSBflags & ESB_DISABLE_LEFT)) {
    00328                 xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
    00329                         INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
    00330             }
    00331
    00332             // Right button
    00333             if ((wOldFlags & ESB_DISABLE_RIGHT) != (pw->WSBflags & ESB_DISABLE_RIGHT)) {
    00334                 xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
    00335                         INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
    00336             }
    00337         }
    00338     }
    00339
    00340     /*
    00341      *  Then take care of the Vertical Scroll bar, if one exists.
    00342      */
    00343     if((wSBflags == SB_VERT) || (wSBflags == SB_BOTH)) {
    00344         if(wArrows == ESB_ENABLE_BOTH)      // Enable both the arrows
    00345             pw->WSBflags &= ~(SB_DISABLE_MASK << 2);
    00346         else
    00347             pw->WSBflags |= (wArrows << 2);
    00348
    00349         /*
    00350          * Update the display of the Vertical Scroll Bar;
    00351          */
    00352         if(pw->WSBflags != wOldFlags) {
    00353             bRetValue = TRUE;
    00354             if (TestWF(pwnd, WFVPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
    00355                     IsVisible(pwnd)) {
    00356                 xxxDrawScrollBar(pwnd, hdc, TRUE);  // Vertical Scroll Bar
    00357             }
    00358
    00359             if (FWINABLE()) {
    00360                 // Up button
    00361                 if ((wOldFlags & (ESB_DISABLE_UP << 2)) != (pw->WSBflags & (ESB_DISABLE_UP << 2))) {
    00362                     xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
    00363                             INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
    00364                 }
    00365
    00366                 // Down button
    00367                 if ((wOldFlags & (ESB_DISABLE_DOWN << 2)) != (pw->WSBflags & (ESB_DISABLE_DOWN << 2))) {
    00368                     xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
    00369                             INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
    00370                 }
    00371             }
    00372         }
    00373     }
    00374
    00375     _ReleaseDC(hdc);
    00376
    00377     return bRetValue;
    00378 }
    00379
    00380
    00381 /***************************************************************************\
    00382 * EnableScrollBar()
    00383 *
    00384 * This function can be used to selectively Enable/Disable
    00385 *     the arrows of a scroll bar; It could be used with Windows Scroll
    00386 *     bars as well as scroll bar controls
    00387 *
    00388 * History:
    00389 *  4-18-91 MikeHar Ported for the 31 merge
    00390 \***************************************************************************/
    00391
    00392 BOOL xxxEnableScrollBar(
    00393     PWND pwnd,
    00394     UINT wSBflags,  // Whether it is a Window Scroll Bar; if so, HORZ or VERT?
    00395                     // Possible values are SB_HORZ, SB_VERT, SB_CTL or SB_BOTH
    00396     UINT wArrows)   // Which arrows must be enabled/disabled:
    00397                     // ESB_ENABLE_BOTH = > Enable both arrows.
    00398                     // ESB_DISABLE_LTUP = > Disable Left/Up arrow;
    00399                     // ESB_DISABLE_RTDN = > DIsable Right/Down arrow;
    00400                     // ESB_DISABLE_BOTH = > Disable both the arrows;
    00401 {
    00402 #define ES_NOTHING 0
    00403 #define ES_DISABLE 1
    00404 #define ES_ENABLE  2
    00405     UINT wOldFlags;
    00406     UINT wEnableWindow;
    00407
    00408     CheckLock(pwnd);
    00409
    00410     if(wSBflags != SB_CTL) {
    00411         return xxxEnableWndSBArrows(pwnd, wSBflags, wArrows);
    00412     }
    00413
    00414     /*
    00415      *  Let us assume that we don't have to call EnableWindow
    00416      */
    00417     wEnableWindow = ES_NOTHING;
    00418
    00419     wOldFlags = ((PSBWND)pwnd)->wDisableFlags & (UINT)SB_DISABLE_MASK;
    00420
    00421     /*
    00422      * Check if the present state of the arrows is exactly the same
    00423      *  as what the caller wants:
    00424      */
    00425     if (wOldFlags == wArrows)
    00426         return FALSE ;          // If so, nothing needs to be done;
    00427
    00428     /*
    00429      * Check if the caller wants to disable both the arrows
    00430      */
    00431     if (wArrows == ESB_DISABLE_BOTH) {
    00432         wEnableWindow = ES_DISABLE;      // Yes! So, disable the whole SB Ctl.
    00433     } else {
    00434
    00435         /*
    00436          * Check if the caller wants to enable both the arrows
    00437          */
    00438         if(wArrows == ESB_ENABLE_BOTH) {
    00439
    00440             /*
    00441              * We need to enable the SB Ctl only if it was already disabled.
    00442              */
    00443             if(wOldFlags == ESB_DISABLE_BOTH)
    00444                 wEnableWindow = ES_ENABLE;// EnableWindow(.., TRUE);
    00445         } else {
    00446
    00447             /*
    00448              * Now, Caller wants to disable only one arrow;
    00449              * Check if one of the arrows was already disabled and we want
    00450              * to disable the other;If so, the whole SB Ctl will have to be
    00451              * disabled; Check if this is the case:
    00452              */
    00453             if((wOldFlags | wArrows) == ESB_DISABLE_BOTH)
    00454                 wEnableWindow = ES_DISABLE;      // EnableWindow(, FALSE);
    00455          }
    00456     }
    00457     if(wEnableWindow != ES_NOTHING) {
    00458
    00459         /*
    00460          * EnableWindow returns old state of the window; We must return
    00461          * TRUE only if the Old state is different from new state.
    00462          */
    00463         if(xxxEnableWindow(pwnd, (BOOL)(wEnableWindow == ES_ENABLE))) {
    00464             return !(TestWF(pwnd, WFDISABLED));
    00465         } else {
    00466             return TestWF(pwnd, WFDISABLED);
    00467         }
    00468     }
    00469
    00470     return (BOOL)xxxSendMessage(pwnd, SBM_ENABLE_ARROWS, (DWORD)wArrows, 0);
    00471 #undef ES_NOTHING
    00472 #undef ES_DISABLE
    00473 #undef ES_ENABLE
    00474 }
    00475
    00476 /***************************************************************************\
    00477 *
    00478 *  DrawSize() -
    00479 *
    00480 \***************************************************************************/
    00481 void FAR DrawSize(PWND pwnd, HDC hdc, int cxFrame,int cyFrame)
    00482 {
    00483     int     x, y;
    00484     //HBRUSH  hbrSave;
    00485
    00486     if (TestWF(pwnd, WEFLEFTSCROLL)) {
    00487         x = cxFrame;
    00488     } else {
    00489         x = pwnd->rcWindow.right - pwnd->rcWindow.left - cxFrame - SYSMET(CXVSCROLL);
    00490     }
    00491     y = pwnd->rcWindow.bottom - pwnd->rcWindow.top  - cyFrame - SYSMET(CYHSCROLL);
    00492
    00493     // If we have a scrollbar control, or the sizebox is not associated with
    00494     // a sizeable window, draw the flat gray sizebox.  Otherwise, use the
    00495     // sizing grip.
    00496     if (IsScrollBarControl(pwnd))
    00497     {
    00498         if (TestWF(pwnd, SBFSIZEGRIP))
    00499             goto DrawSizeGrip;
    00500         else
    00501             goto DrawBox;
    00502
    00503     }
    00504     else if (!SizeBoxHwnd(pwnd))
    00505     {
    00506 DrawBox:
    00507         {
    00508             //hbrSave = GreSelectBrush(hdc, SYSHBR(3DFACE));
    00509             //GrePatBlt(hdc, x, y, SYSMET(CXVSCROLL), SYSMET(CYHSCROLL), PATCOPY);
    00510             //GreSelectBrush(hdc, hbrSave);
    00511
    00512             POLYPATBLT PolyData;
    00513
    00514             PolyData.x         = x;
    00515             PolyData.y         = y;
    00516             PolyData.cx        = SYSMET(CXVSCROLL);
    00517             PolyData.cy        = SYSMET(CYHSCROLL);
    00518             PolyData.BrClr.hbr = SYSHBR(3DFACE);
    00519
    00520             GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
    00521
    00522         }
    00523     }
    00524     else
    00525     {
    00526 DrawSizeGrip:
    00527         // Blt out the grip bitmap.
    00528         BitBltSysBmp(hdc, x, y, TestWF(pwnd, WEFLEFTSCROLL) ? OBI_NCGRIP_L : OBI_NCGRIP);
    00529     }
    00530 }
    00531
    00532 /***************************************************************************\
    00533 * xxxSelectColorObjects
    00534 *
    00535 *
    00536 *
    00537 * History:
    00538 \***************************************************************************/
    00539
    00540 HBRUSH xxxGetColorObjects(
    00541     PWND pwnd,
    00542     HDC hdc)
    00543 {
    00544     HBRUSH hbrRet;
    00545
    00546     CheckLock(pwnd);
    00547
    00548     // Use the scrollbar color even if the scrollbar is disabeld.
    00549     if (!IsScrollBarControl(pwnd))
    00550         hbrRet = (HBRUSH)xxxDefWindowProc(pwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(pwnd));
    00551     else {
    00552         // B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
    00553         // owner.  If the app doesn't process the message, DefWindowProc32
    00554         // will always return the appropriate system brush. If the app.
    00555         // returns an invalid object, GetControlBrush will call DWP for
    00556         // the default brush. Thus hbrRet doesn't need any validation
    00557         // here.
    00558         hbrRet = xxxGetControlBrush(pwnd, hdc, WM_CTLCOLORSCROLLBAR);
    00559     }
    00560
    00561     return hbrRet;
    00562 }
    00563
    00564 /***************************************************************************\
    00565 *
    00566 *  DrawGroove()
    00567 *
    00568 *  Draws lines & middle of thumb groove
    00569 *  Note that pw points into prc.  Moreover, note that both pw & prc are
    00570 *  NEAR pointers, so *prc better not be on the stack.
    00571 *
    00572 \***************************************************************************/
    00573 void NEAR DrawGroove(HDC hdc, HBRUSH  hbr, LPRECT prc, BOOL fVert)
    00574 {
    00575     if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == gpsi->hbrGray))
    00576         FillRect(hdc, prc, hbr);
    00577     else
    00578     {
    00579         RECT    rc;
    00580
    00581     // Draw sides
    00582         CopyRect(&rc, prc);
    00583         DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT |
    00584             (fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
    00585
    00586     // Fill middle
    00587         FillRect(hdc, &rc, hbr);
    00588     }
    00589 }
    00590
    00591 /***************************************************************************\
    00592 * CalcTrackDragRect
    00593 *
    00594 * Give the rectangle for a scrollbar in pSBTrack->pSBCalc,
    00595 * calculate pSBTrack->rcTrack, the rectangle where tracking
    00596 * may occur without cancelling the thumbdrag operation.
    00597 *
    00598 \***************************************************************************/
    00599
    00600 void CalcTrackDragRect(PSBTRACK pSBTrack) {
    00601
    00602     int     cx;
    00603     int     cy;
    00604     LPINT   pwX, pwY;
    00605
    00606     //
    00607     // Point pwX and pwY at the parts of the rectangle
    00608     // corresponding to pSBCalc->pxLeft, pxTop, etc.
    00609     //
    00610     // pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
    00611     // scrollbar and the top edge of horizontal one.
    00612     // pSBTrack->pSBCalc->pxTop is the top of a vertical
    00613     // scrollbar and the left of horizontal one.
    00614     // etc...
    00615     //
    00616     // Point pwX and pwY to the corresponding parts
    00617     // of pSBTrack->rcTrack.
    00618     //
    00619
    00620     pwX = pwY = (LPINT)&pSBTrack->rcTrack;
    00621
    00622     if (pSBTrack->fTrackVert) {
    00623         cy = SYSMET(CYVTHUMB);
    00624         pwY++;
    00625     } else {
    00626         cy = SYSMET(CXHTHUMB);
    00627         pwX++;
    00628     }
    00629     /*
    00630      * Later5.0 GerardoB: People keep complaining about this tracking region
    00631      *  being too narrow so let's make it wider while PM decides what to do
    00632      *  about it.
    00633      * We also used to have some hard coded min and max values but that should
    00634      *  depend on some metric, if at all needed.
    00635      */
    00636     cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8;
    00637     cy *= 2;
    00638
    00639     *(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx;
    00640     *(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy;
    00641     *(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx;
    00642     *(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy;
    00643 }
    00644
    00645 void RecalcTrackRect(PSBTRACK pSBTrack) {
    00646     LPINT pwX, pwY;
    00647     RECT rcSB;
    00648
    00649
    00650     if (!pSBTrack->fCtlSB)
    00651         CalcSBStuff(pSBTrack->spwndTrack, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
    00652
    00653     pwX = (LPINT)&rcSB;
    00654     pwY = pwX + 1;
    00655     if (!pSBTrack->fTrackVert)
    00656         pwX = pwY--;
    00657
    00658     *(pwX + 0) = pSBTrack->pSBCalc->pxLeft;
    00659     *(pwY + 0) = pSBTrack->pSBCalc->pxTop;
    00660     *(pwX + 2) = pSBTrack->pSBCalc->pxRight;
    00661     *(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
    00662
    00663     switch(pSBTrack->cmdSB) {
    00664     case SB_LINEUP:
    00665         *(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow;
    00666         break;
    00667     case SB_LINEDOWN:
    00668         *(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow;
    00669         break;
    00670     case SB_PAGEUP:
    00671         *(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow;
    00672         *(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop;
    00673         break;
    00674     case SB_THUMBPOSITION:
    00675         CalcTrackDragRect(pSBTrack);
    00676         break;
    00677     case SB_PAGEDOWN:
    00678         *(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom;
    00679         *(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow;
    00680         break;
    00681     }
    00682
    00683     if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
    00684         CopyRect(&pSBTrack->rcTrack, &rcSB);
    00685     }
    00686 }
    00687
    00688 /***************************************************************************\
    00689 * DrawThumb2
    00690 *
    00691 *
    00692 *
    00693 * History:
    00694 * 01-03-94  FritzS   Chicago changes
    00695 \***************************************************************************/
    00696
    00697 void DrawThumb2(
    00698     PWND pwnd,
    00699     PSBCALC pSBCalc,
    00700     HDC hdc,
    00701     HBRUSH hbr,
    00702     BOOL fVert,
    00703     UINT wDisable)  /* Disabled flags for the scroll bar */
    00704 {
    00705     int    *pLength;
    00706     int    *pWidth;
    00707     RECT   rcSB;
    00708     PSBTRACK pSBTrack;
    00709
    00710     //
    00711     // Bail out if the scrollbar has an empty rect
    00712     //
    00713     if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight))
    00714         return;
    00715     pLength = (LPINT)&rcSB;
    00716     if (fVert)
    00717         pWidth = pLength++;
    00718     else
    00719         pWidth  = pLength + 1;
    00720
    00721     pWidth[0] = pSBCalc->pxLeft;
    00722     pWidth[2] = pSBCalc->pxRight;
    00723
    00724     /*
    00725      * If both scroll bar arrows are disabled, then we should not draw
    00726      * the thumb.  So, quit now!
    00727      */
    00728     if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
    00729         ((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb)) {
    00730         pLength[0] = pSBCalc->pxUpArrow;
    00731         pLength[2] = pSBCalc->pxDownArrow;
    00732
    00733         DrawGroove(hdc, hbr, &rcSB, fVert);
    00734         return;
    00735     }
    00736
    00737     if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop) {
    00738         // Fill in space above Thumb
    00739         pLength[0] = pSBCalc->pxUpArrow;
    00740         pLength[2] = pSBCalc->pxThumbTop;
    00741
    00742         DrawGroove(hdc, hbr, &rcSB, fVert);
    00743     }
    00744
    00745     if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow) {
    00746         // Fill in space below Thumb
    00747         pLength[0] = pSBCalc->pxThumbBottom;
    00748         pLength[2] = pSBCalc->pxDownArrow;
    00749
    00750         DrawGroove(hdc, hbr, &rcSB, fVert);
    00751     }
    00752
    00753     //
    00754     // Draw elevator
    00755     //
    00756     pLength[0] = pSBCalc->pxThumbTop;
    00757     pLength[2] = pSBCalc->pxThumbBottom;
    00758
    00759     // Not soft!
    00760     DrawPushButton(hdc, &rcSB, 0, 0);
    00761
    00762     /*
    00763      * If we're tracking a page scroll, then we've obliterated the hilite.
    00764      * We need to correct the hiliting rectangle, and rehilite it.
    00765      */
    00766     pSBTrack = PWNDTOPSBTRACK(pwnd);
    00767
    00768     if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) &&
    00769             (pwnd == pSBTrack->spwndTrack) &&
    00770             (BOOL)pSBTrack->fTrackVert == fVert) {
    00771
    00772         if (pSBTrack->fTrackRecalc) {
    00773             RecalcTrackRect(pSBTrack);
    00774             pSBTrack->fTrackRecalc = FALSE;
    00775         }
    00776
    00777         pLength = (int *)&pSBTrack->rcTrack;
    00778
    00779         if (fVert)
    00780             pLength++;
    00781
    00782         if (pSBTrack->cmdSB == SB_PAGEUP)
    00783             pLength[2] = pSBCalc->pxThumbTop;
    00784         else
    00785             pLength[0] = pSBCalc->pxThumbBottom;
    00786
    00787         if (pLength[0] < pLength[2])
    00788             InvertRect(hdc, &pSBTrack->rcTrack);
    00789     }
    00790 }
    00791
    00792 /***************************************************************************\
    00793 * xxxDrawSB2
    00794 *
    00795 *
    00796 *
    00797 * History:
    00798 \***************************************************************************/
    00799
    00800 void xxxDrawSB2(
    00801     PWND pwnd,
    00802     PSBCALC pSBCalc,
    00803     HDC hdc,
    00804     BOOL fVert,
    00805     UINT wDisable)
    00806 {
    00807
    00808     int     cLength;
    00809     int     cWidth;
    00810     int     *pwX;
    00811     int     *pwY;
    00812     HBRUSH hbr;
    00813     HBRUSH hbrSave;
    00814     int cpxArrow;
    00815     RECT    rc, rcSB;
    00816     COLORREF crText, crBk;
    00817
    00818     CheckLock(pwnd);
    00819
    00820     cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2;
    00821     cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
    00822
    00823     if ((cLength <= 0) || (cWidth <= 0)) {
    00824         return;
    00825     }
    00826     if (fVert)
    00827         cpxArrow = SYSMET(CYVSCROLL);
    00828     else
    00829         cpxArrow = SYSMET(CXHSCROLL);
    00830
    00831     /*
    00832      * Save background and DC color, since they get changed in
    00833      * xxxGetColorObjects. Restore before we return.
    00834      */
    00835     crBk = GreGetBkColor(hdc);
    00836     crText = GreGetTextColor(hdc);
    00837
    00838     hbr = xxxGetColorObjects(pwnd, hdc);
    00839
    00840     if (cLength > cpxArrow)
    00841         cLength = cpxArrow;
    00842     pwX = (int *)&rcSB;
    00843     pwY = pwX + 1;
    00844     if (!fVert)
    00845         pwX = pwY--;
    00846
    00847     pwX[0] = pSBCalc->pxLeft;
    00848     pwY[0] = pSBCalc->pxTop;
    00849     pwX[2] = pSBCalc->pxRight;
    00850     pwY[2] = pSBCalc->pxBottom;
    00851
    00852     hbrSave = GreSelectBrush(hdc, SYSHBR(BTNTEXT));
    00853
    00854     //
    00855     // BOGUS
    00856     // Draw scrollbar arrows as disabled if the scrollbar itself is
    00857     // disabled OR if the window it is a part of is disabled?
    00858     //
    00859     if (fVert) {
    00860         if ((cLength == SYSMET(CYVSCROLL)) && (cWidth == SYSMET(CXVSCROLL))) {
    00861             BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_UPARROW_I : OBI_UPARROW);
    00862             BitBltSysBmp(hdc, rcSB.left, rcSB.bottom - cLength, (wDisable & RTDNFLAG) ? OBI_DNARROW_I : OBI_DNARROW);
    00863         } else {
    00864             CopyRect(&rc, &rcSB);
    00865             rc.bottom = rc.top + cLength;
    00866             DrawFrameControl(hdc, &rc, DFC_SCROLL,
    00867                 DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
    00868
    00869             rc.bottom = rcSB.bottom;
    00870             rc.top = rcSB.bottom - cLength;
    00871             DrawFrameControl(hdc, &rc, DFC_SCROLL,
    00872                 DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
    00873         }
    00874     } else {
    00875         if ((cLength == SYSMET(CXHSCROLL)) && (cWidth == SYSMET(CYHSCROLL))) {
    00876             BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_LFARROW_I : OBI_LFARROW);
    00877             BitBltSysBmp(hdc, rcSB.right - cLength, rcSB.top, (wDisable & RTDNFLAG) ? OBI_RGARROW_I : OBI_RGARROW);
    00878         } else {
    00879             CopyRect(&rc, &rcSB);
    00880             rc.right = rc.left + cLength;
    00881             DrawFrameControl(hdc, &rc, DFC_SCROLL,
    00882                 DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
    00883
    00884             rc.right = rcSB.right;
    00885             rc.left = rcSB.right - cLength;
    00886             DrawFrameControl(hdc, &rc, DFC_SCROLL,
    00887                 DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
    00888         }
    00889     }
    00890
    00891     hbrSave = GreSelectBrush(hdc, hbrSave);
    00892     DrawThumb2(pwnd, pSBCalc, hdc, hbr, fVert, wDisable);
    00893     GreSelectBrush(hdc, hbrSave);
    00894
    00895     GreSetBkColor(hdc, crBk);
    00896     GreSetTextColor(hdc, crText);
    00897 }
    00898
    00899 /***************************************************************************\
    00900 * zzzSetSBCaretPos
    00901 *
    00902 *
    00903 *
    00904 * History:
    00905 \***************************************************************************/
    00906
    00907 void zzzSetSBCaretPos(
    00908     PSBWND psbwnd)
    00909 {
    00910
    00911     if ((PWND)psbwnd == PtiCurrent()->pq->spwndFocus) {
    00912         zzzSetCaretPos((psbwnd->fVert ? psbwnd->SBCalc.pxLeft : psbwnd->SBCalc.pxThumbTop) + SYSMET(CXEDGE),
    00913                 (psbwnd->fVert ? psbwnd->SBCalc.pxThumbTop : psbwnd->SBCalc.pxLeft) + SYSMET(CYEDGE));
    00914     }
    00915 }
    00916
    00917 /***************************************************************************\
    00918 * CalcSBStuff2
    00919 *
    00920 *
    00921 *
    00922 * History:
    00923 \***************************************************************************/
    00924
    00925 void CalcSBStuff2(
    00926     PSBCALC  pSBCalc,
    00927     LPRECT lprc,
    00928     CONST PSBDATA pw,
    00929     BOOL fVert)
    00930 {
    00931     int cpx;
    00932     DWORD dwRange;
    00933     int denom;
    00934
    00935     if (fVert) {
    00936         pSBCalc->pxTop = lprc->top;
    00937         pSBCalc->pxBottom = lprc->bottom;
    00938         pSBCalc->pxLeft = lprc->left;
    00939         pSBCalc->pxRight = lprc->right;
    00940         pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
    00941     } else {
    00942
    00943         /*
    00944          * For horiz scroll bars, "left" & "right" are "top" and "bottom",
    00945          * and vice versa.
    00946          */
    00947         pSBCalc->pxTop = lprc->left;
    00948         pSBCalc->pxBottom = lprc->right;
    00949         pSBCalc->pxLeft = lprc->top;
    00950         pSBCalc->pxRight = lprc->bottom;
    00951         pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
    00952     }
    00953
    00954     pSBCalc->pos = pw->pos;
    00955     pSBCalc->page = pw->page;
    00956     pSBCalc->posMin = pw->posMin;
    00957     pSBCalc->posMax = pw->posMax;
    00958
    00959     dwRange = ((DWORD)(pSBCalc->posMax - pSBCalc->posMin)) + 1;
    00960
    00961     //
    00962     // For the case of short scroll bars that don't have enough
    00963     // room to fit the full-sized up and down arrows, shorten
    00964     // their sizes to make 'em fit
    00965     //
    00966     cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
    00967
    00968     pSBCalc->pxUpArrow   = pSBCalc->pxTop    + cpx;
    00969     pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
    00970
    00971     if ((pw->page != 0) && (dwRange != 0)) {
    00972         // JEFFBOG -- This is the one and only place where we should
    00973         // see 'range'.  Elsewhere it should be 'range - page'.
    00974
    00975         /*
    00976          * The minimun thumb size used to depend on the frame/edge metrics.
    00977          * People that increase the scrollbar width/height expect the minimun
    00978          *  to grow with proportianally. So NT5 bases the minimun on
    00979          *  CXH/YVSCROLL, which is set by default in cpxThumb.
    00980          */
    00981         /*
    00982          * i is used to keep the macro "max" from executing EngMulDiv twice.
    00983          */
    00984         int i = EngMulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
    00985                                              pw->page, dwRange);
    00986         pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
    00987     }
    00988
    00989     pSBCalc->pxMin = pSBCalc->pxTop + cpx;
    00990     pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
    00991
    00992     denom = dwRange - (pw->page ? pw->page : 1);
    00993     if (denom)
    00994         pSBCalc->pxThumbTop = EngMulDiv(pw->pos - pw->posMin,
    00995             pSBCalc->cpx, denom) +
    00996             pSBCalc->pxMin;
    00997     else
    00998         pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
    00999
    01000     pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
    01001
    01002 }
    01003
    01004 /***************************************************************************\
    01005 * SBCtlSetup
    01006 *
    01007 *
    01008 *
    01009 * History:
    01010 \***************************************************************************/
    01011
    01012 void SBCtlSetup(
    01013     PSBWND psbwnd)
    01014 {
    01015     RECT rc;
    01016
    01017     GetRect((PWND)psbwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS);
    01018     CalcSBStuff2(&psbwnd->SBCalc, &rc, (PSBDATA)&psbwnd->SBCalc, psbwnd->fVert);
    01019 }
    01020
    01021 /***************************************************************************\
    01022 * HotTrackSB
    01023 *
    01024 \***************************************************************************/
    01025
    01026 #ifdef COLOR_HOTTRACKING
    01027
    01028 DWORD GetTrackFlags(int ht, BOOL fDraw)
    01029 {
    01030     if (fDraw) {
    01031         switch(ht) {
    01032         case HTSCROLLUP:
    01033         case HTSCROLLUPPAGE:
    01034             return LTUPFLAG;
    01035
    01036         case HTSCROLLDOWN:
    01037         case HTSCROLLDOWNPAGE:
    01038             return RTDNFLAG;
    01039
    01040         case HTSCROLLTHUMB:
    01041             return LTUPFLAG | RTDNFLAG;
    01042
    01043         default:
    01044             return 0;
    01045         }
    01046     } else {
    01047         return 0;
    01048     }
    01049 }
    01050
    01051 BOOL xxxHotTrackSB(PWND pwnd, int htEx, BOOL fDraw)
    01052 {
    01053     SBCALC SBCalc;
    01054     HDC  hdc;
    01055     BOOL fVert = HIWORD(htEx);
    01056     int ht = LOWORD(htEx);
    01057     DWORD dwTrack = GetTrackFlags(ht, fDraw);
    01058
    01059     CheckLock(pwnd);
    01060
    01061     /*
    01062      * xxxDrawSB2 does not callback or leave the critical section when it's
    01063      * not a SB control and the window belongs to a different thread. It
    01064      * calls xxxDefWindowProc which simply returns the brush color.
    01065      */
    01066     CalcSBStuff(pwnd, &SBCalc, fVert);
    01067     hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
    01068     xxxDrawSB2(pwnd, &SBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert), dwTrack);
    01069     _ReleaseDC(hdc);
    01070     return TRUE;
    01071 }
    01072
    01073 void xxxHotTrackSBCtl(PSBWND psbwnd, int ht, BOOL fDraw)
    01074 {
    01075     DWORD dwTrack = GetTrackFlags(ht, fDraw);
    01076     HDC hdc;
    01077
    01078     CheckLock(psbwnd);
    01079
    01080     SBCtlSetup(psbwnd);
    01081     hdc = _GetDCEx((PWND)psbwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
    01082     xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags, dwTrack);
    01083     _ReleaseDC(hdc);
    01084 }
    01085 #endif // COLOR_HOTTRACKING
    01086
    01087 BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres)
    01088 {
    01089     // pass the struct because we modify the struct but don't want that
    01090     // modified version to get back to the calling app
    01091
    01092     BOOL fChanged = FALSE;
    01093
    01094     if (lpsi->fMask & SIF_RETURNOLDPOS)
    01095         // save previous position
    01096         *lplres = pw->pos;
    01097
    01098     if (lpsi->fMask & SIF_RANGE) {
    01099         // if the range MAX is below the range MIN -- then treat is as a
    01100         // zero range starting at the range MIN.
    01101         if (lpsi->nMax < lpsi->nMin)
    01102             lpsi->nMax = lpsi->nMin;
    01103
    01104         if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) {
    01105             pw->posMin = lpsi->nMin;
    01106             pw->posMax = lpsi->nMax;
    01107
    01108             if (!(lpsi->fMask & SIF_PAGE)) {
    01109                 lpsi->fMask |= SIF_PAGE;
    01110                 lpsi->nPage = pw->page;
    01111             }
    01112
    01113             if (!(lpsi->fMask & SIF_POS)) {
    01114                 lpsi->fMask |= SIF_POS;
    01115                 lpsi->nPos = pw->pos;
    01116             }
    01117
    01118             fChanged = TRUE;
    01119         }
    01120     }
    01121
    01122     if (lpsi->fMask & SIF_PAGE) {
    01123         DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
    01124
    01125         // Clip page to 0, posMax - posMin + 1
    01126
    01127         if (lpsi->nPage > dwMaxPage)
    01128             lpsi->nPage = dwMaxPage;
    01129
    01130
    01131         if (pw->page != (int)(lpsi->nPage)) {
    01132             pw->page = lpsi->nPage;
    01133
    01134             if (!(lpsi->fMask & SIF_POS)) {
    01135                 lpsi->fMask |= SIF_POS;
    01136                 lpsi->nPos = pw->pos;
    01137             }
    01138
    01139             fChanged = TRUE;
    01140         }
    01141     }
    01142
    01143     if (lpsi->fMask & SIF_POS) {
    01144         int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0);
    01145         // Clip pos to posMin, posMax - (page - 1).
    01146
    01147         if (lpsi->nPos < pw->posMin)
    01148             lpsi->nPos = pw->posMin;
    01149         else if (lpsi->nPos > iMaxPos)
    01150             lpsi->nPos = iMaxPos;
    01151
    01152
    01153         if (pw->pos != lpsi->nPos) {
    01154             pw->pos = lpsi->nPos;
    01155             fChanged = TRUE;
    01156         }
    01157     }
    01158
    01159     if (!(lpsi->fMask & SIF_RETURNOLDPOS)) {
    01160         // Return the new position
    01161         *lplres = pw->pos;
    01162     }
    01163
    01164     /*
    01165      * This was added by JimA as Cairo merge but will conflict
    01166      * with the documentation for SetScrollPos
    01167      */
    01168 /*
    01169     else if (*lplres == pw->pos)
    01170         *lplres = 0;
    01171 */
    01172     if (lpsi->fMask & SIF_RANGE) {
    01173         if (*lpfScroll = (pw->posMin != pw->posMax))
    01174             goto checkPage;
    01175     } else if (lpsi->fMask & SIF_PAGE)
    01176 checkPage:
    01177         *lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
    01178
    01179     return fChanged;
    01180 }
    01181
    01182
    01183 /***************************************************************************\
    01184 * CalcSBStuff
    01185 *
    01186 *
    01187 *
    01188 * History:
    01189 \***************************************************************************/
    01190
    01191 void CalcSBStuff(
    01192     PWND pwnd,
    01193     PSBCALC pSBCalc,
    01194     BOOL fVert)
    01195 {
    01196     RECT    rcT;
    01197     RECT    rcClient;
    01198 #ifdef USE_MIRRORING
    01199     int     cx, iTemp;
    01200 #endif
    01201
    01202     //
    01203     // Get client rectangle.  We know that scrollbars always align to the right
    01204     // and to the bottom of the client area.
    01205     //
    01206     GetRect(pwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS);
    01207 #ifdef USE_MIRRORING
    01208     if (TestWF(pwnd, WEFLAYOUTRTL)) {
    01209         cx             = pwnd->rcWindow.right - pwnd->rcWindow.left;
    01210         iTemp          = rcClient.left;
    01211         rcClient.left  = cx - rcClient.right;
    01212         rcClient.right = cx - iTemp;
    01213     }
    01214 #endif
    01215
    01216     if (fVert) {
    01217          // Only add on space if vertical scrollbar is really there.
    01218         if (TestWF(pwnd, WEFLEFTSCROLL)) {
    01219             rcT.right = rcT.left = rcClient.left;
    01220             if (TestWF(pwnd, WFVPRESENT))
    01221                 rcT.left -= SYSMET(CXVSCROLL);
    01222         } else {
    01223             rcT.right = rcT.left = rcClient.right;
    01224             if (TestWF(pwnd, WFVPRESENT))
    01225                 rcT.right += SYSMET(CXVSCROLL);
    01226         }
    01227
    01228         rcT.top = rcClient.top;
    01229         rcT.bottom = rcClient.bottom;
    01230     } else {
    01231         // Only add on space if horizontal scrollbar is really there.
    01232         rcT.bottom = rcT.top = rcClient.bottom;
    01233         if (TestWF(pwnd, WFHPRESENT))
    01234             rcT.bottom += SYSMET(CYHSCROLL);
    01235
    01236         rcT.left = rcClient.left;
    01237         rcT.right = rcClient.right;
    01238     }
    01239
    01240     // If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
    01241     // we can do here, so just let it go through.  We won't fault but the scrollbar won't work
    01242     // properly either...
    01243     if (_InitPwSB(pwnd))
    01244         CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &pwnd->pSBInfo->Vert :  &pwnd->pSBInfo->Horz, fVert);
    01245
    01246 }
    01247
    01248 /***************************************************************************\
    01249 *
    01250 *  DrawCtlThumb()
    01251 *
    01252 \***************************************************************************/
    01253 void DrawCtlThumb(PSBWND psb)
    01254 {
    01255     HBRUSH  hbr, hbrSave;
    01256     HDC     hdc = (HDC) _GetWindowDC((PWND) psb);
    01257
    01258     SBCtlSetup(psb);
    01259
    01260     hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects((PWND) psb, hdc));
    01261
    01262     DrawThumb2((PWND) psb, &psb->SBCalc, hdc, hbr, psb->fVert, psb->wDisableFlags);
    01263
    01264     GreSelectBrush(hdc, hbrSave);
    01265     _ReleaseDC(hdc);
    01266 }
    01267
    01268
    01269 /***************************************************************************\
    01270 * xxxDrawThumb
    01271 *
    01272 *
    01273 *
    01274 * History:
    01275 \***************************************************************************/
    01276
    01277 void xxxDrawThumb(
    01278     PWND pwnd,
    01279     PSBCALC pSBCalc,
    01280     BOOL fVert)
    01281 {
    01282     HBRUSH hbr, hbrSave;
    01283     HDC hdc;
    01284     UINT wDisableFlags;
    01285     SBCALC SBCalc;
    01286
    01287     CheckLock(pwnd);
    01288
    01289     if (!pSBCalc) pSBCalc = &SBCalc;
    01290     hdc = (HDC)_GetWindowDC(pwnd);
    01291
    01292     CalcSBStuff(pwnd, &SBCalc, fVert);
    01293     wDisableFlags = GetWndSBDisableFlags(pwnd, fVert);
    01294
    01295     hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
    01296
    01297     DrawThumb2(pwnd, &SBCalc, hdc, hbr, fVert, wDisableFlags);
    01298
    01299     GreSelectBrush(hdc, hbrSave);
    01300
    01301     /*
    01302      * Won't hurt even if DC is already released (which happens automatically
    01303      * if window is destroyed during xxxSelectColorObjects)
    01304      */
    01305     _ReleaseDC(hdc);
    01306 }
    01307
    01308 /***************************************************************************\
    01309 * xxxSetScrollBar
    01310 *
    01311 *
    01312 *
    01313 * History:
    01314 \***************************************************************************/
    01315
    01316 LONG xxxSetScrollBar(
    01317     PWND pwnd,
    01318     int code,
    01319     LPSCROLLINFO lpsi,
    01320     BOOL fRedraw)
    01321 {
    01322     BOOL        fVert;
    01323     PSBDATA pw;
    01324     PSBINFO pSBInfo;
    01325     BOOL fOldScroll;
    01326     BOOL fScroll;
    01327     WORD        wfScroll;
    01328     LONG     lres;
    01329     BOOL        fNewScroll;
    01330
    01331     CheckLock(pwnd);
    01332     UserAssert(IsWinEventNotifyDeferredOK());
    01333
    01334     if (fRedraw)
    01335         // window must be visible to redraw
    01336         fRedraw = IsVisible(pwnd);
    01337
    01338     if (code == SB_CTL)
    01339 #ifdef FE_SB // xxxSetScrollBar()
    01340         // scroll bar control; send the control a message
    01341         if(GETPTI(pwnd)->TIF_flags & TIF_16BIT) {
    01342             //
    01343             // If the target application is 16bit apps, we don't pass win40's message.
    01344             // This fix for Ichitaro v6.3. It eats the message. It never forwards
    01345             // the un-processed messages to original windows procedure via
    01346             // CallWindowProc().
    01347             //
    01348             // Is this from xxxSetScrollPos() ?
    01349             if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) {
    01350                 return (int)xxxSendMessage(pwnd, SBM_SETPOS, lpsi->nPos, fRedraw);
    01351             // Is this from xxxSetScrollRange() ?
    01352             } else if(lpsi->fMask == SIF_RANGE) {
    01353                 xxxSendMessage(pwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax);
    01354                 return TRUE;
    01355             // Others...
    01356             } else {
    01357                 return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
    01358             }
    01359         } else {
    01360             return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
    01361         }
    01362 #else
    01363         // scroll bar control; send the control a message
    01364         return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
    01365 #endif // FE_SB
    01366
    01367     fVert = (code != SB_HORZ);
    01368
    01369     wfScroll = (fVert) ? WFVSCROLL : WFHSCROLL;
    01370
    01371     fScroll = fOldScroll = (TestWF(pwnd, wfScroll)) ? TRUE : FALSE;
    01372
    01373     /*
    01374      * Don't do anything if we're setting position of a nonexistent scroll bar.
    01375      */
    01376     if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (pwnd->pSBInfo == NULL)) {
    01377         RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
    01378         return 0;
    01379     }
    01380
    01381     if (fNewScroll = !(pSBInfo = pwnd->pSBInfo)) {
    01382         if ((pSBInfo = _InitPwSB(pwnd)) == NULL)
    01383             return 0;
    01384     }
    01385
    01386     pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
    01387
    01388     if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll) {
    01389         // no change -- but if REDRAW is specified and there's a scrollbar,
    01390         // redraw the thumb
    01391         if (fOldScroll && fRedraw)
    01392             goto redrawAfterSet;
    01393
    01394         return lres;
    01395     }
    01396
    01397     ClrWF(pwnd, wfScroll);
    01398
    01399     if (fScroll)
    01400         SetWF(pwnd, wfScroll);
    01401     else if (!TestWF(pwnd, (WFHSCROLL | WFVSCROLL))) {
    01402         // if neither scroll bar is set and both ranges are 0, then free up the
    01403         // scroll info
    01404
    01405         pSBInfo = pwnd->pSBInfo;
    01406
    01407         if ((pSBInfo->Horz.posMin == pSBInfo->Horz.posMax) &&
    01408             (pSBInfo->Vert.posMin == pSBInfo->Vert.posMax)) {
    01409             DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo));
    01410             pwnd->pSBInfo = NULL;
    01411         }
    01412     }
    01413
    01414     if (lpsi->fMask & SIF_DISABLENOSCROLL) {
    01415         if (fOldScroll) {
    01416             SetWF(pwnd, wfScroll);
    01417             xxxEnableWndSBArrows(pwnd, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
    01418         }
    01419     } else if (fOldScroll ^ fScroll) {
    01420         PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
    01421         if (pSBTrack && (pwnd == pSBTrack->spwndTrack)) {
    01422             pSBTrack->fTrackRecalc = TRUE;
    01423         }
    01424         xxxRedrawFrame(pwnd);
    01425         // Note: after xxx, pSBTrack may no longer be valid (but we return now)
    01426         return lres;
    01427     }
    01428
    01429     if (fScroll && fRedraw && (fVert ? TestWF(pwnd, WFVPRESENT) : TestWF(pwnd, WFHPRESENT))) {
    01430         PSBTRACK pSBTrack;
    01431 redrawAfterSet:
    01432         if (FWINABLE()) {
    01433             xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, pwnd, (fVert ? OBJID_VSCROLL : OBJID_HSCROLL),
    01434                     INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
    01435         }
    01436         pSBTrack = PWNDTOPSBTRACK(pwnd);
    01437         // Bail out if the caller is trying to change the position of
    01438         // a scrollbar that is in the middle of tracking.  We'll hose
    01439         // TrackThumb() otherwise.
    01440
    01441         if (pSBTrack && (pwnd == pSBTrack->spwndTrack) &&
    01442                 ((BOOL)(pSBTrack->fTrackVert) == fVert) &&
    01443                 (pSBTrack->xxxpfnSB == xxxTrackThumb)) {
    01444             return lres;
    01445         }
    01446
    01447         xxxDrawThumb(pwnd, NULL, fVert);
    01448         // Note: after xxx, pSBTrack may no longer be valid (but we return now)
    01449     }
    01450
    01451     return lres;
    01452 }
    01453
    01454
    01455
    01456 /***************************************************************************\
    01457 * xxxDrawScrollBar
    01458 *
    01459 *
    01460 *
    01461 * History:
    01462 \***************************************************************************/
    01463
    01464 void xxxDrawScrollBar(
    01465     PWND pwnd,
    01466     HDC hdc,
    01467     BOOL fVert)
    01468 {
    01469     SBCALC SBCalc;
    01470     PSBCALC pSBCalc;
    01471     PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
    01472
    01473     CheckLock(pwnd);
    01474     if (pSBTrack && (pwnd == pSBTrack->spwndTrack) && (pSBTrack->fCtlSB == FALSE)
    01475          && (fVert == (BOOL)pSBTrack->fTrackVert)) {
    01476         pSBCalc = pSBTrack->pSBCalc;
    01477     } else {
    01478         pSBCalc = &SBCalc;
    01479     }
    01480     CalcSBStuff(pwnd, pSBCalc, fVert);
    01481
    01482     xxxDrawSB2(pwnd, pSBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert));
    01483 }
    01484
    01485 /***************************************************************************\
    01486 * SBPosFromPx
    01487 *
    01488 * Compute scroll bar position from pixel location
    01489 *
    01490 * History:
    01491 \***************************************************************************/
    01492
    01493 int SBPosFromPx(
    01494     PSBCALC  pSBCalc,
    01495     int px)
    01496 {
    01497     if (px < pSBCalc->pxMin) {
    01498         return pSBCalc->posMin;
    01499     }
    01500     if (px >= pSBCalc->pxMin + pSBCalc->cpx) {
    01501         return (pSBCalc->posMax - (pSBCalc->page ? pSBCalc->page - 1 : 0));
    01502     }
    01503     if (pSBCalc->cpx)
    01504         return (pSBCalc->posMin + EngMulDiv(pSBCalc->posMax - pSBCalc->posMin -
    01505             (pSBCalc->page ? pSBCalc->page - 1 : 0),
    01506             px - pSBCalc->pxMin, pSBCalc->cpx));
    01507     else
    01508         return (pSBCalc->posMin - 1);
    01509 }
    01510
    01511 /***************************************************************************\
    01512 * InvertScrollHilite
    01513 *
    01514 *
    01515 *
    01516 * History:
    01517 \***************************************************************************/
    01518
    01519 void InvertScrollHilite(
    01520     PWND pwnd,
    01521     PSBTRACK pSBTrack)
    01522 {
    01523     HDC hdc;
    01524
    01525     /*
    01526      * Don't invert if the thumb is all the way at the top or bottom
    01527      * or you will end up inverting the line between the arrow and the thumb.
    01528      */
    01529     if (!IsRectEmpty(&pSBTrack->rcTrack)) {
    01530         if (pSBTrack->fTrackRecalc) {
    01531             RecalcTrackRect(pSBTrack);
    01532             pSBTrack->fTrackRecalc = FALSE;
    01533         }
    01534
    01535         hdc = (HDC)_GetWindowDC(pwnd);
    01536         InvertRect(hdc, &pSBTrack->rcTrack);
    01537         _ReleaseDC(hdc);
    01538     }
    01539 }
    01540
    01541 /***************************************************************************\
    01542 * xxxDoScroll
    01543 *
    01544 * Sends scroll notification to the scroll bar owner
    01545 *
    01546 * History:
    01547 \***************************************************************************/
    01548
    01549 void xxxDoScroll(
    01550     PWND pwnd,
    01551     PWND pwndNotify,
    01552     int cmd,
    01553     int pos,
    01554     BOOL fVert
    01555 )
    01556 {
    01557     TL tlpwndNotify;
    01558
    01559     /*
    01560      * Special case!!!! this routine is always passed pwnds that are
    01561      * not thread locked, so they need to be thread locked here.  The
    01562      * callers always know that by the time DoScroll() returns,
    01563      * pwnd and pwndNotify could be invalid.
    01564      */
    01565     ThreadLock(pwndNotify, &tlpwndNotify);
    01566     xxxSendMessage(pwndNotify, (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
    01567             MAKELONG(cmd, pos), (LPARAM)HW(pwnd));
    01568
    01569     ThreadUnlock(&tlpwndNotify);
    01570 }
    01571
    01572 // -------------------------------------------------------------------------
    01573 //
    01574 //  CheckScrollRecalc()
    01575 //
    01576 // -------------------------------------------------------------------------
    01577 //void CheckScrollRecalc(PWND pwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
    01578 //{
    01579 //    if ((pSBState->pwndCalc != pwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
    01580 //    {
    01581 //        // Calculate SB stuff based on whether it's a control or in a window
    01582 //        if (pSBState->fCtlSB)
    01583 //            SBCtlSetup((PSBWND) pwnd);
    01584 //        else
    01585 //            CalcSBStuff(pwnd, pSBCalc, pSBState->fVertSB);
    01586 //    }
    01587 //}
    01588
    01589
    01590 /***************************************************************************\
    01591 * xxxMoveThumb
    01592 *
    01593 * History:
    01594 \***************************************************************************/
    01595
    01596 void xxxMoveThumb(
    01597     PWND pwnd,
    01598     PSBCALC  pSBCalc,
    01599     int px)
    01600 {
    01601     HBRUSH  hbr, hbrSave;
    01602     HDC     hdc;
    01603     PSBTRACK pSBTrack;
    01604
    01605     CheckLock(pwnd);
    01606
    01607     pSBTrack = PWNDTOPSBTRACK(pwnd);
    01608
    01609     if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
    01610         return;
    01611
    01612 pxReCalc:
    01613
    01614     pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
    01615
    01616     /* Tentative position changed -- notify the guy. */
    01617     if (pSBTrack->posNew != pSBTrack->posOld) {
    01618         if (pSBTrack->spwndSBNotify != NULL) {
    01619             xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert
    01620             );
    01621
    01622         }
    01623         // After xxxDoScroll, re-evaluate pSBTrack
    01624         REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(1)");
    01625         if ((pSBTrack == NULL) || (pSBTrack->xxxpfnSB == NULL))
    01626             return;
    01627
    01628         pSBTrack->posOld = pSBTrack->posNew;
    01629
    01630         //
    01631         // Anything can happen after the SendMessage above!
    01632         // Make sure that the SBINFO structure contains data for the
    01633         // window being tracked -- if not, recalculate data in SBINFO
    01634         //
    01635 //        CheckScrollRecalc(pwnd, pSBState, pSBCalc);
    01636         // when we yield, our range can get messed with
    01637         // so make sure we handle this
    01638
    01639         if (px >= pSBCalc->pxMin + pSBCalc->cpx)
    01640         {
    01641             px = pSBCalc->pxMin + pSBCalc->cpx;
    01642             goto pxReCalc;
    01643         }
    01644
    01645     }
    01646
    01647     hdc = _GetWindowDC(pwnd);
    01648
    01649     pSBCalc->pxThumbTop = px;
    01650     pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
    01651
    01652     // at this point, the disable flags are always going to be 0 --
    01653     // we're in the middle of tracking.
    01654     hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
    01655
    01656     // After xxxGetColorObjects, re-evaluate pSBTrack
    01657     REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(2)");
    01658     if (pSBTrack == NULL) {
    01659         RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ;
    01660         _ReleaseDC(hdc);
    01661         return;
    01662     }
    01663     DrawThumb2(pwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0);
    01664     GreSelectBrush(hdc, hbrSave);
    01665     _ReleaseDC(hdc);
    01666
    01667     pSBTrack->pxOld = px;
    01668 }
    01669
    01670 /***************************************************************************\
    01671 * zzzDrawInvertScrollArea
    01672 *
    01673 *
    01674 *
    01675 * History:
    01676 \***************************************************************************/
    01677
    01678 void zzzDrawInvertScrollArea(
    01679     PWND pwnd,
    01680     PSBTRACK pSBTrack,
    01681     BOOL fHit,
    01682     UINT cmd)
    01683 {
    01684     HDC hdc;
    01685     RECT rcTemp;
    01686     int cx, cy;
    01687     UINT bm;
    01688
    01689     if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN)) {
    01690         // not hitting on arrow -- just invert the area and return
    01691         InvertScrollHilite(pwnd, pSBTrack);
    01692
    01693         if (cmd == SB_PAGEUP) {
    01694             if (fHit)
    01695                 SetWF(pwnd, WFPAGEUPBUTTONDOWN);
    01696             else
    01697                 ClrWF(pwnd, WFPAGEUPBUTTONDOWN);
    01698         } else {
    01699             if (fHit)
    01700                 SetWF(pwnd, WFPAGEDNBUTTONDOWN);
    01701             else
    01702                 ClrWF(pwnd, WFPAGEDNBUTTONDOWN);
    01703         }
    01704
    01705         if (FWINABLE()) {
    01706             zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
    01707                     (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
    01708                     ((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE),
    01709                     WEF_USEPWNDTHREAD);
    01710             // Note: after zzz, pSBTrack may no longer be valid (but we return now)
    01711         }
    01712         return;
    01713     }
    01714
    01715     if (pSBTrack->fTrackRecalc) {
    01716         RecalcTrackRect(pSBTrack);
    01717         pSBTrack->fTrackRecalc = FALSE;
    01718     }
    01719
    01720     CopyRect(&rcTemp, &pSBTrack->rcTrack);
    01721
    01722     hdc = _GetWindowDC(pwnd);
    01723
    01724     if (pSBTrack->fTrackVert) {
    01725         cx = SYSMET(CXVSCROLL);
    01726         cy = SYSMET(CYVSCROLL);
    01727     } else {
    01728         cx = SYSMET(CXHSCROLL);
    01729         cy = SYSMET(CYHSCROLL);
    01730     }
    01731
    01732     if ((cx == (rcTemp.right - rcTemp.left)) &&
    01733         (cy == (rcTemp.bottom - rcTemp.top))) {
    01734         if (cmd == SB_LINEUP)
    01735             bm = (pSBTrack->fTrackVert) ? OBI_UPARROW : OBI_LFARROW;
    01736         else // SB_LINEDOWN
    01737             bm = (pSBTrack->fTrackVert) ? OBI_DNARROW : OBI_RGARROW;
    01738
    01739         if (fHit)
    01740             bm += DOBI_PUSHED;
    01741
    01742         BitBltSysBmp(hdc, rcTemp.left, rcTemp.top, bm);
    01743     } else {
    01744         DrawFrameControl(hdc, &rcTemp, DFC_SCROLL,
    01745             ((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) |
    01746             ((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) |
    01747             ((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX));
    01748     }
    01749
    01750     _ReleaseDC(hdc);
    01751
    01752
    01753     if (cmd == SB_LINEUP) {
    01754         if (fHit)
    01755             SetWF(pwnd, WFLINEUPBUTTONDOWN);
    01756         else
    01757             ClrWF(pwnd, WFLINEUPBUTTONDOWN);
    01758     } else {
    01759         if (fHit)
    01760             SetWF(pwnd, WFLINEDNBUTTONDOWN);
    01761         else
    01762             ClrWF(pwnd, WFLINEDNBUTTONDOWN);
    01763     }
    01764
    01765     if (FWINABLE()) {
    01766         zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
    01767                 (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
    01768                 (cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN),
    01769                 WEF_USEPWNDTHREAD);
    01770         // Note: after zzz, pSBTrack may no longer be valid (but we return now)
    01771     }
    01772 }
    01773
    01774 /***************************************************************************\
    01775 * xxxEndScroll
    01776 *
    01777 *
    01778 *
    01779 * History:
    01780 \***************************************************************************/
    01781
    01782 void xxxEndScroll(
    01783     PWND pwnd,
    01784     BOOL fCancel)
    01785 {
    01786     UINT oldcmd;
    01787     PSBTRACK pSBTrack;
    01788     CheckLock(pwnd);
    01789     UserAssert(!IsWinEventNotifyDeferred());
    01790
    01791     pSBTrack = PWNDTOPSBTRACK(pwnd);
    01792     if (pSBTrack && PtiCurrent()->pq->spwndCapture == pwnd && pSBTrack->xxxpfnSB != NULL) {
    01793
    01794         oldcmd = pSBTrack->cmdSB;
    01795         pSBTrack->cmdSB = 0;
    01796         xxxReleaseCapture();
    01797
    01798         // After xxxReleaseCapture, revalidate pSBTrack
    01799         RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01800
    01801         if (pSBTrack->xxxpfnSB == xxxTrackThumb) {
    01802
    01803             if (fCancel) {
    01804                 pSBTrack->posOld = pSBTrack->pSBCalc->pos;
    01805             }
    01806
    01807             /*
    01808              * DoScroll does thread locking on these two pwnds -
    01809              * this is ok since they are not used after this
    01810              * call.
    01811              */
    01812             if (pSBTrack->spwndSBNotify != NULL) {
    01813                 xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
    01814                         SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert
    01815                 );
    01816                 // After xxxDoScroll, revalidate pSBTrack
    01817                 RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01818             }
    01819
    01820             if (pSBTrack->fCtlSB) {
    01821                 DrawCtlThumb((PSBWND) pwnd);
    01822             } else {
    01823                 xxxDrawThumb(pwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
    01824                 // Note: after xxx, pSBTrack may no longer be valid
    01825             }
    01826
    01827         } else if (pSBTrack->xxxpfnSB == xxxTrackBox) {
    01828             DWORD lParam;
    01829             POINT ptMsg;
    01830
    01831             if (pSBTrack->hTimerSB != 0) {
    01832                 _KillSystemTimer(pwnd, IDSYS_SCROLL);
    01833                 pSBTrack->hTimerSB = 0;
    01834             }
    01835             lParam = _GetMessagePos();
    01836 #ifdef USE_MIRRORING
    01837             if (TestWF(pwnd, WEFLAYOUTRTL)) {
    01838                 ptMsg.x = pwnd->rcWindow.right - GET_X_LPARAM(lParam);
    01839             } else
    01840 #endif
    01841             {
    01842                 ptMsg.x = GET_X_LPARAM(lParam) - pwnd->rcWindow.left;
    01843             }
    01844             ptMsg.y = GET_Y_LPARAM(lParam) - pwnd->rcWindow.top;
    01845             if (PtInRect(&pSBTrack->rcTrack, ptMsg)) {
    01846                 zzzDrawInvertScrollArea(pwnd, pSBTrack, FALSE, oldcmd);
    01847                 // Note: after zzz, pSBTrack may no longer be valid
    01848             }
    01849         }
    01850
    01851         /*
    01852          * Always send SB_ENDSCROLL message.
    01853          *
    01854          * DoScroll does thread locking on these two pwnds -
    01855          * this is ok since they are not used after this
    01856          * call.
    01857          */
    01858
    01859         // After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
    01860         RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01861
    01862         if (pSBTrack->spwndSBNotify != NULL) {
    01863             xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
    01864                     SB_ENDSCROLL, 0, pSBTrack->fTrackVert);
    01865             // After xxxDoScroll, revalidate pSBTrack
    01866             RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01867         }
    01868
    01869         ClrWF(pwnd, WFSCROLLBUTTONDOWN);
    01870         ClrWF(pwnd, WFVERTSCROLLTRACK);
    01871
    01872         if (FWINABLE()) {
    01873             xxxWindowEvent(EVENT_SYSTEM_SCROLLINGEND, pwnd,
    01874                     (pSBTrack->fCtlSB ? OBJID_CLIENT :
    01875                             (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
    01876                     INDEXID_CONTAINER, 0);
    01877             // After xxxWindowEvent, revalidate pSBTrack
    01878             RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01879         }
    01880
    01881         /*
    01882          * If this is a Scroll Bar Control, turn the caret back on.
    01883          */
    01884         if (pSBTrack->spwndSB != NULL) {
    01885             zzzShowCaret(pSBTrack->spwndSB);
    01886             // After zzz, revalidate pSBTrack
    01887             RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01888         }
    01889
    01890
    01891         pSBTrack->xxxpfnSB = NULL;
    01892
    01893         /*
    01894          * Unlock structure members so they are no longer holding down windows.
    01895          */
    01896         Unlock(&pSBTrack->spwndSB);
    01897         Unlock(&pSBTrack->spwndSBNotify);
    01898         Unlock(&pSBTrack->spwndTrack);
    01899         UserFreePool(pSBTrack);
    01900         PWNDTOPSBTRACK(pwnd) = NULL;
    01901     }
    01902 }
    01903
    01904
    01905 /***************************************************************************\
    01906 * xxxContScroll
    01907 *
    01908 *
    01909 *
    01910 * History:
    01911 \***************************************************************************/
    01912
    01913 VOID xxxContScroll(
    01914     PWND pwnd,
    01915     UINT message,
    01916     UINT_PTR ID,
    01917     LPARAM lParam)
    01918 {
    01919     LONG pt;
    01920     PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
    01921
    01922     UNREFERENCED_PARAMETER(message);
    01923     UNREFERENCED_PARAMETER(ID);
    01924     UNREFERENCED_PARAMETER(lParam);
    01925
    01926     if (pSBTrack == NULL)
    01927         return;
    01928
    01929     CheckLock(pwnd);
    01930
    01931     pt = _GetMessagePos();
    01932 #ifdef USE_MIRRORING
    01933     if (TestWF(pwnd, WEFLAYOUTRTL)) {
    01934         pt = MAKELONG(pwnd->rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
    01935     } else
    01936 #endif
    01937     {
    01938         pt = MAKELONG( GET_X_LPARAM(pt) - pwnd->rcWindow.left, GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
    01939     }
    01940     xxxTrackBox(pwnd, WM_NULL, 0, pt, NULL);
    01941     // After xxxTrackBox, revalidate pSBTrack
    01942     RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    01943
    01944     if (pSBTrack->fHitOld) {
    01945         pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
    01946                 gpsi->dtScroll / 8, xxxContScroll);
    01947
    01948         /*
    01949          * DoScroll does thread locking on these two pwnds -
    01950          * this is ok since they are not used after this
    01951          * call.
    01952          */
    01953         if (pSBTrack->spwndSBNotify != NULL) {
    01954             xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
    01955                     pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
    01956             // Note: after xxx, pSBTrack may no longer be valid (but we return now)
    01957         }
    01958     }
    01959
    01960     return;
    01961 }
    01962
    01963 /***************************************************************************\
    01964 * xxxTrackBox
    01965 *
    01966 *
    01967 *
    01968 * History:
    01969 \***************************************************************************/
    01970
    01971 void xxxTrackBox(
    01972     PWND pwnd,
    01973     UINT message,
    01974     WPARAM wParam,
    01975     LPARAM lParam,
    01976     PSBCALC pSBCalc)
    01977 {
    01978     BOOL fHit;
    01979     POINT ptHit;
    01980     PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
    01981     int cmsTimer;
    01982
    01983     UNREFERENCED_PARAMETER(wParam);
    01984     UNREFERENCED_PARAMETER(pSBCalc);
    01985
    01986     CheckLock(pwnd);
    01987     UserAssert(IsWinEventNotifyDeferredOK());
    01988
    01989     if (pSBTrack == NULL)
    01990         return;
    01991
    01992     if (message != WM_NULL && HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
    01993         return;
    01994
    01995     if (pSBTrack->fTrackRecalc) {
    01996         RecalcTrackRect(pSBTrack);
    01997         pSBTrack->fTrackRecalc = FALSE;
    01998     }
    01999
    02000     ptHit.x = GET_X_LPARAM(lParam);
    02001     ptHit.y = GET_Y_LPARAM(lParam);
    02002     fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
    02003
    02004     if (fHit != (BOOL)pSBTrack->fHitOld) {
    02005         zzzDrawInvertScrollArea(pwnd, pSBTrack, fHit, pSBTrack->cmdSB);
    02006         // After zzz, pSBTrack may no longer be valid
    02007         RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02008     }
    02009
    02010     cmsTimer = gpsi->dtScroll / 8;
    02011
    02012     switch (message) {
    02013     case WM_LBUTTONUP:
    02014         xxxEndScroll(pwnd, FALSE);
    02015         // Note: after xxx, pSBTrack may no longer be valid
    02016         break;
    02017
    02018     case WM_LBUTTONDOWN:
    02019         pSBTrack->hTimerSB = 0;
    02020         cmsTimer = gpsi->dtScroll;
    02021
    02022         /*
    02023          *** FALL THRU **
    02024          */
    02025
    02026     case WM_MOUSEMOVE:
    02027         if (fHit && fHit != (BOOL)pSBTrack->fHitOld) {
    02028
    02029             /*
    02030              * We moved back into the normal rectangle: reset timer
    02031              */
    02032             pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
    02033                     cmsTimer, xxxContScroll);
    02034
    02035             /*
    02036              * DoScroll does thread locking on these two pwnds -
    02037              * this is ok since they are not used after this
    02038              * call.
    02039              */
    02040             if (pSBTrack->spwndSBNotify != NULL) {
    02041                 xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
    02042                         pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
    02043                 // Note: after xxx, pSBTrack may no longer be valid
    02044             }
    02045         }
    02046     }
    02047     // After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
    02048     RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02049     pSBTrack->fHitOld = fHit;
    02050 }
    02051
    02052
    02053 /***************************************************************************\
    02054 * xxxTrackThumb
    02055 *
    02056 *
    02057 *
    02058 * History:
    02059 \***************************************************************************/
    02060
    02061 void xxxTrackThumb(
    02062     PWND pwnd,
    02063     UINT message,
    02064     WPARAM wParam,
    02065     LPARAM lParam,
    02066     PSBCALC pSBCalc)
    02067 {
    02068     int px;
    02069     PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
    02070     POINT pt;
    02071
    02072     UNREFERENCED_PARAMETER(wParam);
    02073
    02074     CheckLock(pwnd);
    02075
    02076     if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
    02077         return;
    02078
    02079     if (pSBTrack == NULL)
    02080         return;
    02081
    02082     // Make sure that the SBINFO structure contains data for the
    02083     // window being tracked -- if not, recalculate data in SBINFO
    02084 //    CheckScrollRecalc(pwnd, pSBState, pSBCalc);
    02085     if (pSBTrack->fTrackRecalc) {
    02086         RecalcTrackRect(pSBTrack);
    02087         pSBTrack->fTrackRecalc = FALSE;
    02088     }
    02089
    02090
    02091     pt.y = GET_Y_LPARAM(lParam);
    02092     pt.x = GET_X_LPARAM(lParam);
    02093     if (!PtInRect(&pSBTrack->rcTrack, pt))
    02094         px = pSBCalc->pxStart;
    02095     else {
    02096         px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
    02097         if (px < pSBCalc->pxMin)
    02098             px = pSBCalc->pxMin;
    02099         else if (px >= pSBCalc->pxMin + pSBCalc->cpx)
    02100             px = pSBCalc->pxMin + pSBCalc->cpx;
    02101     }
    02102
    02103     xxxMoveThumb(pwnd, pSBCalc, px);
    02104
    02105     /*
    02106      * We won't get the WM_LBUTTONUP message if we got here through
    02107      * the scroll menu, so test the button state directly.
    02108      */
    02109     if (message == WM_LBUTTONUP || _GetKeyState(VK_LBUTTON) >= 0) {
    02110         xxxEndScroll(pwnd, FALSE);
    02111     }
    02112
    02113 }
    02114
    02115 /***************************************************************************\
    02116 * xxxSBTrackLoop
    02117 *
    02118 *
    02119 *
    02120 * History:
    02121 \***************************************************************************/
    02122
    02123 void xxxSBTrackLoop(
    02124     PWND pwnd,
    02125     LPARAM lParam,
    02126     PSBCALC pSBCalc)
    02127 {
    02128     MSG msg;
    02129     UINT cmd;
    02130     PTHREADINFO ptiCurrent;
    02131     VOID (*xxxpfnSB)(PWND, UINT, WPARAM, LPARAM, PSBCALC);
    02132     PSBTRACK pSBTrack;
    02133
    02134     CheckLock(pwnd);
    02135     UserAssert(IsWinEventNotifyDeferredOK());
    02136
    02137     pSBTrack = PWNDTOPSBTRACK(pwnd);
    02138
    02139     if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
    02140         // mode cancelled -- exit track loop
    02141         return;
    02142
    02143     if (pSBTrack->fTrackVert)
    02144         SetWF(pwnd, WFVERTSCROLLTRACK);
    02145
    02146     if (FWINABLE()) {
    02147         xxxWindowEvent(EVENT_SYSTEM_SCROLLINGSTART, pwnd,
    02148                 (pSBTrack->fCtlSB ? OBJID_CLIENT :
    02149                         (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
    02150                 INDEXID_CONTAINER, 0);
    02151         // Note: after xxx, pSBTrack may no longer be valid
    02152     }
    02153
    02154     (*xxxpfnSB)(pwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc);
    02155     // Note: after xxx, pSBTrack may no longer be valid
    02156
    02157     ptiCurrent = PtiCurrent();
    02158
    02159     while (ptiCurrent->pq->spwndCapture == pwnd) {
    02160         if (!xxxGetMessage(&msg, NULL, 0, 0)) {
    02161             // Note: after xxx, pSBTrack may no longer be valid
    02162             break;
    02163         }
    02164
    02165         if (!_CallMsgFilter(&msg, MSGF_SCROLLBAR)) {
    02166             cmd = msg.message;
    02167
    02168             if (msg.hwnd == HWq(pwnd) && ((cmd >= WM_MOUSEFIRST && cmd <=
    02169                     WM_MOUSELAST) || (cmd >= WM_KEYFIRST &&
    02170                     cmd <= WM_KEYLAST))) {
    02171                 cmd = SystoChar(cmd, msg.lParam);
    02172
    02173                 // After xxxWindowEvent, xxxpfnSB, xxxTranslateMessage or
    02174                 // xxxDispatchMessage, re-evaluate pSBTrack.
    02175                 REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
    02176                 if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
    02177                     // mode cancelled -- exit track loop
    02178                     return;
    02179
    02180                 (*xxxpfnSB)(pwnd, cmd, msg.wParam, msg.lParam, pSBCalc);
    02181             } else {
    02182                 xxxTranslateMessage(&msg, 0);
    02183                 xxxDispatchMessage(&msg);
    02184             }
    02185         }
    02186     }
    02187 }
    02188
    02189
    02190 /***************************************************************************\
    02191 * xxxSBTrackInit
    02192 *
    02193 * History:
    02194 \***************************************************************************/
    02195
    02196 void xxxSBTrackInit(
    02197     PWND pwnd,
    02198     LPARAM lParam,
    02199     int curArea,
    02200     UINT uType)
    02201 {
    02202     int px;
    02203     LPINT pwX;
    02204     LPINT pwY;
    02205     UINT wDisable;     // Scroll bar disable flags;
    02206     SBCALC SBCalc;
    02207     PSBCALC pSBCalc;
    02208     RECT rcSB;
    02209     PSBTRACK pSBTrack;
    02210
    02211     CheckLock(pwnd);
    02212
    02213
    02214     if (PWNDTOPSBTRACK(pwnd)) {
    02215         RIPMSG1(RIP_WARNING, "xxxSBTrackInit: PWNDTOPSBTRACK(pwnd) == %#p",
    02216                 PWNDTOPSBTRACK(pwnd));
    02217         return;
    02218     }
    02219
    02220     pSBTrack = (PSBTRACK)UserAllocPoolWithQuota(sizeof(*pSBTrack), TAG_SCROLLTRACK);
    02221     if (pSBTrack == NULL)
    02222         return;
    02223
    02224     pSBTrack->hTimerSB = 0;
    02225     pSBTrack->fHitOld = FALSE;
    02226
    02227     pSBTrack->xxxpfnSB = xxxTrackBox;
    02228
    02229     pSBTrack->spwndTrack = NULL;
    02230     pSBTrack->spwndSB = NULL;
    02231     pSBTrack->spwndSBNotify = NULL;
    02232     Lock(&pSBTrack->spwndTrack, pwnd);
    02233     PWNDTOPSBTRACK(pwnd) = pSBTrack;
    02234
    02235     pSBTrack->fCtlSB = (!curArea);
    02236     if (pSBTrack->fCtlSB) {
    02237
    02238         /*
    02239          * This is a scroll bar control.
    02240          */
    02241         Lock(&pSBTrack->spwndSB, pwnd);
    02242         pSBTrack->fTrackVert = ((PSBWND)pwnd)->fVert;
    02243         Lock(&pSBTrack->spwndSBNotify, pwnd->spwndParent);
    02244         wDisable = ((PSBWND)pwnd)->wDisableFlags;
    02245         pSBCalc = &((PSBWND)pwnd)->SBCalc;
    02246         pSBTrack->nBar = SB_CTL;
    02247     } else {
    02248
    02249         /*
    02250          * This is a scroll bar that is part of the window frame.
    02251          */
    02252
    02253 #ifdef USE_MIRRORING
    02254         //
    02255         // Mirror the window coord of the scroll bar,
    02256         // if it is a mirrored one
    02257         //
    02258         if (TestWF(pwnd,WEFLAYOUTRTL)) {
    02259             lParam = MAKELONG(
    02260                     pwnd->rcWindow.right - GET_X_LPARAM(lParam),
    02261                     GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
    02262         }
    02263         else {
    02264 #endif
    02265         lParam = MAKELONG(
    02266                 GET_X_LPARAM(lParam) - pwnd->rcWindow.left,
    02267                 GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
    02268
    02269 #ifdef USE_MIRRORING
    02270         }
    02271 #endif
    02272         Lock(&pSBTrack->spwndSBNotify, pwnd);
    02273         Lock(&pSBTrack->spwndSB, NULL);
    02274         pSBTrack->fTrackVert = (curArea - HTHSCROLL);
    02275         wDisable = GetWndSBDisableFlags(pwnd, pSBTrack->fTrackVert);
    02276         pSBCalc = &SBCalc;
    02277         pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ;
    02278     }
    02279
    02280     pSBTrack->pSBCalc = pSBCalc;
    02281     /*
    02282      *  Check if the whole scroll bar is disabled
    02283      */
    02284     if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
    02285         Unlock(&pSBTrack->spwndSBNotify);
    02286         Unlock(&pSBTrack->spwndSB);
    02287         Unlock(&pSBTrack->spwndTrack);
    02288         UserFreePool(pSBTrack);
    02289         PWNDTOPSBTRACK(pwnd) = NULL;
    02290         return;  // It is a disabled scroll bar; So, do not respond.
    02291     }
    02292
    02293     if (!pSBTrack->fCtlSB) {
    02294         CalcSBStuff(pwnd, pSBCalc, pSBTrack->fTrackVert);
    02295     }
    02296
    02297     pwX = (LPINT)&rcSB;
    02298     pwY = pwX + 1;
    02299     if (!pSBTrack->fTrackVert)
    02300         pwX = pwY--;
    02301
    02302     px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
    02303
    02304     *(pwX + 0) = pSBCalc->pxLeft;
    02305     *(pwY + 0) = pSBCalc->pxTop;
    02306     *(pwX + 2) = pSBCalc->pxRight;
    02307     *(pwY + 2) = pSBCalc->pxBottom;
    02308     pSBTrack->cmdSB = (UINT)-1;
    02309     if (px < pSBCalc->pxUpArrow) {
    02310
    02311         /*
    02312          *  The click occurred on Left/Up arrow; Check if it is disabled
    02313          */
    02314         if(wDisable & LTUPFLAG) {
    02315             if(pSBTrack->fCtlSB) {   // If this is a scroll bar control,
    02316                 zzzShowCaret(pSBTrack->spwndSB);  // show the caret before returning;
    02317                 // After zzzShowCaret, revalidate pSBTrack
    02318                 RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02319             }
    02320
    02321             Unlock(&pSBTrack->spwndSBNotify);
    02322             Unlock(&pSBTrack->spwndSB);
    02323             Unlock(&pSBTrack->spwndTrack);
    02324             UserFreePool(pSBTrack);
    02325             PWNDTOPSBTRACK(pwnd) = NULL;
    02326             return;         // Yes! disabled. Do not respond.
    02327         }
    02328
    02329         // LINEUP -- make rcSB the Up Arrow's Rectangle
    02330         pSBTrack->cmdSB = SB_LINEUP;
    02331         *(pwY + 2) = pSBCalc->pxUpArrow;
    02332     } else if (px >= pSBCalc->pxDownArrow) {
    02333
    02334         /*
    02335          * The click occurred on Right/Down arrow; Check if it is disabled
    02336          */
    02337         if (wDisable & RTDNFLAG) {
    02338             if (pSBTrack->fCtlSB) {    // If this is a scroll bar control,
    02339                 zzzShowCaret(pSBTrack->spwndSB);  // show the caret before returning;
    02340                 // After zzzShowCaret, revalidate pSBTrack
    02341                 RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02342             }
    02343
    02344             Unlock(&pSBTrack->spwndSBNotify);
    02345             Unlock(&pSBTrack->spwndSB);
    02346             Unlock(&pSBTrack->spwndTrack);
    02347             UserFreePool(pSBTrack);
    02348             PWNDTOPSBTRACK(pwnd) = NULL;
    02349             return;// Yes! disabled. Do not respond.
    02350         }
    02351
    02352         // LINEDOWN -- make rcSB the Down Arrow's Rectangle
    02353         pSBTrack->cmdSB = SB_LINEDOWN;
    02354         *(pwY + 0) = pSBCalc->pxDownArrow;
    02355     } else if (px < pSBCalc->pxThumbTop) {
    02356         // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
    02357         pSBTrack->cmdSB = SB_PAGEUP;
    02358         *(pwY + 0) = pSBCalc->pxUpArrow;
    02359         *(pwY + 2) = pSBCalc->pxThumbTop;
    02360     } else if (px < pSBCalc->pxThumbBottom) {
    02361
    02362 DoThumbPos:
    02363         /*
    02364          * Elevator isn't there if there's no room.
    02365          */
    02366         if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) {
    02367             Unlock(&pSBTrack->spwndSBNotify);
    02368             Unlock(&pSBTrack->spwndSB);
    02369             Unlock(&pSBTrack->spwndTrack);
    02370             UserFreePool(pSBTrack);
    02371             PWNDTOPSBTRACK(pwnd) = NULL;
    02372             return;
    02373         }
    02374         // THUMBPOSITION -- we're tracking with the thumb
    02375         pSBTrack->cmdSB = SB_THUMBPOSITION;
    02376         CalcTrackDragRect(pSBTrack);
    02377
    02378         pSBTrack->xxxpfnSB = xxxTrackThumb;
    02379         pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop;
    02380         pSBTrack->posNew = pSBTrack->posOld = pSBCalc->pos;
    02381         pSBTrack->dpxThumb = pSBCalc->pxStart - px;
    02382
    02383         xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
    02384         // After xxxCapture, revalidate pSBTrack
    02385         RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02386
    02387         /*
    02388          * DoScroll does thread locking on these two pwnds -
    02389          * this is ok since they are not used after this
    02390          * call.
    02391          */
    02392         if (pSBTrack->spwndSBNotify != NULL) {
    02393             xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
    02394                     SB_THUMBTRACK, pSBTrack->posOld, pSBTrack->fTrackVert
    02395             );
    02396             // Note: after xxx, pSBTrack may no longer be valid
    02397         }
    02398     } else if (px < pSBCalc->pxDownArrow) {
    02399         // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
    02400         pSBTrack->cmdSB = SB_PAGEDOWN;
    02401         *(pwY + 0) = pSBCalc->pxThumbBottom;
    02402         *(pwY + 2) = pSBCalc->pxDownArrow;
    02403     }
    02404
    02405     /*
    02406      * If the shift key is down, we'll position the thumb directly so it's
    02407      * centered on the click point.
    02408      */
    02409     if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) ||
    02410             (uType == SCROLL_MENU)) {
    02411         if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
    02412             goto DoThumbPos;
    02413         }
    02414         pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2);
    02415     }
    02416
    02417     xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
    02418     // After xxxCapture, revalidate pSBTrack
    02419     RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
    02420
    02421     if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
    02422         CopyRect(&pSBTrack->rcTrack, &rcSB);
    02423     }
    02424
    02425     xxxSBTrackLoop(pwnd, lParam, pSBCalc);
    02426
    02427     // After xxx, re-evaluate pSBTrack
    02428     REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
    02429     if (pSBTrack) {
    02430         Unlock(&pSBTrack->spwndSBNotify);
    02431         Unlock(&pSBTrack->spwndSB);
    02432         Unlock(&pSBTrack->spwndTrack);
    02433         UserFreePool(pSBTrack);
    02434         PWNDTOPSBTRACK(pwnd) = NULL;
    02435     }
    02436 }
    02437
    02438 /***************************************************************************\
    02439 * GetScrollMenu
    02440 *
    02441 * History:
    02442 \***************************************************************************/
    02443
    02444 PMENU xxxGetScrollMenu(
    02445     PWND pwnd,
    02446     BOOL fVert)
    02447 {
    02448     PMENU pMenu;
    02449     PMENU *ppDesktopMenu;
    02450
    02451     /*
    02452      * Grab the menu from the desktop.  If the desktop menu
    02453      * has not been loaded and this is not a system thread,
    02454      * load it now.  Callbacks cannot be made from a system
    02455      * thread or when a thread is in cleanup.
    02456      */
    02457     if (fVert) {
    02458         ppDesktopMenu = &pwnd->head.rpdesk->spmenuVScroll;
    02459     } else {
    02460         ppDesktopMenu = &pwnd->head.rpdesk->spmenuHScroll;
    02461     }
    02462     pMenu = *ppDesktopMenu;
    02463     if (pMenu == NULL && !(PtiCurrent()->TIF_flags & (TIF_SYSTEMTHREAD | TIF_INCLEANUP))) {
    02464         UNICODE_STRING strMenuName;
    02465
    02466         RtlInitUnicodeStringOrId(&strMenuName,
    02467             fVert ? MAKEINTRESOURCE(ID_VSCROLLMENU) : MAKEINTRESOURCE(ID_HSCROLLMENU));
    02468         pMenu = xxxClientLoadMenu(NULL, &strMenuName);
    02469         LockDesktopMenu(ppDesktopMenu, pMenu);
    02470     }
    02471
    02472     /*
    02473      * Return the handle to the scroll menu.
    02474      */
    02475     if (pMenu != NULL) {
    02476         return _GetSubMenu(pMenu, 0);
    02477     }
    02478
    02479     return NULL;
    02480 }
    02481
    02482 /***************************************************************************\
    02483 * xxxDoScrollMenu
    02484 *
    02485 * History:
    02486 \***************************************************************************/
    02487
    02488 VOID
    02489 xxxDoScrollMenu(
    02490     PWND pwndNotify,
    02491     PWND pwndSB,
    02492     BOOL fVert,
    02493     LPARAM lParam)
    02494 {
    02495     PMENU pMenu;
    02496     SBCALC SBCalc, *pSBCalc;
    02497     UINT cmd;
    02498     POINT pt;
    02499     TL tlpmenu;
    02500     UINT wDisable;
    02501
    02502     /*
    02503      * Check the compatibility flag.  Word 6.0 AV's when selecting an item
    02504      * in this menu.
    02505      * NOTE: If this hack is to be extended for other apps we should use
    02506      * another bit for GACF_NOSCROLLBARCTXMENU as the current one is re-used
    02507      *  MCostea #119380
    02508      */
    02509     if (GetAppCompatFlags(NULL) & GACF_NOSCROLLBARCTXMENU) {
    02510         return;
    02511     }
    02512
    02513     /*
    02514      * Initialize some stuff.
    02515      */
    02516     POINTSTOPOINT(pt, lParam);
    02517     if (pwndSB) {
    02518         SBCtlSetup((PSBWND)pwndSB);
    02519         pSBCalc = &(((PSBWND)pwndSB)->SBCalc);
    02520         wDisable = ((PSBWND)pwndSB)->wDisableFlags;
    02521         pt.x -= pwndSB->rcWindow.left;
    02522         pt.y -= pwndSB->rcWindow.top;
    02523     } else {
    02524         pSBCalc = &SBCalc;
    02525         CalcSBStuff(pwndNotify, pSBCalc, fVert);
    02526         wDisable = GetWndSBDisableFlags(pwndNotify, fVert);
    02527         pt.x -= pwndNotify->rcWindow.left;
    02528         pt.y -= pwndNotify->rcWindow.top;
    02529     }
    02530
    02531     /*
    02532      * Make sure the scrollbar isn't disabled.
    02533      */
    02534     if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
    02535         return;
    02536     }
    02537
    02538     /*
    02539      * Put up a menu and scroll accordingly.
    02540      */
    02541     if ((pMenu = xxxGetScrollMenu(pwndNotify, fVert)) != NULL) {
    02542         ThreadLockAlways(pMenu, &tlpmenu);
    02543         cmd = xxxTrackPopupMenuEx(pMenu,
    02544                                   TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
    02545                                   GET_X_LPARAM(lParam),
    02546                                   GET_Y_LPARAM(lParam),
    02547                                   pwndNotify,
    02548                                   NULL);
    02549         ThreadUnlock(&tlpmenu);
    02550         if (cmd) {
    02551             if ((cmd & 0x00FF) == SB_THUMBPOSITION) {
    02552                 if (pwndSB) {
    02553                     xxxSBTrackInit(pwndSB, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU);
    02554                 } else {
    02555                     xxxSBTrackInit(pwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU);
    02556                 }
    02557             } else {
    02558                 xxxDoScroll(pwndSB,
    02559                             pwndNotify,
    02560                             cmd & 0x00FF,
    02561                             0,
    02562                             fVert
    02563                 );
    02564                 xxxDoScroll(pwndSB,
    02565                             pwndNotify,
    02566                             SB_ENDSCROLL,
    02567                             0,
    02568                             fVert
    02569                 );
    02570             }
    02571         }
    02572     }
    02573 }
    02574
    02575 /***************************************************************************\
    02576 * xxxSBWndProc
    02577 *
    02578 * History:
    02579 * 08-15-95 jparsons Added guard against NULL lParam [51986]
    02580 \***************************************************************************/
    02581
    02582 LRESULT xxxSBWndProc(
    02583     PSBWND psbwnd,
    02584     UINT message,
    02585     WPARAM wParam,
    02586     LPARAM lParam)
    02587 {
    02588     LONG l;
    02589     LONG lres;
    02590     int cx;
    02591     int cy;
    02592     UINT cmd;
    02593     UINT uSide;
    02594     HDC hdc;
    02595     RECT rc;
    02596     POINT pt;
    02597     BOOL fSizeReal;
    02598     HBRUSH hbrSave;
    02599     BOOL fSize;
    02600     PAINTSTRUCT ps;
    02601     UINT style;
    02602     TL tlpwndParent;
    02603     SCROLLINFO      si;
    02604     LPSCROLLINFO    lpsi = &si;
    02605     BOOL            fRedraw = FALSE;
    02606     BOOL            fScroll;
    02607
    02608     CheckLock(psbwnd);
    02609     UserAssert(IsWinEventNotifyDeferredOK());
    02610
    02611     VALIDATECLASSANDSIZE(((PWND)psbwnd), message, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
    02612
    02613     style = LOBYTE(psbwnd->wnd.style);
    02614     fSize = ((style & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
    02615
    02616     switch (message) {
    02617     case WM_CREATE:
    02618         /*
    02619          * Guard against lParam being NULL since the thunk allows it [51986]
    02620          */
    02621         if (lParam) {
    02622             rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) +
    02623                     ((LPCREATESTRUCT)lParam)->cx;
    02624             rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) +
    02625                     ((LPCREATESTRUCT)lParam)->cy;
    02626             // This is because we can't just rev CardFile -- we should fix the
    02627             // problem here in case anyone else happened to have some EXTRA
    02628             // scroll styles on their scroll bar controls (jeffbog 03/21/94)
    02629             if (!TestWF((PWND)psbwnd, WFWIN40COMPAT))
    02630                 psbwnd->wnd.style &= ~(WS_HSCROLL | WS_VSCROLL);
    02631
    02632             if (!fSize) {
    02633                 l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams);
    02634                 psbwnd->SBCalc.pos = psbwnd->SBCalc.posMin = LOWORD(l);
    02635                 psbwnd->SBCalc.posMax = HIWORD(l);
    02636                 psbwnd->fVert = ((LOBYTE(psbwnd->wnd.style) & SBS_VERT) != 0);
    02637                 psbwnd->SBCalc.page = 0;
    02638             }
    02639
    02640             if (psbwnd->wnd.style & WS_DISABLED)
    02641                 psbwnd->wDisableFlags = SB_DISABLE_MASK;
    02642
    02643             if (style & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) {
    02644                 if (fSize) {
    02645                     if (style & SBS_SIZEBOXBOTTOMRIGHTALIGN) {
    02646                         rc.left = rc.right - SYSMET(CXVSCROLL);
    02647                         rc.top = rc.bottom - SYSMET(CYHSCROLL);
    02648                     }
    02649
    02650                     rc.right = rc.left + SYSMET(CXVSCROLL);
    02651                     rc.bottom = rc.top + SYSMET(CYHSCROLL);
    02652                 } else {
    02653                     if (style & SBS_VERT) {
    02654                         if (style & SBS_LEFTALIGN)
    02655                             rc.right = rc.left + SYSMET(CXVSCROLL);
    02656                         else
    02657                             rc.left = rc.right - SYSMET(CXVSCROLL);
    02658                     } else {
    02659                         if (style & SBS_TOPALIGN)
    02660                             rc.bottom = rc.top + SYSMET(CYHSCROLL);
    02661                         else
    02662                             rc.top = rc.bottom - SYSMET(CYHSCROLL);
    02663                     }
    02664                 }
    02665
    02666                 xxxMoveWindow((PWND)psbwnd, rc.left, rc.top, rc.right - rc.left,
    02667                          rc.bottom - rc.top, FALSE);
    02668             }
    02669         } /* if */
    02670
    02671         else {
    02672             RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING,
    02673                     "xxxSBWndProc - NULL lParam for WM_CREATE\n") ;
    02674         } /* else */
    02675
    02676         break;
    02677
    02678     case WM_SIZE:
    02679         if (PtiCurrent()->pq->spwndFocus != (PWND)psbwnd)
    02680             break;
    02681
    02682         // scroll bar has the focus -- recalc it's thumb caret size
    02683         // no need to DeferWinEventNotify() - see xxxCreateCaret below.
    02684         zzzDestroyCaret();
    02685
    02686             //   |             |
    02687             //   |  FALL THRU  |
    02688             //   V             V
    02689
    02690     case WM_SETFOCUS:
    02691         SBCtlSetup(psbwnd);
    02692
    02693         cx = (psbwnd->fVert ? psbwnd->wnd.rcWindow.right - psbwnd->wnd.rcWindow.left
    02694                             : psbwnd->SBCalc.cpxThumb) - 2 * SYSMET(CXEDGE);
    02695         cy = (psbwnd->fVert ? psbwnd->SBCalc.cpxThumb
    02696                             : psbwnd->wnd.rcWindow.bottom - psbwnd->wnd.rcWindow.top) - 2 * SYSMET(CYEDGE);
    02697
    02698         xxxCreateCaret((PWND)psbwnd, (HBITMAP)1, cx, cy);
    02699         zzzSetSBCaretPos(psbwnd);
    02700         zzzShowCaret((PWND)psbwnd);
    02701         break;
    02702
    02703     case WM_KILLFOCUS:
    02704         zzzDestroyCaret();
    02705         break;
    02706
    02707     case WM_ERASEBKGND:
    02708
    02709         /*
    02710          * Do nothing, but don't let DefWndProc() do it either.
    02711          * It will be erased when its painted.
    02712          */
    02713         return (LONG)TRUE;
    02714
    02715     case WM_PRINTCLIENT:
    02716     case WM_PAINT:
    02717         if ((hdc = (HDC)wParam) == NULL) {
    02718             hdc = xxxBeginPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
    02719         }
    02720         if (!fSize) {
    02721             SBCtlSetup(psbwnd);
    02722             xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags);
    02723         } else {
    02724             fSizeReal = TestWF((PWND)psbwnd, WFSIZEBOX);
    02725             if (!fSizeReal)
    02726                 SetWF((PWND)psbwnd, WFSIZEBOX);
    02727
    02728             DrawSize((PWND)psbwnd, hdc, 0, 0);
    02729
    02730             if (!fSizeReal)
    02731                 ClrWF((PWND)psbwnd, WFSIZEBOX);
    02732         }
    02733
    02734         if (wParam == 0L)
    02735             xxxEndPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
    02736         break;
    02737
    02738     case WM_GETDLGCODE:
    02739         return DLGC_WANTARROWS;
    02740
    02741     case WM_CONTEXTMENU:
    02742             ThreadLock(psbwnd->wnd.spwndParent, &tlpwndParent);
    02743             xxxDoScrollMenu(psbwnd->wnd.spwndParent, (PWND)psbwnd, psbwnd->fVert, lParam);
    02744             ThreadUnlock(&tlpwndParent);
    02745         break;
    02746
    02747     case WM_NCHITTEST:
    02748         if (style & SBS_SIZEGRIP) {
    02749 #ifdef USE_MIRRORING
    02750             /*
    02751              * If the scroll bar is RTL mirrored, then
    02752              * mirror the hittest of the grip location.
    02753              */
    02754             if (TestWF((PWND)psbwnd, WEFLAYOUTRTL))
    02755                 return HTBOTTOMLEFT;
    02756             else
    02757 #endif
    02758                 return HTBOTTOMRIGHT;
    02759         } else {
    02760             goto DoDefault;
    02761         }
    02762         break;
    02763
    02764 #ifdef COLOR_HOTTRACKING
    02765     case WM_MOUSELEAVE:
    02766         xxxHotTrackSBCtl(psbwnd, 0, FALSE);
    02767         psbwnd->ht = 0;
    02768         break;
    02769
    02770     case WM_MOUSEMOVE:
    02771         {
    02772             int ht;
    02773
    02774             if (psbwnd->ht == 0) {
    02775                 TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, HWq(psbwnd), 0};
    02776                 TrackMouseEvent(&tme);
    02777             }
    02778
    02779             pt.x = GET_X_LPARAM(lParam);
    02780             pt.y = GET_Y_LPARAM(lParam);
    02781             ht = HitTestScrollBar((PWND)psbwnd, psbwnd->fVert, pt);
    02782             if (psbwnd->ht != ht) {
    02783                 xxxHotTrackSBCtl(psbwnd, ht, TRUE);
    02784                 psbwnd->ht = ht;
    02785             }
    02786         }
    02787         break;
    02788 #endif // COLOR_HOTTRACKING
    02789
    02790     case WM_LBUTTONDBLCLK:
    02791         cmd = SC_ZOOM;
    02792         if (fSize)
    02793             goto postmsg;
    02794
    02795         /*
    02796          *** FALL THRU **
    02797          */
    02798
    02799     case WM_LBUTTONDOWN:
    02800             //
    02801             // Note that SBS_SIZEGRIP guys normally won't ever see button
    02802             // downs.  This is because they return HTBOTTOMRIGHT to
    02803             // WindowHitTest handling.  This will walk up the parent chain
    02804             // to the first sizeable ancestor, bailing out at caption windows
    02805             // of course.  That dude, if he exists, will handle the sizing
    02806             // instead.
    02807             //
    02808         if (!fSize) {
    02809             if (TestWF((PWND)psbwnd, WFTABSTOP)) {
    02810                 xxxSetFocus((PWND)psbwnd);
    02811             }
    02812
    02813             zzzHideCaret((PWND)psbwnd);
    02814             SBCtlSetup(psbwnd);
    02815
    02816             /*
    02817              * SBCtlSetup enters SEM_SB, and xxxSBTrackInit leaves it.
    02818              */
    02819             xxxSBTrackInit((PWND)psbwnd, lParam, 0, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
    02820             break;
    02821         } else {
    02822             cmd = SC_SIZE;
    02823 postmsg:
    02824             pt.x = GET_X_LPARAM(lParam);
    02825             pt.y = GET_Y_LPARAM(lParam);
    02826             _ClientToScreen((PWND)psbwnd, &pt);
    02827             lParam = MAKELONG(pt.x, pt.y);
    02828
    02829             /*
    02830              * convert HT value into a move value.  This is bad,
    02831              * but this is purely temporary.
    02832              */
    02833 #ifdef USE_MIRRORING
    02834             if (TestWF(((PWND)psbwnd)->spwndParent,WEFLAYOUTRTL)) {
    02835                 uSide = HTBOTTOMLEFT;
    02836             } else
    02837 #endif
    02838             {
    02839                 uSide = HTBOTTOMRIGHT;
    02840             }
    02841             ThreadLock(((PWND)psbwnd)->spwndParent, &tlpwndParent);
    02842             xxxSendMessage(((PWND)psbwnd)->spwndParent, WM_SYSCOMMAND,
    02843                     (cmd | (uSide - HTSIZEFIRST + 1)), lParam);
    02844             ThreadUnlock(&tlpwndParent);
    02845         }
    02846         break;
    02847
    02848     case WM_KEYUP:
    02849         switch (wParam) {
    02850         case VK_HOME:
    02851         case VK_END:
    02852         case VK_PRIOR:
    02853         case VK_NEXT:
    02854         case VK_LEFT:
    02855         case VK_UP:
    02856         case VK_RIGHT:
    02857         case VK_DOWN:
    02858
    02859             /*
    02860              * Send end scroll message when user up clicks on keyboard
    02861              * scrolling.
    02862              *
    02863              * DoScroll does thread locking on these two pwnds -
    02864              * this is ok since they are not used after this
    02865              * call.
    02866              */
    02867             xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent,
    02868                     SB_ENDSCROLL, 0, psbwnd->fVert
    02869             );
    02870             break;
    02871
    02872         default:
    02873             break;
    02874         }
    02875         break;
    02876
    02877     case WM_KEYDOWN:
    02878         switch (wParam) {
    02879         case VK_HOME:
    02880             wParam = SB_TOP;
    02881             goto KeyScroll;
    02882
    02883         case VK_END:
    02884             wParam = SB_BOTTOM;
    02885             goto KeyScroll;
    02886
    02887         case VK_PRIOR:
    02888             wParam = SB_PAGEUP;
    02889             goto KeyScroll;
    02890
    02891         case VK_NEXT:
    02892             wParam = SB_PAGEDOWN;
    02893             goto KeyScroll;
    02894
    02895         case VK_LEFT:
    02896         case VK_UP:
    02897             wParam = SB_LINEUP;
    02898             goto KeyScroll;
    02899
    02900         case VK_RIGHT:
    02901         case VK_DOWN:
    02902             wParam = SB_LINEDOWN;
    02903 KeyScroll:
    02904
    02905             /*
    02906              * DoScroll does thread locking on these two pwnds -
    02907              * this is ok since they are not used after this
    02908              * call.
    02909              */
    02910             xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent, (int)wParam,
    02911                     0, psbwnd->fVert
    02912             );
    02913             break;
    02914
    02915         default:
    02916             break;
    02917         }
    02918         break;
    02919
    02920     case WM_ENABLE:
    02921         return xxxSendMessage((PWND)psbwnd, SBM_ENABLE_ARROWS,
    02922                (wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
    02923
    02924     case SBM_ENABLE_ARROWS:
    02925
    02926         /*
    02927          * This is used to enable/disable the arrows in a SB ctrl
    02928          */
    02929         return (LONG)xxxEnableSBCtlArrows((PWND)psbwnd, (UINT)wParam);
    02930
    02931     case SBM_GETPOS:
    02932         return (LONG)psbwnd->SBCalc.pos;
    02933
    02934     case SBM_GETRANGE:
    02935         *((LPINT)wParam) = psbwnd->SBCalc.posMin;
    02936         *((LPINT)lParam) = psbwnd->SBCalc.posMax;
    02937         return MAKELRESULT(LOWORD(psbwnd->SBCalc.posMin), LOWORD(psbwnd->SBCalc.posMax));
    02938
    02939     case SBM_GETSCROLLINFO:
    02940         return (LONG)_SBGetParms((PWND)psbwnd, SB_CTL, (PSBDATA)&psbwnd->SBCalc, (LPSCROLLINFO) lParam);
    02941
    02942     case SBM_SETRANGEREDRAW:
    02943         fRedraw = TRUE;
    02944
    02945     case SBM_SETRANGE:
    02946         // Save the old values of Min and Max for return value
    02947         si.cbSize = sizeof(si);
    02948 //        si.nMin = LOWORD(lParam);
    02949 //        si.nMax = HIWORD(lParam);
    02950         si.nMin = (int)wParam;
    02951         si.nMax = (int)lParam;
    02952         si.fMask = SIF_RANGE | SIF_RETURNOLDPOS;
    02953         goto SetInfo;
    02954
    02955     case SBM_SETPOS:
    02956         fRedraw = (BOOL) lParam;
    02957         si.cbSize = sizeof(si);
    02958         si.fMask = SIF_POS | SIF_RETURNOLDPOS;
    02959         si.nPos  = (int)wParam;
    02960         goto SetInfo;
    02961
    02962     case SBM_SETSCROLLINFO:
    02963         lpsi = (LPSCROLLINFO) lParam;
    02964         fRedraw = (BOOL) wParam;
    02965 SetInfo:
    02966         fScroll = TRUE;
    02967
    02968         if (SBSetParms((PSBDATA)&psbwnd->SBCalc, lpsi, &fScroll, &lres) && FWINABLE()) {
    02969             xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, (PWND)psbwnd, OBJID_CLIENT,
    02970                     INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
    02971         }
    02972
    02973         if (!fRedraw)
    02974             return lres;
    02975
    02976
    02977         /*
    02978          * We must set the new position of the caret irrespective of
    02979          * whether the window is visible or not;
    02980          * Still, this will work only if the app has done a xxxSetScrollPos
    02981          * with fRedraw = TRUE;
    02982          * Fix for Bug #5188 --SANKAR-- 10-15-89
    02983          * No need to DeferWinEventNotify since psbwnd is locked.
    02984          */
    02985         zzzHideCaret((PWND)psbwnd);
    02986         SBCtlSetup(psbwnd);
    02987         zzzSetSBCaretPos(psbwnd);
    02988
    02989             /*
    02990              ** The following zzzShowCaret() must be done after the DrawThumb2(),
    02991              ** otherwise this caret will be erased by DrawThumb2() resulting
    02992              ** in this bug:
    02993              ** Fix for Bug #9263 --SANKAR-- 02-09-90
    02994              *
    02995              */
    02996
    02997             /*
    02998              *********** zzzShowCaret((PWND)psbwnd); ******
    02999              */
    03000
    03001         if (_FChildVisible((PWND)psbwnd) && fRedraw) {
    03002             UINT    wDisable;
    03003             HBRUSH  hbrUse;
    03004
    03005             if (!fScroll)
    03006                 fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
    03007
    03008             wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
    03009             xxxEnableScrollBar((PWND) psbwnd, SB_CTL, wDisable);
    03010
    03011             hdc = _GetWindowDC((PWND)psbwnd);
    03012             hbrSave = GreSelectBrush(hdc, hbrUse = xxxGetColorObjects((PWND)psbwnd, hdc));
    03013
    03014                 /*
    03015                  * Before we used to only hideshowthumb() if the mesage was
    03016                  * not SBM_SETPOS.  I am not sure why but this case was ever
    03017                  * needed for win 3.x but on NT it resulted in trashing the border
    03018                  * of the scrollbar when the app called SetScrollPos() during
    03019                  * scrollbar tracking.  - mikehar 8/26
    03020                  */
    03021             DrawThumb2((PWND)psbwnd, &psbwnd->SBCalc, hdc, hbrUse, psbwnd->fVert,
    03022                          psbwnd->wDisableFlags);
    03023             GreSelectBrush(hdc, hbrSave);
    03024             _ReleaseDC(hdc);
    03025         }
    03026
    03027             /*
    03028              * This zzzShowCaret() has been moved to this place from above
    03029              * Fix for Bug #9263 --SANKAR-- 02-09-90
    03030              */
    03031         zzzShowCaret((PWND)psbwnd);
    03032         return lres;
    03033
    03034     default:
    03035 DoDefault:
    03036         return xxxDefWindowProc((PWND)psbwnd, message, wParam, lParam);
    03037     }
    03038
    03039     return 0L;
    03040 }