Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3011 lines
90 KiB

/**************************** Module Header ********************************\
* Module Name: sbctl.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Scroll bar internal routines
*
* History:
* 11/21/90 JimA Created.
* 02-04-91 IanJa Revalidaion added
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
void CalcSBStuff(
PWND pwnd,
PSBCALC pSBCalc,
BOOL fVert);
#define IsScrollBarControl(h) (GETFNID(h) == FNID_SCROLLBAR)
/*
* Now it is possible to selectively Enable/Disable just one arrow of a Window
* scroll bar; Various bits in the 7th word in the rgwScroll array indicates which
* one of these arrows are disabled; The following masks indicate which bit of the
* word indicates which arrow;
*/
#define WSB_HORZ_LF 0x0001 // Represents the Left arrow of the horizontal scroll bar.
#define WSB_HORZ_RT 0x0002 // Represents the Right arrow of the horizontal scroll bar.
#define WSB_VERT_UP 0x0004 // Represents the Up arrow of the vert scroll bar.
#define WSB_VERT_DN 0x0008 // Represents the Down arrow of the vert scroll bar.
#define WSB_VERT (WSB_VERT_UP | WSB_VERT_DN)
#define WSB_HORZ (WSB_HORZ_LF | WSB_HORZ_RT)
void DrawCtlThumb(PSBWND);
/*
* RETURN_IF_PSBTRACK_INVALID:
* This macro tests whether the pSBTrack we have is invalid, which can happen
* if it gets freed during a callback.
* This protects agains the original pSBTrack being freed and no new one
* being allocated or a new one being allocated at a different address.
* This does not protect against the original pSBTrack being freed and a new
* one being allocated at the same address.
* If pSBTrack has changed, we assert that there is not already a new one
* because we are really not expecting this.
*/
#define RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd) \
if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \
UserAssert(PWNDTOPSBTRACK(pwnd) == NULL); \
return; \
}
/*
* REEVALUATE_PSBTRACK
* This macro just refreshes the local variable pSBTrack, in case it has
* been changed during a callback. After performing this operation, pSBTrack
* should be tested to make sure it is not now NULL.
*/
#if DBG
#define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \
RIPMSG3(RIP_VERBOSE, \
"%s: pSBTrack changed from %#p to %#p", \
(str), (pSBTrack), PWNDTOPSBTRACK(pwnd)); \
} \
(pSBTrack) = PWNDTOPSBTRACK(pwnd)
#else
#define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
(pSBTrack) = PWNDTOPSBTRACK(pwnd)
#endif
/***************************************************************************\
* HitTestScrollBar
*
* 11/15/96 vadimg ported from Memphis sources
\***************************************************************************/
int HitTestScrollBar(PWND pwnd, BOOL fVert, POINT pt)
{
UINT wDisable;
int px;
BOOL fCtl = IsScrollBarControl(pwnd);
SBCALC SBCalc, *pSBCalc;
if (fCtl) {
wDisable = ((PSBWND)pwnd)->wDisableFlags;
} else {
//
// Reflect the click coordinates on the horizontal
// scroll bar if the window is mirrored
//
if (TestWF(pwnd,WEFLAYOUTRTL) && !fVert) {
pt.x = pwnd->rcWindow.right - pt.x;
} else {
pt.x -= pwnd->rcWindow.left;
}
pt.y -= pwnd->rcWindow.top;
wDisable = GetWndSBDisableFlags(pwnd, fVert);
}
if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
return HTERROR;
}
if (fCtl) {
pSBCalc = &(((PSBWND)pwnd)->SBCalc);
} else {
pSBCalc = &SBCalc;
CalcSBStuff(pwnd, pSBCalc, fVert);
}
px = fVert ? pt.y : pt.x;
if (px < pSBCalc->pxUpArrow) {
if (wDisable & LTUPFLAG) {
return HTERROR;
}
return HTSCROLLUP;
} else if (px >= pSBCalc->pxDownArrow) {
if (wDisable & RTDNFLAG) {
return HTERROR;
}
return HTSCROLLDOWN;
} else if (px < pSBCalc->pxThumbTop) {
return HTSCROLLUPPAGE;
} else if (px < pSBCalc->pxThumbBottom) {
return HTSCROLLTHUMB;
} else if (px < pSBCalc->pxDownArrow) {
return HTSCROLLDOWNPAGE;
}
return HTERROR;
}
BOOL _SBGetParms(
PWND pwnd,
int code,
PSBDATA pw,
LPSCROLLINFO lpsi)
{
PSBTRACK pSBTrack;
pSBTrack = PWNDTOPSBTRACK(pwnd);
if (lpsi->fMask & SIF_RANGE) {
lpsi->nMin = pw->posMin;
lpsi->nMax = pw->posMax;
}
if (lpsi->fMask & SIF_PAGE)
lpsi->nPage = pw->page;
if (lpsi->fMask & SIF_POS) {
lpsi->nPos = pw->pos;
}
if (lpsi->fMask & SIF_TRACKPOS)
{
if (pSBTrack && (pSBTrack->nBar == code) && (pSBTrack->spwndTrack == pwnd)) {
// posNew is in the context of psbiSB's window and bar code
lpsi->nTrackPos = pSBTrack->posNew;
} else {
lpsi->nTrackPos = pw->pos;
}
}
return ((lpsi->fMask & SIF_ALL) ? TRUE : FALSE);
}
/***************************************************************************\
* GetWndSBDisableFlags
*
* This returns the scroll bar Disable flags of the scroll bars of a
* given Window.
*
*
* History:
* 4-18-91 MikeHar Ported for the 31 merge
\***************************************************************************/
UINT GetWndSBDisableFlags(
PWND pwnd, // The window whose scroll bar Disable Flags are to be returned;
BOOL fVert) // If this is TRUE, it means Vertical scroll bar.
{
PSBINFO pw;
if ((pw = pwnd->pSBInfo) == NULL) {
RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
return 0;
}
return (fVert ? (pw->WSBflags & WSB_VERT) >> 2 : pw->WSBflags & WSB_HORZ);
}
/***************************************************************************\
* xxxEnableSBCtlArrows()
*
* This function can be used to selectively Enable/Disable
* the arrows of a scroll bar Control
*
* History:
* 04-18-91 MikeHar Ported for the 31 merge
\***************************************************************************/
BOOL xxxEnableSBCtlArrows(
PWND pwnd,
UINT wArrows)
{
UINT wOldFlags;
UINT wNewFlags;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
wOldFlags = ((PSBWND)pwnd)->wDisableFlags; // Get the original status
if (wArrows == ESB_ENABLE_BOTH) { // Enable both the arrows
((PSBWND)pwnd)->wDisableFlags &= ~SB_DISABLE_MASK;
} else {
((PSBWND)pwnd)->wDisableFlags |= wArrows;
}
/*
* Check if the status has changed because of this call
*/
if (wOldFlags == ((PSBWND)pwnd)->wDisableFlags)
return FALSE;
/*
* Else, redraw the scroll bar control to reflect the new state
*/
if (IsVisible(pwnd))
xxxInvalidateRect(pwnd, NULL, TRUE);
wNewFlags = ((PSBWND)pwnd)->wDisableFlags;
/*
* state change notifications
*/
if ((wOldFlags & ESB_DISABLE_UP) != (wNewFlags & ESB_DISABLE_UP)) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
}
if ((wOldFlags & ESB_DISABLE_DOWN) != (wNewFlags & ESB_DISABLE_DOWN)) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT,
INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
}
return TRUE;
}
/***************************************************************************\
* xxxEnableWndSBArrows()
*
* This function can be used to selectively Enable/Disable
* the arrows of a Window Scroll bar(s)
*
* History:
* 4-18-91 MikeHar Ported for the 31 merge
\***************************************************************************/
BOOL xxxEnableWndSBArrows(
PWND pwnd,
UINT wSBflags,
UINT wArrows)
{
INT wOldFlags;
PSBINFO pw;
BOOL bRetValue = FALSE;
HDC hdc;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
if ((pw = pwnd->pSBInfo) != NULL) {
wOldFlags = pw->WSBflags;
} else {
/*
* Originally everything is enabled; Check to see if this function is
* asked to disable anything; Otherwise, no change in status; So, must
* return immediately;
*/
if(!wArrows)
return FALSE; // No change in status!
wOldFlags = 0; // Both are originally enabled;
if((pw = _InitPwSB(pwnd)) == NULL) // Allocate the pSBInfo for hWnd
return FALSE;
}
if((hdc = _GetWindowDC(pwnd)) == NULL)
return FALSE;
/*
* First Take care of the Horizontal Scroll bar, if one exists.
*/
if((wSBflags == SB_HORZ) || (wSBflags == SB_BOTH)) {
if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
pw->WSBflags &= ~SB_DISABLE_MASK;
else
pw->WSBflags |= wArrows;
/*
* Update the display of the Horizontal Scroll Bar;
*/
if(pw->WSBflags != wOldFlags) {
bRetValue = TRUE;
wOldFlags = pw->WSBflags;
if (TestWF(pwnd, WFHPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
IsVisible(pwnd)) {
xxxDrawScrollBar(pwnd, hdc, FALSE); // Horizontal Scroll Bar.
}
}
// Left button
if ((wOldFlags & ESB_DISABLE_LEFT) != (pw->WSBflags & ESB_DISABLE_LEFT)) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
}
// Right button
if ((wOldFlags & ESB_DISABLE_RIGHT) != (pw->WSBflags & ESB_DISABLE_RIGHT)) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL,
INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
}
}
/*
* Then take care of the Vertical Scroll bar, if one exists.
*/
if((wSBflags == SB_VERT) || (wSBflags == SB_BOTH)) {
if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
pw->WSBflags &= ~(SB_DISABLE_MASK << 2);
else
pw->WSBflags |= (wArrows << 2);
/*
* Update the display of the Vertical Scroll Bar;
*/
if(pw->WSBflags != wOldFlags) {
bRetValue = TRUE;
if (TestWF(pwnd, WFVPRESENT) && !TestWF(pwnd, WFMINIMIZED) &&
IsVisible(pwnd)) {
xxxDrawScrollBar(pwnd, hdc, TRUE); // Vertical Scroll Bar
}
// Up button
if ((wOldFlags & (ESB_DISABLE_UP << 2)) != (pw->WSBflags & (ESB_DISABLE_UP << 2))) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD);
}
// Down button
if ((wOldFlags & (ESB_DISABLE_DOWN << 2)) != (pw->WSBflags & (ESB_DISABLE_DOWN << 2))) {
xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL,
INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD);
}
}
}
_ReleaseDC(hdc);
return bRetValue;
}
/***************************************************************************\
* EnableScrollBar()
*
* This function can be used to selectively Enable/Disable
* the arrows of a scroll bar; It could be used with Windows Scroll
* bars as well as scroll bar controls
*
* History:
* 4-18-91 MikeHar Ported for the 31 merge
\***************************************************************************/
BOOL xxxEnableScrollBar(
PWND pwnd,
UINT wSBflags, // Whether it is a Window Scroll Bar; if so, HORZ or VERT?
// Possible values are SB_HORZ, SB_VERT, SB_CTL or SB_BOTH
UINT wArrows) // Which arrows must be enabled/disabled:
// ESB_ENABLE_BOTH = > Enable both arrows.
// ESB_DISABLE_LTUP = > Disable Left/Up arrow;
// ESB_DISABLE_RTDN = > DIsable Right/Down arrow;
// ESB_DISABLE_BOTH = > Disable both the arrows;
{
#define ES_NOTHING 0
#define ES_DISABLE 1
#define ES_ENABLE 2
UINT wOldFlags;
UINT wEnableWindow;
CheckLock(pwnd);
if(wSBflags != SB_CTL) {
return xxxEnableWndSBArrows(pwnd, wSBflags, wArrows);
}
/*
* Let us assume that we don't have to call EnableWindow
*/
wEnableWindow = ES_NOTHING;
wOldFlags = ((PSBWND)pwnd)->wDisableFlags & (UINT)SB_DISABLE_MASK;
/*
* Check if the present state of the arrows is exactly the same
* as what the caller wants:
*/
if (wOldFlags == wArrows)
return FALSE ; // If so, nothing needs to be done;
/*
* Check if the caller wants to disable both the arrows
*/
if (wArrows == ESB_DISABLE_BOTH) {
wEnableWindow = ES_DISABLE; // Yes! So, disable the whole SB Ctl.
} else {
/*
* Check if the caller wants to enable both the arrows
*/
if(wArrows == ESB_ENABLE_BOTH) {
/*
* We need to enable the SB Ctl only if it was already disabled.
*/
if(wOldFlags == ESB_DISABLE_BOTH)
wEnableWindow = ES_ENABLE;// EnableWindow(.., TRUE);
} else {
/*
* Now, Caller wants to disable only one arrow;
* Check if one of the arrows was already disabled and we want
* to disable the other;If so, the whole SB Ctl will have to be
* disabled; Check if this is the case:
*/
if((wOldFlags | wArrows) == ESB_DISABLE_BOTH)
wEnableWindow = ES_DISABLE; // EnableWindow(, FALSE);
}
}
if(wEnableWindow != ES_NOTHING) {
/*
* EnableWindow returns old state of the window; We must return
* TRUE only if the Old state is different from new state.
*/
if(xxxEnableWindow(pwnd, (BOOL)(wEnableWindow == ES_ENABLE))) {
return !(TestWF(pwnd, WFDISABLED));
} else {
return TestWF(pwnd, WFDISABLED);
}
}
return (BOOL)xxxSendMessage(pwnd, SBM_ENABLE_ARROWS, (DWORD)wArrows, 0);
#undef ES_NOTHING
#undef ES_DISABLE
#undef ES_ENABLE
}
/***************************************************************************\
*
* DrawSize() -
*
\***************************************************************************/
void FAR DrawSize(PWND pwnd, HDC hdc, int cxFrame,int cyFrame)
{
int x, y;
//HBRUSH hbrSave;
if (TestWF(pwnd, WEFLEFTSCROLL)) {
x = cxFrame;
} else {
x = pwnd->rcWindow.right - pwnd->rcWindow.left - cxFrame - SYSMET(CXVSCROLL);
}
y = pwnd->rcWindow.bottom - pwnd->rcWindow.top - cyFrame - SYSMET(CYHSCROLL);
// If we have a scrollbar control, or the sizebox is not associated with
// a sizeable window, draw the flat gray sizebox. Otherwise, use the
// sizing grip.
if (IsScrollBarControl(pwnd))
{
if (TestWF(pwnd, SBFSIZEGRIP))
goto DrawSizeGrip;
else
goto DrawBox;
}
else if (!SizeBoxHwnd(pwnd))
{
DrawBox:
{
//hbrSave = GreSelectBrush(hdc, SYSHBR(3DFACE));
//GrePatBlt(hdc, x, y, SYSMET(CXVSCROLL), SYSMET(CYHSCROLL), PATCOPY);
//GreSelectBrush(hdc, hbrSave);
POLYPATBLT PolyData;
PolyData.x = x;
PolyData.y = y;
PolyData.cx = SYSMET(CXVSCROLL);
PolyData.cy = SYSMET(CYHSCROLL);
PolyData.BrClr.hbr = SYSHBR(3DFACE);
GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
}
}
else
{
DrawSizeGrip:
// Blt out the grip bitmap.
BitBltSysBmp(hdc, x, y, TestWF(pwnd, WEFLEFTSCROLL) ? OBI_NCGRIP_L : OBI_NCGRIP);
}
}
/***************************************************************************\
* xxxSelectColorObjects
*
*
*
* History:
\***************************************************************************/
HBRUSH xxxGetColorObjects(
PWND pwnd,
HDC hdc)
{
HBRUSH hbrRet;
CheckLock(pwnd);
// Use the scrollbar color even if the scrollbar is disabeld.
if (!IsScrollBarControl(pwnd))
hbrRet = (HBRUSH)xxxDefWindowProc(pwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(pwnd));
else {
// B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
// owner. If the app doesn't process the message, DefWindowProc32
// will always return the appropriate system brush. If the app.
// returns an invalid object, GetControlBrush will call DWP for
// the default brush. Thus hbrRet doesn't need any validation
// here.
hbrRet = xxxGetControlBrush(pwnd, hdc, WM_CTLCOLORSCROLLBAR);
}
return hbrRet;
}
/***************************************************************************\
*
* DrawGroove()
*
* Draws lines & middle of thumb groove
* Note that pw points into prc. Moreover, note that both pw & prc are
* NEAR pointers, so *prc better not be on the stack.
*
\***************************************************************************/
void NEAR DrawGroove(HDC hdc, HBRUSH hbr, LPRECT prc, BOOL fVert)
{
if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == gpsi->hbrGray))
FillRect(hdc, prc, hbr);
else
{
RECT rc;
// Draw sides
CopyRect(&rc, prc);
DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT |
(fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
// Fill middle
FillRect(hdc, &rc, hbr);
}
}
/***************************************************************************\
* CalcTrackDragRect
*
* Give the rectangle for a scrollbar in pSBTrack->pSBCalc,
* calculate pSBTrack->rcTrack, the rectangle where tracking
* may occur without cancelling the thumbdrag operation.
*
\***************************************************************************/
void CalcTrackDragRect(PSBTRACK pSBTrack) {
int cx;
int cy;
LPINT pwX, pwY;
//
// Point pwX and pwY at the parts of the rectangle
// corresponding to pSBCalc->pxLeft, pxTop, etc.
//
// pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
// scrollbar and the top edge of horizontal one.
// pSBTrack->pSBCalc->pxTop is the top of a vertical
// scrollbar and the left of horizontal one.
// etc...
//
// Point pwX and pwY to the corresponding parts
// of pSBTrack->rcTrack.
//
pwX = pwY = (LPINT)&pSBTrack->rcTrack;
if (pSBTrack->fTrackVert) {
cy = SYSMET(CYVTHUMB);
pwY++;
} else {
cy = SYSMET(CXHTHUMB);
pwX++;
}
/*
* Later5.0 GerardoB: People keep complaining about this tracking region
* being too narrow so let's make it wider while PM decides what to do
* about it.
* We also used to have some hard coded min and max values but that should
* depend on some metric, if at all needed.
*/
cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8;
cy *= 2;
*(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx;
*(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy;
*(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx;
*(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy;
}
void RecalcTrackRect(PSBTRACK pSBTrack) {
LPINT pwX, pwY;
RECT rcSB;
if (!pSBTrack->fCtlSB)
CalcSBStuff(pSBTrack->spwndTrack, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
pwX = (LPINT)&rcSB;
pwY = pwX + 1;
if (!pSBTrack->fTrackVert)
pwX = pwY--;
*(pwX + 0) = pSBTrack->pSBCalc->pxLeft;
*(pwY + 0) = pSBTrack->pSBCalc->pxTop;
*(pwX + 2) = pSBTrack->pSBCalc->pxRight;
*(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
switch(pSBTrack->cmdSB) {
case SB_LINEUP:
*(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow;
break;
case SB_LINEDOWN:
*(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow;
break;
case SB_PAGEUP:
*(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow;
*(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop;
break;
case SB_THUMBPOSITION:
CalcTrackDragRect(pSBTrack);
break;
case SB_PAGEDOWN:
*(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom;
*(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow;
break;
}
if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
CopyRect(&pSBTrack->rcTrack, &rcSB);
}
}
/***************************************************************************\
* DrawThumb2
*
*
*
* History:
* 01-03-94 FritzS Chicago changes
\***************************************************************************/
void DrawThumb2(
PWND pwnd,
PSBCALC pSBCalc,
HDC hdc,
HBRUSH hbr,
BOOL fVert,
UINT wDisable) /* Disabled flags for the scroll bar */
{
int *pLength;
int *pWidth;
RECT rcSB;
PSBTRACK pSBTrack;
//
// Bail out if the scrollbar has an empty rect
//
if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight))
return;
pLength = (LPINT)&rcSB;
if (fVert)
pWidth = pLength++;
else
pWidth = pLength + 1;
pWidth[0] = pSBCalc->pxLeft;
pWidth[2] = pSBCalc->pxRight;
/*
* If both scroll bar arrows are disabled, then we should not draw
* the thumb. So, quit now!
*/
if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb)) {
pLength[0] = pSBCalc->pxUpArrow;
pLength[2] = pSBCalc->pxDownArrow;
DrawGroove(hdc, hbr, &rcSB, fVert);
return;
}
if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop) {
// Fill in space above Thumb
pLength[0] = pSBCalc->pxUpArrow;
pLength[2] = pSBCalc->pxThumbTop;
DrawGroove(hdc, hbr, &rcSB, fVert);
}
if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow) {
// Fill in space below Thumb
pLength[0] = pSBCalc->pxThumbBottom;
pLength[2] = pSBCalc->pxDownArrow;
DrawGroove(hdc, hbr, &rcSB, fVert);
}
//
// Draw elevator
//
pLength[0] = pSBCalc->pxThumbTop;
pLength[2] = pSBCalc->pxThumbBottom;
// Not soft!
DrawPushButton(hdc, &rcSB, 0, 0);
/*
* If we're tracking a page scroll, then we've obliterated the hilite.
* We need to correct the hiliting rectangle, and rehilite it.
*/
pSBTrack = PWNDTOPSBTRACK(pwnd);
if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) &&
(pwnd == pSBTrack->spwndTrack) &&
(BOOL)pSBTrack->fTrackVert == fVert) {
if (pSBTrack->fTrackRecalc) {
RecalcTrackRect(pSBTrack);
pSBTrack->fTrackRecalc = FALSE;
}
pLength = (int *)&pSBTrack->rcTrack;
if (fVert)
pLength++;
if (pSBTrack->cmdSB == SB_PAGEUP)
pLength[2] = pSBCalc->pxThumbTop;
else
pLength[0] = pSBCalc->pxThumbBottom;
if (pLength[0] < pLength[2])
InvertRect(hdc, &pSBTrack->rcTrack);
}
}
/***************************************************************************\
* xxxDrawSB2
*
*
*
* History:
\***************************************************************************/
void xxxDrawSB2(
PWND pwnd,
PSBCALC pSBCalc,
HDC hdc,
BOOL fVert,
UINT wDisable)
{
int cLength;
int cWidth;
int *pwX;
int *pwY;
HBRUSH hbr;
HBRUSH hbrSave;
int cpxArrow;
RECT rc, rcSB;
COLORREF crText, crBk;
CheckLock(pwnd);
cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2;
cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
if ((cLength <= 0) || (cWidth <= 0)) {
return;
}
if (fVert)
cpxArrow = SYSMET(CYVSCROLL);
else
cpxArrow = SYSMET(CXHSCROLL);
/*
* Save background and DC color, since they get changed in
* xxxGetColorObjects. Restore before we return.
*/
crBk = GreGetBkColor(hdc);
crText = GreGetTextColor(hdc);
hbr = xxxGetColorObjects(pwnd, hdc);
if (cLength > cpxArrow)
cLength = cpxArrow;
pwX = (int *)&rcSB;
pwY = pwX + 1;
if (!fVert)
pwX = pwY--;
pwX[0] = pSBCalc->pxLeft;
pwY[0] = pSBCalc->pxTop;
pwX[2] = pSBCalc->pxRight;
pwY[2] = pSBCalc->pxBottom;
hbrSave = GreSelectBrush(hdc, SYSHBR(BTNTEXT));
//
// BOGUS
// Draw scrollbar arrows as disabled if the scrollbar itself is
// disabled OR if the window it is a part of is disabled?
//
if (fVert) {
if ((cLength == SYSMET(CYVSCROLL)) && (cWidth == SYSMET(CXVSCROLL))) {
BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_UPARROW_I : OBI_UPARROW);
BitBltSysBmp(hdc, rcSB.left, rcSB.bottom - cLength, (wDisable & RTDNFLAG) ? OBI_DNARROW_I : OBI_DNARROW);
} else {
CopyRect(&rc, &rcSB);
rc.bottom = rc.top + cLength;
DrawFrameControl(hdc, &rc, DFC_SCROLL,
DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.bottom = rcSB.bottom;
rc.top = rcSB.bottom - cLength;
DrawFrameControl(hdc, &rc, DFC_SCROLL,
DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
}
} else {
if ((cLength == SYSMET(CXHSCROLL)) && (cWidth == SYSMET(CYHSCROLL))) {
BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_LFARROW_I : OBI_LFARROW);
BitBltSysBmp(hdc, rcSB.right - cLength, rcSB.top, (wDisable & RTDNFLAG) ? OBI_RGARROW_I : OBI_RGARROW);
} else {
CopyRect(&rc, &rcSB);
rc.right = rc.left + cLength;
DrawFrameControl(hdc, &rc, DFC_SCROLL,
DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.right = rcSB.right;
rc.left = rcSB.right - cLength;
DrawFrameControl(hdc, &rc, DFC_SCROLL,
DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
}
}
hbrSave = GreSelectBrush(hdc, hbrSave);
DrawThumb2(pwnd, pSBCalc, hdc, hbr, fVert, wDisable);
GreSelectBrush(hdc, hbrSave);
GreSetBkColor(hdc, crBk);
GreSetTextColor(hdc, crText);
}
/***************************************************************************\
* zzzSetSBCaretPos
*
*
*
* History:
\***************************************************************************/
void zzzSetSBCaretPos(
PSBWND psbwnd)
{
if ((PWND)psbwnd == PtiCurrent()->pq->spwndFocus) {
zzzSetCaretPos((psbwnd->fVert ? psbwnd->SBCalc.pxLeft : psbwnd->SBCalc.pxThumbTop) + SYSMET(CXEDGE),
(psbwnd->fVert ? psbwnd->SBCalc.pxThumbTop : psbwnd->SBCalc.pxLeft) + SYSMET(CYEDGE));
}
}
/***************************************************************************\
* CalcSBStuff2
*
*
*
* History:
\***************************************************************************/
void CalcSBStuff2(
PSBCALC pSBCalc,
LPRECT lprc,
CONST PSBDATA pw,
BOOL fVert)
{
int cpx;
DWORD dwRange;
int denom;
if (fVert) {
pSBCalc->pxTop = lprc->top;
pSBCalc->pxBottom = lprc->bottom;
pSBCalc->pxLeft = lprc->left;
pSBCalc->pxRight = lprc->right;
pSBCalc->cpxThumb = SYSMET(CYVSCROLL);
} else {
/*
* For horiz scroll bars, "left" & "right" are "top" and "bottom",
* and vice versa.
*/
pSBCalc->pxTop = lprc->left;
pSBCalc->pxBottom = lprc->right;
pSBCalc->pxLeft = lprc->top;
pSBCalc->pxRight = lprc->bottom;
pSBCalc->cpxThumb = SYSMET(CXHSCROLL);
}
pSBCalc->pos = pw->pos;
pSBCalc->page = pw->page;
pSBCalc->posMin = pw->posMin;
pSBCalc->posMax = pw->posMax;
dwRange = ((DWORD)(pSBCalc->posMax - pSBCalc->posMin)) + 1;
//
// For the case of short scroll bars that don't have enough
// room to fit the full-sized up and down arrows, shorten
// their sizes to make 'em fit
//
cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx;
pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
if ((pw->page != 0) && (dwRange != 0)) {
// JEFFBOG -- This is the one and only place where we should
// see 'range'. Elsewhere it should be 'range - page'.
/*
* The minimun thumb size used to depend on the frame/edge metrics.
* People that increase the scrollbar width/height expect the minimun
* to grow with proportianally. So NT5 bases the minimun on
* CXH/YVSCROLL, which is set by default in cpxThumb.
*/
/*
* i is used to keep the macro "max" from executing EngMulDiv twice.
*/
int i = EngMulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow,
pw->page, dwRange);
pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i);
}
pSBCalc->pxMin = pSBCalc->pxTop + cpx;
pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
denom = dwRange - (pw->page ? pw->page : 1);
if (denom)
pSBCalc->pxThumbTop = EngMulDiv(pw->pos - pw->posMin,
pSBCalc->cpx, denom) +
pSBCalc->pxMin;
else
pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
}
/***************************************************************************\
* SBCtlSetup
*
*
*
* History:
\***************************************************************************/
void SBCtlSetup(
PSBWND psbwnd)
{
RECT rc;
GetRect((PWND)psbwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS);
CalcSBStuff2(&psbwnd->SBCalc, &rc, (PSBDATA)&psbwnd->SBCalc, psbwnd->fVert);
}
/***************************************************************************\
* HotTrackSB
*
\***************************************************************************/
#ifdef COLOR_HOTTRACKING
DWORD GetTrackFlags(int ht, BOOL fDraw)
{
if (fDraw) {
switch(ht) {
case HTSCROLLUP:
case HTSCROLLUPPAGE:
return LTUPFLAG;
case HTSCROLLDOWN:
case HTSCROLLDOWNPAGE:
return RTDNFLAG;
case HTSCROLLTHUMB:
return LTUPFLAG | RTDNFLAG;
default:
return 0;
}
} else {
return 0;
}
}
BOOL xxxHotTrackSB(PWND pwnd, int htEx, BOOL fDraw)
{
SBCALC SBCalc;
HDC hdc;
BOOL fVert = HIWORD(htEx);
int ht = LOWORD(htEx);
DWORD dwTrack = GetTrackFlags(ht, fDraw);
CheckLock(pwnd);
/*
* xxxDrawSB2 does not callback or leave the critical section when it's
* not a SB control and the window belongs to a different thread. It
* calls xxxDefWindowProc which simply returns the brush color.
*/
CalcSBStuff(pwnd, &SBCalc, fVert);
hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
xxxDrawSB2(pwnd, &SBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert), dwTrack);
_ReleaseDC(hdc);
return TRUE;
}
void xxxHotTrackSBCtl(PSBWND psbwnd, int ht, BOOL fDraw)
{
DWORD dwTrack = GetTrackFlags(ht, fDraw);
HDC hdc;
CheckLock(psbwnd);
SBCtlSetup(psbwnd);
hdc = _GetDCEx((PWND)psbwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE);
xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags, dwTrack);
_ReleaseDC(hdc);
}
#endif // COLOR_HOTTRACKING
BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres)
{
// pass the struct because we modify the struct but don't want that
// modified version to get back to the calling app
BOOL fChanged = FALSE;
if (lpsi->fMask & SIF_RETURNOLDPOS)
// save previous position
*lplres = pw->pos;
if (lpsi->fMask & SIF_RANGE) {
// if the range MAX is below the range MIN -- then treat is as a
// zero range starting at the range MIN.
if (lpsi->nMax < lpsi->nMin)
lpsi->nMax = lpsi->nMin;
if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) {
pw->posMin = lpsi->nMin;
pw->posMax = lpsi->nMax;
if (!(lpsi->fMask & SIF_PAGE)) {
lpsi->fMask |= SIF_PAGE;
lpsi->nPage = pw->page;
}
if (!(lpsi->fMask & SIF_POS)) {
lpsi->fMask |= SIF_POS;
lpsi->nPos = pw->pos;
}
fChanged = TRUE;
}
}
if (lpsi->fMask & SIF_PAGE) {
DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
// Clip page to 0, posMax - posMin + 1
if (lpsi->nPage > dwMaxPage)
lpsi->nPage = dwMaxPage;
if (pw->page != (int)(lpsi->nPage)) {
pw->page = lpsi->nPage;
if (!(lpsi->fMask & SIF_POS)) {
lpsi->fMask |= SIF_POS;
lpsi->nPos = pw->pos;
}
fChanged = TRUE;
}
}
if (lpsi->fMask & SIF_POS) {
int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0);
// Clip pos to posMin, posMax - (page - 1).
if (lpsi->nPos < pw->posMin)
lpsi->nPos = pw->posMin;
else if (lpsi->nPos > iMaxPos)
lpsi->nPos = iMaxPos;
if (pw->pos != lpsi->nPos) {
pw->pos = lpsi->nPos;
fChanged = TRUE;
}
}
if (!(lpsi->fMask & SIF_RETURNOLDPOS)) {
// Return the new position
*lplres = pw->pos;
}
/*
* This was added by JimA as Cairo merge but will conflict
* with the documentation for SetScrollPos
*/
/*
else if (*lplres == pw->pos)
*lplres = 0;
*/
if (lpsi->fMask & SIF_RANGE) {
if (*lpfScroll = (pw->posMin != pw->posMax))
goto checkPage;
} else if (lpsi->fMask & SIF_PAGE)
checkPage:
*lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
return fChanged;
}
/***************************************************************************\
* CalcSBStuff
*
*
*
* History:
\***************************************************************************/
void CalcSBStuff(
PWND pwnd,
PSBCALC pSBCalc,
BOOL fVert)
{
RECT rcT;
RECT rcClient;
int cx, iTemp;
//
// Get client rectangle. We know that scrollbars always align to the right
// and to the bottom of the client area.
//
GetRect(pwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS);
if (TestWF(pwnd, WEFLAYOUTRTL)) {
cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
iTemp = rcClient.left;
rcClient.left = cx - rcClient.right;
rcClient.right = cx - iTemp;
}
if (fVert) {
// Only add on space if vertical scrollbar is really there.
if (TestWF(pwnd, WEFLEFTSCROLL)) {
rcT.right = rcT.left = rcClient.left;
if (TestWF(pwnd, WFVPRESENT))
rcT.left -= SYSMET(CXVSCROLL);
} else {
rcT.right = rcT.left = rcClient.right;
if (TestWF(pwnd, WFVPRESENT))
rcT.right += SYSMET(CXVSCROLL);
}
rcT.top = rcClient.top;
rcT.bottom = rcClient.bottom;
} else {
// Only add on space if horizontal scrollbar is really there.
rcT.bottom = rcT.top = rcClient.bottom;
if (TestWF(pwnd, WFHPRESENT))
rcT.bottom += SYSMET(CYHSCROLL);
rcT.left = rcClient.left;
rcT.right = rcClient.right;
}
// If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
// we can do here, so just let it go through. We won't fault but the scrollbar won't work
// properly either...
if (_InitPwSB(pwnd))
CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &pwnd->pSBInfo->Vert : &pwnd->pSBInfo->Horz, fVert);
}
/***************************************************************************\
*
* DrawCtlThumb()
*
\***************************************************************************/
void DrawCtlThumb(PSBWND psb)
{
HBRUSH hbr, hbrSave;
HDC hdc = (HDC) _GetWindowDC((PWND) psb);
SBCtlSetup(psb);
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects((PWND) psb, hdc));
DrawThumb2((PWND) psb, &psb->SBCalc, hdc, hbr, psb->fVert, psb->wDisableFlags);
GreSelectBrush(hdc, hbrSave);
_ReleaseDC(hdc);
}
/***************************************************************************\
* xxxDrawThumb
*
*
*
* History:
\***************************************************************************/
void xxxDrawThumb(
PWND pwnd,
PSBCALC pSBCalc,
BOOL fVert)
{
HBRUSH hbr, hbrSave;
HDC hdc;
UINT wDisableFlags;
SBCALC SBCalc;
CheckLock(pwnd);
if (!pSBCalc) pSBCalc = &SBCalc;
hdc = (HDC)_GetWindowDC(pwnd);
CalcSBStuff(pwnd, &SBCalc, fVert);
wDisableFlags = GetWndSBDisableFlags(pwnd, fVert);
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
DrawThumb2(pwnd, &SBCalc, hdc, hbr, fVert, wDisableFlags);
GreSelectBrush(hdc, hbrSave);
/*
* Won't hurt even if DC is already released (which happens automatically
* if window is destroyed during xxxSelectColorObjects)
*/
_ReleaseDC(hdc);
}
/***************************************************************************\
* xxxSetScrollBar
*
*
*
* History:
\***************************************************************************/
LONG xxxSetScrollBar(
PWND pwnd,
int code,
LPSCROLLINFO lpsi,
BOOL fRedraw)
{
BOOL fVert;
PSBDATA pw;
PSBINFO pSBInfo;
BOOL fOldScroll;
BOOL fScroll;
WORD wfScroll;
LONG lres;
BOOL fNewScroll;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
if (fRedraw)
// window must be visible to redraw
fRedraw = IsVisible(pwnd);
if (code == SB_CTL)
#ifdef FE_SB // xxxSetScrollBar()
// scroll bar control; send the control a message
if(GETPTI(pwnd)->TIF_flags & TIF_16BIT) {
//
// If the target application is 16bit apps, we don't pass win40's message.
// This fix for Ichitaro v6.3. It eats the message. It never forwards
// the un-processed messages to original windows procedure via
// CallWindowProc().
//
// Is this from xxxSetScrollPos() ?
if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) {
return (int)xxxSendMessage(pwnd, SBM_SETPOS, lpsi->nPos, fRedraw);
// Is this from xxxSetScrollRange() ?
} else if(lpsi->fMask == SIF_RANGE) {
xxxSendMessage(pwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax);
return TRUE;
// Others...
} else {
return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
}
} else {
return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
}
#else
// scroll bar control; send the control a message
return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi);
#endif // FE_SB
fVert = (code != SB_HORZ);
wfScroll = (fVert) ? WFVSCROLL : WFHSCROLL;
fScroll = fOldScroll = (TestWF(pwnd, wfScroll)) ? TRUE : FALSE;
/*
* Don't do anything if we're setting position of a nonexistent scroll bar.
*/
if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (pwnd->pSBInfo == NULL)) {
RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, "");
return 0;
}
if (fNewScroll = !(pSBInfo = pwnd->pSBInfo)) {
if ((pSBInfo = _InitPwSB(pwnd)) == NULL)
return 0;
}
pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll) {
// no change -- but if REDRAW is specified and there's a scrollbar,
// redraw the thumb
if (fOldScroll && fRedraw)
goto redrawAfterSet;
return lres;
}
ClrWF(pwnd, wfScroll);
if (fScroll)
SetWF(pwnd, wfScroll);
else if (!TestWF(pwnd, (WFHSCROLL | WFVSCROLL))) {
// if neither scroll bar is set and both ranges are 0, then free up the
// scroll info
pSBInfo = pwnd->pSBInfo;
if ((pSBInfo->Horz.posMin == pSBInfo->Horz.posMax) &&
(pSBInfo->Vert.posMin == pSBInfo->Vert.posMax)) {
DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo));
pwnd->pSBInfo = NULL;
}
}
if (lpsi->fMask & SIF_DISABLENOSCROLL) {
if (fOldScroll) {
SetWF(pwnd, wfScroll);
xxxEnableWndSBArrows(pwnd, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
}
} else if (fOldScroll ^ fScroll) {
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
if (pSBTrack && (pwnd == pSBTrack->spwndTrack)) {
pSBTrack->fTrackRecalc = TRUE;
}
xxxRedrawFrame(pwnd);
// Note: after xxx, pSBTrack may no longer be valid (but we return now)
return lres;
}
if (fScroll && fRedraw && (fVert ? TestWF(pwnd, WFVPRESENT) : TestWF(pwnd, WFHPRESENT))) {
PSBTRACK pSBTrack;
redrawAfterSet:
xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, pwnd, (fVert ? OBJID_VSCROLL : OBJID_HSCROLL),
INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
pSBTrack = PWNDTOPSBTRACK(pwnd);
// Bail out if the caller is trying to change the position of
// a scrollbar that is in the middle of tracking. We'll hose
// TrackThumb() otherwise.
if (pSBTrack && (pwnd == pSBTrack->spwndTrack) &&
((BOOL)(pSBTrack->fTrackVert) == fVert) &&
(pSBTrack->xxxpfnSB == xxxTrackThumb)) {
return lres;
}
xxxDrawThumb(pwnd, NULL, fVert);
// Note: after xxx, pSBTrack may no longer be valid (but we return now)
}
return lres;
}
/***************************************************************************\
* xxxDrawScrollBar
*
*
*
* History:
\***************************************************************************/
void xxxDrawScrollBar(
PWND pwnd,
HDC hdc,
BOOL fVert)
{
SBCALC SBCalc;
PSBCALC pSBCalc;
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
CheckLock(pwnd);
if (pSBTrack && (pwnd == pSBTrack->spwndTrack) && (pSBTrack->fCtlSB == FALSE)
&& (fVert == (BOOL)pSBTrack->fTrackVert)) {
pSBCalc = pSBTrack->pSBCalc;
} else {
pSBCalc = &SBCalc;
}
CalcSBStuff(pwnd, pSBCalc, fVert);
xxxDrawSB2(pwnd, pSBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert));
}
/***************************************************************************\
* SBPosFromPx
*
* Compute scroll bar position from pixel location
*
* History:
\***************************************************************************/
int SBPosFromPx(
PSBCALC pSBCalc,
int px)
{
if (px < pSBCalc->pxMin) {
return pSBCalc->posMin;
}
if (px >= pSBCalc->pxMin + pSBCalc->cpx) {
return (pSBCalc->posMax - (pSBCalc->page ? pSBCalc->page - 1 : 0));
}
if (pSBCalc->cpx)
return (pSBCalc->posMin + EngMulDiv(pSBCalc->posMax - pSBCalc->posMin -
(pSBCalc->page ? pSBCalc->page - 1 : 0),
px - pSBCalc->pxMin, pSBCalc->cpx));
else
return (pSBCalc->posMin - 1);
}
/***************************************************************************\
* InvertScrollHilite
*
*
*
* History:
\***************************************************************************/
void InvertScrollHilite(
PWND pwnd,
PSBTRACK pSBTrack)
{
HDC hdc;
/*
* Don't invert if the thumb is all the way at the top or bottom
* or you will end up inverting the line between the arrow and the thumb.
*/
if (!IsRectEmpty(&pSBTrack->rcTrack)) {
if (pSBTrack->fTrackRecalc) {
RecalcTrackRect(pSBTrack);
pSBTrack->fTrackRecalc = FALSE;
}
hdc = (HDC)_GetWindowDC(pwnd);
InvertRect(hdc, &pSBTrack->rcTrack);
_ReleaseDC(hdc);
}
}
/***************************************************************************\
* xxxDoScroll
*
* Sends scroll notification to the scroll bar owner
*
* History:
\***************************************************************************/
void xxxDoScroll(
PWND pwnd,
PWND pwndNotify,
int cmd,
int pos,
BOOL fVert
)
{
TL tlpwndNotify;
/*
* Special case!!!! this routine is always passed pwnds that are
* not thread locked, so they need to be thread locked here. The
* callers always know that by the time DoScroll() returns,
* pwnd and pwndNotify could be invalid.
*/
ThreadLock(pwndNotify, &tlpwndNotify);
xxxSendMessage(pwndNotify, (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL),
MAKELONG(cmd, pos), (LPARAM)HW(pwnd));
ThreadUnlock(&tlpwndNotify);
}
// -------------------------------------------------------------------------
//
// CheckScrollRecalc()
//
// -------------------------------------------------------------------------
//void CheckScrollRecalc(PWND pwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
//{
// if ((pSBState->pwndCalc != pwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
// {
// // Calculate SB stuff based on whether it's a control or in a window
// if (pSBState->fCtlSB)
// SBCtlSetup((PSBWND) pwnd);
// else
// CalcSBStuff(pwnd, pSBCalc, pSBState->fVertSB);
// }
//}
/***************************************************************************\
* xxxMoveThumb
*
* History:
\***************************************************************************/
void xxxMoveThumb(
PWND pwnd,
PSBCALC pSBCalc,
int px)
{
HBRUSH hbr, hbrSave;
HDC hdc;
PSBTRACK pSBTrack;
CheckLock(pwnd);
pSBTrack = PWNDTOPSBTRACK(pwnd);
if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
return;
pxReCalc:
pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
/* Tentative position changed -- notify the guy. */
if (pSBTrack->posNew != pSBTrack->posOld) {
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert
);
}
// After xxxDoScroll, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(1)");
if ((pSBTrack == NULL) || (pSBTrack->xxxpfnSB == NULL))
return;
pSBTrack->posOld = pSBTrack->posNew;
//
// Anything can happen after the SendMessage above!
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
//
// CheckScrollRecalc(pwnd, pSBState, pSBCalc);
// when we yield, our range can get messed with
// so make sure we handle this
if (px >= pSBCalc->pxMin + pSBCalc->cpx)
{
px = pSBCalc->pxMin + pSBCalc->cpx;
goto pxReCalc;
}
}
hdc = _GetWindowDC(pwnd);
pSBCalc->pxThumbTop = px;
pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
// at this point, the disable flags are always going to be 0 --
// we're in the middle of tracking.
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
// After xxxGetColorObjects, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(2)");
if (pSBTrack == NULL) {
RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ;
_ReleaseDC(hdc);
return;
}
DrawThumb2(pwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0);
GreSelectBrush(hdc, hbrSave);
_ReleaseDC(hdc);
pSBTrack->pxOld = px;
}
/***************************************************************************\
* zzzDrawInvertScrollArea
*
*
*
* History:
\***************************************************************************/
void zzzDrawInvertScrollArea(
PWND pwnd,
PSBTRACK pSBTrack,
BOOL fHit,
UINT cmd)
{
HDC hdc;
RECT rcTemp;
int cx, cy;
UINT bm;
if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN)) {
// not hitting on arrow -- just invert the area and return
InvertScrollHilite(pwnd, pSBTrack);
if (cmd == SB_PAGEUP) {
if (fHit)
SetWF(pwnd, WFPAGEUPBUTTONDOWN);
else
ClrWF(pwnd, WFPAGEUPBUTTONDOWN);
} else {
if (fHit)
SetWF(pwnd, WFPAGEDNBUTTONDOWN);
else
ClrWF(pwnd, WFPAGEDNBUTTONDOWN);
}
zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
(pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE),
WEF_USEPWNDTHREAD);
// Note: after zzz, pSBTrack may no longer be valid (but we return now)
return;
}
if (pSBTrack->fTrackRecalc) {
RecalcTrackRect(pSBTrack);
pSBTrack->fTrackRecalc = FALSE;
}
CopyRect(&rcTemp, &pSBTrack->rcTrack);
hdc = _GetWindowDC(pwnd);
if (pSBTrack->fTrackVert) {
cx = SYSMET(CXVSCROLL);
cy = SYSMET(CYVSCROLL);
} else {
cx = SYSMET(CXHSCROLL);
cy = SYSMET(CYHSCROLL);
}
if ((cx == (rcTemp.right - rcTemp.left)) &&
(cy == (rcTemp.bottom - rcTemp.top))) {
if (cmd == SB_LINEUP)
bm = (pSBTrack->fTrackVert) ? OBI_UPARROW : OBI_LFARROW;
else // SB_LINEDOWN
bm = (pSBTrack->fTrackVert) ? OBI_DNARROW : OBI_RGARROW;
if (fHit)
bm += DOBI_PUSHED;
BitBltSysBmp(hdc, rcTemp.left, rcTemp.top, bm);
} else {
DrawFrameControl(hdc, &rcTemp, DFC_SCROLL,
((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) |
((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) |
((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX));
}
_ReleaseDC(hdc);
if (cmd == SB_LINEUP) {
if (fHit)
SetWF(pwnd, WFLINEUPBUTTONDOWN);
else
ClrWF(pwnd, WFLINEUPBUTTONDOWN);
} else {
if (fHit)
SetWF(pwnd, WFLINEDNBUTTONDOWN);
else
ClrWF(pwnd, WFLINEDNBUTTONDOWN);
}
zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd,
(pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
(cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN),
WEF_USEPWNDTHREAD);
// Note: after zzz, pSBTrack may no longer be valid (but we return now)
}
/***************************************************************************\
* xxxEndScroll
*
*
*
* History:
\***************************************************************************/
void xxxEndScroll(
PWND pwnd,
BOOL fCancel)
{
UINT oldcmd;
PSBTRACK pSBTrack;
CheckLock(pwnd);
UserAssert(!IsWinEventNotifyDeferred());
pSBTrack = PWNDTOPSBTRACK(pwnd);
if (pSBTrack && PtiCurrent()->pq->spwndCapture == pwnd && pSBTrack->xxxpfnSB != NULL) {
oldcmd = pSBTrack->cmdSB;
pSBTrack->cmdSB = 0;
xxxReleaseCapture();
// After xxxReleaseCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->xxxpfnSB == xxxTrackThumb) {
if (fCancel) {
pSBTrack->posOld = pSBTrack->pSBCalc->pos;
}
/*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert
);
// After xxxDoScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
if (pSBTrack->fCtlSB) {
DrawCtlThumb((PSBWND) pwnd);
} else {
xxxDrawThumb(pwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
// Note: after xxx, pSBTrack may no longer be valid
}
} else if (pSBTrack->xxxpfnSB == xxxTrackBox) {
DWORD lParam;
POINT ptMsg;
if (pSBTrack->hTimerSB != 0) {
_KillSystemTimer(pwnd, IDSYS_SCROLL);
pSBTrack->hTimerSB = 0;
}
lParam = _GetMessagePos();
if (TestWF(pwnd, WEFLAYOUTRTL)) {
ptMsg.x = pwnd->rcWindow.right - GET_X_LPARAM(lParam);
} else {
ptMsg.x = GET_X_LPARAM(lParam) - pwnd->rcWindow.left;
}
ptMsg.y = GET_Y_LPARAM(lParam) - pwnd->rcWindow.top;
if (PtInRect(&pSBTrack->rcTrack, ptMsg)) {
zzzDrawInvertScrollArea(pwnd, pSBTrack, FALSE, oldcmd);
// Note: after zzz, pSBTrack may no longer be valid
}
}
/*
* Always send SB_ENDSCROLL message.
*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
// After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
SB_ENDSCROLL, 0, pSBTrack->fTrackVert);
// After xxxDoScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
ClrWF(pwnd, WFSCROLLBUTTONDOWN);
ClrWF(pwnd, WFVERTSCROLLTRACK);
xxxWindowEvent(EVENT_SYSTEM_SCROLLINGEND, pwnd,
(pSBTrack->fCtlSB ? OBJID_CLIENT :
(pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
INDEXID_CONTAINER, 0);
// After xxxWindowEvent, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
/*
* If this is a Scroll Bar Control, turn the caret back on.
*/
if (pSBTrack->spwndSB != NULL) {
zzzShowCaret(pSBTrack->spwndSB);
// After zzz, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
pSBTrack->xxxpfnSB = NULL;
/*
* Unlock structure members so they are no longer holding down windows.
*/
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
}
}
/***************************************************************************\
* xxxContScroll
*
*
*
* History:
\***************************************************************************/
VOID xxxContScroll(
PWND pwnd,
UINT message,
UINT_PTR ID,
LPARAM lParam)
{
LONG pt;
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
UNREFERENCED_PARAMETER(message);
UNREFERENCED_PARAMETER(ID);
UNREFERENCED_PARAMETER(lParam);
if (pSBTrack == NULL)
return;
CheckLock(pwnd);
pt = _GetMessagePos();
if (TestWF(pwnd, WEFLAYOUTRTL)) {
pt = MAKELONG(pwnd->rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
} else {
pt = MAKELONG( GET_X_LPARAM(pt) - pwnd->rcWindow.left, GET_Y_LPARAM(pt) - pwnd->rcWindow.top);
}
xxxTrackBox(pwnd, WM_NULL, 0, pt, NULL);
// After xxxTrackBox, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->fHitOld) {
pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
gpsi->dtScroll / 8, xxxContScroll);
/*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
// Note: after xxx, pSBTrack may no longer be valid (but we return now)
}
}
return;
}
/***************************************************************************\
* xxxTrackBox
*
*
*
* History:
\***************************************************************************/
void xxxTrackBox(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
PSBCALC pSBCalc)
{
BOOL fHit;
POINT ptHit;
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
int cmsTimer;
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(pSBCalc);
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
if (pSBTrack == NULL)
return;
if (message != WM_NULL && HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
return;
if (pSBTrack->fTrackRecalc) {
RecalcTrackRect(pSBTrack);
pSBTrack->fTrackRecalc = FALSE;
}
ptHit.x = GET_X_LPARAM(lParam);
ptHit.y = GET_Y_LPARAM(lParam);
fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
if (fHit != (BOOL)pSBTrack->fHitOld) {
zzzDrawInvertScrollArea(pwnd, pSBTrack, fHit, pSBTrack->cmdSB);
// After zzz, pSBTrack may no longer be valid
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
cmsTimer = gpsi->dtScroll / 8;
switch (message) {
case WM_LBUTTONUP:
xxxEndScroll(pwnd, FALSE);
// Note: after xxx, pSBTrack may no longer be valid
break;
case WM_LBUTTONDOWN:
pSBTrack->hTimerSB = 0;
cmsTimer = gpsi->dtScroll;
/*
*** FALL THRU **
*/
case WM_MOUSEMOVE:
if (fHit && fHit != (BOOL)pSBTrack->fHitOld) {
/*
* We moved back into the normal rectangle: reset timer
*/
pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL,
cmsTimer, xxxContScroll);
/*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
pSBTrack->cmdSB, 0, pSBTrack->fTrackVert);
// Note: after xxx, pSBTrack may no longer be valid
}
}
}
// After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
pSBTrack->fHitOld = fHit;
}
/***************************************************************************\
* xxxTrackThumb
*
*
*
* History:
\***************************************************************************/
void xxxTrackThumb(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
PSBCALC pSBCalc)
{
int px;
PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
POINT pt;
UNREFERENCED_PARAMETER(wParam);
CheckLock(pwnd);
if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
return;
if (pSBTrack == NULL)
return;
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
// CheckScrollRecalc(pwnd, pSBState, pSBCalc);
if (pSBTrack->fTrackRecalc) {
RecalcTrackRect(pSBTrack);
pSBTrack->fTrackRecalc = FALSE;
}
pt.y = GET_Y_LPARAM(lParam);
pt.x = GET_X_LPARAM(lParam);
if (!PtInRect(&pSBTrack->rcTrack, pt))
px = pSBCalc->pxStart;
else {
px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
if (px < pSBCalc->pxMin)
px = pSBCalc->pxMin;
else if (px >= pSBCalc->pxMin + pSBCalc->cpx)
px = pSBCalc->pxMin + pSBCalc->cpx;
}
xxxMoveThumb(pwnd, pSBCalc, px);
/*
* We won't get the WM_LBUTTONUP message if we got here through
* the scroll menu, so test the button state directly.
*/
if (message == WM_LBUTTONUP || _GetKeyState(VK_LBUTTON) >= 0) {
xxxEndScroll(pwnd, FALSE);
}
}
/***************************************************************************\
* xxxSBTrackLoop
*
*
*
* History:
\***************************************************************************/
void xxxSBTrackLoop(
PWND pwnd,
LPARAM lParam,
PSBCALC pSBCalc)
{
MSG msg;
UINT cmd;
PTHREADINFO ptiCurrent;
VOID (*xxxpfnSB)(PWND, UINT, WPARAM, LPARAM, PSBCALC);
PSBTRACK pSBTrack;
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
pSBTrack = PWNDTOPSBTRACK(pwnd);
if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
// mode cancelled -- exit track loop
return;
if (pSBTrack->fTrackVert)
SetWF(pwnd, WFVERTSCROLLTRACK);
xxxWindowEvent(EVENT_SYSTEM_SCROLLINGSTART, pwnd,
(pSBTrack->fCtlSB ? OBJID_CLIENT :
(pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)),
INDEXID_CONTAINER, 0);
// Note: after xxx, pSBTrack may no longer be valid
(*xxxpfnSB)(pwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc);
// Note: after xxx, pSBTrack may no longer be valid
ptiCurrent = PtiCurrent();
while (ptiCurrent->pq->spwndCapture == pwnd) {
if (!xxxGetMessage(&msg, NULL, 0, 0)) {
// Note: after xxx, pSBTrack may no longer be valid
break;
}
if (!_CallMsgFilter(&msg, MSGF_SCROLLBAR)) {
cmd = msg.message;
if (msg.hwnd == HWq(pwnd) && ((cmd >= WM_MOUSEFIRST && cmd <=
WM_MOUSELAST) || (cmd >= WM_KEYFIRST &&
cmd <= WM_KEYLAST))) {
cmd = SystoChar(cmd, msg.lParam);
// After xxxWindowEvent, xxxpfnSB, xxxTranslateMessage or
// xxxDispatchMessage, re-evaluate pSBTrack.
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB)))
// mode cancelled -- exit track loop
return;
(*xxxpfnSB)(pwnd, cmd, msg.wParam, msg.lParam, pSBCalc);
} else {
xxxTranslateMessage(&msg, 0);
xxxDispatchMessage(&msg);
}
}
}
}
/***************************************************************************\
* xxxSBTrackInit
*
* History:
\***************************************************************************/
void xxxSBTrackInit(
PWND pwnd,
LPARAM lParam,
int curArea,
UINT uType)
{
int px;
LPINT pwX;
LPINT pwY;
UINT wDisable; // Scroll bar disable flags;
SBCALC SBCalc;
PSBCALC pSBCalc;
RECT rcSB;
PSBTRACK pSBTrack;
CheckLock(pwnd);
if (PWNDTOPSBTRACK(pwnd)) {
RIPMSG1(RIP_WARNING, "xxxSBTrackInit: PWNDTOPSBTRACK(pwnd) == %#p",
PWNDTOPSBTRACK(pwnd));
return;
}
pSBTrack = (PSBTRACK)UserAllocPoolWithQuota(sizeof(*pSBTrack), TAG_SCROLLTRACK);
if (pSBTrack == NULL)
return;
pSBTrack->hTimerSB = 0;
pSBTrack->fHitOld = FALSE;
pSBTrack->xxxpfnSB = xxxTrackBox;
pSBTrack->spwndTrack = NULL;
pSBTrack->spwndSB = NULL;
pSBTrack->spwndSBNotify = NULL;
Lock(&pSBTrack->spwndTrack, pwnd);
PWNDTOPSBTRACK(pwnd) = pSBTrack;
pSBTrack->fCtlSB = (!curArea);
if (pSBTrack->fCtlSB) {
/*
* This is a scroll bar control.
*/
Lock(&pSBTrack->spwndSB, pwnd);
pSBTrack->fTrackVert = ((PSBWND)pwnd)->fVert;
Lock(&pSBTrack->spwndSBNotify, pwnd->spwndParent);
wDisable = ((PSBWND)pwnd)->wDisableFlags;
pSBCalc = &((PSBWND)pwnd)->SBCalc;
pSBTrack->nBar = SB_CTL;
} else {
/*
* This is a scroll bar that is part of the window frame.
*/
//
// Mirror the window coord of the scroll bar,
// if it is a mirrored one
//
if (TestWF(pwnd,WEFLAYOUTRTL)) {
lParam = MAKELONG(
pwnd->rcWindow.right - GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
} else {
lParam = MAKELONG(
GET_X_LPARAM(lParam) - pwnd->rcWindow.left,
GET_Y_LPARAM(lParam) - pwnd->rcWindow.top);
}
Lock(&pSBTrack->spwndSBNotify, pwnd);
Lock(&pSBTrack->spwndSB, NULL);
pSBTrack->fTrackVert = (curArea - HTHSCROLL);
wDisable = GetWndSBDisableFlags(pwnd, pSBTrack->fTrackVert);
pSBCalc = &SBCalc;
pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ;
}
pSBTrack->pSBCalc = pSBCalc;
/*
* Check if the whole scroll bar is disabled
*/
if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
return; // It is a disabled scroll bar; So, do not respond.
}
if (!pSBTrack->fCtlSB) {
CalcSBStuff(pwnd, pSBCalc, pSBTrack->fTrackVert);
}
pwX = (LPINT)&rcSB;
pwY = pwX + 1;
if (!pSBTrack->fTrackVert)
pwX = pwY--;
px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
*(pwX + 0) = pSBCalc->pxLeft;
*(pwY + 0) = pSBCalc->pxTop;
*(pwX + 2) = pSBCalc->pxRight;
*(pwY + 2) = pSBCalc->pxBottom;
pSBTrack->cmdSB = (UINT)-1;
if (px < pSBCalc->pxUpArrow) {
/*
* The click occurred on Left/Up arrow; Check if it is disabled
*/
if(wDisable & LTUPFLAG) {
if(pSBTrack->fCtlSB) { // If this is a scroll bar control,
zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
// After zzzShowCaret, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
return; // Yes! disabled. Do not respond.
}
// LINEUP -- make rcSB the Up Arrow's Rectangle
pSBTrack->cmdSB = SB_LINEUP;
*(pwY + 2) = pSBCalc->pxUpArrow;
} else if (px >= pSBCalc->pxDownArrow) {
/*
* The click occurred on Right/Down arrow; Check if it is disabled
*/
if (wDisable & RTDNFLAG) {
if (pSBTrack->fCtlSB) { // If this is a scroll bar control,
zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
// After zzzShowCaret, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
}
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
return;// Yes! disabled. Do not respond.
}
// LINEDOWN -- make rcSB the Down Arrow's Rectangle
pSBTrack->cmdSB = SB_LINEDOWN;
*(pwY + 0) = pSBCalc->pxDownArrow;
} else if (px < pSBCalc->pxThumbTop) {
// PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
pSBTrack->cmdSB = SB_PAGEUP;
*(pwY + 0) = pSBCalc->pxUpArrow;
*(pwY + 2) = pSBCalc->pxThumbTop;
} else if (px < pSBCalc->pxThumbBottom) {
DoThumbPos:
/*
* Elevator isn't there if there's no room.
*/
if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) {
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
return;
}
// THUMBPOSITION -- we're tracking with the thumb
pSBTrack->cmdSB = SB_THUMBPOSITION;
CalcTrackDragRect(pSBTrack);
pSBTrack->xxxpfnSB = xxxTrackThumb;
pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop;
pSBTrack->posNew = pSBTrack->posOld = pSBCalc->pos;
pSBTrack->dpxThumb = pSBCalc->pxStart - px;
xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
// After xxxCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
/*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
if (pSBTrack->spwndSBNotify != NULL) {
xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify,
SB_THUMBTRACK, pSBTrack->posOld, pSBTrack->fTrackVert
);
// Note: after xxx, pSBTrack may no longer be valid
}
} else if (px < pSBCalc->pxDownArrow) {
// PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
pSBTrack->cmdSB = SB_PAGEDOWN;
*(pwY + 0) = pSBCalc->pxThumbBottom;
*(pwY + 2) = pSBCalc->pxDownArrow;
}
/*
* If the shift key is down, we'll position the thumb directly so it's
* centered on the click point.
*/
if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) ||
(uType == SCROLL_MENU)) {
if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
goto DoThumbPos;
}
pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2);
}
xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE);
// After xxxCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->cmdSB != SB_THUMBPOSITION) {
CopyRect(&pSBTrack->rcTrack, &rcSB);
}
xxxSBTrackLoop(pwnd, lParam, pSBCalc);
// After xxx, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop");
if (pSBTrack) {
Unlock(&pSBTrack->spwndSBNotify);
Unlock(&pSBTrack->spwndSB);
Unlock(&pSBTrack->spwndTrack);
UserFreePool(pSBTrack);
PWNDTOPSBTRACK(pwnd) = NULL;
}
}
/***************************************************************************\
* GetScrollMenu
*
* History:
\***************************************************************************/
PMENU xxxGetScrollMenu(
PWND pwnd,
BOOL fVert)
{
PMENU pMenu;
PMENU *ppDesktopMenu;
/*
* Grab the menu from the desktop. If the desktop menu
* has not been loaded and this is not a system thread,
* load it now. Callbacks cannot be made from a system
* thread or when a thread is in cleanup.
*/
if (fVert) {
ppDesktopMenu = &pwnd->head.rpdesk->spmenuVScroll;
} else {
ppDesktopMenu = &pwnd->head.rpdesk->spmenuHScroll;
}
pMenu = *ppDesktopMenu;
if (pMenu == NULL && !(PtiCurrent()->TIF_flags & (TIF_SYSTEMTHREAD | TIF_INCLEANUP))) {
UNICODE_STRING strMenuName;
RtlInitUnicodeStringOrId(&strMenuName,
fVert ? MAKEINTRESOURCE(ID_VSCROLLMENU) : MAKEINTRESOURCE(ID_HSCROLLMENU));
pMenu = xxxClientLoadMenu(NULL, &strMenuName);
LockDesktopMenu(ppDesktopMenu, pMenu);
}
/*
* Return the handle to the scroll menu.
*/
if (pMenu != NULL) {
return _GetSubMenu(pMenu, 0);
}
return NULL;
}
/***************************************************************************\
* xxxDoScrollMenu
*
* History:
\***************************************************************************/
VOID
xxxDoScrollMenu(
PWND pwndNotify,
PWND pwndSB,
BOOL fVert,
LPARAM lParam)
{
PMENU pMenu;
SBCALC SBCalc, *pSBCalc;
UINT cmd;
POINT pt;
TL tlpmenu;
UINT wDisable;
/*
* Check the compatibility flag. Word 6.0 AV's when selecting an item
* in this menu.
* NOTE: If this hack is to be extended for other apps we should use
* another bit for GACF_NOSCROLLBARCTXMENU as the current one is re-used
* MCostea #119380
*/
if (GetAppCompatFlags(NULL) & GACF_NOSCROLLBARCTXMENU) {
return;
}
/*
* Initialize some stuff.
*/
POINTSTOPOINT(pt, lParam);
if (pwndSB) {
SBCtlSetup((PSBWND)pwndSB);
pSBCalc = &(((PSBWND)pwndSB)->SBCalc);
wDisable = ((PSBWND)pwndSB)->wDisableFlags;
pt.x -= pwndSB->rcWindow.left;
pt.y -= pwndSB->rcWindow.top;
} else {
pSBCalc = &SBCalc;
CalcSBStuff(pwndNotify, pSBCalc, fVert);
wDisable = GetWndSBDisableFlags(pwndNotify, fVert);
pt.x -= pwndNotify->rcWindow.left;
pt.y -= pwndNotify->rcWindow.top;
}
/*
* Make sure the scrollbar isn't disabled.
*/
if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) {
return;
}
/*
* Put up a menu and scroll accordingly.
*/
if ((pMenu = xxxGetScrollMenu(pwndNotify, fVert)) != NULL) {
ThreadLockAlways(pMenu, &tlpmenu);
cmd = xxxTrackPopupMenuEx(pMenu,
TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY,
GET_X_LPARAM(lParam),
GET_Y_LPARAM(lParam),
pwndNotify,
NULL);
ThreadUnlock(&tlpmenu);
if (cmd) {
if ((cmd & 0x00FF) == SB_THUMBPOSITION) {
if (pwndSB) {
xxxSBTrackInit(pwndSB, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU);
} else {
xxxSBTrackInit(pwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU);
}
} else {
xxxDoScroll(pwndSB,
pwndNotify,
cmd & 0x00FF,
0,
fVert
);
xxxDoScroll(pwndSB,
pwndNotify,
SB_ENDSCROLL,
0,
fVert
);
}
}
}
}
/***************************************************************************\
* xxxSBWndProc
*
* History:
* 08-15-95 jparsons Added guard against NULL lParam [51986]
\***************************************************************************/
LRESULT xxxSBWndProc(
PSBWND psbwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
LONG l;
LONG lres;
int cx;
int cy;
UINT cmd;
UINT uSide;
HDC hdc;
RECT rc;
POINT pt;
BOOL fSizeReal;
HBRUSH hbrSave;
BOOL fSize;
PAINTSTRUCT ps;
UINT style;
TL tlpwndParent;
SCROLLINFO si;
LPSCROLLINFO lpsi = &si;
BOOL fRedraw = FALSE;
BOOL fScroll;
CheckLock(psbwnd);
UserAssert(IsWinEventNotifyDeferredOK());
VALIDATECLASSANDSIZE(((PWND)psbwnd), message, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
style = LOBYTE(psbwnd->wnd.style);
fSize = ((style & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
switch (message) {
case WM_CREATE:
/*
* Guard against lParam being NULL since the thunk allows it [51986]
*/
if (lParam) {
rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) +
((LPCREATESTRUCT)lParam)->cx;
rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) +
((LPCREATESTRUCT)lParam)->cy;
// This is because we can't just rev CardFile -- we should fix the
// problem here in case anyone else happened to have some EXTRA
// scroll styles on their scroll bar controls (jeffbog 03/21/94)
if (!TestWF((PWND)psbwnd, WFWIN40COMPAT))
psbwnd->wnd.style &= ~(WS_HSCROLL | WS_VSCROLL);
if (!fSize) {
l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams);
psbwnd->SBCalc.pos = psbwnd->SBCalc.posMin = LOWORD(l);
psbwnd->SBCalc.posMax = HIWORD(l);
psbwnd->fVert = ((LOBYTE(psbwnd->wnd.style) & SBS_VERT) != 0);
psbwnd->SBCalc.page = 0;
}
if (psbwnd->wnd.style & WS_DISABLED)
psbwnd->wDisableFlags = SB_DISABLE_MASK;
if (style & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) {
if (fSize) {
if (style & SBS_SIZEBOXBOTTOMRIGHTALIGN) {
rc.left = rc.right - SYSMET(CXVSCROLL);
rc.top = rc.bottom - SYSMET(CYHSCROLL);
}
rc.right = rc.left + SYSMET(CXVSCROLL);
rc.bottom = rc.top + SYSMET(CYHSCROLL);
} else {
if (style & SBS_VERT) {
if (style & SBS_LEFTALIGN)
rc.right = rc.left + SYSMET(CXVSCROLL);
else
rc.left = rc.right - SYSMET(CXVSCROLL);
} else {
if (style & SBS_TOPALIGN)
rc.bottom = rc.top + SYSMET(CYHSCROLL);
else
rc.top = rc.bottom - SYSMET(CYHSCROLL);
}
}
xxxMoveWindow((PWND)psbwnd, rc.left, rc.top, rc.right - rc.left,
rc.bottom - rc.top, FALSE);
}
} /* if */
else {
RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING,
"xxxSBWndProc - NULL lParam for WM_CREATE\n") ;
} /* else */
break;
case WM_SIZE:
if (PtiCurrent()->pq->spwndFocus != (PWND)psbwnd)
break;
// scroll bar has the focus -- recalc it's thumb caret size
// no need to DeferWinEventNotify() - see xxxCreateCaret below.
zzzDestroyCaret();
// | |
// | FALL THRU |
// V V
case WM_SETFOCUS:
SBCtlSetup(psbwnd);
cx = (psbwnd->fVert ? psbwnd->wnd.rcWindow.right - psbwnd->wnd.rcWindow.left
: psbwnd->SBCalc.cpxThumb) - 2 * SYSMET(CXEDGE);
cy = (psbwnd->fVert ? psbwnd->SBCalc.cpxThumb
: psbwnd->wnd.rcWindow.bottom - psbwnd->wnd.rcWindow.top) - 2 * SYSMET(CYEDGE);
xxxCreateCaret((PWND)psbwnd, (HBITMAP)1, cx, cy);
zzzSetSBCaretPos(psbwnd);
zzzShowCaret((PWND)psbwnd);
break;
case WM_KILLFOCUS:
zzzDestroyCaret();
break;
case WM_ERASEBKGND:
/*
* Do nothing, but don't let DefWndProc() do it either.
* It will be erased when its painted.
*/
return (LONG)TRUE;
case WM_PRINTCLIENT:
case WM_PAINT:
if ((hdc = (HDC)wParam) == NULL) {
hdc = xxxBeginPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
}
if (!fSize) {
SBCtlSetup(psbwnd);
xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags);
} else {
fSizeReal = TestWF((PWND)psbwnd, WFSIZEBOX);
if (!fSizeReal)
SetWF((PWND)psbwnd, WFSIZEBOX);
DrawSize((PWND)psbwnd, hdc, 0, 0);
if (!fSizeReal)
ClrWF((PWND)psbwnd, WFSIZEBOX);
}
if (wParam == 0L)
xxxEndPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps);
break;
case WM_GETDLGCODE:
return DLGC_WANTARROWS;
case WM_CONTEXTMENU:
ThreadLock(psbwnd->wnd.spwndParent, &tlpwndParent);
xxxDoScrollMenu(psbwnd->wnd.spwndParent, (PWND)psbwnd, psbwnd->fVert, lParam);
ThreadUnlock(&tlpwndParent);
break;
case WM_NCHITTEST:
if (style & SBS_SIZEGRIP) {
/*
* If the scroll bar is RTL mirrored, then
* mirror the hittest of the grip location.
*/
if (TestWF((PWND)psbwnd, WEFLAYOUTRTL)) {
return HTBOTTOMLEFT;
} else {
return HTBOTTOMRIGHT;
}
} else {
goto DoDefault;
}
break;
#ifdef COLOR_HOTTRACKING
case WM_MOUSELEAVE:
xxxHotTrackSBCtl(psbwnd, 0, FALSE);
psbwnd->ht = 0;
break;
case WM_MOUSEMOVE:
{
int ht;
if (psbwnd->ht == 0) {
TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, HWq(psbwnd), 0};
TrackMouseEvent(&tme);
}
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
ht = HitTestScrollBar((PWND)psbwnd, psbwnd->fVert, pt);
if (psbwnd->ht != ht) {
xxxHotTrackSBCtl(psbwnd, ht, TRUE);
psbwnd->ht = ht;
}
}
break;
#endif // COLOR_HOTTRACKING
case WM_LBUTTONDBLCLK:
cmd = SC_ZOOM;
if (fSize)
goto postmsg;
/*
*** FALL THRU **
*/
case WM_LBUTTONDOWN:
//
// Note that SBS_SIZEGRIP guys normally won't ever see button
// downs. This is because they return HTBOTTOMRIGHT to
// WindowHitTest handling. This will walk up the parent chain
// to the first sizeable ancestor, bailing out at caption windows
// of course. That dude, if he exists, will handle the sizing
// instead.
//
if (!fSize) {
if (TestWF((PWND)psbwnd, WFTABSTOP)) {
xxxSetFocus((PWND)psbwnd);
}
zzzHideCaret((PWND)psbwnd);
SBCtlSetup(psbwnd);
/*
* SBCtlSetup enters SEM_SB, and xxxSBTrackInit leaves it.
*/
xxxSBTrackInit((PWND)psbwnd, lParam, 0, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL);
break;
} else {
cmd = SC_SIZE;
postmsg:
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
_ClientToScreen((PWND)psbwnd, &pt);
lParam = MAKELONG(pt.x, pt.y);
/*
* convert HT value into a move value. This is bad,
* but this is purely temporary.
*/
if (TestWF(((PWND)psbwnd)->spwndParent,WEFLAYOUTRTL)) {
uSide = HTBOTTOMLEFT;
} else {
uSide = HTBOTTOMRIGHT;
}
ThreadLock(((PWND)psbwnd)->spwndParent, &tlpwndParent);
xxxSendMessage(((PWND)psbwnd)->spwndParent, WM_SYSCOMMAND,
(cmd | (uSide - HTSIZEFIRST + 1)), lParam);
ThreadUnlock(&tlpwndParent);
}
break;
case WM_KEYUP:
switch (wParam) {
case VK_HOME:
case VK_END:
case VK_PRIOR:
case VK_NEXT:
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN:
/*
* Send end scroll message when user up clicks on keyboard
* scrolling.
*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent,
SB_ENDSCROLL, 0, psbwnd->fVert
);
break;
default:
break;
}
break;
case WM_KEYDOWN:
switch (wParam) {
case VK_HOME:
wParam = SB_TOP;
goto KeyScroll;
case VK_END:
wParam = SB_BOTTOM;
goto KeyScroll;
case VK_PRIOR:
wParam = SB_PAGEUP;
goto KeyScroll;
case VK_NEXT:
wParam = SB_PAGEDOWN;
goto KeyScroll;
case VK_LEFT:
case VK_UP:
wParam = SB_LINEUP;
goto KeyScroll;
case VK_RIGHT:
case VK_DOWN:
wParam = SB_LINEDOWN;
KeyScroll:
/*
* DoScroll does thread locking on these two pwnds -
* this is ok since they are not used after this
* call.
*/
xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent, (int)wParam,
0, psbwnd->fVert
);
break;
default:
break;
}
break;
case WM_ENABLE:
return xxxSendMessage((PWND)psbwnd, SBM_ENABLE_ARROWS,
(wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
case SBM_ENABLE_ARROWS:
/*
* This is used to enable/disable the arrows in a SB ctrl
*/
return (LONG)xxxEnableSBCtlArrows((PWND)psbwnd, (UINT)wParam);
case SBM_GETPOS:
return (LONG)psbwnd->SBCalc.pos;
case SBM_GETRANGE:
*((LPINT)wParam) = psbwnd->SBCalc.posMin;
*((LPINT)lParam) = psbwnd->SBCalc.posMax;
return MAKELRESULT(LOWORD(psbwnd->SBCalc.posMin), LOWORD(psbwnd->SBCalc.posMax));
case SBM_GETSCROLLINFO:
return (LONG)_SBGetParms((PWND)psbwnd, SB_CTL, (PSBDATA)&psbwnd->SBCalc, (LPSCROLLINFO) lParam);
case SBM_SETRANGEREDRAW:
fRedraw = TRUE;
case SBM_SETRANGE:
// Save the old values of Min and Max for return value
si.cbSize = sizeof(si);
// si.nMin = LOWORD(lParam);
// si.nMax = HIWORD(lParam);
si.nMin = (int)wParam;
si.nMax = (int)lParam;
si.fMask = SIF_RANGE | SIF_RETURNOLDPOS;
goto SetInfo;
case SBM_SETPOS:
fRedraw = (BOOL) lParam;
si.cbSize = sizeof(si);
si.fMask = SIF_POS | SIF_RETURNOLDPOS;
si.nPos = (int)wParam;
goto SetInfo;
case SBM_SETSCROLLINFO:
lpsi = (LPSCROLLINFO) lParam;
fRedraw = (BOOL) wParam;
SetInfo:
fScroll = TRUE;
if (SBSetParms((PSBDATA)&psbwnd->SBCalc, lpsi, &fScroll, &lres)) {
xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, (PWND)psbwnd, OBJID_CLIENT,
INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD);
}
if (!fRedraw)
return lres;
/*
* We must set the new position of the caret irrespective of
* whether the window is visible or not;
* Still, this will work only if the app has done a xxxSetScrollPos
* with fRedraw = TRUE;
* Fix for Bug #5188 --SANKAR-- 10-15-89
* No need to DeferWinEventNotify since psbwnd is locked.
*/
zzzHideCaret((PWND)psbwnd);
SBCtlSetup(psbwnd);
zzzSetSBCaretPos(psbwnd);
/*
** The following zzzShowCaret() must be done after the DrawThumb2(),
** otherwise this caret will be erased by DrawThumb2() resulting
** in this bug:
** Fix for Bug #9263 --SANKAR-- 02-09-90
*
*/
/*
*********** zzzShowCaret((PWND)psbwnd); ******
*/
if (_FChildVisible((PWND)psbwnd) && fRedraw) {
UINT wDisable;
HBRUSH hbrUse;
if (!fScroll)
fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH;
xxxEnableScrollBar((PWND) psbwnd, SB_CTL, wDisable);
hdc = _GetWindowDC((PWND)psbwnd);
hbrSave = GreSelectBrush(hdc, hbrUse = xxxGetColorObjects((PWND)psbwnd, hdc));
/*
* Before we used to only hideshowthumb() if the mesage was
* not SBM_SETPOS. I am not sure why but this case was ever
* needed for win 3.x but on NT it resulted in trashing the border
* of the scrollbar when the app called SetScrollPos() during
* scrollbar tracking. - mikehar 8/26
*/
DrawThumb2((PWND)psbwnd, &psbwnd->SBCalc, hdc, hbrUse, psbwnd->fVert,
psbwnd->wDisableFlags);
GreSelectBrush(hdc, hbrSave);
_ReleaseDC(hdc);
}
/*
* This zzzShowCaret() has been moved to this place from above
* Fix for Bug #9263 --SANKAR-- 02-09-90
*/
zzzShowCaret((PWND)psbwnd);
return lres;
case SBM_GETSCROLLBARINFO:
return (LONG)xxxGetScrollBarInfo((PWND)psbwnd, OBJID_CLIENT, (PSCROLLBARINFO)lParam);
default:
DoDefault:
return xxxDefWindowProc((PWND)psbwnd, message, wParam, lParam);
}
return 0L;
}