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

visrgn.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: visrgn.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains User's visible region ('visrgn') manipulation 00007 * functions. 00008 * 00009 * History: 00010 * 23-Oct-1990 DarrinM Created. 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 /* 00017 * Globals used to keep track of pwnds which 00018 * need to be excluded from the visrgns. 00019 */ 00020 #define CEXCLUDERECTSMAX 30 00021 #define CEXCLUDEPWNDSMAX 30 00022 00023 00024 BOOL gfVisAlloc; 00025 int gcrcVisExclude; 00026 int gcrcVisExcludeMax; 00027 PWND *gapwndVisExclude; 00028 PWND *gapwndVisDefault; 00029 00030 /***************************************************************************\ 00031 * SetRectRgnIndirect 00032 * 00033 * Sets a rect region from a rectangle. 00034 * 00035 * History: 00036 * 26-Sep-1996 adams Created. 00037 \***************************************************************************/ 00038 00039 BOOL 00040 SetRectRgnIndirect(HRGN hrgn, LPCRECT lprc) 00041 { 00042 return GreSetRectRgn(hrgn, lprc->left, lprc->top, lprc->right, lprc->bottom); 00043 } 00044 00045 00046 00047 /***************************************************************************\ 00048 * CreateEmptyRgn 00049 * 00050 * Creates an empty region. 00051 * 00052 * History: 00053 * 24-Sep-1996 adams Created. 00054 \***************************************************************************/ 00055 00056 HRGN 00057 CreateEmptyRgn(void) 00058 { 00059 return GreCreateRectRgnIndirect(PZERO(RECT)); 00060 } 00061 00062 00063 00064 /***************************************************************************\ 00065 * CreateEmptyRgnPublic 00066 * 00067 * Creates an empty region and make it public. 00068 * 00069 * History: 00070 * 24-Sep-1996 adams Created. 00071 \***************************************************************************/ 00072 00073 HRGN 00074 CreateEmptyRgnPublic(void) 00075 { 00076 HRGN hrgn; 00077 00078 if (hrgn = CreateEmptyRgn()) { 00079 UserVerify(GreSetRegionOwner(hrgn, OBJECT_OWNER_PUBLIC)); 00080 } 00081 00082 return hrgn; 00083 } 00084 00085 00086 00087 /***************************************************************************\ 00088 * SetEmptyRgn 00089 * 00090 * Sets an empty region. 00091 * 00092 * History: 00093 * 26-Sep-1996 adams Created. 00094 \***************************************************************************/ 00095 00096 BOOL 00097 SetEmptyRgn(HRGN hrgn) 00098 { 00099 return SetRectRgnIndirect(hrgn, PZERO(RECT)); 00100 } 00101 00102 00103 00104 /***************************************************************************\ 00105 * SetOrCreateRectRgnIndirectPublic 00106 * 00107 * Sets a region to a rectangle, creating it and making it public 00108 * if it is not already there. 00109 * 00110 * History: 00111 * 01-Oct-1996 adams Created. 00112 \***************************************************************************/ 00113 00114 HRGN 00115 SetOrCreateRectRgnIndirectPublic(HRGN * phrgn, LPCRECT lprc) 00116 { 00117 if (*phrgn) { 00118 UserVerify(SetRectRgnIndirect(*phrgn, lprc)); 00119 } else if (*phrgn = GreCreateRectRgnIndirect((LPRECT) lprc)) { 00120 UserVerify(GreSetRegionOwner(*phrgn, OBJECT_OWNER_PUBLIC)); 00121 } 00122 00123 return *phrgn; 00124 } 00125 00126 00127 /***************************************************************************\ 00128 * ResizeVisExcludeMemory 00129 * 00130 * This routine is used to resize the vis-rgn memory buffer if the count 00131 * is exceeded. 00132 * 00133 * 00134 * History: 00135 * 22-Oct-1994 ChrisWil Created 00136 * 27-Feb-1997 adams Removed call to UserReallocPool, since the pool 00137 * allocator doesn't support realloc. 00138 \***************************************************************************/ 00139 00140 BOOL ResizeVisExcludeMemory(VOID) 00141 { 00142 int crcNew; 00143 PWND apwndNew; 00144 00145 /* 00146 * Note (adams): a previous version of the code called UserReallocPool 00147 * if memory had already been allocated. Unfortunately, UserReallocPool 00148 * just has to allocate more memory and copy the contents, since Rtl 00149 * doesn't have a realloc function. If Rtl later gains a Realloc function, 00150 * this code should be changed to the previous version. 00151 */ 00152 00153 crcNew = gcrcVisExcludeMax + CEXCLUDEPWNDSMAX; 00154 apwndNew = (PWND)UserAllocPool( 00155 crcNew * sizeof(PWND), TAG_VISRGN); 00156 00157 if (!apwndNew) 00158 return FALSE; 00159 00160 UserAssert(gcrcVisExcludeMax == gcrcVisExclude); 00161 RtlCopyMemory(apwndNew, gapwndVisExclude, gcrcVisExcludeMax * sizeof(PWND)); 00162 if (gfVisAlloc) { 00163 UserFreePool(gapwndVisExclude); 00164 } else { 00165 gfVisAlloc = TRUE; 00166 } 00167 00168 gcrcVisExcludeMax = crcNew; 00169 gapwndVisExclude = (PWND *)apwndNew; 00170 return TRUE; 00171 } 00172 00173 00174 00175 /***************************************************************************\ 00176 * ExcludeWindowRects 00177 * This routine checks to see if the pwnd needs to be added to the list 00178 * of excluded-clip-rects. If so, it appends the pwnd to the array. They 00179 * do not need to be sorted, since GreSubtractRgnRectList() sorts them 00180 * internally. 00181 * 00182 * 00183 * History: 00184 * 05-Nov-1992 DavidPe Created. 00185 * 21-Oct-1994 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds. 00186 \***************************************************************************/ 00187 00188 #define CheckIntersectRect(prc1, prc2) \ 00189 ( prc1->left < prc2->right \ 00190 && prc2->left < prc1->right \ 00191 && prc1->top < prc2->bottom \ 00192 && prc2->top < prc1->bottom) 00193 00194 #define EmptyRect(prc) \ 00195 ( prc->left >= prc->right \ 00196 || prc->top >= prc->bottom) 00197 00198 BOOL ExcludeWindowRects( 00199 PWND pwnd , 00200 PWND pwndStop, 00201 LPRECT lprcIntersect) 00202 { 00203 PRECT prc; 00204 00205 #if DBG 00206 if (pwnd != NULL && pwndStop != NULL && 00207 pwnd->spwndParent != pwndStop->spwndParent) { 00208 RIPMSG0(RIP_ERROR, "ExcludeWindowRects: bad windows passed in"); 00209 } 00210 #endif 00211 00212 while ((pwnd != NULL) && (pwnd != pwndStop)) { 00213 UserAssert(pwnd); 00214 prc = &pwnd->rcWindow; 00215 if ( TestWF(pwnd, WFVISIBLE) 00216 && !FLayeredOrRedirected(pwnd) 00217 && (TestWF(pwnd, WEFTRANSPARENT) == 0) 00218 && CheckIntersectRect(lprcIntersect, prc) 00219 && !EmptyRect(prc)) { 00220 00221 UserAssert(gcrcVisExclude <= gcrcVisExcludeMax); 00222 if (gcrcVisExclude == gcrcVisExcludeMax) { 00223 if (!ResizeVisExcludeMemory()) { 00224 return FALSE; 00225 } 00226 } 00227 00228 gapwndVisExclude[gcrcVisExclude++] = pwnd; 00229 } 00230 00231 pwnd = pwnd->spwndNext; 00232 } 00233 00234 return TRUE; 00235 } 00236 00237 00238 00239 /***************************************************************************\ 00240 * CalcWindowVisRgn 00241 * 00242 * This routine performs the work of calculating the VisRgn for a window. 00243 * 00244 * 00245 * History: 00246 * 02-Nov-1992 DavidPe Created. 00247 * 21-Oct-1992 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds. 00248 \***************************************************************************/ 00249 00250 BOOL CalcWindowVisRgn( 00251 PWND pwnd, 00252 HRGN *phrgn, 00253 DWORD flags) 00254 { 00255 RECT rcWindow; 00256 PWND pwndParent; 00257 PWND pwndRoot; 00258 PWND pwndLoop; 00259 BOOL fClipSiblings; 00260 BOOL fRgnParent = FALSE; 00261 BOOL fResult; 00262 PWND apwndVisDefault[CEXCLUDEPWNDSMAX]; 00263 00264 00265 /* 00266 * First get the initial window rectangle which will be used for 00267 * the basis of exclusion calculations. 00268 */ 00269 rcWindow = (flags & DCX_WINDOW ? pwnd->rcWindow : pwnd->rcClient); 00270 00271 /* 00272 * Get the parent of this window. We start at the parent and backtrack 00273 * through the window-parent-list until we reach the end of the parent- 00274 * list. This will give us the intersect-rectangle which is used as 00275 * the basis for checking intersection of the exclusion rects. 00276 */ 00277 pwndRoot = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndParent; 00278 pwndParent = pwnd->spwndParent; 00279 00280 /* 00281 * The parent can be NULL in the case when pwnd == pwndRoot. In other 00282 * cases we should figure why the hell the parent is NULL. 00283 */ 00284 if (pwndParent == NULL) { 00285 #if DBG 00286 if (pwnd != pwndRoot) { 00287 RIPMSG0(RIP_ERROR, "CalcWindowVisRgn: pwndParent is NULL"); 00288 } 00289 #endif 00290 goto NullRegion; 00291 } 00292 00293 while (pwndParent != pwndRoot) { 00294 00295 /* 00296 * Don't clip layered DCs to the desktop. The surface of the layered 00297 * DC is the size of the window and we always want to have the image 00298 * of the entire window in that surface. 00299 */ 00300 if ((flags & DCX_LAYERED) && (GETFNID(pwndParent) == FNID_DESKTOP)) 00301 break; 00302 00303 /* 00304 * Remember if any of the parents have a window region. 00305 */ 00306 if (pwndParent->hrgnClip != NULL) 00307 fRgnParent = TRUE; 00308 00309 /* 00310 * Intersect the parent's client rectangle with the window rectangle. 00311 */ 00312 if (!IntersectRect(&rcWindow, &rcWindow, &pwndParent->rcClient)) 00313 goto NullRegion; 00314 00315 pwndParent = pwndParent->spwndParent; 00316 } 00317 00318 /* 00319 * Initialize the VisRgn memory-buffer. This is 00320 * used to hold the pwnd's. 00321 */ 00322 gapwndVisDefault = apwndVisDefault; 00323 gapwndVisExclude = gapwndVisDefault; 00324 gcrcVisExcludeMax = ARRAY_SIZE(apwndVisDefault); 00325 gcrcVisExclude = 0; 00326 00327 /* 00328 * Build the list of exclude-rects. 00329 */ 00330 fClipSiblings = (BOOL)(flags & DCX_CLIPSIBLINGS); 00331 pwndParent = pwnd->spwndParent; 00332 pwndLoop = pwnd; 00333 00334 while (pwndParent != pwndRoot) { 00335 00336 /* 00337 * Don't exclude siblings of a layered window when calculating 00338 * the virgn of a layered redirection DC. We must always have 00339 * a complete image of this window in the redirection bitmap. 00340 */ 00341 if ((flags & DCX_LAYERED) && FLayeredOrRedirected(pwndLoop)) { 00342 fClipSiblings = FALSE; 00343 } 00344 00345 /* 00346 * Exclude any siblings if necessary. 00347 */ 00348 if (fClipSiblings && (pwndParent->spwndChild != pwndLoop)) { 00349 00350 if (!ExcludeWindowRects(pwndParent->spwndChild, 00351 pwndLoop, 00352 &rcWindow)) { 00353 00354 goto NullRegion; 00355 } 00356 } 00357 00358 00359 /* 00360 * Set this flag for next time through the loop... 00361 */ 00362 fClipSiblings = TestWF(pwndParent, WFCLIPSIBLINGS); 00363 00364 pwndLoop = pwndParent; 00365 pwndParent = pwndLoop->spwndParent; 00366 } 00367 00368 if ((flags & DCX_CLIPCHILDREN) && (pwnd->spwndChild != NULL)) { 00369 00370 if (!ExcludeWindowRects(pwnd->spwndChild, NULL, &rcWindow)) { 00371 goto NullRegion; 00372 } 00373 } 00374 00375 /* 00376 * If there are rectangles to exclude call GDI to create 00377 * a region excluding them from the window rectangle. If 00378 * not simply call GreSetRectRgn(). 00379 */ 00380 if (gcrcVisExclude > 0) { 00381 00382 RECT arcVisRects[CEXCLUDERECTSMAX]; 00383 PRECT arcExclude; 00384 int i; 00385 int ircVisExclude = 0; 00386 int irgnVisExclude = 0; 00387 00388 /* 00389 * If we need to exclude more rectangles than fit in 00390 * the pre-allocated buffer, obviously we have to 00391 * allocate one that's big enough. 00392 */ 00393 00394 if (gcrcVisExclude <= CEXCLUDERECTSMAX) { 00395 arcExclude = arcVisRects; 00396 } else { 00397 arcExclude = (PRECT)UserAllocPoolWithQuota( 00398 sizeof(RECT) * gcrcVisExclude, TAG_VISRGN); 00399 00400 if (!arcExclude) 00401 goto NullRegion; 00402 } 00403 00404 /* 00405 * Now run through the list and put the 00406 * window rectangles into the array for the call 00407 * to CombineRgnRectList(). 00408 */ 00409 for (i = 0; i < gcrcVisExclude; i++) { 00410 00411 /* 00412 * If the window has a clip-rgn associated with 00413 * it, then re-use gpwneExcludeList[] entries for 00414 * storing them. 00415 */ 00416 if (gapwndVisExclude[i]->hrgnClip != NULL) { 00417 00418 gapwndVisExclude[irgnVisExclude++] = gapwndVisExclude[i]; 00419 continue; 00420 } 00421 00422 /* 00423 * This window doesn't have a clipping region; remember its 00424 * rect for clipping purposes. 00425 */ 00426 arcExclude[ircVisExclude++] = gapwndVisExclude[i]->rcWindow; 00427 } 00428 00429 if (*phrgn == NULL) 00430 *phrgn = CreateEmptyRgn(); 00431 00432 if (ircVisExclude != 0) { 00433 GreSubtractRgnRectList(*phrgn, 00434 &rcWindow, 00435 arcExclude, 00436 ircVisExclude); 00437 } else { 00438 SetRectRgnIndirect(*phrgn, &rcWindow); 00439 } 00440 00441 for (i = 0; i < irgnVisExclude; i++) { 00442 00443 SetRectRgnIndirect(ghrgnInv2, &gapwndVisExclude[i]->rcWindow); 00444 IntersectRgn(ghrgnInv2, ghrgnInv2, gapwndVisExclude[i]->hrgnClip); 00445 00446 if (SubtractRgn(*phrgn, *phrgn, ghrgnInv2) == NULLREGION) 00447 break; 00448 } 00449 00450 if (arcExclude != arcVisRects) { 00451 UserFreePool((HLOCAL)arcExclude); 00452 } 00453 00454 } else { 00455 00456 /* 00457 * If the window was somehow destroyed, then we will return 00458 * a null-region. Emptying the rect will accomplish this. 00459 */ 00460 if (TestWF(pwnd, WFDESTROYED)) { 00461 SetRectEmpty(&rcWindow); 00462 } 00463 00464 /* 00465 * If there weren't any rectangles to exclude, simply call 00466 * GreSetRectRgn() with the window rectangle. 00467 */ 00468 SetOrCreateRectRgnIndirectPublic(phrgn, &rcWindow); 00469 } 00470 00471 /* 00472 * Clip out this window's window region 00473 */ 00474 if (pwnd->hrgnClip != NULL) { 00475 IntersectRgn(*phrgn, *phrgn, pwnd->hrgnClip); 00476 } 00477 00478 /* 00479 * Clip out parent's window regions, if there are any. 00480 */ 00481 if (fRgnParent) { 00482 00483 PWND pwndT; 00484 00485 for (pwndT = pwnd->spwndParent; 00486 pwndT != pwndRoot; 00487 pwndT = pwndT->spwndParent) { 00488 00489 if (pwndT->hrgnClip != NULL) { 00490 00491 if (IntersectRgn(*phrgn, *phrgn, pwndT->hrgnClip) == NULLREGION) 00492 break; 00493 } 00494 } 00495 } 00496 00497 fResult = TRUE; 00498 // fall-through 00499 00500 Cleanup: 00501 if (gfVisAlloc) { 00502 UserFreePool((HLOCAL)gapwndVisExclude); 00503 gfVisAlloc = FALSE; 00504 } 00505 00506 return fResult; 00507 00508 NullRegion: 00509 SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT)); 00510 fResult = FALSE; 00511 goto Cleanup; 00512 } 00513 00514 /***************************************************************************\ 00515 * CalcVisRgn 00516 * 00517 * Will return FALSE if the pwndOrg is not visible, TRUE otherwise. 00518 * 00519 * History: 00520 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00521 \***************************************************************************/ 00522 00523 BOOL CalcVisRgn( 00524 HRGN *phrgn, 00525 PWND pwndOrg, 00526 PWND pwndClip, 00527 DWORD flags) 00528 { 00529 PDESKTOP pdesk; 00530 00531 UserAssert(pwndOrg != NULL); 00532 00533 /* 00534 * If the window's not visible or is not an active desktop, 00535 * or if the clip window is in the process of being destroyed, 00536 * the visrgn is empty. 00537 */ 00538 pdesk = pwndOrg->head.rpdesk; 00539 00540 UserAssert(pdesk); 00541 00542 /* 00543 * Make sure this happens in the IO windowstation 00544 */ 00545 #if DBG 00546 if (grpdeskRitInput != NULL) { 00547 UserAssert(pdesk->rpwinstaParent == grpdeskRitInput->rpwinstaParent || 00548 !IsVisible(pwndOrg)); 00549 } 00550 #endif // DBG 00551 00552 if (!IsVisible(pwndOrg) || pdesk != grpdeskRitInput) { 00553 goto EmptyRgn; 00554 } 00555 00556 /* 00557 * If LockWindowUpdate() has been called, and this window is a child 00558 * of the lock window, always return an empty visrgn. 00559 */ 00560 if ((gspwndLockUpdate != NULL) && 00561 !(flags & DCX_LOCKWINDOWUPDATE) && 00562 _IsDescendant(gspwndLockUpdate, pwndOrg)) { 00563 00564 goto EmptyRgn; 00565 } 00566 00567 /* 00568 * Now go compute the visrgn for pwndClip. 00569 */ 00570 return CalcWindowVisRgn(pwndClip, phrgn, flags); 00571 00572 EmptyRgn: 00573 SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT)); 00574 return FALSE; 00575 } 00576 00577 /***************************************************************************\ 00578 * CalcWindowRgn 00579 * 00580 * 00581 * History: 00582 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00583 \***************************************************************************/ 00584 00585 int CalcWindowRgn( 00586 PWND pwnd, 00587 HRGN hrgn, 00588 BOOL fClient) 00589 { 00590 SetRectRgnIndirect(hrgn, (fClient) ? &pwnd->rcClient : &pwnd->rcWindow); 00591 00592 /* 00593 * If the window has a region, then intersect the rectangle region with 00594 * that. If this is low on memory, it'll propagate ERROR back. 00595 */ 00596 if (pwnd->hrgnClip != NULL) { 00597 return IntersectRgn(hrgn, hrgn, pwnd->hrgnClip); 00598 } 00599 00600 return SIMPLEREGION; 00601 }

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