00001 /**************************** Module Header ********************************\ 00002 * Module Name: spb.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Save Popup Bits (SPB) support routines. 00007 * 00008 * History: 00009 * 18-Jul-1991 DarrinM Created. 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 /***************************************************************************\ 00016 * FBitsTouch 00017 * 00018 * This routine checkes to see if the rectangle *lprcDirty in pwndDirty 00019 * invalidates any bits in the SPB structure at *pspb. 00020 * 00021 * pwndDirty "touches" pwndSpb if: 00022 * 1. pwndDirty is visible AND: 00023 * 2. pwndDirty == or descendent of pwndSpb, and pwndSpb is a LOCKUPDATE 00024 * spb. 00025 * 3. pwndDirty is pwndSpb's parent. (e.g., drawing in the 00026 * desktop window, behind a dialog box). 00027 * 4. A parent of pwndDirty is the sibling of pwndSpb, and the parent 00028 * is lower in the zorder. 00029 * 00030 * History: 00031 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00032 \***************************************************************************/ 00033 00034 BOOL FBitsTouch( 00035 PWND pwndDirty, 00036 LPRECT lprcDirty, 00037 PSPB pspb, 00038 DWORD flags) 00039 { 00040 PWND pwndSpb, 00041 pwndDirtySave; 00042 int fSpbLockUpdate; 00043 00044 /* 00045 * When no window is passed in, skip all the window-related stuff and 00046 * go directly to check the rectangle. 00047 */ 00048 if (pwndDirty == NULL) 00049 goto ProbablyTouch; 00050 00051 /* 00052 * If pwndDirty or its parents are invisible, 00053 * then it can't invalidate any SPBs 00054 */ 00055 if (!IsVisible(pwndDirty)) 00056 return FALSE; 00057 00058 pwndSpb = pspb->spwnd; 00059 fSpbLockUpdate = pspb->flags & SPB_LOCKUPDATE; 00060 if (fSpbLockUpdate) { 00061 00062 /* 00063 * If the guy is drawing through a locked window via 00064 * DCX_LOCKWINDOWUPDATE and the spb is a LOCKUPDATE SPB, then 00065 * don't do any invalidation of the SPB. Basically we're trying 00066 * to avoid having the tracking rectangle invalidate the SPB 00067 * since it's drawn via a WinGetClipPS() ps. 00068 */ 00069 if (flags & DCX_LOCKWINDOWUPDATE) 00070 return FALSE; 00071 } 00072 00073 /* 00074 * If pwndDirty is pwndSpb's immediate parent (e.g., drawing in the 00075 * desktop window behind a dialog box), then we may touch: do the 00076 * intersection. 00077 */ 00078 if (pwndDirty == pwndSpb->spwndParent) 00079 goto ProbablyTouch; 00080 00081 /* 00082 * We know that pwndDirty != pwndSpb->spwndParent. 00083 * Now find the parent of pwndDirty that is a sibling of pwndSpb. 00084 */ 00085 pwndDirtySave = pwndDirty; 00086 00087 while (pwndSpb->spwndParent != pwndDirty->spwndParent) { 00088 pwndDirty = pwndDirty->spwndParent; 00089 00090 /* 00091 * If we get to the top of the tree, it's because: 00092 * 1. pwndSpb == pwndDesktop 00093 * 2. pwndDirty is a parent of pwndSpb 00094 * 3. pwndDirty == pwndDesktop 00095 * 4. pwndDirty is a child of some other desktop 00096 * 5. pwndSpb and pwndDirty aren't siblings 00097 * 00098 * In all these cases, pwndDirty can't touch pwndSpb. 00099 */ 00100 if (pwndDirty == NULL) 00101 return FALSE; 00102 } 00103 00104 /* 00105 * If pwndSpb is the same as pwndDirty, then it will invalidate 00106 * only if the SPB is LOCKUPDATE. 00107 * 00108 * Non-LOCKUPDATE SPB's can't be invalidated by their 00109 * own windows, but LOCKUPDATE SPB's can. 00110 */ 00111 if (pwndDirty == pwndSpb) { 00112 if (!fSpbLockUpdate) 00113 return FALSE; 00114 00115 /* 00116 * If pwndSpb itself was drawn in, then we can't 00117 * try subtracting children. 00118 */ 00119 if (pwndDirtySave == pwndSpb) 00120 goto ProbablyTouch; 00121 00122 /* 00123 * We want to calculate the immediate child of pwndSpb 00124 * on the path from pwndDirty to pwndSpb, so we can 00125 * subtract off the rectangles of the children of pwndSpb 00126 * in case there are intervening windows. 00127 */ 00128 while (pwndSpb != pwndDirtySave->spwndParent) { 00129 pwndDirtySave = pwndDirtySave->spwndParent; 00130 } 00131 00132 /* 00133 * The SubtractIntervening loop subtracts the 00134 * window rects starting from pwndSpb and ending 00135 * at the window before pwndDirty, so set up 00136 * our variables appropriately. 00137 */ 00138 pwndDirty = pwndDirtySave; 00139 pwndSpb = pwndSpb->spwndChild; 00140 00141 } else { 00142 /* 00143 * Now compare the Z order of pwndDirty and pwndSpb. 00144 * If pwndDirty is above pwndSpb, then the SPB can't be touched. 00145 */ 00146 pwndDirtySave = pwndDirty; 00147 00148 /* 00149 * Compare the Z order by searching starting at pwndDirty, 00150 * moving DOWN the Z order list. If we encounter pwndSpb, 00151 * then pwndDirty is ABOVE or EQUAL to pwndSpb. 00152 */ 00153 for ( ; pwndDirty != NULL; pwndDirty = pwndDirty->spwndNext) { 00154 if (pwndDirty == pwndSpb) { 00155 return FALSE; 00156 } 00157 } 00158 pwndDirty = pwndDirtySave; 00159 00160 /* 00161 * We don't want to subtract the SPB window itself 00162 */ 00163 pwndSpb = pwndSpb->spwndNext; 00164 } 00165 00166 /* 00167 * Subtract Intervening rectangles. 00168 * pwndDirty is below pwndSpb. If there are any intervening 00169 * windows, subtract their window rects from lprcDirty to see if pwndDirty 00170 * is obscured. 00171 */ 00172 while (pwndSpb && pwndSpb != pwndDirty) { 00173 /* 00174 * If this window has a region selected, hwndDirty may draw through 00175 * it even though it has a full rectangle! We can't subtract its 00176 * rect from the dirty rect in this case. 00177 */ 00178 if ( TestWF(pwndSpb, WFVISIBLE) && 00179 !pwndSpb->hrgnClip && 00180 !SubtractRect(lprcDirty, lprcDirty, &pwndSpb->rcWindow)) { 00181 00182 return FALSE; 00183 } 00184 00185 pwndSpb = pwndSpb->spwndNext; 00186 } 00187 00188 // fall through 00189 ProbablyTouch: 00190 00191 /* 00192 * If the rectangles don't intersect, there is no invalidation. 00193 * (we make this test relatively late because it's expensive compared 00194 * to the tests above). 00195 * Otherwise, *lprcDirty now has the area of bits not obscured 00196 * by intervening windows. 00197 */ 00198 00199 return IntersectRect(lprcDirty, lprcDirty, &pspb->rc); 00200 } 00201 00202 /***************************************************************************\ 00203 * SpbCheckRect2 00204 * 00205 * Subtracts lprc in pwnd from pspb's region if lprc touches pspb. 00206 * 00207 * Returns FALSE if there is a memory allocation error, or if lprc 00208 * contains psbp's region; otherwise, returns TRUE. 00209 * 00210 * History: 00211 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00212 \***************************************************************************/ 00213 00214 BOOL SpbCheckRect2( 00215 PSPB pspb, 00216 PWND pwnd, 00217 LPRECT lprc, 00218 DWORD flags) 00219 { 00220 RECT rcTouch = *lprc; 00221 00222 /* 00223 * See if lprc touches any saved bits, taking into account what 00224 * window the drawing is occuring in. 00225 */ 00226 if (FBitsTouch(pwnd, &rcTouch, pspb, flags)) { 00227 00228 /* 00229 * If no SPB region exists, make one for the whole thing 00230 */ 00231 if (!pspb->hrgn && SetOrCreateRectRgnIndirectPublic( 00232 &pspb->hrgn, &pspb->rc) == ERROR) { 00233 00234 goto Error; 00235 } 00236 00237 /* 00238 * Subtract the rectangle that is invalid from the SPB region 00239 */ 00240 SetRectRgnIndirect(ghrgnSCR, &rcTouch); 00241 switch (SubtractRgn(pspb->hrgn, pspb->hrgn, ghrgnSCR)) { 00242 case ERROR: 00243 case NULLREGION: 00244 goto Error; 00245 00246 default: 00247 break; 00248 } 00249 } 00250 00251 return TRUE; 00252 00253 Error: 00254 FreeSpb(pspb); 00255 return FALSE; 00256 } 00257 00258 /***************************************************************************\ 00259 * SpbTransfer 00260 * 00261 * Validate the SPB rectangle from a window's update region, after 00262 * subtracting the window's update region from the SPB. 00263 * 00264 * NOTE: Although SpbTransfer calls xxxInternalInvalidate, it doesn't 00265 * specify any flags that will cause immediate updating. Therefore the 00266 * critsect isn't left and we don't consider this an 'xxx' routine. 00267 * Also, no revalidation is necessary. 00268 * 00269 * History: 00270 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00271 \***************************************************************************/ 00272 00273 BOOL SpbTransfer( 00274 PSPB pspb, 00275 PWND pwnd, 00276 BOOL fChildren) 00277 { 00278 RECT rc; 00279 00280 /* 00281 * If the window has an update region... 00282 */ 00283 if (pwnd->hrgnUpdate != NULL) { 00284 00285 /* 00286 * Invalidate its update region rectangle from the SPB 00287 */ 00288 if (pwnd->hrgnUpdate > HRGN_FULL) { 00289 GreGetRgnBox(pwnd->hrgnUpdate, &rc); 00290 } else { 00291 rc = pwnd->rcWindow; 00292 } 00293 00294 /* 00295 * Intersect the update region bounds with the parent client rects, 00296 * to make sure we don't invalidate more than we need to. If 00297 * nothing to validate, return TRUE (because SPB is probably not empty) 00298 * These RDW_ flags won't cause the critical section to be left, nor 00299 * will they provoke WinEvent notifications. 00300 */ 00301 if (IntersectWithParents(pwnd, &rc)) { 00302 BEGINATOMICCHECK(); 00303 00304 xxxInternalInvalidate(pwnd, 00305 ghrgnSPB2, 00306 RDW_VALIDATE | RDW_NOCHILDREN); 00307 00308 ENDATOMICCHECK(); 00309 00310 /* 00311 * If the SPB vanished, return FALSE. 00312 */ 00313 if (!SpbCheckRect2(pspb, pwnd, &rc, DCX_WINDOW)) 00314 return FALSE; 00315 } 00316 } 00317 00318 if (fChildren) { 00319 for (pwnd = pwnd->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) { 00320 if (!SpbTransfer(pspb, pwnd, TRUE)) { 00321 return FALSE; 00322 } 00323 } 00324 } 00325 00326 return TRUE; 00327 } 00328 00329 /***************************************************************************\ 00330 * CreateSpb 00331 * 00332 * This function, called after the window is created but before it is visible, 00333 * saves the contents of the screen where the window will be drawn in a SPB 00334 * structure, and links the structure into a linked list of SPB structures. 00335 * popup bits. This routine is called from SetWindowPos. 00336 * 00337 * History: 00338 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00339 \***************************************************************************/ 00340 00341 VOID CreateSpb( 00342 PWND pwnd, 00343 UINT flags, 00344 HDC hdcScreen) 00345 { 00346 PSPB pspb; 00347 int fSpbLockUpdate; 00348 00349 /* 00350 * Non-LOCKWINDOWUPDATE SPBs can only be created for top-level windows. 00351 * 00352 * This is because of the way that the display driver RestoreBits function 00353 * works. It can put bits down in places that aren't even part of the 00354 * window's visrgn, and these bits need to be invalidated. The 00355 * SetWindowPos() code to handle this case only knows how to invalidate 00356 * one of windows (i.e., the window's immediate parent), but all levels 00357 * need to get invalidated. See also the comments in wmswp.c, near the 00358 * call to RestoreSpb(). 00359 * 00360 * For example: the Q&E app brings up a copyright dialog that is a child 00361 * of its main window. While this is up, the user alt-f alt-l to execute 00362 * the file login command, which brings up another dialog that is a child 00363 * of the desktop. When the copyright dialog goes away, the display driver 00364 * restores bits on top of the second dialog. The SWP code knows to 00365 * invalidate the bogus stuff in the main window, but not in the desktop. 00366 * 00367 * LOCKUPDATE SPBs are fine, because they don't call RestoreBits. 00368 */ 00369 fSpbLockUpdate = flags & SPB_LOCKUPDATE; 00370 if ( !fSpbLockUpdate && 00371 pwnd->spwndParent != NULL && 00372 pwnd->spwndParent != PWNDDESKTOP(pwnd)) { 00373 00374 return; 00375 } 00376 00377 /* 00378 * We go and check all the existing DCs at this point, to handle the 00379 * case where we're saving an image of a window that has a "dirty" 00380 * DC, which would eventually invalidate our saved image (but which 00381 * is really okay). 00382 */ 00383 if (AnySpbs()) { 00384 00385 SpbCheck(); 00386 00387 } else { 00388 00389 PDCE pdce; 00390 00391 /* 00392 * Reset the dirty areas of all of the DC's and enable 00393 * bounds accumulation. We're creating a SPB now. This 00394 * is only done if there are no other SPB's in the list. 00395 */ 00396 GreLockDisplay(gpDispInfo->hDev); 00397 00398 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 00399 00400 if (pdce->DCX_flags & DCX_LAYERED) 00401 continue; 00402 00403 GreGetBounds(pdce->hdc, NULL, GGB_ENABLE_WINMGR); 00404 } 00405 00406 GreUnlockDisplay(gpDispInfo->hDev); 00407 } 00408 00409 /* 00410 * Create the save popup bits structure 00411 */ 00412 pspb = (PSPB)UserAllocPoolWithQuota(sizeof(SPB), TAG_SPB); 00413 if (!pspb) 00414 return; 00415 00416 pspb->spwnd = NULL; 00417 pspb->rc = pwnd->rcWindow; 00418 00419 /* 00420 * Clip to the screen 00421 */ 00422 if (!IntersectRect(&pspb->rc, &pspb->rc, &gpDispInfo->rcScreen)) 00423 goto BMError; 00424 00425 pspb->hrgn = NULL; 00426 pspb->hbm = NULL; 00427 pspb->flags = flags; 00428 Lock(&(pspb->spwnd), pwnd); 00429 00430 if (!fSpbLockUpdate) { 00431 00432 RECT rc = pspb->rc; 00433 00434 if (!SYSMET(SAMEDISPLAYFORMAT)) { 00435 PMONITOR pMonitor = _MonitorFromRect(&pspb->rc, MONITOR_DEFAULTTOPRIMARY); 00436 RECT rcT; 00437 00438 /* 00439 * If the intersection with the monitor isn't the entire visible 00440 * window rectangle, then bail! We don't save SPBs for windows 00441 * that span multiple monitors. Since we do a lot of work to 00442 * pin dialogs and menus, there won't be too many of these 00443 * babies. 00444 */ 00445 if (SubtractRect(&rcT, &pspb->rc, &pMonitor->rcMonitor) && 00446 GreRectInRegion(gpDispInfo->hrgnScreen, &rcT)) 00447 goto BMError2; 00448 00449 /* 00450 * Clip to the window's monitor 00451 */ 00452 if (!IntersectRect(&pspb->rc, &pspb->rc, &pMonitor->rcMonitor)) 00453 goto BMError2; 00454 00455 /* 00456 * dont save bits in a mixed bitdepth situtation 00457 * we cant create the exactly correct format bitmap 00458 * in all cases (555/565, and Paletized) so as 00459 * a cop-out dont save bitmaps at all (on secondaries) 00460 * in mixed bit-depth. 00461 * 00462 * the correct fix is to create a compatible 00463 * bitmap for the monitor device and directly 00464 * BitBlt() from/to the device (pMonitor->hdcMonitor) 00465 * but this involves too much code at this time. 00466 */ 00467 if (pMonitor != gpDispInfo->pMonitorPrimary) 00468 goto BMError2; 00469 } 00470 00471 /* 00472 * If this window is a regional window, don't use driver save 00473 * bits. Because it can only restore an entire rectangle, 00474 * invalid region is calculated assuming the old vis rgn was 00475 * rectangular. For regional windows, this would end up always 00476 * invalidating the area of (rcWindow - hrgnWindow) every 00477 * time an spb would be used. On the other hand, the invalid 00478 * area calculated when not using driver save bits is perfect, 00479 * because the restore blt can be correctly clipped to begin with. 00480 */ 00481 if ((pwnd->hrgnClip == NULL) && 00482 (pspb->ulSaveId = GreSaveScreenBits(gpDispInfo->hDev, 00483 SS_SAVE, 00484 0, 00485 (RECTL *)&rc))) { 00486 00487 /* 00488 * Remember that we copied this bitmap into on board memory. 00489 */ 00490 pspb->flags |= SPB_SAVESCREENBITS; 00491 00492 } else { 00493 HBITMAP hbmSave; 00494 BOOL bRet; 00495 00496 /* 00497 * The following delta byte-aligns the screen bitmap 00498 */ 00499 int dx = pspb->rc.left & 0x0007; 00500 int cx = pspb->rc.right - pspb->rc.left; 00501 int cy = pspb->rc.bottom - pspb->rc.top; 00502 00503 /* 00504 * NOTE: we don't care about setting up a visrgn in 00505 * hdcScreen, because BitBlt ignores it on reads. 00506 */ 00507 pspb->hbm = GreCreateCompatibleBitmap(hdcScreen, cx + dx, cy); 00508 if (!pspb->hbm) 00509 goto BMError2; 00510 00511 hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm); 00512 if (!hbmSave) 00513 goto BMError2; 00514 00515 /* 00516 * Copy the contents of the screen to the bitmap in the 00517 * save popup bits structure. If we ever find we run 00518 * into problems with the screen access check we can 00519 * do a bLockDisplay, give this process permission, do 00520 * the BitBlt and then take away permission. GDI 00521 * accesses the screen and that bit only under the 00522 * display semaphore so it is safe. Alternatively 00523 * if it is too hard to change this processes permission 00524 * here we could do it in GDI by marking the psoSrc 00525 * readable temporarily while completing the operation 00526 * and then setting it back to unreadable when done. 00527 * Or we could just fail it like the CreateCompatibleDC 00528 * failed and force a redraw. Basically we can't add 00529 * 3K of code in GDI to do a BitBlt that just does 1 00530 * test differently for this 1 place in User. 00531 * 00532 */ 00533 bRet = GreBitBlt(ghdcMem, 00534 dx, 00535 0, 00536 cx, 00537 cy, 00538 hdcScreen, 00539 pspb->rc.left, 00540 pspb->rc.top, 00541 0x00CC0000, 00542 0); 00543 00544 GreSelectBitmap(ghdcMem, hbmSave); 00545 00546 if (!bRet) 00547 goto BMError2; 00548 00549 GreSetBitmapOwner(pspb->hbm, OBJECT_OWNER_PUBLIC); 00550 } 00551 00552 /* 00553 * Mark that the window has an SPB. 00554 */ 00555 SetWF(pwnd, WFHASSPB); 00556 00557 /* 00558 * non-LOCKUPDATE SPBs are not invalidated by 00559 * drawing in pspb->spwnd, so start the SPB validation 00560 * loop below at the sibling immediately below us. 00561 */ 00562 pwnd = pwnd->spwndNext; 00563 } 00564 00565 /* 00566 * Link the new save popup bits structure into the list. 00567 */ 00568 pspb->pspbNext = gpDispInfo->pspbFirst; 00569 gpDispInfo->pspbFirst = pspb; 00570 00571 /* 00572 * Here we deal with any update regions that may be 00573 * pending in windows underneath the SPB. 00574 * 00575 * For all windows that might affect this SPB: 00576 * - Subtract the SPB rect from the update region 00577 * - Subtract the window from the SPB 00578 * 00579 * Note that we use pspb->spwnd here, in case it has 00580 * no siblings. 00581 * 00582 * ghrgnSPB2 is the region that is used inside of SpbTransfer to 00583 * validate window update regions. Intersect with the window clipping 00584 * region, if it exists. Don't want to intersect with the spb rect if 00585 * a clipping region exists because we'll end up validating more than 00586 * we want to validate. 00587 */ 00588 SetRectRgnIndirect(ghrgnSPB2, &pspb->rc); 00589 if (pspb->spwnd->hrgnClip != NULL) { 00590 00591 /* 00592 * If we get an error bail since an error might result in more 00593 * being validated than we want. Since the below code is only an 00594 * optimizer, this is ok: the window will remain invalid and will 00595 * draw, thereby invalidating the SPB like usual. 00596 */ 00597 if (IntersectRgn(ghrgnSPB2, 00598 ghrgnSPB2, 00599 pspb->spwnd->hrgnClip) == ERROR) { 00600 return; 00601 } 00602 } 00603 00604 if (pspb->spwnd->spwndParent == NULL || 00605 SpbTransfer(pspb, pspb->spwnd->spwndParent, FALSE)) { 00606 00607 /* 00608 * Do the same for the siblings underneath us... 00609 */ 00610 for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) { 00611 if (!SpbTransfer(pspb, pwnd, TRUE)) 00612 break; 00613 } 00614 } 00615 00616 return; 00617 00618 BMError2: 00619 /* 00620 * Error creating the bitmap: clean up and return. 00621 */ 00622 if (pspb->hbm) 00623 GreDeleteObject(pspb->hbm); 00624 00625 Unlock(&pspb->spwnd); 00626 // fall-through 00627 00628 BMError: 00629 UserFreePool(pspb); 00630 } 00631 00632 /***************************************************************************\ 00633 * RestoreSpb 00634 * 00635 * Restores the bits associated with pwnd's SPB onto the screen, clipped 00636 * to hrgnUncovered if possible. 00637 * 00638 * Upon return, hrgnUncovered is modified to contain the part of hrgnUncovered 00639 * that must be invalidated by the caller. FALSE is returned if the area 00640 * to be invalidated is empty. 00641 * 00642 * NOTE: Because the device driver SaveBitmap() function can not clip, this 00643 * function may write bits into an area of the screen larger than the passed-in 00644 * hrgnUncovered. In this case, the returned invalid region may be larger 00645 * than the passed-in hrgnUncovered. 00646 * 00647 * History: 00648 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00649 \***************************************************************************/ 00650 00651 UINT RestoreSpb( 00652 PWND pwnd, 00653 HRGN hrgnUncovered, 00654 HDC *phdcScreen) 00655 { 00656 PSPB pspb; 00657 UINT uInvalidate; 00658 HRGN hrgnRestorable; 00659 00660 /* 00661 * Note that we DON'T call SpbCheck() here -- 00662 * SpbCheck() is called by zzzBltValidBits(). 00663 */ 00664 pspb = FindSpb(pwnd); 00665 00666 /* 00667 * Assume all of hrgnUncovered was restored, and there's nothing 00668 * for our caller to invalidate. 00669 */ 00670 uInvalidate = RSPB_NO_INVALIDATE; 00671 hrgnRestorable = hrgnUncovered; 00672 00673 /* 00674 * First determine whether or not there is any area at all to restore. 00675 * If hrgnUncovered & pspb->hrgn is empty, then all of hrgnUncovered 00676 * needs to be invalidated, and there's nothing to restore. 00677 */ 00678 if (pspb->hrgn != NULL) { 00679 /* 00680 * At least some of hrgnUncovered needs to be invalidated. 00681 */ 00682 uInvalidate = RSPB_INVALIDATE; 00683 00684 /* 00685 * Calculate the true area of bits to be restored. If it becomes 00686 * empty, then just free the SPB without changing hrgnUncovered, 00687 * which is the area that must be invalidated. 00688 */ 00689 hrgnRestorable = ghrgnSPB1; 00690 switch (IntersectRgn(hrgnRestorable, hrgnUncovered, pspb->hrgn)) { 00691 case ERROR: 00692 case NULLREGION: 00693 goto Error; 00694 00695 default: 00696 break; 00697 } 00698 } 00699 00700 if (pspb->flags & SPB_SAVESCREENBITS) { 00701 00702 RECT rc = pspb->rc; 00703 00704 /* 00705 * Since the restore frees the onboard memory, clear this 00706 * bit so FreeSpb() won't try to free it again (regardless of 00707 * whether we get an error or not) 00708 */ 00709 pspb->flags &= ~SPB_SAVESCREENBITS; 00710 if (!(GreSaveScreenBits(gpDispInfo->hDev, 00711 SS_RESTORE, 00712 pspb->ulSaveId, 00713 (RECTL *)&rc))) { 00714 goto Error; 00715 } 00716 00717 /* 00718 * The SS_RESTORE call will always restore the entire SPB 00719 * rectangle, part of which may fall outside of hrgnUncovered. 00720 * The area that must be invalidated by our caller is simply 00721 * the SPB rectangle minus the area of restorable bits. 00722 * 00723 * If this region is not empty, then the SPB was not completely 00724 * restored, so we must return FALSE. 00725 */ 00726 SetRectRgnIndirect(ghrgnSPB2, &pspb->rc); 00727 if (SubtractRgn(hrgnUncovered, ghrgnSPB2, hrgnRestorable) != NULLREGION) { 00728 uInvalidate = RSPB_INVALIDATE_SSB; 00729 } 00730 } else { 00731 00732 HDC hdcScreen; 00733 HBITMAP hbmSave; 00734 00735 /* 00736 * In the unlikely event we need a screen DC and one wasn't passed in, 00737 * get it now. If we get one, we return the handle in *phdcScreen 00738 * so that our caller can release it later. 00739 */ 00740 if (!*phdcScreen) { 00741 *phdcScreen = gpDispInfo->hdcScreen; 00742 } 00743 00744 hdcScreen = *phdcScreen; 00745 00746 hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm); 00747 if (!hbmSave) 00748 goto Error; 00749 00750 /* 00751 * Be sure to clip to the area of restorable bits. 00752 */ 00753 00754 GreSelectVisRgn(hdcScreen, hrgnRestorable, SVR_COPYNEW); 00755 00756 GreBitBlt(hdcScreen, 00757 pspb->rc.left, pspb->rc.top, 00758 pspb->rc.right - pspb->rc.left, 00759 pspb->rc.bottom - pspb->rc.top, 00760 ghdcMem, 00761 pspb->rc.left & 0x0007, 00762 0, 00763 SRCCOPY, 00764 0); 00765 00766 GreSelectBitmap(ghdcMem, hbmSave); 00767 00768 /* 00769 * Now compute the area to be invalidated for return. 00770 * This is simply the original hrgnUncovered - hrgnRestorable 00771 */ 00772 SubtractRgn(hrgnUncovered, hrgnUncovered, hrgnRestorable); 00773 } 00774 00775 if (pwnd->hrgnClip == NULL || !IsVisible(pwnd)) 00776 FreeSpb(pspb); 00777 00778 return uInvalidate; 00779 00780 Error: 00781 FreeSpb(pspb); 00782 return RSPB_INVALIDATE; 00783 } 00784 00785 00786 00787 /***************************************************************************\ 00788 * LockWindowUpdate2 (API) 00789 * 00790 * Locks gspwndLockUpdate and it's children from updating. If 00791 * gspwndLockUpdate is NULL, then all windows will be unlocked. When 00792 * unlocked, the portions of the screen that would have been written to 00793 * are invalidated so they get repainted. TRUE is returned if the routine 00794 * is successful. 00795 * 00796 * If called when another app has something locked, then this function fails. 00797 * 00798 * History: 00799 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00800 \***************************************************************************/ 00801 00802 BOOL LockWindowUpdate2( 00803 PWND pwndLock, 00804 BOOL fThreadOverride) 00805 { 00806 PSPB pspb; 00807 BOOL fInval; 00808 HRGN hrgn; 00809 PTHREADINFO ptiCurrent = PtiCurrent(); 00810 00811 if ( /* 00812 * If we're full screen right now, fail this call. 00813 */ 00814 TEST_PUDF(PUDF_LOCKFULLSCREEN) 00815 00816 || 00817 00818 /* 00819 * If the screen is already locked, and it's being locked 00820 * by some other app, then fail. If fThreadOverride is set 00821 * then we're calling internally and it's okay to cancel 00822 * someone elses LockUpdate. 00823 */ 00824 ( gptiLockUpdate != NULL && 00825 gptiLockUpdate != PtiCurrent() && 00826 !fThreadOverride)) { 00827 UserAssert(IsWinEventNotifyDeferredOK()); 00828 00829 RIPERR0(ERROR_SCREEN_ALREADY_LOCKED, 00830 RIP_WARNING, 00831 "LockWindowUpdate failed because screen is locked by another application."); 00832 00833 return FALSE; 00834 } 00835 00836 if ((pwndLock != NULL) == (gptiLockUpdate != NULL)) { 00837 if (!fThreadOverride) { 00838 RIPERR1(ERROR_INVALID_PARAMETER, 00839 RIP_WARNING, 00840 "LockWindowUpdate failed because it is already %s.", 00841 (pwndLock != NULL) ? "locked" : "unlocked"); 00842 } 00843 00844 return FALSE; 00845 } 00846 00847 /* 00848 * This must be done while holding the screen critsec. 00849 * Deadlock if we callback during this, so defer WinEvent notifications 00850 */ 00851 DeferWinEventNotify(); 00852 GreLockDisplay(gpDispInfo->hDev); 00853 00854 if (pwndLock != NULL) { 00855 /* 00856 * We're about to make pwndLock and its siblings invisible: 00857 * go invalidate any other affected SPBs. 00858 */ 00859 SpbCheckPwnd(pwndLock); 00860 00861 CreateSpb(pwndLock, SPB_LOCKUPDATE, NULL); 00862 00863 Lock(&(gspwndLockUpdate), pwndLock); 00864 gptiLockUpdate = ptiCurrent; 00865 00866 zzzInvalidateDCCache(pwndLock, IDC_DEFAULT); 00867 00868 } else { 00869 /* 00870 * Flush any accumulated rectangles and invalidate spbs. 00871 */ 00872 SpbCheck(); 00873 00874 /* 00875 * Save this in a local before we set it to NULL 00876 */ 00877 pwndLock = gspwndLockUpdate; 00878 00879 gptiLockUpdate = NULL; 00880 Unlock(&gspwndLockUpdate); 00881 00882 zzzInvalidateDCCache(pwndLock, IDC_DEFAULT); 00883 00884 /* 00885 * Assume SPB doesn't exist, or couldn't be created, and that we 00886 * must invalidate the entire window. 00887 */ 00888 fInval = TRUE; 00889 hrgn = HRGN_FULL; 00890 00891 /* 00892 * Find the LOCKUPDATE spb in the list, and if present calculate 00893 * the area that has been invalidated, if any. 00894 */ 00895 for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) { 00896 00897 if (pspb->flags & SPB_LOCKUPDATE) { 00898 00899 if (pspb->hrgn == NULL) { 00900 00901 /* 00902 * If no invalid area, then no invalidation needed. 00903 */ 00904 fInval = FALSE; 00905 00906 } else { 00907 00908 /* 00909 * Subtract SPB valid region from SPB rectangle, to 00910 * yield invalid region. 00911 */ 00912 hrgn = ghrgnSPB1; 00913 SetRectRgnIndirect(hrgn, &pspb->rc); 00914 00915 /* 00916 * If spb rect minus the spb valid rgn is empty, 00917 * then there is nothing to invalidate. 00918 */ 00919 fInval = SubtractRgn(hrgn, hrgn, pspb->hrgn) != NULLREGION; 00920 } 00921 00922 FreeSpb(pspb); 00923 00924 /* 00925 * Exit this loop (there can be only one LOCKUPDATE spb) 00926 */ 00927 break; 00928 } 00929 } 00930 00931 if (fInval) { 00932 BEGINATOMICCHECK(); 00933 // want to prevent WinEvent notifies, but this make break asserts 00934 DeferWinEventNotify(); 00935 xxxInternalInvalidate(PWNDDESKTOP(pwndLock), 00936 hrgn, 00937 RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); 00938 zzzEndDeferWinEventNotify(); 00939 ENDATOMICCHECK(); 00940 } 00941 00942 /* 00943 * Invalidate any other SPBs affected by the fact that this window 00944 * and its children are being made visible. 00945 */ 00946 SpbCheckPwnd(pwndLock); 00947 } 00948 00949 GreUnlockDisplay(gpDispInfo->hDev); 00950 zzzEndDeferWinEventNotify(); 00951 00952 return TRUE; 00953 } 00954 00955 /***************************************************************************\ 00956 * FindSpb 00957 * 00958 * Returns a pointer to the SPB structure associated with the specified 00959 * window or NULL if there is no associated structure. 00960 * 00961 * History: 00962 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00963 \***************************************************************************/ 00964 00965 PSPB FindSpb( 00966 PWND pwnd) 00967 { 00968 PSPB pspb; 00969 00970 /* 00971 * Walk through the list of save popup bits looking for a match on 00972 * window handle. 00973 */ 00974 for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) { 00975 00976 if (pspb->spwnd == pwnd && !(pspb->flags & SPB_LOCKUPDATE)) 00977 break; 00978 } 00979 00980 return pspb; 00981 } 00982 00983 /***************************************************************************\ 00984 * SpbCheck 00985 * 00986 * Modifies all of the save popup bits structures to reflect changes on the 00987 * screen. This function walks through all of the DC's, and if the DC is 00988 * dirty, then the dirty area is removed from the associated save popup bits 00989 * structure. 00990 * 00991 * History: 00992 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 00993 \***************************************************************************/ 00994 00995 VOID SpbCheck(VOID) 00996 { 00997 PDCE pdce; 00998 RECT rcBounds; 00999 01000 if (AnySpbs()) { 01001 01002 GreLockDisplay(gpDispInfo->hDev); 01003 01004 /* 01005 * Walk through all of the DC's, accumulating dirty areas. 01006 */ 01007 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 01008 01009 /* 01010 * Only check valid cache entries... 01011 */ 01012 if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS)) 01013 continue; 01014 01015 SpbCheckDce(pdce); 01016 } 01017 01018 /* 01019 * Subtact out DirectDraw dirty rect from all the SPB's. The call to 01020 * GreGetDirectDrawBounds will also reset the accumulated bounds. 01021 */ 01022 if (GreGetDirectDrawBounds(gpDispInfo->hDev, &rcBounds)) { 01023 SpbCheckRect(NULL, &rcBounds, 0); 01024 } 01025 01026 GreUnlockDisplay(gpDispInfo->hDev); 01027 } 01028 } 01029 01030 /***************************************************************************\ 01031 * SpbCheckDce 01032 * 01033 * This function retrieves the dirty area of a DC and removes the area from 01034 * the list of SPB structures. The DC is then marked as clean. 01035 * 01036 * History: 01037 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 01038 \***************************************************************************/ 01039 01040 VOID SpbCheckDce( 01041 PDCE pdce) 01042 { 01043 RECT rc; 01044 01045 if (pdce->DCX_flags & DCX_LAYERED) 01046 return; 01047 01048 /* 01049 * Query the dirty bounds rectangle. Doing this clears the bounds 01050 * as well. 01051 */ 01052 if (GreGetBounds(pdce->hdc, &rc, 0)) { 01053 01054 if (pdce->pMonitor != NULL) { 01055 /* 01056 * Convert the bounds rect to screen coords. 01057 */ 01058 OffsetRect(&rc, pdce->pMonitor->rcMonitor.left, 01059 pdce->pMonitor->rcMonitor.top); 01060 } 01061 01062 /* 01063 * Intersect the returned rectangle with the window rectangle 01064 * in case the guy was drawing outside his window 01065 */ 01066 if (IntersectRect(&rc, &rc, &(pdce->pwndOrg)->rcWindow)) 01067 SpbCheckRect(pdce->pwndOrg, &rc, pdce->DCX_flags); 01068 } 01069 } 01070 01071 /***************************************************************************\ 01072 * SpbCheckRect 01073 * 01074 * This function removes the passed rectangle from the SPB structures which 01075 * touch it. 01076 * 01077 * History: 01078 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 01079 \***************************************************************************/ 01080 01081 VOID SpbCheckRect( 01082 PWND pwnd, 01083 LPRECT lprc, 01084 DWORD flags) 01085 { 01086 PSPB pspb, pspbNext; 01087 01088 /* 01089 * If this window isn't visible, we're done. 01090 */ 01091 if (!IsVisible(pwnd)) 01092 return; 01093 01094 for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) { 01095 01096 /* 01097 * Get the pointer to the next save popup bits structure now 01098 * in case SpbCheckRect2() frees the current one. 01099 */ 01100 pspbNext = pspb->pspbNext; 01101 01102 /* 01103 * In win3.1 they used to exit the function if this function 01104 * returned false. This meant that if one of the spbs was freed 01105 * the rest of the spbs would not be invalidated. 01106 */ 01107 SpbCheckRect2(pspb, pwnd, lprc, flags); 01108 } 01109 } 01110 01111 /***************************************************************************\ 01112 * SpbCheckPwnd 01113 * 01114 * This routine checks to see if the window rectangle of PWND affects any SPBs. 01115 * It is called if pwnd or its children are being hidden or shown without 01116 * going through WinSetWindowPos(). 01117 * 01118 * Any SPBs for children of pwnd are destroyed. 01119 * 01120 * It must be called while pwnd is still visible. 01121 * 01122 * History: 01123 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 01124 \***************************************************************************/ 01125 01126 VOID SpbCheckPwnd( 01127 PWND pwnd) 01128 { 01129 PSPB pspb; 01130 PWND pwndSpb; 01131 PSPB pspbNext; 01132 01133 /* 01134 * First blow away any SPBs owned by this window or its children. 01135 */ 01136 for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) { 01137 01138 /* 01139 * Get pspbNext now in case we free the SPB 01140 */ 01141 pspbNext = pspb->pspbNext; 01142 01143 /* 01144 * If pspb->spwnd is == pwnd or a child of pwnd, then free the SPB 01145 */ 01146 for (pwndSpb = pspb->spwnd; pwndSpb; pwndSpb = pwndSpb->spwndParent) { 01147 01148 if (pwnd == pwndSpb) 01149 FreeSpb(pspb); 01150 } 01151 } 01152 01153 /* 01154 * Then see if any other SPBs are affected... 01155 */ 01156 if (gpDispInfo->pspbFirst != NULL) { 01157 SpbCheckRect(pwnd, &pwnd->rcWindow, 0); 01158 } 01159 } 01160 01161 /***************************************************************************\ 01162 * FreeSpb 01163 * 01164 * This function deletes the bitmap and region assocaited with a save popup 01165 * bits structure and then unlinks and destroys the spb structure itself. 01166 * 01167 * History: 01168 * 18-Jul-1991 DarrinM Ported from Win 3.1 sources. 01169 \***************************************************************************/ 01170 01171 VOID FreeSpb( 01172 PSPB pspb) 01173 { 01174 PSPB *ppspb; 01175 PDCE pdce; 01176 01177 if (pspb == NULL) 01178 return; 01179 01180 /* 01181 * Delete the bitmap. If saved in screen memory, make special call. 01182 */ 01183 if (pspb->flags & SPB_SAVESCREENBITS) { 01184 GreSaveScreenBits(gpDispInfo->hDev, SS_FREE, pspb->ulSaveId, NULL); 01185 } else if (pspb->hbm != NULL) { 01186 GreDeleteObject(pspb->hbm); 01187 } 01188 01189 /* 01190 * Destroy the region. 01191 */ 01192 if (pspb->hrgn != NULL){ 01193 GreDeleteObject(pspb->hrgn); 01194 } 01195 01196 /* 01197 * Forget that there is an attached SPB. 01198 */ 01199 if (pspb->spwnd != NULL) { 01200 ClrWF(pspb->spwnd, WFHASSPB); 01201 Unlock(&pspb->spwnd); 01202 } 01203 01204 /* 01205 * Unlink the spb. 01206 */ 01207 ppspb = &gpDispInfo->pspbFirst; 01208 while (*ppspb != pspb) { 01209 ppspb = &(*ppspb)->pspbNext; 01210 } 01211 01212 *ppspb = pspb->pspbNext; 01213 01214 /* 01215 * Free the save popup bits structure. 01216 */ 01217 UserFreePool(pspb); 01218 01219 /* 01220 * If we no longer have any SPBs then turn off window MGR 01221 * bounds collection. 01222 */ 01223 if (!AnySpbs()) { 01224 01225 GreLockDisplay(gpDispInfo->hDev); 01226 01227 /* 01228 * Reset the dirty areas of all of the DC's. NULL means reset. 01229 */ 01230 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 01231 01232 if (pdce->DCX_flags & DCX_LAYERED) 01233 continue; 01234 01235 GreGetBounds(pdce->hdc, NULL, GGB_DISABLE_WINMGR); 01236 } 01237 01238 GreUnlockDisplay(gpDispInfo->hDev); 01239 } 01240 01241 } 01242 01243 /***************************************************************************\ 01244 * FreeAllSpbs 01245 * 01246 * This function deletes all spb-bitmaps. 01247 * 01248 * History: 01249 * 07-Oct-1995 ChrisWil Ported from Chicago. 01250 \***************************************************************************/ 01251 01252 VOID FreeAllSpbs(void) 01253 { 01254 01255 while(AnySpbs()) { 01256 FreeSpb(gpDispInfo->pspbFirst); 01257 } 01258 01259 gpDispInfo->pspbFirst = NULL; 01260 }