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 }

Generated on Sat May 15 19:41:43 2004 for test by doxygen 1.3.7