dc.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 73k
Category:

Windows Develop

Development Platform:

Visual C++

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