2 * PROJECT: ReactOS Kernel
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
10 /* INCLUDES ******************************************************************/
17 int FASTCALL
CLIPPING_UpdateGCRegion(DC
* Dc
);
19 /* GLOBALS *******************************************************************/
21 /* NOTE - I think we should store this per window station (including gdi objects) */
22 /* Answer: No, use the DCE pMonitor to compare with! */
24 static LIST_ENTRY LEDce
;
25 static INT DCECount
= 0; // Count of DCE in system.
27 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
28 DCX_NORESETATTRS | DCX_LOCKWINDOWUPDATE | \
29 DCX_LAYEREDWIN | DCX_CACHE | DCX_WINDOW | \
32 /* FUNCTIONS *****************************************************************/
35 // This should be moved to dc.c or dcutil.c.
38 DceCreateDisplayDC(VOID
)
41 UNICODE_STRING DriverName
;
42 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
43 hDC
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
45 // If NULL, first time through! Build the default window dc!
47 if (hDC
&& !defaultDCstate
) // Ultra HAX! Dedicated to GvG!
48 { // This is a cheesy way to do this.
49 PDC dc
= DC_LockDc ( hDC
);
50 defaultDCstate
= ExAllocatePoolWithTag(PagedPool
, sizeof(DC
), TAG_DC
);
51 RtlZeroMemory(defaultDCstate
, sizeof(DC
));
52 defaultDCstate
->pdcattr
= &defaultDCstate
->dcattr
;
53 DC_vCopyState(dc
, defaultDCstate
, TRUE
);
55 InitializeListHead(&LEDce
);
62 DceGetVisRgn(PWINDOW_OBJECT Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
66 VisRgn
= VIS_ComputeVisibleRegion( Window
,
67 0 == (Flags
& DCX_WINDOW
),
68 0 != (Flags
& DCX_CLIPCHILDREN
),
69 0 != (Flags
& DCX_CLIPSIBLINGS
));
72 VisRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
78 DceAllocDCE(PWINDOW_OBJECT Window OPTIONAL
, DCE_TYPE Type
)
83 if (Window
) Wnd
= Window
->Wnd
;
85 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), TAG_PDCE
);
89 pDce
->hDC
= DceCreateDisplayDC();
92 ExFreePoolWithTag(pDce
, TAG_PDCE
);
96 DPRINT("Alloc DCE's! %d\n",DCECount
);
97 pDce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
100 pDce
->hrgnClip
= NULL
;
101 pDce
->hrgnClipPublic
= NULL
;
102 pDce
->hrgnSavedVis
= NULL
;
103 pDce
->ppiOwner
= NULL
;
105 InsertTailList(&LEDce
, &pDce
->List
);
107 DCU_SetDcUndeletable(pDce
->hDC
);
109 if (Type
== DCE_WINDOW_DC
|| Type
== DCE_CLASS_DC
) //Window DCE have ownership.
111 pDce
->ptiOwner
= GetW32ThreadInfo();
115 DPRINT("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %x\n", pDce
->hDC
);
116 IntGdiSetDCOwnerEx( pDce
->hDC
, GDI_OBJ_HMGR_NONE
, FALSE
);
117 pDce
->ptiOwner
= NULL
;
120 if (Type
== DCE_CACHE_DC
)
122 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
126 pDce
->DCXFlags
= DCX_DCEBUSY
;
129 if (Type
== DCE_WINDOW_DC
)
131 if (Wnd
->style
& WS_CLIPCHILDREN
) pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
132 if (Wnd
->style
& WS_CLIPSIBLINGS
) pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
140 DceSetDrawable( PWINDOW_OBJECT Window OPTIONAL
,
146 DC
*dc
= DC_LockDc(hDC
);
158 if (Flags
& DCX_WINDOW
)
160 dc
->ptlDCOrig
.x
= Wnd
->rcWindow
.left
;
161 dc
->ptlDCOrig
.y
= Wnd
->rcWindow
.top
;
165 dc
->ptlDCOrig
.x
= Wnd
->rcClient
.left
;
166 dc
->ptlDCOrig
.y
= Wnd
->rcClient
.top
;
174 DceDeleteClipRgn(DCE
* Dce
)
176 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
178 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
180 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
182 else if (Dce
->hrgnClip
!= NULL
)
184 GDIOBJ_FreeObjByHandle(Dce
->hrgnClip
, GDI_OBJECT_TYPE_REGION
|GDI_OBJECT_TYPE_SILENT
);
187 Dce
->hrgnClip
= NULL
;
189 /* make it dirty so that the vis rgn gets recomputed next time */
190 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
194 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
196 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_INDESTROY
| DCX_DCEEMPTY
| DCX_DCEBUSY
)))
201 /* restore previous visible region */
202 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
203 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
205 DceDeleteClipRgn(dce
);
208 if (dce
->DCXFlags
& DCX_CACHE
)
210 if (!(dce
->DCXFlags
& DCX_NORESETATTRS
))
212 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
213 IntGdiSetHookFlags(dce
->hDC
, DCHF_VALIDATEVISRGN
);
216 if (!IntGdiCleanDC(dce
->hDC
)) return 0;
218 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
220 /* don't keep around invalidated entries
221 * because SetDCState() disables hVisRgn updates
222 * by removing dirty bit. */
223 dce
->hwndCurrent
= 0;
224 dce
->DCXFlags
&= DCX_CACHE
;
225 dce
->DCXFlags
|= DCX_DCEEMPTY
;
228 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
229 DPRINT("Exit!!!!! DCX_CACHE!!!!!! hDC-> %x \n", dce
->hDC
);
230 if (!IntGdiSetDCOwnerEx( dce
->hDC
, GDI_OBJ_HMGR_NONE
, FALSE
))
232 dce
->ptiOwner
= NULL
; // Reset ownership.
233 dce
->ppiOwner
= NULL
;
235 #if 0 // Need to research and fix before this is a "growing" issue.
239 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
242 if (!(pDCE
->DCXFlags
& DCX_DCEBUSY
))
243 { /* Free the unused cache DCEs. */
244 pDCE
= DceFreeDCE(pDCE
, TRUE
);
249 while (pLE
!= &LEDce
);
253 return 1; // Released!
257 DceUpdateVisRgn(DCE
*Dce
, PWINDOW_OBJECT Window
, ULONG Flags
)
259 HANDLE hRgnVisible
= NULL
;
261 PWINDOW_OBJECT DesktopWindow
;
263 if (Flags
& DCX_PARENTCLIP
)
265 PWINDOW_OBJECT Parent
;
268 Parent
= Window
->spwndParent
;
275 ParentWnd
= Parent
->Wnd
;
277 if (ParentWnd
->style
& WS_CLIPSIBLINGS
)
279 DcxFlags
= DCX_CLIPSIBLINGS
|
280 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
284 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
286 hRgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->hSelf
, Flags
);
288 else if (Window
== NULL
)
290 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
291 if (NULL
!= DesktopWindow
)
293 hRgnVisible
= IntSysCreateRectRgnIndirect(&DesktopWindow
->Wnd
->rcWindow
);
302 hRgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
306 if (Flags
& DCX_INTERSECTRGN
)
308 if(Dce
->hrgnClip
!= NULL
)
310 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_AND
);
314 if(hRgnVisible
!= NULL
)
316 REGION_FreeRgnByHandle(hRgnVisible
);
318 hRgnVisible
= IntSysCreateRectRgn(0, 0, 0, 0);
321 else if (Flags
& DCX_EXCLUDERGN
&& Dce
->hrgnClip
!= NULL
)
323 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_DIFF
);
326 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
327 GdiSelectVisRgn(Dce
->hDC
, hRgnVisible
);
331 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
334 if (hRgnVisible
!= NULL
)
336 REGION_FreeRgnByHandle(hRgnVisible
);
341 UserGetDCEx(PWINDOW_OBJECT Window OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
343 PWINDOW_OBJECT Parent
;
346 BOOL UpdateClipOrigin
= FALSE
;
354 Flags
&= ~DCX_USESTYLE
;
360 if (Flags
& (DCX_WINDOW
| DCX_PARENTCLIP
)) Flags
|= DCX_CACHE
;
362 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set.
363 if (Flags
& DCX_USESTYLE
)
365 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
366 if (!(Flags
& DCX_WINDOW
)) // not window rectangle
368 if (Wnd
->pcls
->style
& CS_PARENTDC
)
370 Flags
|= DCX_PARENTCLIP
;
373 if (!(Flags
& DCX_CACHE
) && // Not on the cheap wine list.
374 !(Wnd
->pcls
->style
& CS_OWNDC
) )
376 if (!(Wnd
->pcls
->style
& CS_CLASSDC
))
377 // The window is not POWNED or has any CLASS, so we are looking for cheap wine.
381 if (Wnd
->pcls
->pdce
) hDC
= ((PDCE
)Wnd
->pcls
->pdce
)->hDC
;
382 DPRINT("We have CLASS!!\n");
385 /* else // For Testing!
387 DPRINT1("We have POWNER!!\n");
388 if (Window->Dce) DPRINT1("We have POWNER with DCE!!\n");
391 if (Wnd
->style
& WS_CLIPSIBLINGS
)
393 Flags
|= DCX_CLIPSIBLINGS
;
396 if (Wnd
->style
& WS_CLIPCHILDREN
&&
397 !(Wnd
->style
& WS_MINIMIZE
))
399 Flags
|= DCX_CLIPCHILDREN
;
401 /* If minized with icon in the set, we are forced to be cheap! */
402 if (Wnd
->style
& WS_MINIMIZE
&&
410 if (Wnd
->style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
415 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
417 if (Flags
& DCX_NOCLIPCHILDREN
)
420 Flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
423 Parent
= (Window
? Window
->spwndParent
: NULL
);
425 if (NULL
== Window
|| !(Wnd
->style
& WS_CHILD
) || NULL
== Parent
)
427 Flags
&= ~DCX_PARENTCLIP
;
428 Flags
|= DCX_CLIPSIBLINGS
;
431 /* it seems parent clip is ignored when clipping siblings or children */
432 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
434 if (Flags
& DCX_PARENTCLIP
)
436 if ((Wnd
->style
& WS_VISIBLE
) &&
437 (Parent
->Wnd
->style
& WS_VISIBLE
))
439 Flags
&= ~DCX_CLIPCHILDREN
;
440 if (Parent
->Wnd
->style
& WS_CLIPSIBLINGS
)
442 Flags
|= DCX_CLIPSIBLINGS
;
447 // Window nz, check to see if we still own this or it is just cheap wine tonight.
448 if (!(Flags
& DCX_CACHE
))
450 if ( Wnd
->head
.pti
!= GetW32ThreadInfo())
451 Flags
|= DCX_CACHE
; // Ah~ Not Powned! Forced to be cheap~
454 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
456 if (Flags
& DCX_CACHE
)
457 { // Scan the cheap wine list for our match.
458 DCE
* DceEmpty
= NULL
;
459 DCE
* DceUnused
= NULL
;
460 KeEnterCriticalRegion();
462 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
465 // The reason for this you may ask?
466 // Well, it seems ReactOS calls GetDC with out first creating a desktop DC window!
467 // Need to test for null here. Not sure if this is a bug or a feature.
468 // First time use hax, need to use DceAllocDCE during window display init.
471 // The way I understand this, you can have more than one DC per window.
472 // Only one Owned if one was requested and saved and one Cached.
474 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
477 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
481 else if (Dce
->hwndCurrent
== (Window
? Window
->hSelf
: NULL
) &&
482 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
484 UpdateClipOrigin
= TRUE
;
488 pLE
= Dce
->List
.Flink
;
489 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
491 while (pLE
!= &LEDce
);
492 KeLeaveCriticalRegion();
494 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
498 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
500 if (!Dce
) return NULL
;
502 Dce
->hwndCurrent
= (Window
? Window
->hSelf
: NULL
);
504 else // If we are here, we are POWNED or having CLASS.
506 KeEnterCriticalRegion();
508 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
510 { // Check for Window handle than HDC match for CLASS.
511 if ((Dce
->hwndCurrent
== Window
->hSelf
) ||
514 pLE
= Dce
->List
.Flink
;
515 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
517 while (pLE
!= &LEDce
);
518 KeLeaveCriticalRegion();
520 if ( (Flags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) &&
521 (Dce
->DCXFlags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) )
523 DceDeleteClipRgn(Dce
);
526 // First time use hax, need to use DceAllocDCE during window display init.
532 if (!GDIOBJ_ValidateHandle(Dce
->hDC
, GDI_OBJECT_TYPE_DC
))
534 DPRINT1("FIXME: Got DCE with invalid hDC! 0x%x\n", Dce
->hDC
);
535 Dce
->hDC
= DceCreateDisplayDC();
536 /* FIXME: Handle error */
539 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
542 Bump it up! This prevents the random errors in wine dce tests and with
543 proper bits set in DCX_CACHECOMPAREMASK.
545 http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
546 http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
550 RemoveEntryList(&Dce
->List
);
551 InsertHeadList(&LEDce
, &Dce
->List
);
554 /* Introduced in rev 6691 and modified later. */
555 if ( (Flags
& DCX_INTERSECTUPDATE
) && !ClipRegion
)
557 Flags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
558 Dce
->DCXFlags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
559 ClipRegion
= Window
->hrgnUpdate
;
562 if (ClipRegion
== (HRGN
) 1)
564 if (!(Flags
& DCX_WINDOW
))
566 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcClient
);
570 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Window
->Wnd
->rcWindow
);
572 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
574 else if (ClipRegion
!= NULL
)
576 if (Dce
->hrgnClip
!= NULL
)
578 DPRINT1("Should not be called!!\n");
579 GDIOBJ_FreeObjByHandle(Dce
->hrgnClip
, GDI_OBJECT_TYPE_REGION
|GDI_OBJECT_TYPE_SILENT
);
580 Dce
->hrgnClip
= NULL
;
582 Dce
->hrgnClip
= ClipRegion
;
585 DceSetDrawable(Window
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
587 DceUpdateVisRgn(Dce
, Window
, Flags
);
589 if (Dce
->DCXFlags
& DCX_CACHE
)
591 DPRINT("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce
->hDC
);
592 // Need to set ownership so Sync dcattr will work.
593 IntGdiSetDCOwnerEx( Dce
->hDC
, GDI_OBJ_HMGR_POWNED
, FALSE
);
594 Dce
->ptiOwner
= GetW32ThreadInfo(); // Set the temp owning
598 Wnd
->ExStyle
& WS_EX_LAYOUTRTL
&&
599 !(Flags
& DCX_KEEPLAYOUT
) )
601 NtGdiSetLayout(Dce
->hDC
, -1, LAYOUT_RTL
);
604 if (Dce
->DCXFlags
& DCX_PROCESSOWNED
)
606 ppi
= PsGetCurrentProcessWin32Process();
607 ppi
->W32PF_flags
|= W32PF_OWNDCCLEANUP
;
608 Dce
->ptiOwner
= NULL
;
615 /***********************************************************************
619 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
625 if (NULL
== pdce
) return NULL
;
627 pLE
= pdce
->List
.Flink
;
628 ret
= CONTAINING_RECORD(pLE
, DCE
, List
);
630 pdce
->DCXFlags
|= DCX_INDESTROY
;
632 if (Force
&& !GDIOBJ_OwnedByCurrentProcess(pdce
->hDC
))
634 DPRINT("Change ownership for DCE! -> %x\n" , pdce
);
635 // Note: Windows sets W32PF_OWNDCCLEANUP and moves on.
636 if (!IsObjectDead((HGDIOBJ
) pdce
->hDC
))
638 DC_SetOwnership( pdce
->hDC
, PsGetCurrentProcess());
642 DPRINT1("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",pdce
->hDC
);
648 if (!GreGetObjectOwner(pdce
->hDC
, GDIObjType_DC_TYPE
))
649 DC_SetOwnership( pdce
->hDC
, PsGetCurrentProcess());
652 if (!Hit
) IntGdiDeleteDC(pdce
->hDC
, TRUE
);
654 if (pdce
->hrgnClip
&& !(pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
656 GDIOBJ_FreeObjByHandle(pdce
->hrgnClip
, GDI_OBJECT_TYPE_REGION
|GDI_OBJECT_TYPE_SILENT
);
657 pdce
->hrgnClip
= NULL
;
660 RemoveEntryList(&pdce
->List
);
662 if (IsListEmpty(&pdce
->List
))
664 DPRINT1("List is Empty! DCE! -> %x\n" , pdce
);
668 ExFreePoolWithTag(pdce
, TAG_PDCE
);
671 DPRINT("Freed DCE's! %d \n", DCECount
);
676 /***********************************************************************
679 * Remove owned DCE and reset unreleased cache DCEs.
682 DceFreeWindowDCE(PWINDOW_OBJECT Window
)
689 DPRINT1("FreeWindowDCE No Entry! %d\n",DCECount
);
694 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
699 DPRINT1("FreeWindowDCE No DCE Pointer!\n");
702 if (IsListEmpty(&pDCE
->List
))
704 DPRINT1("FreeWindowDCE List is Empty!!!!\n");
707 if ( pDCE
->hwndCurrent
== Window
->hSelf
&&
708 !(pDCE
->DCXFlags
& DCX_DCEEMPTY
) )
710 if (!(pDCE
->DCXFlags
& DCX_CACHE
)) /* owned or Class DCE*/
712 if (Window
->Wnd
->pcls
->style
& CS_CLASSDC
) /* Test Class first */
714 if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE*/
715 DceDeleteClipRgn(pDCE
);
716 // Update and reset Vis Rgn and clear the dirty bit.
717 // Should release VisRgn than reset it to default.
718 DceUpdateVisRgn(pDCE
, Window
, pDCE
->DCXFlags
);
719 pDCE
->DCXFlags
= DCX_DCEEMPTY
|DCX_CACHE
;
720 pDCE
->hwndCurrent
= 0;
722 DPRINT("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %x \n", pDCE
->hDC
);
723 if (!IntGdiSetDCOwnerEx( pDCE
->hDC
, GDI_OBJ_HMGR_NONE
, FALSE
))
725 DPRINT1("Fail Owner Switch hDC-> %x \n", pDCE
->hDC
);
728 /* Do not change owner so thread can clean up! */
730 else if (Window
->Wnd
->pcls
->style
& CS_OWNDC
) /* owned DCE*/
732 pDCE
= DceFreeDCE(pDCE
, FALSE
);
738 DPRINT1("Not POWNED or CLASSDC hwndCurrent -> %x \n", pDCE
->hwndCurrent
);
744 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* shared cache DCE */
746 /* FIXME: AFAICS we are doing the right thing here so
747 * this should be a DPRINT. But this is best left as an ERR
748 * because the 'application error' is likely to come from
749 * another part of Wine (i.e. it's our fault after all).
750 * We should change this to DPRINT when ReactOS is more stable
753 DPRINT1("[%p] GetDC() without ReleaseDC()!\n", Window
->hSelf
);
754 DceReleaseDC(pDCE
, FALSE
);
756 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
757 pDCE
->hwndCurrent
= 0;
760 pLE
= pDCE
->List
.Flink
;
761 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
763 while (pLE
!= &LEDce
);
767 DceFreeClassDCE(HDC hDC
)
772 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
777 if (pDCE
->hDC
== hDC
)
779 pDCE
= DceFreeDCE(pDCE
, TRUE
); // Might have gone cheap!
783 pLE
= pDCE
->List
.Flink
;
784 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
786 while (pLE
!= &LEDce
);
790 DceFreeThreadDCE(PTHREADINFO pti
)
795 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
800 if (pDCE
->ptiOwner
== pti
)
802 if (pDCE
->DCXFlags
& DCX_CACHE
)
804 pDCE
= DceFreeDCE(pDCE
, TRUE
);
809 pLE
= pDCE
->List
.Flink
;
810 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
812 while (pLE
!= &LEDce
);
821 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
826 pDCE
= DceFreeDCE(pDCE
, TRUE
);
829 while (pLE
!= &LEDce
);
833 DceResetActiveDCEs(PWINDOW_OBJECT Window
)
837 PWINDOW_OBJECT CurrentWindow
;
847 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
848 if(!pDCE
) return; // Another null test!
852 if(pLE
== &LEDce
) break;
853 if (0 == (pDCE
->DCXFlags
& (DCX_DCEEMPTY
|DCX_INDESTROY
)))
855 if (Window
->hSelf
== pDCE
->hwndCurrent
)
857 CurrentWindow
= Window
;
861 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
862 if (NULL
== CurrentWindow
)
864 pLE
= pDCE
->List
.Flink
;
865 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
870 if (!GDIOBJ_ValidateHandle(pDCE
->hDC
, GDI_OBJECT_TYPE_DC
) ||
871 (dc
= DC_LockDc(pDCE
->hDC
)) == NULL
)
873 pLE
= pDCE
->List
.Flink
;
874 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
877 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
879 if (pDCE
->DCXFlags
& DCX_WINDOW
)
881 DeltaX
= CurrentWindow
->Wnd
->rcWindow
.left
- dc
->ptlDCOrig
.x
;
882 DeltaY
= CurrentWindow
->Wnd
->rcWindow
.top
- dc
->ptlDCOrig
.y
;
883 dc
->ptlDCOrig
.x
= CurrentWindow
->Wnd
->rcWindow
.left
;
884 dc
->ptlDCOrig
.y
= CurrentWindow
->Wnd
->rcWindow
.top
;
888 DeltaX
= CurrentWindow
->Wnd
->rcClient
.left
- dc
->ptlDCOrig
.x
;
889 DeltaY
= CurrentWindow
->Wnd
->rcClient
.top
- dc
->ptlDCOrig
.y
;
890 dc
->ptlDCOrig
.x
= CurrentWindow
->Wnd
->rcClient
.left
;
891 dc
->ptlDCOrig
.y
= CurrentWindow
->Wnd
->rcClient
.top
;
893 if (NULL
!= dc
->rosdc
.hClipRgn
)
895 NtGdiOffsetRgn(dc
->rosdc
.hClipRgn
, DeltaX
, DeltaY
);
896 CLIPPING_UpdateGCRegion(dc
);
898 if (NULL
!= pDCE
->hrgnClip
)
900 NtGdiOffsetRgn(pDCE
->hrgnClip
, DeltaX
, DeltaY
);
905 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
907 if (Window
->hSelf
!= pDCE
->hwndCurrent
)
909 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
910 // UserDerefObject(CurrentWindow);
913 pLE
= pDCE
->List
.Flink
;
914 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
916 while (pLE
!= &LEDce
);
920 IntWindowFromDC(HDC hDc
)
927 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
932 if (Dce
->DCXFlags
& DCX_INDESTROY
)
935 Ret
= Dce
->hwndCurrent
;
938 pLE
= Dce
->List
.Flink
;
939 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
941 while (pLE
!= &LEDce
);
946 UserReleaseDC(PWINDOW_OBJECT Window
, HDC hDc
, BOOL EndPaint
)
953 DPRINT("%p %p\n", Window
, hDc
);
955 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
964 pLE
= dce
->List
.Flink
;
965 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
967 while (pLE
!= &LEDce
);
969 if ( Hit
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
971 nRet
= DceReleaseDC(dce
, EndPaint
);
978 UserGetWindowDC(PWINDOW_OBJECT Wnd
)
980 return UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
984 UserGethWnd( HDC hdc
, PWNDOBJ
*pwndo
)
990 hWnd
= IntWindowFromDC(hdc
);
992 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
994 pWndgdi
= (WNDGDI
*)IntGetProp(Wnd
, AtomWndObj
);
996 if ( pWndgdi
&& pWndgdi
->Hwnd
== hWnd
)
998 if (pwndo
) *pwndo
= (PWNDOBJ
)pWndgdi
;
1005 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
1007 PWINDOW_OBJECT Wnd
=NULL
;
1008 DECLARE_RETURN(HDC
);
1010 DPRINT("Enter NtUserGetDCEx\n");
1011 UserEnterExclusive();
1013 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
1017 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
1020 DPRINT("Leave NtUserGetDCEx, ret=%i\n",_ret_
);
1028 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1029 * entire window, including title bar, menus, and scroll bars. A window device
1030 * context permits painting anywhere in a window, because the origin of the
1031 * device context is the upper-left corner of the window instead of the client
1038 NtUserGetWindowDC(HWND hWnd
)
1040 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1044 NtUserGetDC(HWND hWnd
)
1046 DPRINT("NtUGetDC -> %x:%x\n", hWnd
, !hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1048 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1052 * Select logical palette into device context.
1053 * \param hDC handle to the device context
1054 * \param hpal handle to the palette
1055 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1056 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1057 * palette colors in the best way.
1058 * \return old palette
1060 * \todo implement ForceBackground == TRUE
1064 NtUserSelectPalette(HDC hDC
,
1066 BOOL ForceBackground
)
1069 UserEnterExclusive();
1070 // Implement window checks
1071 oldPal
= GdiSelectPalette( hDC
, hpal
, ForceBackground
);