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

update.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: update.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains the APIs used to invalidate, validate, and force 00007 * updating of windows. 00008 * 00009 * History: 00010 * 27-Oct-1990 DarrinM Created. 00011 * 25-Jan-1991 IanJa Revalidation added 00012 * 16-Jul-1991 DarrinM Recreated from Win 3.1 sources. 00013 \***************************************************************************/ 00014 00015 #include "precomp.h" 00016 #pragma hdrstop 00017 00018 /* 00019 * Local Constants. 00020 */ 00021 #define UW_ENUMCHILDREN 0x0001 00022 #define UW_RECURSED 0x0004 00023 00024 #define RIR_OUTSIDE 0 00025 #define RIR_INTERSECT 1 00026 #define RIR_INSIDE 2 00027 00028 #define RDW_IGNOREUPDATEDIRTY 0x8000 00029 00030 00031 /***************************************************************************\ 00032 * xxxInvalidateRect (API) 00033 * 00034 * 00035 * History: 00036 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00037 \***************************************************************************/ 00038 00039 BOOL xxxInvalidateRect( 00040 PWND pwnd, 00041 LPRECT lprcInvalid, 00042 BOOL fErase) 00043 { 00044 CheckLock(pwnd); 00045 00046 /* 00047 * BACKWARD COMPATIBILITY HACK 00048 * 00049 * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with 00050 * hwnd == NULL always INVALIDATED and ERASED the entire desktop, and 00051 * synchronously sent WM_ERASEBKGND and WM_NCPAINT messages before 00052 * returning. The Rgn() calls did not have this behavior. 00053 */ 00054 if (pwnd == NULL) { 00055 return xxxRedrawWindow( 00056 pwnd, 00057 NULL, 00058 NULL, 00059 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW); 00060 } else { 00061 return xxxRedrawWindow( 00062 pwnd, 00063 lprcInvalid, 00064 NULL, 00065 fErase ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE); 00066 } 00067 } 00068 00069 /***************************************************************************\ 00070 * xxxValidateRect (API) 00071 * 00072 * 00073 * History: 00074 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00075 \***************************************************************************/ 00076 00077 BOOL xxxValidateRect( 00078 PWND pwnd, 00079 LPRECT lprcValid) 00080 { 00081 CheckLock(pwnd); 00082 00083 /* 00084 * BACKWARD COMPATIBILITY HACK 00085 * 00086 * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with 00087 * hwnd == NULL always INVALIDATED and ERASED the entire desktop, and 00088 * synchronously sent WM_ERASEBKGND and WM_NCPAINT messages before 00089 * returning. The Rgn() calls did not have this behavior. 00090 */ 00091 if (pwnd == NULL) { 00092 return xxxRedrawWindow( 00093 pwnd, 00094 NULL, 00095 NULL, 00096 RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW); 00097 } else { 00098 return xxxRedrawWindow(pwnd, lprcValid, NULL, RDW_VALIDATE); 00099 } 00100 } 00101 00102 /***************************************************************************\ 00103 * xxxInvalidateRgn (API) 00104 * 00105 * 00106 * History: 00107 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00108 \***************************************************************************/ 00109 00110 BOOL xxxInvalidateRgn( 00111 PWND pwnd, 00112 HRGN hrgnInvalid, 00113 BOOL fErase) 00114 { 00115 CheckLock(pwnd); 00116 00117 return xxxRedrawWindow( 00118 pwnd, 00119 NULL, 00120 hrgnInvalid, 00121 fErase ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE); 00122 } 00123 00124 /***************************************************************************\ 00125 * xxxValidateRgn (API) 00126 * 00127 * 00128 * History: 00129 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00130 \***************************************************************************/ 00131 00132 BOOL xxxValidateRgn( 00133 PWND pwnd, 00134 HRGN hrgnValid) 00135 { 00136 CheckLock(pwnd); 00137 00138 return xxxRedrawWindow(pwnd, NULL, hrgnValid, RDW_VALIDATE); 00139 } 00140 00141 /***************************************************************************\ 00142 * SmartRectInRegion 00143 * 00144 * This routine is similar to RectInRegion, except that it also determines 00145 * whether or not *lprc is completely within hrgn or not. 00146 * 00147 * RIR_OUTSIDE - no intersection 00148 * RIR_INTERSECT - *lprc intersects hrgn, but not completely inside 00149 * RIR_INSIDE - *lprc is completely within hrgn. 00150 * 00151 * LATER: 00152 * It would be MUCH faster to put this functionality into GDI's RectInRegion 00153 * call (a la PM's RectInRegion) 00154 * 00155 * History: 00156 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00157 \***************************************************************************/ 00158 00159 UINT SmartRectInRegion( 00160 HRGN hrgn, 00161 LPRECT lprc) 00162 { 00163 RECT rc; 00164 00165 if (!GreRectInRegion(hrgn, lprc)) 00166 return RIR_OUTSIDE; 00167 00168 /* 00169 * Algorithm: if the intersection of hrgn and *lprc is the 00170 * same as *lprc, then *lprc is completely within hrgn. 00171 * 00172 * If the region is a rectangular one, then do it the easy way. 00173 */ 00174 if (GreGetRgnBox(hrgn, &rc) == SIMPLEREGION) { 00175 00176 if (!IntersectRect(&rc, &rc, lprc)) 00177 return RIR_OUTSIDE; 00178 00179 if (EqualRect(lprc, &rc)) 00180 return RIR_INSIDE; 00181 00182 } else { 00183 00184 SetRectRgnIndirect(ghrgnInv2, lprc); 00185 00186 switch (IntersectRgn(ghrgnInv2, ghrgnInv2, hrgn)) { 00187 00188 case SIMPLEREGION: 00189 GreGetRgnBox(ghrgnInv2, &rc); 00190 if (EqualRect(lprc, &rc)) 00191 return RIR_INSIDE; 00192 break; 00193 00194 #define RECTINREGION_BUG 00195 #ifdef RECTINREGION_BUG 00196 00197 /* 00198 * NOTE: RectInRegion has a BUG, where it sometimes returns TRUE 00199 * even if the rectangles of a region touch only on the edges 00200 * with no overlap. This will result in an empty region after 00201 * the combination above. 00202 */ 00203 case NULLREGION: 00204 return RIR_OUTSIDE; 00205 break; 00206 #endif 00207 00208 default: 00209 break; 00210 } 00211 } 00212 00213 return RIR_INTERSECT; 00214 } 00215 00216 /***************************************************************************\ 00217 * PixieHack 00218 * 00219 * BACKWARD COMPATIBILITY HACK 00220 * 00221 * In 3.0, WM_NCPAINT messages would be sent to any child window that was 00222 * inside the bounding rectangle of a window management operation involving 00223 * any other child, even if the intersection of that region with the child 00224 * is empty. 00225 * 00226 * Some apps such as Pixie 2.3 and CA Cricket Presents rely on this to ensure 00227 * that their tool windows stay on top of other child windows. When the tool 00228 * window gets a WM_NCPAINT, it brings itself to the top of the pile. 00229 * 00230 * Borland ObjectVision depends on getting the WM_NCPAINT after an 00231 * invalidation of its parent window in an area that include the non-client 00232 * area of the child. When it recieves the WM_NCPAINT, it must get a 00233 * clip region of HRGN_FULL, or nothing gets drawn. 00234 * 00235 * History: 00236 * 02-Mar-1992 MikeKe Ported from Win 3.1 sources. 00237 \***************************************************************************/ 00238 00239 VOID PixieHack( 00240 PWND pwnd, 00241 LPRECT prcBounds) 00242 { 00243 /* 00244 * If a child intersects the update region, and it isn't already 00245 * getting an NCPAINT, then make sure it gets one later. 00246 * 00247 * Don't apply this hack to top level windows. 00248 */ 00249 if ((pwnd != _GetDesktopWindow()) && 00250 TestWF(pwnd, WFCLIPCHILDREN) && 00251 !TestWF(pwnd, WFMINIMIZED)) { 00252 00253 RECT rc; 00254 00255 for (pwnd = pwnd->spwndChild; pwnd; pwnd = pwnd->spwndNext) { 00256 00257 /* 00258 * If the window isn't already getting an NCPAINT message, 00259 * and it has a caption, and it's inside the bounding rect, 00260 * make sure it gets a WM_NCPAINT with wParam == HRGN_FULL. 00261 */ 00262 if (!TestWF(pwnd, WFSENDNCPAINT) && 00263 (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION)) && 00264 IntersectRect(&rc, prcBounds, &pwnd->rcWindow)) { 00265 00266 /* 00267 * Sync paint count is incremented when 00268 * (senderasebkgnd | sendncpaint) goes from 0 to != 0. 00269 * (should make a routine out of this!) 00270 */ 00271 SetWF(pwnd, WFSENDNCPAINT); 00272 00273 /* 00274 * Force HRGN_FULL clip rgn. 00275 */ 00276 SetWF(pwnd, WFPIXIEHACK); 00277 } 00278 } 00279 } 00280 } 00281 00282 /***************************************************************************\ 00283 * xxxRedrawWindow (API) 00284 * 00285 * Forward to xxxInvalidateWindow if the window is visible. 00286 * 00287 * BACKWARD COMPATIBILITY HACK 00288 * 00289 * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with pwnd == NULL 00290 * always INVALIDATED and ERASED all windows, and synchronously sent 00291 * WM_ERASEBKGND and WM_NCPAINT messages before returning. The Rgn() calls 00292 * did not have this behavior. This case is handled in 00293 * InvalidateRect/ValidateRect. 00294 * 00295 * History: 00296 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00297 \***************************************************************************/ 00298 00299 BOOL xxxRedrawWindow( 00300 PWND pwnd, 00301 LPRECT lprcUpdate, 00302 HRGN hrgnUpdate, 00303 DWORD flags) 00304 { 00305 CheckLock(pwnd); 00306 00307 /* 00308 * Always map NULL to the desktop. 00309 */ 00310 if (pwnd == NULL) { 00311 pwnd = PtiCurrent()->rpdesk->pDeskInfo->spwnd; 00312 } 00313 00314 UserAssert(pwnd != NULL); 00315 00316 if (IsVisible(pwnd)) { 00317 00318 TL tlpwnd; 00319 HRGN hrgn = hrgnUpdate; 00320 00321 if (flags & (RDW_VALIDATE | RDW_INVALIDATE)) { 00322 00323 /* 00324 * Create a (in)validate region in client window coordinates. 00325 */ 00326 if (hrgn == NULL) { 00327 if (!lprcUpdate) { 00328 hrgn = HRGN_FULL; 00329 } else { 00330 hrgn = ghrgnInv0; 00331 00332 #ifdef USE_MIRRORING 00333 if (TestWF(pwnd, WEFLAYOUTRTL)) { 00334 MirrorRect(pwnd, lprcUpdate); 00335 } 00336 #endif 00337 00338 if (pwnd == PWNDDESKTOP(pwnd)) { 00339 SetRectRgnIndirect(hrgn, lprcUpdate); 00340 } else { 00341 GreSetRectRgn( 00342 hrgn, 00343 lprcUpdate->left + pwnd->rcClient.left, 00344 lprcUpdate->top + pwnd->rcClient.top, 00345 lprcUpdate->right + pwnd->rcClient.left, 00346 lprcUpdate->bottom + pwnd->rcClient.top); 00347 } 00348 } 00349 } else { 00350 /* 00351 * If necessary, make a copy of the passed-in region, because 00352 * we'll be trashing it... 00353 */ 00354 if (hrgn != HRGN_FULL) { 00355 CopyRgn(ghrgnInv0, hrgn); 00356 00357 #ifdef USE_MIRRORING 00358 MirrorRegion(pwnd, ghrgnInv0, TRUE); 00359 #endif 00360 00361 hrgn = ghrgnInv0; 00362 } 00363 00364 if (pwnd != PWNDDESKTOP(pwnd)) { 00365 GreOffsetRgn(hrgn, pwnd->rcClient.left, pwnd->rcClient.top); 00366 } 00367 } 00368 } 00369 00370 ThreadLock(pwnd, &tlpwnd); 00371 xxxInternalInvalidate(pwnd, hrgn, flags | RDW_REDRAWWINDOW); 00372 ThreadUnlock(&tlpwnd); 00373 } 00374 00375 return TRUE; 00376 } 00377 00378 /***************************************************************************\ 00379 * InternalInvalidate2 00380 * 00381 * (In)validates hrgn in pwnd and in child windows of pwnd. Child windows 00382 * also subtract their visible region from hrgnSubtract. 00383 * 00384 * pwnd - The window to (in)validate. 00385 * hrng - The region to (in)validate. 00386 * hrgnSubtract - The region to subtract the visible region of 00387 * child windows from. 00388 * prcParents - Contains the intersection of pwnd's client or window rect 00389 * with the client rectangles of its parents. May just be 00390 * the window's client or window rect. 00391 * 00392 * flags - RDW_ flags. 00393 * 00394 * Returns FALSE if hrgnSubtract becomes a NULLREGION, TRUE otherwise. 00395 * 00396 * History: 00397 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00398 \***************************************************************************/ 00399 00400 BOOL InternalInvalidate2( 00401 PWND pwnd, 00402 HRGN hrgn, 00403 HRGN hrgnSubtract, 00404 LPRECT prcParents, 00405 DWORD flags) 00406 { 00407 /* 00408 * NOTE: Uses ghrgnInv2 00409 */ 00410 RECT rcOurShare; 00411 DWORD flagsChildren; 00412 PWND pwndT; 00413 00414 /* 00415 * This routine is called recursively down the parent/child chain. 00416 * Remember if on the way one of the windows has a clipping region. 00417 * This info is used later on to optimize out a loop in the common 00418 * case. 00419 */ 00420 if (pwnd->hrgnClip != NULL) { 00421 flags |= RDW_HASWINDOWRGN; 00422 } 00423 00424 /* 00425 * If we recurse, make sure our children subtract themselves off. 00426 */ 00427 flagsChildren = flags | RDW_SUBTRACTSELF; 00428 CopyRect(&rcOurShare, &pwnd->rcWindow); 00429 00430 /* 00431 * If we're invalidating, we only want to deal with the part of 00432 * our window rectangle that intersects our parents. 00433 * This way, we don't end up validating or invalidating more than our 00434 * fair share. If we're completely obscured by our parents, then there is 00435 * nothing to do. 00436 * 00437 * We don't perform this intersection if we're validating, because there 00438 * are cases where a child and its update region may exist but be obscured 00439 * by parents, and we want to make sure validation will work in these 00440 * cases. ScrollWindow() can cause this when children are offset, as can 00441 * various 3.0 compatibility hacks. 00442 */ 00443 00444 if (flags & RDW_INVALIDATE) { 00445 /* 00446 * Don't subtract out any sprite windows from the invalid region. 00447 * Behave as if it's not there. However, always allow layered window 00448 * invalidation when RDW_INVALIDATELAYERS is passed in. 00449 */ 00450 if (FLayeredOrRedirected(pwnd) && !(flags & RDW_INVALIDATELAYERS)) 00451 return TRUE; 00452 00453 if (!IntersectRect(&rcOurShare, &rcOurShare, prcParents)) { 00454 00455 /* 00456 * BACKWARD COMPATIBILITY HACK: If hrgn is (HRGN)1, we need to 00457 * invalidate ALL child windows, even if they're not visible. This 00458 * is a bummer, because it'll result in all sorts of repaints that 00459 * aren't necessary. 00460 * 00461 * Various apps, including WordStar for Windows and WaveEdit, 00462 * depend on this behavior. Here's how WaveEdit relies on this: it 00463 * has a CS_HDREDRAW | CS_VREDRAW window, that moves its children 00464 * around with MoveWindow( ..., fRedraw = FALSE). The windows 00465 * not part of the new client area didn't get invalidated. 00466 */ 00467 if (!TestWF(pwnd, WFWIN31COMPAT) && (hrgn == HRGN_FULL)) { 00468 00469 /* 00470 * For purposes of hit-testing, our share is our window 00471 * rectangle. However, we don't want to diddle the region 00472 * passed to us, because by rights we're really clipped out! 00473 */ 00474 flags &= ~RDW_SUBTRACTSELF; 00475 flagsChildren &= ~RDW_SUBTRACTSELF; 00476 00477 } else { 00478 return TRUE; 00479 } 00480 } 00481 00482 /* 00483 * If our window rect doesn't intersect the valid/invalid region, 00484 * nothing further to do. 00485 */ 00486 if (hrgn > HRGN_FULL) { 00487 00488 switch (SmartRectInRegion(hrgn, &rcOurShare)) { 00489 case RIR_OUTSIDE: 00490 return TRUE; 00491 00492 case RIR_INTERSECT: 00493 00494 /* 00495 * The update region can be within the window rect but not 00496 * touch the window region; in this case we don't want this 00497 * update region to be distributed to this window. If this 00498 * is the case, return TRUE as if RIR_OUTSIDE. 00499 * 00500 * If RDW_HASWINDOWRGN is set, either this window or 00501 * one of its parents has a window clipping region. This 00502 * flag is just an optimization so that this loop isn't 00503 * executed all the time. 00504 * 00505 * A future optimization may be to calculate this parent 00506 * clipped region as part of recursion like prcParents is 00507 * calculated. It is not super important though because this 00508 * case rarely happens (a window with a region), and even 00509 * more rare, a regional window that is a child of a regional 00510 * window parent. 00511 */ 00512 if (flags & RDW_HASWINDOWRGN) { 00513 00514 /* 00515 * Clip to the window's clipping region and parents! 00516 * If we don't clip to parents, we may get a case where 00517 * a child clips out some update region that was meant to 00518 * go to a sibling of the parent. 00519 */ 00520 SetRectRgnIndirect(ghrgnInv2, &rcOurShare); 00521 for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndParent) { 00522 00523 if (pwndT->hrgnClip != NULL) { 00524 00525 /* 00526 * An error at this stage would possibly result 00527 * in more being subtracted out of the clipping 00528 * region that we'd like. 00529 */ 00530 IntersectRgn(ghrgnInv2, ghrgnInv2, pwndT->hrgnClip); 00531 } 00532 } 00533 00534 if (IntersectRgn(ghrgnInv2, ghrgnInv2, hrgn) == NULLREGION) 00535 return TRUE; 00536 } 00537 break; 00538 00539 case RIR_INSIDE: 00540 /* 00541 * If the rectangle is completely within hrgn, then we can use 00542 * HRGN_FULL, which is much faster and easier to deal with. 00543 * 00544 * COMPAT HACK: There are some apps (PP, MSDRAW) that depend 00545 * on some weirdities of the 3.0 GetUpdateRect in order to 00546 * paint properly. Since this stuff hinges on whether the 00547 * update region is 1 or a real region, we need to simulate 00548 * when 3.0 would generate a HRGN(1) update region. The 00549 * following optimization was not made in 3.0, so we yank it 00550 * in 3.1 for these apps. (win31 bugs 8235,10380) 00551 */ 00552 if (!(GetAppCompatFlags(GETPTI(pwnd)) & GACF_NOHRGN1)) 00553 hrgn = HRGN_FULL; 00554 break; 00555 } 00556 } 00557 } 00558 00559 /* 00560 * If not CLIPCHILDREN, go diddle the update region BEFORE our clipped 00561 * children have done their thing to hrgnSubtract. Otherwise, 00562 * we'll diddle after we recurse. 00563 */ 00564 if (!TestWF(pwnd, WFCLIPCHILDREN)) { 00565 InternalInvalidate3(pwnd, hrgn, flags); 00566 } 00567 00568 /* 00569 * If this is a GACF_ALWAYSSENDNCPAINT app, take care of it... 00570 */ 00571 if (TestWF(pwnd, WFALWAYSSENDNCPAINT)) 00572 PixieHack(pwnd, &rcOurShare); 00573 00574 /* 00575 * Recurse on our children if necessary. 00576 * 00577 * By default, our children are enumerated if we are not CLIPCHILDREN. 00578 * Don't bother with children if we're minimized. 00579 */ 00580 if ((pwnd->spwndChild != NULL) && 00581 !TestWF(pwnd, WFMINIMIZED) && 00582 !(flags & RDW_NOCHILDREN) && 00583 ((flags & RDW_ALLCHILDREN) || !TestWF(pwnd, WFCLIPCHILDREN))) { 00584 00585 RECT rcChildrenShare; 00586 PWND pwndChild; 00587 00588 /* 00589 * If we're invalidating, make sure our children 00590 * erase and frame themselves. Also, tell children to subtract 00591 * themselves from hrgnSubtract. 00592 */ 00593 if (flags & RDW_INVALIDATE) { 00594 flagsChildren |= RDW_ERASE | RDW_FRAME; 00595 } 00596 00597 /* 00598 * Our children are clipped to our client rect, so reflect 00599 * that in the rectangle we give them. 00600 */ 00601 if (IntersectRect(&rcChildrenShare, &rcOurShare, &pwnd->rcClient) || 00602 (!TestWF(pwnd, WFWIN31COMPAT) && (hrgn == HRGN_FULL))) { 00603 00604 for (pwndChild = pwnd->spwndChild; pwndChild != NULL; 00605 pwndChild = pwndChild->spwndNext) { 00606 00607 if (!TestWF(pwndChild, WFVISIBLE)) 00608 continue; 00609 00610 if (!InternalInvalidate2(pwndChild, 00611 hrgn, 00612 hrgnSubtract, 00613 &rcChildrenShare, 00614 flagsChildren)) { 00615 00616 /* 00617 * The children swallowed the region: 00618 * If there are no update region related things 00619 * to do then we can just return with FALSE 00620 */ 00621 if (!(flags & (RDW_INTERNALPAINT | RDW_NOINTERNALPAINT))) 00622 return FALSE; 00623 00624 /* 00625 * We have to enumerate the rest of the children because 00626 * one of the RDW_NO/INTERNALPAINT bits is set. Since 00627 * there's no longer any update region to worry about, 00628 * strip out the update region bits from the parent 00629 * and child fiags. Also, tell the children not to 00630 * bother subtracting themselves from the region. 00631 */ 00632 flags &= ~(RDW_INVALIDATE | 00633 RDW_ERASE | 00634 RDW_FRAME | 00635 RDW_VALIDATE | 00636 RDW_NOERASE | 00637 RDW_NOFRAME); 00638 00639 flagsChildren &= ~(RDW_INVALIDATE | 00640 RDW_ERASE | 00641 RDW_FRAME | 00642 RDW_VALIDATE | 00643 RDW_NOERASE | 00644 RDW_NOFRAME | 00645 RDW_SUBTRACTSELF); 00646 } 00647 } 00648 } 00649 } 00650 00651 /* 00652 * Go diddle the update region (AFTER our clipped children may have 00653 * done their thing to hrgnSubtract) 00654 */ 00655 if (TestWF(pwnd, WFCLIPCHILDREN)) 00656 InternalInvalidate3(pwnd, hrgn, flags); 00657 00658 /* 00659 * If we're invalidating and we're supposed to, 00660 * try to subtract off our window area from the region. 00661 * 00662 * This way our parent and our siblings below us will not 00663 * get any update region for areas that don't need one. 00664 */ 00665 if (flags & RDW_SUBTRACTSELF) { 00666 00667 /* 00668 * Subtract our visible region from the update rgn only if: 00669 * a) we're not a transparent window 00670 * b) we are clipsiblings 00671 * c) we're validating OR our parent is clipchildren. 00672 * 00673 * The check for validation is a backward-compatibility hack: this 00674 * is what 3.0 did, so this is what we do here. 00675 * 00676 * BACKWARD COMPATIBILITY HACK 00677 * 00678 * In 3.0, we subtracted this window from the update rgn if it 00679 * was clipsiblings, even if the parent was not clipchildren. 00680 * This causes a compatibility problem for Lotus Notes 3.1: it 00681 * has a combobox dropdown in a dialog that is a WS_CLIPSIBLING 00682 * sibling of the other dialog controls, which are not WS_CLIPSIBLINGs. 00683 * The dialog is not WS_CLIPCHILDREN. What happens is that a listbox 00684 * underneath the dropdown also gets a paint msg (since we didn't 00685 * do this subtraction), and, since it's not CLIPSIBLINGS, it 00686 * obliterates the dropdown. 00687 * 00688 * This is a very obscure difference, and it's too late in the 00689 * project to make this change now, so we're leaving the code as is 00690 * and using a compatibility hack to enable the 3.0-compatible 00691 * behavior. It's quite likely that this code works the way it does 00692 * for other compatibility reasons. Sigh (neilk). 00693 */ 00694 if (!TestWF(pwnd, WEFTRANSPARENT) && 00695 TestWF(pwnd, WFCLIPSIBLINGS) && 00696 ((flags & RDW_VALIDATE) || 00697 ((pwnd->spwndParent != NULL) && 00698 (TestWF(pwnd->spwndParent, WFCLIPCHILDREN) || 00699 (GetAppCompatFlags(GETPTI(pwnd)) & GACF_SUBTRACTCLIPSIBS))))) { 00700 00701 /* 00702 * Intersect with our visible area. 00703 * 00704 * Don't worry about errors: an error will result in more, not less 00705 * area being invalidated, which is okay. 00706 */ 00707 SetRectRgnIndirect(ghrgnInv2, &rcOurShare); 00708 00709 /* 00710 * If RDW_HASWINDOWRGN is set, either this window or 00711 * one of its parents has a window clipping region. This 00712 * flag is just an optimization so that this loop isn't 00713 * executed all the time. 00714 */ 00715 if (flags & RDW_HASWINDOWRGN) { 00716 00717 /* 00718 * Clip to the window's clipping region and parents! 00719 * If we don't clip to parents, we may get a case where 00720 * a child clips out some update region that was meant to 00721 * go to a sibling of the parent. 00722 */ 00723 for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndParent) { 00724 00725 if (pwndT->hrgnClip != NULL) { 00726 00727 /* 00728 * An error at this stage would possibly result in more 00729 * being subtracted out of the clipping region that 00730 * we'd like. 00731 */ 00732 IntersectRgn(ghrgnInv2, ghrgnInv2, pwndT->hrgnClip); 00733 } 00734 } 00735 } 00736 00737 00738 #if 1 00739 /* 00740 * TEMP HACK!!! RE-ENABLE this code when regions work again 00741 */ 00742 if (SubtractRgn(hrgnSubtract, hrgnSubtract, ghrgnInv2) == NULLREGION) 00743 return FALSE; 00744 #else 00745 { 00746 DWORD iRet; 00747 00748 iRet = SubtractRgn(hrgnSubtract, hrgnSubtract, ghrgnInv2); 00749 00750 if (iRet == NULLREGION) 00751 return FALSE; 00752 00753 if (iRet == SIMPLEREGION) { 00754 RECT rcSub; 00755 GreGetRgnBox(hrgnSubtract, &rcSub); 00756 if (rcSub.left > rcSub.right) 00757 return FALSE; 00758 } 00759 } 00760 #endif 00761 00762 00763 00764 } 00765 } 00766 00767 return TRUE; 00768 } 00769 00770 /***************************************************************************\ 00771 * InternalInvalidate3 00772 * 00773 * Adds or subtracts hrgn to the windows update region and sets appropriate 00774 * painting state flags. 00775 * 00776 * pwnd - The window. 00777 * hrng - The region to add to the update region. 00778 * flags - RDW_ flags. 00779 * 00780 * History: 00781 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 00782 \***************************************************************************/ 00783 00784 VOID InternalInvalidate3( 00785 PWND pwnd, 00786 HRGN hrgn, 00787 DWORD flags) 00788 { 00789 BOOL fNeededPaint; 00790 00791 fNeededPaint = NEEDSPAINT(pwnd); 00792 00793 if (flags & (RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ERASE | RDW_FRAME)) { 00794 00795 if (flags & RDW_INTERNALPAINT) 00796 SetWF(pwnd, WFINTERNALPAINT); 00797 00798 if (flags & RDW_INVALIDATE) { 00799 00800 /* 00801 * Make sure that the NONCPAINT bit is cleared 00802 * to ensure that the caption will redraw when we update. 00803 */ 00804 ClrWF(pwnd, WFNONCPAINT); 00805 00806 /* 00807 * If another app is invalidating this window, then set the 00808 * UPDATEDIRTY flag. 00809 * 00810 * Solves critical section where thread A draws, then validates, 00811 * but thread B goes and invalidates before A validates. 00812 * See comments later in RDW_VALIDATE code. 00813 */ 00814 if (GETPTI(pwnd) != PtiCurrent()) { 00815 00816 SetWF(pwnd, WFUPDATEDIRTY); 00817 00818 /* 00819 * Paint order problem, see paint.c 00820 */ 00821 if (TestWF(pwnd, WFWMPAINTSENT)) { 00822 SetWF(pwnd, WFDONTVALIDATE); 00823 } 00824 } 00825 00826 /* 00827 * BACKWARD COMPATIBILITY HACK 00828 * 00829 * In 3.0, InvalidateRect(pwnd, NULL, FALSE) would always 00830 * clear the WFSENDERASEBKGND flag, even if it was previously 00831 * set from an InvalidateRect(pwnd, NULL, TRUE). This is bogus, 00832 * because it can cause you to "lose" WM_ERASEBKGND messages, but 00833 * AttachMate Extra (and maybe other apps) depend on this behavior. 00834 */ 00835 if ((hrgn == HRGN_FULL) && !TestWF(pwnd, WFWIN31COMPAT)) 00836 ClrWF(pwnd, WFSENDERASEBKGND); 00837 00838 if (flags & RDW_ERASE) 00839 SetWF(pwnd, WFSENDERASEBKGND); 00840 00841 if ((flags & (RDW_FRAME | RDW_ERASE)) && !TestWF(pwnd, WEFTRANSPARENT)) 00842 SetHungFlag(pwnd, WFREDRAWIFHUNG); 00843 00844 if (flags & RDW_FRAME) 00845 SetWF(pwnd, WFSENDNCPAINT); 00846 00847 /* 00848 * If window is already completely invalidated, 00849 * no need to do any further invalidation. 00850 */ 00851 if (pwnd->hrgnUpdate != HRGN_FULL) { 00852 00853 if (hrgn == HRGN_FULL) { 00854 InvalidateAll: 00855 DeleteMaybeSpecialRgn(pwnd->hrgnUpdate); 00856 pwnd->hrgnUpdate = HRGN_FULL; 00857 00858 } else { 00859 if (pwnd->hrgnUpdate == NULL) { 00860 00861 if (!(pwnd->hrgnUpdate = CreateEmptyRgnPublic())) 00862 goto InvalidateAll; 00863 00864 if (CopyRgn(pwnd->hrgnUpdate, hrgn) == ERROR) 00865 goto InvalidateAll; 00866 00867 } else { // pwnd->hrgnUpdate is a region 00868 00869 if (UnionRgn(pwnd->hrgnUpdate, 00870 pwnd->hrgnUpdate, 00871 hrgn) == ERROR) { 00872 00873 goto InvalidateAll; 00874 } 00875 } 00876 } 00877 } 00878 } 00879 00880 if (!fNeededPaint && NEEDSPAINT(pwnd)) 00881 IncPaintCount(pwnd); 00882 00883 } else if (flags & (RDW_VALIDATE | RDW_NOINTERNALPAINT | RDW_NOERASE | RDW_NOFRAME)) { 00884 00885 /* 00886 * Validation: 00887 * 00888 * Do not allow validation if this window has been invalidated from 00889 * another process - because this window may be validating just 00890 * after another process invalidated, thereby validating invalid 00891 * bits. 00892 * 00893 * Sometimes applications draw stuff, then validate what they drew. 00894 * If another app invalidated some area during the drawing operation, 00895 * then it will need another paint message. 00896 * 00897 * This wouldn't be necessary if people validated BEFORE they drew. 00898 */ 00899 if (TestWF(pwnd, WFUPDATEDIRTY) && !(flags & RDW_IGNOREUPDATEDIRTY)) 00900 return; 00901 00902 if (flags & RDW_NOINTERNALPAINT) 00903 ClrWF(pwnd, WFINTERNALPAINT); 00904 00905 if (flags & RDW_VALIDATE) { 00906 00907 if (flags & RDW_NOERASE) 00908 ClrWF(pwnd, WFSENDERASEBKGND); 00909 00910 if (flags & RDW_NOFRAME) { 00911 ClrWF(pwnd, WFSENDNCPAINT); 00912 ClrWF(pwnd, WFPIXIEHACK); 00913 } 00914 00915 if (flags & (RDW_NOERASE | RDW_NOFRAME)) 00916 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00917 00918 if (pwnd->hrgnUpdate != NULL) { 00919 00920 /* 00921 * If WFSENDNCPAINT is set, then all or part of the 00922 * window border still needs to be drawn. This means 00923 * that we must subtract off the client rectangle only. 00924 * Convert HRGN_FULL to the client region. 00925 */ 00926 if (TestWF(pwnd, WFSENDNCPAINT) && (hrgn == HRGN_FULL)) { 00927 hrgn = ghrgnInv2; 00928 CalcWindowRgn(pwnd, hrgn, TRUE); 00929 } 00930 00931 if (hrgn == HRGN_FULL) { 00932 ValidateAll: 00933 00934 /* 00935 * We're validating the entire window. Just 00936 * blow away the update region. 00937 */ 00938 DeleteMaybeSpecialRgn(pwnd->hrgnUpdate); 00939 pwnd->hrgnUpdate = (HRGN)NULL; 00940 00941 /* 00942 * No need to erase the background... 00943 */ 00944 ClrWF(pwnd, WFSENDERASEBKGND); 00945 ClearHungFlag(pwnd, WFREDRAWIFHUNG); 00946 00947 } else { 00948 00949 /* 00950 * Subtracting some region from pwnd->hrgnUpdate. 00951 * Be sure pwnd->hrgnUpdate is a real region. 00952 */ 00953 if (pwnd->hrgnUpdate == HRGN_FULL) { 00954 00955 /* 00956 * If the WFSENDNCPAINT bit is set, 00957 * the update region must include the entire window 00958 * area. Otherwise it includes only the client. 00959 */ 00960 pwnd->hrgnUpdate = CreateEmptyRgnPublic(); 00961 00962 /* 00963 * If the creation failed, punt by 00964 * invalidating the entire window. 00965 */ 00966 if (pwnd->hrgnUpdate == NULL) 00967 goto InvalidateAll; 00968 00969 if (CalcWindowRgn(pwnd, 00970 pwnd->hrgnUpdate, 00971 !(TestWF(pwnd, WFSENDNCPAINT))) == ERROR) { 00972 00973 goto InvalidateAll; 00974 } 00975 } 00976 00977 /* 00978 * Subtract off the region. If we get an error, 00979 * punt by invalidating everything. If the 00980 * region becomes empty, then validate everything. 00981 */ 00982 switch (SubtractRgn(pwnd->hrgnUpdate, 00983 pwnd->hrgnUpdate, 00984 hrgn)) { 00985 case ERROR: 00986 goto InvalidateAll; 00987 00988 case NULLREGION: 00989 goto ValidateAll; 00990 } 00991 } 00992 } 00993 } 00994 00995 if (fNeededPaint && !NEEDSPAINT(pwnd)) 00996 DecPaintCount(pwnd); 00997 } 00998 } 00999 01000 /***************************************************************************\ 01001 * ValidateParents 01002 * 01003 * This routine validates hrgn from the update regions of the parent windows 01004 * between pwnd and its first clip children parent. 01005 * If hrgn is NULL, then the window rect (intersected with all parents) 01006 * is validated. 01007 * 01008 * This routine is called when a window is being drawn in 01009 * UpdateWindow() so that non-CLIPCHILDREN parents 01010 * of windows being redrawn won't draw on their valid children. 01011 * 01012 * Returns FALSE if fRecurse is TRUE and a non-CLIPCHILDREN parent 01013 * has an update region; otherwise, returns TRUE. 01014 * 01015 * History: 01016 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01017 \***************************************************************************/ 01018 01019 BOOL ValidateParents( 01020 PWND pwnd, 01021 BOOL fRecurse) 01022 { 01023 RECT rcParents; 01024 RECT rc; 01025 PWND pwndParent = pwnd; 01026 BOOL fInit = FALSE; 01027 01028 /* 01029 * This is checking whether we are in an in-between state, just before 01030 * a WM_SYNCPAINT is about to arrive. If not, then ValidateParents() 01031 * needs to work like it did in Win 3.1. 01032 */ 01033 while (TestWF(pwndParent, WFCHILD)) 01034 pwndParent = pwndParent->spwndParent; 01035 01036 if (!TestWF(pwndParent, WFSYNCPAINTPENDING)) 01037 fRecurse = FALSE; 01038 01039 pwndParent = pwnd; 01040 01041 while ((pwndParent = pwndParent->spwndParent) != NULL) { 01042 01043 /* 01044 * Stop when we find a clipchildren parent 01045 */ 01046 if (TestWF(pwndParent, WFCLIPCHILDREN)) 01047 break; 01048 01049 /* 01050 * Subtract the region from this parent's update region, 01051 * if it has one. 01052 */ 01053 if (pwndParent->hrgnUpdate != NULL) { 01054 if (fRecurse) { 01055 return FALSE; 01056 } 01057 if (!fInit) { 01058 fInit = TRUE; 01059 01060 /* 01061 * Do initial setup. If our window rectangle is 01062 * completely obscured, get out. 01063 */ 01064 rc = pwnd->rcWindow; 01065 if (!IntersectWithParents(pwnd, &rc)) 01066 break; 01067 01068 SetRectRgnIndirect(ghrgnInv1, &rc); 01069 01070 /* 01071 * If this window has a region, make sure the piece being validated 01072 * is within this region. 01073 */ 01074 if (pwnd->hrgnClip != NULL) { 01075 01076 /* 01077 * If we get NULLREGION back, there is nothing to validate 01078 * against parents, so break out. If ERROR gets returned, 01079 * there is not much we can do: the best "wrong" thing 01080 * to do is just continue and validate a little more 01081 * from the parent. 01082 */ 01083 if (!IntersectRgn(ghrgnInv1, ghrgnInv1, pwnd->hrgnClip)) 01084 break; 01085 } 01086 } 01087 01088 /* 01089 * Calculate the rcParents parameter to 01090 * pass up to InternalInvalidate2. 01091 */ 01092 rcParents = pwndParent->rcWindow; 01093 01094 if (!IntersectWithParents(pwndParent, &rcParents)) 01095 break; 01096 01097 InternalInvalidate2( 01098 pwndParent, 01099 ghrgnInv1, 01100 ghrgnInv1, 01101 &rcParents, 01102 RDW_VALIDATE | RDW_NOCHILDREN | RDW_IGNOREUPDATEDIRTY); 01103 } 01104 } 01105 01106 return TRUE; 01107 } 01108 01109 /***************************************************************************\ 01110 * xxxUpdateWindow2 01111 * 01112 * Sends a WM_PAINT message to the window if it needs painting, 01113 * then sends the message to its children. 01114 * 01115 * Always returns TRUE. 01116 * 01117 * History: 01118 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01119 \***************************************************************************/ 01120 01121 void xxxUpdateWindow2( 01122 PWND pwnd, 01123 DWORD flags) 01124 { 01125 TL tlpwnd; 01126 01127 CheckLock(pwnd); 01128 01129 if (NEEDSPAINT(pwnd)) { 01130 01131 /* 01132 * Punch a hole in our parent's update region, if we have one. 01133 */ 01134 if (pwnd->hrgnUpdate) { 01135 if (ValidateParents(pwnd, flags & UW_RECURSED) == FALSE) { 01136 return; 01137 } 01138 } 01139 01140 /* 01141 * Now that we're sending the message, clear the 01142 * internal paint bit if it was previously set. 01143 */ 01144 if (TestWF(pwnd, WFINTERNALPAINT)) { 01145 01146 ClrWF(pwnd, WFINTERNALPAINT); 01147 01148 /* 01149 * If there is no update region, then no further paint messages 01150 * are pending, so we must dec the paint count. 01151 */ 01152 if (pwnd->hrgnUpdate == NULL) 01153 DecPaintCount(pwnd); 01154 } 01155 01156 /* 01157 * Set a flag indicating that a paint message was not processed 01158 * (but should be). 01159 */ 01160 SetWF(pwnd, WFPAINTNOTPROCESSED); 01161 01162 /* 01163 * Clear this bit, for apps (like MicroLink) that don't call 01164 * BeginPaint or GetUpdateRect/Rgn (but DO call ValidateRect) 01165 * when handling their WM_PAINT message. 01166 */ 01167 ClrWF(pwnd, WFUPDATEDIRTY); 01168 01169 /* 01170 * BACKWARD COMPATIBILITY HACK 01171 * 01172 * Win 3.0 always sent WM_PAINTICON with wParam == TRUE for no good 01173 * reason, and Lotus Notes has come to depend on this. 01174 */ 01175 if (!TestWF(pwnd, WFWIN40COMPAT) && 01176 TestWF(pwnd, WFMINIMIZED) && 01177 (pwnd->pcls->spicn != NULL)) { 01178 01179 xxxSendMessage(pwnd, WM_PAINTICON, TRUE, 0L); 01180 01181 } else { 01182 01183 xxxSendMessage(pwnd, WM_PAINT, 0, 0L); 01184 } 01185 01186 /* 01187 * If the guy didn't call BeginPaint/EndPaint(), or GetUpdateRect/Rgn 01188 * with fErase == TRUE, then we have to clean up for him here. 01189 */ 01190 if (TestWF(pwnd, WFPAINTNOTPROCESSED)) { 01191 01192 RIPMSG0(RIP_VERBOSE, 01193 "App didn't call BeginPaint() or GetUpdateRect/Rgn(fErase == TRUE) in WM_PAINT"); 01194 01195 xxxSimpleDoSyncPaint(pwnd); 01196 } 01197 } 01198 01199 /* 01200 * For desktop window, do not force the top level window repaint at this 01201 * this point. We are calling UpdateWindow() for the desktop before 01202 * size/move is sent for the top level windows. 01203 * 01204 * BUG: The comment above seems a bit random. Is there really a problem? 01205 * If nothing else this has to remain this way because it is 01206 * how Win 3.0 worked (neilk) 01207 */ 01208 if ((flags & UW_ENUMCHILDREN) && (pwnd != PWNDDESKTOP(pwnd))) { 01209 01210 /* 01211 * Update any children... 01212 */ 01213 ThreadLockNever(&tlpwnd); 01214 pwnd = pwnd->spwndChild; 01215 while (pwnd != NULL) { 01216 01217 /* 01218 * If there is a transparent window that needs painting, 01219 * skip it if another window below it needs to paint. 01220 */ 01221 if (TestWF(pwnd, WEFTRANSPARENT) && NEEDSPAINT(pwnd)) { 01222 01223 PWND pwndT = pwnd; 01224 01225 while ((pwndT = pwndT->spwndNext) != NULL) { 01226 if (NEEDSPAINT(pwndT)) 01227 break; 01228 } 01229 01230 if (pwndT != NULL) { 01231 pwnd = pwnd->spwndNext; 01232 continue; 01233 } 01234 } 01235 01236 ThreadLockExchangeAlways(pwnd, &tlpwnd); 01237 xxxUpdateWindow2(pwnd, flags | UW_RECURSED); 01238 pwnd = pwnd->spwndNext; 01239 } 01240 01241 ThreadUnlock(&tlpwnd); 01242 } 01243 01244 return; 01245 } 01246 01247 /***************************************************************************\ 01248 * xxxInternalUpdateWindow 01249 * 01250 * Sends a WM_PAINT message to the window if it needs painting, 01251 * then sends the message to its children. Won't send WM_PAINT 01252 * if the window is transparent and has siblings that need 01253 * painting. 01254 * 01255 * History: 01256 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01257 \***************************************************************************/ 01258 01259 void xxxInternalUpdateWindow( 01260 PWND pwnd, 01261 DWORD flags) 01262 { 01263 CheckLock(pwnd); 01264 01265 /* 01266 * If the passed-in window is transparent and a sibling below 01267 * needs repainting, don't do anything. 01268 */ 01269 if (TestWF(pwnd, WEFTRANSPARENT)) { 01270 01271 PWND pwndT = pwnd; 01272 PTHREADINFO ptiCurrent = GETPTI(pwnd); 01273 01274 while ((pwndT = pwndT->spwndNext) != NULL) { 01275 01276 /* 01277 * Make sure sibling window belongs to same app. 01278 */ 01279 if (GETPTI(pwndT) != ptiCurrent) 01280 continue; 01281 01282 if (NEEDSPAINT(pwndT)) 01283 return; 01284 } 01285 } 01286 01287 /* 01288 * Enumerate pwnd and all its children, sending WM_PAINTs as needed. 01289 */ 01290 xxxUpdateWindow2(pwnd, flags); 01291 } 01292 01293 /***************************************************************************\ 01294 * xxxInternalInvalidate 01295 * 01296 * (In)validates hrgnUpdate and updates the window. 01297 * 01298 * History: 01299 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01300 \***************************************************************************/ 01301 01302 VOID xxxInternalInvalidate( 01303 PWND pwnd, 01304 HRGN hrgnUpdate, 01305 DWORD flags) 01306 { 01307 RECT rcParents; 01308 HRGN hrgnSubtract; 01309 01310 #if DBG 01311 if (flags & (RDW_ERASENOW | RDW_UPDATENOW)) { 01312 CheckLock(pwnd); 01313 } 01314 #endif 01315 01316 /* 01317 * Allow invalidation of a layered window when someone specifically 01318 * invalidates it. This will also prevent invalidation of layered 01319 * windows during recursive desktop invalidations. 01320 */ 01321 if (FLayeredOrRedirected(pwnd)) { 01322 flags |= RDW_INVALIDATELAYERS; 01323 } 01324 01325 /* 01326 * Ensure that hrgnSubtract is a valid region: if it's NULLREGION, 01327 * use the client region. 01328 */ 01329 rcParents = (flags & RDW_FRAME ? pwnd->rcWindow : pwnd->rcClient); 01330 01331 if (flags & (RDW_VALIDATE | RDW_INVALIDATE)) { 01332 01333 hrgnSubtract = hrgnUpdate; 01334 01335 if (hrgnSubtract == HRGN_FULL) { 01336 01337 hrgnSubtract = ghrgnInv1; 01338 CalcWindowRgn(pwnd, 01339 hrgnSubtract, 01340 (flags & RDW_FRAME) ? FALSE : TRUE); 01341 } 01342 01343 /* 01344 * Calculate the bounding rectangle of our screen real estate, 01345 * by intersecting with our parent rectangles. While we're at 01346 * it, check the visibility of ourself and our parents. 01347 * 01348 * If we're validating we want to skip this, since there 01349 * are a number of cases where obscured windows may have 01350 * update regions to be validated -- in particular, after 01351 * a ScrollWindow() call where a child window was offset 01352 * by OffsetChildren() to a new, obscured position. Some of 01353 * the 3.0 compatibility hacks also can lead to this situation. 01354 */ 01355 if ((flags & RDW_INVALIDATE) && !IntersectWithParents(pwnd, &rcParents)) 01356 return; 01357 01358 } else { 01359 /* 01360 * hrgnsubtract needs to be a real region even if 01361 * we are not invalidating or validating. It really doesn't 01362 * matter what the region is, but we set it to null so the code 01363 * has less degrees of freedom. 01364 */ 01365 hrgnSubtract = ghrgnInv1; 01366 SetEmptyRgn(hrgnSubtract); 01367 } 01368 01369 /* 01370 * If we're invalidating, and we're being called by the app, 01371 * we need to invalidate any SPBs that might be affected by 01372 * drawing in the client area of this window. 01373 * We have to do this because there is no guarantee that the 01374 * application will draw in an area that is invalidated 01375 * (e.g., if the window is completely obscured by another). 01376 */ 01377 if ( (flags & (RDW_INVALIDATE | RDW_REDRAWWINDOW)) == (RDW_INVALIDATE | RDW_REDRAWWINDOW) && 01378 AnySpbs()) { 01379 01380 RECT rcInvalid; 01381 01382 /* 01383 * Intersect the parent's rect with the region bounds... 01384 */ 01385 GreGetRgnBox(hrgnSubtract, &rcInvalid); 01386 IntersectRect(&rcInvalid, &rcInvalid, &rcParents); 01387 SpbCheckRect(pwnd, &rcInvalid, 0); 01388 } 01389 01390 /* 01391 * Now go do the recursive update region calculations... 01392 */ 01393 InternalInvalidate2(pwnd, hrgnUpdate, hrgnSubtract, &rcParents, flags); 01394 01395 /* 01396 * Finally handle any needed drawing. 01397 * 01398 * (NOTE: RDW_UPDATENOW implies RDW_ERASENOW) 01399 */ 01400 if (flags & RDW_UPDATENOW) { 01401 01402 xxxInternalUpdateWindow(pwnd, 01403 flags & RDW_NOCHILDREN ? 0 : UW_ENUMCHILDREN); 01404 01405 } else if (flags & RDW_ERASENOW) { 01406 01407 UINT flagsDSP; 01408 01409 if (flags & RDW_NOCHILDREN) { 01410 flagsDSP = 0; 01411 } else if (flags & RDW_ALLCHILDREN) { 01412 flagsDSP = DSP_ALLCHILDREN; 01413 } else { 01414 flagsDSP = DSP_ENUMCLIPPEDCHILDREN; 01415 } 01416 01417 xxxDoSyncPaint(pwnd, flagsDSP); 01418 } 01419 } 01420 01421 /***************************************************************************\ 01422 * UpdateWindow (API) 01423 * 01424 * Updates the window and all its children. 01425 * 01426 * History: 01427 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01428 \***************************************************************************/ 01429 01430 BOOL xxxUpdateWindow( 01431 PWND pwnd) 01432 { 01433 CheckLock(pwnd); 01434 01435 xxxInternalUpdateWindow(pwnd, UW_ENUMCHILDREN); 01436 01437 /* 01438 * This function needs to return a value, since it is 01439 * called through NtUserCallHwndLock. 01440 */ 01441 return TRUE; 01442 } 01443 01444 /***************************************************************************\ 01445 * ExcludeUpdateRgn (API) 01446 * 01447 * ENTRY: hdc - DC to exclude from 01448 * pwnd - window handle 01449 * 01450 * EXIT: GDI region type 01451 * 01452 * WARNINGS: The DC is assumed to correspond to the client area of the window. 01453 * 01454 * The map mode of hdc MUST be text mode (0, 0 is top left corner, 01455 * one pixel per unit, ascending down and to right) or things won't 01456 * work. 01457 * 01458 * History: 01459 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01460 \***************************************************************************/ 01461 01462 int _ExcludeUpdateRgn( 01463 HDC hdc, 01464 PWND pwnd) 01465 { 01466 POINT pt; 01467 01468 if (pwnd->hrgnUpdate == NULL) { 01469 01470 RECT rc; 01471 01472 /* 01473 * Pass FALSE for fXForm since &rc isn't used. 01474 */ 01475 return GreGetClipBox(hdc, &rc, FALSE); 01476 01477 } else if (pwnd->hrgnUpdate == HRGN_FULL) { 01478 01479 return GreIntersectClipRect(hdc, 0, 0, 0, 0); 01480 01481 } else { 01482 01483 /* 01484 * If no clip rgn exists, then subtract from a device-sized clip rgn. 01485 * (GetClipRgn returns clip rgn in screen coordinates). 01486 */ 01487 GreGetDCOrg(hdc, &pt); 01488 if (GreGetRandomRgn(hdc, ghrgnInv1, 1) != 1) { 01489 CopyRgn(ghrgnInv1, gpDispInfo->hrgnScreen); 01490 } else { 01491 01492 /* 01493 * Gets returned in dc coords - translate to screen. 01494 */ 01495 GreOffsetRgn(ghrgnInv1, pt.x, pt.y); 01496 } 01497 01498 SubtractRgn(ghrgnInv1, ghrgnInv1, pwnd->hrgnUpdate); 01499 01500 /* 01501 * Map to dc coords before select 01502 */ 01503 GreOffsetRgn(ghrgnInv1, -pt.x, -pt.y); 01504 01505 return GreExtSelectClipRgn(hdc, ghrgnInv1, RGN_COPY); 01506 } 01507 } 01508 01509 /***************************************************************************\ 01510 * GetUpdateRect (API) 01511 * 01512 * Returns the bounding rectangle of the update region, or an empty rectangle 01513 * if there is no update region. Rectangle is in client-relative coordinates. 01514 * 01515 * Returns TRUE if the update region is non-empty, FALSE if there is no 01516 * update region. 01517 * 01518 * lprc may be NULL to query whether or not an update region exists at all 01519 * or not. 01520 * 01521 * History: 01522 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01523 \***************************************************************************/ 01524 01525 BOOL xxxGetUpdateRect( 01526 PWND pwnd, 01527 LPRECT lprc, 01528 BOOL fErase) 01529 { 01530 RECT rc; 01531 01532 CheckLock(pwnd); 01533 01534 if (fErase) 01535 xxxSimpleDoSyncPaint(pwnd); 01536 01537 /* 01538 * The app is looking at the update region: okay to allow window 01539 * validation. 01540 */ 01541 ClrWF(pwnd, WFUPDATEDIRTY); 01542 01543 if (pwnd->hrgnUpdate == NULL) { 01544 01545 if (lprc) { 01546 SetRectEmpty(lprc); 01547 } 01548 01549 return FALSE; 01550 01551 } else { 01552 01553 /* 01554 * We must handle the case where a window has an update region, 01555 * but it is completely obscured by its parents. In this case, we 01556 * must validate the window and all its children, and return FALSE. 01557 * 01558 * An OffsetChildren() call resulting from SetWindowPos() or 01559 * ScrollWindowEx() will cause this to happen. Update regions are 01560 * just offset without checking their new positions to see if they 01561 * are obscured by the parent(s). This is too painful to check in 01562 * those cases, so we instead handle it here. 01563 * 01564 * BeginPaint() handles this case correctly by returning an empty 01565 * rectangle, so nothing special need be done there. 01566 */ 01567 if (pwnd->hrgnUpdate == HRGN_FULL) { 01568 01569 rc = pwnd->rcClient; 01570 01571 } else { 01572 01573 switch (GreGetRgnBox(pwnd->hrgnUpdate, &rc)) { 01574 case ERROR: 01575 case NULLREGION: 01576 SetRectEmpty(&rc); 01577 break; 01578 01579 case SIMPLEREGION: 01580 case COMPLEXREGION: 01581 break; 01582 } 01583 01584 IntersectRect(&rc, &rc, &pwnd->rcClient); 01585 } 01586 01587 if (IntersectWithParents(pwnd, &rc)) { 01588 01589 if (pwnd != PWNDDESKTOP(pwnd)) { 01590 OffsetRect(&rc, -pwnd->rcClient.left, -pwnd->rcClient.top); 01591 } 01592 01593 /* 01594 * If the window is CS_OWNDC, then we must map the returned 01595 * rectangle with DPtoLP, to ensure that the rectangle is 01596 * in the same coordinate system as the rectangle returned 01597 * by BeginPaint(). 01598 * 01599 * BUT ONLY IF hwnd->hrgnUpdate != HRGN_FULL! For true 01600 * compatibility with 3.0. 01601 */ 01602 if (TestCF(pwnd, CFOWNDC) && 01603 (TestWF(pwnd, WFWIN31COMPAT) || pwnd->hrgnUpdate != HRGN_FULL)) { 01604 01605 PDCE pdce; 01606 01607 /* 01608 * Look up this window's DC in the cache, and use it to 01609 * map the returned rectangle. 01610 */ 01611 for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) { 01612 01613 if (pdce->pwndOrg == pwnd && !(pdce->DCX_flags & DCX_CACHE)) { 01614 GreDPtoLP(pdce->hdc, (LPPOINT)&rc, 2); 01615 break; 01616 } 01617 } 01618 } 01619 01620 } else { 01621 SetRectEmpty(&rc); 01622 } 01623 } 01624 01625 if (lprc) { 01626 #ifdef USE_MIRRORING 01627 if (TestWF(pwnd, WEFLAYOUTRTL)) { 01628 MirrorRect(pwnd, &rc); 01629 } 01630 #endif 01631 *lprc = rc; 01632 } 01633 01634 /* 01635 * If we're in the process a dragging a full window, mark the start 01636 * of the application painting. This is to make sure that if the 01637 * application calls DefWindowProc on the WM_PAINT after painting, we 01638 * won't erase the newly painted areas. Visual Slick calls GetUpdateRect 01639 * and then DefWindowProc. 01640 * See other comments for xxxBeginPaint and xxxDWP_Paint. 01641 * 8/3/94 johannec 01642 * 01643 * NOTE: This causes other problems in vslick where some controls 01644 * won't paint. Since the app doesn't call BeginPaint/EndPaint 01645 * to truly set/clear the STARTPAINT flag, we do not clear this 01646 * bit. (6-27-1996 : ChrisWil). 01647 * 01648 * 01649 * if (TEST_PUDF(PUDF_DRAGGINGFULLWINDOW)) { 01650 * SetWF(pwnd, WFSTARTPAINT); 01651 * } 01652 */ 01653 01654 return TRUE; 01655 } 01656 01657 /***************************************************************************\ 01658 * GetUpdateRgn (API) 01659 * 01660 * 01661 * History: 01662 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01663 \***************************************************************************/ 01664 01665 int xxxGetUpdateRgn( 01666 PWND pwnd, 01667 HRGN hrgn, 01668 BOOL fErase) 01669 { 01670 RECT rc; 01671 int code; 01672 BOOL fNotEmpty; 01673 01674 01675 CheckLock(pwnd); 01676 01677 if (fErase) 01678 xxxSimpleDoSyncPaint(pwnd); 01679 01680 /* 01681 * The application is looking at the update region: okay to 01682 * allow validation 01683 */ 01684 ClrWF(pwnd, WFUPDATEDIRTY); 01685 01686 if (pwnd->hrgnUpdate == NULL) 01687 goto ReturnEmpty; 01688 01689 rc = pwnd->rcClient; 01690 fNotEmpty = IntersectWithParents(pwnd, &rc); 01691 01692 if (pwnd->hrgnUpdate == HRGN_FULL) { 01693 01694 /* 01695 * Since the update region may be larger than the window 01696 * rectangle, intersect it with the window rectangle. 01697 */ 01698 if (!fNotEmpty) 01699 goto ReturnEmpty; 01700 01701 code = SIMPLEREGION; 01702 01703 /* 01704 * Normalize the rectangle\region relative to the unclipped window 01705 */ 01706 if (pwnd != PWNDDESKTOP(pwnd)) { 01707 OffsetRect(&rc, -pwnd->rcClient.left, -pwnd->rcClient.top); 01708 } 01709 01710 SetRectRgnIndirect(hrgn, &rc); 01711 01712 } else { 01713 01714 SetRectRgnIndirect(ghrgnInv2, &rc); 01715 code = IntersectRgn(hrgn, ghrgnInv2, pwnd->hrgnUpdate); 01716 01717 switch (code) { 01718 case NULLREGION: 01719 case ERROR: 01720 goto ReturnEmpty; 01721 01722 default: 01723 if (pwnd != PWNDDESKTOP(pwnd)) { 01724 GreOffsetRgn(hrgn, -pwnd->rcClient.left, -pwnd->rcClient.top); 01725 } 01726 break; 01727 } 01728 } 01729 01730 #ifdef USE_MIRRORING 01731 MirrorRegion(pwnd, hrgn, TRUE); 01732 #endif 01733 /* 01734 * If we're in the process a dragging a full window, mark the start 01735 * of the application painting. This is to make sure that if the 01736 * application calls DefWindowProc on the WM_PAINT after painting, we 01737 * won't erase the newly painted areas. 01738 * See other comments for xxxBeginPaint and xxxDWP_Paint. 01739 * 8/3/94 johannec 01740 * 01741 * NOTE: This causes other problems in vslick where some controls 01742 * won't paint. Since the app doesn't call BeginPaint/EndPaint 01743 * to truly set/clear the STARTPAINT flag, we do not clear this 01744 * bit. (6-27-1996 : ChrisWil). 01745 * 01746 * if (TEST(PUDF(PUDF_DRAGGINGFULLWINDOW)) { 01747 * SetWF(pwnd, WFSTARTPAINT); 01748 * } 01749 */ 01750 01751 return code; 01752 01753 ReturnEmpty: 01754 SetEmptyRgn(hrgn); 01755 return NULLREGION; 01756 } 01757 01758 /***************************************************************************\ 01759 * IntersectWithParents 01760 * 01761 * This routine calculates the intersection of a rectangle with the client 01762 * rectangles of all of pwnd's parents. Returns FALSE if the intersection 01763 * is empty, a window is invisible, or a parent is minimized. 01764 * 01765 * Stop the intesesection if the window itself or any of its parents are 01766 * layered windows, so we always have a complete bitmap of them. 01767 * 01768 * History: 01769 * 16-Jul-1991 DarrinM Ported from Win 3.1 sources. 01770 \***************************************************************************/ 01771 01772 BOOL IntersectWithParents( 01773 PWND pwnd, 01774 LPRECT lprc) 01775 { 01776 if (FLayeredOrRedirected(pwnd)) 01777 return TRUE; 01778 01779 while ((pwnd = pwnd->spwndParent) != NULL) { 01780 01781 if (!TestWF(pwnd, WFVISIBLE) || TestWF(pwnd, WFMINIMIZED)) 01782 return FALSE; 01783 01784 if (!IntersectRect(lprc, lprc, &pwnd->rcClient)) 01785 return FALSE; 01786 01787 if (FLayeredOrRedirected(pwnd)) 01788 return TRUE; 01789 } 01790 01791 return TRUE; 01792 }

Generated on Sat May 15 19:42:11 2004 for test by doxygen 1.3.7