|
|
/**************************** Module Header ********************************\
* Module Name: spb.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Save Popup Bits (SPB) support routines. * * History: * 18-Jul-1991 DarrinM Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* FBitsTouch * * This routine checkes to see if the rectangle *lprcDirty in pwndDirty * invalidates any bits in the SPB structure at *pspb. * * pwndDirty "touches" pwndSpb if: * 1. pwndDirty is visible AND: * 2. pwndDirty == or descendent of pwndSpb, and pwndSpb is a LOCKUPDATE * spb. * 3. pwndDirty is pwndSpb's parent. (e.g., drawing in the * desktop window, behind a dialog box). * 4. A parent of pwndDirty is the sibling of pwndSpb, and the parent * is lower in the zorder. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
BOOL FBitsTouch( PWND pwndDirty, LPRECT lprcDirty, PSPB pspb, DWORD flags) { PWND pwndSpb, pwndDirtySave; int fSpbLockUpdate;
/*
* When no window is passed in, skip all the window-related stuff and * go directly to check the rectangle. */ if (pwndDirty == NULL) goto ProbablyTouch;
/*
* If pwndDirty or its parents are invisible, * then it can't invalidate any SPBs */ if (!IsVisible(pwndDirty)) return FALSE;
pwndSpb = pspb->spwnd; fSpbLockUpdate = pspb->flags & SPB_LOCKUPDATE; if (fSpbLockUpdate) {
/*
* If the guy is drawing through a locked window via * DCX_LOCKWINDOWUPDATE and the spb is a LOCKUPDATE SPB, then * don't do any invalidation of the SPB. Basically we're trying * to avoid having the tracking rectangle invalidate the SPB * since it's drawn via a WinGetClipPS() ps. */ if (flags & DCX_LOCKWINDOWUPDATE) return FALSE; }
/*
* If pwndDirty is pwndSpb's immediate parent (e.g., drawing in the * desktop window behind a dialog box), then we may touch: do the * intersection. */ if (pwndDirty == pwndSpb->spwndParent) goto ProbablyTouch;
/*
* We know that pwndDirty != pwndSpb->spwndParent. * Now find the parent of pwndDirty that is a sibling of pwndSpb. */ pwndDirtySave = pwndDirty;
while (pwndSpb->spwndParent != pwndDirty->spwndParent) { pwndDirty = pwndDirty->spwndParent;
/*
* If we get to the top of the tree, it's because: * 1. pwndSpb == pwndDesktop * 2. pwndDirty is a parent of pwndSpb * 3. pwndDirty == pwndDesktop * 4. pwndDirty is a child of some other desktop * 5. pwndSpb and pwndDirty aren't siblings * * In all these cases, pwndDirty can't touch pwndSpb. */ if (pwndDirty == NULL) return FALSE; }
/*
* If pwndSpb is the same as pwndDirty, then it will invalidate * only if the SPB is LOCKUPDATE. * * Non-LOCKUPDATE SPB's can't be invalidated by their * own windows, but LOCKUPDATE SPB's can. */ if (pwndDirty == pwndSpb) { if (!fSpbLockUpdate) return FALSE;
/*
* If pwndSpb itself was drawn in, then we can't * try subtracting children. */ if (pwndDirtySave == pwndSpb) goto ProbablyTouch;
/*
* We want to calculate the immediate child of pwndSpb * on the path from pwndDirty to pwndSpb, so we can * subtract off the rectangles of the children of pwndSpb * in case there are intervening windows. */ while (pwndSpb != pwndDirtySave->spwndParent) { pwndDirtySave = pwndDirtySave->spwndParent; }
/*
* The SubtractIntervening loop subtracts the * window rects starting from pwndSpb and ending * at the window before pwndDirty, so set up * our variables appropriately. */ pwndDirty = pwndDirtySave; pwndSpb = pwndSpb->spwndChild;
} else { /*
* Now compare the Z order of pwndDirty and pwndSpb. * If pwndDirty is above pwndSpb, then the SPB can't be touched. */ pwndDirtySave = pwndDirty;
/*
* Compare the Z order by searching starting at pwndDirty, * moving DOWN the Z order list. If we encounter pwndSpb, * then pwndDirty is ABOVE or EQUAL to pwndSpb. */ for ( ; pwndDirty != NULL; pwndDirty = pwndDirty->spwndNext) { if (pwndDirty == pwndSpb) { return FALSE; } } pwndDirty = pwndDirtySave;
/*
* We don't want to subtract the SPB window itself */ pwndSpb = pwndSpb->spwndNext; }
/*
* Subtract Intervening rectangles. * pwndDirty is below pwndSpb. If there are any intervening * windows, subtract their window rects from lprcDirty to see if pwndDirty * is obscured. */ while (pwndSpb && pwndSpb != pwndDirty) { /*
* If this window has a region selected, hwndDirty may draw through * it even though it has a full rectangle! We can't subtract its * rect from the dirty rect in this case. */ if ( TestWF(pwndSpb, WFVISIBLE) && !pwndSpb->hrgnClip && !TestWF(pwndSpb, WEFLAYERED) && !SubtractRect(lprcDirty, lprcDirty, &pwndSpb->rcWindow)) {
return FALSE; }
pwndSpb = pwndSpb->spwndNext; }
// fall through
ProbablyTouch:
/*
* If the rectangles don't intersect, there is no invalidation. * (we make this test relatively late because it's expensive compared * to the tests above). * Otherwise, *lprcDirty now has the area of bits not obscured * by intervening windows. */
return IntersectRect(lprcDirty, lprcDirty, &pspb->rc); }
/***************************************************************************\
* SpbCheckRect2 * * Subtracts lprc in pwnd from pspb's region if lprc touches pspb. * * Returns FALSE if there is a memory allocation error, or if lprc * contains psbp's region; otherwise, returns TRUE. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
BOOL SpbCheckRect2( PSPB pspb, PWND pwnd, LPRECT lprc, DWORD flags) { RECT rcTouch = *lprc;
/*
* See if lprc touches any saved bits, taking into account what * window the drawing is occuring in. */ if (FBitsTouch(pwnd, &rcTouch, pspb, flags)) {
/*
* If no SPB region exists, make one for the whole thing */ if (!pspb->hrgn && SetOrCreateRectRgnIndirectPublic( &pspb->hrgn, &pspb->rc) == ERROR) {
goto Error; }
/*
* Subtract the rectangle that is invalid from the SPB region */ SetRectRgnIndirect(ghrgnSCR, &rcTouch); switch (SubtractRgn(pspb->hrgn, pspb->hrgn, ghrgnSCR)) { case ERROR: case NULLREGION: goto Error;
default: break; } }
return TRUE;
Error: FreeSpb(pspb); return FALSE; }
/***************************************************************************\
* SpbTransfer * * Validate the SPB rectangle from a window's update region, after * subtracting the window's update region from the SPB. * * NOTE: Although SpbTransfer calls xxxInternalInvalidate, it doesn't * specify any flags that will cause immediate updating. Therefore the * critsect isn't left and we don't consider this an 'xxx' routine. * Also, no revalidation is necessary. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
BOOL SpbTransfer( PSPB pspb, PWND pwnd, BOOL fChildren) { RECT rc;
/*
* If the window has an update region... */ if (pwnd->hrgnUpdate != NULL) {
/*
* Invalidate its update region rectangle from the SPB */ if (pwnd->hrgnUpdate > HRGN_FULL) { GreGetRgnBox(pwnd->hrgnUpdate, &rc); } else { rc = pwnd->rcWindow; }
/*
* Intersect the update region bounds with the parent client rects, * to make sure we don't invalidate more than we need to. If * nothing to validate, return TRUE (because SPB is probably not empty) * These RDW_ flags won't cause the critical section to be left, nor * will they provoke WinEvent notifications. */ if (IntersectWithParents(pwnd, &rc)) { BEGINATOMICCHECK();
xxxInternalInvalidate(pwnd, ghrgnSPB2, RDW_VALIDATE | RDW_NOCHILDREN);
ENDATOMICCHECK();
/*
* If the SPB vanished, return FALSE. */ if (!SpbCheckRect2(pspb, pwnd, &rc, DCX_WINDOW)) return FALSE; } }
if (fChildren) { for (pwnd = pwnd->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) { if (!SpbTransfer(pspb, pwnd, TRUE)) { return FALSE; } } }
return TRUE; }
/***************************************************************************\
* CreateSpb * * This function, called after the window is created but before it is visible, * saves the contents of the screen where the window will be drawn in a SPB * structure, and links the structure into a linked list of SPB structures. * popup bits. This routine is called from SetWindowPos. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID CreateSpb( PWND pwnd, UINT flags, HDC hdcScreen) { PSPB pspb; int fSpbLockUpdate;
/*
* Non-LOCKWINDOWUPDATE SPBs can only be created for top-level windows. * * This is because of the way that the display driver RestoreBits function * works. It can put bits down in places that aren't even part of the * window's visrgn, and these bits need to be invalidated. The * SetWindowPos() code to handle this case only knows how to invalidate * one of windows (i.e., the window's immediate parent), but all levels * need to get invalidated. See also the comments in wmswp.c, near the * call to RestoreSpb(). * * For example: the Q&E app brings up a copyright dialog that is a child * of its main window. While this is up, the user alt-f alt-l to execute * the file login command, which brings up another dialog that is a child * of the desktop. When the copyright dialog goes away, the display driver * restores bits on top of the second dialog. The SWP code knows to * invalidate the bogus stuff in the main window, but not in the desktop. * * LOCKUPDATE SPBs are fine, because they don't call RestoreBits. */ fSpbLockUpdate = flags & SPB_LOCKUPDATE; if ( !fSpbLockUpdate && pwnd->spwndParent != NULL && pwnd->spwndParent != PWNDDESKTOP(pwnd)) {
return; }
/*
* We go and check all the existing DCs at this point, to handle the * case where we're saving an image of a window that has a "dirty" * DC, which would eventually invalidate our saved image (but which * is really okay). */ if (AnySpbs()) {
SpbCheck();
} else {
PDCE pdce;
/*
* Reset the dirty areas of all of the DC's and enable * bounds accumulation. We're creating a SPB now. This * is only done if there are no other SPB's in the list. */ GreLockDisplay(gpDispInfo->hDev);
for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
if (pdce->DCX_flags & DCX_REDIRECTED) continue;
GreGetBounds(pdce->hdc, NULL, GGB_ENABLE_WINMGR); }
GreUnlockDisplay(gpDispInfo->hDev); }
/*
* Create the save popup bits structure */ pspb = (PSPB)UserAllocPoolWithQuota(sizeof(SPB), TAG_SPB); if (!pspb) return;
pspb->spwnd = NULL; pspb->rc = pwnd->rcWindow;
/*
* Clip to the screen */ if (!IntersectRect(&pspb->rc, &pspb->rc, &gpDispInfo->rcScreen)) goto BMError;
pspb->hrgn = NULL; pspb->hbm = NULL; pspb->flags = flags; Lock(&(pspb->spwnd), pwnd);
if (!fSpbLockUpdate) {
RECT rc = pspb->rc;
if (!SYSMET(SAMEDISPLAYFORMAT)) { PMONITOR pMonitor = _MonitorFromRect(&pspb->rc, MONITOR_DEFAULTTOPRIMARY); RECT rcT;
/*
* If the intersection with the monitor isn't the entire visible * window rectangle, then bail! We don't save SPBs for windows * that span multiple monitors. Since we do a lot of work to * pin dialogs and menus, there won't be too many of these * babies. */ if (SubtractRect(&rcT, &pspb->rc, &pMonitor->rcMonitor) && GreRectInRegion(gpDispInfo->hrgnScreen, &rcT)) goto BMError2;
/*
* Clip to the window's monitor */ if (!IntersectRect(&pspb->rc, &pspb->rc, &pMonitor->rcMonitor)) goto BMError2;
/*
* dont save bits in a mixed bitdepth situtation * we cant create the exactly correct format bitmap * in all cases (555/565, and Paletized) so as * a cop-out dont save bitmaps at all (on secondaries) * in mixed bit-depth. * * the correct fix is to create a compatible * bitmap for the monitor device and directly * BitBlt() from/to the device (pMonitor->hdcMonitor) * but this involves too much code at this time. */ if (pMonitor != gpDispInfo->pMonitorPrimary) goto BMError2; }
/*
* If this window is a regional window, don't use driver save * bits. Because it can only restore an entire rectangle, * invalid region is calculated assuming the old vis rgn was * rectangular. For regional windows, this would end up always * invalidating the area of (rcWindow - hrgnWindow) every * time an spb would be used. On the other hand, the invalid * area calculated when not using driver save bits is perfect, * because the restore blt can be correctly clipped to begin with. */ if ((pwnd->hrgnClip == NULL) && (pspb->ulSaveId = GreSaveScreenBits(gpDispInfo->hDev, SS_SAVE, 0, (RECTL *)&rc))) {
/*
* Remember that we copied this bitmap into on board memory. */ pspb->flags |= SPB_SAVESCREENBITS;
} else { HBITMAP hbmSave; BOOL bRet;
/*
* The following delta byte-aligns the screen bitmap */ int dx = pspb->rc.left & 0x0007; int cx = pspb->rc.right - pspb->rc.left; int cy = pspb->rc.bottom - pspb->rc.top;
/*
* NOTE: we don't care about setting up a visrgn in * hdcScreen, because BitBlt ignores it on reads. */ pspb->hbm = GreCreateCompatibleBitmap(hdcScreen, cx + dx, cy); if (!pspb->hbm) goto BMError2;
hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm); if (!hbmSave) goto BMError2;
/*
* Copy the contents of the screen to the bitmap in the * save popup bits structure. If we ever find we run * into problems with the screen access check we can * do a bLockDisplay, give this process permission, do * the BitBlt and then take away permission. GDI * accesses the screen and that bit only under the * display semaphore so it is safe. Alternatively * if it is too hard to change this processes permission * here we could do it in GDI by marking the psoSrc * readable temporarily while completing the operation * and then setting it back to unreadable when done. * Or we could just fail it like the CreateCompatibleDC * failed and force a redraw. Basically we can't add * 3K of code in GDI to do a BitBlt that just does 1 * test differently for this 1 place in User. * */ bRet = GreBitBlt(ghdcMem, dx, 0, cx, cy, hdcScreen, pspb->rc.left, pspb->rc.top, 0x00CC0000, 0);
GreSelectBitmap(ghdcMem, hbmSave);
if (!bRet) goto BMError2;
GreSetBitmapOwner(pspb->hbm, OBJECT_OWNER_PUBLIC); }
/*
* Mark that the window has an SPB. */ SetWF(pwnd, WFHASSPB);
/*
* non-LOCKUPDATE SPBs are not invalidated by * drawing in pspb->spwnd, so start the SPB validation * loop below at the sibling immediately below us. */ pwnd = pwnd->spwndNext; }
/*
* Link the new save popup bits structure into the list. */ pspb->pspbNext = gpDispInfo->pspbFirst; gpDispInfo->pspbFirst = pspb;
/*
* Here we deal with any update regions that may be * pending in windows underneath the SPB. * * For all windows that might affect this SPB: * - Subtract the SPB rect from the update region * - Subtract the window from the SPB * * Note that we use pspb->spwnd here, in case it has * no siblings. * * ghrgnSPB2 is the region that is used inside of SpbTransfer to * validate window update regions. Intersect with the window clipping * region, if it exists. Don't want to intersect with the spb rect if * a clipping region exists because we'll end up validating more than * we want to validate. */ SetRectRgnIndirect(ghrgnSPB2, &pspb->rc); if (pspb->spwnd->hrgnClip != NULL) {
/*
* If we get an error bail since an error might result in more * being validated than we want. Since the below code is only an * optimizer, this is ok: the window will remain invalid and will * draw, thereby invalidating the SPB like usual. */ if (IntersectRgn(ghrgnSPB2, ghrgnSPB2, pspb->spwnd->hrgnClip) == ERROR) { return; } }
if (pspb->spwnd->spwndParent == NULL || SpbTransfer(pspb, pspb->spwnd->spwndParent, FALSE)) {
/*
* Do the same for the siblings underneath us... */ for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) { if (!SpbTransfer(pspb, pwnd, TRUE)) break; } }
return;
BMError2: /*
* Error creating the bitmap: clean up and return. */ if (pspb->hbm) GreDeleteObject(pspb->hbm);
Unlock(&pspb->spwnd); // fall-through
BMError: UserFreePool(pspb); }
/***************************************************************************\
* RestoreSpb * * Restores the bits associated with pwnd's SPB onto the screen, clipped * to hrgnUncovered if possible. * * Upon return, hrgnUncovered is modified to contain the part of hrgnUncovered * that must be invalidated by the caller. FALSE is returned if the area * to be invalidated is empty. * * NOTE: Because the device driver SaveBitmap() function can not clip, this * function may write bits into an area of the screen larger than the passed-in * hrgnUncovered. In this case, the returned invalid region may be larger * than the passed-in hrgnUncovered. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
UINT RestoreSpb( PWND pwnd, HRGN hrgnUncovered, HDC *phdcScreen) { PSPB pspb; UINT uInvalidate; HRGN hrgnRestorable;
/*
* Note that we DON'T call SpbCheck() here -- * SpbCheck() is called by zzzBltValidBits(). */ pspb = FindSpb(pwnd);
/*
* Assume all of hrgnUncovered was restored, and there's nothing * for our caller to invalidate. */ uInvalidate = RSPB_NO_INVALIDATE; hrgnRestorable = hrgnUncovered;
/*
* First determine whether or not there is any area at all to restore. * If hrgnUncovered & pspb->hrgn is empty, then all of hrgnUncovered * needs to be invalidated, and there's nothing to restore. */ if (pspb->hrgn != NULL) { /*
* At least some of hrgnUncovered needs to be invalidated. */ uInvalidate = RSPB_INVALIDATE;
/*
* Calculate the true area of bits to be restored. If it becomes * empty, then just free the SPB without changing hrgnUncovered, * which is the area that must be invalidated. */ hrgnRestorable = ghrgnSPB1; switch (IntersectRgn(hrgnRestorable, hrgnUncovered, pspb->hrgn)) { case ERROR: case NULLREGION: goto Error;
default: break; } }
if (pspb->flags & SPB_SAVESCREENBITS) {
RECT rc = pspb->rc;
/*
* Since the restore frees the onboard memory, clear this * bit so FreeSpb() won't try to free it again (regardless of * whether we get an error or not) */ pspb->flags &= ~SPB_SAVESCREENBITS; if (!(GreSaveScreenBits(gpDispInfo->hDev, SS_RESTORE, pspb->ulSaveId, (RECTL *)&rc))) { goto Error; }
/*
* The SS_RESTORE call will always restore the entire SPB * rectangle, part of which may fall outside of hrgnUncovered. * The area that must be invalidated by our caller is simply * the SPB rectangle minus the area of restorable bits. * * If this region is not empty, then the SPB was not completely * restored, so we must return FALSE. */ SetRectRgnIndirect(ghrgnSPB2, &pspb->rc); if (SubtractRgn(hrgnUncovered, ghrgnSPB2, hrgnRestorable) != NULLREGION) { uInvalidate = RSPB_INVALIDATE_SSB; } } else {
HDC hdcScreen; HBITMAP hbmSave;
/*
* In the unlikely event we need a screen DC and one wasn't passed in, * get it now. If we get one, we return the handle in *phdcScreen * so that our caller can release it later. */ if (!*phdcScreen) { *phdcScreen = gpDispInfo->hdcScreen; }
hdcScreen = *phdcScreen;
hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm); if (!hbmSave) goto Error;
/*
* Be sure to clip to the area of restorable bits. */
GreSelectVisRgn(hdcScreen, hrgnRestorable, SVR_COPYNEW);
GreBitBlt(hdcScreen, pspb->rc.left, pspb->rc.top, pspb->rc.right - pspb->rc.left, pspb->rc.bottom - pspb->rc.top, ghdcMem, pspb->rc.left & 0x0007, 0, SRCCOPY, 0);
GreSelectBitmap(ghdcMem, hbmSave);
/*
* Now compute the area to be invalidated for return. * This is simply the original hrgnUncovered - hrgnRestorable */ SubtractRgn(hrgnUncovered, hrgnUncovered, hrgnRestorable); }
if (pwnd->hrgnClip == NULL || !IsVisible(pwnd)) FreeSpb(pspb);
return uInvalidate;
Error: FreeSpb(pspb); return RSPB_INVALIDATE; }
/***************************************************************************\
* LockWindowUpdate2 (API) * * Locks gspwndLockUpdate and it's children from updating. If * gspwndLockUpdate is NULL, then all windows will be unlocked. When * unlocked, the portions of the screen that would have been written to * are invalidated so they get repainted. TRUE is returned if the routine * is successful. * * If called when another app has something locked, then this function fails. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
BOOL LockWindowUpdate2( PWND pwndLock, BOOL fThreadOverride) { PSPB pspb; BOOL fInval; HRGN hrgn; PTHREADINFO ptiCurrent = PtiCurrent();
if ( /*
* If we're full screen right now, fail this call. */ TEST_PUDF(PUDF_LOCKFULLSCREEN)
||
/*
* If the screen is already locked, and it's being locked * by some other app, then fail. If fThreadOverride is set * then we're calling internally and it's okay to cancel * someone elses LockUpdate. */ ( gptiLockUpdate != NULL && gptiLockUpdate != PtiCurrent() && !fThreadOverride)) { UserAssert(IsWinEventNotifyDeferredOK());
RIPERR0(ERROR_SCREEN_ALREADY_LOCKED, RIP_WARNING, "LockWindowUpdate failed because screen is locked by another application.");
return FALSE; }
if ((pwndLock != NULL) == (gptiLockUpdate != NULL)) { if (!fThreadOverride) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "LockWindowUpdate failed because it is already %s.", (pwndLock != NULL) ? "locked" : "unlocked"); }
return FALSE; }
/*
* This must be done while holding the screen critsec. * Deadlock if we callback during this, so defer WinEvent notifications */ DeferWinEventNotify(); GreLockDisplay(gpDispInfo->hDev);
if (pwndLock != NULL) { /*
* We're about to make pwndLock and its siblings invisible: * go invalidate any other affected SPBs. */ SpbCheckPwnd(pwndLock);
CreateSpb(pwndLock, SPB_LOCKUPDATE, NULL);
Lock(&(gspwndLockUpdate), pwndLock); gptiLockUpdate = ptiCurrent;
zzzInvalidateDCCache(pwndLock, IDC_DEFAULT);
} else { /*
* Flush any accumulated rectangles and invalidate spbs. */ SpbCheck();
/*
* Save this in a local before we set it to NULL */ pwndLock = gspwndLockUpdate;
gptiLockUpdate = NULL; Unlock(&gspwndLockUpdate);
zzzInvalidateDCCache(pwndLock, IDC_DEFAULT);
/*
* Assume SPB doesn't exist, or couldn't be created, and that we * must invalidate the entire window. */ fInval = TRUE; hrgn = HRGN_FULL;
/*
* Find the LOCKUPDATE spb in the list, and if present calculate * the area that has been invalidated, if any. */ for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) {
if (pspb->flags & SPB_LOCKUPDATE) {
if (pspb->hrgn == NULL) {
/*
* If no invalid area, then no invalidation needed. */ fInval = FALSE;
} else {
/*
* Subtract SPB valid region from SPB rectangle, to * yield invalid region. */ hrgn = ghrgnSPB1; SetRectRgnIndirect(hrgn, &pspb->rc);
/*
* If spb rect minus the spb valid rgn is empty, * then there is nothing to invalidate. */ fInval = SubtractRgn(hrgn, hrgn, pspb->hrgn) != NULLREGION; }
FreeSpb(pspb);
/*
* Exit this loop (there can be only one LOCKUPDATE spb) */ break; } }
if (fInval) { /*
* When unlocking a Layered window (or a child of a layered * window), we need to invalidate that layered window specifically * or the window will ignore the invalidation request. For regular * windows, we invalidate the desktop instead. */ PWND pwndInvalidate; if ((pwndInvalidate = GetStyleWindow(pwndLock, WEFLAYERED)) == NULL) { pwndInvalidate = PWNDDESKTOP(pwndLock); }
BEGINATOMICCHECK(); // want to prevent WinEvent notifies, but this make break asserts
DeferWinEventNotify(); xxxInternalInvalidate(pwndInvalidate, hrgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); zzzEndDeferWinEventNotify(); ENDATOMICCHECK(); }
/*
* Invalidate any other SPBs affected by the fact that this window * and its children are being made visible. */ SpbCheckPwnd(pwndLock); }
GreUnlockDisplay(gpDispInfo->hDev); zzzEndDeferWinEventNotify();
return TRUE; }
/***************************************************************************\
* FindSpb * * Returns a pointer to the SPB structure associated with the specified * window or NULL if there is no associated structure. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
PSPB FindSpb( PWND pwnd) { PSPB pspb;
/*
* Walk through the list of save popup bits looking for a match on * window handle. */ for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) {
if (pspb->spwnd == pwnd && !(pspb->flags & SPB_LOCKUPDATE)) break; }
return pspb; }
/***************************************************************************\
* SpbCheck * * Modifies all of the save popup bits structures to reflect changes on the * screen. This function walks through all of the DC's, and if the DC is * dirty, then the dirty area is removed from the associated save popup bits * structure. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID SpbCheck(VOID) { PDCE pdce; RECT rcBounds;
if (AnySpbs()) {
GreLockDisplay(gpDispInfo->hDev);
/*
* Walk through all of the DC's, accumulating dirty areas. */ for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
/*
* Only check valid cache entries... */ if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS)) continue;
SpbCheckDce(pdce); }
/*
* Subtact out DirectDraw dirty rect from all the SPB's. The call to * GreGetDirectDrawBounds will also reset the accumulated bounds. */ if (GreGetDirectDrawBounds(gpDispInfo->hDev, &rcBounds)) { SpbCheckRect(NULL, &rcBounds, 0); }
GreUnlockDisplay(gpDispInfo->hDev); } }
/***************************************************************************\
* SpbCheckDce * * This function retrieves the dirty area of a DC and removes the area from * the list of SPB structures. The DC is then marked as clean. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID SpbCheckDce( PDCE pdce) { RECT rc;
if (pdce->DCX_flags & DCX_REDIRECTED) return;
/*
* Query the dirty bounds rectangle. Doing this clears the bounds * as well. */ if (GreGetBounds(pdce->hdc, &rc, 0)) {
if (pdce->pMonitor != NULL) { /*
* Convert the bounds rect to screen coords. */ OffsetRect(&rc, pdce->pMonitor->rcMonitor.left, pdce->pMonitor->rcMonitor.top); }
/*
* Intersect the returned rectangle with the window rectangle * in case the guy was drawing outside his window */ if (IntersectRect(&rc, &rc, &(pdce->pwndOrg)->rcWindow)) SpbCheckRect(pdce->pwndOrg, &rc, pdce->DCX_flags); } }
/***************************************************************************\
* SpbCheckRect * * This function removes the passed rectangle from the SPB structures which * touch it. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID SpbCheckRect( PWND pwnd, LPRECT lprc, DWORD flags) { PSPB pspb, pspbNext;
/*
* If this window isn't visible, we're done. */ if (!IsVisible(pwnd)) return;
for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) {
/*
* Get the pointer to the next save popup bits structure now * in case SpbCheckRect2() frees the current one. */ pspbNext = pspb->pspbNext;
/*
* In win3.1 they used to exit the function if this function * returned false. This meant that if one of the spbs was freed * the rest of the spbs would not be invalidated. */ SpbCheckRect2(pspb, pwnd, lprc, flags); } }
/***************************************************************************\
* SpbCheckPwnd * * This routine checks to see if the window rectangle of PWND affects any SPBs. * It is called if pwnd or its children are being hidden or shown without * going through WinSetWindowPos(). * * Any SPBs for children of pwnd are destroyed. * * It must be called while pwnd is still visible. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID SpbCheckPwnd( PWND pwnd) { PSPB pspb; PWND pwndSpb; PSPB pspbNext;
/*
* First blow away any SPBs owned by this window or its children. */ for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) {
/*
* Get pspbNext now in case we free the SPB */ pspbNext = pspb->pspbNext;
/*
* If pspb->spwnd is == pwnd or a child of pwnd, then free the SPB */ for (pwndSpb = pspb->spwnd; pwndSpb; pwndSpb = pwndSpb->spwndParent) {
if (pwnd == pwndSpb) FreeSpb(pspb); } }
/*
* Then see if any other SPBs are affected... */ if (gpDispInfo->pspbFirst != NULL) { SpbCheckRect(pwnd, &pwnd->rcWindow, 0); } }
/***************************************************************************\
* FreeSpb * * This function deletes the bitmap and region assocaited with a save popup * bits structure and then unlinks and destroys the spb structure itself. * * History: * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. \***************************************************************************/
VOID FreeSpb( PSPB pspb) { PSPB *ppspb; PDCE pdce;
if (pspb == NULL) return;
/*
* Delete the bitmap. If saved in screen memory, make special call. */ if (pspb->flags & SPB_SAVESCREENBITS) { GreSaveScreenBits(gpDispInfo->hDev, SS_FREE, pspb->ulSaveId, NULL); } else if (pspb->hbm != NULL) { GreDeleteObject(pspb->hbm); }
/*
* Destroy the region. */ if (pspb->hrgn != NULL){ GreDeleteObject(pspb->hrgn); }
/*
* Forget that there is an attached SPB. */ if (pspb->spwnd != NULL) { ClrWF(pspb->spwnd, WFHASSPB); Unlock(&pspb->spwnd); }
/*
* Unlink the spb. */ ppspb = &gpDispInfo->pspbFirst; while (*ppspb != pspb) { ppspb = &(*ppspb)->pspbNext; }
*ppspb = pspb->pspbNext;
/*
* Free the save popup bits structure. */ UserFreePool(pspb);
/*
* If we no longer have any SPBs then turn off window MGR * bounds collection. */ if (!AnySpbs()) {
GreLockDisplay(gpDispInfo->hDev);
/*
* Reset the dirty areas of all of the DC's. NULL means reset. */ for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
if (pdce->DCX_flags & DCX_REDIRECTED) continue;
GreGetBounds(pdce->hdc, NULL, GGB_DISABLE_WINMGR); }
GreUnlockDisplay(gpDispInfo->hDev); }
}
/***************************************************************************\
* FreeAllSpbs * * This function deletes all spb-bitmaps. * * History: * 07-Oct-1995 ChrisWil Ported from Chicago. \***************************************************************************/
VOID FreeAllSpbs(void) {
while(AnySpbs()) { FreeSpb(gpDispInfo->pspbFirst); }
gpDispInfo->pspbFirst = NULL; }
|