Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

dc.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: dc.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module contains User's DC APIs and related functions. 00007 * 00008 * History: 00009 * 23-Oct-1990 DarrinM Created. 00010 * 07-Feb-1991 MikeKe Added Revalidation code (None). 00011 * 17-Jul-1991 DarrinM Recreated from Win 3.1 source. 00012 * 21-Jan-1992 IanJa ANSI/Unicode neutral (null op). 00013 \***************************************************************************/ 00014 00015 #include "precomp.h" 00016 #pragma hdrstop 00017 00018 /* 00019 * DBG Related Information. 00020 */ 00021 #if DBG 00022 BOOL fDisableCache; // TRUE to disable DC cache. 00023 #endif 00024 00025 /***************************************************************************\ 00026 * DecrementFreeDCECount 00027 * 00028 \***************************************************************************/ 00029 00030 __inline VOID DecrementFreeDCECount(VOID) 00031 { 00032 gnDCECount--; 00033 UserAssert(gnDCECount >= 0); 00034 } 00035 00036 /***************************************************************************\ 00037 * IncrementFreeDCECount 00038 * 00039 \***************************************************************************/ 00040 00041 __inline VOID IncrementFreeDCECount(VOID) 00042 { 00043 gnDCECount++; 00044 UserAssert(gnDCECount >= 0); 00045 } 00046 00047 /***************************************************************************\ 00048 * SetMonitorRegion 00049 * 00050 * The region is in meta dc coordinates, so convert to monitor coords. 00051 \***************************************************************************/ 00052 00053 void SetMonitorRegion(PMONITOR pMonitor, HRGN hrgnDst, HRGN hrgnSrc) 00054 { 00055 if (IntersectRgn(hrgnDst, hrgnSrc, pMonitor->hrgnMonitor) == ERROR) { 00056 GreSetRectRgn(hrgnDst, 0, 0, 0, 0); 00057 return; 00058 } 00059 00060 GreOffsetRgn(hrgnDst, -pMonitor->rcMonitor.left, -pMonitor->rcMonitor.top); 00061 } 00062 00063 /***************************************************************************\ 00064 * ResetOrg 00065 * 00066 * Resets the origin of the DC associated with *pdce, and selects 00067 * a new visrgn. 00068 * 00069 * History: 00070 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00071 \***************************************************************************/ 00072 00073 VOID ResetOrg( 00074 HRGN hrgn, 00075 PDCE pdce, 00076 BOOL fSetVisRgn) 00077 { 00078 RECT rc; 00079 PWND pwndLayer; 00080 00081 /* 00082 * For compatibility purposes, make sure that the DC's for the 00083 * desktop windows originate at the primary monitor, i.e. (0,0). 00084 */ 00085 if (GETFNID(pdce->pwndOrg) == FNID_DESKTOP) { 00086 rc.left = rc.top = 0; 00087 rc.right = SYSMET(CXVIRTUALSCREEN); 00088 rc.bottom = SYSMET(CYVIRTUALSCREEN); 00089 } else if (pdce->DCX_flags & DCX_WINDOW) { 00090 rc = pdce->pwndOrg->rcWindow; 00091 } else { 00092 rc = pdce->pwndOrg->rcClient; 00093 } 00094 00095 if (pdce->pMonitor != NULL) { 00096 OffsetRect(&rc, -pdce->pMonitor->rcMonitor.left, 00097 -pdce->pMonitor->rcMonitor.top); 00098 00099 if (hrgn != NULL) { 00100 SetMonitorRegion(pdce->pMonitor, hrgn, hrgn); 00101 } 00102 } 00103 00104 if ((pwndLayer = GetLayeredWindow(pdce->pwndOrg)) != NULL) { 00105 if (pdce->DCX_flags & DCX_LAYERED) { 00106 int x = pwndLayer->rcWindow.left; 00107 int y = pwndLayer->rcWindow.top; 00108 00109 /* 00110 * For layered redirection DCs, the surface origin is the 00111 * window origin, so offset both the rectangle and the 00112 * region appropriately. 00113 */ 00114 OffsetRect(&rc, -x, -y); 00115 if (hrgn != NULL) { 00116 GreOffsetRgn(hrgn, -x, -y); 00117 } 00118 } else { 00119 /* 00120 * Layered windows can only draw to the screen via the redirection 00121 * DCs or UpdateLayeredWindow, so select an empty visrgn into this 00122 * screen DC. 00123 */ 00124 if (hrgn != NULL) { 00125 GreSetRectRgn(hrgn, 0, 0, 0, 0); 00126 } 00127 } 00128 } else { 00129 UserAssert(!(pdce->DCX_flags & DCX_LAYERED)); 00130 } 00131 00132 GreSetDCOrg(pdce->hdc, rc.left, rc.top, (PRECTL)&rc); 00133 00134 if (fSetVisRgn) { 00135 GreSelectVisRgn(pdce->hdc, hrgn, SVR_DELETEOLD); 00136 } 00137 } 00138 00139 /***************************************************************************\ 00140 * GetDC (API) 00141 * 00142 * Standard call to GetDC(). 00143 * 00144 * History: 00145 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00146 \***************************************************************************/ 00147 00148 HDC _GetDC( 00149 PWND pwnd) 00150 { 00151 /* 00152 * Special case for NULL: For backward compatibility we want to return 00153 * a window DC for the desktop that does not exclude its children. 00154 */ 00155 if (pwnd == NULL) { 00156 00157 PDESKTOP pdesk = PtiCurrent()->rpdesk; 00158 00159 if (pdesk) { 00160 return _GetDCEx(pdesk->pDeskInfo->spwnd, 00161 NULL, 00162 DCX_WINDOW | DCX_CACHE); 00163 } 00164 00165 /* 00166 * The thread has no desktop. Fail the call. 00167 */ 00168 return NULL; 00169 } 00170 00171 return _GetDCEx(pwnd, NULL, DCX_USESTYLE); 00172 } 00173 00174 /***************************************************************************\ 00175 * _ReleaseDC (API) 00176 * 00177 * Release the DC retrieved from GetDC(). 00178 * 00179 * History: 00180 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00181 \***************************************************************************/ 00182 00183 BOOL _ReleaseDC( 00184 HDC hdc) 00185 { 00186 CheckCritIn(); 00187 00188 return (ReleaseCacheDC(hdc, FALSE) == DCE_NORELEASE ? FALSE : TRUE); 00189 } 00190 00191 /***************************************************************************\ 00192 * _GetWindowDC (API) 00193 * 00194 * Retrive a DC for the window. 00195 * 00196 * History: 00197 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00198 * 25-Jan-1996 ChrisWil Allow rgnClip so that WM_NCACTIVATE can clip. 00199 \***************************************************************************/ 00200 00201 HDC _GetWindowDC( 00202 PWND pwnd) 00203 { 00204 00205 #if 0 00206 00207 /* 00208 * For WIN31 and previous apps, we want to actually return back a 00209 * client DC. Before WIN40, the window rect and client rect were the 00210 * same, and there was this terrible hack to grab the window dc when 00211 * painting because window DCs never clip anything. Otherwise the 00212 * children of the minimized window would be clipped out of the fake 00213 * client area. So apps would call GetWindowDC() to redraw their icons, 00214 * since GetDC() would clip empty if the window had a class icon. 00215 */ 00216 if (TestWF(pwnd, WFMINIMIZED) && !TestWF(pwnd, WFWIN40COMPAT)) 00217 return(_GetDCEx(pwnd, hrgnClip, DCX_INTERNAL | DCX_CACHE | DCX_USESTYLE)); 00218 #endif 00219 00220 return _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE); 00221 } 00222 00223 /***************************************************************************\ 00224 * UserSetDCVisRgn 00225 * 00226 * Set the visrgn for the DCE. If the window has a (hrgnClipPublic), we use 00227 * that instead of the (hrgnClip) since it's a public-object. The other is 00228 * created and owned by the user-thread and can't be used if say we're in the 00229 * hung-app-drawing (different process). Both regions should be equalent in 00230 * data. 00231 * 00232 * History: 00233 * 10-Nov-1992 DavidPe Created. 00234 * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry. 00235 \***************************************************************************/ 00236 00237 VOID UserSetDCVisRgn( 00238 PDCE pdce) 00239 { 00240 HRGN hrgn = NULL; 00241 00242 /* 00243 * If the visrgn calculated is empt, set the flag DCX_PWNDORGINVISIBLE, 00244 * otherwise clear it (it could've been set earlier on). 00245 */ 00246 if (!CalcVisRgn(&hrgn, pdce->pwndOrg, pdce->pwndClip, pdce->DCX_flags)) { 00247 pdce->DCX_flags |= DCX_PWNDORGINVISIBLE; 00248 } else { 00249 pdce->DCX_flags &= ~DCX_PWNDORGINVISIBLE; 00250 } 00251 00252 /* 00253 * Deal with INTERSECTRGN and EXCLUDERGN. 00254 */ 00255 if (pdce->DCX_flags & DCX_INTERSECTRGN) { 00256 00257 UserAssert(pdce->hrgnClipPublic != HRGN_FULL); 00258 00259 if (pdce->hrgnClipPublic == NULL) { 00260 SetEmptyRgn(hrgn); 00261 } else { 00262 IntersectRgn(hrgn, hrgn, pdce->hrgnClipPublic); 00263 } 00264 00265 } else if (pdce->DCX_flags & DCX_EXCLUDERGN) { 00266 00267 UserAssert(pdce->hrgnClipPublic != NULL); 00268 00269 if (pdce->hrgnClipPublic == HRGN_FULL) { 00270 SetEmptyRgn(hrgn); 00271 } else { 00272 SubtractRgn(hrgn, hrgn, pdce->hrgnClipPublic); 00273 } 00274 } 00275 00276 ResetOrg(hrgn, pdce, TRUE); 00277 } 00278 00279 /***************************************************************************\ 00280 * UserGetClientRgn 00281 * 00282 * Return a copy of the client region and rectangle for the given hwnd. 00283 * 00284 * The caller must enter the user critical section before calling this function. 00285 * 00286 * History: 00287 * 27-Sep-1993 WendyWu Created. 00288 \***************************************************************************/ 00289 00290 HRGN UserGetClientRgn( 00291 HWND hwnd, 00292 LPRECT lprc, 00293 BOOL bWindowInsteadOfClient) 00294 { 00295 HRGN hrgnClient = (HRGN)NULL; 00296 PWND pwnd; 00297 00298 /* 00299 * Must be in critical section. 00300 */ 00301 CheckCritIn(); 00302 00303 if (pwnd = ValidateHwnd(hwnd)) { 00304 00305 if (bWindowInsteadOfClient) { 00306 00307 /* 00308 * Never clip children for WO_RGN_WINDOW so that NetMeeting 00309 * gets the unioned window area: 00310 */ 00311 00312 CalcVisRgn(&hrgnClient, 00313 pwnd, 00314 pwnd, 00315 DCX_WINDOW | 00316 (TestWF(pwnd, WFCLIPSIBLINGS) ? DCX_CLIPSIBLINGS : 0)); 00317 } else { 00318 CalcVisRgn(&hrgnClient, 00319 pwnd, 00320 pwnd, 00321 DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS); 00322 } 00323 00324 *lprc = pwnd->rcClient; 00325 } 00326 00327 return hrgnClient; 00328 } 00329 00330 /***************************************************************************\ 00331 * UserGetHwnd 00332 * 00333 * Return a hwnd and the associated pwo for the given display hdc. 00334 * 00335 * It returns FALSE if no hwnd corresponds to the hdc is found or if the 00336 * hwnd has incorrect styles for a device format window. 00337 * 00338 * The caller must enter the user critical section before calling this function. 00339 * 00340 * History: 00341 * 27-Sep-1993 WendyWu Created. 00342 \***************************************************************************/ 00343 00344 BOOL UserGetHwnd( 00345 HDC hdc, 00346 HWND *phwnd, 00347 PVOID *ppwo, 00348 BOOL bCheckStyle) 00349 { 00350 PWND pwnd; 00351 PDCE pdce; 00352 00353 /* 00354 * Must be in critical section. 00355 */ 00356 CheckCritIn(); 00357 00358 /* 00359 * Find pdce and pwnd for this DC. 00360 * 00361 * Note: the SAMEHANDLE macro strips out the user defined bits in the 00362 * handle before doing the comparison. This is important because when 00363 * GRE calls this function, it may have lost track of the OWNDC bit. 00364 */ 00365 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 00366 00367 if (pdce->hdc == hdc) // this should be undone once SAMEHANDLE is fixed for kmode 00368 break; 00369 } 00370 00371 /* 00372 * Return FALSE If it is not in the pdce list. 00373 */ 00374 if ((pdce == NULL) || (pdce->pwndOrg == NULL)) 00375 return FALSE; 00376 00377 pwnd = pdce->pwndOrg; 00378 00379 /* 00380 * The window style must be clipchildren and clipsiblings. 00381 * the window's class must not be parentdc 00382 */ 00383 if (bCheckStyle) { 00384 00385 if ( !TestWF(pwnd, WFCLIPCHILDREN) || 00386 !TestWF(pwnd, WFCLIPSIBLINGS) || 00387 TestCF(pwnd, CFPARENTDC)) { 00388 00389 RIPMSG0(RIP_WARNING, "UserGetHwnd: Bad OpenGL window style or class"); 00390 return FALSE; 00391 } 00392 } 00393 00394 /* 00395 * Return the hwnd with the correct styles for a device format window. 00396 */ 00397 *phwnd = HW(pwnd); 00398 *ppwo = _GetProp(pwnd, PROP_WNDOBJ, TRUE); 00399 00400 return TRUE; 00401 } 00402 00403 /***************************************************************************\ 00404 * UserAssociateHwnd 00405 * 00406 * Associate a gdi WNDOBJ with hwnd. The caller must enter the user 00407 * critical section before calling this function. 00408 * 00409 * If 'pwo' is NULL, the association is removed. 00410 * 00411 * History: 00412 * 13-Jan-1994 HockL Created. 00413 \***************************************************************************/ 00414 00415 VOID UserAssociateHwnd( 00416 HWND hwnd, 00417 PVOID pwo) 00418 { 00419 PWND pwnd; 00420 00421 /* 00422 * Must be in critical section. 00423 */ 00424 CheckCritIn(); 00425 00426 if (pwnd = ValidateHwnd(hwnd)) { 00427 00428 if (pwo != NULL) { 00429 if (InternalSetProp(pwnd, PROP_WNDOBJ, pwo, PROPF_INTERNAL | PROPF_NOPOOL)) 00430 gcountPWO++; 00431 } else { 00432 if (InternalRemoveProp(pwnd, PROP_WNDOBJ, TRUE)) 00433 gcountPWO--; 00434 } 00435 } 00436 } 00437 00438 /***************************************************************************\ 00439 * UserReleaseDC 00440 * 00441 * Enter's the critical section and calls _ReleaseDC. 00442 * 00443 * History: 00444 * 25-Jan-1996 ChrisWil Created comment block. 00445 \***************************************************************************/ 00446 00447 BOOL UserReleaseDC( 00448 HDC hdc) 00449 { 00450 BOOL b; 00451 00452 EnterCrit(); 00453 b = _ReleaseDC(hdc); 00454 LeaveCrit(); 00455 00456 return b; 00457 } 00458 00459 /***************************************************************************\ 00460 * InvalidateDce 00461 * 00462 * If the DCE is not in use, removes all information and marks it invalid. 00463 * Otherwise, it resets the DCE flags based on the window styles and 00464 * recalculates the vis rgn. 00465 * 00466 * History: 00467 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00468 \***************************************************************************/ 00469 00470 VOID InvalidateDce( 00471 PDCE pdce) 00472 { 00473 GreLockDisplay(gpDispInfo->hDev); 00474 00475 if (!(pdce->DCX_flags & DCX_INUSE)) { 00476 00477 /* 00478 * Accumulate any bounds for this CE 00479 * since we're about to mark it invalid. 00480 */ 00481 SpbCheckDce(pdce); 00482 00483 MarkDCEInvalid(pdce); 00484 00485 pdce->pwndOrg = NULL; 00486 pdce->pwndClip = NULL; 00487 pdce->hrgnClip = NULL; 00488 pdce->hrgnClipPublic = NULL; 00489 00490 /* 00491 * Remove the vis rgn since it is still owned - if we did not, 00492 * gdi would not be able to clean up properly if the app that 00493 * owns this vis rgn exist while the vis rgn is still selected. 00494 */ 00495 GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD); 00496 00497 } else { 00498 00499 PWND pwndOrg = pdce->pwndOrg; 00500 PWND pwndClip = pdce->pwndClip; 00501 00502 /* 00503 * In case the window's clipping style bits changed, 00504 * reset the DCE flags from the window style bits. 00505 * Note that minimized windows never exclude their children. 00506 */ 00507 pdce->DCX_flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS); 00508 00509 /* 00510 * Chicago stuff... 00511 */ 00512 if (TestCF(pwndOrg, CFPARENTDC) && 00513 (TestWF(pwndOrg, WFWIN31COMPAT) || !TestWF(pwndClip, WFCLIPCHILDREN)) && 00514 (TestWF(pwndOrg, WFVISIBLE) == TestWF(pwndClip, WFVISIBLE))) { 00515 00516 if (TestWF(pwndClip, WFCLIPSIBLINGS)) 00517 pdce->DCX_flags |= DCX_CLIPSIBLINGS; 00518 00519 } else { 00520 00521 if (TestWF(pwndOrg, WFCLIPCHILDREN) && !TestWF(pwndOrg, WFMINIMIZED)) 00522 pdce->DCX_flags |= DCX_CLIPCHILDREN; 00523 00524 if (TestWF(pwndOrg, WFCLIPSIBLINGS)) 00525 pdce->DCX_flags |= DCX_CLIPSIBLINGS; 00526 } 00527 00528 /* 00529 * Mark that any saved visrgn needs to be recomputed. 00530 */ 00531 pdce->DCX_flags |= DCX_SAVEDRGNINVALID; 00532 00533 UserSetDCVisRgn(pdce); 00534 } 00535 00536 GreUnlockDisplay(gpDispInfo->hDev); 00537 } 00538 00539 /***************************************************************************\ 00540 * DeleteHrgnClip 00541 * 00542 * Deletes the clipping regions in the DCE, restores the saved visrgn, 00543 * and invalidates the DCE if saved visrgn is invalid. 00544 * 00545 * History: 00546 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00547 \***************************************************************************/ 00548 00549 VOID DeleteHrgnClip( 00550 PDCE pdce) 00551 { 00552 /* 00553 * Clear these flags first in case we get a DCHook() callback... 00554 */ 00555 pdce->DCX_flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); 00556 00557 /* 00558 * Blow away pdce->hrgnClip and clear the associated flags. 00559 * Do not delete hrgnClip if DCX_NODELETERGN is set! 00560 */ 00561 if (!(pdce->DCX_flags & DCX_NODELETERGN)) { 00562 DeleteMaybeSpecialRgn(pdce->hrgnClip); 00563 } else { 00564 pdce->DCX_flags &= ~DCX_NODELETERGN; 00565 } 00566 00567 DeleteMaybeSpecialRgn(pdce->hrgnClipPublic); 00568 00569 pdce->hrgnClip = NULL; 00570 pdce->hrgnClipPublic = NULL; 00571 00572 /* 00573 * If the saved visrgn was invalidated by an InvalidateDce() 00574 * while we had it checked out, then invalidate the entry now. 00575 */ 00576 if (pdce->DCX_flags & DCX_SAVEDRGNINVALID) { 00577 InvalidateDce(pdce); 00578 00579 /* 00580 * We've just gone through InvalidateDce, so the visrgn in the 00581 * DC has been properly reset. Simply nuke the old saved visrgn. 00582 */ 00583 if (pdce->hrgnSavedVis != NULL) { 00584 GreDeleteObject(pdce->hrgnSavedVis); 00585 pdce->hrgnSavedVis = NULL; 00586 } 00587 } else { 00588 /* 00589 * The saved visrgn is still valid, select it back into the 00590 * DC so the entry may be re-used without recomputing. 00591 */ 00592 if (pdce->hrgnSavedVis != NULL) { 00593 GreSelectVisRgn(pdce->hdc, pdce->hrgnSavedVis, SVR_DELETEOLD); 00594 pdce->hrgnSavedVis = NULL; 00595 } 00596 } 00597 } 00598 00599 /***************************************************************************\ 00600 * GetDCEx (API) 00601 * 00602 * 00603 * History: 00604 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 00605 * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry. 00606 \***************************************************************************/ 00607 00608 HDC _GetDCEx( 00609 PWND pwnd, 00610 HRGN hrgnClip, 00611 DWORD DCX_flags) 00612 { 00613 HRGN hrgn; 00614 HDC hdcMatch; 00615 PWND pwndClip; 00616 PWND pwndOrg; 00617 PDCE pdce; 00618 PDCE *ppdce; 00619 PDCE *ppdceNotInUse; 00620 DWORD DCX_flagsMatch; 00621 BOOL bpwndOrgVisible; 00622 PWND pwndLayer; 00623 HBITMAP hbmLayer; 00624 BOOL fVisRgnError = FALSE; 00625 00626 /* 00627 * Lock the device while we're playing with visrgns. 00628 */ 00629 GreLockDisplay(gpDispInfo->hDev); 00630 00631 if (pwnd == NULL) 00632 pwnd = PtiCurrent()->rpdesk->pDeskInfo->spwnd; 00633 00634 hdcMatch = NULL; 00635 pwndOrg = pwndClip = pwnd; 00636 00637 bpwndOrgVisible = IsVisible(pwndOrg); 00638 00639 if (PpiCurrent()->W32PF_Flags & W32PF_OWNDCCLEANUP) { 00640 DelayedDestroyCacheDC(); 00641 } 00642 00643 /* 00644 * If necessary, compute DCX flags from window style. 00645 */ 00646 if (DCX_flags & DCX_USESTYLE) { 00647 00648 DCX_flags &= ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_PARENTCLIP); 00649 00650 if (!(DCX_flags & DCX_WINDOW)) { 00651 00652 if (TestCF(pwndOrg, CFPARENTDC)) 00653 DCX_flags |= DCX_PARENTCLIP; 00654 00655 /* 00656 * If the DCX_CACHE flag is present, override OWNDC/CLASSDC. 00657 * Otherwise, calculate from appropriate style bits. 00658 */ 00659 if (!(DCX_flags & DCX_CACHE) && !TestCF(pwndOrg, CFOWNDC)) { 00660 if (TestCF(pwndOrg, CFCLASSDC)) { 00661 /* 00662 * Look for a non-cache entry that matches hdc... 00663 */ 00664 if (pwndOrg->pcls->pdce != NULL) { 00665 hdcMatch = pwndOrg->pcls->pdce->hdc; 00666 } 00667 } else { 00668 DCX_flags |= DCX_CACHE; 00669 } 00670 } 00671 00672 if (TestWF(pwndOrg, WFCLIPCHILDREN)) 00673 DCX_flags |= DCX_CLIPCHILDREN; 00674 00675 if (TestWF(pwndOrg, WFCLIPSIBLINGS)) 00676 DCX_flags |= DCX_CLIPSIBLINGS; 00677 00678 /* 00679 * Minimized windows never exclude their children. 00680 */ 00681 if (TestWF(pwndOrg, WFMINIMIZED)) { 00682 DCX_flags &= ~DCX_CLIPCHILDREN; 00683 00684 if (pwndOrg->pcls->spicn) 00685 DCX_flags |= DCX_CACHE; 00686 } 00687 00688 } else { 00689 if (TestWF(pwndClip, WFCLIPSIBLINGS)) 00690 DCX_flags |= DCX_CLIPSIBLINGS; 00691 00692 DCX_flags |= DCX_CACHE; 00693 00694 /* 00695 * Window DCs never exclude children. 00696 */ 00697 } 00698 } 00699 00700 /* 00701 * Deal with all the Win 3.0-compatible clipping rules: 00702 * 00703 * DCX_NOCLIPCHILDREN overrides: 00704 * DCX_PARENTCLIP/CS_OWNDC/CS_CLASSDC 00705 * DCX_PARENTCLIP overrides: 00706 * DCX_CLIPSIBLINGS/DCX_CLIPCHILDREN/CS_OWNDC/CS_CLASSDC 00707 */ 00708 if (DCX_flags & DCX_NOCLIPCHILDREN) { 00709 DCX_flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN); 00710 DCX_flags |= DCX_CACHE; 00711 } 00712 00713 /* 00714 * Deal with layered windows. 00715 */ 00716 if ((pwndLayer = GetLayeredWindow(pwndOrg)) != NULL && 00717 (hbmLayer = _GetProp(pwndLayer, PROP_LAYER, TRUE)) != NULL) { 00718 00719 /* 00720 * Get a layered redirection DC. 00721 */ 00722 DCX_flags |= DCX_LAYERED; 00723 00724 /* 00725 * When the window we're getting the DC for is the layered and 00726 * redirected window, don't allow to clip to its parent, since 00727 * clipping must not exceed the size of the backing bitmap. 00728 */ 00729 if (pwndOrg == pwndLayer) { 00730 DCX_flags &= ~DCX_PARENTCLIP; 00731 } 00732 00733 /* 00734 * Convert hrgnClip from screen to the redirection DC coordinates. 00735 */ 00736 if (hrgnClip > HRGN_SPECIAL_LAST) { 00737 GreOffsetRgn(hrgnClip, -pwndLayer->rcWindow.left, 00738 -pwndLayer->rcWindow.top); 00739 } 00740 } else { 00741 pwndLayer = NULL; 00742 hbmLayer = NULL; 00743 } 00744 00745 if (DCX_flags & DCX_PARENTCLIP) { 00746 00747 PWND pwndParent; 00748 00749 /* 00750 * If this window has no parent. This can occur if the app is 00751 * calling GetDC in response to a CBT_CREATEWND callback. In this 00752 * case, the parent is not yet setup. 00753 */ 00754 if (pwndOrg->spwndParent == NULL) 00755 pwndParent = PtiCurrent()->rpdesk->pDeskInfo->spwnd; 00756 else 00757 pwndParent = pwndOrg->spwndParent; 00758 00759 /* 00760 * Always get the DC from the cache. 00761 */ 00762 DCX_flags |= DCX_CACHE; 00763 00764 /* 00765 * We can't use a shared DC if the visibility of the 00766 * child does not match the parent's, or if a 00767 * CLIPSIBLINGS or CLIPCHILDREN DC is requested. 00768 * 00769 * In 3.1, we pay attention to the CLIPSIBLINGS and CLIPCHILDREN 00770 * bits of CS_PARENTDC windows, by overriding CS_PARENTDC if 00771 * either of these flags are requested. 00772 * 00773 * BACKWARD COMPATIBILITY HACK 00774 * 00775 * If parent is CLIPCHILDREN, get a cache DC, but don't 00776 * use parent's DC. Windows PowerPoint depends on this 00777 * behavior in order to draw the little gray rect between 00778 * its scroll bars correctly. 00779 */ 00780 if (!(DCX_flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) && 00781 (TestWF(pwndOrg, WFWIN31COMPAT) || !TestWF(pwndParent, WFCLIPCHILDREN)) && 00782 TestWF(pwndParent, WFVISIBLE) == TestWF(pwndOrg, WFVISIBLE)) { 00783 00784 pwndClip = pwndParent; 00785 00786 #if DBG 00787 if (DCX_flags & DCX_CLIPCHILDREN) 00788 RIPMSG0(RIP_WARNING, "WS_CLIPCHILDREN overridden by CS_PARENTDC"); 00789 if (DCX_flags & DCX_CLIPSIBLINGS) 00790 RIPMSG0(RIP_WARNING, "WS_CLIPSIBLINGS overridden by CS_PARENTDC"); 00791 #endif 00792 /* 00793 * Make sure flags reflect hwndClip rather than hwndOrg. 00794 * But, we must never clip the children (since that's who 00795 * wants to do the drawing!) 00796 */ 00797 DCX_flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS); 00798 if (TestWF(pwndClip, WFCLIPSIBLINGS)) 00799 DCX_flags |= DCX_CLIPSIBLINGS; 00800 } 00801 } 00802 00803 /* 00804 * Make sure we don't return an OWNDC if the calling thread didn't 00805 * create this window - need to returned cached always in this case. 00806 * 00807 * Win95 does not contain this code. Why? 00808 */ 00809 if (!(DCX_flags & DCX_CACHE)) { 00810 if (pwndOrg == NULL || GETPTI(pwndOrg) != PtiCurrent()) 00811 DCX_flags |= DCX_CACHE; 00812 } 00813 00814 DCX_flagsMatch = DCX_flags & DCX_MATCHMASK; 00815 00816 if (!(DCX_flags & DCX_CACHE)) { 00817 00818 /* 00819 * Handle CS_OWNDC and CS_CLASSDC cases specially. Based on the 00820 * supplied match information, we need to find the appropriate DCE. 00821 */ 00822 for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) { 00823 00824 if (pdce->DCX_flags & DCX_CACHE) 00825 continue; 00826 00827 /* 00828 * Look for the entry that matches hdcMatch or pwndOrg... 00829 */ 00830 if (!(pdce->pwndOrg == pwndOrg || pdce->hdc == hdcMatch)) 00831 continue; 00832 00833 /* 00834 * NOTE: The "Multiple-BeginPaint()-of-OWNDC-Window" Conundrum 00835 * 00836 * There is a situation having to do with OWNDC or CLASSDC window 00837 * DCs that can theoretically arise that is handled specially 00838 * here and in ReleaseCacheDC(). These DCs are identified with 00839 * the DCX_CACHE bit CLEAR. 00840 * 00841 * In the case where BeginPaint() (or a similar operation) is 00842 * called more than once without an intervening EndPaint(), the 00843 * DCX_INTERSECTRGN (or DCX_EXCLUDERGN) bit may already be set 00844 * when we get here. 00845 * 00846 * Theoretically, the correct thing to do is to save the current 00847 * hrgnClip, and set up the new one here. In ReleaseCacheDC, the 00848 * saved hrgnClip is restored and the visrgn recomputed. 00849 * 00850 * All of this is only necessary if BOTH calls involve an 00851 * hrgnClip that causes the visrgn to be changed (i.e., the 00852 * simple hrgnClip test clears the INTERSECTRGN or EXCLUDERGN bit 00853 * fails), which is not at all likely. 00854 * 00855 * When this code encounters this multiple-BeginPaint case it 00856 * punts by honoring the new EXCLUDE/INTERSECTRGN bits, but it 00857 * first restores the DC to a wide-open visrgn before doing so. 00858 * This means that the first EndPaint() will restore the visrgn 00859 * to a wide-open DC, rather than clipped to the first 00860 * BeginPaint()'s update rgn. This is a good punt, because worst 00861 * case an app does a bit more drawing than it should. 00862 */ 00863 if ((pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && 00864 (DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))) { 00865 00866 RIPMSG0(RIP_WARNING, "Nested BeginPaint() calls, please fix Your app!"); 00867 DeleteHrgnClip(pdce); 00868 } 00869 00870 if (pdce->DCX_flags & DCX_LAYERED) { 00871 /* 00872 * We're giving out the same DC again. Since it may not have 00873 * been released, transfer any accumulated bits if needed. 00874 */ 00875 UpdateLayeredSprite(pdce); 00876 00877 /* 00878 * As this point, the DC may get converted back to a screen 00879 * DC, so we must select the screen surface back into the DC. 00880 */ 00881 UserVerify(GreSelectRedirectionBitmap(pdce->hdc, NULL)); 00882 } 00883 00884 /* 00885 * If we matched exactly, no recomputation necessary 00886 * (we found a CS_OWNDC or a CS_CLASSDC that is already set up) 00887 * Otherwise, we have a CS_CLASSDC that needs recomputation. 00888 */ 00889 if ( pdce->pwndOrg == pwndOrg && 00890 bpwndOrgVisible && 00891 (pdce->DCX_flags & DCX_LAYERED) == (DCX_flags & DCX_LAYERED) && 00892 !(pdce->DCX_flags & DCX_PWNDORGINVISIBLE)) { 00893 00894 goto HaveComputedEntry; 00895 } 00896 00897 goto RecomputeEntry; 00898 } 00899 00900 RIPMSG1(RIP_WARNING, "Couldn't find DC for %p - bad code path", pwndOrg); 00901 00902 NullExit: 00903 00904 GreUnlockDisplay(gpDispInfo->hDev); 00905 return NULL; 00906 00907 } else { 00908 00909 /* 00910 * Make a quick pass through the cache, looking for an 00911 * exact match. 00912 */ 00913 SearchAgain: 00914 00915 #if DBG 00916 if (fDisableCache) 00917 goto SearchFailed; 00918 #endif 00919 00920 /* 00921 * CONSIDER (adams): Put this check into the loop above so we don't 00922 * touch all these pages twice? 00923 */ 00924 for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) { 00925 00926 /* 00927 * If we find an entry that is not in use and whose clip flags 00928 * and clip window match, we can use it. 00929 * 00930 * NOTE: DCX_INTERSECT/EXCLUDERGN cache entries always have 00931 * DCX_INUSE set, so we'll never erroneously match one here. 00932 */ 00933 UserAssert(!(pdce->DCX_flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) || 00934 (pdce->DCX_flags & DCX_INUSE)); 00935 00936 if ((pdce->pwndClip == pwndClip) && 00937 pdce->pMonitor == NULL && 00938 (DCX_flagsMatch == (pdce->DCX_flags & (DCX_MATCHMASK | DCX_INUSE | DCX_INVALID)))) { 00939 00940 /* 00941 * Special case for icon - bug 9103 (win31) 00942 */ 00943 if (TestWF(pwndClip, WFMINIMIZED) && 00944 (pdce->pwndOrg != pdce->pwndClip)) { 00945 continue; 00946 } 00947 00948 /* 00949 * If the pwndOrg of the DC we found is not visible and 00950 * the pwndOrg we're looking for is visble, then 00951 * the visrgn is no good, we can't reuse it so keep 00952 * looking. 00953 */ 00954 if (bpwndOrgVisible && pdce->DCX_flags & DCX_PWNDORGINVISIBLE) { 00955 continue; 00956 } 00957 00958 /* 00959 * Set INUSE before performing any GDI operations, just 00960 * in case DCHook() has a mind to recalculate the visrgn... 00961 */ 00962 pdce->DCX_flags |= DCX_INUSE; 00963 00964 /* 00965 * We found an entry with the proper visrgn. 00966 * If the origin doesn't match, update the CE and reset it. 00967 */ 00968 if (pwndOrg != pdce->pwndOrg) { 00969 /* 00970 * Need to flush any dirty rectangle stuff now. 00971 */ 00972 SpbCheckDce(pdce); 00973 00974 pdce->pwndOrg = pwndOrg; 00975 ResetOrg(NULL, pdce, FALSE); 00976 } 00977 00978 goto HaveComputedEntry; 00979 } 00980 } 00981 00982 #if DBG 00983 SearchFailed: 00984 #endif 00985 00986 /* 00987 * Couldn't find an exact match. Find some invalid or non-inuse 00988 * entry we can reuse. 00989 */ 00990 ppdceNotInUse = NULL; 00991 for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) { 00992 00993 /* 00994 * Skip non-cache entries 00995 */ 00996 if (!(pdce->DCX_flags & DCX_CACHE)) 00997 continue; 00998 00999 /* 01000 * Skip monitor-specific entires 01001 */ 01002 if (pdce->pMonitor != NULL) 01003 continue; 01004 01005 if (pdce->DCX_flags & DCX_INVALID) { 01006 break; 01007 } else if (!(pdce->DCX_flags & DCX_INUSE)) { 01008 01009 /* 01010 * Remember the non-inuse one, but keep looking for an invalid. 01011 */ 01012 ppdceNotInUse = ppdce; 01013 } 01014 } 01015 01016 /* 01017 * If we broke out of the loop, we found an invalid entry to reuse. 01018 * Otherwise see if we found a non-inuse entry to reuse. 01019 */ 01020 if (pdce == NULL && ((ppdce = ppdceNotInUse) == NULL)) { 01021 01022 /* 01023 * Create another DCE if we need it. 01024 */ 01025 if (!CreateCacheDC(pwndOrg, 01026 DCX_INVALID | DCX_CACHE | 01027 (DCX_flags & DCX_LAYERED), 01028 NULL)) { 01029 goto NullExit; 01030 } 01031 01032 goto SearchAgain; 01033 } 01034 01035 /* 01036 * We've chosen an entry to reuse: now fill it in and recompute it. 01037 */ 01038 pdce = *ppdce; 01039 01040 RecomputeEntry: 01041 01042 /* 01043 * Any non-invalid entries that we reuse might still have some bounds 01044 * that need to be used to invalidate SPBs. Apply them here. 01045 */ 01046 if (!(pdce->DCX_flags & DCX_INVALID)) 01047 SpbCheckDce(pdce); 01048 01049 /* 01050 * We want to compute only the matchable visrgn at first, 01051 * so we don't set up hrgnClip, or set the EXCLUDERGN or INTERSECTRGN 01052 * bits yet -- we'll deal with those later. 01053 */ 01054 pdce->DCX_flags = DCX_flagsMatch | DCX_INUSE; 01055 01056 #if DBG 01057 /* 01058 * We're about to select the visrgn into the DC, even though it's 01059 * not yet completely setup. Turn off the visrgn validation for now. 01060 * It will be turned on before this function returns. 01061 */ 01062 GreValidateVisrgn(pdce->hdc, FALSE); 01063 #endif 01064 01065 /* 01066 * Now recompute the visrgn (minus any hrgnClip shenanigans) 01067 */ 01068 hrgn = NULL; 01069 if (CalcVisRgn(&hrgn, pwndOrg, pwndClip, DCX_flagsMatch) == FALSE) { 01070 pdce->DCX_flags |= DCX_PWNDORGINVISIBLE; 01071 } 01072 01073 pdce->pwndOrg = pwndOrg; 01074 pdce->pwndClip = pwndClip; 01075 pdce->hrgnClip = NULL; // Just in case... 01076 pdce->hrgnClipPublic = NULL; 01077 01078 ResetOrg(hrgn, pdce, TRUE); 01079 01080 if (hrgn == NULL) { 01081 fVisRgnError = TRUE; 01082 } 01083 01084 /* 01085 * When we arrive here, pdce (and *ppdce) point to 01086 * a cache entry whose visrgn and origin are set up. 01087 * All that remains to be done is to deal with EXCLUDE/INTERSECTRGN 01088 */ 01089 HaveComputedEntry: 01090 01091 /* 01092 * If the window clipping flags have changed in the window 01093 * since the last time this dc was invalidated, then recompute 01094 * this dc entry. 01095 */ 01096 if ((pdce->DCX_flags & DCX_MATCHMASK) != (DCX_flags & DCX_MATCHMASK)) 01097 goto RecomputeEntry; 01098 01099 /* 01100 * Let's check these assertions just in case... 01101 */ 01102 UserAssert(pdce); 01103 UserAssert(*ppdce == pdce); 01104 UserAssert(pdce->DCX_flags & DCX_INUSE); 01105 UserAssert(!(pdce->DCX_flags & DCX_INVALID)); 01106 UserAssert((pdce->DCX_flags & DCX_MATCHMASK) == (DCX_flags & DCX_MATCHMASK)); 01107 01108 /* 01109 * Move the dce to the head of the list so it's easy to find later. 01110 */ 01111 if (pdce != gpDispInfo->pdceFirst) { 01112 *ppdce = pdce->pdceNext; 01113 pdce->pdceNext = gpDispInfo->pdceFirst; 01114 gpDispInfo->pdceFirst = pdce; 01115 } 01116 01117 #if DBG 01118 /* 01119 * We're about to mess with the visrgn in this DC, even though it's 01120 * not yet completely setup. Turn off the visrgn validation for now. 01121 * It will be turned on before this function returns. 01122 */ 01123 GreValidateVisrgn(pdce->hdc, FALSE); 01124 #endif 01125 01126 /* 01127 * Time to deal with DCX_INTERSECTRGN or DCX_EXCLUDERGN. 01128 * 01129 * We handle these two bits specially, because cache entries 01130 * with these bits set cannot be reused with the bits set. This 01131 * is because the area described in hrgnClip would have to be 01132 * compared along with the bit, which is a pain, especially since 01133 * they'd never match very often anyhow. 01134 * 01135 * What we do instead is to save the visrgn of the window before 01136 * applying either of these two flags, which is then restored 01137 * at ReleaseCacheDC() time, along with the clearing of these bits. 01138 * This effectively converts a cache entry with either of these 01139 * bits set into a "normal" cache entry that can be matched. 01140 */ 01141 if (DCX_flags & DCX_INTERSECTRGN) { 01142 01143 if (hrgnClip != HRGN_FULL) { 01144 01145 SetEmptyRgn(ghrgnGDC); 01146 01147 /* 01148 * Save the visrgn for reuse on ReleaseDC(). 01149 * (do this BEFORE we set hrgnClip & pdce->flag bit, 01150 * so that if a DCHook() callback occurs it recalculates 01151 * without hrgnClip) 01152 */ 01153 UserAssertMsg0(!pdce->hrgnSavedVis, 01154 "Nested SaveVisRgn attempt in _GetDCEx"); 01155 01156 /* 01157 * get the current vis region into hrgnSavedVis. Temporarily 01158 * store a dummy one in the DC. 01159 */ 01160 01161 pdce->hrgnSavedVis = CreateEmptyRgn(); 01162 01163 GreSelectVisRgn(pdce->hdc,pdce->hrgnSavedVis, SVR_SWAP); 01164 01165 pdce->hrgnClip = hrgnClip; 01166 01167 if (DCX_flags & DCX_NODELETERGN) 01168 pdce->DCX_flags |= DCX_NODELETERGN; 01169 01170 pdce->DCX_flags |= DCX_INTERSECTRGN; 01171 01172 if (hrgnClip == NULL) { 01173 01174 pdce->hrgnClipPublic = NULL; 01175 01176 } else { 01177 01178 IntersectRgn(ghrgnGDC, pdce->hrgnSavedVis, hrgnClip); 01179 01180 /* 01181 * Make a copy of the hrgnClip and make it public 01182 * so that we can use it in calculations in HungDraw. 01183 */ 01184 pdce->hrgnClipPublic = CreateEmptyRgnPublic(); 01185 CopyRgn(pdce->hrgnClipPublic, hrgnClip); 01186 } 01187 01188 /* 01189 * Clear the SAVEDRGNINVALID bit, since we're just 01190 * about to set it properly now. If the dce later 01191 * gets invalidated, it'll set this bit so we know 01192 * to recompute it when we restore the visrgn. 01193 */ 01194 pdce->DCX_flags &= ~DCX_SAVEDRGNINVALID; 01195 01196 /* 01197 * Select in the new region. we use the SWAP_REGION mode 01198 * so that ghrgnGDC always has a valid rgn 01199 */ 01200 01201 GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_SWAP); 01202 } 01203 } else if (DCX_flags & DCX_EXCLUDERGN) { 01204 01205 if (hrgnClip != NULL) { 01206 01207 SetEmptyRgn(ghrgnGDC); 01208 01209 /* 01210 * Save the visrgn for reuse on ReleaseDC(). 01211 * (do this BEFORE we set hrgnClip & pdce->flag bit, 01212 * so that if a DCHook() callback occurs it recalculates 01213 * without hrgnClip) 01214 */ 01215 UserAssertMsg0(!pdce->hrgnSavedVis, 01216 "Nested SaveVisRgn attempt in _GetDCEx"); 01217 01218 /* 01219 * get the current vis region into hrgnSavedVis. Temporarily 01220 * store a dummy one in the DC. 01221 */ 01222 pdce->hrgnSavedVis = CreateEmptyRgn(); 01223 01224 GreSelectVisRgn(pdce->hdc,pdce->hrgnSavedVis, SVR_SWAP); 01225 01226 pdce->hrgnClip = hrgnClip; 01227 01228 if (DCX_flags & DCX_NODELETERGN) 01229 pdce->DCX_flags |= DCX_NODELETERGN; 01230 01231 pdce->DCX_flags |= DCX_EXCLUDERGN; 01232 01233 if (hrgnClip == HRGN_FULL) { 01234 01235 pdce->hrgnClipPublic = HRGN_FULL; 01236 01237 } else { 01238 01239 SubtractRgn(ghrgnGDC, pdce->hrgnSavedVis, hrgnClip); 01240 01241 /* 01242 * Make a copy of the hrgnClip and make it public 01243 * so that we can use it in calculations in HungDraw. 01244 */ 01245 pdce->hrgnClipPublic = CreateEmptyRgnPublic(); 01246 CopyRgn(pdce->hrgnClipPublic, hrgnClip); 01247 } 01248 01249 /* 01250 * Clear the SAVEDRGNINVALID bit, since we're just 01251 * about to set it properly now. If the dce later 01252 * gets invalidated, it'll set this bit so we know 01253 * to recompute it when we restore the visrgn. 01254 */ 01255 pdce->DCX_flags &= ~DCX_SAVEDRGNINVALID; 01256 01257 /* 01258 * Select in the new region. we use the SWAP_REGION mode 01259 * so that ghrgnGDC always has a valid rgn 01260 */ 01261 01262 GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_SWAP); 01263 } 01264 } 01265 } 01266 01267 if (pdce->DCX_flags & DCX_LAYERED) { 01268 UserAssert(pwndLayer != NULL); 01269 UserAssert(hbmLayer != NULL); 01270 01271 UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbmLayer)); 01272 01273 /* 01274 * Enable bounds accumulation, so we know if there was any drawing 01275 * done into that DC and the actual rect we need to update when 01276 * this DC is released. 01277 */ 01278 GreGetBounds(pdce->hdc, NULL, GGB_ENABLE_WINMGR); 01279 01280 /* 01281 * In case the visrgn couldn't be allocated, clear it in the 01282 * dc again, since we just selected a new surface. 01283 */ 01284 if (fVisRgnError) { 01285 GreSelectVisRgn(pdce->hdc, NULL, SVR_DELETEOLD); 01286 } 01287 } 01288 01289 /* 01290 * Whew! Set ownership and return the bloody DC. 01291 * Only set ownership for cache dcs. Own dcs have already been owned. 01292 * The reason why we don't want to set the ownership over again is 01293 * because the console sets its owndcs to PUBLIC so gdisrv can use 01294 * them without asserting. We don't want to set the ownership back 01295 * again. 01296 */ 01297 if (pdce->DCX_flags & DCX_CACHE) { 01298 01299 if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_CURRENT)) { 01300 RIPMSG1(RIP_WARNING, "GetDCEx: SetDCOwner Failed %lX", pdce->hdc); 01301 } 01302 01303 /* 01304 * Decrement the Free DCE Count. This should always be >= 0, 01305 * since we'll create a new dce if the cache is all in use. 01306 */ 01307 DecrementFreeDCECount(); 01308 01309 pdce->ptiOwner = PtiCurrent(); 01310 } 01311 01312 #ifdef USE_MIRRORING 01313 if (TestWF(pwnd, WEFLAYOUTRTL) && !(DCX_flags & DCX_NOMIRROR)) { 01314 GreSetLayout(pdce->hdc, -1, LAYOUT_RTL); 01315 } 01316 #endif 01317 01318 #if DBG 01319 GreValidateVisrgn(pdce->hdc, TRUE); 01320 #endif 01321 01322 GreUnlockDisplay(gpDispInfo->hDev); 01323 01324 return pdce->hdc; 01325 } 01326 01327 /***************************************************************************\ 01328 * ReleaseCacheDC 01329 * 01330 * Releases a DC from the cache. 01331 * 01332 * History: 01333 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 01334 * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry. 01335 \***************************************************************************/ 01336 01337 UINT ReleaseCacheDC( 01338 HDC hdc, 01339 BOOL fEndPaint) 01340 { 01341 PDCE pdce; 01342 PDCE *ppdce; 01343 01344 for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) { 01345 01346 if (pdce->hdc == hdc) { 01347 01348 /* 01349 * Check for redundant releases or release of an invalid entry 01350 */ 01351 if ((pdce->DCX_flags & (DCX_DESTROYTHIS | DCX_INVALID | DCX_INUSE)) != DCX_INUSE) 01352 return DCE_NORELEASE; 01353 01354 /* 01355 * Lock the display since we may be playing with visrgns. 01356 */ 01357 GreLockDisplay(gpDispInfo->hDev); 01358 01359 if (pdce->DCX_flags & DCX_LAYERED) { 01360 UpdateLayeredSprite(pdce); 01361 } 01362 01363 /* 01364 * If this is a permanent DC, then don't reset its state. 01365 */ 01366 if (pdce->DCX_flags & DCX_CACHE) { 01367 /* 01368 * Restore the DC state and mark the entry as not in use. 01369 * Set owner back to server as well, since it's going back 01370 * into the cache. 01371 */ 01372 if (!(pdce->DCX_flags & DCX_NORESETATTRS)) { 01373 /* 01374 * If bSetupDC() failed, the DC is busy (ie. in-use 01375 * by another thread), so don't release it. 01376 */ 01377 if ( (!(GreCleanDC(hdc))) || 01378 (!(GreSetDCOwner(hdc, OBJECT_OWNER_NONE))) ) { 01379 01380 GreUnlockDisplay(gpDispInfo->hDev); 01381 return DCE_NORELEASE; 01382 } 01383 01384 } else if (!GreSetDCOwner(pdce->hdc, OBJECT_OWNER_NONE)) { 01385 01386 GreUnlockDisplay(gpDispInfo->hDev); 01387 return DCE_NORELEASE; 01388 } 01389 01390 pdce->ptiOwner = NULL; 01391 pdce->DCX_flags &= ~DCX_INUSE; 01392 01393 #if DBG 01394 /* 01395 * Turn off checked only surface validation for now, since 01396 * we may select a different surface (screen) in this DC that 01397 * may not correspond to the visrgn currently in the DC. When 01398 * the DC is given out again, it will be revalidated. 01399 */ 01400 GreValidateVisrgn(pdce->hdc, FALSE); 01401 #endif 01402 01403 /* 01404 * The DC is no longer in use, so unselect the redirection 01405 * bitmap from it. 01406 */ 01407 if (pdce->DCX_flags & DCX_LAYERED) { 01408 UserVerify(GreSelectRedirectionBitmap(pdce->hdc, NULL)); 01409 } 01410 01411 /* 01412 * Increment the Free DCE count. This holds the count 01413 * of available DCEs. Check the threshold, and destroy 01414 * the dce if it's above the mark. 01415 */ 01416 IncrementFreeDCECount(); 01417 01418 if (gnDCECount > DCE_SIZE_CACHETHRESHOLD) { 01419 if (DestroyCacheDC(ppdce, pdce->hdc)) { 01420 GreUnlockDisplay(gpDispInfo->hDev); 01421 return DCE_FREED; 01422 } 01423 } 01424 } 01425 01426 /* 01427 * If we have an EXCLUDERGN or INTERSECTRGN cache entry, 01428 * convert it back to a "normal" cache entry by restoring 01429 * the visrgn and blowing away hrgnClip. 01430 * 01431 * Note that for non-DCX_CACHE DCs, we only do this if 01432 * we're being called from EndPaint(). 01433 */ 01434 if ((pdce->DCX_flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && 01435 ((pdce->DCX_flags & DCX_CACHE) || fEndPaint)) { 01436 DeleteHrgnClip(pdce); 01437 } 01438 01439 GreUnlockDisplay(gpDispInfo->hDev); 01440 return DCE_RELEASED; 01441 } 01442 } 01443 01444 /* 01445 * Yell if DC couldn't be found... 01446 */ 01447 RIPERR1(ERROR_DC_NOT_FOUND, RIP_WARNING, 01448 "Invalid device context (DC) handle passed to ReleaseCacheDC (0x%08lx)", hdc); 01449 01450 return DCE_NORELEASE; 01451 } 01452 01453 /***************************************************************************\ 01454 * CreateCacheDC 01455 * 01456 * Creates a DCE and adds it to the cache. 01457 * 01458 * History: 01459 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 01460 * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry. 01461 \***************************************************************************/ 01462 01463 HDC CreateCacheDC( 01464 PWND pwndOrg, 01465 DWORD DCX_flags, 01466 PMONITOR pMonitor 01467 ) 01468 { 01469 PDCE pdce; 01470 HDC hdc; 01471 HANDLE hDev; 01472 01473 if ((pdce = (PDCE)UserAllocPool(sizeof(DCE), TAG_DCE)) == NULL) 01474 return NULL; 01475 01476 if (pMonitor == NULL) { 01477 hDev = gpDispInfo->hDev; 01478 } else { 01479 hDev = pMonitor->hDev; 01480 } 01481 01482 if ((hdc = GreCreateDisplayDC(hDev, DCTYPE_DIRECT, FALSE)) == NULL) { 01483 UserFreePool(pdce); 01484 return NULL; 01485 } 01486 01487 /* 01488 * Link this entry into the cache entry list. 01489 */ 01490 pdce->pdceNext = gpDispInfo->pdceFirst; 01491 gpDispInfo->pdceFirst = pdce; 01492 01493 pdce->hdc = hdc; 01494 pdce->DCX_flags = DCX_flags; 01495 pdce->pwndOrg = pwndOrg; 01496 pdce->pwndClip = pwndOrg; 01497 pdce->hrgnClip = NULL; 01498 pdce->hrgnClipPublic = NULL; 01499 pdce->hrgnSavedVis = NULL; 01500 pdce->pMonitor = pMonitor; 01501 01502 /* 01503 * Mark it as undeleteable so no application can delete it out of our 01504 * cache! 01505 */ 01506 GreMarkUndeletableDC(hdc); 01507 01508 if (DCX_flags & DCX_OWNDC) { 01509 01510 /* 01511 * Set the ownership of owndcs immediately: that way console can set 01512 * the owernship to PUBLIC when it calls GetDC so that both the input 01513 * thread and the service threads can use the same owndc. 01514 */ 01515 GreSetDCOwner(hdc, OBJECT_OWNER_CURRENT); 01516 pdce->ptiOwner = PtiCurrent(); 01517 01518 } else { 01519 01520 /* 01521 * Otherwise it is a cache dc... set its owner to none - nothing 01522 * is using it - equivalent of "being in the cache" but unaccessible 01523 * to other processes. 01524 */ 01525 GreSetDCOwner(hdc, OBJECT_OWNER_NONE); 01526 pdce->ptiOwner = NULL; 01527 01528 /* 01529 * Increment the available-cacheDC count. Once this hits our 01530 * threshold, then we can free-up some of the entries. 01531 */ 01532 IncrementFreeDCECount(); 01533 } 01534 01535 /* 01536 * If we're creating a permanent DC, then compute it now. 01537 */ 01538 if (!(DCX_flags & DCX_CACHE)) { 01539 01540 /* 01541 * Set up the class DC now... 01542 */ 01543 if (TestCF(pwndOrg, CFCLASSDC)) 01544 pwndOrg->pcls->pdce = pdce; 01545 01546 /* 01547 * Finish setting up DCE and force eventual visrgn calculation. 01548 */ 01549 UserAssert(!(DCX_flags & DCX_WINDOW)); 01550 01551 pdce->DCX_flags |= DCX_INUSE; 01552 01553 InvalidateDce(pdce); 01554 } 01555 01556 /* 01557 * If there are any spb's around then enable bounds accumulation. 01558 */ 01559 if (AnySpbs()) 01560 GreGetBounds(pdce->hdc, NULL, DCB_ENABLE | DCB_SET | DCB_WINDOWMGR); 01561 01562 return pdce->hdc; 01563 } 01564 01565 /***************************************************************************\ 01566 * WindowFromCacheDC 01567 * 01568 * Returns the window associated with a DC. 01569 * 01570 * History: 01571 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 01572 \***************************************************************************/ 01573 01574 PWND WindowFromCacheDC( 01575 HDC hdc) 01576 { 01577 PDCE pdce; 01578 for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) { 01579 01580 if (pdce->hdc == hdc) 01581 return (pdce->DCX_flags & DCX_DESTROYTHIS) ? NULL : pdce->pwndOrg; 01582 } 01583 01584 return NULL; 01585 } 01586 01587 /***************************************************************************\ 01588 * DelayedDestroyCacheDC 01589 * 01590 * Destroys DCE's which have been partially destroyed. 01591 * 01592 * History: 01593 * 16-Jun-1992 DavidPe Created. 01594 \***************************************************************************/ 01595 01596 VOID DelayedDestroyCacheDC(VOID) 01597 { 01598 PDCE *ppdce; 01599 PDCE pdce; 01600 01601 01602 /* 01603 * Zip through the cache looking for a DCX_DESTROYTHIS hdc. 01604 */ 01605 for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL; ) { 01606 01607 /* 01608 * If we found a DCE on this thread that we tried to destroy 01609 * earlier, try and destroy it again. 01610 */ 01611 pdce = *ppdce; 01612 01613 if (pdce->DCX_flags & DCX_DESTROYTHIS) 01614 DestroyCacheDC(ppdce, pdce->hdc); 01615 01616 /* 01617 * Step to the next DC. If the DC was deleted, there 01618 * is no need to calculate address of the next entry. 01619 */ 01620 if (pdce == *ppdce) 01621 ppdce = &pdce->pdceNext; 01622 } 01623 01624 PpiCurrent()->W32PF_Flags &= ~W32PF_OWNDCCLEANUP; 01625 } 01626 01627 /***************************************************************************\ 01628 * DestroyCacheDC 01629 * 01630 * Removes a DC from the cache, freeing all resources associated 01631 * with it. 01632 * 01633 * History: 01634 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 01635 * 20-Dec-1995 ChrisWil Added (hrgnClipPublic) entry. 01636 \***************************************************************************/ 01637 01638 BOOL DestroyCacheDC( 01639 PDCE *ppdce, 01640 HDC hdc) 01641 { 01642 PDCE pdce; 01643 01644 /* 01645 * Zip through the cache looking for hdc. 01646 */ 01647 if (ppdce == NULL) { 01648 for (ppdce = &gpDispInfo->pdceFirst; (pdce = *ppdce); ppdce = &pdce->pdceNext) { 01649 if (pdce->hdc == hdc) 01650 break; 01651 } 01652 } 01653 01654 if (ppdce == NULL) 01655 return FALSE; 01656 01657 /* 01658 * Set this here so we know this DCE is supposed to be deleted. 01659 */ 01660 pdce = *ppdce; 01661 pdce->DCX_flags |= DCX_DESTROYTHIS; 01662 01663 /* 01664 * Free up the dce object and contents. 01665 */ 01666 01667 if (!(pdce->DCX_flags & DCX_NODELETERGN)) { 01668 DeleteMaybeSpecialRgn(pdce->hrgnClip); 01669 pdce->hrgnClip = NULL; 01670 } 01671 01672 if (pdce->hrgnClipPublic != NULL) { 01673 GreDeleteObject(pdce->hrgnClipPublic); 01674 pdce->hrgnClipPublic = NULL; 01675 } 01676 01677 if (pdce->hrgnSavedVis != NULL) { 01678 GreDeleteObject(pdce->hrgnSavedVis); 01679 pdce->hrgnSavedVis = NULL; 01680 } 01681 01682 /* 01683 * If GreSetDCOwner() or GreDeleteDC() fail, the 01684 * DC is in-use by another thread. Set 01685 * W32PF_OWNDCCLEANUP so we know to scan for and 01686 * delete this DCE later. 01687 */ 01688 if (!GreSetDCOwner(hdc, OBJECT_OWNER_PUBLIC)) { 01689 PpiCurrent()->W32PF_Flags |= W32PF_OWNDCCLEANUP; 01690 return FALSE; 01691 } 01692 01693 /* 01694 * Set the don't rip flag so our routine RipIfCacheDC() doesn't 01695 * rip (called back from gdi). 01696 */ 01697 #if DBG 01698 pdce->DCX_flags |= DCX_DONTRIPONDESTROY; 01699 GreMarkDeletableDC(hdc); // So GRE doesn't RIP. 01700 #endif 01701 01702 if (!GreDeleteDC(hdc)) { 01703 01704 #if DBG 01705 GreMarkUndeletableDC(hdc); 01706 pdce->DCX_flags &= ~DCX_DONTRIPONDESTROY; 01707 #endif 01708 PpiCurrent()->W32PF_Flags |= W32PF_OWNDCCLEANUP; 01709 return FALSE; 01710 } 01711 01712 /* 01713 * Decrement this dc-entry from the free-list count. 01714 */ 01715 if (pdce->DCX_flags & DCX_CACHE) { 01716 01717 if (!(pdce->DCX_flags & DCX_INUSE)) { 01718 DecrementFreeDCECount(); 01719 } 01720 } 01721 01722 #if DBG 01723 pdce->pwndOrg = NULL; 01724 pdce->pwndClip = NULL; 01725 #endif 01726 01727 /* 01728 * Unlink the DCE from the list. 01729 */ 01730 *ppdce = pdce->pdceNext; 01731 01732 UserFreePool(pdce); 01733 01734 return TRUE; 01735 } 01736 01737 01738 /***************************************************************************\ 01739 * InvalidateGDIWindows 01740 * 01741 * Recalculates the visrgn of all descendents of pwnd on behalf of GRE. 01742 * 01743 * History: 01744 \***************************************************************************/ 01745 01746 VOID InvalidateGDIWindows( 01747 PWND pwnd) 01748 { 01749 PVOID pwo; 01750 01751 if (pwnd != NULL) { 01752 01753 if ((pwo = _GetProp(pwnd, PROP_WNDOBJ, TRUE)) != NULL) { 01754 01755 HRGN hrgnClient = NULL; 01756 01757 if (GreWindowInsteadOfClient(pwo)) { 01758 01759 /* 01760 * Never clip children for WO_RGN_WINDOW so that NetMeeting 01761 * gets the unioned window area: 01762 */ 01763 01764 CalcVisRgn(&hrgnClient, 01765 pwnd, 01766 pwnd, 01767 DCX_WINDOW | 01768 (TestWF(pwnd, WFCLIPSIBLINGS) ? DCX_CLIPSIBLINGS : 0)); 01769 } else { 01770 CalcVisRgn(&hrgnClient, 01771 pwnd, 01772 pwnd, 01773 DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS); 01774 } 01775 01776 GreSetClientRgn(pwo, hrgnClient, &(pwnd->rcClient)); 01777 } 01778 01779 pwnd = pwnd->spwndChild; 01780 while (pwnd != NULL) { 01781 InvalidateGDIWindows(pwnd); 01782 pwnd = pwnd->spwndNext; 01783 } 01784 } 01785 } 01786 01787 /***************************************************************************\ 01788 * zzzInvalidateDCCache 01789 * 01790 * This function is called when the visrgn of a window is changing for 01791 * some reason. It is responsible for ensuring that all of the cached 01792 * visrgns in the DC cache that are affected by the visrgn change are 01793 * invalidated. 01794 * 01795 * Operations that affect the visrgn of a window (i.e., things that better 01796 * call this routine one way or another:) 01797 * 01798 * Hiding or showing self or parent 01799 * Moving, sizing, or Z-order change of self or parent 01800 * Minimizing or unminimizing self or parent 01801 * Screen or paint locking of self or parent 01802 * LockWindowUpdate of self or parent 01803 * 01804 * Invalidates any cache entries associated with pwnd and/or any children of 01805 * pwnd by either recalcing them on the fly if they're in use, or causing 01806 * them to be recalced later. 01807 * 01808 * History: 01809 * 17-Jul-1991 DarrinM Ported from Win 3.1 sources. 01810 \***************************************************************************/ 01811 01812 BOOL zzzInvalidateDCCache( 01813 PWND pwndInvalid, 01814 DWORD flags) 01815 { 01816 PWND pwnd; 01817 PDCE pdce; 01818 PTHREADINFO ptiCurrent = PtiCurrent(); 01819 TL tlpwndInvalid; 01820 FLONG fl; 01821 01822 /* 01823 * Invalidation implies screen real estate is changing so we must 01824 * jiggle the mouse, because a different window may be underneath 01825 * the mouse, which needs to get a mouse move in order to change the 01826 * mouse pointer. 01827 * 01828 * The check for the tracking is added for full-drag-windows. In doing 01829 * full-drag, zzzBltValidBits() is called from setting the window-pos. 01830 * This resulted in an extra-mousemove being queued from this routine. 01831 * So, when we're tracking, don't queue a mousemove. This pointer is 01832 * null when tracking is off, so it won't effect the normal case. 01833 */ 01834 ThreadLockAlwaysWithPti(ptiCurrent, pwndInvalid, &tlpwndInvalid); 01835 01836 if (!(ptiCurrent->TIF_flags & TIF_MOVESIZETRACKING) && 01837 !(flags & IDC_NOMOUSE)) { 01838 01839 #ifdef REDIRECTION 01840 if (!IsGlobalHooked(ptiCurrent, WHF_FROM_WH(WH_HITTEST))) 01841 #endif // REDIRECTION 01842 01843 zzzSetFMouseMoved(); 01844 } 01845 01846 /* 01847 * The visrgn of pwnd is changing. First see if a change to this 01848 * visrgn will also affect other window's visrgns: 01849 * 01850 * 1) if parent is clipchildren, we need to invalidate parent 01851 * 2) if clipsiblings, we need to invalidate our sibling's visrgns. 01852 * 01853 * We don't optimize the case where we're NOT clipsiblings, and our 01854 * parent is clipchildren: very rare case. 01855 * We also don't optimize the fact that a clipsiblings window visrgn 01856 * change only affects the visrgns of windows BELOW it. 01857 */ 01858 if (flags & IDC_DEFAULT) { 01859 01860 flags = 0; 01861 01862 if ((pwndInvalid->spwndParent != NULL) && 01863 (pwndInvalid != PWNDDESKTOP(pwndInvalid))) { 01864 01865 /* 01866 * If the parent is a clip-children window, then 01867 * a change to our visrgn will affect his visrgn, and 01868 * possibly those of our siblings. So, invalidate starting 01869 * from our parent. Note that we don't need to invalidate 01870 * any window DCs associated with our parent. 01871 */ 01872 if (TestWF(pwndInvalid->spwndParent, WFCLIPCHILDREN)) { 01873 01874 flags = IDC_CLIENTONLY; 01875 pwndInvalid = pwndInvalid->spwndParent; 01876 01877 } else if (TestWF(pwndInvalid, WFCLIPSIBLINGS)) { 01878 01879 /* 01880 * If we are clip-siblings, chances are that our siblings are 01881 * too. A change to our visrgn might affect our siblings, 01882 * so invalidate all of our siblings. 01883 * 01884 * NOTE! This code assumes that if pwndInvalid is NOT 01885 * CLIPSIBLINGs, that either it does not overlap other 01886 * CLIPSIBLINGs windows, or that none of the siblings are 01887 * CLIPSIBLINGs. This is a reasonable assumption, because 01888 * mixing CLIPSIBLINGs and non CLIPSIBLINGs windows that 01889 * overlap is generally unpredictable anyhow. 01890 */ 01891 flags = IDC_CHILDRENONLY; 01892 pwndInvalid = pwndInvalid->spwndParent; 01893 } 01894 } 01895 } 01896 01897 /* 01898 * Go through the list of DCE's, looking for any that need to be 01899 * invalidated or recalculated. Basically, any DCE that contains 01900 * a window handle that is equal to pwndInvalid or a child of pwndInvalid 01901 * needs to be invalidated. 01902 */ 01903 for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) { 01904 01905 if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS)) 01906 continue; 01907 01908 /* 01909 * HACK ALERT 01910 * 01911 * A minimized client DC must never exclude its children, even if 01912 * its WS_CLIPCHILDREN bit is set. For CS_OWNDC windows we must 01913 * update the flags of the DCE to reflect the change in window state 01914 * when the visrgn is eventually recomputed. 01915 */ 01916 if (!(pdce->DCX_flags & (DCX_CACHE | DCX_WINDOW))) { 01917 01918 if (TestWF(pdce->pwndOrg, WFCLIPCHILDREN)) 01919 pdce->DCX_flags |= DCX_CLIPCHILDREN; 01920 01921 if (TestWF(pdce->pwndOrg, WFMINIMIZED)) 01922 pdce->DCX_flags &= ~DCX_CLIPCHILDREN; 01923 } 01924 01925 /* 01926 * This code assumes that if pdce->pwndClip != pdce->pwndOrg, 01927 * that pdce->pwndClip == pdce->pwndOrg->spwndParent. To ensure 01928 * that both windows are visited, we start the walk upwards from 01929 * the lower of the two, or pwndOrg. 01930 */ 01931 UserAssert((pdce->pwndClip == pdce->pwndOrg) || 01932 (pdce->pwndClip == pdce->pwndOrg->spwndParent)); 01933 01934 /* 01935 * Walk upwards from pdce->pwndOrg, to see if we encounter 01936 * pwndInvalid. 01937 */ 01938 for (pwnd = pdce->pwndOrg; pwnd; pwnd = pwnd->spwndParent) { 01939 01940 if (pwnd == pwndInvalid) { 01941 01942 if (pwndInvalid == pdce->pwndOrg) { 01943 01944 /* 01945 * Ignore DCEs for pwndInvalid if IDC_CHILDRENONLY. 01946 */ 01947 if (flags & IDC_CHILDRENONLY) 01948 break; 01949 01950 /* 01951 * Ignore window DCEs for pwndInvalid if IDC_CLIENTONLY 01952 */ 01953 if ((flags & IDC_CLIENTONLY) && (pdce->DCX_flags & DCX_WINDOW)) 01954 break; 01955 } 01956 01957 InvalidateDce(pdce); 01958 break; 01959 } 01960 } 01961 } 01962 01963 /* 01964 * Update WNDOBJs in gdi if they exist. 01965 */ 01966 GreLockDisplay(gpDispInfo->hDev); 01967 01968 fl = (flags & IDC_MOVEBLT) ? GCR_DELAYFINALUPDATE : 0; 01969 01970 if (gcountPWO != 0) { 01971 InvalidateGDIWindows(pwndInvalid); 01972 fl |= GCR_WNDOBJEXISTS; 01973 } 01974 01975 GreClientRgnUpdated(fl); 01976 01977 GreUpdateSpriteVisRgn(gpDispInfo->hDev); 01978 01979 GreUnlockDisplay(gpDispInfo->hDev); 01980 01981 ThreadUnlock(&tlpwndInvalid); 01982 01983 return TRUE; 01984 } 01985 01986 /***************************************************************************\ 01987 * _WindowFromDC (API) 01988 * 01989 * Takes a dc, returns the window associated with it. 01990 * 01991 * History: 01992 * 23-Jun-1991 ScottLu Created. 01993 \***************************************************************************/ 01994 01995 PWND _WindowFromDC( 01996 HDC hdc) 01997 { 01998 PDCE pdce; 01999 02000 for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) { 02001 02002 if (!(pdce->DCX_flags & DCX_INUSE) || (pdce->DCX_flags & DCX_CREATEDC)) 02003 continue; 02004 02005 if (pdce->hdc == hdc) 02006 return pdce->pwndOrg; 02007 } 02008 02009 return NULL; 02010 } 02011 02012 /***************************************************************************\ 02013 * FastWindowFromDC 02014 * 02015 * Returns the window associated with a DC, and puts it at the 02016 * front of the list. 02017 * 02018 * History: 02019 * 23-Jun-1991 ScottLu Created. 02020 \***************************************************************************/ 02021 02022 PWND FastWindowFromDC( 02023 HDC hdc) 02024 { 02025 PDCE *ppdce; 02026 PDCE pdceT; 02027 02028 if ((gpDispInfo->pdceFirst->hdc == hdc) && 02029 (gpDispInfo->pdceFirst->DCX_flags & DCX_INUSE)) { 02030 02031 return gpDispInfo->pdceFirst->pwndOrg; 02032 } 02033 02034 for (ppdce = &gpDispInfo->pdceFirst; *ppdce; ppdce = &(*ppdce)->pdceNext) { 02035 02036 if (((*ppdce)->hdc == hdc) && ((*ppdce)->DCX_flags & DCX_INUSE)) { 02037 02038 /* 02039 * Unlink/link to make it first. 02040 */ 02041 pdceT = *ppdce; 02042 *ppdce = pdceT->pdceNext; 02043 pdceT->pdceNext = gpDispInfo->pdceFirst; 02044 gpDispInfo->pdceFirst = pdceT; 02045 02046 return pdceT->pwndOrg; 02047 } 02048 } 02049 02050 return NULL; 02051 } 02052 02053 /***************************************************************************\ 02054 * GetDCOrgOnScreen 02055 * 02056 * This function gets the DC origin of a window in screen coordinates. The 02057 * DC origin is always in the surface coordinates. For screen DCs the 02058 * surface is the screen, so their origin is already in the screen 02059 * coordinates. For redirected DCs, GreGetDCOrg will return the origin 02060 * of the DC in the redirected surface coordinates to which we will add 02061 * the origin of the redirected window that the surface is backing. 02062 * 02063 * 11/25/1998 vadimg created 02064 \***************************************************************************/ 02065 02066 BOOL GetDCOrgOnScreen(HDC hdc, LPPOINT ppt) 02067 { 02068 if (GreGetDCOrg(hdc, ppt)) { 02069 POINT ptScreen; 02070 02071 /* 02072 * Get the origin of the redirected window in screen coordinates. 02073 */ 02074 if (UserGetRedirectedWindowOrigin(hdc, &ptScreen)) { 02075 ppt->x += ptScreen.x; 02076 ppt->y += ptScreen.y; 02077 return TRUE; 02078 } 02079 } 02080 return FALSE; 02081 } 02082 02083 /***************************************************************************\ 02084 * UserGetRedirectedWindowOrigin 02085 * 02086 * The DC origin is in the surface coordinates. For screen DCs, the surface 02087 * is the screen and so their origin is in the screen coordinates. But for 02088 * redirected DCs, the backing surface origin is the same as the window 02089 * being redirected. This function retrieves the screen origin of a redirected 02090 * window corresponding to a redirection DC. It returns FALSE if this isn't 02091 * a valid DC or it's not a redirected DC. 02092 * 02093 * 11/18/1998 vadimg created 02094 \***************************************************************************/ 02095 02096 BOOL UserGetRedirectedWindowOrigin(HDC hdc, LPPOINT ppt) 02097 { 02098 PWND pwnd; 02099 PDCE pdce; 02100 02101 if ((pdce = LookupDC(hdc)) == NULL) 02102 return FALSE; 02103 02104 if (!(pdce->DCX_flags & DCX_LAYERED)) 02105 return FALSE; 02106 02107 pwnd = GetLayeredWindow(pdce->pwndOrg); 02108 02109 ppt->x = pwnd->rcWindow.left; 02110 ppt->y = pwnd->rcWindow.top; 02111 02112 return TRUE; 02113 } 02114 02115 /***************************************************************************\ 02116 * LookupDC 02117 * 02118 * Validate a DC by returning a correspnding pdce. 02119 * 02120 * 11/12/1997 vadimg created 02121 \***************************************************************************/ 02122 02123 PDCE LookupDC(HDC hdc) 02124 { 02125 PDCE pdce; 02126 02127 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 02128 02129 if (pdce->DCX_flags & (DCX_INVALID | DCX_DESTROYTHIS)) 02130 continue; 02131 02132 if (pdce->hdc == hdc && pdce->pMonitor == NULL && 02133 (pdce->DCX_flags & DCX_INUSE)) { 02134 return pdce; 02135 } 02136 } 02137 return NULL; 02138 } 02139 02140 /***************************************************************************\ 02141 * GetMonitorDC 02142 * 02143 * 11/06/97 vadimg ported from Memphis 02144 \***************************************************************************/ 02145 02146 #define DCX_LEAVEBITS (DCX_WINDOW | DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | \ 02147 DCX_PARENTCLIP | DCX_LOCKWINDOWUPDATE | DCX_NOCLIPCHILDREN | \ 02148 DCX_USESTYLE | DCX_EXCLUDEUPDATE | DCX_INTERSECTUPDATE | \ 02149 DCX_EXCLUDERGN | DCX_INTERSECTRGN) 02150 02151 HDC GetMonitorDC(PDCE pdceOrig, PMONITOR pMonitor) 02152 { 02153 PDCE pdce; 02154 POINT pt; 02155 RECT rc; 02156 02157 TryAgain: 02158 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 02159 /* 02160 * Find an available DC for this monitor. 02161 */ 02162 if (pdce->DCX_flags & (DCX_INUSE | DCX_DESTROYTHIS)) 02163 continue; 02164 02165 if (pdce->pMonitor != pMonitor) 02166 continue; 02167 02168 if (!(pdce->DCX_flags & DCX_INVALID)) 02169 SpbCheckDce(pdce); 02170 02171 /* 02172 * Copy DC properties and style bits. 02173 */ 02174 GreSetDCOwner(pdce->hdc, OBJECT_OWNER_CURRENT); 02175 pdce->pwndOrg = pdceOrig->pwndOrg; 02176 pdce->pwndClip = pdceOrig->pwndClip; 02177 pdce->ptiOwner = pdceOrig->ptiOwner; 02178 pdce->DCX_flags = (DCX_INUSE | DCX_CACHE) | 02179 (pdceOrig->DCX_flags & DCX_LEAVEBITS); 02180 02181 if (pdceOrig->hrgnClip > HRGN_FULL) { 02182 UserAssert(pdce->hrgnClip == NULL); 02183 UserAssert(pdceOrig->DCX_flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)); 02184 02185 pdce->hrgnClip = CreateEmptyRgn(); 02186 SetMonitorRegion(pMonitor, pdce->hrgnClip, pdceOrig->hrgnClip); 02187 } else { 02188 pdce->hrgnClip = pdceOrig->hrgnClip; 02189 } 02190 02191 /* 02192 * Setup the visrgn clipped to this monitor. 02193 */ 02194 GreCopyVisRgn(pdceOrig->hdc, ghrgnGDC); 02195 SetMonitorRegion(pMonitor, ghrgnGDC, ghrgnGDC); 02196 GreSelectVisRgn(pdce->hdc, ghrgnGDC, SVR_COPYNEW); 02197 02198 GreGetDCOrgEx(pdceOrig->hdc, &pt, &rc); 02199 OffsetRect(&rc, -pMonitor->rcMonitor.left, -pMonitor->rcMonitor.top); 02200 GreSetDCOrg(pdce->hdc, rc.left, rc.top, (PRECTL)&rc); 02201 02202 /* 02203 * Decrement the Free DCE Count. This should always be >= 0, 02204 * since we'll create a new dce if the cache is all in use. 02205 */ 02206 DecrementFreeDCECount(); 02207 02208 return pdce->hdc; 02209 } 02210 02211 /* 02212 * If this call succeeds a new DC will be available in the cache, 02213 * so the loop will find it and properly set it up. 02214 */ 02215 if (CreateCacheDC(NULL, DCX_INVALID | DCX_CACHE, pMonitor) == NULL) 02216 return NULL; 02217 02218 goto TryAgain; 02219 } 02220 02221 /***************************************************************************\ 02222 * RipIfCacheDC 02223 * 02224 * This is called on debug systems by gdi when it is destroying a dc 02225 * to make sure it isn't in the cache. 02226 * 02227 * History: 02228 \***************************************************************************/ 02229 02230 #if DBG 02231 VOID RipIfCacheDC( 02232 HDC hdc) 02233 { 02234 PDCE pdce; 02235 02236 /* 02237 * This is called on debug systems by gdi when it is destroying a dc 02238 * to make sure it isn't in the cache. 02239 */ 02240 EnterCrit(); 02241 02242 for (pdce = gpDispInfo->pdceFirst; pdce; pdce = pdce->pdceNext) { 02243 02244 if (pdce->hdc == hdc && !(pdce->DCX_flags & DCX_DONTRIPONDESTROY)) { 02245 02246 RIPMSG1(RIP_ERROR, 02247 "Deleting DC in DC cache - contact JohnC. hdc == %08lx\n", 02248 pdce->hdc); 02249 } 02250 } 02251 02252 LeaveCrit(); 02253 } 02254 #endif 02255 02256 #ifdef USE_MIRRORING 02257 /***************************************************************************\ 02258 * MirrorRect 02259 * 02260 * Mirror the client window coordinates. 02261 * 02262 * 02263 * History: 02264 \***************************************************************************/ 02265 void MirrorRect(PWND pwnd, LPRECT lprc) 02266 { 02267 int left, cx; 02268 02269 cx = pwnd->rcClient.right - pwnd->rcClient.left; 02270 left = lprc->left; 02271 lprc->left = cx - lprc->right; 02272 lprc->right = cx - left; 02273 } 02274 02275 /***************************************************************************\ 02276 * OrderRects 02277 * 02278 * Order the rectangles, so that they flow from left to right. This is needed 02279 * when combining a mirrored region (see MirrorRegion) 02280 * 02281 * 02282 * History: 02283 \***************************************************************************/ 02284 void OrderRects(LPRECT lpR, int nRects) 02285 { 02286 RECT R; 02287 int i,j; 02288 02289 // 02290 // Sort Left to right 02291 // 02292 for (i=0; i<nRects; i++){ 02293 for (j=i+1; (j<nRects) && ((lpR+j)->top == (lpR+i)->top); j++){ 02294 if (((lpR+j)->left < (lpR+i)->left)) { 02295 R = *(lpR+i); 02296 *(lpR+i) = *(lpR+j); 02297 *(lpR+j) = R; 02298 } 02299 } 02300 } 02301 02302 } 02303 02304 /***************************************************************************\ 02305 * MirrorRegion 02306 * 02307 * Mirror a region in a window. This is done by mirroring the rects 02308 * that constitute the region. 'bUseClient' param controls whether 02309 * the region is a client one or not. 02310 * 02311 * History: 02312 \***************************************************************************/ 02313 BOOL MirrorRegion(PWND pwnd, HRGN hrgn, BOOL bUseClient) 02314 { 02315 int nRects, i, nDataSize, Saveleft, cx; 02316 HRGN hrgn2 = NULL; 02317 RECT *lpR; 02318 RGNDATA *lpRgnData; 02319 BOOL bRet = FALSE; 02320 02321 if (TestWF(pwnd, WEFLAYOUTRTL) && hrgn > HRGN_SPECIAL_LAST) { 02322 nDataSize = GreGetRegionData(hrgn, 0, NULL); 02323 if (nDataSize && (lpRgnData = (RGNDATA *)UserAllocPool(nDataSize, TAG_MIRROR))) { 02324 if (GreGetRegionData(hrgn, nDataSize, lpRgnData)) { 02325 nRects = lpRgnData->rdh.nCount; 02326 lpR = (RECT *)lpRgnData->Buffer; 02327 02328 if (bUseClient) { 02329 cx = pwnd->rcClient.right - pwnd->rcClient.left; 02330 } else { 02331 cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 02332 } 02333 02334 Saveleft = lpRgnData->rdh.rcBound.left; 02335 lpRgnData->rdh.rcBound.left = cx - lpRgnData->rdh.rcBound.right; 02336 lpRgnData->rdh.rcBound.right = cx - Saveleft; 02337 02338 02339 for (i=0; i<nRects; i++){ 02340 Saveleft = lpR->left; 02341 lpR->left = cx - lpR->right; 02342 lpR->right = cx - Saveleft; 02343 02344 lpR++; 02345 } 02346 02347 OrderRects((RECT *)lpRgnData->Buffer, nRects); 02348 hrgn2 = GreExtCreateRegion(NULL, nDataSize, lpRgnData); 02349 if (hrgn2) { 02350 GreCombineRgn(hrgn, hrgn2, NULL, RGN_COPY); 02351 GreDeleteObject((HGDIOBJ)hrgn2); 02352 bRet = TRUE; 02353 } 02354 } 02355 02356 //Free mem. 02357 UserFreePool(lpRgnData); 02358 } 02359 } 02360 02361 return bRet; 02362 } 02363 02364 #endif

Generated on Sat May 15 19:39:39 2004 for test by doxygen 1.3.7