Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1272 lines
39 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: spb.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Save Popup Bits (SPB) support routines.
  7. *
  8. * History:
  9. * 18-Jul-1991 DarrinM Created.
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. /***************************************************************************\
  14. * FBitsTouch
  15. *
  16. * This routine checkes to see if the rectangle *lprcDirty in pwndDirty
  17. * invalidates any bits in the SPB structure at *pspb.
  18. *
  19. * pwndDirty "touches" pwndSpb if:
  20. * 1. pwndDirty is visible AND:
  21. * 2. pwndDirty == or descendent of pwndSpb, and pwndSpb is a LOCKUPDATE
  22. * spb.
  23. * 3. pwndDirty is pwndSpb's parent. (e.g., drawing in the
  24. * desktop window, behind a dialog box).
  25. * 4. A parent of pwndDirty is the sibling of pwndSpb, and the parent
  26. * is lower in the zorder.
  27. *
  28. * History:
  29. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  30. \***************************************************************************/
  31. BOOL FBitsTouch(
  32. PWND pwndDirty,
  33. LPRECT lprcDirty,
  34. PSPB pspb,
  35. DWORD flags)
  36. {
  37. PWND pwndSpb,
  38. pwndDirtySave;
  39. int fSpbLockUpdate;
  40. /*
  41. * When no window is passed in, skip all the window-related stuff and
  42. * go directly to check the rectangle.
  43. */
  44. if (pwndDirty == NULL)
  45. goto ProbablyTouch;
  46. /*
  47. * If pwndDirty or its parents are invisible,
  48. * then it can't invalidate any SPBs
  49. */
  50. if (!IsVisible(pwndDirty))
  51. return FALSE;
  52. pwndSpb = pspb->spwnd;
  53. fSpbLockUpdate = pspb->flags & SPB_LOCKUPDATE;
  54. if (fSpbLockUpdate) {
  55. /*
  56. * If the guy is drawing through a locked window via
  57. * DCX_LOCKWINDOWUPDATE and the spb is a LOCKUPDATE SPB, then
  58. * don't do any invalidation of the SPB. Basically we're trying
  59. * to avoid having the tracking rectangle invalidate the SPB
  60. * since it's drawn via a WinGetClipPS() ps.
  61. */
  62. if (flags & DCX_LOCKWINDOWUPDATE)
  63. return FALSE;
  64. }
  65. /*
  66. * If pwndDirty is pwndSpb's immediate parent (e.g., drawing in the
  67. * desktop window behind a dialog box), then we may touch: do the
  68. * intersection.
  69. */
  70. if (pwndDirty == pwndSpb->spwndParent)
  71. goto ProbablyTouch;
  72. /*
  73. * We know that pwndDirty != pwndSpb->spwndParent.
  74. * Now find the parent of pwndDirty that is a sibling of pwndSpb.
  75. */
  76. pwndDirtySave = pwndDirty;
  77. while (pwndSpb->spwndParent != pwndDirty->spwndParent) {
  78. pwndDirty = pwndDirty->spwndParent;
  79. /*
  80. * If we get to the top of the tree, it's because:
  81. * 1. pwndSpb == pwndDesktop
  82. * 2. pwndDirty is a parent of pwndSpb
  83. * 3. pwndDirty == pwndDesktop
  84. * 4. pwndDirty is a child of some other desktop
  85. * 5. pwndSpb and pwndDirty aren't siblings
  86. *
  87. * In all these cases, pwndDirty can't touch pwndSpb.
  88. */
  89. if (pwndDirty == NULL)
  90. return FALSE;
  91. }
  92. /*
  93. * If pwndSpb is the same as pwndDirty, then it will invalidate
  94. * only if the SPB is LOCKUPDATE.
  95. *
  96. * Non-LOCKUPDATE SPB's can't be invalidated by their
  97. * own windows, but LOCKUPDATE SPB's can.
  98. */
  99. if (pwndDirty == pwndSpb) {
  100. if (!fSpbLockUpdate)
  101. return FALSE;
  102. /*
  103. * If pwndSpb itself was drawn in, then we can't
  104. * try subtracting children.
  105. */
  106. if (pwndDirtySave == pwndSpb)
  107. goto ProbablyTouch;
  108. /*
  109. * We want to calculate the immediate child of pwndSpb
  110. * on the path from pwndDirty to pwndSpb, so we can
  111. * subtract off the rectangles of the children of pwndSpb
  112. * in case there are intervening windows.
  113. */
  114. while (pwndSpb != pwndDirtySave->spwndParent) {
  115. pwndDirtySave = pwndDirtySave->spwndParent;
  116. }
  117. /*
  118. * The SubtractIntervening loop subtracts the
  119. * window rects starting from pwndSpb and ending
  120. * at the window before pwndDirty, so set up
  121. * our variables appropriately.
  122. */
  123. pwndDirty = pwndDirtySave;
  124. pwndSpb = pwndSpb->spwndChild;
  125. } else {
  126. /*
  127. * Now compare the Z order of pwndDirty and pwndSpb.
  128. * If pwndDirty is above pwndSpb, then the SPB can't be touched.
  129. */
  130. pwndDirtySave = pwndDirty;
  131. /*
  132. * Compare the Z order by searching starting at pwndDirty,
  133. * moving DOWN the Z order list. If we encounter pwndSpb,
  134. * then pwndDirty is ABOVE or EQUAL to pwndSpb.
  135. */
  136. for ( ; pwndDirty != NULL; pwndDirty = pwndDirty->spwndNext) {
  137. if (pwndDirty == pwndSpb) {
  138. return FALSE;
  139. }
  140. }
  141. pwndDirty = pwndDirtySave;
  142. /*
  143. * We don't want to subtract the SPB window itself
  144. */
  145. pwndSpb = pwndSpb->spwndNext;
  146. }
  147. /*
  148. * Subtract Intervening rectangles.
  149. * pwndDirty is below pwndSpb. If there are any intervening
  150. * windows, subtract their window rects from lprcDirty to see if pwndDirty
  151. * is obscured.
  152. */
  153. while (pwndSpb && pwndSpb != pwndDirty) {
  154. /*
  155. * If this window has a region selected, hwndDirty may draw through
  156. * it even though it has a full rectangle! We can't subtract its
  157. * rect from the dirty rect in this case.
  158. */
  159. if ( TestWF(pwndSpb, WFVISIBLE) &&
  160. !pwndSpb->hrgnClip &&
  161. !TestWF(pwndSpb, WEFLAYERED) &&
  162. !SubtractRect(lprcDirty, lprcDirty, &pwndSpb->rcWindow)) {
  163. return FALSE;
  164. }
  165. pwndSpb = pwndSpb->spwndNext;
  166. }
  167. // fall through
  168. ProbablyTouch:
  169. /*
  170. * If the rectangles don't intersect, there is no invalidation.
  171. * (we make this test relatively late because it's expensive compared
  172. * to the tests above).
  173. * Otherwise, *lprcDirty now has the area of bits not obscured
  174. * by intervening windows.
  175. */
  176. return IntersectRect(lprcDirty, lprcDirty, &pspb->rc);
  177. }
  178. /***************************************************************************\
  179. * SpbCheckRect2
  180. *
  181. * Subtracts lprc in pwnd from pspb's region if lprc touches pspb.
  182. *
  183. * Returns FALSE if there is a memory allocation error, or if lprc
  184. * contains psbp's region; otherwise, returns TRUE.
  185. *
  186. * History:
  187. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  188. \***************************************************************************/
  189. BOOL SpbCheckRect2(
  190. PSPB pspb,
  191. PWND pwnd,
  192. LPRECT lprc,
  193. DWORD flags)
  194. {
  195. RECT rcTouch = *lprc;
  196. /*
  197. * See if lprc touches any saved bits, taking into account what
  198. * window the drawing is occuring in.
  199. */
  200. if (FBitsTouch(pwnd, &rcTouch, pspb, flags)) {
  201. /*
  202. * If no SPB region exists, make one for the whole thing
  203. */
  204. if (!pspb->hrgn && SetOrCreateRectRgnIndirectPublic(
  205. &pspb->hrgn, &pspb->rc) == ERROR) {
  206. goto Error;
  207. }
  208. /*
  209. * Subtract the rectangle that is invalid from the SPB region
  210. */
  211. SetRectRgnIndirect(ghrgnSCR, &rcTouch);
  212. switch (SubtractRgn(pspb->hrgn, pspb->hrgn, ghrgnSCR)) {
  213. case ERROR:
  214. case NULLREGION:
  215. goto Error;
  216. default:
  217. break;
  218. }
  219. }
  220. return TRUE;
  221. Error:
  222. FreeSpb(pspb);
  223. return FALSE;
  224. }
  225. /***************************************************************************\
  226. * SpbTransfer
  227. *
  228. * Validate the SPB rectangle from a window's update region, after
  229. * subtracting the window's update region from the SPB.
  230. *
  231. * NOTE: Although SpbTransfer calls xxxInternalInvalidate, it doesn't
  232. * specify any flags that will cause immediate updating. Therefore the
  233. * critsect isn't left and we don't consider this an 'xxx' routine.
  234. * Also, no revalidation is necessary.
  235. *
  236. * History:
  237. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  238. \***************************************************************************/
  239. BOOL SpbTransfer(
  240. PSPB pspb,
  241. PWND pwnd,
  242. BOOL fChildren)
  243. {
  244. RECT rc;
  245. /*
  246. * If the window has an update region...
  247. */
  248. if (pwnd->hrgnUpdate != NULL) {
  249. /*
  250. * Invalidate its update region rectangle from the SPB
  251. */
  252. if (pwnd->hrgnUpdate > HRGN_FULL) {
  253. GreGetRgnBox(pwnd->hrgnUpdate, &rc);
  254. } else {
  255. rc = pwnd->rcWindow;
  256. }
  257. /*
  258. * Intersect the update region bounds with the parent client rects,
  259. * to make sure we don't invalidate more than we need to. If
  260. * nothing to validate, return TRUE (because SPB is probably not empty)
  261. * These RDW_ flags won't cause the critical section to be left, nor
  262. * will they provoke WinEvent notifications.
  263. */
  264. if (IntersectWithParents(pwnd, &rc)) {
  265. BEGINATOMICCHECK();
  266. xxxInternalInvalidate(pwnd,
  267. ghrgnSPB2,
  268. RDW_VALIDATE | RDW_NOCHILDREN);
  269. ENDATOMICCHECK();
  270. /*
  271. * If the SPB vanished, return FALSE.
  272. */
  273. if (!SpbCheckRect2(pspb, pwnd, &rc, DCX_WINDOW))
  274. return FALSE;
  275. }
  276. }
  277. if (fChildren) {
  278. for (pwnd = pwnd->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) {
  279. if (!SpbTransfer(pspb, pwnd, TRUE)) {
  280. return FALSE;
  281. }
  282. }
  283. }
  284. return TRUE;
  285. }
  286. /***************************************************************************\
  287. * CreateSpb
  288. *
  289. * This function, called after the window is created but before it is visible,
  290. * saves the contents of the screen where the window will be drawn in a SPB
  291. * structure, and links the structure into a linked list of SPB structures.
  292. * popup bits. This routine is called from SetWindowPos.
  293. *
  294. * History:
  295. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  296. \***************************************************************************/
  297. VOID CreateSpb(
  298. PWND pwnd,
  299. UINT flags,
  300. HDC hdcScreen)
  301. {
  302. PSPB pspb;
  303. int fSpbLockUpdate;
  304. /*
  305. * Non-LOCKWINDOWUPDATE SPBs can only be created for top-level windows.
  306. *
  307. * This is because of the way that the display driver RestoreBits function
  308. * works. It can put bits down in places that aren't even part of the
  309. * window's visrgn, and these bits need to be invalidated. The
  310. * SetWindowPos() code to handle this case only knows how to invalidate
  311. * one of windows (i.e., the window's immediate parent), but all levels
  312. * need to get invalidated. See also the comments in wmswp.c, near the
  313. * call to RestoreSpb().
  314. *
  315. * For example: the Q&E app brings up a copyright dialog that is a child
  316. * of its main window. While this is up, the user alt-f alt-l to execute
  317. * the file login command, which brings up another dialog that is a child
  318. * of the desktop. When the copyright dialog goes away, the display driver
  319. * restores bits on top of the second dialog. The SWP code knows to
  320. * invalidate the bogus stuff in the main window, but not in the desktop.
  321. *
  322. * LOCKUPDATE SPBs are fine, because they don't call RestoreBits.
  323. */
  324. fSpbLockUpdate = flags & SPB_LOCKUPDATE;
  325. if ( !fSpbLockUpdate &&
  326. pwnd->spwndParent != NULL &&
  327. pwnd->spwndParent != PWNDDESKTOP(pwnd)) {
  328. return;
  329. }
  330. /*
  331. * We go and check all the existing DCs at this point, to handle the
  332. * case where we're saving an image of a window that has a "dirty"
  333. * DC, which would eventually invalidate our saved image (but which
  334. * is really okay).
  335. */
  336. if (AnySpbs()) {
  337. SpbCheck();
  338. } else {
  339. PDCE pdce;
  340. /*
  341. * Reset the dirty areas of all of the DC's and enable
  342. * bounds accumulation. We're creating a SPB now. This
  343. * is only done if there are no other SPB's in the list.
  344. */
  345. GreLockDisplay(gpDispInfo->hDev);
  346. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  347. if (pdce->DCX_flags & DCX_REDIRECTED)
  348. continue;
  349. GreGetBounds(pdce->hdc, NULL, GGB_ENABLE_WINMGR);
  350. }
  351. GreUnlockDisplay(gpDispInfo->hDev);
  352. }
  353. /*
  354. * Create the save popup bits structure
  355. */
  356. pspb = (PSPB)UserAllocPoolWithQuota(sizeof(SPB), TAG_SPB);
  357. if (!pspb)
  358. return;
  359. pspb->spwnd = NULL;
  360. pspb->rc = pwnd->rcWindow;
  361. /*
  362. * Clip to the screen
  363. */
  364. if (!IntersectRect(&pspb->rc, &pspb->rc, &gpDispInfo->rcScreen))
  365. goto BMError;
  366. pspb->hrgn = NULL;
  367. pspb->hbm = NULL;
  368. pspb->flags = flags;
  369. Lock(&(pspb->spwnd), pwnd);
  370. if (!fSpbLockUpdate) {
  371. RECT rc = pspb->rc;
  372. if (!SYSMET(SAMEDISPLAYFORMAT)) {
  373. PMONITOR pMonitor = _MonitorFromRect(&pspb->rc, MONITOR_DEFAULTTOPRIMARY);
  374. RECT rcT;
  375. /*
  376. * If the intersection with the monitor isn't the entire visible
  377. * window rectangle, then bail! We don't save SPBs for windows
  378. * that span multiple monitors. Since we do a lot of work to
  379. * pin dialogs and menus, there won't be too many of these
  380. * babies.
  381. */
  382. if (SubtractRect(&rcT, &pspb->rc, &pMonitor->rcMonitor) &&
  383. GreRectInRegion(gpDispInfo->hrgnScreen, &rcT))
  384. goto BMError2;
  385. /*
  386. * Clip to the window's monitor
  387. */
  388. if (!IntersectRect(&pspb->rc, &pspb->rc, &pMonitor->rcMonitor))
  389. goto BMError2;
  390. /*
  391. * dont save bits in a mixed bitdepth situtation
  392. * we cant create the exactly correct format bitmap
  393. * in all cases (555/565, and Paletized) so as
  394. * a cop-out dont save bitmaps at all (on secondaries)
  395. * in mixed bit-depth.
  396. *
  397. * the correct fix is to create a compatible
  398. * bitmap for the monitor device and directly
  399. * BitBlt() from/to the device (pMonitor->hdcMonitor)
  400. * but this involves too much code at this time.
  401. */
  402. if (pMonitor != gpDispInfo->pMonitorPrimary)
  403. goto BMError2;
  404. }
  405. /*
  406. * If this window is a regional window, don't use driver save
  407. * bits. Because it can only restore an entire rectangle,
  408. * invalid region is calculated assuming the old vis rgn was
  409. * rectangular. For regional windows, this would end up always
  410. * invalidating the area of (rcWindow - hrgnWindow) every
  411. * time an spb would be used. On the other hand, the invalid
  412. * area calculated when not using driver save bits is perfect,
  413. * because the restore blt can be correctly clipped to begin with.
  414. */
  415. if ((pwnd->hrgnClip == NULL) &&
  416. (pspb->ulSaveId = GreSaveScreenBits(gpDispInfo->hDev,
  417. SS_SAVE,
  418. 0,
  419. (RECTL *)&rc))) {
  420. /*
  421. * Remember that we copied this bitmap into on board memory.
  422. */
  423. pspb->flags |= SPB_SAVESCREENBITS;
  424. } else {
  425. HBITMAP hbmSave;
  426. BOOL bRet;
  427. /*
  428. * The following delta byte-aligns the screen bitmap
  429. */
  430. int dx = pspb->rc.left & 0x0007;
  431. int cx = pspb->rc.right - pspb->rc.left;
  432. int cy = pspb->rc.bottom - pspb->rc.top;
  433. /*
  434. * NOTE: we don't care about setting up a visrgn in
  435. * hdcScreen, because BitBlt ignores it on reads.
  436. */
  437. pspb->hbm = GreCreateCompatibleBitmap(hdcScreen, cx + dx, cy);
  438. if (!pspb->hbm)
  439. goto BMError2;
  440. hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm);
  441. if (!hbmSave)
  442. goto BMError2;
  443. /*
  444. * Copy the contents of the screen to the bitmap in the
  445. * save popup bits structure. If we ever find we run
  446. * into problems with the screen access check we can
  447. * do a bLockDisplay, give this process permission, do
  448. * the BitBlt and then take away permission. GDI
  449. * accesses the screen and that bit only under the
  450. * display semaphore so it is safe. Alternatively
  451. * if it is too hard to change this processes permission
  452. * here we could do it in GDI by marking the psoSrc
  453. * readable temporarily while completing the operation
  454. * and then setting it back to unreadable when done.
  455. * Or we could just fail it like the CreateCompatibleDC
  456. * failed and force a redraw. Basically we can't add
  457. * 3K of code in GDI to do a BitBlt that just does 1
  458. * test differently for this 1 place in User.
  459. *
  460. */
  461. bRet = GreBitBlt(ghdcMem,
  462. dx,
  463. 0,
  464. cx,
  465. cy,
  466. hdcScreen,
  467. pspb->rc.left,
  468. pspb->rc.top,
  469. 0x00CC0000,
  470. 0);
  471. GreSelectBitmap(ghdcMem, hbmSave);
  472. if (!bRet)
  473. goto BMError2;
  474. GreSetBitmapOwner(pspb->hbm, OBJECT_OWNER_PUBLIC);
  475. }
  476. /*
  477. * Mark that the window has an SPB.
  478. */
  479. SetWF(pwnd, WFHASSPB);
  480. /*
  481. * non-LOCKUPDATE SPBs are not invalidated by
  482. * drawing in pspb->spwnd, so start the SPB validation
  483. * loop below at the sibling immediately below us.
  484. */
  485. pwnd = pwnd->spwndNext;
  486. }
  487. /*
  488. * Link the new save popup bits structure into the list.
  489. */
  490. pspb->pspbNext = gpDispInfo->pspbFirst;
  491. gpDispInfo->pspbFirst = pspb;
  492. /*
  493. * Here we deal with any update regions that may be
  494. * pending in windows underneath the SPB.
  495. *
  496. * For all windows that might affect this SPB:
  497. * - Subtract the SPB rect from the update region
  498. * - Subtract the window from the SPB
  499. *
  500. * Note that we use pspb->spwnd here, in case it has
  501. * no siblings.
  502. *
  503. * ghrgnSPB2 is the region that is used inside of SpbTransfer to
  504. * validate window update regions. Intersect with the window clipping
  505. * region, if it exists. Don't want to intersect with the spb rect if
  506. * a clipping region exists because we'll end up validating more than
  507. * we want to validate.
  508. */
  509. SetRectRgnIndirect(ghrgnSPB2, &pspb->rc);
  510. if (pspb->spwnd->hrgnClip != NULL) {
  511. /*
  512. * If we get an error bail since an error might result in more
  513. * being validated than we want. Since the below code is only an
  514. * optimizer, this is ok: the window will remain invalid and will
  515. * draw, thereby invalidating the SPB like usual.
  516. */
  517. if (IntersectRgn(ghrgnSPB2,
  518. ghrgnSPB2,
  519. pspb->spwnd->hrgnClip) == ERROR) {
  520. return;
  521. }
  522. }
  523. if (pspb->spwnd->spwndParent == NULL ||
  524. SpbTransfer(pspb, pspb->spwnd->spwndParent, FALSE)) {
  525. /*
  526. * Do the same for the siblings underneath us...
  527. */
  528. for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) {
  529. if (!SpbTransfer(pspb, pwnd, TRUE))
  530. break;
  531. }
  532. }
  533. return;
  534. BMError2:
  535. /*
  536. * Error creating the bitmap: clean up and return.
  537. */
  538. if (pspb->hbm)
  539. GreDeleteObject(pspb->hbm);
  540. Unlock(&pspb->spwnd);
  541. // fall-through
  542. BMError:
  543. UserFreePool(pspb);
  544. }
  545. /***************************************************************************\
  546. * RestoreSpb
  547. *
  548. * Restores the bits associated with pwnd's SPB onto the screen, clipped
  549. * to hrgnUncovered if possible.
  550. *
  551. * Upon return, hrgnUncovered is modified to contain the part of hrgnUncovered
  552. * that must be invalidated by the caller. FALSE is returned if the area
  553. * to be invalidated is empty.
  554. *
  555. * NOTE: Because the device driver SaveBitmap() function can not clip, this
  556. * function may write bits into an area of the screen larger than the passed-in
  557. * hrgnUncovered. In this case, the returned invalid region may be larger
  558. * than the passed-in hrgnUncovered.
  559. *
  560. * History:
  561. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  562. \***************************************************************************/
  563. UINT RestoreSpb(
  564. PWND pwnd,
  565. HRGN hrgnUncovered,
  566. HDC *phdcScreen)
  567. {
  568. PSPB pspb;
  569. UINT uInvalidate;
  570. HRGN hrgnRestorable;
  571. /*
  572. * Note that we DON'T call SpbCheck() here --
  573. * SpbCheck() is called by zzzBltValidBits().
  574. */
  575. pspb = FindSpb(pwnd);
  576. /*
  577. * Assume all of hrgnUncovered was restored, and there's nothing
  578. * for our caller to invalidate.
  579. */
  580. uInvalidate = RSPB_NO_INVALIDATE;
  581. hrgnRestorable = hrgnUncovered;
  582. /*
  583. * First determine whether or not there is any area at all to restore.
  584. * If hrgnUncovered & pspb->hrgn is empty, then all of hrgnUncovered
  585. * needs to be invalidated, and there's nothing to restore.
  586. */
  587. if (pspb->hrgn != NULL) {
  588. /*
  589. * At least some of hrgnUncovered needs to be invalidated.
  590. */
  591. uInvalidate = RSPB_INVALIDATE;
  592. /*
  593. * Calculate the true area of bits to be restored. If it becomes
  594. * empty, then just free the SPB without changing hrgnUncovered,
  595. * which is the area that must be invalidated.
  596. */
  597. hrgnRestorable = ghrgnSPB1;
  598. switch (IntersectRgn(hrgnRestorable, hrgnUncovered, pspb->hrgn)) {
  599. case ERROR:
  600. case NULLREGION:
  601. goto Error;
  602. default:
  603. break;
  604. }
  605. }
  606. if (pspb->flags & SPB_SAVESCREENBITS) {
  607. RECT rc = pspb->rc;
  608. /*
  609. * Since the restore frees the onboard memory, clear this
  610. * bit so FreeSpb() won't try to free it again (regardless of
  611. * whether we get an error or not)
  612. */
  613. pspb->flags &= ~SPB_SAVESCREENBITS;
  614. if (!(GreSaveScreenBits(gpDispInfo->hDev,
  615. SS_RESTORE,
  616. pspb->ulSaveId,
  617. (RECTL *)&rc))) {
  618. goto Error;
  619. }
  620. /*
  621. * The SS_RESTORE call will always restore the entire SPB
  622. * rectangle, part of which may fall outside of hrgnUncovered.
  623. * The area that must be invalidated by our caller is simply
  624. * the SPB rectangle minus the area of restorable bits.
  625. *
  626. * If this region is not empty, then the SPB was not completely
  627. * restored, so we must return FALSE.
  628. */
  629. SetRectRgnIndirect(ghrgnSPB2, &pspb->rc);
  630. if (SubtractRgn(hrgnUncovered, ghrgnSPB2, hrgnRestorable) != NULLREGION) {
  631. uInvalidate = RSPB_INVALIDATE_SSB;
  632. }
  633. } else {
  634. HDC hdcScreen;
  635. HBITMAP hbmSave;
  636. /*
  637. * In the unlikely event we need a screen DC and one wasn't passed in,
  638. * get it now. If we get one, we return the handle in *phdcScreen
  639. * so that our caller can release it later.
  640. */
  641. if (!*phdcScreen) {
  642. *phdcScreen = gpDispInfo->hdcScreen;
  643. }
  644. hdcScreen = *phdcScreen;
  645. hbmSave = (HBITMAP)GreSelectBitmap(ghdcMem, pspb->hbm);
  646. if (!hbmSave)
  647. goto Error;
  648. /*
  649. * Be sure to clip to the area of restorable bits.
  650. */
  651. GreSelectVisRgn(hdcScreen, hrgnRestorable, SVR_COPYNEW);
  652. GreBitBlt(hdcScreen,
  653. pspb->rc.left, pspb->rc.top,
  654. pspb->rc.right - pspb->rc.left,
  655. pspb->rc.bottom - pspb->rc.top,
  656. ghdcMem,
  657. pspb->rc.left & 0x0007,
  658. 0,
  659. SRCCOPY,
  660. 0);
  661. GreSelectBitmap(ghdcMem, hbmSave);
  662. /*
  663. * Now compute the area to be invalidated for return.
  664. * This is simply the original hrgnUncovered - hrgnRestorable
  665. */
  666. SubtractRgn(hrgnUncovered, hrgnUncovered, hrgnRestorable);
  667. }
  668. if (pwnd->hrgnClip == NULL || !IsVisible(pwnd))
  669. FreeSpb(pspb);
  670. return uInvalidate;
  671. Error:
  672. FreeSpb(pspb);
  673. return RSPB_INVALIDATE;
  674. }
  675. /***************************************************************************\
  676. * LockWindowUpdate2 (API)
  677. *
  678. * Locks gspwndLockUpdate and it's children from updating. If
  679. * gspwndLockUpdate is NULL, then all windows will be unlocked. When
  680. * unlocked, the portions of the screen that would have been written to
  681. * are invalidated so they get repainted. TRUE is returned if the routine
  682. * is successful.
  683. *
  684. * If called when another app has something locked, then this function fails.
  685. *
  686. * History:
  687. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  688. \***************************************************************************/
  689. BOOL LockWindowUpdate2(
  690. PWND pwndLock,
  691. BOOL fThreadOverride)
  692. {
  693. PSPB pspb;
  694. BOOL fInval;
  695. HRGN hrgn;
  696. PTHREADINFO ptiCurrent = PtiCurrent();
  697. if ( /*
  698. * If we're full screen right now, fail this call.
  699. */
  700. TEST_PUDF(PUDF_LOCKFULLSCREEN)
  701. ||
  702. /*
  703. * If the screen is already locked, and it's being locked
  704. * by some other app, then fail. If fThreadOverride is set
  705. * then we're calling internally and it's okay to cancel
  706. * someone elses LockUpdate.
  707. */
  708. ( gptiLockUpdate != NULL &&
  709. gptiLockUpdate != PtiCurrent() &&
  710. !fThreadOverride)) {
  711. UserAssert(IsWinEventNotifyDeferredOK());
  712. RIPERR0(ERROR_SCREEN_ALREADY_LOCKED,
  713. RIP_WARNING,
  714. "LockWindowUpdate failed because screen is locked by another application.");
  715. return FALSE;
  716. }
  717. if ((pwndLock != NULL) == (gptiLockUpdate != NULL)) {
  718. if (!fThreadOverride) {
  719. RIPERR1(ERROR_INVALID_PARAMETER,
  720. RIP_WARNING,
  721. "LockWindowUpdate failed because it is already %s.",
  722. (pwndLock != NULL) ? "locked" : "unlocked");
  723. }
  724. return FALSE;
  725. }
  726. /*
  727. * This must be done while holding the screen critsec.
  728. * Deadlock if we callback during this, so defer WinEvent notifications
  729. */
  730. DeferWinEventNotify();
  731. GreLockDisplay(gpDispInfo->hDev);
  732. if (pwndLock != NULL) {
  733. /*
  734. * We're about to make pwndLock and its siblings invisible:
  735. * go invalidate any other affected SPBs.
  736. */
  737. SpbCheckPwnd(pwndLock);
  738. CreateSpb(pwndLock, SPB_LOCKUPDATE, NULL);
  739. Lock(&(gspwndLockUpdate), pwndLock);
  740. gptiLockUpdate = ptiCurrent;
  741. zzzInvalidateDCCache(pwndLock, IDC_DEFAULT);
  742. } else {
  743. /*
  744. * Flush any accumulated rectangles and invalidate spbs.
  745. */
  746. SpbCheck();
  747. /*
  748. * Save this in a local before we set it to NULL
  749. */
  750. pwndLock = gspwndLockUpdate;
  751. gptiLockUpdate = NULL;
  752. Unlock(&gspwndLockUpdate);
  753. zzzInvalidateDCCache(pwndLock, IDC_DEFAULT);
  754. /*
  755. * Assume SPB doesn't exist, or couldn't be created, and that we
  756. * must invalidate the entire window.
  757. */
  758. fInval = TRUE;
  759. hrgn = HRGN_FULL;
  760. /*
  761. * Find the LOCKUPDATE spb in the list, and if present calculate
  762. * the area that has been invalidated, if any.
  763. */
  764. for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) {
  765. if (pspb->flags & SPB_LOCKUPDATE) {
  766. if (pspb->hrgn == NULL) {
  767. /*
  768. * If no invalid area, then no invalidation needed.
  769. */
  770. fInval = FALSE;
  771. } else {
  772. /*
  773. * Subtract SPB valid region from SPB rectangle, to
  774. * yield invalid region.
  775. */
  776. hrgn = ghrgnSPB1;
  777. SetRectRgnIndirect(hrgn, &pspb->rc);
  778. /*
  779. * If spb rect minus the spb valid rgn is empty,
  780. * then there is nothing to invalidate.
  781. */
  782. fInval = SubtractRgn(hrgn, hrgn, pspb->hrgn) != NULLREGION;
  783. }
  784. FreeSpb(pspb);
  785. /*
  786. * Exit this loop (there can be only one LOCKUPDATE spb)
  787. */
  788. break;
  789. }
  790. }
  791. if (fInval) {
  792. /*
  793. * When unlocking a Layered window (or a child of a layered
  794. * window), we need to invalidate that layered window specifically
  795. * or the window will ignore the invalidation request. For regular
  796. * windows, we invalidate the desktop instead.
  797. */
  798. PWND pwndInvalidate;
  799. if ((pwndInvalidate = GetStyleWindow(pwndLock, WEFLAYERED)) == NULL) {
  800. pwndInvalidate = PWNDDESKTOP(pwndLock);
  801. }
  802. BEGINATOMICCHECK();
  803. // want to prevent WinEvent notifies, but this make break asserts
  804. DeferWinEventNotify();
  805. xxxInternalInvalidate(pwndInvalidate,
  806. hrgn,
  807. RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  808. zzzEndDeferWinEventNotify();
  809. ENDATOMICCHECK();
  810. }
  811. /*
  812. * Invalidate any other SPBs affected by the fact that this window
  813. * and its children are being made visible.
  814. */
  815. SpbCheckPwnd(pwndLock);
  816. }
  817. GreUnlockDisplay(gpDispInfo->hDev);
  818. zzzEndDeferWinEventNotify();
  819. return TRUE;
  820. }
  821. /***************************************************************************\
  822. * FindSpb
  823. *
  824. * Returns a pointer to the SPB structure associated with the specified
  825. * window or NULL if there is no associated structure.
  826. *
  827. * History:
  828. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  829. \***************************************************************************/
  830. PSPB FindSpb(
  831. PWND pwnd)
  832. {
  833. PSPB pspb;
  834. /*
  835. * Walk through the list of save popup bits looking for a match on
  836. * window handle.
  837. */
  838. for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspb->pspbNext) {
  839. if (pspb->spwnd == pwnd && !(pspb->flags & SPB_LOCKUPDATE))
  840. break;
  841. }
  842. return pspb;
  843. }
  844. /***************************************************************************\
  845. * SpbCheck
  846. *
  847. * Modifies all of the save popup bits structures to reflect changes on the
  848. * screen. This function walks through all of the DC's, and if the DC is
  849. * dirty, then the dirty area is removed from the associated save popup bits
  850. * structure.
  851. *
  852. * History:
  853. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  854. \***************************************************************************/
  855. VOID SpbCheck(VOID)
  856. {
  857. PDCE pdce;
  858. RECT rcBounds;
  859. if (AnySpbs()) {
  860. GreLockDisplay(gpDispInfo->hDev);
  861. /*
  862. * Walk through all of the DC's, accumulating dirty areas.
  863. */
  864. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  865. /*
  866. * Only check valid cache entries...
  867. */
  868. if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS))
  869. continue;
  870. SpbCheckDce(pdce);
  871. }
  872. /*
  873. * Subtact out DirectDraw dirty rect from all the SPB's. The call to
  874. * GreGetDirectDrawBounds will also reset the accumulated bounds.
  875. */
  876. if (GreGetDirectDrawBounds(gpDispInfo->hDev, &rcBounds)) {
  877. SpbCheckRect(NULL, &rcBounds, 0);
  878. }
  879. GreUnlockDisplay(gpDispInfo->hDev);
  880. }
  881. }
  882. /***************************************************************************\
  883. * SpbCheckDce
  884. *
  885. * This function retrieves the dirty area of a DC and removes the area from
  886. * the list of SPB structures. The DC is then marked as clean.
  887. *
  888. * History:
  889. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  890. \***************************************************************************/
  891. VOID SpbCheckDce(
  892. PDCE pdce)
  893. {
  894. RECT rc;
  895. if (pdce->DCX_flags & DCX_REDIRECTED)
  896. return;
  897. /*
  898. * Query the dirty bounds rectangle. Doing this clears the bounds
  899. * as well.
  900. */
  901. if (GreGetBounds(pdce->hdc, &rc, 0)) {
  902. if (pdce->pMonitor != NULL) {
  903. /*
  904. * Convert the bounds rect to screen coords.
  905. */
  906. OffsetRect(&rc, pdce->pMonitor->rcMonitor.left,
  907. pdce->pMonitor->rcMonitor.top);
  908. }
  909. /*
  910. * Intersect the returned rectangle with the window rectangle
  911. * in case the guy was drawing outside his window
  912. */
  913. if (IntersectRect(&rc, &rc, &(pdce->pwndOrg)->rcWindow))
  914. SpbCheckRect(pdce->pwndOrg, &rc, pdce->DCX_flags);
  915. }
  916. }
  917. /***************************************************************************\
  918. * SpbCheckRect
  919. *
  920. * This function removes the passed rectangle from the SPB structures which
  921. * touch it.
  922. *
  923. * History:
  924. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  925. \***************************************************************************/
  926. VOID SpbCheckRect(
  927. PWND pwnd,
  928. LPRECT lprc,
  929. DWORD flags)
  930. {
  931. PSPB pspb, pspbNext;
  932. /*
  933. * If this window isn't visible, we're done.
  934. */
  935. if (!IsVisible(pwnd))
  936. return;
  937. for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) {
  938. /*
  939. * Get the pointer to the next save popup bits structure now
  940. * in case SpbCheckRect2() frees the current one.
  941. */
  942. pspbNext = pspb->pspbNext;
  943. /*
  944. * In win3.1 they used to exit the function if this function
  945. * returned false. This meant that if one of the spbs was freed
  946. * the rest of the spbs would not be invalidated.
  947. */
  948. SpbCheckRect2(pspb, pwnd, lprc, flags);
  949. }
  950. }
  951. /***************************************************************************\
  952. * SpbCheckPwnd
  953. *
  954. * This routine checks to see if the window rectangle of PWND affects any SPBs.
  955. * It is called if pwnd or its children are being hidden or shown without
  956. * going through WinSetWindowPos().
  957. *
  958. * Any SPBs for children of pwnd are destroyed.
  959. *
  960. * It must be called while pwnd is still visible.
  961. *
  962. * History:
  963. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  964. \***************************************************************************/
  965. VOID SpbCheckPwnd(
  966. PWND pwnd)
  967. {
  968. PSPB pspb;
  969. PWND pwndSpb;
  970. PSPB pspbNext;
  971. /*
  972. * First blow away any SPBs owned by this window or its children.
  973. */
  974. for (pspb = gpDispInfo->pspbFirst; pspb != NULL; pspb = pspbNext) {
  975. /*
  976. * Get pspbNext now in case we free the SPB
  977. */
  978. pspbNext = pspb->pspbNext;
  979. /*
  980. * If pspb->spwnd is == pwnd or a child of pwnd, then free the SPB
  981. */
  982. for (pwndSpb = pspb->spwnd; pwndSpb; pwndSpb = pwndSpb->spwndParent) {
  983. if (pwnd == pwndSpb)
  984. FreeSpb(pspb);
  985. }
  986. }
  987. /*
  988. * Then see if any other SPBs are affected...
  989. */
  990. if (gpDispInfo->pspbFirst != NULL) {
  991. SpbCheckRect(pwnd, &pwnd->rcWindow, 0);
  992. }
  993. }
  994. /***************************************************************************\
  995. * FreeSpb
  996. *
  997. * This function deletes the bitmap and region assocaited with a save popup
  998. * bits structure and then unlinks and destroys the spb structure itself.
  999. *
  1000. * History:
  1001. * 18-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1002. \***************************************************************************/
  1003. VOID FreeSpb(
  1004. PSPB pspb)
  1005. {
  1006. PSPB *ppspb;
  1007. PDCE pdce;
  1008. if (pspb == NULL)
  1009. return;
  1010. /*
  1011. * Delete the bitmap. If saved in screen memory, make special call.
  1012. */
  1013. if (pspb->flags & SPB_SAVESCREENBITS) {
  1014. GreSaveScreenBits(gpDispInfo->hDev, SS_FREE, pspb->ulSaveId, NULL);
  1015. } else if (pspb->hbm != NULL) {
  1016. GreDeleteObject(pspb->hbm);
  1017. }
  1018. /*
  1019. * Destroy the region.
  1020. */
  1021. if (pspb->hrgn != NULL){
  1022. GreDeleteObject(pspb->hrgn);
  1023. }
  1024. /*
  1025. * Forget that there is an attached SPB.
  1026. */
  1027. if (pspb->spwnd != NULL) {
  1028. ClrWF(pspb->spwnd, WFHASSPB);
  1029. Unlock(&pspb->spwnd);
  1030. }
  1031. /*
  1032. * Unlink the spb.
  1033. */
  1034. ppspb = &gpDispInfo->pspbFirst;
  1035. while (*ppspb != pspb) {
  1036. ppspb = &(*ppspb)->pspbNext;
  1037. }
  1038. *ppspb = pspb->pspbNext;
  1039. /*
  1040. * Free the save popup bits structure.
  1041. */
  1042. UserFreePool(pspb);
  1043. /*
  1044. * If we no longer have any SPBs then turn off window MGR
  1045. * bounds collection.
  1046. */
  1047. if (!AnySpbs()) {
  1048. GreLockDisplay(gpDispInfo->hDev);
  1049. /*
  1050. * Reset the dirty areas of all of the DC's. NULL means reset.
  1051. */
  1052. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  1053. if (pdce->DCX_flags & DCX_REDIRECTED)
  1054. continue;
  1055. GreGetBounds(pdce->hdc, NULL, GGB_DISABLE_WINMGR);
  1056. }
  1057. GreUnlockDisplay(gpDispInfo->hDev);
  1058. }
  1059. }
  1060. /***************************************************************************\
  1061. * FreeAllSpbs
  1062. *
  1063. * This function deletes all spb-bitmaps.
  1064. *
  1065. * History:
  1066. * 07-Oct-1995 ChrisWil Ported from Chicago.
  1067. \***************************************************************************/
  1068. VOID FreeAllSpbs(void)
  1069. {
  1070. while(AnySpbs()) {
  1071. FreeSpb(gpDispInfo->pspbFirst);
  1072. }
  1073. gpDispInfo->pspbFirst = NULL;
  1074. }