2 * PROJECT: ReactOS Win32k subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/ntuser/windc.c
5 * PURPOSE: Window DC management
6 * COPYRIGHT: Copyright 2007 ReactOS Team
10 DBG_DEFAULT_CHANNEL(UserDce
);
12 /* GLOBALS *******************************************************************/
14 /* NOTE: I think we should store this per window station (including GDI objects) */
15 /* Answer: No, use the DCE pMonitor to compare with! */
17 static LIST_ENTRY LEDce
;
18 static INT DCECount
= 0; // Count of DCE in system.
20 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
21 DCX_NORESETATTRS | DCX_LOCKWINDOWUPDATE | \
22 DCX_LAYEREDWIN | DCX_CACHE | DCX_WINDOW | \
25 /* FUNCTIONS *****************************************************************/
32 InitializeListHead(&LEDce
);
33 return STATUS_SUCCESS
;
37 // This should be moved to dc.c or dcutil.c.
40 DceCreateDisplayDC(VOID
)
42 UNICODE_STRING DriverName
= RTL_CONSTANT_STRING(L
"DISPLAY");
44 co_IntGraphicsCheck(TRUE
);
46 return IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
49 /* Returns the DCE pointer from the HDC handle */
52 DceGetDceFromDC(HDC hdc
)
54 LIST_ENTRY
* Entry
= LEDce
.Flink
;
57 while (Entry
!= &LEDce
)
59 dce
= CONTAINING_RECORD(Entry
, DCE
, List
);
70 DceGetVisRgn(PWND Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
74 hVisRgn
= VIS_ComputeVisibleRegion( Window
,
75 0 == (Flags
& DCX_WINDOW
),
76 0 != (Flags
& DCX_CLIPCHILDREN
),
77 0 != (Flags
& DCX_CLIPSIBLINGS
));
79 RetRgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
83 PREGION VisRgn
= REGION_LockRgn(hVisRgn
);
84 IntGdiCombineRgn(RetRgn
, VisRgn
, NULL
, RGN_COPY
);
85 REGION_UnlockRgn(VisRgn
);
86 GreDeleteObject(hVisRgn
);
93 DceAllocDCE(PWND Window OPTIONAL
, DCE_TYPE Type
)
97 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), USERTAG_DCE
);
101 pDce
->hDC
= DceCreateDisplayDC();
104 ExFreePoolWithTag(pDce
, USERTAG_DCE
);
108 TRACE("Alloc DCE's! %d\n",DCECount
);
109 pDce
->hwndCurrent
= (Window
? Window
->head
.h
: NULL
);
110 pDce
->pwndOrg
= Window
;
111 pDce
->pwndClip
= Window
;
112 pDce
->hrgnClip
= NULL
;
113 pDce
->hrgnClipPublic
= NULL
;
114 pDce
->hrgnSavedVis
= NULL
;
115 pDce
->ppiOwner
= NULL
;
117 InsertTailList(&LEDce
, &pDce
->List
);
119 DCU_SetDcUndeletable(pDce
->hDC
);
121 if (Type
== DCE_WINDOW_DC
|| Type
== DCE_CLASS_DC
) // Window DCE have ownership.
123 pDce
->ptiOwner
= GetW32ThreadInfo();
127 TRACE("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %p\n", pDce
->hDC
);
128 GreSetDCOwner(pDce
->hDC
, GDI_OBJ_HMGR_NONE
);
129 pDce
->ptiOwner
= NULL
;
132 if (Type
== DCE_CACHE_DC
)
134 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
138 pDce
->DCXFlags
= DCX_DCEBUSY
;
141 if (Type
== DCE_WINDOW_DC
)
143 if (Window
->style
& WS_CLIPCHILDREN
) pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
144 if (Window
->style
& WS_CLIPSIBLINGS
) pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
152 DceSetDrawable( PWND Window OPTIONAL
,
157 DC
*dc
= DC_LockDc(hDC
);
168 if (Flags
& DCX_WINDOW
)
170 dc
->ptlDCOrig
.x
= Window
->rcWindow
.left
;
171 dc
->ptlDCOrig
.y
= Window
->rcWindow
.top
;
175 dc
->ptlDCOrig
.x
= Window
->rcClient
.left
;
176 dc
->ptlDCOrig
.y
= Window
->rcClient
.top
;
179 dc
->fs
|= DC_FLAG_DIRTY_RAO
;
185 DceDeleteClipRgn(DCE
* Dce
)
187 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
189 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
191 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
193 else if (Dce
->hrgnClip
!= NULL
)
195 GreDeleteObject(Dce
->hrgnClip
);
198 Dce
->hrgnClip
= NULL
;
200 /* Make it dirty so that the vis rgn gets recomputed next time */
201 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
202 IntGdiSetHookFlags(Dce
->hDC
, DCHF_INVALIDATEVISRGN
);
207 DceUpdateVisRgn(DCE
*Dce
, PWND Window
, ULONG Flags
)
209 PREGION RgnVisible
= NULL
;
213 if (Flags
& DCX_PARENTCLIP
)
217 Parent
= Window
->spwndParent
;
224 if (Parent
->style
& WS_CLIPSIBLINGS
)
226 DcxFlags
= DCX_CLIPSIBLINGS
|
227 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
231 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
233 RgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->head
.h
, Flags
);
235 else if (Window
== NULL
)
237 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
238 if (NULL
!= DesktopWindow
)
240 RgnVisible
= IntSysCreateRectpRgnIndirect(&DesktopWindow
->rcWindow
);
249 RgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
253 if (Flags
& DCX_INTERSECTRGN
)
255 if(Dce
->hrgnClip
!= NULL
)
257 PREGION RgnClip
= REGION_LockRgn(Dce
->hrgnClip
);
258 IntGdiCombineRgn(RgnVisible
, RgnVisible
, RgnClip
, RGN_AND
);
259 REGION_UnlockRgn(RgnClip
);
263 if(RgnVisible
!= NULL
)
265 REGION_Delete(RgnVisible
);
267 RgnVisible
= IntSysCreateRectpRgn(0, 0, 0, 0);
270 else if ((Flags
& DCX_EXCLUDERGN
) && Dce
->hrgnClip
!= NULL
)
272 PREGION RgnClip
= REGION_LockRgn(Dce
->hrgnClip
);
273 IntGdiCombineRgn(RgnVisible
, RgnVisible
, RgnClip
, RGN_DIFF
);
274 REGION_UnlockRgn(RgnClip
);
277 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
278 GdiSelectVisRgn(Dce
->hDC
, RgnVisible
);
279 /* Tell GDI driver */
281 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
283 if (RgnVisible
!= NULL
)
285 REGION_Delete(RgnVisible
);
290 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
292 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_INDESTROY
| DCX_DCEEMPTY
| DCX_DCEBUSY
)))
297 /* Restore previous visible region */
300 DceUpdateVisRgn(dce
, dce
->pwndOrg
, dce
->DCXFlags
);
303 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
304 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
306 DceDeleteClipRgn(dce
);
309 if (dce
->DCXFlags
& DCX_CACHE
)
311 if (!(dce
->DCXFlags
& DCX_NORESETATTRS
))
314 if (!IntGdiCleanDC(dce
->hDC
)) return 0;
316 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
318 /* Don't keep around invalidated entries
319 * because SetDCState() disables hVisRgn updates
320 * by removing dirty bit. */
321 dce
->hwndCurrent
= 0;
323 dce
->pwndClip
= NULL
;
324 dce
->DCXFlags
&= DCX_CACHE
;
325 dce
->DCXFlags
|= DCX_DCEEMPTY
;
328 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
329 TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %p \n", dce
->hDC
);
330 if (!GreSetDCOwner(dce
->hDC
, GDI_OBJ_HMGR_NONE
))
332 dce
->ptiOwner
= NULL
; // Reset ownership.
333 dce
->ppiOwner
= NULL
;
335 #if 0 // Need to research and fix before this is a "growing" issue.
339 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
342 if (!(pDCE
->DCXFlags
& DCX_DCEBUSY
))
343 { /* Free the unused cache DCEs. */
344 pDCE
= DceFreeDCE(pDCE
, TRUE
);
349 while (pLE
!= &LEDce
);
353 return 1; // Released!
358 UserGetDCEx(PWND Wnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
363 BOOL UpdateClipOrigin
= FALSE
;
364 BOOL bUpdateVisRgn
= TRUE
;
371 Flags
&= ~DCX_USESTYLE
;
375 if (Flags
& (DCX_WINDOW
| DCX_PARENTCLIP
)) Flags
|= DCX_CACHE
;
377 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set.
378 if (Flags
& DCX_USESTYLE
)
380 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
381 if (!(Flags
& DCX_WINDOW
)) // Not window rectangle
383 if (Wnd
->pcls
->style
& CS_PARENTDC
)
385 Flags
|= DCX_PARENTCLIP
;
388 if (!(Flags
& DCX_CACHE
) && // Not on the cheap wine list.
389 !(Wnd
->pcls
->style
& CS_OWNDC
) )
391 if (!(Wnd
->pcls
->style
& CS_CLASSDC
))
392 // The window is not POWNED or has any CLASS, so we are looking for cheap wine.
396 if (Wnd
->pcls
->pdce
) hDC
= ((PDCE
)Wnd
->pcls
->pdce
)->hDC
;
397 TRACE("We have CLASS!!\n");
401 if (Wnd
->style
& WS_CLIPSIBLINGS
)
403 Flags
|= DCX_CLIPSIBLINGS
;
406 if (Wnd
->style
& WS_CLIPCHILDREN
&&
407 !(Wnd
->style
& WS_MINIMIZE
))
409 Flags
|= DCX_CLIPCHILDREN
;
411 /* If minized with icon in the set, we are forced to be cheap! */
412 if (Wnd
->style
& WS_MINIMIZE
&&
420 if (Wnd
->style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
425 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
427 if (Flags
& DCX_NOCLIPCHILDREN
)
430 Flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
433 Parent
= (Wnd
? Wnd
->spwndParent
: NULL
);
435 if (NULL
== Wnd
|| !(Wnd
->style
& WS_CHILD
) || NULL
== Parent
)
437 Flags
&= ~DCX_PARENTCLIP
;
438 Flags
|= DCX_CLIPSIBLINGS
;
441 /* It seems parent clip is ignored when clipping siblings or children */
442 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
444 if (Flags
& DCX_PARENTCLIP
)
446 if ((Wnd
->style
& WS_VISIBLE
) &&
447 (Parent
->style
& WS_VISIBLE
))
449 Flags
&= ~DCX_CLIPCHILDREN
;
450 if (Parent
->style
& WS_CLIPSIBLINGS
)
452 Flags
|= DCX_CLIPSIBLINGS
;
457 // Window nz, check to see if we still own this or it is just cheap wine tonight.
458 if (!(Flags
& DCX_CACHE
))
460 if ( Wnd
->head
.pti
!= GetW32ThreadInfo())
461 Flags
|= DCX_CACHE
; // Ah~ Not Powned! Forced to be cheap~
464 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
466 if (Flags
& DCX_CACHE
)
467 { // Scan the cheap wine list for our match.
468 DCE
* DceEmpty
= NULL
;
469 DCE
* DceUnused
= NULL
;
470 KeEnterCriticalRegion();
472 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
475 // The reason for this you may ask?
476 // Well, it seems ReactOS calls GetDC without first creating a desktop DC window!
477 // Need to test for null here. Not sure if this is a bug or a feature.
478 // First time use hax, need to use DceAllocDCE during window display init.
481 // The way I understand this, you can have more than one DC per window.
482 // Only one Owned if one was requested and saved and one Cached.
484 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
487 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
491 else if (Dce
->hwndCurrent
== (Wnd
? Wnd
->head
.h
: NULL
) &&
492 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
494 UpdateClipOrigin
= TRUE
;
498 pLE
= Dce
->List
.Flink
;
499 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
501 while (pLE
!= &LEDce
);
502 KeLeaveCriticalRegion();
504 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
508 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
510 if (!Dce
) return NULL
;
512 Dce
->hwndCurrent
= (Wnd
? Wnd
->head
.h
: NULL
);
513 Dce
->pwndOrg
= Dce
->pwndClip
= Wnd
;
515 else // If we are here, we are POWNED or having CLASS.
517 KeEnterCriticalRegion();
519 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
521 { // Check for Window handle than HDC match for CLASS.
522 if (Dce
->hwndCurrent
== Wnd
->head
.h
)
524 bUpdateVisRgn
= FALSE
;
527 if (Dce
->hDC
== hDC
) break;
528 pLE
= Dce
->List
.Flink
;
529 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
531 while (pLE
!= &LEDce
);
532 KeLeaveCriticalRegion();
534 if ( (Flags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) &&
535 (Dce
->DCXFlags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) )
537 DceDeleteClipRgn(Dce
);
540 // First time use hax, need to use DceAllocDCE during window display init.
546 if (!GreIsHandleValid(Dce
->hDC
))
548 ERR("FIXME: Got DCE with invalid hDC! %p\n", Dce
->hDC
);
549 Dce
->hDC
= DceCreateDisplayDC();
550 /* FIXME: Handle error */
553 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
556 * Bump it up! This prevents the random errors in wine dce tests and with
557 * proper bits set in DCX_CACHECOMPAREMASK.
559 * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
560 * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
564 RemoveEntryList(&Dce
->List
);
565 InsertHeadList(&LEDce
, &Dce
->List
);
568 /* Introduced in rev 6691 and modified later. */
569 if ( (Flags
& DCX_INTERSECTUPDATE
) && !ClipRegion
)
571 Flags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
572 Dce
->DCXFlags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
573 ClipRegion
= Wnd
->hrgnUpdate
;
574 bUpdateVisRgn
= TRUE
;
577 if (ClipRegion
== HRGN_WINDOW
)
579 if (!(Flags
& DCX_WINDOW
))
581 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
585 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
587 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
588 bUpdateVisRgn
= TRUE
;
590 else if (ClipRegion
!= NULL
)
592 if (Dce
->hrgnClip
!= NULL
)
594 ERR("Should not be called!!\n");
595 GreDeleteObject(Dce
->hrgnClip
);
596 Dce
->hrgnClip
= NULL
;
598 Dce
->hrgnClip
= ClipRegion
;
599 bUpdateVisRgn
= TRUE
;
602 if (IntGdiSetHookFlags(Dce
->hDC
, DCHF_VALIDATEVISRGN
)) bUpdateVisRgn
= TRUE
;
604 DceSetDrawable(Wnd
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
606 if (bUpdateVisRgn
) DceUpdateVisRgn(Dce
, Wnd
, Flags
);
608 if (Dce
->DCXFlags
& DCX_CACHE
)
610 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %p\n", Dce
->hDC
);
611 // Need to set ownership so Sync dcattr will work.
612 GreSetDCOwner(Dce
->hDC
, GDI_OBJ_HMGR_POWNED
);
613 Dce
->ptiOwner
= GetW32ThreadInfo(); // Set the temp owning
617 Wnd
->ExStyle
& WS_EX_LAYOUTRTL
&&
618 !(Flags
& DCX_KEEPLAYOUT
) )
620 NtGdiSetLayout(Dce
->hDC
, -1, LAYOUT_RTL
);
623 if (Dce
->DCXFlags
& DCX_PROCESSOWNED
)
625 ppi
= PsGetCurrentProcessWin32Process();
626 ppi
->W32PF_flags
|= W32PF_OWNDCCLEANUP
;
627 Dce
->ptiOwner
= NULL
;
634 /***********************************************************************
638 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
644 if (NULL
== pdce
) return NULL
;
646 pLE
= pdce
->List
.Flink
;
647 ret
= CONTAINING_RECORD(pLE
, DCE
, List
);
649 pdce
->DCXFlags
|= DCX_INDESTROY
;
652 GreGetObjectOwner(pdce
->hDC
) != GDI_OBJ_HMGR_POWNED
)
654 TRACE("Change ownership for DCE! -> %p\n" , pdce
);
655 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on.
656 if (GreIsHandleValid(pdce
->hDC
))
658 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
662 ERR("Attempted to change ownership of an DCEhDC %p currently being destroyed!!!\n",
669 if (GreGetObjectOwner(pdce
->hDC
) == GDI_OBJ_HMGR_PUBLIC
)
670 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
673 if (!Hit
) IntGdiDeleteDC(pdce
->hDC
, TRUE
);
675 if (pdce
->hrgnClip
&& !(pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
677 GreDeleteObject(pdce
->hrgnClip
);
678 pdce
->hrgnClip
= NULL
;
681 RemoveEntryList(&pdce
->List
);
683 if (IsListEmpty(&pdce
->List
))
685 ERR("List is Empty! DCE! -> %p\n" , pdce
);
689 ExFreePoolWithTag(pdce
, USERTAG_DCE
);
692 TRACE("Freed DCE's! %d \n", DCECount
);
697 /***********************************************************************
700 * Remove owned DCE and reset unreleased cache DCEs.
703 DceFreeWindowDCE(PWND Window
)
710 ERR("FreeWindowDCE No Entry! %d\n",DCECount
);
715 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
720 ERR("FreeWindowDCE No DCE Pointer!\n");
723 if (IsListEmpty(&pDCE
->List
))
725 ERR("FreeWindowDCE List is Empty!!!!\n");
728 if ( pDCE
->hwndCurrent
== Window
->head
.h
&&
729 !(pDCE
->DCXFlags
& DCX_DCEEMPTY
) )
731 if (!(pDCE
->DCXFlags
& DCX_CACHE
)) /* Owned or Class DCE */
733 if (Window
->pcls
->style
& CS_CLASSDC
) /* Test Class first */
735 if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE */
736 DceDeleteClipRgn(pDCE
);
737 // Update and reset Vis Rgn and clear the dirty bit.
738 // Should release VisRgn than reset it to default.
739 DceUpdateVisRgn(pDCE
, Window
, pDCE
->DCXFlags
);
740 pDCE
->DCXFlags
= DCX_DCEEMPTY
|DCX_CACHE
;
741 pDCE
->hwndCurrent
= 0;
742 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
744 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %p \n",
746 if (!GreSetDCOwner( pDCE
->hDC
, GDI_OBJ_HMGR_NONE
))
748 ERR("Fail Owner Switch hDC-> %p \n", pDCE
->hDC
);
751 /* Do not change owner so thread can clean up! */
753 else if (Window
->pcls
->style
& CS_OWNDC
) /* Owned DCE */
755 pDCE
= DceFreeDCE(pDCE
, FALSE
);
761 ERR("Not POWNED or CLASSDC hwndCurrent -> %p \n",
763 // ASSERT(FALSE); /* bug 5320 */
768 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* Shared cache DCE */
770 /* FIXME: AFAICS we are doing the right thing here so
771 * this should be a TRACE. But this is best left as an ERR
772 * because the 'application error' is likely to come from
773 * another part of Wine (i.e. it's our fault after all).
774 * We should change this to TRACE when ReactOS is more stable
777 ERR("[%p] GetDC() without ReleaseDC()!\n", Window
->head
.h
);
778 DceReleaseDC(pDCE
, FALSE
);
780 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
781 pDCE
->hwndCurrent
= 0;
782 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
785 pLE
= pDCE
->List
.Flink
;
786 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
788 while (pLE
!= &LEDce
);
792 DceFreeClassDCE(HDC hDC
)
797 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
802 if (pDCE
->hDC
== hDC
)
804 pDCE
= DceFreeDCE(pDCE
, TRUE
); // Might have gone cheap!
808 pLE
= pDCE
->List
.Flink
;
809 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
811 while (pLE
!= &LEDce
);
815 DceFreeThreadDCE(PTHREADINFO pti
)
820 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
825 if (pDCE
->ptiOwner
== pti
)
827 if (pDCE
->DCXFlags
& DCX_CACHE
)
829 pDCE
= DceFreeDCE(pDCE
, TRUE
);
834 pLE
= pDCE
->List
.Flink
;
835 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
837 while (pLE
!= &LEDce
);
846 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
851 pDCE
= DceFreeDCE(pDCE
, TRUE
);
854 while (pLE
!= &LEDce
);
858 DceResetActiveDCEs(PWND Window
)
872 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
877 if(pLE
== &LEDce
) break;
878 if (0 == (pDCE
->DCXFlags
& (DCX_DCEEMPTY
|DCX_INDESTROY
)))
880 if (Window
->head
.h
== pDCE
->hwndCurrent
)
882 CurrentWindow
= Window
;
886 if (!pDCE
->hwndCurrent
)
887 CurrentWindow
= NULL
;
889 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
890 if (NULL
== CurrentWindow
)
892 pLE
= pDCE
->List
.Flink
;
893 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
898 if (!GreIsHandleValid(pDCE
->hDC
) ||
899 (dc
= DC_LockDc(pDCE
->hDC
)) == NULL
)
901 pLE
= pDCE
->List
.Flink
;
902 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
905 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
907 if (pDCE
->DCXFlags
& DCX_WINDOW
)
909 DeltaX
= CurrentWindow
->rcWindow
.left
- dc
->ptlDCOrig
.x
;
910 DeltaY
= CurrentWindow
->rcWindow
.top
- dc
->ptlDCOrig
.y
;
911 dc
->ptlDCOrig
.x
= CurrentWindow
->rcWindow
.left
;
912 dc
->ptlDCOrig
.y
= CurrentWindow
->rcWindow
.top
;
916 DeltaX
= CurrentWindow
->rcClient
.left
- dc
->ptlDCOrig
.x
;
917 DeltaY
= CurrentWindow
->rcClient
.top
- dc
->ptlDCOrig
.y
;
918 dc
->ptlDCOrig
.x
= CurrentWindow
->rcClient
.left
;
919 dc
->ptlDCOrig
.y
= CurrentWindow
->rcClient
.top
;
922 if (NULL
!= dc
->dclevel
.prgnClip
)
924 IntGdiOffsetRgn(dc
->dclevel
.prgnClip
, DeltaX
, DeltaY
);
925 dc
->fs
|= DC_FLAG_DIRTY_RAO
;
927 if (NULL
!= pDCE
->hrgnClip
)
929 NtGdiOffsetRgn(pDCE
->hrgnClip
, DeltaX
, DeltaY
);
934 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
935 IntGdiSetHookFlags(pDCE
->hDC
, DCHF_VALIDATEVISRGN
);
937 pLE
= pDCE
->List
.Flink
;
938 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
940 while (pLE
!= &LEDce
);
944 IntWindowFromDC(HDC hDc
)
951 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
956 if (Dce
->DCXFlags
& DCX_INDESTROY
)
959 Ret
= Dce
->hwndCurrent
;
962 pLE
= Dce
->List
.Flink
;
963 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
965 while (pLE
!= &LEDce
);
970 UserReleaseDC(PWND Window
, HDC hDc
, BOOL EndPaint
)
977 TRACE("%p %p\n", Window
, hDc
);
979 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
988 pLE
= dce
->List
.Flink
;
989 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
991 while (pLE
!= &LEDce
);
993 if ( Hit
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
995 nRet
= DceReleaseDC(dce
, EndPaint
);
1002 UserGetWindowDC(PWND Wnd
)
1004 return UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1008 UserGethWnd( HDC hdc
, PWNDOBJ
*pwndo
)
1015 hWnd
= IntWindowFromDC(hdc
);
1017 if (hWnd
&& (Wnd
= UserGetWindowObject(hWnd
)))
1019 pprop
= IntGetProp(Wnd
, AtomWndObj
);
1021 Clip
= (XCLIPOBJ
*)pprop
->Data
;
1023 if ( Clip
&& Clip
->Hwnd
== hWnd
)
1025 if (pwndo
) *pwndo
= &Clip
->WndObj
;
1032 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
1035 DECLARE_RETURN(HDC
);
1037 TRACE("Enter NtUserGetDCEx\n");
1038 UserEnterExclusive();
1040 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
1044 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
1047 TRACE("Leave NtUserGetDCEx, ret=%p\n", _ret_
);
1055 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1056 * entire window, including title bar, menus, and scroll bars. A window device
1057 * context permits painting anywhere in a window, because the origin of the
1058 * device context is the upper-left corner of the window instead of the client
1065 NtUserGetWindowDC(HWND hWnd
)
1067 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1071 NtUserGetDC(HWND hWnd
)
1073 TRACE("NtUGetDC -> %p:%x\n", hWnd
, !hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1075 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1079 * Select logical palette into device context.
1080 * \param hDC handle to the device context
1081 * \param hpal handle to the palette
1082 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1083 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1084 * palette colors in the best way.
1085 * \return old palette
1087 * \todo implement ForceBackground == TRUE
1091 NtUserSelectPalette(HDC hDC
,
1093 BOOL ForceBackground
)
1096 UserEnterExclusive();
1097 // Implement window checks
1098 oldPal
= GdiSelectPalette( hDC
, hpal
, ForceBackground
);