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.

1538 lines
46 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: paint.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains the APIs used to begin and end window painting.
  7. *
  8. * History:
  9. * 27-Oct-1990 DarrinM Created.
  10. * 12-Feb-1991 IanJa HWND revalidation added
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /***************************************************************************\
  15. * xxxFillWindow (not an API)
  16. *
  17. * pwndBrush - The brush is aligned with with client rect of this window.
  18. * It is usually either pwndPaint or pwndPaint's parent.
  19. *
  20. * pwndPaint - The window to paint.
  21. * hdc - The DC to paint in.
  22. * hbr - The brush to use.
  23. *
  24. * Returns TRUE if successful, FALSE if not.
  25. *
  26. * History:
  27. * 15-Nov-1990 DarrinM Ported from Win 3.0 sources.
  28. * 21-Jan-1991 IanJa Prefix '_' denoting exported function.
  29. \***************************************************************************/
  30. BOOL xxxFillWindow(
  31. PWND pwndBrush,
  32. PWND pwndPaint,
  33. HDC hdc,
  34. HBRUSH hbr)
  35. {
  36. RECT rc;
  37. CheckLock(pwndBrush);
  38. CheckLock(pwndPaint);
  39. /*
  40. * If there is no pwndBrush (sometimes the parent), use pwndPaint.
  41. */
  42. if (pwndBrush == NULL)
  43. pwndBrush = pwndPaint;
  44. if (UT_GetParentDCClipBox(pwndPaint, hdc, &rc))
  45. return xxxPaintRect(pwndBrush, pwndPaint, hdc, hbr, &rc);
  46. return TRUE;
  47. }
  48. /***************************************************************************\
  49. * xxxPaintRect
  50. *
  51. * pwndBrush - The brush is aligned with with client rect of this window.
  52. * It is usually either pwndPaint or pwndPaint's parent.
  53. *
  54. * pwndPaint - The window to paint in.
  55. * hdc - The DC to paint in.
  56. * hbr - The brush to use.
  57. * lprc - The rectangle to paint.
  58. *
  59. * History:
  60. * 15-Nov-1990 DarrinM Ported from Win 3.0 sources.
  61. * 21-Jan-1991 IanJa Prefix '_' denoting exported function.
  62. \***************************************************************************/
  63. BOOL xxxPaintRect(
  64. PWND pwndBrush,
  65. PWND pwndPaint,
  66. HDC hdc,
  67. HBRUSH hbr,
  68. LPRECT lprc)
  69. {
  70. POINT ptOrg;
  71. CheckLock(pwndBrush);
  72. CheckLock(pwndPaint);
  73. if (pwndBrush == NULL) {
  74. pwndBrush = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  75. }
  76. if (pwndBrush == PWNDDESKTOP(pwndBrush)) {
  77. GreSetBrushOrg(
  78. hdc,
  79. 0,
  80. 0,
  81. &ptOrg);
  82. } else {
  83. GreSetBrushOrg(
  84. hdc,
  85. pwndBrush->rcClient.left - pwndPaint->rcClient.left,
  86. pwndBrush->rcClient.top - pwndPaint->rcClient.top,
  87. &ptOrg);
  88. }
  89. /*
  90. * If hbr < CTLCOLOR_MAX, it isn't really a brush but is one of our
  91. * special color values. Translate it to the appropriate WM_CTLCOLOR
  92. * message and send it off to get back a real brush. The translation
  93. * process assumes the CTLCOLOR*** and WM_CTLCOLOR*** values map directly.
  94. */
  95. if (hbr < (HBRUSH)CTLCOLOR_MAX) {
  96. hbr = xxxGetControlColor(pwndBrush,
  97. pwndPaint,
  98. hdc,
  99. HandleToUlong(hbr) + WM_CTLCOLORMSGBOX);
  100. }
  101. FillRect(hdc, lprc, hbr);
  102. GreSetBrushOrg(hdc, ptOrg.x, ptOrg.y, NULL);
  103. return TRUE;
  104. }
  105. /***************************************************************************\
  106. * DeleteMaybeSpecialRgn
  107. *
  108. * Deletes a GDI region, making sure it is not a special region.
  109. *
  110. * History:
  111. * 26-Feb-1992 MikeKe from win3.1
  112. \***************************************************************************/
  113. VOID DeleteMaybeSpecialRgn(
  114. HRGN hrgn)
  115. {
  116. if (hrgn > HRGN_SPECIAL_LAST) {
  117. GreDeleteObject(hrgn);
  118. }
  119. }
  120. /***************************************************************************\
  121. * GetNCUpdateRgn
  122. *
  123. * Gets the update region which includes the non-client area.
  124. *
  125. * History:
  126. * 26-Feb-1992 MikeKe From win3.1
  127. \***************************************************************************/
  128. HRGN GetNCUpdateRgn(
  129. PWND pwnd,
  130. BOOL fValidateFrame)
  131. {
  132. HRGN hrgnUpdate;
  133. if (pwnd->hrgnUpdate > HRGN_FULL) {
  134. /*
  135. * We must make a copy of our update region, because
  136. * it could change if we send a message, and we want to
  137. * make sure the whole thing is used for drawing our
  138. * frame and background. We can't use a global
  139. * temporary region, because more than one app may
  140. * be calling this routine.
  141. */
  142. hrgnUpdate = CreateEmptyRgnPublic();
  143. if (hrgnUpdate == NULL) {
  144. hrgnUpdate = HRGN_FULL;
  145. } else if (CopyRgn(hrgnUpdate, pwnd->hrgnUpdate) == ERROR) {
  146. GreDeleteObject(hrgnUpdate);
  147. hrgnUpdate = HRGN_FULL;
  148. }
  149. if (fValidateFrame) {
  150. /*
  151. * Now that we've taken care of any frame drawing,
  152. * intersect the update region with the window's
  153. * client area. Otherwise, apps that do ValidateRects()
  154. * to draw themselves (e.g., WinWord) won't ever
  155. * subtract off the part of the update region that
  156. * overlaps the frame but not the client.
  157. */
  158. CalcWindowRgn(pwnd, ghrgnInv2, TRUE);
  159. switch (IntersectRgn(pwnd->hrgnUpdate,
  160. pwnd->hrgnUpdate,
  161. ghrgnInv2)) {
  162. case ERROR:
  163. /*
  164. * If an error occured, we can't leave things as
  165. * they are: invalidate the whole window and let
  166. * BeginPaint() take care of it.
  167. */
  168. GreDeleteObject(pwnd->hrgnUpdate);
  169. pwnd->hrgnUpdate = HRGN_FULL;
  170. break;
  171. case NULLREGION:
  172. /*
  173. * There is nothing in the client area to repaint.
  174. * Blow the region away, and decrement the paint count
  175. * if possible.
  176. */
  177. GreDeleteObject(pwnd->hrgnUpdate);
  178. pwnd->hrgnUpdate = NULL;
  179. ClrWF(pwnd, WFUPDATEDIRTY);
  180. if (!TestWF(pwnd, WFINTERNALPAINT))
  181. DecPaintCount(pwnd);
  182. break;
  183. }
  184. }
  185. } else {
  186. hrgnUpdate = pwnd->hrgnUpdate;
  187. }
  188. return hrgnUpdate;
  189. }
  190. /***************************************************************************\
  191. * xxxSendNCPaint
  192. *
  193. * Sends a WM_NCPAINT message to a window.
  194. *
  195. * History:
  196. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  197. \***************************************************************************/
  198. VOID xxxSendNCPaint(
  199. PWND pwnd,
  200. HRGN hrgnUpdate)
  201. {
  202. CheckLock(pwnd);
  203. /*
  204. * Clear the WFSENDNCPAINT bit...
  205. */
  206. ClrWF(pwnd, WFSENDNCPAINT);
  207. /*
  208. * If the window is active, but its FRAMEON bit hasn't
  209. * been set yet, set it and make sure that the entire frame
  210. * gets redrawn when we send the NCPAINT.
  211. */
  212. if ((pwnd == PtiCurrent()->pq->spwndActive) && !TestWF(pwnd, WFFRAMEON)) {
  213. SetWF(pwnd, WFFRAMEON);
  214. hrgnUpdate = HRGN_FULL;
  215. ClrWF(pwnd, WFNONCPAINT);
  216. }
  217. /*
  218. * If PixieHack() has set the WM_NCPAINT bit, we must be sure
  219. * to send with hrgnClip == HRGN_FULL. (see PixieHack() in wmupdate.c)
  220. */
  221. if (TestWF(pwnd, WFPIXIEHACK)) {
  222. ClrWF(pwnd, WFPIXIEHACK);
  223. hrgnUpdate = HRGN_FULL;
  224. }
  225. if (hrgnUpdate)
  226. xxxSendMessage(pwnd, WM_NCPAINT, (WPARAM)hrgnUpdate, 0L);
  227. }
  228. /***************************************************************************\
  229. * xxxSendChildNCPaint
  230. *
  231. * Sends WM_NCPAINT message to the immediate children of a window.
  232. *
  233. * History:
  234. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  235. \***************************************************************************/
  236. VOID xxxSendChildNCPaint(
  237. PWND pwnd)
  238. {
  239. TL tlpwnd;
  240. CheckLock(pwnd);
  241. ThreadLockNever(&tlpwnd);
  242. pwnd = pwnd->spwndChild;
  243. while (pwnd != NULL) {
  244. if ((pwnd->hrgnUpdate == NULL) && TestWF(pwnd, WFSENDNCPAINT)) {
  245. ThreadLockExchangeAlways(pwnd, &tlpwnd);
  246. xxxSendNCPaint(pwnd, HRGN_FULL);
  247. }
  248. pwnd = pwnd->spwndNext;
  249. }
  250. ThreadUnlock(&tlpwnd);
  251. }
  252. /***************************************************************************\
  253. * xxxBeginPaint
  254. *
  255. * Revalidation Note:
  256. * We MUST return NULL if the window is deleted during xxxBeginPaint because
  257. * its DCs are released upon deletion, and we shouldn't return a *released* DC!
  258. *
  259. * History:
  260. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  261. \***************************************************************************/
  262. HDC xxxBeginPaint(
  263. PWND pwnd,
  264. LPPAINTSTRUCT lpps)
  265. {
  266. HRGN hrgnUpdate;
  267. HDC hdc;
  268. BOOL fSendEraseBkgnd;
  269. CheckLock(pwnd);
  270. UserAssert(IsWinEventNotifyDeferredOK());
  271. if (TEST_PUDF(PUDF_DRAGGINGFULLWINDOW))
  272. SetWF(pwnd, WFSTARTPAINT);
  273. /*
  274. * We're processing a WM_PAINT message: clear this flag.
  275. */
  276. ClrWF(pwnd, WFPAINTNOTPROCESSED);
  277. /*
  278. * If this bit gets set while we are drawing the frame we will need
  279. * to redraw it.
  280. *
  281. * If necessary, send our WM_NCPAINT message now.
  282. *
  283. * please heed these notes
  284. *
  285. * We have to send this message BEFORE we diddle hwnd->hrgnUpdate,
  286. * because an app may call ValidateRect or InvalidateRect in its
  287. * handler, and it expects what it does to affect what gets drawn
  288. * in the later WM_PAINT.
  289. *
  290. * It is possible to get an invalidate when we leave the critical
  291. * section below, therefore we loop until UPDATEDIRTY is clear
  292. * meaning there were no additional invalidates.
  293. */
  294. if (TestWF(pwnd, WFSENDNCPAINT)) {
  295. do {
  296. ClrWF(pwnd, WFUPDATEDIRTY);
  297. hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE);
  298. xxxSendNCPaint(pwnd, hrgnUpdate);
  299. DeleteMaybeSpecialRgn(hrgnUpdate);
  300. } while (TestWF(pwnd, WFUPDATEDIRTY));
  301. } else {
  302. ClrWF(pwnd, WFUPDATEDIRTY);
  303. }
  304. /*
  305. * Hide the caret if needed. Do this before we get the DC so
  306. * that if HideCaret() gets and releases a DC we will be able
  307. * to reuse it later here.
  308. * No need to DeferWinEventNotify() since pwnd is locked.
  309. */
  310. if (pwnd == PtiCurrent()->pq->caret.spwnd)
  311. zzzInternalHideCaret();
  312. /*
  313. * Send the check for sending an WM_ERASEBKGND to the
  314. * window.
  315. */
  316. if (fSendEraseBkgnd = TestWF(pwnd, WFSENDERASEBKGND)) {
  317. ClrWF(pwnd, WFERASEBKGND);
  318. ClrWF(pwnd, WFSENDERASEBKGND);
  319. }
  320. /*
  321. * Validate the entire window.
  322. */
  323. if (NEEDSPAINT(pwnd))
  324. DecPaintCount(pwnd);
  325. ClrWF(pwnd, WFINTERNALPAINT);
  326. hrgnUpdate = pwnd->hrgnUpdate;
  327. pwnd->hrgnUpdate = NULL;
  328. if (TestWF(pwnd, WFDONTVALIDATE)) {
  329. if (ghrgnUpdateSave == NULL) {
  330. ghrgnUpdateSave = CreateEmptyRgn();
  331. }
  332. if (ghrgnUpdateSave != NULL) {
  333. UnionRgn(ghrgnUpdateSave, ghrgnUpdateSave, hrgnUpdate);
  334. gnUpdateSave++;
  335. }
  336. }
  337. /*
  338. * Clear these flags for backward compatibility
  339. */
  340. lpps->fIncUpdate =
  341. lpps->fRestore = FALSE;
  342. lpps->hdc =
  343. hdc = _GetDCEx(pwnd,
  344. hrgnUpdate,
  345. DCX_USESTYLE | DCX_INTERSECTRGN);
  346. if (UT_GetParentDCClipBox(pwnd, hdc, &lpps->rcPaint)) {
  347. /*
  348. * If necessary, erase our background, and possibly deal with
  349. * our children's frames and backgrounds.
  350. */
  351. if (fSendEraseBkgnd)
  352. xxxSendEraseBkgnd(pwnd, hdc, hrgnUpdate);
  353. }
  354. /*
  355. * Now that we're completely erased, see if there are any children
  356. * that couldn't draw their own frames because their update regions
  357. * got deleted.
  358. */
  359. xxxSendChildNCPaint(pwnd);
  360. /*
  361. * The erase and frame operation has occured. Clear the WFREDRAWIFHUNG
  362. * bit here. We don't want to clear it until we know the erase and
  363. * frame has occured, so we know we always have a consistent looking
  364. * window.
  365. */
  366. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  367. lpps->fErase = (TestWF(pwnd, WFERASEBKGND) != 0);
  368. return hdc;
  369. }
  370. /***************************************************************************\
  371. * xxxEndPaint (API)
  372. *
  373. *
  374. * History:
  375. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  376. \***************************************************************************/
  377. BOOL xxxEndPaint(
  378. PWND pwnd,
  379. LPPAINTSTRUCT lpps)
  380. {
  381. CheckLock(pwnd);
  382. ReleaseCacheDC(lpps->hdc, TRUE);
  383. if (TestWF(pwnd, WFDONTVALIDATE)) {
  384. if (ghrgnUpdateSave != NULL) {
  385. InternalInvalidate3(pwnd,
  386. ghrgnUpdateSave,
  387. RDW_INVALIDATE | RDW_ERASE);
  388. if (--gnUpdateSave == 0) {
  389. GreDeleteObject(ghrgnUpdateSave);
  390. ghrgnUpdateSave = NULL;
  391. }
  392. }
  393. ClrWF(pwnd, WFDONTVALIDATE);
  394. }
  395. ClrWF(pwnd, WFWMPAINTSENT);
  396. /*
  397. * This used to check that the update-region was empty before
  398. * doing the clear. However, this caused a problem with WOW
  399. * amipro/approach hanging. They were invalidating rects in
  400. * their WM_PAINT handler, and allowing the defwindowproc to
  401. * perform the validation for them. Since we were blocking
  402. * the BeginPaint in this case, it sent them into a infinite
  403. * loop (see bug 19036).
  404. */
  405. ClrWF(pwnd, WFSTARTPAINT);
  406. /*
  407. * Reshow the caret if needed, but AFTER we've released the DC.
  408. * This way ShowCaret() can reuse the DC we just released.
  409. */
  410. if (pwnd == PtiCurrent()->pq->caret.spwnd)
  411. zzzInternalShowCaret();
  412. return TRUE;
  413. }
  414. /***************************************************************************\
  415. * GetLastChild
  416. *
  417. \***************************************************************************/
  418. PWND GetLastChild(PWND pwnd)
  419. {
  420. PWND pwndLast;
  421. pwnd = pwnd->spwndChild;
  422. pwndLast = pwnd;
  423. while (pwnd != NULL) {
  424. pwndLast = pwnd;
  425. pwnd = pwnd->spwndNext;
  426. }
  427. return pwndLast;
  428. }
  429. /***************************************************************************\
  430. * xxxCompositedTraverse
  431. *
  432. * Uses pre-order traversal starting with the last child to render the
  433. * windows in a bottom-up order.
  434. *
  435. * 9/30/1999 vadimg created
  436. \***************************************************************************/
  437. BOOL xxxCompositedTraverse(PWND pwnd)
  438. {
  439. TL tlpwnd;
  440. BOOL fPainted = FALSE;
  441. CheckLock(pwnd);
  442. if (NEEDSPAINT(pwnd)) {
  443. xxxSendMessage(pwnd, WM_PAINT, 0, 0);
  444. fPainted = TRUE;
  445. }
  446. pwnd = GetLastChild(pwnd);
  447. ThreadLock(pwnd, &tlpwnd);
  448. while (pwnd != NULL) {
  449. if (xxxCompositedTraverse(pwnd)) {
  450. fPainted = TRUE;
  451. }
  452. pwnd = pwnd->spwndPrev;
  453. if (ThreadLockExchange(pwnd, &tlpwnd) == NULL) {
  454. break;
  455. }
  456. }
  457. ThreadUnlock(&tlpwnd);
  458. return fPainted;
  459. }
  460. /***************************************************************************\
  461. * xxxCompositedPaint
  462. *
  463. * 9/30/1999 vadimg created
  464. \***************************************************************************/
  465. VOID xxxCompositedPaint(PWND pwnd)
  466. {
  467. BOOL fPainted;
  468. HBITMAP hbm, hbmOld;
  469. PREDIRECT prdr;
  470. HDC hdc;
  471. LPRECT prc;
  472. SIZE size;
  473. POINT pt;
  474. CheckLock(pwnd);
  475. UserAssert(TestWF(pwnd, WEFCOMPOSITED));
  476. SetWF(pwnd, WEFPCOMPOSITING);
  477. /*
  478. * Render the child windows in a bottom-up order.
  479. */
  480. fPainted = xxxCompositedTraverse(pwnd);
  481. ClrWF(pwnd, WEFPCOMPOSITING);
  482. /*
  483. * While we were compositing, an invalid region may have accumulated.
  484. * So, let's go and invalidate that area of the window.
  485. */
  486. BEGINATOMICCHECK();
  487. prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
  488. if (prdr != NULL && prdr->hrgnComp != NULL) {
  489. xxxInternalInvalidate(pwnd, prdr->hrgnComp, RDW_INVALIDATE |
  490. RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
  491. if (prdr->hrgnComp != HRGN_FULL) {
  492. GreDeleteObject(prdr->hrgnComp);
  493. }
  494. prdr->hrgnComp = NULL;
  495. }
  496. ENDATOMICCHECK();
  497. #ifdef REDIRECTION
  498. if (TestWF(pwnd, WEFEXTREDIRECTED)) {
  499. return;
  500. }
  501. #endif // REDIRECTION
  502. BEGINATOMICCHECK();
  503. if (fPainted && TestWF(pwnd, WEFPREDIRECTED)) {
  504. prdr = (PREDIRECT)_GetProp(pwnd, PROP_LAYER, TRUE);
  505. prc = &prdr->rcUpdate;
  506. hbm = prdr->hbm;
  507. UserAssert(hbm != NULL);
  508. if (TestWF(pwnd, WEFLAYERED)) {
  509. hbmOld = GreSelectBitmap(ghdcMem, hbm);
  510. size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  511. size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
  512. pt.x = pt.y = 0;
  513. GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, NULL,
  514. &size, ghdcMem, &pt, 0, NULL, ULW_DEFAULT_ATTRIBUTES, prc);
  515. GreSelectBitmap(ghdcMem, hbmOld);
  516. } else {
  517. /*
  518. * Temporarily clear the redirected bit so that we can get the dc
  519. * with proper screen clipping.
  520. */
  521. ClrWF(pwnd, WEFPREDIRECTED);
  522. hbmOld = GreSelectBitmap(ghdcMem, hbm);
  523. hdc = _GetDCEx(pwnd, NULL, DCX_USESTYLE | DCX_WINDOW | DCX_CACHE);
  524. /*
  525. * Transfer the bits for the window from the redirection bitmap
  526. * to the screen.
  527. */
  528. GreBitBlt(hdc, prc->left, prc->top, prc->right - prc->left,
  529. prc->bottom - prc->top, ghdcMem,
  530. prc->left, prc->top, SRCCOPY, 0);
  531. _ReleaseDC(hdc);
  532. GreSelectBitmap(ghdcMem, hbmOld);
  533. /*
  534. * Restore the redirection bit on the window.
  535. */
  536. SetWF(pwnd, WEFPREDIRECTED);
  537. }
  538. SetRectEmpty(prc);
  539. }
  540. ENDATOMICCHECK();
  541. }
  542. /***************************************************************************\
  543. * InternalDoPaint
  544. *
  545. * Return a window equal to or below pwnd, created by the current thread,
  546. * which needs painting.
  547. *
  548. * pwnd - Window to start searching from. Search is depth first.
  549. * ptiCurrent - The current thread.
  550. *
  551. * History:
  552. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  553. \***************************************************************************/
  554. PWND xxxInternalDoPaint(
  555. PWND pwnd,
  556. PTHREADINFO ptiCurrent)
  557. {
  558. PWND pwndT;
  559. TL tlpwnd;
  560. /*
  561. * Enumerate all windows, top-down, looking for one that
  562. * needs repainting. Skip windows of other tasks.
  563. */
  564. while (pwnd != NULL) {
  565. if (GETPTI(pwnd) == ptiCurrent) {
  566. if (TestWF(pwnd, WEFCOMPOSITED)) {
  567. ThreadLock(pwnd, &tlpwnd);
  568. xxxCompositedPaint(pwnd);
  569. pwnd = pwnd->spwndNext;
  570. if (ThreadUnlock(&tlpwnd) == NULL) {
  571. return NULL;
  572. }
  573. continue;
  574. } else if (NEEDSPAINT(pwnd)) {
  575. /*
  576. * If this window is transparent, we don't want to
  577. * send it a WM_PAINT until all its siblings below it
  578. * have been repainted. If we find an unpainted sibling
  579. * below, return it instead.
  580. */
  581. if (TestWF(pwnd, WEFTRANSPARENT)) {
  582. pwndT = pwnd;
  583. while ((pwndT = pwndT->spwndNext) != NULL) {
  584. /*
  585. * Make sure sibling window belongs to same app
  586. */
  587. if ((GETPTI(pwndT) == ptiCurrent) && NEEDSPAINT(pwndT)) {
  588. if (TestWF(pwndT, WEFTRANSPARENT))
  589. continue;
  590. return pwndT;
  591. }
  592. }
  593. }
  594. return pwnd;
  595. }
  596. }
  597. if (pwnd->spwndChild &&
  598. (pwndT = xxxInternalDoPaint(pwnd->spwndChild, ptiCurrent))) {
  599. return pwndT;
  600. }
  601. pwnd = pwnd->spwndNext;
  602. }
  603. return pwnd;
  604. }
  605. /***************************************************************************\
  606. * DoPaint
  607. *
  608. * Looks at all the desktops for the window needing a paint and places a
  609. * WM_PAINT in its queue.
  610. *
  611. * History:
  612. * 16-Jul-91 DarrinM Ported from Win 3.1 sources.
  613. \***************************************************************************/
  614. BOOL xxxDoPaint(
  615. PWND pwndFilter,
  616. LPMSG lpMsg)
  617. {
  618. PWND pwnd;
  619. PWND pwndT;
  620. PTHREADINFO ptiCurrent = PtiCurrent();
  621. CheckLock(pwndFilter);
  622. #if 0 // CHRISWIL: WIN95 SPECIFIC
  623. /*
  624. * If there is a system modal up and it is attached to another task,
  625. * DON'T do paints. We don't want to return a message for a window in
  626. * another task!
  627. */
  628. if (hwndSysModal && (hwndSysModal->hq != hqCurrent)) {
  629. /*
  630. * Poke this guy so he wakes up at some point in the future,
  631. * otherwise he may never wake up to realize he should paint.
  632. * Causes hangs - e.g. Photoshop installation program
  633. * PostThreadMessage32(Lpq(hqCurrent)->idThread, WM_NULL, 0, 0, 0);
  634. */
  635. return FALSE;
  636. }
  637. #endif
  638. /*
  639. * If this is a system thread, then walk the windowstation desktop-list
  640. * to find the window which needs painting. For other threads, we
  641. * reference off the thread-desktop.
  642. */
  643. if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) {
  644. PWINDOWSTATION pwinsta;
  645. PDESKTOP pdesk;
  646. if ((pwinsta = ptiCurrent->pwinsta) == NULL) {
  647. RIPMSG0(RIP_ERROR, "DoPaint: SYSTEMTHREAD does not have (pwinsta)");
  648. return FALSE;
  649. }
  650. pwnd = pwinsta->pTerm->spwndDesktopOwner;
  651. if (!NEEDSPAINT(pwnd)) {
  652. pwnd = NULL;
  653. for(pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
  654. if (pwnd = xxxInternalDoPaint(pdesk->pDeskInfo->spwnd, ptiCurrent))
  655. break;
  656. }
  657. }
  658. } else {
  659. pwnd = xxxInternalDoPaint(ptiCurrent->rpdesk->pDeskInfo->spwnd,
  660. ptiCurrent);
  661. }
  662. if (pwnd != NULL) {
  663. if (!CheckPwndFilter(pwnd, pwndFilter))
  664. return FALSE;
  665. /*
  666. * We're returning a WM_PAINT message, so clear WFINTERNALPAINT so
  667. * it won't get sent again later.
  668. */
  669. if (TestWF(pwnd, WFINTERNALPAINT)) {
  670. ClrWF(pwnd, WFINTERNALPAINT);
  671. /*
  672. * If there is no update region, then no more paint for this
  673. * window.
  674. */
  675. if (pwnd->hrgnUpdate == NULL)
  676. DecPaintCount(pwnd);
  677. }
  678. /*
  679. * Set the STARTPAINT so that any other calls to BeginPaint while
  680. * painting is begin performed, will prevent painting on those
  681. * windows.
  682. *
  683. * Clear the UPDATEDIRTY since some apps (DBFast) don't call
  684. * GetUpdateRect, BeginPaint/EndPaint.
  685. */
  686. ClrWF(pwnd, WFSTARTPAINT);
  687. ClrWF(pwnd, WFUPDATEDIRTY);
  688. /*
  689. * If we get an invalidate between now and the time the app calls
  690. * BeginPaint() and the windows parent is not CLIPCHILDREN, then
  691. * the parent will paint in the wrong order. So we are going to
  692. * cause the child to paint again. Look in beginpaint and internal
  693. * invalidate for other parts of this fix.
  694. *
  695. * Set a flag to signify that we are in the bad zone.
  696. *
  697. * Must go up the parent links to make sure all parents have
  698. * WFCLIPCHILDREN set otherwise set the WFWMPAINTSENT flag.
  699. * This is to fix Excel spreadsheet and fulldrag. The speadsheet
  700. * parent window (class XLDESK) has WFCLIPCHILDREN set but it's
  701. * parent (class XLMAIN) doesn't. So the main window erases the
  702. * background after the child window paints.
  703. *
  704. * JOHANNEC : 27-Jul-1994
  705. */
  706. /*
  707. * NT Bug 400167: As we walk up the tree, we need to stop short of
  708. * desktop windows and mother desktop windows. We can't do a test
  709. * for WFCLIPCHILDREN on the mother desktop window's parent because
  710. * it doesn't exist. This means that no desktop window will get
  711. * WFWMPAINTSENT set, but the message window will be able to get
  712. * WFWMPAINTSENT set.
  713. */
  714. pwndT = pwnd;
  715. while (pwndT && (GETFNID(pwndT) != FNID_DESKTOP)) {
  716. if (!TestWF(pwndT->spwndParent, WFCLIPCHILDREN)) {
  717. SetWF(pwnd, WFWMPAINTSENT);
  718. break;
  719. }
  720. pwndT = pwndT->spwndParent;
  721. }
  722. /*
  723. * If the top level "tiled" owner/parent of this window is iconed,
  724. * send a WM_PAINTICON rather than a WM_PAINT. The wParam
  725. * is TRUE if this is the tiled window and FALSE if it is a
  726. * child/owned popup of the minimized window.
  727. *
  728. * BACKWARD COMPATIBILITY HACK
  729. *
  730. * 3.0 sent WM_PAINTICON with wParam == TRUE for no apparent
  731. * reason. Lotus Notes 2.1 depends on this for some reason
  732. * to properly change its icon when new mail arrives.
  733. */
  734. if (!TestWF(pwnd, WFWIN40COMPAT) &&
  735. TestWF(pwnd, WFMINIMIZED) &&
  736. (pwnd->pcls->spicn != NULL)) {
  737. StoreMessage(lpMsg, pwnd, WM_PAINTICON, (DWORD)TRUE, 0L, 0L);
  738. } else {
  739. StoreMessage(lpMsg, pwnd, WM_PAINT, 0, 0L, 0L);
  740. }
  741. return TRUE;
  742. }
  743. return FALSE;
  744. }
  745. /***************************************************************************\
  746. * xxxSimpleDoSyncPaint
  747. *
  748. * Process the sync-paint for this window. This can send either a NCPAINT
  749. * or an ERASEBKGND. This assumes no recursion and flags == 0.
  750. *
  751. * History:
  752. * 26-Oct-1993 MikeKe Created
  753. \***************************************************************************/
  754. VOID xxxSimpleDoSyncPaint(
  755. PWND pwnd)
  756. {
  757. HRGN hrgnUpdate;
  758. DWORD flags = 0;
  759. CheckLock(pwnd);
  760. /*
  761. * No syncpaints for composited windows, it messes up their painting
  762. * since erasebkgnds and ncpaints will be sent in the wrong order.
  763. */
  764. if (GetStyleWindow(pwnd, WEFCOMPOSITED) != NULL)
  765. return;
  766. /*
  767. * Since we're taking care of the frame drawing, we can consider
  768. * this WM_PAINT message processed.
  769. */
  770. ClrWF(pwnd, WFPAINTNOTPROCESSED);
  771. /*
  772. * Make copies of these flags, because their state might
  773. * change after we send a message, and we don't want
  774. * to "lose" them.
  775. */
  776. if (TestWF(pwnd, WFSENDNCPAINT))
  777. flags |= DSP_FRAME;
  778. if (TestWF(pwnd, WFSENDERASEBKGND))
  779. flags |= DSP_ERASE;
  780. if (flags & (DSP_ERASE | DSP_FRAME)) {
  781. if (!TestWF(pwnd, WFVISIBLE)) {
  782. /*
  783. * If there is no update region, just clear the bits.
  784. */
  785. ClrWF(pwnd, WFSENDNCPAINT);
  786. ClrWF(pwnd, WFSENDERASEBKGND);
  787. ClrWF(pwnd, WFPIXIEHACK);
  788. ClrWF(pwnd, WFERASEBKGND);
  789. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  790. } else {
  791. PTHREADINFO ptiCurrent = PtiCurrent();
  792. /*
  793. * If there is no update region, we don't have to
  794. * do any erasing, but we may need to send an NCPAINT.
  795. */
  796. if (pwnd->hrgnUpdate == NULL) {
  797. ClrWF(pwnd, WFSENDERASEBKGND);
  798. ClrWF(pwnd, WFERASEBKGND);
  799. flags &= ~DSP_ERASE;
  800. }
  801. /*
  802. * Only mess with windows owned by the current thread.
  803. * NOTE: This means that WM_NCPAINT and WM_ERASEBKGND are
  804. * only sent intra-thread.
  805. */
  806. if (GETPTI(pwnd) == ptiCurrent) {
  807. hrgnUpdate = GetNCUpdateRgn(pwnd, TRUE);
  808. if (flags & DSP_FRAME) {
  809. /*
  810. * If the message got sent before we got here then do
  811. * nothing.
  812. */
  813. if (TestWF(pwnd, WFSENDNCPAINT))
  814. xxxSendNCPaint(pwnd, hrgnUpdate);
  815. }
  816. if (flags & DSP_ERASE) {
  817. if (TestWF(pwnd, WFSENDNCPAINT)) {
  818. /*
  819. * If we got another invalidate during the NCPAINT
  820. * callback get the new update region
  821. */
  822. DeleteMaybeSpecialRgn(hrgnUpdate);
  823. hrgnUpdate = GetNCUpdateRgn(pwnd, FALSE);
  824. }
  825. /*
  826. * If the message got sent before we got here
  827. * (e.g.: an UpdateWindow() inside WM_NCPAINT handler,
  828. * for example), don't do anything.
  829. *
  830. * WINPROJ.EXE (version 1.0) calls UpdateWindow() in
  831. * the WM_NCPAINT handlers for its subclassed listboxes
  832. * in the open dialog.
  833. */
  834. if (TestWF(pwnd, WFSENDERASEBKGND)) {
  835. ClrWF(pwnd, WFSENDERASEBKGND);
  836. ClrWF(pwnd, WFERASEBKGND);
  837. xxxSendEraseBkgnd(pwnd, NULL, hrgnUpdate);
  838. }
  839. /*
  840. * The erase and frame operation has occured. Clear the
  841. * WFREDRAWIFHUNG bit here. We don't want to clear it until we
  842. * know the erase and frame has occured, so we know we always
  843. * have a consistent looking window.
  844. */
  845. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  846. }
  847. DeleteMaybeSpecialRgn(hrgnUpdate);
  848. } else if (!TestwndChild(pwnd) &&
  849. (pwnd != grpdeskRitInput->pDeskInfo->spwnd) &&
  850. FHungApp(GETPTI(pwnd), CMSHUNGAPPTIMEOUT) &&
  851. TestWF(pwnd, WFREDRAWIFHUNG)) {
  852. ClearHungFlag(pwnd, WFREDRAWIFHUNG);
  853. xxxRedrawHungWindow(pwnd, NULL);
  854. }
  855. }
  856. }
  857. }
  858. /***************************************************************************\
  859. * xxxInternalDoSyncPaint
  860. *
  861. * Mostly the same functionality as the old xxxDoSyncPaint.
  862. *
  863. *
  864. * This function is called to erase the background of a window, and
  865. * possibly frame and erase the children too.
  866. *
  867. * WM_SYNCPAINT(wParam)/DoSyncPaint(flags) values:
  868. *
  869. * DSP_ERASE - Erase background
  870. * DSP_FRAME - Draw child frames
  871. * DSP_ENUMCLIPPEDCHILDREN - Recurse if children are clipped
  872. * DSP_NOCHECKPARENTS - Don't check
  873. *
  874. *
  875. * Normally, only the DSP_ENUMCLIPPEDCHILDREN bit of flags is
  876. * significant on entry. If DSP_WM_SYNCPAINT is set, then hrgnUpdate
  877. * and the rest of the flags bits are valid.
  878. *
  879. * History:
  880. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  881. \***************************************************************************/
  882. VOID xxxInternalDoSyncPaint(
  883. PWND pwnd,
  884. DWORD flags)
  885. {
  886. CheckLock(pwnd);
  887. /*
  888. * Do the paint for this window.
  889. */
  890. xxxSimpleDoSyncPaint(pwnd);
  891. /*
  892. * Normally we like to enumerate all of this window's children and have
  893. * them erase their backgrounds synchronously. However, this is a bad
  894. * thing to do if the window is NOT CLIPCHLIDREN. Here's the scenario
  895. * we want to to avoid:
  896. *
  897. * 1) Window 'A' is invalidated
  898. * 2) 'A' erases itself (or not, doesn't matter)
  899. * 3) 'A's children are enumerated and they erase themselves.
  900. * 4) 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN)
  901. * 5) 'A's children paint but their backgrounds aren't their ERASEBKND
  902. * color (because 'A' painted over them) and everything looks like
  903. * dirt.
  904. */
  905. if ((flags & DSP_ALLCHILDREN) ||
  906. ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) {
  907. TL tlpwnd;
  908. PBWL pbwl;
  909. HWND *phwnd;
  910. if (pbwl = BuildHwndList(pwnd->spwndChild, BWL_ENUMLIST, NULL)) {
  911. PTHREADINFO ptiCurrent = PtiCurrent();
  912. HWND hwnd;
  913. /*
  914. * If the client dies during a callback, the hwnd list
  915. * will be freed in xxxDestroyThreadInfo.
  916. */
  917. for (phwnd = pbwl->rghwnd; (hwnd = *phwnd) != (HWND)1; phwnd++) {
  918. if (hwnd == NULL)
  919. continue;
  920. if ((pwnd = (PWND)RevalidateHwnd(hwnd)) == NULL)
  921. continue;
  922. /*
  923. * Note: testing if a window is a child automatically
  924. * excludes the desktop window.
  925. */
  926. if (TestWF(pwnd, WFCHILD) && (ptiCurrent != GETPTI(pwnd))) {
  927. /*
  928. * Don't cause any more intertask sendmessages cause it
  929. * does bad things to cbt's windowproc hooks. (Due to
  930. * SetParent allowing child windows in the topwindow
  931. * hierarchy.
  932. */
  933. continue;
  934. }
  935. /*
  936. * Note that we pass only certain bits down as we recurse:
  937. * the other bits pertain to the current window only.
  938. */
  939. ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
  940. xxxInternalDoSyncPaint(pwnd, flags);
  941. ThreadUnlock(&tlpwnd);
  942. }
  943. FreeHwndList(pbwl);
  944. }
  945. }
  946. }
  947. /***************************************************************************\
  948. * DoQueuedSyncPaint
  949. *
  950. * Queues WM_SYNCPAINT messages for top level windows not of the specified
  951. * thread.
  952. *
  953. * History:
  954. \***************************************************************************/
  955. VOID DoQueuedSyncPaint(
  956. PWND pwnd,
  957. DWORD flags,
  958. PTHREADINFO pti)
  959. {
  960. PTHREADINFO ptiPwnd = GETPTI(pwnd);
  961. if ((ptiPwnd != pti) &&
  962. TestWF(pwnd, WFSENDNCPAINT) &&
  963. TestWF(pwnd, WFSENDERASEBKGND) &&
  964. TestWF(pwnd, WFVISIBLE)) {
  965. PSMS psms = ptiPwnd->psmsReceiveList;
  966. /*
  967. * If this window already has a WM_SYNCPAINT queue'd up, then there's
  968. * no need to send another one. Also protects our heap from getting
  969. * chewed up.
  970. */
  971. while (psms != NULL) {
  972. if ((psms->message == WM_SYNCPAINT) && (psms->spwnd == pwnd)) {
  973. break;
  974. }
  975. psms = psms->psmsReceiveNext;
  976. }
  977. if (psms == NULL) {
  978. /*
  979. * This will give this message the semantics of a notify
  980. * message (sendmessage no wait), without calling back
  981. * the WH_CALLWNDPROC hook. We don't want to do that
  982. * because that'll let all these processes with invalid
  983. * windows to process paint messages before they process
  984. * "synchronous" erasing or framing needs.
  985. *
  986. * Hi word of wParam must be zero or wow will drop it
  987. *
  988. * LATER mikeke
  989. * Do we need to send down the flags with DWP_ERASE and DSP_FRAME
  990. * in it?
  991. */
  992. UserAssert(HIWORD(flags) == 0);
  993. QueueNotifyMessage(pwnd, WM_SYNCPAINT, flags, 0);
  994. /*
  995. * Set our syncpaint-pending flag, since we queued one up. This
  996. * will be used to check when we validate-parents for windows
  997. * without clipchildren.
  998. */
  999. SetWF(pwnd, WFSYNCPAINTPENDING);
  1000. }
  1001. /*
  1002. * If we posted a WM_SYNCPAINT for a top-level window that is not
  1003. * of the current thread we're done; we'll pick up the children
  1004. * when we process the message for real. If we're the desktop
  1005. * however make sure we get all it children.
  1006. */
  1007. if (pwnd != PWNDDESKTOP(pwnd))
  1008. return;
  1009. }
  1010. /*
  1011. * Normally we like to enumerate all of this window's children and have
  1012. * them erase their backgrounds synchronously. However, this is a bad
  1013. * thing to do if the window is NOT CLIPCHLIDREN. Here's the scenario
  1014. * we want to to avoid:
  1015. *
  1016. * 1. Window 'A' is invalidated
  1017. * 2. 'A' erases itself (or not, doesn't matter)
  1018. * 3. 'A's children are enumerated and they erase themselves.
  1019. * 4. 'A' paints over its children (remember, 'A' isn't CLIPCHILDREN)
  1020. * 5. 'A's children paint but their backgrounds aren't their ERASEBKND
  1021. * color (because 'A' painted over them) and everything looks like
  1022. * dirt.
  1023. */
  1024. if ((flags & DSP_ALLCHILDREN) ||
  1025. ((flags & DSP_ENUMCLIPPEDCHILDREN) && TestWF(pwnd, WFCLIPCHILDREN))) {
  1026. PWND pwndT;
  1027. for (pwndT = pwnd->spwndChild; pwndT; pwndT = pwndT->spwndNext) {
  1028. /*
  1029. * Don't cause any more intertask sendmessages cause it does
  1030. * bad things to cbt's windowproc hooks. (Due to SetParent
  1031. * allowing child windows in the topwindow hierarchy.
  1032. * The child bit also catches the desktop window; we want to
  1033. */
  1034. if (TestWF(pwndT, WFCHILD) && (pti != GETPTI(pwndT)))
  1035. continue;
  1036. /*
  1037. * Note that we pass only certain bits down as we recurse:
  1038. * the other bits pertain to the current window only.
  1039. */
  1040. DoQueuedSyncPaint(pwndT, flags, pti);
  1041. }
  1042. }
  1043. }
  1044. /***************************************************************************\
  1045. * xxxDoSyncPaint
  1046. *
  1047. * This funstion is only called for the initial syncpaint so we always
  1048. * queue syncpaints to other threads in this funtion.
  1049. *
  1050. * History:
  1051. \***************************************************************************/
  1052. VOID xxxDoSyncPaint(
  1053. PWND pwnd,
  1054. DWORD flags)
  1055. {
  1056. CheckLock(pwnd);
  1057. /*
  1058. * If any of our non-clipchildren parents have an update region, don't
  1059. * do anything. This way we won't redraw our background or frame out
  1060. * of order, only to have it get obliterated when our parent erases his
  1061. * background.
  1062. */
  1063. if (ParentNeedsPaint(pwnd))
  1064. return;
  1065. /*
  1066. * First of all if we are going to be queueing any WM_SYNCPAINT messages
  1067. * to windows of another thread do it first while the window's update
  1068. * regions are still in sync. This way there is no chance the update
  1069. * region will be incorrect (through window movement during callbacks of
  1070. * the WM_ERASEBKGND|WM_NCPAINT messages).
  1071. */
  1072. DoQueuedSyncPaint(pwnd, flags, PtiCurrent());
  1073. xxxInternalDoSyncPaint(pwnd, flags);
  1074. }
  1075. /***************************************************************************\
  1076. * ParentNeedsPaint
  1077. *
  1078. * Return a non-zero PWND if a non-CLIPCHILDREN parent requires a WM_PAINT
  1079. * message.
  1080. *
  1081. * History:
  1082. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1083. \***************************************************************************/
  1084. PWND ParentNeedsPaint(
  1085. PWND pwnd)
  1086. {
  1087. while ((pwnd = pwnd->spwndParent) != NULL) {
  1088. if (TestWF(pwnd, WFCLIPCHILDREN))
  1089. break;
  1090. if (NEEDSPAINT(pwnd))
  1091. return pwnd;
  1092. }
  1093. return NULL;
  1094. }
  1095. /***************************************************************************\
  1096. * xxxSendEraseBkgnd
  1097. *
  1098. * Sends a WM_ERASEBKGROUND event to the window. This contains the paintDC
  1099. * with the update-region selected into it. If there's no update region
  1100. * then we prevent this event from making it to the window.
  1101. *
  1102. * History:
  1103. * 16-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1104. * 15-Dec-1996 ChrisWil Merged Chicago Functionality (no erase on min).
  1105. \***************************************************************************/
  1106. BOOL xxxSendEraseBkgnd(
  1107. PWND pwnd,
  1108. HDC hdcBeginPaint,
  1109. HRGN hrgnUpdate)
  1110. {
  1111. PTHREADINFO ptiCurrent;
  1112. BOOL fErased;
  1113. HDC hdc;
  1114. CheckLock(pwnd);
  1115. /*
  1116. * For minimized dudes in win3.1, we would've sent an
  1117. * WM_ICONERASEBKGND and cleared the erase bit. Now that min
  1118. * windows in 4.0 are all nonclient, don't bother erasing at
  1119. * all. Pretend like we did.
  1120. *
  1121. * NOTE:
  1122. * For < 4.0 windows, we may have to send a fake WM_ICONERASEKBGND
  1123. * to keep 'em happy. Saves time not to though. Getting a DC and
  1124. * sending the message ain't speedy.
  1125. */
  1126. if ((hrgnUpdate == NULL) || TestWF(pwnd, WFMINIMIZED))
  1127. return FALSE;
  1128. /*
  1129. * If a DC to use was not passed in, get one.
  1130. * We want one clipped to this window's update region.
  1131. */
  1132. if (hdcBeginPaint == NULL) {
  1133. hdc = _GetDCEx(pwnd,
  1134. hrgnUpdate,
  1135. DCX_USESTYLE | DCX_INTERSECTRGN | DCX_NODELETERGN);
  1136. } else {
  1137. hdc = hdcBeginPaint;
  1138. }
  1139. /*
  1140. * If we're send the WM_ERASEBKGND to another process
  1141. * we need to change the DC owner.
  1142. *
  1143. * We'd like to change the owner to pwnd->pti->idProcess, but
  1144. * GDI won't let us assign ownership back to ourselves later.
  1145. */
  1146. ptiCurrent = PtiCurrent();
  1147. if (GETPTI(pwnd)->ppi != ptiCurrent->ppi)
  1148. GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC);
  1149. /*
  1150. * Send the event to the window. This contains the DC clipped to
  1151. * the update-region.
  1152. */
  1153. fErased = (BOOL)xxxSendMessage(pwnd, WM_ERASEBKGND, (WPARAM)hdc, 0L);
  1154. /*
  1155. * If we've changed the DC owner, change it back to
  1156. * the current process.
  1157. */
  1158. if (GETPTI(pwnd)->ppi != ptiCurrent->ppi)
  1159. GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT);
  1160. /*
  1161. * If the WM_ERASEBKGND message did not erase the
  1162. * background, then set this flag to let BeginPaint()
  1163. * know to ask the caller to do it via the fErase
  1164. * flag in the PAINTSTRUCT.
  1165. */
  1166. if (!fErased) {
  1167. SetWF(pwnd, WFERASEBKGND);
  1168. if (!TestWF(pwnd, WFWIN31COMPAT))
  1169. SetWF(pwnd, WFSENDERASEBKGND);
  1170. }
  1171. /*
  1172. * If we got a cache DC in this routine, release it.
  1173. */
  1174. if (hdcBeginPaint == NULL) {
  1175. ReleaseCacheDC(hdc, TRUE);
  1176. }
  1177. return fErased;
  1178. }
  1179. /***************************************************************************\
  1180. * IncPaintCount
  1181. *
  1182. * EFFECTS:
  1183. * If cPaintsReady changes from 0 to 1, the QS_PAINT bit is set for
  1184. * associated queue and we wake up task so repaint will occur.
  1185. *
  1186. * IMPLEMENTATION:
  1187. * Get the queue handle from the window handle, bump the paint count, and
  1188. * if paint count is one, Set the wakebit.
  1189. *
  1190. * History:
  1191. * 17-Jul-1991 DarrinM Translated Win 3.1 ASM code.
  1192. \***************************************************************************/
  1193. VOID IncPaintCount(
  1194. PWND pwnd)
  1195. {
  1196. PTHREADINFO pti = GETPTI(pwnd);
  1197. if (pti->cPaintsReady++ == 0)
  1198. SetWakeBit(pti, QS_PAINT);
  1199. }
  1200. /***************************************************************************\
  1201. * DecPaintCount
  1202. *
  1203. * EFFECTS:
  1204. * If cPaintsReady changes from 1 to 0, the QS_PAINT bit is cleared so
  1205. * that no more paints will occur.
  1206. *
  1207. * IMPLEMENTATION:
  1208. * Get the queue handle from the window handle, decrement the paint count,
  1209. * and if paint count is zero, clear the wakebit.
  1210. *
  1211. * History:
  1212. * 17-Jul-1991 DarrinM Translated Win 3.1 ASM code.
  1213. \***************************************************************************/
  1214. VOID DecPaintCount(
  1215. PWND pwnd)
  1216. {
  1217. PTHREADINFO pti = GETPTI(pwnd);
  1218. if (--pti->cPaintsReady == 0) {
  1219. pti->pcti->fsWakeBits &= ~QS_PAINT;
  1220. pti->pcti->fsChangeBits &= ~QS_PAINT;
  1221. }
  1222. }
  1223. /***************************************************************************\
  1224. * UT_GetParentDCClipBox
  1225. *
  1226. * Return rectangle coordinates of the parent clip-rect. If the window
  1227. * isn't using a parentDC for drawing then return normal clipbox.
  1228. *
  1229. * History:
  1230. * 31-Oct-1990 DarrinM Ported from Win 3.0 sources.
  1231. \***************************************************************************/
  1232. int UT_GetParentDCClipBox(
  1233. PWND pwnd,
  1234. HDC hdc,
  1235. LPRECT lprc)
  1236. {
  1237. RECT rc;
  1238. if (GreGetClipBox(hdc, lprc, TRUE) == NULLREGION)
  1239. return FALSE;
  1240. if ((pwnd == NULL) || !TestCF(pwnd, CFPARENTDC))
  1241. return TRUE;
  1242. GetRect(pwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS);
  1243. return IntersectRect(lprc, lprc, &rc);
  1244. }
  1245. /***************************************************************************\
  1246. * UserRedrawDesktop
  1247. *
  1248. * Redraw the desktop and its children. This is called from GDI for DCI
  1249. * related unlocks, so that all visrgns are recalculated for the apps.
  1250. *
  1251. * History:
  1252. * 08-Jan-1996 ChrisWil Created.
  1253. \***************************************************************************/
  1254. VOID UserRedrawDesktop(VOID)
  1255. {
  1256. TL tlpwnd;
  1257. PWND pwndDesk;
  1258. EnterCrit();
  1259. pwndDesk = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  1260. ThreadLockAlways(pwndDesk, &tlpwnd);
  1261. xxxInternalInvalidate(pwndDesk,
  1262. HRGN_FULL,
  1263. RDW_INVALIDATE |
  1264. RDW_ERASE |
  1265. RDW_FRAME |
  1266. RDW_ALLCHILDREN);
  1267. ThreadUnlock(&tlpwnd);
  1268. LeaveCrit();
  1269. }