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

scrollw.c File Reference

#include "precomp.h"

Go to the source code of this file.

Functions

int GetTrueClipRgn (HDC hdc, HRGN hrgnClip)
int InternalScrollDC (HDC hdc, int dx, int dy, RECT *prcSrc, RECT *prcClip, HRGN hrgnInvalid, HRGN hrgnUpdate, LPRECT prcUpdate, BOOL fLogUnits)
BOOL _ScrollDC (HDC hdc, int dx, int dy, LPRECT prcSrc, LPRECT prcClip, HRGN hrgnUpdate, LPRECT prcUpdate)
int xxxScrollWindowEx (PWND pwnd, int dx, int dy, RECT *prcScroll, RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, DWORD flags)


Function Documentation

BOOL _ScrollDC HDC  hdc,
int  dx,
int  dy,
LPRECT  prcSrc,
LPRECT  prcClip,
HRGN  hrgnUpdate,
LPRECT  prcUpdate
 

Definition at line 653 of file scrollw.c.

References AnySpbs, BOOL, FastWindowFromDC(), HRGN_FULL, tagWND::hrgnUpdate, InternalScrollDC(), NULL, OffsetRect(), tagWND::rcClient, SpbCheckRect(), TRUE, and UnionRect().

Referenced by NtUserScrollDC(), and xxxPaintIconsInSwitchWindow().

00661 { 00662 RECT rcSrc; 00663 RECT rcSpb; 00664 PWND pwnd; 00665 HRGN hrgnInvalid; 00666 BOOL fRet; 00667 00668 /* 00669 * ScrollDC does not scroll update region. Under WinNT, an app calling 00670 * GetUpdateRgn() then ScrollDC() then InvalidateRgn() will not get 00671 * any new update region that happened between the Get and Scroll. Under 00672 * Win3.1, that was not a problem because no other app ran during this 00673 * time. So pass hrgnInvalid - this will affect the hrgnUpdate and 00674 * prcUpdate values being returned from ScrollDC with the update region. 00675 */ 00676 hrgnInvalid = NULL; 00677 if ((pwnd = FastWindowFromDC(hdc)) != NULL) { 00678 00679 hrgnInvalid = pwnd->hrgnUpdate; 00680 00681 if (hrgnInvalid == HRGN_FULL) { 00682 00683 /* 00684 * This is a fix for winhell, a performance testing app 00685 * written by some guy working for a windows magazine. 00686 * this app scrolls it's window while it is completely 00687 * invalid. We normaly won't scroll invalid bits but 00688 * but we make the exception here 00689 */ 00690 hrgnInvalid = NULL; 00691 } 00692 } 00693 00694 fRet = InternalScrollDC(hdc, 00695 dx, 00696 dy, 00697 prcSrc, 00698 prcClip, 00699 hrgnInvalid, 00700 hrgnUpdate, 00701 prcUpdate, 00702 TRUE) != ERROR; 00703 00704 /* 00705 * InternalScrollDC() only scrolls those areas inside the visible region. 00706 * This means it does no operations on parts of the window if the window 00707 * isn't visible. This means SPBs don't get properly invalidated. This 00708 * could be seen by starting a dir, then moving another window with the 00709 * mouse (and keeping the mouse down until the dir finished). The 00710 * screen is remembered with an SPB, and the dir window doesn't get 00711 * properly invalidated because of this. 00712 */ 00713 if (pwnd != NULL && AnySpbs()) { 00714 00715 if (prcSrc) { 00716 00717 rcSrc = *prcSrc; 00718 OffsetRect(&rcSrc, pwnd->rcClient.left, pwnd->rcClient.top); 00719 00720 rcSpb = rcSrc; 00721 OffsetRect(&rcSpb, dx, dy); 00722 UnionRect(&rcSpb, &rcSpb, &rcSrc); 00723 00724 } else { 00725 rcSpb = pwnd->rcClient; 00726 } 00727 00728 SpbCheckRect(pwnd, &rcSpb, 0); 00729 } 00730 00731 return fRet; 00732 }

int GetTrueClipRgn HDC  hdc,
HRGN  hrgnClip
 

Definition at line 30 of file scrollw.c.

References ghrgnScrl2, and IntersectRgn.

Referenced by InternalScrollDC().

00033 { 00034 POINT pt; 00035 int code; 00036 00037 code = GreCopyVisRgn(hdc, hrgnClip); 00038 00039 /* 00040 * NOTE!!! The global ghrgnScrl2 is used in this routine! 00041 */ 00042 GreGetDCOrg(hdc, &pt); 00043 00044 if (GreGetRandomRgn(hdc, ghrgnScrl2, 1)) { 00045 GreOffsetRgn(ghrgnScrl2, pt.x, pt.y); 00046 code = IntersectRgn(hrgnClip, hrgnClip, ghrgnScrl2); 00047 } 00048 00049 /* 00050 * Finally convert the result to DC coordinates 00051 */ 00052 GreOffsetRgn(hrgnClip, -pt.x, -pt.y); 00053 00054 return code; 00055 }

int InternalScrollDC HDC  hdc,
int  dx,
int  dy,
RECT *  prcSrc,
RECT *  prcClip,
HRGN  hrgnInvalid,
HRGN  hrgnUpdate,
LPRECT  prcUpdate,
BOOL  fLogUnits
 

Definition at line 67 of file scrollw.c.

