|
|
/****************************** Module Header ******************************\
* Module Name: visrgn.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains User's visible region ('visrgn') manipulation * functions. * * History: * 23-Oct-1990 DarrinM Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Globals used to keep track of pwnds which * need to be excluded from the visrgns. */ #define CEXCLUDERECTSMAX 30
#define CEXCLUDEPWNDSMAX 30
BOOL gfVisAlloc; int gcrcVisExclude; int gcrcVisExcludeMax; PWND *gapwndVisExclude; PWND *gapwndVisDefault;
/***************************************************************************\
* SetRectRgnIndirect * * Sets a rect region from a rectangle. * * History: * 26-Sep-1996 adams Created. \***************************************************************************/
BOOL SetRectRgnIndirect(HRGN hrgn, LPCRECT lprc) { return GreSetRectRgn(hrgn, lprc->left, lprc->top, lprc->right, lprc->bottom); }
/***************************************************************************\
* CreateEmptyRgn * * Creates an empty region. * * History: * 24-Sep-1996 adams Created. \***************************************************************************/
HRGN CreateEmptyRgn(void) { return GreCreateRectRgnIndirect(PZERO(RECT)); }
/***************************************************************************\
* CreateEmptyRgnPublic * * Creates an empty region and make it public. * * History: * 24-Sep-1996 adams Created. \***************************************************************************/
HRGN CreateEmptyRgnPublic(void) { HRGN hrgn;
if (hrgn = CreateEmptyRgn()) { UserVerify(GreSetRegionOwner(hrgn, OBJECT_OWNER_PUBLIC)); }
return hrgn; }
/***************************************************************************\
* SetEmptyRgn * * Sets an empty region. * * History: * 26-Sep-1996 adams Created. \***************************************************************************/
BOOL SetEmptyRgn(HRGN hrgn) { return SetRectRgnIndirect(hrgn, PZERO(RECT)); }
/***************************************************************************\
* SetOrCreateRectRgnIndirectPublic * * Sets a region to a rectangle, creating it and making it public * if it is not already there. * * History: * 01-Oct-1996 adams Created. \***************************************************************************/
HRGN SetOrCreateRectRgnIndirectPublic(HRGN * phrgn, LPCRECT lprc) { if (*phrgn) { UserVerify(SetRectRgnIndirect(*phrgn, lprc)); } else if (*phrgn = GreCreateRectRgnIndirect((LPRECT) lprc)) { UserVerify(GreSetRegionOwner(*phrgn, OBJECT_OWNER_PUBLIC)); }
return *phrgn; }
/***************************************************************************\
* ResizeVisExcludeMemory * * This routine is used to resize the vis-rgn memory buffer if the count * is exceeded. * * * History: * 22-Oct-1994 ChrisWil Created * 27-Feb-1997 adams Removed call to UserReallocPool, since the pool * allocator doesn't support realloc. \***************************************************************************/
BOOL ResizeVisExcludeMemory(VOID) { int crcNew; PWND apwndNew;
/*
* Note (adams): a previous version of the code called UserReallocPool * if memory had already been allocated. Unfortunately, UserReallocPool * just has to allocate more memory and copy the contents, since Rtl * doesn't have a realloc function. If Rtl later gains a Realloc function, * this code should be changed to the previous version. */
crcNew = gcrcVisExcludeMax + CEXCLUDEPWNDSMAX; apwndNew = (PWND)UserAllocPool( crcNew * sizeof(PWND), TAG_VISRGN);
if (!apwndNew) return FALSE;
UserAssert(gcrcVisExcludeMax == gcrcVisExclude); RtlCopyMemory(apwndNew, gapwndVisExclude, gcrcVisExcludeMax * sizeof(PWND)); if (gfVisAlloc) { UserFreePool(gapwndVisExclude); } else { gfVisAlloc = TRUE; }
gcrcVisExcludeMax = crcNew; gapwndVisExclude = (PWND *)apwndNew; return TRUE; }
/***************************************************************************\
* ExcludeWindowRects * This routine checks to see if the pwnd needs to be added to the list * of excluded-clip-rects. If so, it appends the pwnd to the array. They * do not need to be sorted, since GreSubtractRgnRectList() sorts them * internally. * * * History: * 05-Nov-1992 DavidPe Created. * 21-Oct-1994 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds. \***************************************************************************/
#define CheckIntersectRect(prc1, prc2) \
( prc1->left < prc2->right \ && prc2->left < prc1->right \ && prc1->top < prc2->bottom \ && prc2->top < prc1->bottom)
#define EmptyRect(prc) \
( prc->left >= prc->right \ || prc->top >= prc->bottom)
BOOL ExcludeWindowRects( PWND pwnd , PWND pwndStop, LPRECT lprcIntersect) { PRECT prc;
#if DBG
if (pwnd != NULL && pwndStop != NULL && pwnd->spwndParent != pwndStop->spwndParent) { RIPMSG0(RIP_ERROR, "ExcludeWindowRects: bad windows passed in"); } #endif
while ((pwnd != NULL) && (pwnd != pwndStop)) { UserAssert(pwnd); prc = &pwnd->rcWindow; if ( TestWF(pwnd, WFVISIBLE) #ifdef REDIRECTION
&& (TestWF(pwnd, WEFEXTREDIRECTED) == 0) #endif // REDIRECTION
&& (TestWF(pwnd, WEFLAYERED) == 0) && (TestWF(pwnd, WEFTRANSPARENT) == 0) && CheckIntersectRect(lprcIntersect, prc) && !EmptyRect(prc)) {
UserAssert(gcrcVisExclude <= gcrcVisExcludeMax); if (gcrcVisExclude == gcrcVisExcludeMax) { if (!ResizeVisExcludeMemory()) { return FALSE; } }
gapwndVisExclude[gcrcVisExclude++] = pwnd; }
pwnd = pwnd->spwndNext; }
return TRUE; }
/***************************************************************************\
* CalcWindowVisRgn * * This routine performs the work of calculating the VisRgn for a window. * * * History: * 02-Nov-1992 DavidPe Created. * 21-Oct-1992 ChrisWil Removed pwnd->pwndNextYX. No longer sorts pwnds. \***************************************************************************/
BOOL CalcWindowVisRgn( PWND pwnd, HRGN *phrgn, DWORD flags) { RECT rcWindow; PWND pwndParent; PWND pwndRoot; PWND pwndLoop; BOOL fClipSiblings; BOOL fRgnParent = FALSE; BOOL fResult; PWND apwndVisDefault[CEXCLUDEPWNDSMAX];
/*
* First get the initial window rectangle which will be used for * the basis of exclusion calculations. */ rcWindow = (flags & DCX_WINDOW ? pwnd->rcWindow : pwnd->rcClient);
/*
* Get the parent of this window. We start at the parent and backtrack * through the window-parent-list until we reach the end of the parent- * list. This will give us the intersect-rectangle which is used as * the basis for checking intersection of the exclusion rects. */ pwndRoot = pwnd->head.rpdesk->pDeskInfo->spwnd->spwndParent; pwndParent = pwnd->spwndParent;
/*
* The parent can be NULL in the case when pwnd == pwndRoot. In other * cases we should figure why the parent is NULL. */ if (pwndParent == NULL) { #if DBG
if (pwnd != pwndRoot) { RIPMSG0(RIP_ERROR, "CalcWindowVisRgn: pwndParent is NULL"); } #endif
goto NullRegion; }
while (pwndParent != pwndRoot) {
/*
* Don't clip layered DCs to the desktop. The surface of the layered * DC is the size of the window and we always want to have the image * of the entire window in that surface. */ if ((flags & DCX_REDIRECTED) && (GETFNID(pwndParent) == FNID_DESKTOP)) break;
/*
* Remember if any of the parents have a window region. */ if (pwndParent->hrgnClip != NULL) fRgnParent = TRUE;
/*
* Intersect the parent's client rectangle with the window rectangle. */ if (!IntersectRect(&rcWindow, &rcWindow, &pwndParent->rcClient)) goto NullRegion;
pwndParent = pwndParent->spwndParent; }
/*
* Initialize the VisRgn memory-buffer. This is * used to hold the pwnd's. */ gapwndVisDefault = apwndVisDefault; gapwndVisExclude = gapwndVisDefault; gcrcVisExcludeMax = ARRAY_SIZE(apwndVisDefault); gcrcVisExclude = 0;
/*
* Build the list of exclude-rects. */ fClipSiblings = (BOOL)(flags & DCX_CLIPSIBLINGS); pwndParent = pwnd->spwndParent; pwndLoop = pwnd;
while (pwndParent != pwndRoot) { /*
* If we reach a redirected window, we can stop excluding any * siblings any siblings of any parents. */ if ((flags & DCX_REDIRECTED) && TestWF(pwndLoop, WEFPREDIRECTED)) { break; }
/*
* Exclude any siblings if necessary. */ if (fClipSiblings && (pwndParent->spwndChild != pwndLoop)) {
if (!ExcludeWindowRects(pwndParent->spwndChild, pwndLoop, &rcWindow)) {
goto NullRegion; } }
/*
* Set this flag for next time through the loop... */ fClipSiblings = TestWF(pwndParent, WFCLIPSIBLINGS);
pwndLoop = pwndParent; pwndParent = pwndLoop->spwndParent; }
if ((flags & DCX_CLIPCHILDREN) && (pwnd->spwndChild != NULL)) {
if (!ExcludeWindowRects(pwnd->spwndChild, NULL, &rcWindow)) { goto NullRegion; } }
/*
* If there are rectangles to exclude call GDI to create * a region excluding them from the window rectangle. If * not simply call GreSetRectRgn(). */ if (gcrcVisExclude > 0) {
RECT arcVisRects[CEXCLUDERECTSMAX]; PRECT arcExclude; int i; int ircVisExclude = 0; int irgnVisExclude = 0;
/*
* If we need to exclude more rectangles than fit in * the pre-allocated buffer, obviously we have to * allocate one that's big enough. */
if (gcrcVisExclude <= CEXCLUDERECTSMAX) { arcExclude = arcVisRects; } else { arcExclude = (PRECT)UserAllocPoolWithQuota( sizeof(RECT) * gcrcVisExclude, TAG_VISRGN);
if (!arcExclude) goto NullRegion; }
/*
* Now run through the list and put the * window rectangles into the array for the call * to CombineRgnRectList(). */ for (i = 0; i < gcrcVisExclude; i++) {
/*
* If the window has a clip-rgn associated with * it, then re-use gpwneExcludeList[] entries for * storing them. */ if (gapwndVisExclude[i]->hrgnClip != NULL) {
gapwndVisExclude[irgnVisExclude++] = gapwndVisExclude[i]; continue; }
/*
* This window doesn't have a clipping region; remember its * rect for clipping purposes. */ arcExclude[ircVisExclude++] = gapwndVisExclude[i]->rcWindow; }
if (*phrgn == NULL) *phrgn = CreateEmptyRgn();
if (ircVisExclude != 0) { GreSubtractRgnRectList(*phrgn, &rcWindow, arcExclude, ircVisExclude); } else { SetRectRgnIndirect(*phrgn, &rcWindow); }
for (i = 0; i < irgnVisExclude; i++) {
SetRectRgnIndirect(ghrgnInv2, &gapwndVisExclude[i]->rcWindow); IntersectRgn(ghrgnInv2, ghrgnInv2, gapwndVisExclude[i]->hrgnClip);
if (SubtractRgn(*phrgn, *phrgn, ghrgnInv2) == NULLREGION) break; }
if (arcExclude != arcVisRects) { UserFreePool((HLOCAL)arcExclude); }
} else {
/*
* If the window was somehow destroyed, then we will return * a null-region. Emptying the rect will accomplish this. */ if (TestWF(pwnd, WFDESTROYED)) { SetRectEmpty(&rcWindow); }
/*
* If there weren't any rectangles to exclude, simply call * GreSetRectRgn() with the window rectangle. */ SetOrCreateRectRgnIndirectPublic(phrgn, &rcWindow); }
/*
* Clip out this window's window region */ if (pwnd->hrgnClip != NULL) { IntersectRgn(*phrgn, *phrgn, pwnd->hrgnClip); }
/*
* Clip out parent's window regions, if there are any. */ if (fRgnParent) {
PWND pwndT;
for (pwndT = pwnd->spwndParent; pwndT != pwndRoot; pwndT = pwndT->spwndParent) {
if (pwndT->hrgnClip != NULL) {
if (IntersectRgn(*phrgn, *phrgn, pwndT->hrgnClip) == NULLREGION) break; } } }
fResult = TRUE; // fall-through
Cleanup: if (gfVisAlloc) { UserFreePool((HLOCAL)gapwndVisExclude); gfVisAlloc = FALSE; }
return fResult;
NullRegion: SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT)); fResult = FALSE; goto Cleanup; }
/***************************************************************************\
* CalcVisRgn * * Will return FALSE if the pwndOrg is not visible, TRUE otherwise. * * History: * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
BOOL CalcVisRgn( HRGN *phrgn, PWND pwndOrg, PWND pwndClip, DWORD flags) { PDESKTOP pdesk;
UserAssert(pwndOrg != NULL);
/*
* If the window's not visible or is not an active desktop, * or if the clip window is in the process of being destroyed, * the visrgn is empty. */ pdesk = pwndOrg->head.rpdesk; UserAssert(pdesk); /*
* Make sure this happens in the IO windowstation */ #if DBG
if (grpdeskRitInput != NULL) { UserAssert(pdesk->rpwinstaParent == grpdeskRitInput->rpwinstaParent || !IsVisible(pwndOrg)); } #endif // DBG
/*
* For redirected windows, if it is on the non I/O desktop, we still need * to pass the application a non empty region in order to update the bitmap * Otherwise, the bitmap will never got the chance to be updated and we will end up * rendering a black window region (for the case of layered windows) by the time * we switch to this desktop. (see bug# 287315). Note that this will not render the window on the screen * because the call to CalcVisRgn from UserVisrgnFromHwnd() should never specify * DCX_REDIRECTEDBITMAP. */ #if DBG
if (!TestWF(pwndOrg, WEFPREDIRECTED)) { UserAssert(!(flags & DCX_REDIRECTEDBITMAP)); } #endif
if (!IsVisible(pwndOrg) || ((pdesk != grpdeskRitInput) && !(flags & DCX_REDIRECTEDBITMAP))) { goto EmptyRgn; }
/*
* If LockWindowUpdate() has been called, and this window is a child * of the lock window, always return an empty visrgn. */ if ((gspwndLockUpdate != NULL) && !(flags & DCX_LOCKWINDOWUPDATE) && _IsDescendant(gspwndLockUpdate, pwndOrg)) {
goto EmptyRgn; }
/*
* Now go compute the visrgn for pwndClip. */ return CalcWindowVisRgn(pwndClip, phrgn, flags);
EmptyRgn: SetOrCreateRectRgnIndirectPublic(phrgn, PZERO(RECT)); return FALSE; }
/***************************************************************************\
* CalcWindowRgn * * * History: * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
int CalcWindowRgn( PWND pwnd, HRGN hrgn, BOOL fClient) { SetRectRgnIndirect(hrgn, (fClient) ? &pwnd->rcClient : &pwnd->rcWindow);
/*
* If the window has a region, then intersect the rectangle region with * that. If this is low on memory, it'll propagate ERROR back. */ if (pwnd->hrgnClip != NULL) { return IntersectRgn(hrgn, hrgn, pwnd->hrgnClip); }
return SIMPLEREGION; }
|