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.

1874 lines
60 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: update.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the APIs used to invalidate, validate, and force
  7. * updating of windows.
  8. *
  9. * History:
  10. * 27-Oct-1990 DarrinM Created.
  11. * 25-Jan-1991 IanJa Revalidation added
  12. * 16-Jul-1991 DarrinM Recreated from Win 3.1 sources.
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * Local Constants.
  18. */
  19. #define UW_ENUMCHILDREN 0x0001
  20. #define UW_RECURSED 0x0004
  21. #define RIR_OUTSIDE 0
  22. #define RIR_INTERSECT 1
  23. #define RIR_INSIDE 2
  24. #define RDW_IGNOREUPDATEDIRTY 0x8000
  25. /***************************************************************************\
  26. * xxxInvalidateRect (API)
  27. *
  28. *
  29. * History:
  30. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  31. \***************************************************************************/
  32. BOOL xxxInvalidateRect(
  33. PWND pwnd,
  34. LPRECT lprcInvalid,
  35. BOOL fErase)
  36. {
  37. CheckLock(pwnd);
  38. /*
  39. * BACKWARD COMPATIBILITY HACK
  40. *
  41. * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with
  42. * hwnd == NULL always INVALIDATED and ERASED the entire desktop, and
  43. * synchronously sent WM_ERASEBKGND and WM_NCPAINT messages before
  44. * returning. The Rgn() calls did not have this behavior.
  45. */
  46. if (pwnd == NULL) {
  47. return xxxRedrawWindow(
  48. pwnd,
  49. NULL,
  50. NULL,
  51. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW);
  52. } else {
  53. return xxxRedrawWindow(
  54. pwnd,
  55. lprcInvalid,
  56. NULL,
  57. fErase ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE);
  58. }
  59. }
  60. /***************************************************************************\
  61. * xxxValidateRect (API)
  62. *
  63. *
  64. * History:
  65. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  66. \***************************************************************************/
  67. BOOL xxxValidateRect(
  68. PWND pwnd,
  69. LPRECT lprcValid)
  70. {
  71. CheckLock(pwnd);
  72. /*
  73. * BACKWARD COMPATIBILITY HACK
  74. *
  75. * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with
  76. * hwnd == NULL always INVALIDATED and ERASED the entire desktop, and
  77. * synchronously sent WM_ERASEBKGND and WM_NCPAINT messages before
  78. * returning. The Rgn() calls did not have this behavior.
  79. */
  80. if (pwnd == NULL) {
  81. return xxxRedrawWindow(
  82. pwnd,
  83. NULL,
  84. NULL,
  85. RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_ERASENOW);
  86. } else {
  87. return xxxRedrawWindow(pwnd, lprcValid, NULL, RDW_VALIDATE);
  88. }
  89. }
  90. /***************************************************************************\
  91. * xxxInvalidateRgn (API)
  92. *
  93. *
  94. * History:
  95. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  96. \***************************************************************************/
  97. BOOL xxxInvalidateRgn(
  98. PWND pwnd,
  99. HRGN hrgnInvalid,
  100. BOOL fErase)
  101. {
  102. CheckLock(pwnd);
  103. return xxxRedrawWindow(
  104. pwnd,
  105. NULL,
  106. hrgnInvalid,
  107. fErase ? RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE);
  108. }
  109. /***************************************************************************\
  110. * xxxValidateRgn (API)
  111. *
  112. *
  113. * History:
  114. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  115. \***************************************************************************/
  116. BOOL xxxValidateRgn(
  117. PWND pwnd,
  118. HRGN hrgnValid)
  119. {
  120. CheckLock(pwnd);
  121. return xxxRedrawWindow(pwnd, NULL, hrgnValid, RDW_VALIDATE);
  122. }
  123. /***************************************************************************\
  124. * SmartRectInRegion
  125. *
  126. * This routine is similar to RectInRegion, except that it also determines
  127. * whether or not *lprc is completely within hrgn or not.
  128. *
  129. * RIR_OUTSIDE - no intersection
  130. * RIR_INTERSECT - *lprc intersects hrgn, but not completely inside
  131. * RIR_INSIDE - *lprc is completely within hrgn.
  132. *
  133. * LATER:
  134. * It would be MUCH faster to put this functionality into GDI's RectInRegion
  135. * call (a la PM's RectInRegion)
  136. *
  137. * History:
  138. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  139. \***************************************************************************/
  140. UINT SmartRectInRegion(
  141. HRGN hrgn,
  142. LPRECT lprc)
  143. {
  144. RECT rc;
  145. if (!GreRectInRegion(hrgn, lprc))
  146. return RIR_OUTSIDE;
  147. /*
  148. * Algorithm: if the intersection of hrgn and *lprc is the
  149. * same as *lprc, then *lprc is completely within hrgn.
  150. *
  151. * If the region is a rectangular one, then do it the easy way.
  152. */
  153. if (GreGetRgnBox(hrgn, &rc) == SIMPLEREGION) {
  154. if (!IntersectRect(&rc, &rc, lprc))
  155. return RIR_OUTSIDE;
  156. if (EqualRect(lprc, &rc))
  157. return RIR_INSIDE;
  158. } else {
  159. SetRectRgnIndirect(ghrgnInv2, lprc);
  160. switch (IntersectRgn(ghrgnInv2, ghrgnInv2, hrgn)) {
  161. case SIMPLEREGION:
  162. GreGetRgnBox(ghrgnInv2, &rc);
  163. if (EqualRect(lprc, &rc))
  164. return RIR_INSIDE;
  165. break;
  166. #define RECTINREGION_BUG
  167. #ifdef RECTINREGION_BUG
  168. /*
  169. * NOTE: RectInRegion has a BUG, where it sometimes returns TRUE
  170. * even if the rectangles of a region touch only on the edges
  171. * with no overlap. This will result in an empty region after
  172. * the combination above.
  173. */
  174. case NULLREGION:
  175. return RIR_OUTSIDE;
  176. break;
  177. #endif
  178. default:
  179. break;
  180. }
  181. }
  182. return RIR_INTERSECT;
  183. }
  184. /***************************************************************************\
  185. * PixieHack
  186. *
  187. * BACKWARD COMPATIBILITY HACK
  188. *
  189. * In 3.0, WM_NCPAINT messages would be sent to any child window that was
  190. * inside the bounding rectangle of a window management operation involving
  191. * any other child, even if the intersection of that region with the child
  192. * is empty.
  193. *
  194. * Some apps such as Pixie 2.3 and CA Cricket Presents rely on this to ensure
  195. * that their tool windows stay on top of other child windows. When the tool
  196. * window gets a WM_NCPAINT, it brings itself to the top of the pile.
  197. *
  198. * Borland ObjectVision depends on getting the WM_NCPAINT after an
  199. * invalidation of its parent window in an area that include the non-client
  200. * area of the child. When it recieves the WM_NCPAINT, it must get a
  201. * clip region of HRGN_FULL, or nothing gets drawn.
  202. *
  203. * History:
  204. * 02-Mar-1992 MikeKe Ported from Win 3.1 sources.
  205. \***************************************************************************/
  206. VOID PixieHack(
  207. PWND pwnd,
  208. LPRECT prcBounds)
  209. {
  210. /*
  211. * If a child intersects the update region, and it isn't already
  212. * getting an NCPAINT, then make sure it gets one later.
  213. *
  214. * Don't apply this hack to top level windows.
  215. */
  216. if ((pwnd != _GetDesktopWindow()) &&
  217. TestWF(pwnd, WFCLIPCHILDREN) &&
  218. !TestWF(pwnd, WFMINIMIZED)) {
  219. RECT rc;
  220. for (pwnd = pwnd->spwndChild; pwnd; pwnd = pwnd->spwndNext) {
  221. /*
  222. * If the window isn't already getting an NCPAINT message,
  223. * and it has a caption, and it's inside the bounding rect,
  224. * make sure it gets a WM_NCPAINT with wParam == HRGN_FULL.
  225. */
  226. if (!TestWF(pwnd, WFSENDNCPAINT) &&
  227. (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION)) &&
  228. IntersectRect(&rc, prcBounds, &pwnd->rcWindow)) {
  229. /*
  230. * Sync paint count is incremented when
  231. * (senderasebkgnd | sendncpaint) goes from 0 to != 0.
  232. * (should make a routine out of this!)
  233. */
  234. SetWF(pwnd, WFSENDNCPAINT);
  235. /*
  236. * Force HRGN_FULL clip rgn.
  237. */
  238. SetWF(pwnd, WFPIXIEHACK);
  239. }
  240. }
  241. }
  242. }
  243. /***************************************************************************\
  244. * xxxRedrawWindow (API)
  245. *
  246. * Forward to xxxInvalidateWindow if the window is visible.
  247. *
  248. * BACKWARD COMPATIBILITY HACK
  249. *
  250. * In Windows 3.0 and less, ValidateRect/InvalidateRect() call with pwnd == NULL
  251. * always INVALIDATED and ERASED all windows, and synchronously sent
  252. * WM_ERASEBKGND and WM_NCPAINT messages before returning. The Rgn() calls
  253. * did not have this behavior. This case is handled in
  254. * InvalidateRect/ValidateRect.
  255. *
  256. * History:
  257. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  258. \***************************************************************************/
  259. BOOL xxxRedrawWindow(
  260. PWND pwnd,
  261. LPRECT lprcUpdate,
  262. HRGN hrgnUpdate,
  263. DWORD flags)
  264. {
  265. CheckLock(pwnd);
  266. /*
  267. * Always map NULL to the desktop.
  268. */
  269. if (pwnd == NULL) {
  270. pwnd = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  271. }
  272. UserAssert(pwnd != NULL);
  273. if (IsVisible(pwnd)) {
  274. TL tlpwnd;
  275. HRGN hrgn = hrgnUpdate;
  276. if (flags & (RDW_VALIDATE | RDW_INVALIDATE)) {
  277. /*
  278. * Create a (in)validate region in client window coordinates.
  279. */
  280. if (hrgn == NULL) {
  281. if (!lprcUpdate) {
  282. hrgn = HRGN_FULL;
  283. } else {
  284. hrgn = ghrgnInv0;
  285. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  286. MirrorClientRect(pwnd, lprcUpdate);
  287. }
  288. if (pwnd == PWNDDESKTOP(pwnd)) {
  289. SetRectRgnIndirect(hrgn, lprcUpdate);
  290. } else {
  291. GreSetRectRgn(
  292. hrgn,
  293. lprcUpdate->left + pwnd->rcClient.left,
  294. lprcUpdate->top + pwnd->rcClient.top,
  295. lprcUpdate->right + pwnd->rcClient.left,
  296. lprcUpdate->bottom + pwnd->rcClient.top);
  297. }
  298. }
  299. } else {
  300. /*
  301. * If necessary, make a copy of the passed-in region, because
  302. * we'll be trashing it...
  303. */
  304. if (hrgn != HRGN_FULL) {
  305. CopyRgn(ghrgnInv0, hrgn);
  306. MirrorRegion(pwnd, ghrgnInv0, TRUE);
  307. hrgn = ghrgnInv0;
  308. }
  309. if (pwnd != PWNDDESKTOP(pwnd)) {
  310. GreOffsetRgn(hrgn, pwnd->rcClient.left, pwnd->rcClient.top);
  311. }
  312. }
  313. }
  314. ThreadLock(pwnd, &tlpwnd);
  315. xxxInternalInvalidate(pwnd, hrgn, flags | RDW_REDRAWWINDOW);
  316. ThreadUnlock(&tlpwnd);
  317. }
  318. return TRUE;
  319. }
  320. /***************************************************************************\
  321. * InternalInvalidate2
  322. *
  323. * (In)validates hrgn in pwnd and in child windows of pwnd. Child windows
  324. * also subtract their visible region from hrgnSubtract.
  325. *
  326. * pwnd - The window to (in)validate.
  327. * hrng - The region to (in)validate.
  328. * hrgnSubtract - The region to subtract the visible region of
  329. * child windows from.
  330. * prcParents - Contains the intersection of pwnd's client or window rect
  331. * with the client rectangles of its parents. May just be
  332. * the window's client or window rect.
  333. *
  334. * flags - RDW_ flags.
  335. *
  336. * Returns FALSE if hrgnSubtract becomes a NULLREGION, TRUE otherwise.
  337. *
  338. * History:
  339. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  340. \***************************************************************************/
  341. BOOL InternalInvalidate2(
  342. PWND pwnd,
  343. HRGN hrgn,
  344. HRGN hrgnSubtract,
  345. LPRECT prcParents,
  346. DWORD flags)
  347. {
  348. /*
  349. * NOTE: Uses ghrgnInv2
  350. */
  351. RECT rcOurShare;
  352. DWORD flagsChildren;
  353. PWND pwndT;
  354. /*
  355. * This routine is called recursively down the parent/child chain.
  356. * Remember if on the way one of the windows has a clipping region.
  357. * This info is used later on to optimize out a loop in the common
  358. * case.
  359. */
  360. if (pwnd->hrgnClip != NULL) {
  361. flags |= RDW_HASWINDOWRGN;
  362. }
  363. /*
  364. * If we recurse, make sure our children subtract themselves off.
  365. */
  366. flagsChildren = flags | RDW_SUBTRACTSELF;
  367. CopyRect(&rcOurShare, &pwnd->rcWindow);
  368. /*
  369. * If we're invalidating, we only want to deal with the part of
  370. * our window rectangle that intersects our parents.
  371. * This way, we don't end up validating or invalidating more than our
  372. * fair share. If we're completely obscured by our parents, then there is
  373. * nothing to do.
  374. *
  375. * We don't perform this intersection if we're validating, because there
  376. * are cases where a child and its update region may exist but be obscured
  377. * by parents, and we want to make sure validation will work in these
  378. * cases. ScrollWindow() can cause this when children are offset, as can
  379. * various 3.0 compatibility hacks.
  380. */
  381. if (flags & RDW_INVALIDATE) {
  382. /*
  383. * Don't subtract out any sprite windows from the invalid region.
  384. * Behave as if it's not there. However, always allow layered window
  385. * invalidation when RDW_INVALIDATELAYERS is passed in.
  386. */
  387. #ifdef REDIRECTION
  388. if ((TestWF(pwnd, WEFLAYERED) || TestWF(pwnd, WEFEXTREDIRECTED)) &&
  389. #else // REDIRECTION
  390. if ((TestWF(pwnd, WEFLAYERED)) &&
  391. #endif // REDIRECTION
  392. !(flags & RDW_INVALIDATELAYERS))
  393. return TRUE;
  394. if (!IntersectRect(&rcOurShare, &rcOurShare, prcParents)) {
  395. /*
  396. * BACKWARD COMPATIBILITY HACK: If hrgn is (HRGN)1, we need to
  397. * invalidate ALL child windows, even if they're not visible. This
  398. * is a bummer, because it'll result in all sorts of repaints that
  399. * aren't necessary.
  400. *
  401. * Various apps, including WordStar for Windows and WaveEdit,
  402. * depend on this behavior. Here's how WaveEdit relies on this: it
  403. * has a CS_HDREDRAW | CS_VREDRAW window, that moves its children
  404. * around with MoveWindow( ..., fRedraw = FALSE). The windows
  405. * not part of the new client area didn't get invalidated.
  406. */
  407. if (!TestWF(pwnd, WFWIN31COMPAT) && (hrgn == HRGN_FULL)) {
  408. /*
  409. * For purposes of hit-testing, our share is our window
  410. * rectangle. However, we don't want to diddle the region
  411. * passed to us, because by rights we're really clipped out!
  412. */
  413. flags &= ~RDW_SUBTRACTSELF;
  414. flagsChildren &= ~RDW_SUBTRACTSELF;
  415. } else {
  416. return TRUE;
  417. }
  418. }
  419. /*
  420. * If our window rect doesn't intersect the valid/invalid region,
  421. * nothing further to do.
  422. */
  423. if (hrgn > HRGN_FULL) {
  424. switch (SmartRectInRegion(hrgn, &rcOurShare)) {
  425. case RIR_OUTSIDE:
  426. return TRUE;
  427. case RIR_INTERSECT:
  428. /*
  429. * The update region can be within the window rect but not
  430. * touch the window region; in this case we don't want this
  431. * update region to be distributed to this window. If this
  432. * is the case, return TRUE as if RIR_OUTSIDE.
  433. *
  434. * If RDW_HASWINDOWRGN is set, either this window or
  435. * one of its parents has a window clipping region. This
  436. * flag is just an optimization so that this loop isn't
  437. * executed all the time.
  438. *
  439. * A future optimization may be to calculate this parent
  440. * clipped region as part of recursion like prcParents is
  441. * calculated. It is not super important though because this
  442. * case rarely happens (a window with a region), and even
  443. * more rare, a regional window that is a child of a regional
  444. * window parent.
  445. */
  446. if (flags & RDW_HASWINDOWRGN) {
  447. /*
  448. * Clip to the window's clipping region and parents!
  449. * If we don't clip to parents, we may get a case where
  450. * a child clips out some update region that was meant to
  451. * go to a sibling of the parent.
  452. */
  453. SetRectRgnIndirect(ghrgnInv2, &rcOurShare);
  454. for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndParent) {
  455. if (pwndT->hrgnClip != NULL) {
  456. /*
  457. * An error at this stage would possibly result
  458. * in more being subtracted out of the clipping
  459. * region that we'd like.
  460. */
  461. IntersectRgn(ghrgnInv2, ghrgnInv2, pwndT->hrgnClip);
  462. }
  463. }
  464. if (IntersectRgn(ghrgnInv2, ghrgnInv2, hrgn) == NULLREGION)
  465. return TRUE;
  466. }
  467. break;
  468. case RIR_INSIDE:
  469. /*
  470. * If the rectangle is completely within hrgn, then we can use
  471. * HRGN_FULL, which is much faster and easier to deal with.
  472. *
  473. * COMPAT HACK: There are some apps (PP, MSDRAW) that depend
  474. * on some weirdities of the 3.0 GetUpdateRect in order to
  475. * paint properly. Since this stuff hinges on whether the
  476. * update region is 1 or a real region, we need to simulate
  477. * when 3.0 would generate a HRGN(1) update region. The
  478. * following optimization was not made in 3.0, so we yank it
  479. * in 3.1 for these apps. (win31 bugs 8235,10380)
  480. */
  481. if (!(GetAppCompatFlags(GETPTI(pwnd)) & GACF_NOHRGN1))
  482. hrgn = HRGN_FULL;
  483. break;
  484. }
  485. }
  486. /*
  487. * While we are in the middle of compositing, no invalidation should
  488. * happen, or it will mess up our painting order. This is because on
  489. * this compositing pass we may validate some of the new invalid area
  490. * and the invalid area that didn't get validated will bleed through
  491. * on the next compositing pass. So we will remember an accumulated
  492. * invalid area which will really get invalidated once the compositing
  493. * pass is completed.
  494. */
  495. if (TestWF(pwnd, WEFPCOMPOSITING)) {
  496. PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  497. if (prdr != NULL) {
  498. HRGN hrgnComp = prdr->hrgnComp;
  499. if (hrgnComp == NULL) {
  500. if ((hrgnComp = CreateEmptyRgnPublic()) == NULL) {
  501. hrgnComp = HRGN_FULL;
  502. }
  503. }
  504. SetRectRgnIndirect(ghrgnInv2, &rcOurShare);
  505. if (hrgnComp != HRGN_FULL) {
  506. GreCombineRgn(hrgnComp, hrgnComp, ghrgnInv2, RGN_OR);
  507. }
  508. prdr->hrgnComp = hrgnComp;
  509. if (SubtractRgn(hrgnSubtract, hrgnSubtract, ghrgnInv2) == NULLREGION) {
  510. return FALSE;
  511. }
  512. return TRUE;
  513. }
  514. }
  515. }
  516. /*
  517. * If not CLIPCHILDREN, go diddle the update region BEFORE our clipped
  518. * children have done their thing to hrgnSubtract. Otherwise,
  519. * we'll diddle after we recurse.
  520. */
  521. if (!TestWF(pwnd, WFCLIPCHILDREN)) {
  522. InternalInvalidate3(pwnd, hrgn, flags);
  523. }
  524. /*
  525. * If this is a GACF_ALWAYSSENDNCPAINT app, take care of it...
  526. */
  527. if (TestWF(pwnd, WFALWAYSSENDNCPAINT))
  528. PixieHack(pwnd, &rcOurShare);
  529. /*
  530. * Recurse on our children if necessary.
  531. *
  532. * By default, our children are enumerated if we are not CLIPCHILDREN.
  533. * Don't bother with children if we're minimized.
  534. */
  535. if ((pwnd->spwndChild != NULL) &&
  536. !TestWF(pwnd, WFMINIMIZED) &&
  537. !(flags & RDW_NOCHILDREN) &&
  538. ((flags & RDW_ALLCHILDREN) || !TestWF(pwnd, WFCLIPCHILDREN))) {
  539. RECT rcChildrenShare;
  540. PWND pwndChild;
  541. /*
  542. * If we're invalidating, make sure our children
  543. * erase and frame themselves. Also, tell children to subtract
  544. * themselves from hrgnSubtract.
  545. */
  546. if (flags & RDW_INVALIDATE) {
  547. flagsChildren |= RDW_ERASE | RDW_FRAME;
  548. }
  549. /*
  550. * Our children are clipped to our client rect, so reflect
  551. * that in the rectangle we give them.
  552. */
  553. if (IntersectRect(&rcChildrenShare, &rcOurShare, &pwnd->rcClient) ||
  554. (!TestWF(pwnd, WFWIN31COMPAT) && (hrgn == HRGN_FULL))) {
  555. for (pwndChild = pwnd->spwndChild; pwndChild != NULL;
  556. pwndChild = pwndChild->spwndNext) {
  557. if (!TestWF(pwndChild, WFVISIBLE))
  558. continue;
  559. if (!InternalInvalidate2(pwndChild,
  560. hrgn,
  561. hrgnSubtract,
  562. &rcChildrenShare,
  563. flagsChildren)) {
  564. /*
  565. * The children swallowed the region:
  566. * If there are no update region related things
  567. * to do then we can just return with FALSE
  568. */
  569. if (!(flags & (RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)))
  570. return FALSE;
  571. /*
  572. * We have to enumerate the rest of the children because
  573. * one of the RDW_NO/INTERNALPAINT bits is set. Since
  574. * there's no longer any update region to worry about,
  575. * strip out the update region bits from the parent
  576. * and child fiags. Also, tell the children not to
  577. * bother subtracting themselves from the region.
  578. */
  579. flags &= ~(RDW_INVALIDATE |
  580. RDW_ERASE |
  581. RDW_FRAME |
  582. RDW_VALIDATE |
  583. RDW_NOERASE |
  584. RDW_NOFRAME);
  585. flagsChildren &= ~(RDW_INVALIDATE |
  586. RDW_ERASE |
  587. RDW_FRAME |
  588. RDW_VALIDATE |
  589. RDW_NOERASE |
  590. RDW_NOFRAME |
  591. RDW_SUBTRACTSELF);
  592. }
  593. }
  594. }
  595. }
  596. /*
  597. * Go diddle the update region (AFTER our clipped children may have
  598. * done their thing to hrgnSubtract)
  599. */
  600. if (TestWF(pwnd, WFCLIPCHILDREN))
  601. InternalInvalidate3(pwnd, hrgn, flags);
  602. /*
  603. * If we're invalidating and we're supposed to,
  604. * try to subtract off our window area from the region.
  605. *
  606. * This way our parent and our siblings below us will not
  607. * get any update region for areas that don't need one.
  608. */
  609. if (flags & RDW_SUBTRACTSELF) {
  610. /*
  611. * Subtract our visible region from the update rgn only if:
  612. * a) we're not a transparent window
  613. * b) we are clipsiblings
  614. * c) we're validating OR our parent is clipchildren.
  615. *
  616. * The check for validation is a backward-compatibility hack: this
  617. * is what 3.0 did, so this is what we do here.
  618. *
  619. * BACKWARD COMPATIBILITY HACK
  620. *
  621. * In 3.0, we subtracted this window from the update rgn if it
  622. * was clipsiblings, even if the parent was not clipchildren.
  623. * This causes a compatibility problem for Lotus Notes 3.1: it
  624. * has a combobox dropdown in a dialog that is a WS_CLIPSIBLING
  625. * sibling of the other dialog controls, which are not WS_CLIPSIBLINGs.
  626. * The dialog is not WS_CLIPCHILDREN. What happens is that a listbox
  627. * underneath the dropdown also gets a paint msg (since we didn't
  628. * do this subtraction), and, since it's not CLIPSIBLINGS, it
  629. * obliterates the dropdown.
  630. *
  631. * This is a very obscure difference, and it's too late in the
  632. * project to make this change now, so we're leaving the code as is
  633. * and using a compatibility hack to enable the 3.0-compatible
  634. * behavior. It's quite likely that this code works the way it does
  635. * for other compatibility reasons. Sigh (neilk).
  636. */
  637. if (!TestWF(pwnd, WEFTRANSPARENT) &&
  638. TestWF(pwnd, WFCLIPSIBLINGS) &&
  639. ((flags & RDW_VALIDATE) ||
  640. ((pwnd->spwndParent != NULL) &&
  641. (TestWF(pwnd->spwndParent, WFCLIPCHILDREN) ||
  642. (GetAppCompatFlags(GETPTI(pwnd)) & GACF_SUBTRACTCLIPSIBS))))) {
  643. /*
  644. * Intersect with our visible area.
  645. *
  646. * Don't worry about errors: an error will result in more, not less
  647. * area being invalidated, which is okay.
  648. */
  649. SetRectRgnIndirect(ghrgnInv2, &rcOurShare);
  650. /*
  651. * If RDW_HASWINDOWRGN is set, either this window or
  652. * one of its parents has a window clipping region. This
  653. * flag is just an optimization so that this loop isn't
  654. * executed all the time.
  655. */
  656. if (flags & RDW_HASWINDOWRGN) {
  657. /*
  658. * Clip to the window's clipping region and parents!
  659. * If we don't clip to parents, we may get a case where
  660. * a child clips out some update region that was meant to
  661. * go to a sibling of the parent.
  662. */
  663. for (pwndT = pwnd; pwndT != NULL; pwndT = pwndT->spwndParent) {
  664. if (pwndT->hrgnClip != NULL) {
  665. /*
  666. * An error at this stage would possibly result in more
  667. * being subtracted out of the clipping region that
  668. * we'd like.
  669. */
  670. IntersectRgn(ghrgnInv2, ghrgnInv2, pwndT->hrgnClip);
  671. }
  672. }
  673. }
  674. #if 1
  675. /*
  676. * TEMP HACK!!! RE-ENABLE this code when regions work again
  677. */
  678. if (SubtractRgn(hrgnSubtract, hrgnSubtract, ghrgnInv2) == NULLREGION)
  679. return FALSE;
  680. #else
  681. {
  682. DWORD iRet;
  683. iRet = SubtractRgn(hrgnSubtract, hrgnSubtract, ghrgnInv2);
  684. if (iRet == NULLREGION)
  685. return FALSE;
  686. if (iRet == SIMPLEREGION) {
  687. RECT rcSub;
  688. GreGetRgnBox(hrgnSubtract, &rcSub);
  689. if (rcSub.left > rcSub.right)
  690. return FALSE;
  691. }
  692. }
  693. #endif
  694. }
  695. }
  696. return TRUE;
  697. }
  698. /***************************************************************************\
  699. * InternalInvalidate3
  700. *
  701. * Adds or subtracts hrgn to the windows update region and sets appropriate
  702. * painting state flags.
  703. *
  704. * pwnd - The window.
  705. * hrng - The region to add to the update region.
  706. * flags - RDW_ flags.
  707. *
  708. * History:
  709. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  710. \***************************************************************************/
  711. VOID InternalInvalidate3(
  712. PWND pwnd,
  713. HRGN hrgn,
  714. DWORD flags)
  715. {
  716. BOOL fNeededPaint;
  717. fNeededPaint = NEEDSPAINT(pwnd);
  718. if (flags & (RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_ERASE | RDW_FRAME)) {
  719. if (flags & RDW_INTERNALPAINT)
  720. SetWF(pwnd, WFINTERNALPAINT);
  721. if (flags & RDW_INVALIDATE) {
  722. /*
  723. * Make sure that the NONCPAINT bit is cleared
  724. * to ensure that the caption will redraw when we update.
  725. */
  726. ClrWF(pwnd, WFNONCPAINT);
  727. /*
  728. * If another app is invalidating this window, then set the
  729. * UPDATEDIRTY flag.
  730. *
  731. * Solves critical section where thread A draws, then validates,
  732. * but thread B goes and invalidates before A validates.
  733. * See comments later in RDW_VALIDATE code.
  734. */
  735. if (GETPTI(pwnd) != PtiCurrent()) {
  736. SetWF(pwnd, WFUPDATEDIRTY);
  737. /*
  738. * Paint order problem, see paint.c
  739. */
  740. if (TestWF(pwnd, WFWMPAINTSENT)) {
  741. SetWF(pwnd, WFDONTVALIDATE);
  742. }
  743. }
  744. /*
  745. * BACKWARD COMPATIBILITY HACK
  746. *
  747. * In 3.0, InvalidateRect(pwnd, NULL, FALSE) would always
  748. * clear the WFSENDERASEBKGND flag, even if it was previously
  749. * set from an InvalidateRect(pwnd, NULL, TRUE). This is bogus,
  750. * because it can cause you to "lose" WM_ERASEBKGND messages, but
  751. * AttachMate Extra (and maybe other apps) depend on this behavior.
  752. */
  753. if ((hrgn == HRGN_FULL) && !TestWF(pwnd, WFWIN31COMPAT))
  754. ClrWF(pwnd, WFSENDERASEBKGND);
  755. if (flags & RDW_ERASE)
  756. SetWF(pwnd, WFSENDERASEBKGND);
  757. if ((flags & (RDW_FRAME | RDW_ERASE)) && !TestWF(pwnd, WEFTRANSPARENT))
  758. SetHungFlag(pwnd, WFREDRAWIFHUNG);
  759. if (flags & RDW_FRAME)
  760. SetWF(pwnd, WFSENDNCPAINT);
  761. /*
  762. * If window is already completely invalidated,
  763. * no need to do any further invalidation.
  764. */
  765. if (pwnd->hrgnUpdate != HRGN_FULL) {
  766. if (hrgn == HRGN_FULL) {
  767. InvalidateAll:
  768. DeleteMaybeSpecialRgn(pwnd->hrgnUpdate);
  769. pwnd->hrgnUpdate = HRGN_FULL;
  770. } else {
  771. if (pwnd->hrgnUpdate == NULL) {
  772. if (!(pwnd->hrgnUpdate = CreateEmptyRgnPublic()))
  773. goto InvalidateAll;
  774. if (CopyRgn(pwnd->hrgnUpdate, hrgn) == ERROR)
  775. goto InvalidateAll;
  776. } else { // pwnd->hrgnUpdate is a region
  777. if (UnionRgn(pwnd->hrgnUpdate,
  778. pwnd->hrgnUpdate,
  779. hrgn) == ERROR) {
  780. goto InvalidateAll;
  781. }
  782. }
  783. }
  784. }
  785. }
  786. if (!fNeededPaint && NEEDSPAINT(pwnd))
  787. IncPaintCount(pwnd);
  788. } else if (flags & (RDW_VALIDATE | RDW_NOINTERNALPAINT | RDW_NOERASE | RDW_NOFRAME)) {
  789. /*
  790. * Validation:
  791. *
  792. * Do not allow validation if this window has been invalidated from
  793. * another process - because this window may be validating just
  794. * after another process invalidated, thereby validating invalid
  795. * bits.
  796. *
  797. * Sometimes applications draw stuff, then validate what they drew.
  798. * If another app invalidated some area during the drawing operation,
  799. * then it will need another paint message.
  800. *
  801. * This wouldn't be necessary if people validated BEFORE they drew.
  802. */
  803. if (TestWF(pwnd, WFUPDATEDIRTY) && !(flags & RDW_IGNOREUPDATEDIRTY))
  804. return;
  805. if (flags & RDW_NOINTERNALPAINT)
  806. ClrWF(pwnd, WFINTERNALPAINT);
  807. if (flags & RDW_VALIDATE) {
  808. if (flags & RDW_NOERASE)
  809. ClrWF(pwnd, WFSENDERASEBKGND);
  810. if (flags & RDW_NOFRAME) {
  811. ClrWF(pwnd, WFSENDNCPAINT);
  812. ClrWF(pwnd, WFPIXIEHACK);
  813. }
  814. if (flags & (RDW_NOERASE | RDW_NOFRAME))
  815. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  816. if (pwnd->hrgnUpdate != NULL) {
  817. /*
  818. * If WFSENDNCPAINT is set, then all or part of the
  819. * window border still needs to be drawn. This means
  820. * that we must subtract off the client rectangle only.
  821. * Convert HRGN_FULL to the client region.
  822. */
  823. if (TestWF(pwnd, WFSENDNCPAINT) && (hrgn == HRGN_FULL)) {
  824. hrgn = ghrgnInv2;
  825. CalcWindowRgn(pwnd, hrgn, TRUE);
  826. }
  827. if (hrgn == HRGN_FULL) {
  828. ValidateAll:
  829. /*
  830. * We're validating the entire window. Just
  831. * blow away the update region.
  832. */
  833. DeleteMaybeSpecialRgn(pwnd->hrgnUpdate);
  834. pwnd->hrgnUpdate = (HRGN)NULL;
  835. /*
  836. * No need to erase the background...
  837. */
  838. ClrWF(pwnd, WFSENDERASEBKGND);
  839. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  840. } else {
  841. /*
  842. * Subtracting some region from pwnd->hrgnUpdate.
  843. * Be sure pwnd->hrgnUpdate is a real region.
  844. */
  845. if (pwnd->hrgnUpdate == HRGN_FULL) {
  846. /*
  847. * If the WFSENDNCPAINT bit is set,
  848. * the update region must include the entire window
  849. * area. Otherwise it includes only the client.
  850. */
  851. pwnd->hrgnUpdate = CreateEmptyRgnPublic();
  852. /*
  853. * If the creation failed, punt by
  854. * invalidating the entire window.
  855. */
  856. if (pwnd->hrgnUpdate == NULL)
  857. goto InvalidateAll;
  858. if (CalcWindowRgn(pwnd,
  859. pwnd->hrgnUpdate,
  860. !(TestWF(pwnd, WFSENDNCPAINT))) == ERROR) {
  861. goto InvalidateAll;
  862. }
  863. }
  864. /*
  865. * Subtract off the region. If we get an error,
  866. * punt by invalidating everything. If the
  867. * region becomes empty, then validate everything.
  868. */
  869. switch (SubtractRgn(pwnd->hrgnUpdate,
  870. pwnd->hrgnUpdate,
  871. hrgn)) {
  872. case ERROR:
  873. goto InvalidateAll;
  874. case NULLREGION:
  875. goto ValidateAll;
  876. }
  877. }
  878. }
  879. }
  880. if (fNeededPaint && !NEEDSPAINT(pwnd))
  881. DecPaintCount(pwnd);
  882. }
  883. }
  884. /***************************************************************************\
  885. * ValidateParents
  886. *
  887. * This routine validates hrgn from the update regions of the parent windows
  888. * between pwnd and its first clip children parent.
  889. * If hrgn is NULL, then the window rect (intersected with all parents)
  890. * is validated.
  891. *
  892. * This routine is called when a window is being drawn in
  893. * UpdateWindow() so that non-CLIPCHILDREN parents
  894. * of windows being redrawn won't draw on their valid children.
  895. *
  896. * Returns FALSE if fRecurse is TRUE and a non-CLIPCHILDREN parent
  897. * has an update region; otherwise, returns TRUE.
  898. *
  899. * History:
  900. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  901. \***************************************************************************/
  902. BOOL ValidateParents(
  903. PWND pwnd,
  904. BOOL fRecurse)
  905. {
  906. RECT rcParents;
  907. RECT rc;
  908. PWND pwndParent = pwnd;
  909. BOOL fInit = FALSE;
  910. /*
  911. * This is checking whether we are in an in-between state, just before
  912. * a WM_SYNCPAINT is about to arrive. If not, then ValidateParents()
  913. * needs to work like it did in Win 3.1.
  914. */
  915. while (TestWF(pwndParent, WFCHILD))
  916. pwndParent = pwndParent->spwndParent;
  917. if (!TestWF(pwndParent, WFSYNCPAINTPENDING))
  918. fRecurse = FALSE;
  919. pwndParent = pwnd;
  920. while ((pwndParent = pwndParent->spwndParent) != NULL) {
  921. /*
  922. * Stop when we find a clipchildren parent
  923. */
  924. if (TestWF(pwndParent, WFCLIPCHILDREN))
  925. break;
  926. /*
  927. * Subtract the region from this parent's update region,
  928. * if it has one.
  929. */
  930. if (pwndParent->hrgnUpdate != NULL) {
  931. if (fRecurse) {
  932. return FALSE;
  933. }
  934. if (!fInit) {
  935. fInit = TRUE;
  936. /*
  937. * Do initial setup. If our window rectangle is
  938. * completely obscured, get out.
  939. */
  940. rc = pwnd->rcWindow;
  941. if (!IntersectWithParents(pwnd, &rc))
  942. break;
  943. SetRectRgnIndirect(ghrgnInv1, &rc);
  944. /*
  945. * If this window has a region, make sure the piece being validated
  946. * is within this region.
  947. */
  948. if (pwnd->hrgnClip != NULL) {
  949. /*
  950. * If we get NULLREGION back, there is nothing to validate
  951. * against parents, so break out. If ERROR gets returned,
  952. * there is not much we can do: the best "wrong" thing
  953. * to do is just continue and validate a little more
  954. * from the parent.
  955. */
  956. if (!IntersectRgn(ghrgnInv1, ghrgnInv1, pwnd->hrgnClip))
  957. break;
  958. }
  959. }
  960. /*
  961. * Calculate the rcParents parameter to
  962. * pass up to InternalInvalidate2.
  963. */
  964. rcParents = pwndParent->rcWindow;
  965. if (!IntersectWithParents(pwndParent, &rcParents))
  966. break;
  967. InternalInvalidate2(
  968. pwndParent,
  969. ghrgnInv1,
  970. ghrgnInv1,
  971. &rcParents,
  972. RDW_VALIDATE | RDW_NOCHILDREN | RDW_IGNOREUPDATEDIRTY);
  973. }
  974. }
  975. return TRUE;
  976. }
  977. /***************************************************************************\
  978. * xxxUpdateWindow2
  979. *
  980. * Sends a WM_PAINT message to the window if it needs painting,
  981. * then sends the message to its children.
  982. *
  983. * Always returns TRUE.
  984. *
  985. * History:
  986. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  987. \***************************************************************************/
  988. void xxxUpdateWindow2(
  989. PWND pwnd,
  990. DWORD flags)
  991. {
  992. TL tlpwnd;
  993. CheckLock(pwnd);
  994. if (NEEDSPAINT(pwnd)) {
  995. /*
  996. * Punch a hole in our parent's update region, if we have one.
  997. */
  998. if (pwnd->hrgnUpdate) {
  999. if (ValidateParents(pwnd, flags & UW_RECURSED) == FALSE) {
  1000. return;
  1001. }
  1002. }
  1003. /*
  1004. * Now that we're sending the message, clear the
  1005. * internal paint bit if it was previously set.
  1006. */
  1007. if (TestWF(pwnd, WFINTERNALPAINT)) {
  1008. ClrWF(pwnd, WFINTERNALPAINT);
  1009. /*
  1010. * If there is no update region, then no further paint messages
  1011. * are pending, so we must dec the paint count.
  1012. */
  1013. if (pwnd->hrgnUpdate == NULL)
  1014. DecPaintCount(pwnd);
  1015. }
  1016. /*
  1017. * Set a flag indicating that a paint message was not processed
  1018. * (but should be).
  1019. */
  1020. SetWF(pwnd, WFPAINTNOTPROCESSED);
  1021. /*
  1022. * Clear this bit, for apps (like MicroLink) that don't call
  1023. * BeginPaint or GetUpdateRect/Rgn (but DO call ValidateRect)
  1024. * when handling their WM_PAINT message.
  1025. */
  1026. ClrWF(pwnd, WFUPDATEDIRTY);
  1027. /*
  1028. * BACKWARD COMPATIBILITY HACK
  1029. *
  1030. * Win 3.0 always sent WM_PAINTICON with wParam == TRUE for no good
  1031. * reason, and Lotus Notes has come to depend on this.
  1032. */
  1033. if (!TestWF(pwnd, WFWIN40COMPAT) &&
  1034. TestWF(pwnd, WFMINIMIZED) &&
  1035. (pwnd->pcls->spicn != NULL)) {
  1036. xxxSendMessage(pwnd, WM_PAINTICON, TRUE, 0L);
  1037. } else {
  1038. xxxSendMessage(pwnd, WM_PAINT, 0, 0L);
  1039. }
  1040. /*
  1041. * If the guy didn't call BeginPaint/EndPaint(), or GetUpdateRect/Rgn
  1042. * with fErase == TRUE, then we have to clean up for him here.
  1043. */
  1044. if (TestWF(pwnd, WFPAINTNOTPROCESSED)) {
  1045. RIPMSG0(RIP_VERBOSE,
  1046. "App didn't call BeginPaint() or GetUpdateRect/Rgn(fErase == TRUE) in WM_PAINT");
  1047. xxxSimpleDoSyncPaint(pwnd);
  1048. }
  1049. }
  1050. /*
  1051. * For desktop window, do not force the top level window repaint at this
  1052. * this point. We are calling UpdateWindow() for the desktop before
  1053. * size/move is sent for the top level windows.
  1054. *
  1055. * BUG: The comment above seems a bit random. Is there really a problem?
  1056. * If nothing else this has to remain this way because it is
  1057. * how Win 3.0 worked (neilk)
  1058. */
  1059. if ((flags & UW_ENUMCHILDREN) && (pwnd != PWNDDESKTOP(pwnd))) {
  1060. /*
  1061. * Update any children...
  1062. */
  1063. ThreadLockNever(&tlpwnd);
  1064. pwnd = pwnd->spwndChild;
  1065. while (pwnd != NULL) {
  1066. /*
  1067. * If there is a transparent window that needs painting,
  1068. * skip it if another window below it needs to paint.
  1069. */
  1070. if (TestWF(pwnd, WEFTRANSPARENT) && NEEDSPAINT(pwnd)) {
  1071. PWND pwndT = pwnd;
  1072. while ((pwndT = pwndT->spwndNext) != NULL) {
  1073. if (NEEDSPAINT(pwndT))
  1074. break;
  1075. }
  1076. if (pwndT != NULL) {
  1077. pwnd = pwnd->spwndNext;
  1078. continue;
  1079. }
  1080. }
  1081. ThreadLockExchangeAlways(pwnd, &tlpwnd);
  1082. xxxUpdateWindow2(pwnd, flags | UW_RECURSED);
  1083. pwnd = pwnd->spwndNext;
  1084. }
  1085. ThreadUnlock(&tlpwnd);
  1086. }
  1087. return;
  1088. }
  1089. /***************************************************************************\
  1090. * xxxInternalUpdateWindow
  1091. *
  1092. * Sends a WM_PAINT message to the window if it needs painting,
  1093. * then sends the message to its children. Won't send WM_PAINT
  1094. * if the window is transparent and has siblings that need
  1095. * painting.
  1096. *
  1097. * History:
  1098. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1099. \***************************************************************************/
  1100. void xxxInternalUpdateWindow(
  1101. PWND pwnd,
  1102. DWORD flags)
  1103. {
  1104. PWND pwndComp;
  1105. CheckLock(pwnd);
  1106. if ((pwndComp = GetStyleWindow(pwnd, WEFCOMPOSITED)) != NULL) {
  1107. TL tlpwnd;
  1108. ThreadLockAlways(pwndComp, &tlpwnd);
  1109. xxxCompositedPaint(pwndComp);
  1110. ThreadUnlock(&tlpwnd);
  1111. return;
  1112. }
  1113. /*
  1114. * If the passed-in window is transparent and a sibling below
  1115. * needs repainting, don't do anything.
  1116. */
  1117. if (TestWF(pwnd, WEFTRANSPARENT)) {
  1118. PWND pwndT = pwnd;
  1119. PTHREADINFO ptiCurrent = GETPTI(pwnd);
  1120. while ((pwndT = pwndT->spwndNext) != NULL) {
  1121. /*
  1122. * Make sure sibling window belongs to same app.
  1123. */
  1124. if (GETPTI(pwndT) != ptiCurrent)
  1125. continue;
  1126. if (NEEDSPAINT(pwndT))
  1127. return;
  1128. }
  1129. }
  1130. /*
  1131. * Enumerate pwnd and all its children, sending WM_PAINTs as needed.
  1132. */
  1133. xxxUpdateWindow2(pwnd, flags);
  1134. }
  1135. /***************************************************************************\
  1136. * xxxInternalInvalidate
  1137. *
  1138. * (In)validates hrgnUpdate and updates the window.
  1139. *
  1140. * History:
  1141. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1142. \***************************************************************************/
  1143. VOID xxxInternalInvalidate(
  1144. PWND pwnd,
  1145. HRGN hrgnUpdate,
  1146. DWORD flags)
  1147. {
  1148. RECT rcParents;
  1149. HRGN hrgnSubtract;
  1150. PWND pwndComp = NULL;
  1151. PWND pwndSave;
  1152. HRGN hrgnComp;
  1153. #if DBG
  1154. if (flags & (RDW_ERASENOW | RDW_UPDATENOW)) {
  1155. CheckLock(pwnd);
  1156. }
  1157. #endif
  1158. /*
  1159. * For children of composited windows, invalidate starting from the
  1160. * composited window itself.
  1161. */
  1162. if (flags & RDW_INVALIDATE) {
  1163. if ((pwndComp = GetStyleWindow(pwnd, WEFCOMPOSITED)) != NULL) {
  1164. if (hrgnUpdate == HRGN_FULL) {
  1165. hrgnComp = GreCreateRectRgnIndirect(&pwnd->rcWindow);
  1166. if (hrgnComp != NULL) {
  1167. hrgnUpdate = hrgnComp;
  1168. }
  1169. } else {
  1170. hrgnComp = NULL;
  1171. }
  1172. pwndSave = pwnd;
  1173. pwnd = pwndComp;
  1174. flags |= RDW_ALLCHILDREN;
  1175. }
  1176. }
  1177. /*
  1178. * Allow invalidation of a layered window when someone specifically
  1179. * invalidates it. This will also prevent invalidation of layered
  1180. * windows during recursive desktop invalidations.
  1181. */
  1182. #ifdef REDIRECTION
  1183. if (TestWF(pwnd, WEFLAYERED) || TestWF(pwnd, WEFEXTREDIRECTED)) {
  1184. #else // REDIRECTION
  1185. if (TestWF(pwnd, WEFLAYERED)) {
  1186. #endif // REDIRECTION
  1187. flags |= RDW_INVALIDATELAYERS;
  1188. }
  1189. /*
  1190. * Ensure that hrgnSubtract is a valid region: if it's NULLREGION,
  1191. * use the client region.
  1192. */
  1193. rcParents = (flags & RDW_FRAME ? pwnd->rcWindow : pwnd->rcClient);
  1194. if (flags & (RDW_VALIDATE | RDW_INVALIDATE)) {
  1195. hrgnSubtract = hrgnUpdate;
  1196. if (hrgnSubtract == HRGN_FULL) {
  1197. hrgnSubtract = ghrgnInv1;
  1198. CalcWindowRgn(pwnd,
  1199. hrgnSubtract,
  1200. (flags & RDW_FRAME) ? FALSE : TRUE);
  1201. }
  1202. /*
  1203. * Calculate the bounding rectangle of our screen real estate,
  1204. * by intersecting with our parent rectangles. While we're at
  1205. * it, check the visibility of ourself and our parents.
  1206. *
  1207. * If we're validating we want to skip this, since there
  1208. * are a number of cases where obscured windows may have
  1209. * update regions to be validated -- in particular, after
  1210. * a ScrollWindow() call where a child window was offset
  1211. * by OffsetChildren() to a new, obscured position. Some of
  1212. * the 3.0 compatibility hacks also can lead to this situation.
  1213. */
  1214. if ((flags & RDW_INVALIDATE) && !IntersectWithParents(pwnd, &rcParents))
  1215. return;
  1216. } else {
  1217. /*
  1218. * hrgnsubtract needs to be a real region even if
  1219. * we are not invalidating or validating. It really doesn't
  1220. * matter what the region is, but we set it to null so the code
  1221. * has less degrees of freedom.
  1222. */
  1223. hrgnSubtract = ghrgnInv1;
  1224. SetEmptyRgn(hrgnSubtract);
  1225. }
  1226. /*
  1227. * If we're invalidating, and we're being called by the app,
  1228. * we need to invalidate any SPBs that might be affected by
  1229. * drawing in the client area of this window.
  1230. * We have to do this because there is no guarantee that the
  1231. * application will draw in an area that is invalidated
  1232. * (e.g., if the window is completely obscured by another).
  1233. */
  1234. if ( (flags & (RDW_INVALIDATE | RDW_REDRAWWINDOW)) == (RDW_INVALIDATE | RDW_REDRAWWINDOW) &&
  1235. AnySpbs()) {
  1236. RECT rcInvalid;
  1237. /*
  1238. * Intersect the parent's rect with the region bounds...
  1239. */
  1240. GreGetRgnBox(hrgnSubtract, &rcInvalid);
  1241. IntersectRect(&rcInvalid, &rcInvalid, &rcParents);
  1242. SpbCheckRect(pwnd, &rcInvalid, 0);
  1243. }
  1244. /*
  1245. * Now go do the recursive update region calculations...
  1246. */
  1247. InternalInvalidate2(pwnd, hrgnUpdate, hrgnSubtract, &rcParents, flags);
  1248. if (pwndComp != NULL) {
  1249. pwnd = pwndSave;
  1250. if (hrgnComp != NULL) {
  1251. GreDeleteObject(hrgnComp);
  1252. }
  1253. }
  1254. /*
  1255. * Finally handle any needed drawing.
  1256. *
  1257. * (NOTE: RDW_UPDATENOW implies RDW_ERASENOW)
  1258. */
  1259. if (flags & RDW_UPDATENOW) {
  1260. xxxInternalUpdateWindow(pwnd,
  1261. flags & RDW_NOCHILDREN ? 0 : UW_ENUMCHILDREN);
  1262. } else if (flags & RDW_ERASENOW) {
  1263. UINT flagsDSP;
  1264. if (flags & RDW_NOCHILDREN) {
  1265. flagsDSP = 0;
  1266. } else if (flags & RDW_ALLCHILDREN) {
  1267. flagsDSP = DSP_ALLCHILDREN;
  1268. } else {
  1269. flagsDSP = DSP_ENUMCLIPPEDCHILDREN;
  1270. }
  1271. xxxDoSyncPaint(pwnd, flagsDSP);
  1272. }
  1273. }
  1274. /***************************************************************************\
  1275. * UpdateWindow (API)
  1276. *
  1277. * Updates the window and all its children.
  1278. *
  1279. * History:
  1280. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1281. \***************************************************************************/
  1282. BOOL xxxUpdateWindow(
  1283. PWND pwnd)
  1284. {
  1285. CheckLock(pwnd);
  1286. xxxInternalUpdateWindow(pwnd, UW_ENUMCHILDREN);
  1287. /*
  1288. * This function needs to return a value, since it is
  1289. * called through NtUserCallHwndLock.
  1290. */
  1291. return TRUE;
  1292. }
  1293. /***************************************************************************\
  1294. * ExcludeUpdateRgn (API)
  1295. *
  1296. * ENTRY: hdc - DC to exclude from
  1297. * pwnd - window handle
  1298. *
  1299. * EXIT: GDI region type
  1300. *
  1301. * WARNINGS: The DC is assumed to correspond to the client area of the window.
  1302. *
  1303. * The map mode of hdc MUST be text mode (0, 0 is top left corner,
  1304. * one pixel per unit, ascending down and to right) or things won't
  1305. * work.
  1306. *
  1307. * History:
  1308. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1309. \***************************************************************************/
  1310. int _ExcludeUpdateRgn(
  1311. HDC hdc,
  1312. PWND pwnd)
  1313. {
  1314. POINT pt;
  1315. if (pwnd->hrgnUpdate == NULL) {
  1316. RECT rc;
  1317. /*
  1318. * Pass FALSE for fXForm since &rc isn't used.
  1319. */
  1320. return GreGetClipBox(hdc, &rc, FALSE);
  1321. } else if (pwnd->hrgnUpdate == HRGN_FULL) {
  1322. return GreIntersectClipRect(hdc, 0, 0, 0, 0);
  1323. } else {
  1324. /*
  1325. * If no clip rgn exists, then subtract from a device-sized clip rgn.
  1326. * (GetClipRgn returns clip rgn in screen coordinates).
  1327. */
  1328. GreGetDCOrg(hdc, &pt);
  1329. if (GreGetRandomRgn(hdc, ghrgnInv1, 1) != 1) {
  1330. CopyRgn(ghrgnInv1, gpDispInfo->hrgnScreen);
  1331. } else {
  1332. /*
  1333. * Gets returned in dc coords - translate to screen.
  1334. */
  1335. GreOffsetRgn(ghrgnInv1, pt.x, pt.y);
  1336. }
  1337. SubtractRgn(ghrgnInv1, ghrgnInv1, pwnd->hrgnUpdate);
  1338. /*
  1339. * Map to dc coords before select
  1340. */
  1341. GreOffsetRgn(ghrgnInv1, -pt.x, -pt.y);
  1342. return GreExtSelectClipRgn(hdc, ghrgnInv1, RGN_COPY);
  1343. }
  1344. }
  1345. /***************************************************************************\
  1346. * GetUpdateRect (API)
  1347. *
  1348. * Returns the bounding rectangle of the update region, or an empty rectangle
  1349. * if there is no update region. Rectangle is in client-relative coordinates.
  1350. *
  1351. * Returns TRUE if the update region is non-empty, FALSE if there is no
  1352. * update region.
  1353. *
  1354. * lprc may be NULL to query whether or not an update region exists at all
  1355. * or not.
  1356. *
  1357. * History:
  1358. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1359. \***************************************************************************/
  1360. BOOL xxxGetUpdateRect(
  1361. PWND pwnd,
  1362. LPRECT lprc,
  1363. BOOL fErase)
  1364. {
  1365. RECT rc;
  1366. CheckLock(pwnd);
  1367. if (fErase)
  1368. xxxSimpleDoSyncPaint(pwnd);
  1369. /*
  1370. * The app is looking at the update region: okay to allow window
  1371. * validation.
  1372. */
  1373. ClrWF(pwnd, WFUPDATEDIRTY);
  1374. if (pwnd->hrgnUpdate == NULL) {
  1375. if (lprc) {
  1376. SetRectEmpty(lprc);
  1377. }
  1378. return FALSE;
  1379. } else {
  1380. /*
  1381. * We must handle the case where a window has an update region,
  1382. * but it is completely obscured by its parents. In this case, we
  1383. * must validate the window and all its children, and return FALSE.
  1384. *
  1385. * An OffsetChildren() call resulting from SetWindowPos() or
  1386. * ScrollWindowEx() will cause this to happen. Update regions are
  1387. * just offset without checking their new positions to see if they
  1388. * are obscured by the parent(s). This is too painful to check in
  1389. * those cases, so we instead handle it here.
  1390. *
  1391. * BeginPaint() handles this case correctly by returning an empty
  1392. * rectangle, so nothing special need be done there.
  1393. */
  1394. if (pwnd->hrgnUpdate == HRGN_FULL) {
  1395. rc = pwnd->rcClient;
  1396. } else {
  1397. switch (GreGetRgnBox(pwnd->hrgnUpdate, &rc)) {
  1398. case ERROR:
  1399. case NULLREGION:
  1400. SetRectEmpty(&rc);
  1401. break;
  1402. case SIMPLEREGION:
  1403. case COMPLEXREGION:
  1404. break;
  1405. }
  1406. IntersectRect(&rc, &rc, &pwnd->rcClient);
  1407. }
  1408. if (IntersectWithParents(pwnd, &rc)) {
  1409. if (pwnd != PWNDDESKTOP(pwnd)) {
  1410. OffsetRect(&rc, -pwnd->rcClient.left, -pwnd->rcClient.top);
  1411. }
  1412. /*
  1413. * If the window is CS_OWNDC, then we must map the returned
  1414. * rectangle with DPtoLP, to ensure that the rectangle is
  1415. * in the same coordinate system as the rectangle returned
  1416. * by BeginPaint().
  1417. *
  1418. * BUT ONLY IF hwnd->hrgnUpdate != HRGN_FULL! For true
  1419. * compatibility with 3.0.
  1420. */
  1421. if (TestCF(pwnd, CFOWNDC) &&
  1422. (TestWF(pwnd, WFWIN31COMPAT) || pwnd->hrgnUpdate != HRGN_FULL)) {
  1423. PDCE pdce;
  1424. /*
  1425. * Look up this window's DC in the cache, and use it to
  1426. * map the returned rectangle.
  1427. */
  1428. for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) {
  1429. if (pdce->pwndOrg == pwnd && !(pdce->DCX_flags & DCX_CACHE)) {
  1430. GreDPtoLP(pdce->hdc, (LPPOINT)&rc, 2);
  1431. break;
  1432. }
  1433. }
  1434. }
  1435. } else {
  1436. SetRectEmpty(&rc);
  1437. }
  1438. }
  1439. if (lprc) {
  1440. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  1441. MirrorClientRect(pwnd, &rc);
  1442. }
  1443. *lprc = rc;
  1444. }
  1445. /*
  1446. * If we're in the process a dragging a full window, mark the start
  1447. * of the application painting. This is to make sure that if the
  1448. * application calls DefWindowProc on the WM_PAINT after painting, we
  1449. * won't erase the newly painted areas. Visual Slick calls GetUpdateRect
  1450. * and then DefWindowProc.
  1451. * See other comments for xxxBeginPaint and xxxDWP_Paint.
  1452. * 8/3/94 johannec
  1453. *
  1454. * NOTE: This causes other problems in vslick where some controls
  1455. * won't paint. Since the app doesn't call BeginPaint/EndPaint
  1456. * to truly set/clear the STARTPAINT flag, we do not clear this
  1457. * bit. (6-27-1996 : ChrisWil).
  1458. *
  1459. *
  1460. * if (TEST_PUDF(PUDF_DRAGGINGFULLWINDOW)) {
  1461. * SetWF(pwnd, WFSTARTPAINT);
  1462. * }
  1463. */
  1464. return TRUE;
  1465. }
  1466. /***************************************************************************\
  1467. * GetUpdateRgn (API)
  1468. *
  1469. *
  1470. * History:
  1471. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1472. \***************************************************************************/
  1473. int xxxGetUpdateRgn(
  1474. PWND pwnd,
  1475. HRGN hrgn,
  1476. BOOL fErase)
  1477. {
  1478. RECT rc;
  1479. int code;
  1480. BOOL fNotEmpty;
  1481. CheckLock(pwnd);
  1482. if (fErase)
  1483. xxxSimpleDoSyncPaint(pwnd);
  1484. /*
  1485. * The application is looking at the update region: okay to
  1486. * allow validation
  1487. */
  1488. ClrWF(pwnd, WFUPDATEDIRTY);
  1489. if (pwnd->hrgnUpdate == NULL)
  1490. goto ReturnEmpty;
  1491. rc = pwnd->rcClient;
  1492. fNotEmpty = IntersectWithParents(pwnd, &rc);
  1493. if (pwnd->hrgnUpdate == HRGN_FULL) {
  1494. /*
  1495. * Since the update region may be larger than the window
  1496. * rectangle, intersect it with the window rectangle.
  1497. */
  1498. if (!fNotEmpty)
  1499. goto ReturnEmpty;
  1500. code = SIMPLEREGION;
  1501. /*
  1502. * Normalize the rectangle\region relative to the unclipped window
  1503. */
  1504. if (pwnd != PWNDDESKTOP(pwnd)) {
  1505. OffsetRect(&rc, -pwnd->rcClient.left, -pwnd->rcClient.top);
  1506. }
  1507. SetRectRgnIndirect(hrgn, &rc);
  1508. } else {
  1509. SetRectRgnIndirect(ghrgnInv2, &rc);
  1510. code = IntersectRgn(hrgn, ghrgnInv2, pwnd->hrgnUpdate);
  1511. switch (code) {
  1512. case NULLREGION:
  1513. case ERROR:
  1514. goto ReturnEmpty;
  1515. default:
  1516. if (pwnd != PWNDDESKTOP(pwnd)) {
  1517. GreOffsetRgn(hrgn, -pwnd->rcClient.left, -pwnd->rcClient.top);
  1518. }
  1519. break;
  1520. }
  1521. }
  1522. MirrorRegion(pwnd, hrgn, TRUE);
  1523. /*
  1524. * If we're in the process a dragging a full window, mark the start
  1525. * of the application painting. This is to make sure that if the
  1526. * application calls DefWindowProc on the WM_PAINT after painting, we
  1527. * won't erase the newly painted areas.
  1528. * See other comments for xxxBeginPaint and xxxDWP_Paint.
  1529. * 8/3/94 johannec
  1530. *
  1531. * NOTE: This causes other problems in vslick where some controls
  1532. * won't paint. Since the app doesn't call BeginPaint/EndPaint
  1533. * to truly set/clear the STARTPAINT flag, we do not clear this
  1534. * bit. (6-27-1996 : ChrisWil).
  1535. *
  1536. * if (TEST(PUDF(PUDF_DRAGGINGFULLWINDOW)) {
  1537. * SetWF(pwnd, WFSTARTPAINT);
  1538. * }
  1539. */
  1540. return code;
  1541. ReturnEmpty:
  1542. SetEmptyRgn(hrgn);
  1543. return NULLREGION;
  1544. }
  1545. /***************************************************************************\
  1546. * IntersectWithParents
  1547. *
  1548. * This routine calculates the intersection of a rectangle with the client
  1549. * rectangles of all of pwnd's parents. Returns FALSE if the intersection
  1550. * is empty, a window is invisible, or a parent is minimized.
  1551. *
  1552. * Stop the intesesection if the window itself or any of its parents are
  1553. * layered windows, so we always have a complete bitmap of them.
  1554. *
  1555. * History:
  1556. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1557. \***************************************************************************/
  1558. BOOL IntersectWithParents(
  1559. PWND pwnd,
  1560. LPRECT lprc)
  1561. {
  1562. if (TestWF(pwnd, WEFPREDIRECTED))
  1563. return TRUE;
  1564. while ((pwnd = pwnd->spwndParent) != NULL) {
  1565. if (!TestWF(pwnd, WFVISIBLE) || TestWF(pwnd, WFMINIMIZED))
  1566. return FALSE;
  1567. if (!IntersectRect(lprc, lprc, &pwnd->rcClient))
  1568. return FALSE;
  1569. if (TestWF(pwnd, WEFPREDIRECTED))
  1570. return TRUE;
  1571. }
  1572. return TRUE;
  1573. }