test: scrollw.c File Reference

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 }