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

scrollw.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: scrollw.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Window and DC scrolling routines. 00007 * 00008 * History: 00009 * 18-Jul-1991 DarrinM Recreated from Win 3.1 source. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 /* 00016 * Problems so far: 00017 * DCs not at origin (0, 0) 00018 * funny coordinate systems 00019 */ 00020 00021 /***************************************************************************\ 00022 * GetTrueClipRgn 00023 * 00024 * Get copy of true clip region and its bounds. 00025 * 00026 * History: 00027 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00028 \***************************************************************************/ 00029 00030 int GetTrueClipRgn( 00031 HDC hdc, 00032 HRGN hrgnClip) 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 } 00056 00057 /***************************************************************************\ 00058 * InternalScrollDC 00059 * 00060 * This function requires all input parameters in device coordinates 00061 * (NOT screen!) 00062 * 00063 * History: 00064 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00065 \***************************************************************************/ 00066 00067 int InternalScrollDC( 00068 HDC hdc, 00069 int dx, 00070 int dy, 00071 RECT *prcSrc, 00072 RECT *prcClip, 00073 HRGN hrgnInvalid, 00074 HRGN hrgnUpdate, 00075 LPRECT prcUpdate, 00076 BOOL fLogUnits) 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 } 00644 00645 /***************************************************************************\ 00646 * _ScrollDC (API) 00647 * 00648 * 00649 * History: 00650 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00651 \***************************************************************************/ 00652 00653 BOOL _ScrollDC( 00654 HDC hdc, 00655 int dx, 00656 int dy, 00657 LPRECT prcSrc, 00658 LPRECT prcClip, 00659 HRGN hrgnUpdate, 00660 LPRECT prcUpdate) 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 } 00733 00734 /***************************************************************************\ 00735 * ScrollWindowEx (API) 00736 * 00737 * 00738 * History: 00739 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00740 \***************************************************************************/ 00741 int xxxScrollWindowEx( 00742 PWND pwnd, 00743 int dx, 00744 int dy, 00745 RECT *prcScroll, 00746 RECT *prcClip, 00747 HRGN hrgnUpdate, 00748 LPRECT prcUpdate, 00749 DWORD flags) 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 } 01185

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