References BOOL, CopyRect, CopyRgn, CreateEmptyRgn(), EqualRect, ErrorExit(), FALSE, GetDCOrgOnScreen(), GetTrueClipRgn(), ghrgnScrl1, ghrgnScrl2, ghrgnScrlDst, ghrgnScrlSrc, ghrgnScrlValid, ghrgnScrlVis, gpDispInfo, tagDISPLAYINFO::hDev, HRGN_FULL, IntersectRect(), IntersectRgn, NULL, SetEmptyRgn(), SetRectEmpty, SetRectRgnIndirect(), SubtractRect(), SubtractRgn, TRUE, UnionRect(), and UnionRgn.

Referenced by _ScrollDC(), and xxxScrollWindowEx().

00077 { 00078 RECT rcVis; 00079 RECT rcSrc; 00080 RECT rcClip; 00081 RECT rcUnclippedSrc; 00082 RECT rcDst; 00083 RECT rcUpdate; 00084 RECT rcValid; 00085 BOOL fSrcNotEmpty; 00086 BOOL fHaveVisRgn; 00087 POINT rgpt[2]; 00088 int dxLog; 00089 int dyLog; 00090 int wClip; 00091 int wClipValid; 00092 #if defined(USE_MIRRORING) 00093 BOOL bMirroredDC=FALSE; 00094 #endif 00095 00096 fHaveVisRgn = FALSE; 00097 00098 /* 00099 * Enter a critical region to ensure that no one changes visrgns 00100 * or update regions while we scroll bits around. 00101 */ 00102 GreLockDisplay(gpDispInfo->hDev); 00103 00104 if ((wClip = GreGetClipBox(hdc, &rcVis, TRUE)) == ERROR) { 00105 00106 ErrorExit: 00107 00108 GreUnlockDisplay(gpDispInfo->hDev); 00109 return ERROR; 00110 } 00111 00112 CopyRect(&rcSrc, (prcSrc) ? prcSrc : &rcVis); 00113 if (prcClip) { 00114 CopyRect(&rcClip, prcClip); 00115 } 00116 00117 dxLog = dx; 00118 dyLog = dy; 00119 00120 if (fLogUnits) { 00121 00122 /* 00123 * Convert input parameters to device coordinates 00124 */ 00125 GreLPtoDP(hdc, (LPPOINT)&rcVis, 2); 00126 GreLPtoDP(hdc, (LPPOINT)&rcSrc, 2); 00127 00128 #if defined(USE_MIRRORING) 00129 // 00130 // Since this is a mirrored DC, then the resulting 00131 // device coord will be flowing from right to left 00132 // (i.e. rc.right < rc.left) so they should be flipped. 00133 // [samera] 00134 // 00135 if (GreGetLayout(hdc) & LAYOUT_RTL) { 00136 int iTemp = rcVis.left; 00137 rcVis.left = rcVis.right; 00138 rcVis.right = iTemp; 00139 00140 iTemp = rcSrc.left; 00141 rcSrc.left = rcSrc.right; 00142 rcSrc.right = iTemp; 00143 00144 bMirroredDC = TRUE; 00145 } 00146 #endif 00147 00148 if (prcClip) { 00149 GreLPtoDP(hdc, (LPPOINT)&rcClip, 2); 00150 00151 #if defined(USE_MIRRORING) 00152 // 00153 // Since this is a mirrored DC, then the resulting 00154 // device coord will be flowing from right to left 00155 // (i.e. rc.right < rc.left) so they should be flipped. 00156 // [samera] 00157 // 00158 if (bMirroredDC) { 00159 int iTemp = rcClip.left; 00160 rcClip.left = rcClip.right; 00161 rcClip.right = iTemp; 00162 } 00163 #endif 00164 } 00165 00166 /* 00167 * The delta values must be treated as a vector from 00168 * the point (0, 0) to (dx, dy). Scale it as such, then 00169 * compute the difference. This handles flipped coordinate systems. 00170 */ 00171 rgpt[0].x = rgpt[0].y = 0; 00172 rgpt[1].x = dx; 00173 rgpt[1].y = dy; 00174 00175 GreLPtoDP(hdc, rgpt, 2); 00176 00177 dx = rgpt[1].x - rgpt[0].x; 00178 dy = rgpt[1].y - rgpt[0].y; 00179 } 00180 00181 switch (wClip) { 00182 case NULLREGION: 00183 00184 NullExit: 00185 00186 if (hrgnUpdate && !SetEmptyRgn(hrgnUpdate)) 00187 goto ErrorExit; 00188 00189 if (prcUpdate) { 00190 SetRectEmpty(prcUpdate); 00191 } 00192 00193 GreUnlockDisplay(gpDispInfo->hDev); 00194 return NULLREGION; 00195 00196 case COMPLEXREGION: 00197 GetTrueClipRgn(hdc, ghrgnScrlVis); 00198 fHaveVisRgn = TRUE; 00199 break; 00200 } 00201 00202 /* 00203 * First compute the source and destination rectangles. 00204 * 00205 * rcDst = Offset(rcSrc, dx, dy) 00206 */ 00207 rcDst.left = rcSrc.left + dx; 00208 rcDst.right = rcSrc.right + dx; 00209 rcDst.top = rcSrc.top + dy; 00210 rcDst.bottom = rcSrc.bottom + dy; 00211 00212 /* 00213 * If necessary, intersect with caller-supplied clip rect. 00214 */ 00215 if (prcClip) { 00216 00217 if ((wClip == SIMPLEREGION) && 00218 ((hrgnInvalid == NULL) || (hrgnInvalid == HRGN_FULL))) { 00219 00220 /* 00221 * Simple clip region: just a rect intersection 00222 */ 00223 if (!IntersectRect(&rcVis, &rcVis, &rcClip)) 00224 goto NullExit; 00225 00226 } else { 00227 00228 if (!fHaveVisRgn) { 00229 00230 if (GetTrueClipRgn(hdc, ghrgnScrlVis) == ERROR) 00231 goto ErrorExit; 00232 00233 fHaveVisRgn = TRUE; 00234 } 00235 00236 SetRectRgnIndirect(ghrgnScrl1, &rcClip); 00237 wClip = IntersectRgn(ghrgnScrlVis, ghrgnScrl1, ghrgnScrlVis); 00238 switch (wClip) { 00239 case ERROR: 00240 goto ErrorExit; 00241 00242 case NULLREGION: 00243 goto NullExit; 00244 00245 case SIMPLEREGION: 00246 00247 /* 00248 * If the clipped region is simple, we're back in fat 00249 * rect city. 00250 */ 00251 GreGetRgnBox(ghrgnScrlVis, &rcVis); 00252 break; 00253 00254 case COMPLEXREGION: 00255 break; 00256 } 00257 } 00258 } 00259 00260 /* 00261 * Time for basic scrolling area calculations: 00262 * 00263 * Dst = Offset(Src, dx, dy) & Vis 00264 * Src = Src & Vis 00265 * Valid = Offset(Src, dx, dy) & Dst 00266 * Valid = Valid & Invalid & Offset(Invalid, dx, dy) 00267 * Update = (Src | Dst) - Valid 00268 * 00269 * If the vis region is simple, then we know that the valid region 00270 * will be rectangular. 00271 * 00272 * The rectangular calculation case can only deal with 00273 * ghrgnInvalid == NULL or (HRGN)1: the region case is handled the hard way. 00274 */ 00275 if ((wClip == SIMPLEREGION) && 00276 ((hrgnInvalid == NULL) || (hrgnInvalid == HRGN_FULL))) { 00277 00278 /* 00279 * Save a copy of this for update rect calc optimization. 00280 */ 00281 CopyRect(&rcUnclippedSrc, &rcSrc); 00282 00283 /* 00284 * Dst = Offset(Src, dx, dy) & Vis. 00285 */ 00286 IntersectRect(&rcDst, &rcDst, &rcVis); 00287 00288 /* 00289 * Src = Src & Vis. 00290 */ 00291 fSrcNotEmpty = IntersectRect(&rcSrc, &rcSrc, &rcVis); 00292 00293 /* 00294 * Valid = Offset(Src, dx, dy) & Dst. 00295 */ 00296 if (hrgnInvalid == HRGN_FULL) { 00297 SetRectEmpty(&rcValid); 00298 } else { 00299 00300 rcValid.left = rcSrc.left + dx; 00301 rcValid.right = rcSrc.right + dx; 00302 rcValid.top = rcSrc.top + dy; 00303 rcValid.bottom = rcSrc.bottom + dy; 00304 00305 IntersectRect(&rcValid, &rcValid, &rcDst); 00306 } 00307 00308 /* 00309 * Now calculate the update area. 00310 * 00311 * There are two cases where the result will be a rectangle: 00312 * 00313 * 1) The source rectangle lies completely within the visrgn, 00314 * and the source and destination don't overlap. In this 00315 * case the update region is equal to the source rect. 00316 * 00317 * 2) The clipped source rectangle is empty, in which case 00318 * the update region is equal to the clipped dest rect. 00319 * 00320 * 3) We're scrolling in one dimension only, and the source 00321 * and destination DO overlap. In this case we can use 00322 * UnionRect() and SubtractRect() to do the area arithmetic. 00323 */ 00324 if (!fSrcNotEmpty) { 00325 00326 /* 00327 * Clipped source is empty. Update area is the clipped dest. 00328 */ 00329 CopyRect(&rcUpdate, &rcDst); 00330 goto RectUpdate; 00331 00332 } else if (IntersectRect(&rcUpdate, &rcSrc, &rcDst)) { 00333 00334 /* 00335 * They overlap. If we're scrolling in one dimension only 00336 * then we can use rect arithmetic... 00337 */ 00338 if (dx == 0 || dy == 0) { 00339 00340 UnionRect(&rcUpdate, &rcSrc, &rcDst); 00341 SubtractRect(&rcUpdate, &rcUpdate, &rcValid); 00342 goto RectUpdate; 00343 } 00344 00345 } else if (EqualRect(&rcSrc, &rcUnclippedSrc)) { 00346 00347 /* 00348 * They don't overlap, and the source lies completely 00349 * within the visible region. Update region is the source. 00350 */ 00351 CopyRect(&rcUpdate, &rcSrc); 00352 RectUpdate: 00353 if (prcUpdate) { 00354 CopyRect(prcUpdate, &rcUpdate); 00355 } 00356 00357 if (hrgnUpdate && !SetRectRgnIndirect(hrgnUpdate, &rcUpdate)) { 00358 goto ErrorExit; 00359 } 00360 00361 wClip = SIMPLEREGION; 00362 if (rcUpdate.left >= rcUpdate.right || 00363 rcUpdate.top >= rcUpdate.bottom) 00364 00365 wClip = NULLREGION; 00366 00367 goto DoRectBlt; 00368 } 00369 00370 /* 00371 * The update region isn't rectangular. Need to do our 00372 * area calculations with region calls. Skip all this 00373 * if the caller doesn't care about the update region. 00374 * 00375 * If he wants a rectangle but no region, use ghrgnScrl2 as a temp. 00376 */ 00377 if (hrgnUpdate == NULL && prcUpdate) { 00378 hrgnUpdate = ghrgnScrl2; 00379 } 00380 00381 if (hrgnUpdate != NULL) { 00382 00383 /* 00384 * hrgnUpdateCalc = (rcSrc | rcDst) - rcBltDst 00385 */ 00386 SetRectRgnIndirect(ghrgnScrl1, &rcSrc); 00387 SetRectRgnIndirect(hrgnUpdate, &rcDst); 00388 if (UnionRgn(hrgnUpdate, hrgnUpdate, ghrgnScrl1) == ERROR) 00389 goto ErrorExit; 00390 00391 SetRectRgnIndirect(ghrgnScrl1, &rcValid); 00392 wClip = SubtractRgn(hrgnUpdate, hrgnUpdate, ghrgnScrl1); 00393 if (wClip == ERROR) 00394 goto ErrorExit; 00395 00396 if (prcUpdate) { 00397 GreGetRgnBox(hrgnUpdate, prcUpdate); 00398 } 00399 } 00400 00401 DoRectBlt: 00402 00403 /* 00404 * If the valid rectangle's not empty, then copy those bits... 00405 */ 00406 if (rcValid.left < rcValid.right && rcValid.top < rcValid.bottom) { 00407 00408 /* 00409 * If the DC is in a funny map mode, then be sure to map from 00410 * device to logical coordinates for BLT call... 00411 */ 00412 if (fLogUnits) 00413 GreDPtoLP(hdc, (LPPOINT)&rcValid, 2); 00414 00415 GreBitBlt(hdc, 00416 rcValid.left, 00417 rcValid.top, 00418 rcValid.right - rcValid.left, 00419 rcValid.bottom - rcValid.top, 00420 hdc, 00421 rcValid.left - dxLog, 00422 rcValid.top - dyLog, 00423 SRCCOPY, 00424 0); 00425 } 00426 00427 } else { 00428 00429 /* 00430 * Get the true visrgn if we haven't already. 00431 */ 00432 if (!fHaveVisRgn) { 00433 00434 if (GetTrueClipRgn(hdc, ghrgnScrlVis) == ERROR) 00435 goto ErrorExit; 00436 00437 fHaveVisRgn = TRUE; 00438 } 00439 00440 /* 00441 * The visrgn is not empty. Need to do all our calculations 00442 * with regions. 00443 * 00444 * hrgnSrc = hrgnSrc & ghrgnScrlVis 00445 */ 00446 SetRectRgnIndirect(ghrgnScrlSrc, &rcSrc); 00447 if (IntersectRgn(ghrgnScrlSrc, ghrgnScrlSrc, ghrgnScrlVis) == ERROR) 00448 goto ErrorExit; 00449 00450 /* 00451 * hrgnDst = hrgnDst & ghrgnScrlVis 00452 */ 00453 SetRectRgnIndirect(ghrgnScrlDst, &rcDst); 00454 if (IntersectRgn(ghrgnScrlDst, ghrgnScrlDst, ghrgnScrlVis) == ERROR) 00455 goto ErrorExit; 00456 00457 /* 00458 * Now compute the valid region: 00459 * 00460 * Valid = Offset(Src, dx, dy) & Dst. 00461 * Valid = Valid & Invalid & Offset(Invalid, dx, dy) 00462 * 00463 * If hrgnInvalid is (HRGN)1, then the valid area is empty. 00464 */ 00465 wClipValid = NULLREGION; 00466 if (hrgnInvalid != HRGN_FULL) { 00467 00468 /* 00469 * Valid = Offset(Src, dx, dy) & Dst 00470 */ 00471 if (CopyRgn(ghrgnScrlValid, ghrgnScrlSrc) == ERROR) 00472 goto ErrorExit; 00473 00474 GreOffsetRgn(ghrgnScrlValid, dx, dy); 00475 wClipValid = IntersectRgn(ghrgnScrlValid, 00476 ghrgnScrlValid, 00477 ghrgnScrlDst); 00478 00479 /* 00480 * Valid = Valid - Invalid - Offset(Invalid, dx, dy) 00481 * We need bother only if hrgnInvalid is a real region. 00482 */ 00483 if (hrgnInvalid > HRGN_FULL) { 00484 00485 if (wClipValid != ERROR && wClipValid != NULLREGION) { 00486 POINT pt; 00487 00488 GetDCOrgOnScreen(hdc, &pt); 00489 00490 /* 00491 * hrgnInvalid is in screen coordinates: map to dc coords 00492 */ 00493 CopyRgn(ghrgnScrl2, hrgnInvalid); 00494 GreOffsetRgn(ghrgnScrl2, -pt.x, -pt.y); 00495 00496 wClipValid = SubtractRgn(ghrgnScrlValid, 00497 ghrgnScrlValid, 00498 ghrgnScrl2); 00499 } 00500 00501 if (wClipValid != ERROR && wClipValid != NULLREGION) { 00502 GreOffsetRgn(ghrgnScrl2, dx, dy); 00503 00504 wClipValid = SubtractRgn(ghrgnScrlValid, 00505 ghrgnScrlValid, 00506 ghrgnScrl2); 00507 } 00508 } 00509 00510 if (wClipValid == ERROR) 00511 goto ErrorExit; 00512 } 00513 00514 /* 00515 * If he wants a rectangle but no region, use ghrgnScrl2 as a temp. 00516 */ 00517 if (hrgnUpdate == NULL && prcUpdate) { 00518 hrgnUpdate = ghrgnScrl2; 00519 } 00520 00521 if (hrgnUpdate != NULL) { 00522 00523 /* 00524 * Update = (Src | Dst) - Valid. 00525 */ 00526 wClip = UnionRgn(hrgnUpdate, ghrgnScrlDst, ghrgnScrlSrc); 00527 if (wClip == ERROR) 00528 goto ErrorExit; 00529 00530 if (wClipValid != NULLREGION) { 00531 wClip = SubtractRgn(hrgnUpdate, hrgnUpdate, ghrgnScrlValid); 00532 } 00533 00534 if (prcUpdate) { 00535 GreGetRgnBox(hrgnUpdate, prcUpdate); 00536 } 00537 } 00538 00539 if (wClipValid != NULLREGION) { 00540 00541 #ifdef LATER 00542 00543 /* 00544 * don't use the visrgn here 00545 */ 00546 HRGN hrgnSaveVis = CreateEmptyRgn(); 00547 if (hrgnSaveVis != NULL) { 00548 00549 BOOL fClipped; 00550 00551 fClipped = (GreGetRandomRgn(hdc, hrgnSaveVis, 1) == 1); 00552 GreExtSelectClipRgn(hdc, ghrgnScrlValid, RGN_COPY); 00553 00554 /* 00555 * If the DC is in a funny map mode, then be sure to 00556 * map from device to logical coordinates for BLT call... 00557 */ 00558 if (fLogUnits) 00559 GreDPtoLP(hdc, (LPPOINT)&rcDst, 2); 00560 00561 /* 00562 * Gdi can take along time to process this call if 00563 * it's a printer DC 00564 */ 00565 GreBitBlt(hdc, 00566 rcDst.left, 00567 rcDst.top, 00568 rcDst.right - rcDst.left, 00569 rcDst.bottom - rcDst.top, 00570 hdc, 00571 rcDst.left - dxLog, 00572 rcDst.top - dyLog, 00573 SRCCOPY, 00574 0); 00575 00576 GreExtSelectClipRgn(hdc, 00577 (fClipped ? hrgnSaveVis : NULL), 00578 RGN_COPY); 00579 00580 GreDeleteObject(hrgnSaveVis); 00581 } 00582 00583 #else 00584 00585 /* 00586 * Visrgn is expected in DC surface coordinates: offset 00587 * as appropriate. 00588 */ 00589 POINT pt; 00590 GreGetDCOrg(hdc, &pt); 00591 00592 GreOffsetRgn(ghrgnScrlValid, pt.x, pt.y); 00593 00594 /* 00595 * Select in the temporary vis rgn, saving the old 00596 */ 00597 00598 GreSelectVisRgn(hdc, ghrgnScrlValid, SVR_SWAP); 00599 00600 /* 00601 * If the DC is in a funny map mode, then be sure to map from 00602 * device to logical coordinates for BLT call... 00603 */ 00604 if (fLogUnits) 00605 GreDPtoLP(hdc, (LPPOINT)&rcDst, 2); 00606 00607 /* 00608 * Gdi can take along time to process this call if it's 00609 * a printer DC. 00610 */ 00611 GreBitBlt(hdc, 00612 rcDst.left, 00613 rcDst.top, 00614 rcDst.right - rcDst.left, 00615 rcDst.bottom - rcDst.top, 00616 hdc, 00617 rcDst.left - dxLog, 00618 rcDst.top - dyLog, 00619 SRCCOPY, 00620 0); 00621 00622 /* 00623 * Restore the old vis rgn, leaving ghrgnScrlValid with 00624 * a valid rgn 00625 */ 00626 GreSelectVisRgn(hdc, ghrgnScrlValid, SVR_SWAP); 00627 00628 #endif 00629 } 00630 } 00631 00632 /* 00633 * If necessary, convert the resultant update rect back 00634 * to logical coordinates. 00635 */ 00636 if (fLogUnits && prcUpdate) { 00637 GreDPtoLP(hdc, (LPPOINT)prcUpdate, 2); 00638 } 00639 00640 GreUnlockDisplay(gpDispInfo->hDev); 00641 00642 return wClip; 00643 }

int xxxScrollWindowEx PWND  pwnd,
int  dx,
int  dy,
RECT *  prcScroll,
RECT *  prcClip,
HRGN  hrgnUpdate,
LPRECT  prcUpdate,
DWORD  flags
 

Definition at line 741 of file scrollw.c.

References _GetDCEx(), _IsDescendant(), _ReleaseDC(), AnySpbs, BOOL, tagQ::caret, CFCLASSDC, CFOWNDC, CheckLock, CopyOffsetRect(), CopyRect, CopyRgn, tagCARET::cx, tagCARET::cy, DWORD, FALSE, FAR, GetDCOrgOnScreen(), GetRect(), ghrgnSW, GRECT_CLIENT, GRECT_CLIENTCOORDS, HRGN_FULL, tagWND::hrgnUpdate, IDC_CHILDRENONLY, IDC_CLIENTONLY, INT, InternalScrollDC(), IntersectRect(), IsVisible(), IsWinEventNotifyDeferredOK, NULL, OffsetChildren(), OffsetRect(), PCARET, tagDESKTOP::pDeskInfo, tagTHREADINFO::pq, PtiCurrent, PWNDDESKTOP, tagWND::rcClient, tagWND::rcWindow, tagTHREADINFO::rpdesk, SetEmptyRgn(), SetRect(), SetRectEmpty, SpbCheckRect(), tagCARET::spwnd, tagDESKTOPINFO::spwnd, tagWND::spwndChild, tagWND::spwndNext, tagWND::spwndParent, TestCF, TestWF, ThreadLockExchangeAlways(), ThreadLockNever, ThreadUnlock, TRUE, UnionRect(), WFCLIPCHILDREN, WFMINIMIZED, WFWIN31COMPAT, tagCARET::x, xxxInternalInvalidate(), xxxRedrawWindow(), xxxSendMessage(), tagCARET::y, zzzInternalHideCaret(), zzzInternalShowCaret(), and zzzInvalidateDCCache().

00750 { 00751 INT code; 00752 HDC hdc; 00753 int dxDev; 00754 int dyDev; 00755 RECT rcSrcDev; 00756 RECT rcSpb, rcSrc; 00757 DWORD flagsDCX; 00758 BOOL fHideCaret; 00759 BOOL fRcScroll = (prcScroll != NULL); 00760 BOOL fInvisible = FALSE; 00761 PCARET pcaret; 00762 POINT pt; 00763 TL tlpwndChild; 00764 HRGN hrgnInvalid; 00765 PTHREADINFO ptiCurrent = PtiCurrent(); 00766 00767 CheckLock(pwnd); 00768 UserAssert(IsWinEventNotifyDeferredOK()); 00769 00770 00771 if (pwnd == NULL) 00772 pwnd = ptiCurrent->rpdesk->pDeskInfo->spwnd; // pwndDesktop 00773 00774 #ifdef USE_MIRRORING 00775 if (TestWF(pwnd, WEFLAYOUTRTL)) { 00776 dx = -dx; 00777 00778 MirrorRegion(pwnd, hrgnUpdate, TRUE); 00779 00780 if(prcScroll) { 00781 MirrorRect(pwnd, prcScroll); 00782 } 00783 00784 if (prcClip) { 00785 MirrorRect(pwnd, prcClip); 00786 } 00787 } 00788 #endif 00789 00790 /* 00791 * If nothing's moving, nothing to do. 00792 */ 00793 if ((dx | dy) == 0 ) { 00794 00795 goto DoNothing; 00796 00797 } else if (!IsVisible(pwnd)) { 00798 00799 /* We want to offset our children if we're not minimized. IsVisible() 00800 * will return FALSE if we're minimized, invisible, or the child of 00801 * a minimized/invisible ancestore. 00802 */ 00803 if (!TestWF(pwnd, WFMINIMIZED) && 00804 (flags & SW_SCROLLCHILDREN) && 00805 !fRcScroll) { 00806 00807 fInvisible = TRUE; 00808 flags &= ~SW_INVALIDATE; 00809 } 00810 00811 DoNothing: 00812 00813 if (hrgnUpdate) { 00814 SetEmptyRgn(hrgnUpdate); 00815 } 00816 00817 if (prcUpdate) { 00818 SetRectEmpty(prcUpdate); 00819 } 00820 00821 if (!fInvisible) 00822 return NULLREGION; 00823 } 00824 00825 /* 00826 * Hide the caret. 00827 */ 00828 fHideCaret = FALSE; 00829 00830 if (!fInvisible) { 00831 pcaret = &ptiCurrent->pq->caret; 00832 if (pcaret->spwnd != NULL && _IsDescendant(pcaret->spwnd, pwnd)) { 00833 fHideCaret = TRUE; 00834 zzzInternalHideCaret(); 00835 } 00836 } 00837 00838 /* 00839 * If scrollwindow, and window is clipchildren, use a cache entry. 00840 * Otherwise, always use a 00841 * 00842 * Determine what kind of DC we'll be needing. If the DCX_CACHE bit 00843 * isn't set, it means that we'll be operating in logical coordinates. 00844 */ 00845 if (flags & SW_SCROLLWINDOW) { 00846 00847 /* 00848 * ScrollWindow() call: use the cache if not OWNDC or CLASSDC. 00849 */ 00850 flagsDCX = DCX_USESTYLE; 00851 if (!TestCF(pwnd, CFOWNDC) && !TestCF(pwnd, CFCLASSDC)) 00852 flagsDCX |= DCX_CACHE; 00853 00854 /* 00855 * If SW_SCROLLCHILDREN (i.e., lprcScroll == NULL) and CLIPCHILDREN, 00856 * then use the cache and don't clip children. 00857 * This is screwy, but 3.0 backward compatible. 00858 */ 00859 if ((flags & SW_SCROLLCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN)) 00860 flagsDCX |= DCX_NOCLIPCHILDREN | DCX_CACHE; 00861 00862 } else { 00863 00864 /* 00865 * ScrollWindowEx() call: always use the cache 00866 */ 00867 flagsDCX = DCX_USESTYLE | DCX_CACHE; 00868 00869 /* 00870 * if SW_SCROLLCHILDREN, always use noclipchildren. 00871 */ 00872 if (flags & SW_SCROLLCHILDREN) 00873 flagsDCX |= DCX_NOCLIPCHILDREN; 00874 } 00875 00876 #ifdef USE_MIRRORING 00877 flagsDCX |= DCX_NOMIRROR; 00878 #endif 00879 00880 hdc = _GetDCEx(pwnd, NULL, flagsDCX); 00881 00882 if (flags & SW_INVALIDATE) { 00883 00884 /* 00885 * Get device origin while DC is valid, for later offsetting 00886 */ 00887 GetDCOrgOnScreen(hdc, &pt); 00888 00889 /* 00890 * If the user didn't give us a region to use, use ghrgnSW. 00891 */ 00892 if (hrgnUpdate == NULL) 00893 hrgnUpdate = ghrgnSW; 00894 } 00895 00896 /* 00897 * The DC will be in some logical coordinate system if OWNDC or CLASSDC. 00898 */ 00899 if (!fRcScroll) { 00900 prcScroll = &rcSrc; 00901 00902 /* 00903 * IMPORTANT: 00904 * We have to use CopyOffsetRect() here because GetClientRect() gives 00905 * unreliable results for minimized windows. 3.1 dudes get told that 00906 * their client is non-empty, for compatibility reasons. 00907 */ 00908 GetRect(pwnd, &rcSrc, GRECT_CLIENT | GRECT_CLIENTCOORDS); 00909 00910 /* 00911 * If the DC might be a screwy one, then map the 00912 * rect to logical units. 00913 */ 00914 if (!(flagsDCX & DCX_CACHE)) 00915 GreDPtoLP(hdc, (LPPOINT)&rcSrc, 2); 00916 } 00917 00918 /* 00919 * If the DC is in logical coordinates, map *prcScroll and dx, dy 00920 * to device units for use later. 00921 */ 00922 dxDev = dx; 00923 dyDev = dy; 00924 rcSrcDev = *prcScroll; 00925 00926 if (!(flagsDCX & DCX_CACHE)) { 00927 00928 POINT rgpt[2]; 00929 00930 GreLPtoDP(hdc, (POINT FAR*)&rcSrcDev, 2); 00931 00932 /* 00933 * The delta values must be treated as a vector from 00934 * the point (0, 0) to (dx, dy). Scale it as such, then 00935 * compute the difference. This handles flipped coordinate systems. 00936 */ 00937 rgpt[0].x = rgpt[0].y = 0; 00938 rgpt[1].x = dx; 00939 rgpt[1].y = dy; 00940 00941 GreLPtoDP(hdc, rgpt, 2); 00942 00943 dxDev = rgpt[1].x - rgpt[0].x; 00944 dyDev = rgpt[1].y - rgpt[0].y; 00945 } 00946 00947 if (fInvisible) 00948 code = NULLREGION; 00949 else { 00950 hrgnInvalid = pwnd->hrgnUpdate; 00951 if ((flags & SW_SCROLLWINDOW) && !TestWF(pwnd, WFWIN31COMPAT)) { 00952 /* 00953 * 3.0 Backward compatibility hack: 00954 * The following incorrect code is what 3.0 used to do, and 00955 * there are apps such as Finale and Scrapbook+ that have worked 00956 * around this bug in ways that don't work with the "correct" code. 00957 */ 00958 if (pwnd->hrgnUpdate > HRGN_FULL) { 00959 RECT rc; 00960 00961 GreGetRgnBox(pwnd->hrgnUpdate, &rc); 00962 OffsetRect(&rc, 00963 dxDev - pwnd->rcClient.left, 00964 dyDev - pwnd->rcClient.top); 00965 00966 xxxRedrawWindow(pwnd, 00967 &rc, NULL, 00968 RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); 00969 } 00970 hrgnInvalid = NULL; 00971 } 00972 00973 code = InternalScrollDC(hdc, 00974 dx, 00975 dy, 00976 prcScroll, 00977 prcClip, 00978 hrgnInvalid, 00979 hrgnUpdate, 00980 prcUpdate, 00981 !(flagsDCX & DCX_CACHE)); 00982 #ifdef USE_MIRRORING 00983 if (prcUpdate && TestWF(pwnd, WEFLAYOUTRTL)) { 00984 MirrorRect(pwnd, prcUpdate); 00985 } 00986 #endif 00987 } 00988 00989 /* 00990 * Release the hdc we used. 00991 */ 00992 _ReleaseDC(hdc); 00993 00994 /* 00995 * Check the union of the src and dst rectangle against any SPBs. 00996 * We do this because the window 00997 * might be completely obscured by some window with an SPB, but 00998 * since we're completely covered no BitBlt call will be made 00999 * to accumulate bounds in that area. 01000 */ 01001 if (!fInvisible && AnySpbs()) { 01002 01003 if (fRcScroll) { 01004 if (pwnd == PWNDDESKTOP(pwnd)) { 01005 rcSrc = rcSrcDev; 01006 } else { 01007 CopyOffsetRect( 01008 &rcSrc, 01009 &rcSrcDev, 01010 pwnd->rcClient.left, 01011 pwnd->rcClient.top); 01012 } 01013 01014 rcSpb = rcSrc; 01015 OffsetRect(&rcSpb, dxDev, dyDev); 01016 UnionRect(&rcSpb, &rcSpb, &rcSrc); 01017 01018 } else { 01019 01020 /* 01021 * Use the entire client area. 01022 */ 01023 rcSpb = pwnd->rcClient; 01024 } 01025 01026 SpbCheckRect(pwnd, &rcSpb, 0); 01027 } 01028 01029 /* 01030 * If this guy wants to scroll his children, go at it. Only scroll those 01031 * children intersecting prcScroll. Then invalidate any vis rgns 01032 * calculated for these child windows. 01033 */ 01034 if (flags & SW_SCROLLCHILDREN) { 01035 01036 RECT rc; 01037 01038 /* 01039 * If this window has the caret then offset it if: 01040 * a) The whole window is scrolling 01041 * b) The rectangle scrolled contains the caret rectangle 01042 */ 01043 if (!fInvisible && (pwnd == pcaret->spwnd)) { 01044 01045 if (fRcScroll) 01046 SetRect(&rc, 01047 pcaret->x, 01048 pcaret->y, 01049 pcaret->x + pcaret->cx, 01050 pcaret->y + pcaret->cy); 01051 01052 if (!fRcScroll || IntersectRect(&rc, &rc, &rcSrcDev)) { 01053 pcaret->x += dxDev; 01054 pcaret->y += dyDev; 01055 } 01056 } 01057 01058 if (fRcScroll) { 01059 01060 /* 01061 * Create a copy of prcScroll and map to absolute coordinates... 01062 */ 01063 if (pwnd == PWNDDESKTOP(pwnd)) { 01064 CopyRect(&rc, &rcSrcDev); 01065 } else { 01066 CopyOffsetRect( 01067 &rc, 01068 &rcSrcDev, 01069 pwnd->rcClient.left, 01070 pwnd->rcClient.top); 01071 } 01072 } 01073 01074 if (pwnd->spwndChild) { 01075 01076 OffsetChildren(pwnd, 01077 dxDev, 01078 dyDev, 01079 (fRcScroll ? (LPRECT)&rc : NULL)); 01080 01081 /* 01082 * If we're clipchildren, then shuffling our children 01083 * will affect our client visrgn (but not our window visrgn). 01084 * Otherwise, only our children's 01085 * visrgns were affected by the scroll. 01086 * No need to DeferWinEventNotify() judging by xxxInternalInvalidate() below 01087 */ 01088 zzzInvalidateDCCache(pwnd, 01089 TestWF(pwnd, WFCLIPCHILDREN) ? 01090 IDC_CLIENTONLY : IDC_CHILDRENONLY); 01091 01092 } 01093 } 01094 01095 if (flags & SW_INVALIDATE) { 01096 01097 /* 01098 * If the caller supplied a region, invalidate using a copy, 01099 * because InternalInvalidate may trash the passed-in region. 01100 */ 01101 if (hrgnUpdate != ghrgnSW) 01102 CopyRgn(ghrgnSW, hrgnUpdate); 01103 01104 /* 01105 * Make ghrgnSW screen-relative before invalidation... 01106 */ 01107 GreOffsetRgn(ghrgnSW, pt.x, pt.y); 01108 01109 xxxInternalInvalidate( 01110 pwnd, 01111 ghrgnSW, 01112 (flags & SW_ERASE) ? 01113 (RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE) : 01114 (RDW_INVALIDATE | RDW_ALLCHILDREN)); 01115 } 01116 01117 /* 01118 * Send child move messages if needed. 01119 */ 01120 if (flags & SW_SCROLLCHILDREN) { 01121 01122 PWND pwndChild; 01123 RECT rc; 01124 RECT rcScrolledChildren; 01125 01126 /* 01127 * NOTE: the following code will send MOVE messages 01128 * to windows that didn't move but were in the source rectangle. 01129 * This is not a big deal, and definitely not worth fixing. 01130 */ 01131 if (fRcScroll) { 01132 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01133 CopyOffsetRect(&rcScrolledChildren, &rcSrcDev, dxDev, dyDev); 01134 } else { 01135 CopyOffsetRect( 01136 &rcScrolledChildren, 01137 &rcSrcDev, 01138 dxDev + pwnd->spwndParent->rcClient.left, 01139 dyDev + pwnd->spwndParent->rcClient.top); 01140 } 01141 } 01142 01143 ThreadLockNever(&tlpwndChild); 01144 pwndChild = pwnd->spwndChild; 01145 while (pwndChild != NULL) { 01146 01147 if ( !fRcScroll || 01148 IntersectRect(&rc, &rcScrolledChildren, &pwndChild->rcWindow)) { 01149 01150 /* 01151 * NOTE: Win 3.0 and below passed wParam == TRUE here. 01152 * This was not documented or used, so it was changed 01153 * to be consistent with the documentation. 01154 */ 01155 ThreadLockExchangeAlways(pwndChild, &tlpwndChild); 01156 xxxSendMessage( 01157 pwndChild, 01158 WM_MOVE, 01159 0, 01160 (pwnd == PWNDDESKTOP(pwnd)) ? 01161 MAKELONG(pwndChild->rcClient.left, pwndChild->rcClient.top) : 01162 MAKELONG(pwndChild->rcClient.left - pwnd->rcClient.left, 01163 pwndChild->rcClient.top - pwnd->rcClient.top)); 01164 } 01165 01166 pwndChild = pwndChild->spwndNext; 01167 } 01168 01169 ThreadUnlock(&tlpwndChild); 01170 } 01171 01172 if (fHideCaret) { 01173 01174 /* 01175 * Show the caret again. 01176 */ 01177 zzzInternalShowCaret(); 01178 } 01179 01180 /* 01181 * Return the region code. 01182 */ 01183 return code; 01184 }


Generated on Sat May 15 19:45:32 2004 for test by doxygen 1.3.7