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.

2335 lines
72 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: dc.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains User's DC APIs and related functions.
  7. *
  8. * History:
  9. * 23-Oct-1990 DarrinM Created.
  10. * 07-Feb-1991 MikeKe Added Revalidation code (None).
  11. * 17-Jul-1991 DarrinM Recreated from Win 3.1 source.
  12. * 21-Jan-1992 IanJa ANSI/Unicode neutral (null op).
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * DBG Related Information.
  18. */
  19. #if DBG
  20. BOOL fDisableCache; // TRUE to disable DC cache.
  21. #endif
  22. /***************************************************************************\
  23. * DecrementFreeDCECount
  24. *
  25. \***************************************************************************/
  26. __inline VOID DecrementFreeDCECount(
  27. VOID)
  28. {
  29. UserAssert(gnDCECount >= 0);
  30. gnDCECount--;
  31. }
  32. /***************************************************************************\
  33. * IncrementFreeDCECount
  34. *
  35. \***************************************************************************/
  36. __inline VOID IncrementFreeDCECount(
  37. VOID)
  38. {
  39. UserAssert(gnDCECount >= 0);
  40. gnDCECount++;
  41. }
  42. /***************************************************************************\
  43. * SetMonitorRegion
  44. *
  45. * The region is in meta dc coordinates, so convert to monitor coords.
  46. \***************************************************************************/
  47. VOID SetMonitorRegion(
  48. PMONITOR pMonitor,
  49. HRGN hrgnDst,
  50. HRGN hrgnSrc)
  51. {
  52. if (IntersectRgn(hrgnDst, hrgnSrc, pMonitor->hrgnMonitor) == ERROR) {
  53. GreSetRectRgn(hrgnDst, 0, 0, 0, 0);
  54. return;
  55. }
  56. GreOffsetRgn(hrgnDst, -pMonitor->rcMonitor.left, -pMonitor->rcMonitor.top);
  57. }
  58. /***************************************************************************\
  59. * ResetOrg
  60. *
  61. * Resets the origin of the DC associated with *pdce, and selects
  62. * a new visrgn.
  63. *
  64. * History:
  65. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  66. \***************************************************************************/
  67. VOID ResetOrg(
  68. HRGN hrgn,
  69. PDCE pdce,
  70. BOOL fSetVisRgn)
  71. {
  72. RECT rc;
  73. PWND pwndLayer;
  74. /*
  75. * For compatibility purposes, make sure that the DC's for the
  76. * desktop windows originate at the primary monitor, i.e. (0,0).
  77. */
  78. if (GETFNID(pdce->pwndOrg) == FNID_DESKTOP) {
  79. rc.left = rc.top = 0;
  80. rc.right = SYSMET(CXVIRTUALSCREEN);
  81. rc.bottom = SYSMET(CYVIRTUALSCREEN);
  82. } else if (pdce->DCX_flags & DCX_WINDOW) {
  83. rc = pdce->pwndOrg->rcWindow;
  84. } else {
  85. rc = pdce->pwndOrg->rcClient;
  86. }
  87. if (pdce->pMonitor != NULL) {
  88. OffsetRect(&rc, -pdce->pMonitor->rcMonitor.left,
  89. -pdce->pMonitor->rcMonitor.top);
  90. if (hrgn != NULL) {
  91. SetMonitorRegion(pdce->pMonitor, hrgn, hrgn);
  92. }
  93. }
  94. if (((pwndLayer = GetStyleWindow(pdce->pwndOrg, WEFPREDIRECTED)) != NULL)
  95. && (pdce->DCX_flags & DCX_REDIRECTED)) {
  96. int x = pwndLayer->rcWindow.left;
  97. int y = pwndLayer->rcWindow.top;
  98. /*
  99. * For layered redirection DCs, the surface origin is the
  100. * window origin, so offset both the rectangle and the
  101. * region appropriately.
  102. */
  103. OffsetRect(&rc, -x, -y);
  104. if (hrgn != NULL) {
  105. GreOffsetRgn(hrgn, -x, -y);
  106. }
  107. } else if (GetStyleWindow(pdce->pwndOrg, WEFLAYERED) != NULL) {
  108. /*
  109. * Layered windows can only draw to the screen via the redirection
  110. * DCs or UpdateLayeredWindow, so select an empty visrgn into this
  111. * screen DC.
  112. */
  113. if (hrgn != NULL) {
  114. GreSetRectRgn(hrgn, 0, 0, 0, 0);
  115. }
  116. }
  117. GreSetDCOrg(pdce->hdc, rc.left, rc.top, (PRECTL)&rc);
  118. if (fSetVisRgn) {
  119. GreSelectVisRgn(pdce->hdc, hrgn, SVR_DELETEOLD);
  120. }
  121. }
  122. /***************************************************************************\
  123. * GetDC (API)
  124. *
  125. * Standard call to GetDC().
  126. *
  127. * History:
  128. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  129. \***************************************************************************/
  130. HDC _GetDC(
  131. PWND pwnd)
  132. {
  133. /*
  134. * Special case for NULL: For backward compatibility we want to return
  135. * a window DC for the desktop that does not exclude its children.
  136. */
  137. if (pwnd == NULL) {
  138. PDESKTOP pdesk = PtiCurrent()->rpdesk;
  139. if (pdesk) {
  140. return _GetDCEx(pdesk->pDeskInfo->spwnd,
  141. NULL,
  142. DCX_WINDOW | DCX_CACHE);
  143. }
  144. /*
  145. * The thread has no desktop. Fail the call.
  146. */
  147. return NULL;
  148. }
  149. return _GetDCEx(pwnd, NULL, DCX_USESTYLE);
  150. }
  151. /***************************************************************************\
  152. * _ReleaseDC (API)
  153. *
  154. * Release the DC retrieved from GetDC().
  155. *
  156. * History:
  157. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  158. \***************************************************************************/
  159. BOOL _ReleaseDC(
  160. HDC hdc)
  161. {
  162. CheckCritIn();
  163. return (ReleaseCacheDC(hdc, FALSE) == DCE_NORELEASE ? FALSE : TRUE);
  164. }
  165. /***************************************************************************\
  166. * _GetWindowDC (API)
  167. *
  168. * Retrive a DC for the window.
  169. *
  170. * History:
  171. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  172. * 25-Jan-1996 ChrisWil Allow rgnClip so that WM_NCACTIVATE can clip.
  173. \***************************************************************************/
  174. HDC _GetWindowDC(
  175. PWND pwnd)
  176. {
  177. return _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE);
  178. }
  179. /***************************************************************************\
  180. * UserSetDCVisRgn
  181. *
  182. * Set the visrgn for the DCE. If the window has a (hrgnClipPublic), we use
  183. * that instead of the (hrgnClip) since it's a public-object. The other is
  184. * created and owned by the user-thread and can't be used if say we're in the
  185. * hung-app-drawing (different process). Both regions should be equalent in
  186. * data.
  187. *
  188. * History:
  189. * 10-Nov-1992 DavidPe Created.
  190. * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry.
  191. \***************************************************************************/
  192. VOID UserSetDCVisRgn(
  193. PDCE pdce)
  194. {
  195. HRGN hrgn = NULL;
  196. HRGN hrgnClipPublic;
  197. BOOL fTempPublic;
  198. PWND pwndLayer;
  199. /*
  200. * If the visrgn calculated is empt, set the flag DCX_PWNDORGINVISIBLE,
  201. * otherwise clear it (it could've been set earlier on).
  202. */
  203. if (!CalcVisRgn(&hrgn, pdce->pwndOrg, pdce->pwndClip, pdce->DCX_flags)) {
  204. pdce->DCX_flags |= DCX_PWNDORGINVISIBLE;
  205. } else {
  206. pdce->DCX_flags &= ~DCX_PWNDORGINVISIBLE;
  207. }
  208. /*
  209. * For redirected windows, hrgnClipPublic was offset to 0,0 in _GetDCEx()
  210. * because all coordinates in the DC being used are relative to the
  211. * bitmap and not the screen. But the region we just got from CalcVisRgn()
  212. * is in screen coordinates. So we need to offset hrgnClipPublic back into
  213. * screen coordinates so that we can properly intersect it.
  214. */
  215. if ((pdce->hrgnClipPublic > HRGN_SPECIAL_LAST) &&
  216. ((pwndLayer = GetStyleWindow(pdce->pwndOrg, WEFPREDIRECTED)) != NULL)) {
  217. hrgnClipPublic = CreateEmptyRgnPublic();
  218. CopyRgn(hrgnClipPublic, pdce->hrgnClipPublic);
  219. GreOffsetRgn(hrgnClipPublic, pwndLayer->rcWindow.left, pwndLayer->rcWindow.top);
  220. fTempPublic = TRUE;
  221. } else {
  222. hrgnClipPublic = pdce->hrgnClipPublic;
  223. fTempPublic = FALSE;
  224. }
  225. /*
  226. * Deal with INTERSECTRGN and EXCLUDERGN.
  227. */
  228. if (pdce->DCX_flags & DCX_INTERSECTRGN) {
  229. UserAssert(hrgnClipPublic != HRGN_FULL);
  230. if (hrgnClipPublic == NULL) {
  231. SetEmptyRgn(hrgn);
  232. } else {
  233. IntersectRgn(hrgn, hrgn, hrgnClipPublic);
  234. }
  235. } else if (pdce->DCX_flags & DCX_EXCLUDERGN) {
  236. UserAssert(hrgnClipPublic != NULL);
  237. if (hrgnClipPublic == HRGN_FULL) {
  238. SetEmptyRgn(hrgn);
  239. } else {
  240. SubtractRgn(hrgn, hrgn, hrgnClipPublic);
  241. }
  242. }
  243. ResetOrg(hrgn, pdce, TRUE);
  244. if (fTempPublic) {
  245. GreDeleteObject(hrgnClipPublic);
  246. }
  247. }
  248. /***************************************************************************\
  249. * UserGetClientRgn
  250. *
  251. * Return a copy of the client region and rectangle for the given hwnd.
  252. *
  253. * The caller must enter the user critical section before calling this function.
  254. *
  255. * History:
  256. * 27-Sep-1993 WendyWu Created.
  257. \***************************************************************************/
  258. HRGN UserGetClientRgn(
  259. HWND hwnd,
  260. LPRECT lprc,
  261. BOOL bWindowInsteadOfClient)
  262. {
  263. HRGN hrgnClient = (HRGN)NULL;
  264. PWND pwnd;
  265. /*
  266. * Must be in critical section.
  267. */
  268. CheckCritIn();
  269. if (pwnd = ValidateHwnd(hwnd)) {
  270. if (bWindowInsteadOfClient) {
  271. /*
  272. * Never clip children for WO_RGN_WINDOW so that NetMeeting
  273. * gets the unioned window area:
  274. */
  275. CalcVisRgn(&hrgnClient,
  276. pwnd,
  277. pwnd,
  278. DCX_WINDOW |
  279. (TestWF(pwnd, WFCLIPSIBLINGS) ? DCX_CLIPSIBLINGS : 0));
  280. } else {
  281. CalcVisRgn(&hrgnClient,
  282. pwnd,
  283. pwnd,
  284. DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
  285. }
  286. *lprc = pwnd->rcClient;
  287. }
  288. return hrgnClient;
  289. }
  290. /***************************************************************************\
  291. * UserGetHwnd
  292. *
  293. * Return a hwnd and the associated pwo for the given display hdc.
  294. *
  295. * It returns FALSE if no hwnd corresponds to the hdc is found or if the
  296. * hwnd has incorrect styles for a device format window.
  297. *
  298. * The caller must enter the user critical section before calling this function.
  299. *
  300. * History:
  301. * 27-Sep-1993 WendyWu Created.
  302. \***************************************************************************/
  303. BOOL UserGetHwnd(
  304. HDC hdc,
  305. HWND *phwnd,
  306. PVOID *ppwo,
  307. BOOL bCheckStyle)
  308. {
  309. PWND pwnd;
  310. PDCE pdce;
  311. /*
  312. * Must be in critical section.
  313. */
  314. CheckCritIn();
  315. /*
  316. * Find pdce and pwnd for this DC.
  317. *
  318. * Note: the SAMEHANDLE macro strips out the user defined bits in the
  319. * handle before doing the comparison. This is important because when
  320. * GRE calls this function, it may have lost track of the OWNDC bit.
  321. */
  322. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  323. if (pdce->hdc == hdc) // this should be undone once SAMEHANDLE is fixed for kmode
  324. break;
  325. }
  326. /*
  327. * Return FALSE If it is not in the pdce list.
  328. */
  329. if ((pdce == NULL) || (pdce->pwndOrg == NULL))
  330. return FALSE;
  331. pwnd = pdce->pwndOrg;
  332. /*
  333. * The window style must be clipchildren and clipsiblings.
  334. * the window's class must not be parentdc
  335. */
  336. if (bCheckStyle) {
  337. if ( !TestWF(pwnd, WFCLIPCHILDREN) ||
  338. !TestWF(pwnd, WFCLIPSIBLINGS) ||
  339. TestCF(pwnd, CFPARENTDC)) {
  340. RIPMSG0(RIP_WARNING, "UserGetHwnd: Bad OpenGL window style or class");
  341. return FALSE;
  342. }
  343. }
  344. /*
  345. * Return the hwnd with the correct styles for a device format window.
  346. */
  347. *phwnd = HW(pwnd);
  348. *ppwo = _GetProp(pwnd, PROP_WNDOBJ, TRUE);
  349. return TRUE;
  350. }
  351. /***************************************************************************\
  352. * UserAssociateHwnd
  353. *
  354. * Associate a gdi WNDOBJ with hwnd. The caller must enter the user
  355. * critical section before calling this function.
  356. *
  357. * If 'pwo' is NULL, the association is removed.
  358. *
  359. * History:
  360. * 13-Jan-1994 HockL Created.
  361. \***************************************************************************/
  362. VOID UserAssociateHwnd(
  363. HWND hwnd,
  364. PVOID pwo)
  365. {
  366. PWND pwnd;
  367. /*
  368. * Must be in critical section.
  369. */
  370. CheckCritIn();
  371. if (pwnd = ValidateHwnd(hwnd)) {
  372. if (pwo != NULL) {
  373. if (InternalSetProp(pwnd, PROP_WNDOBJ, pwo, PROPF_INTERNAL | PROPF_NOPOOL))
  374. gcountPWO++;
  375. } else {
  376. if (InternalRemoveProp(pwnd, PROP_WNDOBJ, TRUE))
  377. gcountPWO--;
  378. }
  379. }
  380. }
  381. /***************************************************************************\
  382. * UserReleaseDC
  383. *
  384. * Enter's the critical section and calls _ReleaseDC.
  385. *
  386. * History:
  387. * 25-Jan-1996 ChrisWil Created comment block.
  388. \***************************************************************************/
  389. BOOL UserReleaseDC(
  390. HDC hdc)
  391. {
  392. BOOL b;
  393. EnterCrit();
  394. b = _ReleaseDC(hdc);
  395. LeaveCrit();
  396. return b;
  397. }
  398. /***************************************************************************\
  399. * InvalidateDce
  400. *
  401. * If the DCE is not in use, removes all information and marks it invalid.
  402. * Otherwise, it resets the DCE flags based on the window styles and
  403. * recalculates the vis rgn.
  404. *
  405. * History:
  406. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  407. \***************************************************************************/
  408. VOID InvalidateDce(
  409. PDCE pdce)
  410. {
  411. GreLockDisplay(gpDispInfo->hDev);
  412. if (!(pdce->DCX_flags & DCX_INUSE)) {
  413. /*
  414. * Accumulate any bounds for this CE
  415. * since we're about to mark it invalid.
  416. */
  417. SpbCheckDce(pdce);
  418. MarkDCEInvalid(pdce);
  419. pdce->pwndOrg = NULL;
  420. pdce->pwndClip = NULL;
  421. pdce->hrgnClip = NULL;
  422. pdce->hrgnClipPublic = NULL;
  423. /*
  424. * Remove the vis rgn since it is still owned - if we did not,
  425. * gdi would not be able to clean up properly if the app that
  426. * owns this vis rgn exist while the vis rgn is still selected.
  427. */
  428. GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD);
  429. } else {
  430. PWND pwndOrg = pdce->pwndOrg;
  431. PWND pwndClip = pdce->pwndClip;
  432. /*
  433. * In case the window's clipping style bits changed,
  434. * reset the DCE flags from the window style bits.
  435. * Note that minimized windows never exclude their children.
  436. */
  437. pdce->DCX_flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
  438. /*
  439. * Chicago stuff...
  440. */
  441. if (TestCF(pwndOrg, CFPARENTDC) &&
  442. (TestWF(pwndOrg, WFWIN31COMPAT) || !TestWF(pwndClip, WFCLIPCHILDREN)) &&
  443. (TestWF(pwndOrg, WFVISIBLE) == TestWF(pwndClip, WFVISIBLE))) {
  444. if (TestWF(pwndClip, WFCLIPSIBLINGS))
  445. pdce->DCX_flags |= DCX_CLIPSIBLINGS;
  446. } else {
  447. if (TestWF(pwndOrg, WFCLIPCHILDREN) && !TestWF(pwndOrg, WFMINIMIZED))
  448. pdce->DCX_flags |= DCX_CLIPCHILDREN;
  449. if (TestWF(pwndOrg, WFCLIPSIBLINGS))
  450. pdce->DCX_flags |= DCX_CLIPSIBLINGS;
  451. }
  452. /*
  453. * Mark that any saved visrgn needs to be recomputed.
  454. */
  455. pdce->DCX_flags |= DCX_SAVEDRGNINVALID;
  456. UserSetDCVisRgn(pdce);
  457. }
  458. GreUnlockDisplay(gpDispInfo->hDev);
  459. }
  460. /***************************************************************************\
  461. * DeleteHrgnClip
  462. *
  463. * Deletes the clipping regions in the DCE, restores the saved visrgn,
  464. * and invalidates the DCE if saved visrgn is invalid.
  465. *
  466. * History:
  467. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  468. \***************************************************************************/
  469. VOID DeleteHrgnClip(
  470. PDCE pdce)
  471. {
  472. /*
  473. * Clear these flags first in case we get a DCHook() callback...
  474. */
  475. pdce->DCX_flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN);
  476. /*
  477. * Blow away pdce->hrgnClip and clear the associated flags.
  478. * Do not delete hrgnClip if DCX_NODELETERGN is set!
  479. */
  480. if (!(pdce->DCX_flags & DCX_NODELETERGN)) {
  481. DeleteMaybeSpecialRgn(pdce->hrgnClip);
  482. } else {
  483. pdce->DCX_flags &= ~DCX_NODELETERGN;
  484. }
  485. DeleteMaybeSpecialRgn(pdce->hrgnClipPublic);
  486. pdce->hrgnClip = NULL;
  487. pdce->hrgnClipPublic = NULL;
  488. /*
  489. * If the saved visrgn was invalidated by an InvalidateDce()
  490. * while we had it checked out, then invalidate the entry now.
  491. */
  492. if (pdce->DCX_flags & DCX_SAVEDRGNINVALID) {
  493. InvalidateDce(pdce);
  494. /*
  495. * We've just gone through InvalidateDce, so the visrgn in the
  496. * DC has been properly reset. Simply nuke the old saved visrgn.
  497. */
  498. if (pdce->hrgnSavedVis != NULL) {
  499. GreDeleteObject(pdce->hrgnSavedVis);
  500. pdce->hrgnSavedVis = NULL;
  501. }
  502. } else {
  503. /*
  504. * The saved visrgn is still valid, select it back into the
  505. * DC so the entry may be re-used without recomputing.
  506. */
  507. if (pdce->hrgnSavedVis != NULL) {
  508. GreSelectVisRgn(pdce->hdc, pdce->hrgnSavedVis, SVR_DELETEOLD);
  509. pdce->hrgnSavedVis = NULL;
  510. }
  511. }
  512. }
  513. /***************************************************************************\
  514. * GetDCEx (API)
  515. *
  516. *
  517. * History:
  518. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  519. * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry.
  520. \***************************************************************************/
  521. HDC _GetDCEx(
  522. PWND pwnd,
  523. HRGN hrgnClip,
  524. DWORD DCX_flags)
  525. {
  526. HRGN hrgn;
  527. HDC hdcMatch;
  528. PWND pwndClip;
  529. PWND pwndOrg;
  530. PDCE pdce;
  531. PDCE *ppdce;
  532. PDCE *ppdceNotInUse;
  533. DWORD DCX_flagsMatch;
  534. BOOL bpwndOrgVisible;
  535. PWND pwndLayer;
  536. HBITMAP hbmLayer;
  537. BOOL fVisRgnError = FALSE;
  538. /*
  539. * Lock the device while we're playing with visrgns.
  540. */
  541. GreLockDisplay(gpDispInfo->hDev);
  542. if (pwnd == NULL)
  543. pwnd = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  544. hdcMatch = NULL;
  545. pwndOrg = pwndClip = pwnd;
  546. bpwndOrgVisible = IsVisible(pwndOrg);
  547. if (PpiCurrent()->W32PF_Flags & W32PF_OWNDCCLEANUP) {
  548. DelayedDestroyCacheDC();
  549. }
  550. /*
  551. * If necessary, compute DCX flags from window style.
  552. */
  553. if (DCX_flags & DCX_USESTYLE) {
  554. DCX_flags &= ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_PARENTCLIP);
  555. if (!(DCX_flags & DCX_WINDOW)) {
  556. if (TestCF(pwndOrg, CFPARENTDC))
  557. DCX_flags |= DCX_PARENTCLIP;
  558. /*
  559. * If the DCX_CACHE flag is present, override OWNDC/CLASSDC.
  560. * Otherwise, calculate from appropriate style bits.
  561. */
  562. if (!(DCX_flags & DCX_CACHE) && !TestCF(pwndOrg, CFOWNDC)) {
  563. if (TestCF(pwndOrg, CFCLASSDC)) {
  564. /*
  565. * Look for a non-cache entry that matches hdc...
  566. */
  567. if (pwndOrg->pcls->pdce != NULL) {
  568. hdcMatch = pwndOrg->pcls->pdce->hdc;
  569. }
  570. } else {
  571. DCX_flags |= DCX_CACHE;
  572. }
  573. }
  574. if (TestWF(pwndOrg, WFCLIPCHILDREN))
  575. DCX_flags |= DCX_CLIPCHILDREN;
  576. if (TestWF(pwndOrg, WFCLIPSIBLINGS))
  577. DCX_flags |= DCX_CLIPSIBLINGS;
  578. /*
  579. * Minimized windows never exclude their children.
  580. */
  581. if (TestWF(pwndOrg, WFMINIMIZED)) {
  582. DCX_flags &= ~DCX_CLIPCHILDREN;
  583. if (pwndOrg->pcls->spicn)
  584. DCX_flags |= DCX_CACHE;
  585. }
  586. } else {
  587. if (TestWF(pwndClip, WFCLIPSIBLINGS))
  588. DCX_flags |= DCX_CLIPSIBLINGS;
  589. DCX_flags |= DCX_CACHE;
  590. /*
  591. * Window DCs never exclude children.
  592. */
  593. }
  594. }
  595. /*
  596. * Deal with all the Win 3.0-compatible clipping rules:
  597. *
  598. * DCX_NOCLIPCHILDREN overrides:
  599. * DCX_PARENTCLIP/CS_OWNDC/CS_CLASSDC
  600. * DCX_PARENTCLIP overrides:
  601. * DCX_CLIPSIBLINGS/DCX_CLIPCHILDREN/CS_OWNDC/CS_CLASSDC
  602. */
  603. if (DCX_flags & DCX_NOCLIPCHILDREN) {
  604. DCX_flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
  605. DCX_flags |= DCX_CACHE;
  606. }
  607. /*
  608. * Deal with layered windows.
  609. */
  610. if ((pwndLayer = GetStyleWindow(pwndOrg, WEFPREDIRECTED)) != NULL &&
  611. (hbmLayer = GetRedirectionBitmap(pwndLayer)) != NULL) {
  612. /*
  613. * Get a layered redirection DC.
  614. */
  615. DCX_flags |= DCX_REDIRECTED;
  616. /*
  617. * When the window we're getting the DC for is the layered and
  618. * redirected window, don't allow to clip to its parent, since
  619. * clipping must not exceed the size of the backing bitmap.
  620. */
  621. if (pwndOrg == pwndLayer) {
  622. DCX_flags &= ~DCX_PARENTCLIP;
  623. }
  624. /*
  625. * Convert hrgnClip from screen to the redirection DC coordinates.
  626. */
  627. if (hrgnClip > HRGN_SPECIAL_LAST) {
  628. if (DCX_flags & DCX_NODELETERGN) {
  629. HRGN hrgnClipSave = hrgnClip;
  630. hrgnClip = CreateEmptyRgnPublic();
  631. CopyRgn(hrgnClip, hrgnClipSave);
  632. DCX_flags &= ~DCX_NODELETERGN;
  633. }
  634. GreOffsetRgn(hrgnClip, -pwndLayer->rcWindow.left,
  635. -pwndLayer->rcWindow.top);
  636. }
  637. } else {
  638. pwndLayer = NULL;
  639. hbmLayer = NULL;
  640. }
  641. if (DCX_flags & DCX_PARENTCLIP) {
  642. PWND pwndParent;
  643. /*
  644. * If this window has no parent. This can occur if the app is
  645. * calling GetDC in response to a CBT_CREATEWND callback. In this
  646. * case, the parent is not yet setup.
  647. */
  648. if (pwndOrg->spwndParent == NULL)
  649. pwndParent = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
  650. else
  651. pwndParent = pwndOrg->spwndParent;
  652. /*
  653. * Always get the DC from the cache.
  654. */
  655. DCX_flags |= DCX_CACHE;
  656. /*
  657. * We can't use a shared DC if the visibility of the
  658. * child does not match the parent's, or if a
  659. * CLIPSIBLINGS or CLIPCHILDREN DC is requested.
  660. *
  661. * In 3.1, we pay attention to the CLIPSIBLINGS and CLIPCHILDREN
  662. * bits of CS_PARENTDC windows, by overriding CS_PARENTDC if
  663. * either of these flags are requested.
  664. *
  665. * BACKWARD COMPATIBILITY HACK
  666. *
  667. * If parent is CLIPCHILDREN, get a cache DC, but don't
  668. * use parent's DC. Windows PowerPoint depends on this
  669. * behavior in order to draw the little gray rect between
  670. * its scroll bars correctly.
  671. */
  672. if (!(DCX_flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) &&
  673. (TestWF(pwndOrg, WFWIN31COMPAT) || !TestWF(pwndParent, WFCLIPCHILDREN)) &&
  674. TestWF(pwndParent, WFVISIBLE) == TestWF(pwndOrg, WFVISIBLE)) {
  675. pwndClip = pwndParent;
  676. #if DBG
  677. if (DCX_flags & DCX_CLIPCHILDREN)
  678. RIPMSG0(RIP_WARNING, "WS_CLIPCHILDREN overridden by CS_PARENTDC");
  679. if (DCX_flags & DCX_CLIPSIBLINGS)
  680. RIPMSG0(RIP_WARNING, "WS_CLIPSIBLINGS overridden by CS_PARENTDC");
  681. #endif
  682. /*
  683. * Make sure flags reflect hwndClip rather than hwndOrg.
  684. * But, we must never clip the children (since that's who
  685. * wants to do the drawing!)
  686. */
  687. DCX_flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
  688. if (TestWF(pwndClip, WFCLIPSIBLINGS))
  689. DCX_flags |= DCX_CLIPSIBLINGS;
  690. }
  691. }
  692. /*
  693. * Make sure we don't return an OWNDC if the calling thread didn't
  694. * create this window - need to returned cached always in this case.
  695. *
  696. * Win95 does not contain this code. Why?
  697. */
  698. if (!(DCX_flags & DCX_CACHE)) {
  699. if (pwndOrg == NULL || GETPTI(pwndOrg) != PtiCurrent())
  700. DCX_flags |= DCX_CACHE;
  701. }
  702. DCX_flagsMatch = DCX_flags & DCX_MATCHMASK;
  703. if (!(DCX_flags & DCX_CACHE)) {
  704. /*
  705. * Handle CS_OWNDC and CS_CLASSDC cases specially. Based on the
  706. * supplied match information, we need to find the appropriate DCE.
  707. */
  708. for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) {
  709. if (pdce->DCX_flags & DCX_CACHE)
  710. continue;
  711. /*
  712. * Look for the entry that matches hdcMatch or pwndOrg...
  713. */
  714. if (!(pdce->pwndOrg == pwndOrg || pdce->hdc == hdcMatch))
  715. continue;
  716. /*
  717. * NOTE: The "Multiple-BeginPaint()-of-OWNDC-Window" Conundrum
  718. *
  719. * There is a situation having to do with OWNDC or CLASSDC window
  720. * DCs that can theoretically arise that is handled specially
  721. * here and in ReleaseCacheDC(). These DCs are identified with
  722. * the DCX_CACHE bit CLEAR.
  723. *
  724. * In the case where BeginPaint() (or a similar operation) is
  725. * called more than once without an intervening EndPaint(), the
  726. * DCX_INTERSECTRGN (or DCX_EXCLUDERGN) bit may already be set
  727. * when we get here.
  728. *
  729. * Theoretically, the correct thing to do is to save the current
  730. * hrgnClip, and set up the new one here. In ReleaseCacheDC, the
  731. * saved hrgnClip is restored and the visrgn recomputed.
  732. *
  733. * All of this is only necessary if BOTH calls involve an
  734. * hrgnClip that causes the visrgn to be changed (i.e., the
  735. * simple hrgnClip test clears the INTERSECTRGN or EXCLUDERGN bit
  736. * fails), which is not at all likely.
  737. *
  738. * When this code encounters this multiple-BeginPaint case it
  739. * punts by honoring the new EXCLUDE/INTERSECTRGN bits, but it
  740. * first restores the DC to a wide-open visrgn before doing so.
  741. * This means that the first EndPaint() will restore the visrgn
  742. * to a wide-open DC, rather than clipped to the first
  743. * BeginPaint()'s update rgn. This is a good punt, because worst
  744. * case an app does a bit more drawing than it should.
  745. */
  746. if ((pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) &&
  747. (DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))) {
  748. RIPMSG0(RIP_WARNING, "Nested BeginPaint() calls, please fix Your app!");
  749. DeleteHrgnClip(pdce);
  750. }
  751. if (pdce->DCX_flags & DCX_REDIRECTED) {
  752. /*
  753. * We're giving out the same DC again. Since it may not have
  754. * been released, transfer any accumulated bits if needed.
  755. */
  756. UpdateRedirectedDC(pdce);
  757. /*
  758. * As this point, the DC may get converted back to a screen
  759. * DC, so we must select the screen surface back into the DC.
  760. */
  761. UserVerify(GreSelectRedirectionBitmap(pdce->hdc, NULL));
  762. }
  763. /*
  764. * If we matched exactly, no recomputation necessary
  765. * (we found a CS_OWNDC or a CS_CLASSDC that is already set up)
  766. * Otherwise, we have a CS_CLASSDC that needs recomputation.
  767. */
  768. if ( pdce->pwndOrg == pwndOrg &&
  769. bpwndOrgVisible &&
  770. (pdce->DCX_flags & DCX_REDIRECTED) == (DCX_flags & DCX_REDIRECTED) &&
  771. !(pdce->DCX_flags & DCX_PWNDORGINVISIBLE)) {
  772. goto HaveComputedEntry;
  773. }
  774. goto RecomputeEntry;
  775. }
  776. RIPMSG1(RIP_WARNING, "Couldn't find DC for %p - bad code path", pwndOrg);
  777. NullExit:
  778. GreUnlockDisplay(gpDispInfo->hDev);
  779. return NULL;
  780. } else {
  781. /*
  782. * Make a quick pass through the cache, looking for an
  783. * exact match.
  784. */
  785. SearchAgain:
  786. #if DBG
  787. if (fDisableCache) {
  788. goto SearchFailed;
  789. }
  790. #endif
  791. /*
  792. * CONSIDER (adams): Put this check into the loop above so we don't
  793. * touch all these pages twice?
  794. */
  795. for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) {
  796. /*
  797. * If we find an entry that is not in use and whose clip flags
  798. * and clip window match, we can use it.
  799. *
  800. * NOTE: DCX_INTERSECT/EXCLUDERGN cache entries always have
  801. * DCX_INUSE set, so we'll never erroneously match one here.
  802. */
  803. UserAssert(!(pdce->DCX_flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) ||
  804. (pdce->DCX_flags & DCX_INUSE));
  805. if ((pdce->pwndClip == pwndClip) &&
  806. pdce->pMonitor == NULL &&
  807. (DCX_flagsMatch == (pdce->DCX_flags & (DCX_MATCHMASK | DCX_INUSE | DCX_INVALID)))) {
  808. /*
  809. * Special case for icon - bug 9103 (win31)
  810. */
  811. if (TestWF(pwndClip, WFMINIMIZED) &&
  812. (pdce->pwndOrg != pdce->pwndClip)) {
  813. continue;
  814. }
  815. /*
  816. * If the pwndOrg of the DC we found is not visible and
  817. * the pwndOrg we're looking for is visble, then
  818. * the visrgn is no good, we can't reuse it so keep
  819. * looking.
  820. */
  821. if (bpwndOrgVisible && pdce->DCX_flags & DCX_PWNDORGINVISIBLE) {
  822. continue;
  823. }
  824. /*
  825. * Set INUSE before performing any GDI operations, just
  826. * in case DCHook() has a mind to recalculate the visrgn...
  827. */
  828. pdce->DCX_flags |= DCX_INUSE;
  829. /*
  830. * We found an entry with the proper visrgn.
  831. * If the origin doesn't match, update the CE and reset it.
  832. */
  833. if (pwndOrg != pdce->pwndOrg) {
  834. /*
  835. * Need to flush any dirty rectangle stuff now.
  836. */
  837. SpbCheckDce(pdce);
  838. pdce->pwndOrg = pwndOrg;
  839. ResetOrg(NULL, pdce, FALSE);
  840. }
  841. goto HaveComputedEntry;
  842. }
  843. }
  844. #if DBG
  845. SearchFailed:
  846. #endif
  847. /*
  848. * Couldn't find an exact match. Find some invalid or non-inuse
  849. * entry we can reuse.
  850. */
  851. ppdceNotInUse = NULL;
  852. for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) {
  853. /*
  854. * Skip non-cache entries
  855. */
  856. if (!(pdce->DCX_flags & DCX_CACHE))
  857. continue;
  858. /*
  859. * Skip monitor-specific entires
  860. */
  861. if (pdce->pMonitor != NULL)
  862. continue;
  863. if (pdce->DCX_flags & DCX_INVALID) {
  864. break;
  865. } else if (!(pdce->DCX_flags & DCX_INUSE)) {
  866. /*
  867. * Remember the non-inuse one, but keep looking for an invalid.
  868. */
  869. ppdceNotInUse = ppdce;
  870. }
  871. }
  872. /*
  873. * If we broke out of the loop, we found an invalid entry to reuse.
  874. * Otherwise see if we found a non-inuse entry to reuse.
  875. */
  876. if (pdce == NULL && ((ppdce = ppdceNotInUse) == NULL)) {
  877. /*
  878. * Create another DCE if we need it.
  879. */
  880. if (!CreateCacheDC(pwndOrg,
  881. DCX_INVALID | DCX_CACHE |
  882. (DCX_flags & DCX_REDIRECTED),
  883. NULL)) {
  884. goto NullExit;
  885. }
  886. goto SearchAgain;
  887. }
  888. /*
  889. * We've chosen an entry to reuse: now fill it in and recompute it.
  890. */
  891. pdce = *ppdce;
  892. RecomputeEntry:
  893. /*
  894. * Any non-invalid entries that we reuse might still have some bounds
  895. * that need to be used to invalidate SPBs. Apply them here.
  896. */
  897. if (!(pdce->DCX_flags & DCX_INVALID))
  898. SpbCheckDce(pdce);
  899. /*
  900. * We want to compute only the matchable visrgn at first,
  901. * so we don't set up hrgnClip, or set the EXCLUDERGN or INTERSECTRGN
  902. * bits yet -- we'll deal with those later.
  903. */
  904. pdce->DCX_flags = DCX_flagsMatch | DCX_INUSE;
  905. #if DBG || defined(PRERELEASE)
  906. /*
  907. * We're about to select the visrgn into the DC, even though it's
  908. * not yet completely setup. Turn off the visrgn validation for now.
  909. * It will be turned on before this function returns.
  910. */
  911. GreValidateVisrgn(pdce->hdc, FALSE);
  912. #endif
  913. /*
  914. * Now recompute the visrgn (minus any hrgnClip shenanigans)
  915. */
  916. if (TestWF(pwndOrg, WEFPREDIRECTED)) {
  917. DCX_flagsMatch |= DCX_REDIRECTEDBITMAP;
  918. }
  919. hrgn = NULL;
  920. if (CalcVisRgn(&hrgn, pwndOrg, pwndClip, DCX_flagsMatch) == FALSE) {
  921. pdce->DCX_flags |= DCX_PWNDORGINVISIBLE;
  922. }
  923. pdce->pwndOrg = pwndOrg;
  924. pdce->pwndClip = pwndClip;
  925. pdce->hrgnClip = NULL; // Just in case...
  926. pdce->hrgnClipPublic = NULL;
  927. ResetOrg(hrgn, pdce, TRUE);
  928. if (hrgn == NULL) {
  929. fVisRgnError = TRUE;
  930. }
  931. /*
  932. * When we arrive here, pdce (and *ppdce) point to
  933. * a cache entry whose visrgn and origin are set up.
  934. * All that remains to be done is to deal with EXCLUDE/INTERSECTRGN
  935. */
  936. HaveComputedEntry:
  937. /*
  938. * If the window clipping flags have changed in the window
  939. * since the last time this dc was invalidated, then recompute
  940. * this dc entry.
  941. */
  942. if ((pdce->DCX_flags & DCX_MATCHMASK) != (DCX_flags & DCX_MATCHMASK))
  943. goto RecomputeEntry;
  944. /*
  945. * Let's check these assertions just in case...
  946. */
  947. UserAssert(pdce);
  948. UserAssert(*ppdce == pdce);
  949. UserAssert(pdce->DCX_flags & DCX_INUSE);
  950. UserAssert(!(pdce->DCX_flags & DCX_INVALID));
  951. UserAssert((pdce->DCX_flags & DCX_MATCHMASK) == (DCX_flags & DCX_MATCHMASK));
  952. /*
  953. * Move the dce to the head of the list so it's easy to find later.
  954. */
  955. if (pdce != gpDispInfo->pdceFirst) {
  956. *ppdce = pdce->pdceNext;
  957. pdce->pdceNext = gpDispInfo->pdceFirst;
  958. gpDispInfo->pdceFirst = pdce;
  959. }
  960. #if DBG || defined(PRERELEASE)
  961. /*
  962. * We're about to mess with the visrgn in this DC, even though it's
  963. * not yet completely setup. Turn off the visrgn validation for now.
  964. * It will be turned on before this function returns.
  965. */
  966. GreValidateVisrgn(pdce->hdc, FALSE);
  967. #endif
  968. /*
  969. * Time to deal with DCX_INTERSECTRGN or DCX_EXCLUDERGN.
  970. *
  971. * We handle these two bits specially, because cache entries
  972. * with these bits set cannot be reused with the bits set. This
  973. * is because the area described in hrgnClip would have to be
  974. * compared along with the bit, which is a pain, especially since
  975. * they'd never match very often anyhow.
  976. *
  977. * What we do instead is to save the visrgn of the window before
  978. * applying either of these two flags, which is then restored
  979. * at ReleaseCacheDC() time, along with the clearing of these bits.
  980. * This effectively converts a cache entry with either of these
  981. * bits set into a "normal" cache entry that can be matched.
  982. */
  983. if (DCX_flags & DCX_INTERSECTRGN) {
  984. if (hrgnClip != HRGN_FULL) {
  985. SetEmptyRgn(ghrgnGDC);
  986. /*
  987. * Save the visrgn for reuse on ReleaseDC().
  988. * (do this BEFORE we set hrgnClip & pdce->flag bit,
  989. * so that if a DCHook() callback occurs it recalculates
  990. * without hrgnClip)
  991. */
  992. UserAssertMsg0(!pdce->hrgnSavedVis,
  993. "Nested SaveVisRgn attempt in _GetDCEx");
  994. /*
  995. * get the current vis region into hrgnSavedVis. Temporarily
  996. * store a dummy one in the DC.
  997. */
  998. pdce->hrgnSavedVis = CreateEmptyRgn();
  999. GreSelectVisRgn(pdce->hdc,pdce->hrgnSavedVis, SVR_SWAP);
  1000. pdce->hrgnClip = hrgnClip;
  1001. if (DCX_flags & DCX_NODELETERGN)
  1002. pdce->DCX_flags |= DCX_NODELETERGN;
  1003. pdce->DCX_flags |= DCX_INTERSECTRGN;
  1004. if (hrgnClip == NULL) {
  1005. pdce->hrgnClipPublic = NULL;
  1006. } else {
  1007. IntersectRgn(ghrgnGDC, pdce->hrgnSavedVis, hrgnClip);
  1008. /*
  1009. * Make a copy of the hrgnClip and make it public
  1010. * so that we can use it in calculations in HungDraw.
  1011. */
  1012. pdce->hrgnClipPublic = CreateEmptyRgnPublic();
  1013. CopyRgn(pdce->hrgnClipPublic, hrgnClip);
  1014. }
  1015. /*
  1016. * Clear the SAVEDRGNINVALID bit, since we're just
  1017. * about to set it properly now. If the dce later
  1018. * gets invalidated, it'll set this bit so we know
  1019. * to recompute it when we restore the visrgn.
  1020. */
  1021. pdce->DCX_flags &= ~DCX_SAVEDRGNINVALID;
  1022. /*
  1023. * Select in the new region. we use the SWAP_REGION mode
  1024. * so that ghrgnGDC always has a valid rgn
  1025. */
  1026. GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_SWAP);
  1027. }
  1028. } else if (DCX_flags & DCX_EXCLUDERGN) {
  1029. if (hrgnClip != NULL) {
  1030. SetEmptyRgn(ghrgnGDC);
  1031. /*
  1032. * Save the visrgn for reuse on ReleaseDC().
  1033. * (do this BEFORE we set hrgnClip & pdce->flag bit,
  1034. * so that if a DCHook() callback occurs it recalculates
  1035. * without hrgnClip)
  1036. */
  1037. UserAssertMsg0(!pdce->hrgnSavedVis,
  1038. "Nested SaveVisRgn attempt in _GetDCEx");
  1039. /*
  1040. * get the current vis region into hrgnSavedVis. Temporarily
  1041. * store a dummy one in the DC.
  1042. */
  1043. pdce->hrgnSavedVis = CreateEmptyRgn();
  1044. GreSelectVisRgn(pdce->hdc,pdce->hrgnSavedVis, SVR_SWAP);
  1045. pdce->hrgnClip = hrgnClip;
  1046. if (DCX_flags & DCX_NODELETERGN)
  1047. pdce->DCX_flags |= DCX_NODELETERGN;
  1048. pdce->DCX_flags |= DCX_EXCLUDERGN;
  1049. if (hrgnClip == HRGN_FULL) {
  1050. pdce->hrgnClipPublic = HRGN_FULL;
  1051. } else {
  1052. SubtractRgn(ghrgnGDC, pdce->hrgnSavedVis, hrgnClip);
  1053. /*
  1054. * Make a copy of the hrgnClip and make it public
  1055. * so that we can use it in calculations in HungDraw.
  1056. */
  1057. pdce->hrgnClipPublic = CreateEmptyRgnPublic();
  1058. CopyRgn(pdce->hrgnClipPublic, hrgnClip);
  1059. }
  1060. /*
  1061. * Clear the SAVEDRGNINVALID bit, since we're just
  1062. * about to set it properly now. If the dce later
  1063. * gets invalidated, it'll set this bit so we know
  1064. * to recompute it when we restore the visrgn.
  1065. */
  1066. pdce->DCX_flags &= ~DCX_SAVEDRGNINVALID;
  1067. /*
  1068. * Select in the new region. we use the SWAP_REGION mode
  1069. * so that ghrgnGDC always has a valid rgn
  1070. */
  1071. GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_SWAP);
  1072. }
  1073. }
  1074. }
  1075. if (pdce->DCX_flags & DCX_REDIRECTED) {
  1076. UserAssert(pwndLayer != NULL);
  1077. UserAssert(hbmLayer != NULL);
  1078. UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbmLayer));
  1079. /*
  1080. * Enable bounds accumulation, so we know if there was any drawing
  1081. * done into that DC and the actual rect we need to update when
  1082. * this DC is released.
  1083. */
  1084. GreGetBounds(pdce->hdc, NULL, GGB_ENABLE_WINMGR);
  1085. /*
  1086. * In case the visrgn couldn't be allocated, clear it in the
  1087. * dc again, since we just selected a new surface.
  1088. */
  1089. if (fVisRgnError) {
  1090. GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD);
  1091. }
  1092. }
  1093. /*
  1094. * Whew! Set ownership and return the bloody DC.
  1095. * Only set ownership for cache dcs. Own dcs have already been owned.
  1096. * The reason why we don't want to set the ownership over again is
  1097. * because the console sets its owndcs to PUBLIC so gdisrv can use
  1098. * them without asserting. We don't want to set the ownership back
  1099. * again.
  1100. */
  1101. if (pdce->DCX_flags & DCX_CACHE) {
  1102. if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_CURRENT)) {
  1103. RIPMSG1(RIP_WARNING, "GetDCEx: SetDCOwner Failed %lX", pdce->hdc);
  1104. }
  1105. /*
  1106. * Decrement the Free DCE Count. This should always be >= 0,
  1107. * since we'll create a new dce if the cache is all in use.
  1108. */
  1109. DecrementFreeDCECount();
  1110. pdce->ptiOwner = PtiCurrent();
  1111. }
  1112. if (TestWF(pwnd, WEFLAYOUTRTL) && !(DCX_flags & DCX_NOMIRROR)) {
  1113. GreSetLayout(pdce->hdc, -1, LAYOUT_RTL);
  1114. }
  1115. #if DBG || defined(PRERELEASE)
  1116. GreValidateVisrgn(pdce->hdc, TRUE);
  1117. #endif
  1118. GreUnlockDisplay(gpDispInfo->hDev);
  1119. return pdce->hdc;
  1120. }
  1121. /***************************************************************************\
  1122. * ReleaseCacheDC
  1123. *
  1124. * Releases a DC from the cache.
  1125. *
  1126. * History:
  1127. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1128. * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry.
  1129. \***************************************************************************/
  1130. UINT ReleaseCacheDC(
  1131. HDC hdc,
  1132. BOOL fEndPaint)
  1133. {
  1134. PDCE pdce;
  1135. PDCE *ppdce;
  1136. for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) {
  1137. if (pdce->hdc == hdc) {
  1138. /*
  1139. * Check for redundant releases or release of an invalid entry
  1140. */
  1141. if ((pdce->DCX_flags & (DCX_DESTROYTHIS | DCX_INVALID | DCX_INUSE)) != DCX_INUSE)
  1142. return DCE_NORELEASE;
  1143. /*
  1144. * Lock the display since we may be playing with visrgns.
  1145. */
  1146. GreLockDisplay(gpDispInfo->hDev);
  1147. if (pdce->DCX_flags & DCX_REDIRECTED) {
  1148. UpdateRedirectedDC(pdce);
  1149. }
  1150. /*
  1151. * If this is a permanent DC, then don't reset its state.
  1152. */
  1153. if (pdce->DCX_flags & DCX_CACHE) {
  1154. /*
  1155. * Restore the DC state and mark the entry as not in use.
  1156. * Set owner back to server as well, since it's going back
  1157. * into the cache.
  1158. */
  1159. if (!(pdce->DCX_flags & DCX_NORESETATTRS)) {
  1160. /*
  1161. * If bSetupDC() failed, the DC is busy (ie. in-use
  1162. * by another thread), so don't release it.
  1163. */
  1164. if ( (!(GreCleanDC(hdc))) ||
  1165. (!(GreSetDCOwner(hdc, OBJECT_OWNER_NONE))) ) {
  1166. GreUnlockDisplay(gpDispInfo->hDev);
  1167. return DCE_NORELEASE;
  1168. }
  1169. } else if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_NONE)) {
  1170. GreUnlockDisplay(gpDispInfo->hDev);
  1171. return DCE_NORELEASE;
  1172. }
  1173. pdce->ptiOwner = NULL;
  1174. pdce->DCX_flags &= ~DCX_INUSE;
  1175. #if DBG || defined(PRERELEASE)
  1176. /*
  1177. * Turn off checked only surface validation for now, since
  1178. * we may select a different surface (screen) in this DC that
  1179. * may not correspond to the visrgn currently in the DC. When
  1180. * the DC is given out again, it will be revalidated.
  1181. */
  1182. GreValidateVisrgn(pdce->hdc, FALSE);
  1183. #endif
  1184. /*
  1185. * The DC is no longer in use, so unselect the redirection
  1186. * bitmap from it.
  1187. */
  1188. if (pdce->DCX_flags & DCX_REDIRECTED) {
  1189. UserVerify(GreSelectRedirectionBitmap(pdce->hdc, NULL));
  1190. }
  1191. /*
  1192. * Increment the Free DCE count. This holds the count
  1193. * of available DCEs. Check the threshold, and destroy
  1194. * the dce if it's above the mark.
  1195. */
  1196. IncrementFreeDCECount();
  1197. if (gnDCECount > DCE_SIZE_CACHETHRESHOLD) {
  1198. if (DestroyCacheDC(ppdce, pdce->hdc)) {
  1199. GreUnlockDisplay(gpDispInfo->hDev);
  1200. return DCE_FREED;
  1201. }
  1202. }
  1203. }
  1204. /*
  1205. * If we have an EXCLUDERGN or INTERSECTRGN cache entry,
  1206. * convert it back to a "normal" cache entry by restoring
  1207. * the visrgn and blowing away hrgnClip.
  1208. *
  1209. * Note that for non-DCX_CACHE DCs, we only do this if
  1210. * we're being called from EndPaint().
  1211. */
  1212. if ((pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) &&
  1213. ((pdce->DCX_flags & DCX_CACHE) || fEndPaint)) {
  1214. DeleteHrgnClip(pdce);
  1215. }
  1216. GreUnlockDisplay(gpDispInfo->hDev);
  1217. return DCE_RELEASED;
  1218. }
  1219. }
  1220. /*
  1221. * Yell if DC couldn't be found...
  1222. */
  1223. RIPERR1(ERROR_DC_NOT_FOUND, RIP_WARNING,
  1224. "Invalid device context (DC) handle passed to ReleaseCacheDC (0x%08lx)", hdc);
  1225. return DCE_NORELEASE;
  1226. }
  1227. /***************************************************************************\
  1228. * CreateCacheDC
  1229. *
  1230. * Creates a DCE and adds it to the cache.
  1231. *
  1232. * History:
  1233. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1234. * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry.
  1235. \***************************************************************************/
  1236. HDC CreateCacheDC(
  1237. PWND pwndOrg,
  1238. DWORD DCX_flags,
  1239. PMONITOR pMonitor
  1240. )
  1241. {
  1242. PDCE pdce;
  1243. HDC hdc;
  1244. HANDLE hDev;
  1245. if ((pdce = (PDCE)UserAllocPool(sizeof(DCE), TAG_DCE)) == NULL)
  1246. return NULL;
  1247. if (pMonitor == NULL) {
  1248. hDev = gpDispInfo->hDev;
  1249. } else {
  1250. hDev = pMonitor->hDev;
  1251. }
  1252. if ((hdc = GreCreateDisplayDC(hDev, DCTYPE_DIRECT, FALSE)) == NULL) {
  1253. UserFreePool(pdce);
  1254. return NULL;
  1255. }
  1256. /*
  1257. * Link this entry into the cache entry list.
  1258. */
  1259. pdce->pdceNext = gpDispInfo->pdceFirst;
  1260. gpDispInfo->pdceFirst = pdce;
  1261. pdce->hdc = hdc;
  1262. pdce->DCX_flags = DCX_flags;
  1263. pdce->pwndOrg = pwndOrg;
  1264. pdce->pwndClip = pwndOrg;
  1265. pdce->hrgnClip = NULL;
  1266. pdce->hrgnClipPublic = NULL;
  1267. pdce->hrgnSavedVis = NULL;
  1268. pdce->pMonitor = pMonitor;
  1269. /*
  1270. * Mark it as undeleteable so no application can delete it out of our
  1271. * cache!
  1272. */
  1273. GreMarkUndeletableDC(hdc);
  1274. if (DCX_flags & DCX_OWNDC) {
  1275. /*
  1276. * Set the ownership of owndcs immediately: that way console can set
  1277. * the owernship to PUBLIC when it calls GetDC so that both the input
  1278. * thread and the service threads can use the same owndc.
  1279. */
  1280. GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT);
  1281. pdce->ptiOwner = PtiCurrent();
  1282. } else {
  1283. /*
  1284. * Otherwise it is a cache dc... set its owner to none - nothing
  1285. * is using it - equivalent of "being in the cache" but unaccessible
  1286. * to other processes.
  1287. */
  1288. GreSetDCOwner(hdc, OBJECT_OWNER_NONE);
  1289. pdce->ptiOwner = NULL;
  1290. /*
  1291. * Increment the available-cacheDC count. Once this hits our
  1292. * threshold, then we can free-up some of the entries.
  1293. */
  1294. IncrementFreeDCECount();
  1295. }
  1296. /*
  1297. * If we're creating a permanent DC, then compute it now.
  1298. */
  1299. if (!(DCX_flags & DCX_CACHE)) {
  1300. /*
  1301. * Set up the class DC now...
  1302. */
  1303. if (TestCF(pwndOrg, CFCLASSDC))
  1304. pwndOrg->pcls->pdce = pdce;
  1305. /*
  1306. * Finish setting up DCE and force eventual visrgn calculation.
  1307. */
  1308. UserAssert(!(DCX_flags & DCX_WINDOW));
  1309. pdce->DCX_flags |= DCX_INUSE;
  1310. InvalidateDce(pdce);
  1311. }
  1312. /*
  1313. * If there are any spb's around then enable bounds accumulation.
  1314. */
  1315. if (AnySpbs())
  1316. GreGetBounds(pdce->hdc, NULL, DCB_ENABLE | DCB_SET | DCB_WINDOWMGR);
  1317. return pdce->hdc;
  1318. }
  1319. /***************************************************************************\
  1320. * WindowFromCacheDC
  1321. *
  1322. * Returns the window associated with a DC.
  1323. *
  1324. * History:
  1325. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1326. \***************************************************************************/
  1327. PWND WindowFromCacheDC(
  1328. HDC hdc)
  1329. {
  1330. PDCE pdce;
  1331. for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) {
  1332. if (pdce->hdc == hdc)
  1333. return (pdce->DCX_flags & DCX_DESTROYTHIS) ? NULL : pdce->pwndOrg;
  1334. }
  1335. return NULL;
  1336. }
  1337. /***************************************************************************\
  1338. * DelayedDestroyCacheDC
  1339. *
  1340. * Destroys DCE's which have been partially destroyed.
  1341. *
  1342. * History:
  1343. * 16-Jun-1992 DavidPe Created.
  1344. \***************************************************************************/
  1345. VOID DelayedDestroyCacheDC(VOID)
  1346. {
  1347. PDCE *ppdce;
  1348. PDCE pdce;
  1349. /*
  1350. * Zip through the cache looking for a DCX_DESTROYTHIS hdc.
  1351. */
  1352. for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) {
  1353. /*
  1354. * If we found a DCE on this thread that we tried to destroy
  1355. * earlier, try and destroy it again.
  1356. */
  1357. pdce = *ppdce;
  1358. if (pdce->DCX_flags & DCX_DESTROYTHIS)
  1359. DestroyCacheDC(ppdce, pdce->hdc);
  1360. /*
  1361. * Step to the next DC. If the DC was deleted, there
  1362. * is no need to calculate address of the next entry.
  1363. */
  1364. if (pdce == *ppdce)
  1365. ppdce = &pdce->pdceNext;
  1366. }
  1367. PpiCurrent()->W32PF_Flags &= ~W32PF_OWNDCCLEANUP;
  1368. }
  1369. /***************************************************************************\
  1370. * DestroyCacheDC
  1371. *
  1372. * Removes a DC from the cache, freeing all resources associated
  1373. * with it.
  1374. *
  1375. * History:
  1376. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1377. * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry.
  1378. \***************************************************************************/
  1379. BOOL DestroyCacheDC(
  1380. PDCE *ppdce,
  1381. HDC hdc)
  1382. {
  1383. PDCE pdce;
  1384. /*
  1385. * Zip through the cache looking for hdc.
  1386. */
  1387. if (ppdce == NULL) {
  1388. for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) {
  1389. if (pdce->hdc == hdc)
  1390. break;
  1391. }
  1392. }
  1393. if (ppdce == NULL)
  1394. return FALSE;
  1395. /*
  1396. * Set this here so we know this DCE is supposed to be deleted.
  1397. */
  1398. pdce = *ppdce;
  1399. pdce->DCX_flags |= DCX_DESTROYTHIS;
  1400. /*
  1401. * Free up the dce object and contents.
  1402. */
  1403. if (!(pdce->DCX_flags & DCX_NODELETERGN)) {
  1404. DeleteMaybeSpecialRgn(pdce->hrgnClip);
  1405. pdce->hrgnClip = NULL;
  1406. }
  1407. if (pdce->hrgnClipPublic != NULL) {
  1408. GreDeleteObject(pdce->hrgnClipPublic);
  1409. pdce->hrgnClipPublic = NULL;
  1410. }
  1411. if (pdce->hrgnSavedVis != NULL) {
  1412. GreDeleteObject(pdce->hrgnSavedVis);
  1413. pdce->hrgnSavedVis = NULL;
  1414. }
  1415. /*
  1416. * If GreSetDCOwner() or GreDeleteDC() fail, the
  1417. * DC is in-use by another thread. Set
  1418. * W32PF_OWNDCCLEANUP so we know to scan for and
  1419. * delete this DCE later.
  1420. */
  1421. if (!GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC)) {
  1422. PpiCurrent()->W32PF_Flags |= W32PF_OWNDCCLEANUP;
  1423. return FALSE;
  1424. }
  1425. #if DBG
  1426. GreMarkDeletableDC(hdc); // So GRE doesn't RIP.
  1427. #endif
  1428. if (!GreDeleteDC(hdc)) {
  1429. #if DBG
  1430. GreMarkUndeletableDC(hdc);
  1431. #endif
  1432. PpiCurrent()->W32PF_Flags |= W32PF_OWNDCCLEANUP;
  1433. return FALSE;
  1434. }
  1435. /*
  1436. * Decrement this dc-entry from the free-list count.
  1437. */
  1438. if (pdce->DCX_flags & DCX_CACHE) {
  1439. if (!(pdce->DCX_flags & DCX_INUSE)) {
  1440. DecrementFreeDCECount();
  1441. }
  1442. }
  1443. #if DBG
  1444. pdce->pwndOrg = NULL;
  1445. pdce->pwndClip = NULL;
  1446. #endif
  1447. /*
  1448. * Unlink the DCE from the list.
  1449. */
  1450. *ppdce = pdce->pdceNext;
  1451. UserFreePool(pdce);
  1452. return TRUE;
  1453. }
  1454. /***************************************************************************\
  1455. * InvalidateGDIWindows
  1456. *
  1457. * Recalculates the visrgn of all descendents of pwnd on behalf of GRE.
  1458. *
  1459. * History:
  1460. \***************************************************************************/
  1461. VOID InvalidateGDIWindows(
  1462. PWND pwnd)
  1463. {
  1464. PVOID pwo;
  1465. if (pwnd != NULL) {
  1466. if ((pwo = _GetProp(pwnd, PROP_WNDOBJ, TRUE)) != NULL) {
  1467. HRGN hrgnClient = NULL;
  1468. if (GreWindowInsteadOfClient(pwo)) {
  1469. /*
  1470. * Never clip children for WO_RGN_WINDOW so that NetMeeting
  1471. * gets the unioned window area:
  1472. */
  1473. CalcVisRgn(&hrgnClient,
  1474. pwnd,
  1475. pwnd,
  1476. DCX_WINDOW |
  1477. (TestWF(pwnd, WFCLIPSIBLINGS) ? DCX_CLIPSIBLINGS : 0));
  1478. } else {
  1479. CalcVisRgn(&hrgnClient,
  1480. pwnd,
  1481. pwnd,
  1482. DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
  1483. }
  1484. GreSetClientRgn(pwo, hrgnClient, &(pwnd->rcClient));
  1485. }
  1486. pwnd = pwnd->spwndChild;
  1487. while (pwnd != NULL) {
  1488. InvalidateGDIWindows(pwnd);
  1489. pwnd = pwnd->spwndNext;
  1490. }
  1491. }
  1492. }
  1493. /***************************************************************************\
  1494. * zzzInvalidateDCCache
  1495. *
  1496. * This function is called when the visrgn of a window is changing for
  1497. * some reason. It is responsible for ensuring that all of the cached
  1498. * visrgns in the DC cache that are affected by the visrgn change are
  1499. * invalidated.
  1500. *
  1501. * Operations that affect the visrgn of a window (i.e., things that better
  1502. * call this routine one way or another:)
  1503. *
  1504. * Hiding or showing self or parent
  1505. * Moving, sizing, or Z-order change of self or parent
  1506. * Minimizing or unminimizing self or parent
  1507. * Screen or paint locking of self or parent
  1508. * LockWindowUpdate of self or parent
  1509. *
  1510. * Invalidates any cache entries associated with pwnd and/or any children of
  1511. * pwnd by either recalcing them on the fly if they're in use, or causing
  1512. * them to be recalced later.
  1513. *
  1514. * History:
  1515. * 17-Jul-1991 DarrinM Ported from Win 3.1 sources.
  1516. \***************************************************************************/
  1517. BOOL zzzInvalidateDCCache(
  1518. PWND pwndInvalid,
  1519. DWORD flags)
  1520. {
  1521. PWND pwnd;
  1522. PDCE pdce;
  1523. PTHREADINFO ptiCurrent = PtiCurrent();
  1524. TL tlpwndInvalid;
  1525. FLONG fl;
  1526. /*
  1527. * Invalidation implies screen real estate is changing so we must
  1528. * jiggle the mouse, because a different window may be underneath
  1529. * the mouse, which needs to get a mouse move in order to change the
  1530. * mouse pointer.
  1531. *
  1532. * The check for the tracking is added for full-drag-windows. In doing
  1533. * full-drag, zzzBltValidBits() is called from setting the window-pos.
  1534. * This resulted in an extra-mousemove being queued from this routine.
  1535. * So, when we're tracking, don't queue a mousemove. This pointer is
  1536. * null when tracking is off, so it won't effect the normal case.
  1537. */
  1538. ThreadLockAlwaysWithPti(ptiCurrent, pwndInvalid, &tlpwndInvalid);
  1539. if (!(ptiCurrent->TIF_flags & TIF_MOVESIZETRACKING) &&
  1540. !(flags & IDC_NOMOUSE)) {
  1541. #ifdef REDIRECTION
  1542. if (!IsGlobalHooked(ptiCurrent, WHF_FROM_WH(WH_HITTEST)))
  1543. #endif // REDIRECTION
  1544. zzzSetFMouseMoved();
  1545. }
  1546. /*
  1547. * The visrgn of pwnd is changing. First see if a change to this
  1548. * visrgn will also affect other window's visrgns:
  1549. *
  1550. * 1) if parent is clipchildren, we need to invalidate parent
  1551. * 2) if clipsiblings, we need to invalidate our sibling's visrgns.
  1552. *
  1553. * We don't optimize the case where we're NOT clipsiblings, and our
  1554. * parent is clipchildren: very rare case.
  1555. * We also don't optimize the fact that a clipsiblings window visrgn
  1556. * change only affects the visrgns of windows BELOW it.
  1557. */
  1558. if (flags & IDC_DEFAULT) {
  1559. flags = 0;
  1560. if ((pwndInvalid->spwndParent != NULL) &&
  1561. (pwndInvalid != PWNDDESKTOP(pwndInvalid))) {
  1562. /*
  1563. * If the parent is a clip-children window, then
  1564. * a change to our visrgn will affect his visrgn, and
  1565. * possibly those of our siblings. So, invalidate starting
  1566. * from our parent. Note that we don't need to invalidate
  1567. * any window DCs associated with our parent.
  1568. */
  1569. if (TestWF(pwndInvalid->spwndParent, WFCLIPCHILDREN)) {
  1570. flags = IDC_CLIENTONLY;
  1571. pwndInvalid = pwndInvalid->spwndParent;
  1572. } else if (TestWF(pwndInvalid, WFCLIPSIBLINGS)) {
  1573. /*
  1574. * If we are clip-siblings, chances are that our siblings are
  1575. * too. A change to our visrgn might affect our siblings,
  1576. * so invalidate all of our siblings.
  1577. *
  1578. * NOTE! This code assumes that if pwndInvalid is NOT
  1579. * CLIPSIBLINGs, that either it does not overlap other
  1580. * CLIPSIBLINGs windows, or that none of the siblings are
  1581. * CLIPSIBLINGs. This is a reasonable assumption, because
  1582. * mixing CLIPSIBLINGs and non CLIPSIBLINGs windows that
  1583. * overlap is generally unpredictable anyhow.
  1584. */
  1585. flags = IDC_CHILDRENONLY;
  1586. pwndInvalid = pwndInvalid->spwndParent;
  1587. }
  1588. }
  1589. }
  1590. /*
  1591. * Go through the list of DCE's, looking for any that need to be
  1592. * invalidated or recalculated. Basically, any DCE that contains
  1593. * a window handle that is equal to pwndInvalid or a child of pwndInvalid
  1594. * needs to be invalidated.
  1595. */
  1596. for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) {
  1597. if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS))
  1598. continue;
  1599. /*
  1600. * HACK ALERT
  1601. *
  1602. * A minimized client DC must never exclude its children, even if
  1603. * its WS_CLIPCHILDREN bit is set. For CS_OWNDC windows we must
  1604. * update the flags of the DCE to reflect the change in window state
  1605. * when the visrgn is eventually recomputed.
  1606. */
  1607. if (!(pdce->DCX_flags & (DCX_CACHE | DCX_WINDOW))) {
  1608. if (TestWF(pdce->pwndOrg, WFCLIPCHILDREN))
  1609. pdce->DCX_flags |= DCX_CLIPCHILDREN;
  1610. if (TestWF(pdce->pwndOrg, WFMINIMIZED))
  1611. pdce->DCX_flags &= ~DCX_CLIPCHILDREN;
  1612. }
  1613. /*
  1614. * This code assumes that if pdce->pwndClip != pdce->pwndOrg,
  1615. * that pdce->pwndClip == pdce->pwndOrg->spwndParent. To ensure
  1616. * that both windows are visited, we start the walk upwards from
  1617. * the lower of the two, or pwndOrg.
  1618. *
  1619. * This can happen if someone gets a DCX_PARENTCLIP dc and then
  1620. * changes the parent.
  1621. */
  1622. #if DBG
  1623. if ((pdce->pwndClip != pdce->pwndOrg) &&
  1624. (pdce->pwndClip != pdce->pwndOrg->spwndParent)) {
  1625. RIPMSG1(RIP_WARNING, "HDC %lX clipped to wrong parent", pdce->hdc);
  1626. }
  1627. #endif
  1628. /*
  1629. * Walk upwards from pdce->pwndOrg, to see if we encounter
  1630. * pwndInvalid.
  1631. */
  1632. for (pwnd = pdce->pwndOrg; pwnd; pwnd = pwnd->spwndParent) {
  1633. if (pwnd == pwndInvalid) {
  1634. if (pwndInvalid == pdce->pwndOrg) {
  1635. /*
  1636. * Ignore DCEs for pwndInvalid if IDC_CHILDRENONLY.
  1637. */
  1638. if (flags & IDC_CHILDRENONLY)
  1639. break;
  1640. /*
  1641. * Ignore window DCEs for pwndInvalid if IDC_CLIENTONLY
  1642. */
  1643. if ((flags & IDC_CLIENTONLY) && (pdce->DCX_flags & DCX_WINDOW))
  1644. break;
  1645. }
  1646. InvalidateDce(pdce);
  1647. break;
  1648. }
  1649. }
  1650. }
  1651. /*
  1652. * Update WNDOBJs in gdi if they exist.
  1653. */
  1654. GreLockDisplay(gpDispInfo->hDev);
  1655. fl = (flags & IDC_MOVEBLT) ? GCR_DELAYFINALUPDATE : 0;
  1656. if (gcountPWO != 0) {
  1657. InvalidateGDIWindows(pwndInvalid);
  1658. fl |= GCR_WNDOBJEXISTS;
  1659. }
  1660. GreClientRgnUpdated(fl);
  1661. GreUpdateSpriteVisRgn(gpDispInfo->hDev);
  1662. GreUnlockDisplay(gpDispInfo->hDev);
  1663. ThreadUnlock(&tlpwndInvalid);
  1664. return TRUE;
  1665. }
  1666. /***************************************************************************\
  1667. * _WindowFromDC (API)
  1668. *
  1669. * Takes a dc, returns the window associated with it.
  1670. *
  1671. * History:
  1672. * 23-Jun-1991 ScottLu Created.
  1673. \***************************************************************************/
  1674. PWND _WindowFromDC(
  1675. HDC hdc)
  1676. {
  1677. PDCE pdce;
  1678. for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) {
  1679. if (!(pdce->DCX_flags & DCX_INUSE) || (pdce->DCX_flags & DCX_CREATEDC))
  1680. continue;
  1681. if (pdce->hdc == hdc)
  1682. return pdce->pwndOrg;
  1683. }
  1684. return NULL;
  1685. }
  1686. /***************************************************************************\
  1687. * FastWindowFromDC
  1688. *
  1689. * Returns the window associated with a DC, and puts it at the
  1690. * front of the list.
  1691. *
  1692. * History:
  1693. * 23-Jun-1991 ScottLu Created.
  1694. \***************************************************************************/
  1695. PWND FastWindowFromDC(
  1696. HDC hdc)
  1697. {
  1698. PDCE *ppdce;
  1699. PDCE pdceT;
  1700. if ((gpDispInfo->pdceFirst->hdc == hdc) &&
  1701. (gpDispInfo->pdceFirst->DCX_flags & DCX_INUSE)) {
  1702. return gpDispInfo->pdceFirst->pwndOrg;
  1703. }
  1704. for (ppdce = &gpDispInfo->pdceFirst; *ppdce; ppdce = &(*ppdce)->pdceNext) {
  1705. if (((*ppdce)->hdc == hdc) && ((*ppdce)->DCX_flags & DCX_INUSE)) {
  1706. /*
  1707. * Unlink/link to make it first.
  1708. */
  1709. pdceT = *ppdce;
  1710. *ppdce = pdceT->pdceNext;
  1711. pdceT->pdceNext = gpDispInfo->pdceFirst;
  1712. gpDispInfo->pdceFirst = pdceT;
  1713. return pdceT->pwndOrg;
  1714. }
  1715. }
  1716. return NULL;
  1717. }
  1718. /***************************************************************************\
  1719. * GetDCOrgOnScreen
  1720. *
  1721. * This function gets the DC origin of a window in screen coordinates. The
  1722. * DC origin is always in the surface coordinates. For screen DCs the
  1723. * surface is the screen, so their origin is already in the screen
  1724. * coordinates. For redirected DCs, GreGetDCOrg will return the origin
  1725. * of the DC in the redirected surface coordinates to which we will add
  1726. * the origin of the redirected window that the surface is backing.
  1727. *
  1728. * 11/25/1998 vadimg created
  1729. \***************************************************************************/
  1730. BOOL GetDCOrgOnScreen(HDC hdc, LPPOINT ppt)
  1731. {
  1732. if (GreGetDCOrg(hdc, ppt)) {
  1733. POINT ptScreen;
  1734. /*
  1735. * Get the origin of the redirected window in screen coordinates.
  1736. */
  1737. if (UserGetRedirectedWindowOrigin(hdc, &ptScreen)) {
  1738. ppt->x += ptScreen.x;
  1739. ppt->y += ptScreen.y;
  1740. return TRUE;
  1741. }
  1742. }
  1743. return FALSE;
  1744. }
  1745. /***************************************************************************\
  1746. * UserGetRedirectedWindowOrigin
  1747. *
  1748. * The DC origin is in the surface coordinates. For screen DCs, the surface
  1749. * is the screen and so their origin is in the screen coordinates. But for
  1750. * redirected DCs, the backing surface origin is the same as the window
  1751. * being redirected. This function retrieves the screen origin of a redirected
  1752. * window corresponding to a redirection DC. It returns FALSE if this isn't
  1753. * a valid DC or it's not a redirected DC.
  1754. *
  1755. * 11/18/1998 vadimg created
  1756. \***************************************************************************/
  1757. BOOL UserGetRedirectedWindowOrigin(HDC hdc, LPPOINT ppt)
  1758. {
  1759. PWND pwnd;
  1760. PDCE pdce;
  1761. if ((pdce = LookupDC(hdc)) == NULL)
  1762. return FALSE;
  1763. if (!(pdce->DCX_flags & DCX_REDIRECTED))
  1764. return FALSE;
  1765. pwnd = GetStyleWindow(pdce->pwndOrg, WEFPREDIRECTED);
  1766. ppt->x = pwnd->rcWindow.left;
  1767. ppt->y = pwnd->rcWindow.top;
  1768. return TRUE;
  1769. }
  1770. /***************************************************************************\
  1771. * LookupDC
  1772. *
  1773. * Validate a DC by returning a correspnding pdce.
  1774. *
  1775. * 11/12/1997 vadimg created
  1776. \***************************************************************************/
  1777. PDCE LookupDC(HDC hdc)
  1778. {
  1779. PDCE pdce;
  1780. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  1781. if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS))
  1782. continue;
  1783. if (pdce->hdc == hdc && pdce->pMonitor == NULL &&
  1784. (pdce->DCX_flags & DCX_INUSE)) {
  1785. return pdce;
  1786. }
  1787. }
  1788. return NULL;
  1789. }
  1790. /***************************************************************************\
  1791. * GetMonitorDC
  1792. *
  1793. * 11/06/97 vadimg ported from Memphis
  1794. \***************************************************************************/
  1795. #define DCX_LEAVEBITS (DCX_WINDOW | DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | \
  1796. DCX_PARENTCLIP | DCX_LOCKWINDOWUPDATE | DCX_NOCLIPCHILDREN | \
  1797. DCX_USESTYLE | DCX_EXCLUDEUPDATE | DCX_INTERSECTUPDATE | \
  1798. DCX_EXCLUDERGN | DCX_INTERSECTRGN)
  1799. HDC GetMonitorDC(PDCE pdceOrig, PMONITOR pMonitor)
  1800. {
  1801. PDCE pdce;
  1802. POINT pt;
  1803. RECT rc;
  1804. TryAgain:
  1805. for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
  1806. /*
  1807. * Find an available DC for this monitor.
  1808. */
  1809. if (pdce->DCX_flags & (DCX_INUSE | DCX_DESTROYTHIS))
  1810. continue;
  1811. if (pdce->pMonitor != pMonitor)
  1812. continue;
  1813. if (!(pdce->DCX_flags & DCX_INVALID))
  1814. SpbCheckDce(pdce);
  1815. /*
  1816. * Copy DC properties and style bits.
  1817. */
  1818. GreSetDCOwner(pdce->hdc, OBJECT_OWNER_CURRENT);
  1819. pdce->pwndOrg = pdceOrig->pwndOrg;
  1820. pdce->pwndClip = pdceOrig->pwndClip;
  1821. pdce->ptiOwner = pdceOrig->ptiOwner;
  1822. pdce->DCX_flags = (DCX_INUSE | DCX_CACHE) |
  1823. (pdceOrig->DCX_flags & DCX_LEAVEBITS);
  1824. if (pdceOrig->hrgnClip > HRGN_FULL) {
  1825. UserAssert(pdce->hrgnClip == NULL);
  1826. UserAssert(pdceOrig->DCX_flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN));
  1827. pdce->hrgnClip = CreateEmptyRgn();
  1828. SetMonitorRegion(pMonitor, pdce->hrgnClip, pdceOrig->hrgnClip);
  1829. } else {
  1830. pdce->hrgnClip = pdceOrig->hrgnClip;
  1831. }
  1832. /*
  1833. * Setup the visrgn clipped to this monitor.
  1834. */
  1835. GreCopyVisRgn(pdceOrig->hdc, ghrgnGDC);
  1836. SetMonitorRegion(pMonitor, ghrgnGDC, ghrgnGDC);
  1837. GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_COPYNEW);
  1838. GreGetDCOrgEx(pdceOrig->hdc, &pt, &rc);
  1839. OffsetRect(&rc, -pMonitor->rcMonitor.left, -pMonitor->rcMonitor.top);
  1840. GreSetDCOrg(pdce->hdc, rc.left, rc.top, (PRECTL)&rc);
  1841. /*
  1842. * Decrement the Free DCE Count. This should always be >= 0,
  1843. * since we'll create a new dce if the cache is all in use.
  1844. */
  1845. DecrementFreeDCECount();
  1846. return pdce->hdc;
  1847. }
  1848. /*
  1849. * If this call succeeds a new DC will be available in the cache,
  1850. * so the loop will find it and properly set it up.
  1851. */
  1852. if (CreateCacheDC(NULL, DCX_INVALID | DCX_CACHE, pMonitor) == NULL)
  1853. return NULL;
  1854. goto TryAgain;
  1855. }
  1856. /***************************************************************************\
  1857. * OrderRects
  1858. *
  1859. * Order the rectangles, so that they flow from left to right. This is needed
  1860. * when combining a mirrored region (see MirrorRegion)
  1861. *
  1862. *
  1863. * History:
  1864. \***************************************************************************/
  1865. VOID OrderRects(
  1866. LPRECT lpR,
  1867. int nRects)
  1868. {
  1869. RECT R;
  1870. int i, j;
  1871. //
  1872. // Sort Left to right
  1873. //
  1874. for (i = 0; i < nRects; i++) {
  1875. for (j = i + 1; j < nRects && (lpR + j)->top == (lpR + i)->top; j++) {
  1876. if ((lpR + j)->left < (lpR + i)->left) {
  1877. R = *(lpR + i);
  1878. *(lpR + i) = *(lpR + j);
  1879. *(lpR + j) = R;
  1880. }
  1881. }
  1882. }
  1883. }
  1884. /***************************************************************************\
  1885. * MirrorRegion
  1886. *
  1887. * Mirror a region in a window. This is done by mirroring the rects that
  1888. * constitute the region. 'bUseClient' param controls whether the region is a
  1889. * client one or not.
  1890. *
  1891. * History:
  1892. \***************************************************************************/
  1893. BOOL MirrorRegion(
  1894. PWND pwnd,
  1895. HRGN hrgn,
  1896. BOOL bUseClient)
  1897. {
  1898. int nRects, i, nDataSize, Saveleft, cx;
  1899. HRGN hrgn2 = NULL;
  1900. RECT *lpR;
  1901. RGNDATA *lpRgnData;
  1902. BOOL bRet = FALSE;
  1903. if (TestWF(pwnd, WEFLAYOUTRTL) && hrgn > HRGN_SPECIAL_LAST) {
  1904. nDataSize = GreGetRegionData(hrgn, 0, NULL);
  1905. if (nDataSize && (lpRgnData = (RGNDATA *)UserAllocPool(nDataSize, TAG_MIRROR))) {
  1906. if (GreGetRegionData(hrgn, nDataSize, lpRgnData)) {
  1907. nRects = lpRgnData->rdh.nCount;
  1908. lpR = (RECT *)lpRgnData->Buffer;
  1909. if (bUseClient) {
  1910. cx = pwnd->rcClient.right - pwnd->rcClient.left;
  1911. } else {
  1912. cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
  1913. }
  1914. Saveleft = lpRgnData->rdh.rcBound.left;
  1915. lpRgnData->rdh.rcBound.left = cx - lpRgnData->rdh.rcBound.right;
  1916. lpRgnData->rdh.rcBound.right = cx - Saveleft;
  1917. for (i = 0; i<nRects; i++){
  1918. Saveleft = lpR->left;
  1919. lpR->left = cx - lpR->right;
  1920. lpR->right = cx - Saveleft;
  1921. lpR++;
  1922. }
  1923. OrderRects((RECT *)lpRgnData->Buffer, nRects);
  1924. hrgn2 = GreExtCreateRegion(NULL, nDataSize, lpRgnData);
  1925. if (hrgn2) {
  1926. GreCombineRgn(hrgn, hrgn2, NULL, RGN_COPY);
  1927. GreDeleteObject((HGDIOBJ)hrgn2);
  1928. bRet = TRUE;
  1929. }
  1930. }
  1931. UserFreePool(lpRgnData);
  1932. }
  1933. }
  1934. return bRet;
  1935. }