/* rc1 and rc2 are the rectangles where we want to draw or * from where we take pixels. */ VOID FASTCALL DC_vPrepareDCsForBlit( PDC pdcDest, const RECT* rcDest, PDC pdcSrc, const RECT* rcSrc) { PDC pdcFirst, pdcSecond; const RECT *prcFirst, *prcSecond; /* Update brushes */ if (pdcDest->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) DC_vUpdateFillBrush(pdcDest); if (pdcDest->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) DC_vUpdateLineBrush(pdcDest); if(pdcDest->pdcattr->ulDirty_ & DIRTY_TEXT) DC_vUpdateTextBrush(pdcDest); /* Lock them in good order */ if(pdcSrc) { if((ULONG_PTR)pdcDest->ppdev->hsemDevLock >= (ULONG_PTR)pdcSrc->ppdev->hsemDevLock) { pdcFirst = pdcDest; prcFirst = rcDest; pdcSecond = pdcSrc; prcSecond = rcSrc; } else { pdcFirst = pdcSrc; prcFirst = rcSrc; pdcSecond = pdcDest; prcSecond = rcDest; } } else { pdcFirst = pdcDest ; prcFirst = rcDest; pdcSecond = NULL; prcSecond = NULL; } /* Update clipping of dest DC if needed */ if (pdcDest->dctype == DCTYPE_DIRECT) { DCE* dce = DceGetDceFromDC(pdcDest->BaseObject.hHmgr); if (dce) DceUpdateVisRgn(dce, dce->pwndOrg, dce->DCXFlags); } if (pdcDest->fs & DC_FLAG_DIRTY_RAO) CLIPPING_UpdateGCRegion(pdcDest); /* Lock and update first DC */ if(pdcFirst->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcFirst->ppdev->hsemDevLock); /* Update surface if needed */ if(pdcFirst->ppdev->pSurface != pdcFirst->dclevel.pSurface) { DC_vUpdateDC(pdcFirst); } } if(pdcFirst->dctype == DCTYPE_DIRECT) { if (!prcFirst) prcFirst = &pdcFirst->erclClip; MouseSafetyOnDrawStart(pdcFirst->ppdev, prcFirst->left, prcFirst->top, prcFirst->right, prcFirst->bottom) ; } if (!pdcSecond) return; /* Lock and update second DC */ if(pdcSecond->dctype == DCTYPE_DIRECT) { EngAcquireSemaphore(pdcSecond->ppdev->hsemDevLock); /* Update surface if needed */ if(pdcSecond->ppdev->pSurface != pdcSecond->dclevel.pSurface) { DC_vUpdateDC(pdcSecond); } } if(pdcSecond->dctype == DCTYPE_DIRECT) { if (!prcSecond) prcSecond = &pdcSecond->erclClip; MouseSafetyOnDrawStart(pdcSecond->ppdev, prcSecond->left, prcSecond->top, prcSecond->right, prcSecond->bottom) ; } }
VOID FASTCALL DceResetActiveDCEs(PWND Window) { DCE *pDCE; PDC dc; PWND CurrentWindow; INT DeltaX; INT DeltaY; PLIST_ENTRY ListEntry; if (NULL == Window) { return; } ListEntry = LEDce.Flink; while (ListEntry != &LEDce) { pDCE = CONTAINING_RECORD(ListEntry, DCE, List); ListEntry = ListEntry->Flink; if (0 == (pDCE->DCXFlags & (DCX_DCEEMPTY|DCX_INDESTROY))) { if (Window->head.h == pDCE->hwndCurrent) { CurrentWindow = Window; } else { if (!pDCE->hwndCurrent) CurrentWindow = NULL; else CurrentWindow = UserGetWindowObject(pDCE->hwndCurrent); if (NULL == CurrentWindow) { continue; } } if (!GreIsHandleValid(pDCE->hDC) || (dc = DC_LockDc(pDCE->hDC)) == NULL) { continue; } if (Window == CurrentWindow || IntIsChildWindow(Window, CurrentWindow)) { if (pDCE->DCXFlags & DCX_WINDOW) { DeltaX = CurrentWindow->rcWindow.left - dc->ptlDCOrig.x; DeltaY = CurrentWindow->rcWindow.top - dc->ptlDCOrig.y; dc->ptlDCOrig.x = CurrentWindow->rcWindow.left; dc->ptlDCOrig.y = CurrentWindow->rcWindow.top; } else { DeltaX = CurrentWindow->rcClient.left - dc->ptlDCOrig.x; DeltaY = CurrentWindow->rcClient.top - dc->ptlDCOrig.y; dc->ptlDCOrig.x = CurrentWindow->rcClient.left; dc->ptlDCOrig.y = CurrentWindow->rcClient.top; } if (NULL != dc->dclevel.prgnClip) { REGION_bOffsetRgn(dc->dclevel.prgnClip, DeltaX, DeltaY); dc->fs |= DC_FLAG_DIRTY_RAO; } if (NULL != pDCE->hrgnClip) { NtGdiOffsetRgn(pDCE->hrgnClip, DeltaX, DeltaY); } } DC_UnlockDc(dc); DceUpdateVisRgn(pDCE, CurrentWindow, pDCE->DCXFlags); IntGdiSetHookFlags(pDCE->hDC, DCHF_VALIDATEVISRGN); } } }
HDC FASTCALL UserGetDCEx(PWND Wnd OPTIONAL, HANDLE ClipRegion, ULONG Flags) { PWND Parent; ULONG DcxFlags; DCE* Dce = NULL; BOOL UpdateClipOrigin = FALSE; BOOL bUpdateVisRgn = TRUE; HDC hDC = NULL; PPROCESSINFO ppi; PLIST_ENTRY ListEntry; if (NULL == Wnd) { Flags &= ~DCX_USESTYLE; Flags |= DCX_CACHE; } if (Flags & DCX_PARENTCLIP) Flags |= DCX_CACHE; // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set. if (Flags & DCX_USESTYLE) { Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP); if (!(Flags & DCX_WINDOW)) // Not window rectangle { if (Wnd->pcls->style & CS_PARENTDC) { Flags |= DCX_PARENTCLIP; } if (!(Flags & DCX_CACHE) && // Not on the cheap wine list. !(Wnd->pcls->style & CS_OWNDC) ) { if (!(Wnd->pcls->style & CS_CLASSDC)) // The window is not POWNED or has any CLASS, so we are looking for cheap wine. Flags |= DCX_CACHE; else { if (Wnd->pcls->pdce) hDC = ((PDCE)Wnd->pcls->pdce)->hDC; TRACE("We have CLASS!!\n"); } } if (Wnd->style & WS_CLIPSIBLINGS) { Flags |= DCX_CLIPSIBLINGS; } if (Wnd->style & WS_CLIPCHILDREN && !(Wnd->style & WS_MINIMIZE)) { Flags |= DCX_CLIPCHILDREN; } /* If minized with icon in the set, we are forced to be cheap! */ if (Wnd->style & WS_MINIMIZE && Wnd->pcls->spicn) { Flags |= DCX_CACHE; } } else { if (Wnd->style & WS_CLIPSIBLINGS) Flags |= DCX_CLIPSIBLINGS; Flags |= DCX_CACHE; } } if (Flags & DCX_WINDOW) Flags &= ~DCX_CLIPCHILDREN; if (Flags & DCX_NOCLIPCHILDREN) { Flags |= DCX_CACHE; Flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN); } Parent = (Wnd ? Wnd->spwndParent : NULL); if (NULL == Wnd || !(Wnd->style & WS_CHILD) || NULL == Parent) { Flags &= ~DCX_PARENTCLIP; Flags |= DCX_CLIPSIBLINGS; } /* It seems parent clip is ignored when clipping siblings or children */ if (Flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) Flags &= ~DCX_PARENTCLIP; if (Flags & DCX_PARENTCLIP) { if ((Wnd->style & WS_VISIBLE) && (Parent->style & WS_VISIBLE)) { Flags &= ~DCX_CLIPCHILDREN; if (Parent->style & WS_CLIPSIBLINGS) { Flags |= DCX_CLIPSIBLINGS; } } } // Window nz, check to see if we still own this or it is just cheap wine tonight. if (!(Flags & DCX_CACHE)) { if ( Wnd->head.pti != GetW32ThreadInfo()) Flags |= DCX_CACHE; // Ah~ Not Powned! Forced to be cheap~ } DcxFlags = Flags & DCX_CACHECOMPAREMASK; if (Flags & DCX_CACHE) { // Scan the cheap wine list for our match. DCE* DceEmpty = NULL; DCE* DceUnused = NULL; KeEnterCriticalRegion(); ListEntry = LEDce.Flink; while (ListEntry != &LEDce) { Dce = CONTAINING_RECORD(ListEntry, DCE, List); ListEntry = ListEntry->Flink; // // The way I understand this, you can have more than one DC per window. // Only one Owned if one was requested and saved and one Cached. // if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE) { DceUnused = Dce; if (Dce->DCXFlags & DCX_DCEEMPTY) { DceEmpty = Dce; } else if (Dce->hwndCurrent == (Wnd ? Wnd->head.h : NULL) && ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags)) { UpdateClipOrigin = TRUE; break; } } Dce = NULL; // Loop issue? } KeLeaveCriticalRegion(); Dce = (DceEmpty == NULL) ? DceUnused : DceEmpty; if (Dce == NULL) { Dce = DceAllocDCE(NULL, DCE_CACHE_DC); } if (Dce == NULL) return NULL; Dce->hwndCurrent = (Wnd ? Wnd->head.h : NULL); Dce->pwndOrg = Dce->pwndClip = Wnd; } else // If we are here, we are POWNED or having CLASS. { KeEnterCriticalRegion(); ListEntry = LEDce.Flink; while (ListEntry != &LEDce) { Dce = CONTAINING_RECORD(ListEntry, DCE, List); ListEntry = ListEntry->Flink; // Skip Cache DCE entries. if (!(Dce->DCXFlags & DCX_CACHE)) { // Check for Window handle than HDC match for CLASS. if (Dce->hwndCurrent == Wnd->head.h) { bUpdateVisRgn = FALSE; break; } else if (Dce->hDC == hDC) break; } Dce = NULL; // Loop issue? } KeLeaveCriticalRegion(); if (Dce == NULL) { return(NULL); } if ( (Flags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) && (Dce->DCXFlags & (DCX_INTERSECTRGN|DCX_EXCLUDERGN)) ) { DceDeleteClipRgn(Dce); } } // First time use hax, need to use DceAllocDCE during window display init. if (NULL == Dce) { return(NULL); } if (!GreIsHandleValid(Dce->hDC)) { ERR("FIXME: Got DCE with invalid hDC! %p\n", Dce->hDC); Dce->hDC = DceCreateDisplayDC(); /* FIXME: Handle error */ } Dce->DCXFlags = Flags | DCX_DCEBUSY; /* * Bump it up! This prevents the random errors in wine dce tests and with * proper bits set in DCX_CACHECOMPAREMASK. * Reference: * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html */ RemoveEntryList(&Dce->List); InsertHeadList(&LEDce, &Dce->List); /* Introduced in rev 6691 and modified later. */ if ( (Flags & DCX_INTERSECTUPDATE) && !ClipRegion ) { Flags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN; Dce->DCXFlags |= DCX_INTERSECTRGN | DCX_KEEPCLIPRGN; ClipRegion = Wnd->hrgnUpdate; bUpdateVisRgn = TRUE; } if (ClipRegion == HRGN_WINDOW) { if (!(Flags & DCX_WINDOW)) { Dce->hrgnClip = NtGdiCreateRectRgn( Wnd->rcClient.left, Wnd->rcClient.top, Wnd->rcClient.right, Wnd->rcClient.bottom); } else { Dce->hrgnClip = NtGdiCreateRectRgn( Wnd->rcWindow.left, Wnd->rcWindow.top, Wnd->rcWindow.right, Wnd->rcWindow.bottom); } Dce->DCXFlags &= ~DCX_KEEPCLIPRGN; bUpdateVisRgn = TRUE; } else if (ClipRegion != NULL) { if (Dce->hrgnClip != NULL) { ERR("Should not be called!!\n"); GreDeleteObject(Dce->hrgnClip); Dce->hrgnClip = NULL; } Dce->hrgnClip = ClipRegion; bUpdateVisRgn = TRUE; } if (IntGdiSetHookFlags(Dce->hDC, DCHF_VALIDATEVISRGN)) bUpdateVisRgn = TRUE; DceSetDrawable(Wnd, Dce->hDC, Flags, UpdateClipOrigin); if (bUpdateVisRgn) DceUpdateVisRgn(Dce, Wnd, Flags); if (Dce->DCXFlags & DCX_CACHE) { TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %p\n", Dce->hDC); // Need to set ownership so Sync dcattr will work. GreSetDCOwner(Dce->hDC, GDI_OBJ_HMGR_POWNED); Dce->ptiOwner = GetW32ThreadInfo(); // Set the temp owning } if ( Wnd && Wnd->ExStyle & WS_EX_LAYOUTRTL && !(Flags & DCX_KEEPLAYOUT) ) { NtGdiSetLayout(Dce->hDC, -1, LAYOUT_RTL); } if (Dce->DCXFlags & DCX_PROCESSOWNED) { ppi = PsGetCurrentProcessWin32Process(); ppi->W32PF_flags |= W32PF_OWNDCCLEANUP; Dce->ptiOwner = NULL; Dce->ppiOwner = ppi; } return(Dce->hDC); }
/*********************************************************************** * DceFreeWindowDCE * * Remove owned DCE and reset unreleased cache DCEs. */ void FASTCALL DceFreeWindowDCE(PWND Window) { PDCE pDCE; PLIST_ENTRY ListEntry; if (DCECount <= 0) { ERR("FreeWindowDCE No Entry! %d\n",DCECount); return; } ListEntry = LEDce.Flink; while (ListEntry != &LEDce) { pDCE = CONTAINING_RECORD(ListEntry, DCE, List); ListEntry = ListEntry->Flink; if ( pDCE->hwndCurrent == Window->head.h && !(pDCE->DCXFlags & DCX_DCEEMPTY) ) { if (!(pDCE->DCXFlags & DCX_CACHE)) /* Owned or Class DCE */ { if (Window->pcls->style & CS_CLASSDC) /* Test Class first */ { if (pDCE->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) /* Class DCE */ DceDeleteClipRgn(pDCE); // Update and reset Vis Rgn and clear the dirty bit. // Should release VisRgn than reset it to default. DceUpdateVisRgn(pDCE, Window, pDCE->DCXFlags); pDCE->DCXFlags = DCX_DCEEMPTY|DCX_CACHE; pDCE->hwndCurrent = 0; pDCE->pwndOrg = pDCE->pwndClip = NULL; TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %p \n", pDCE->hDC); if (!GreSetDCOwner( pDCE->hDC, GDI_OBJ_HMGR_NONE)) { ERR("Fail Owner Switch hDC-> %p \n", pDCE->hDC); break; } /* Do not change owner so thread can clean up! */ } else if (Window->pcls->style & CS_OWNDC) /* Owned DCE */ { DceFreeDCE(pDCE, FALSE); continue; } else { ERR("Not POWNED or CLASSDC hwndCurrent -> %p \n", pDCE->hwndCurrent); // ASSERT(FALSE); /* bug 5320 */ } } else { if (pDCE->DCXFlags & DCX_DCEBUSY) /* Shared cache DCE */ { /* FIXME: AFAICS we are doing the right thing here so * this should be a TRACE. But this is best left as an ERR * because the 'application error' is likely to come from * another part of Wine (i.e. it's our fault after all). * We should change this to TRACE when ReactOS is more stable * (for 1.0?). */ ERR("[%p] GetDC() without ReleaseDC()!\n", Window->head.h); DceReleaseDC(pDCE, FALSE); } pDCE->DCXFlags |= DCX_DCEEMPTY; pDCE->hwndCurrent = 0; pDCE->pwndOrg = pDCE->pwndClip = NULL; } } } }
static INT FASTCALL DceReleaseDC(DCE* dce, BOOL EndPaint) { if (DCX_DCEBUSY != (dce->DCXFlags & (DCX_INDESTROY | DCX_DCEEMPTY | DCX_DCEBUSY))) { return 0; } /* Restore previous visible region */ if (EndPaint) { DceUpdateVisRgn(dce, dce->pwndOrg, dce->DCXFlags); } if ((dce->DCXFlags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) && ((dce->DCXFlags & DCX_CACHE) || EndPaint)) { DceDeleteClipRgn(dce); } if (dce->DCXFlags & DCX_CACHE) { if (!(dce->DCXFlags & DCX_NORESETATTRS)) { // Clean the DC if (!IntGdiCleanDC(dce->hDC)) return 0; if (dce->DCXFlags & DCX_DCEDIRTY) { /* Don't keep around invalidated entries * because SetDCState() disables hVisRgn updates * by removing dirty bit. */ dce->hwndCurrent = 0; dce->pwndOrg = NULL; dce->pwndClip = NULL; dce->DCXFlags &= DCX_CACHE; dce->DCXFlags |= DCX_DCEEMPTY; } } dce->DCXFlags &= ~DCX_DCEBUSY; TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %p \n", dce->hDC); if (!GreSetDCOwner(dce->hDC, GDI_OBJ_HMGR_NONE)) return 0; dce->ptiOwner = NULL; // Reset ownership. dce->ppiOwner = NULL; #if 0 // Need to research and fix before this is a "growing" issue. if (++DCECache > 32) { ListEntry = LEDce.Flink; while (ListEntry != &LEDce) { pDCE = CONTAINING_RECORD(ListEntry, DCE, List); ListEntry = ListEntry->Flink; if (!(pDCE->DCXFlags & DCX_DCEBUSY)) { /* Free the unused cache DCEs. */ DceFreeDCE(pDCE, TRUE); } } } #endif } return 1; // Released! }