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 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 *****************************************************************/
28 // This should be moved to dc.c or dcutil.c.
31 DceCreateDisplayDC(VOID
)
34 UNICODE_STRING DriverName
;
35 RtlInitUnicodeString(&DriverName
, L
"DISPLAY");
36 hDC
= IntGdiCreateDC(&DriverName
, NULL
, NULL
, NULL
, FALSE
);
38 co_IntGraphicsCheck(TRUE
);
41 // If NULL, first time through! Build the default window dc!
43 if (hDC
&& !defaultDCstate
) // Ultra HAX! Dedicated to GvG!
44 { // This is a cheesy way to do this.
45 PDC dc
= DC_LockDc ( hDC
);
47 defaultDCstate
= ExAllocatePoolWithTag(PagedPool
, sizeof(DC
), TAG_DC
);
48 RtlZeroMemory(defaultDCstate
, sizeof(DC
));
49 defaultDCstate
->pdcattr
= &defaultDCstate
->dcattr
;
50 DC_vCopyState(dc
, defaultDCstate
, TRUE
);
52 InitializeListHead(&LEDce
);
59 DceGetVisRgn(PWND Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
63 VisRgn
= VIS_ComputeVisibleRegion( Window
,
64 0 == (Flags
& DCX_WINDOW
),
65 0 != (Flags
& DCX_CLIPCHILDREN
),
66 0 != (Flags
& DCX_CLIPSIBLINGS
));
69 VisRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
75 DceAllocDCE(PWND Window OPTIONAL
, DCE_TYPE Type
)
79 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), USERTAG_DCE
);
83 pDce
->hDC
= DceCreateDisplayDC();
86 ExFreePoolWithTag(pDce
, USERTAG_DCE
);
90 TRACE("Alloc DCE's! %d\n",DCECount
);
91 pDce
->hwndCurrent
= (Window
? Window
->head
.h
: NULL
);
92 pDce
->pwndOrg
= Window
;
93 pDce
->pwndClip
= Window
;
94 pDce
->hrgnClip
= NULL
;
95 pDce
->hrgnClipPublic
= NULL
;
96 pDce
->hrgnSavedVis
= NULL
;
97 pDce
->ppiOwner
= NULL
;
99 InsertTailList(&LEDce
, &pDce
->List
);
101 DCU_SetDcUndeletable(pDce
->hDC
);
103 if (Type
== DCE_WINDOW_DC
|| Type
== DCE_CLASS_DC
) //Window DCE have ownership.
105 pDce
->ptiOwner
= GetW32ThreadInfo();
109 TRACE("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %x\n", pDce
->hDC
);
110 GreSetDCOwner(pDce
->hDC
, GDI_OBJ_HMGR_NONE
);
111 pDce
->ptiOwner
= NULL
;
114 if (Type
== DCE_CACHE_DC
)
116 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
120 pDce
->DCXFlags
= DCX_DCEBUSY
;
123 if (Type
== DCE_WINDOW_DC
)
125 if (Window
->style
& WS_CLIPCHILDREN
) pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
126 if (Window
->style
& WS_CLIPSIBLINGS
) pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
134 DceSetDrawable( PWND Window OPTIONAL
,
139 DC
*dc
= DC_LockDc(hDC
);
150 if (Flags
& DCX_WINDOW
)
152 dc
->ptlDCOrig
.x
= Window
->rcWindow
.left
;
153 dc
->ptlDCOrig
.y
= Window
->rcWindow
.top
;
157 dc
->ptlDCOrig
.x
= Window
->rcClient
.left
;
158 dc
->ptlDCOrig
.y
= Window
->rcClient
.top
;
166 DceDeleteClipRgn(DCE
* Dce
)
168 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
170 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
172 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
174 else if (Dce
->hrgnClip
!= NULL
)
176 GreDeleteObject(Dce
->hrgnClip
);
179 Dce
->hrgnClip
= NULL
;
181 /* make it dirty so that the vis rgn gets recomputed next time */
182 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
186 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
188 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_INDESTROY
| DCX_DCEEMPTY
| DCX_DCEBUSY
)))
193 /* restore previous visible region */
194 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
195 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
197 DceDeleteClipRgn(dce
);
200 if (dce
->DCXFlags
& DCX_CACHE
)
202 if (!(dce
->DCXFlags
& DCX_NORESETATTRS
))
204 /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
205 IntGdiSetHookFlags(dce
->hDC
, DCHF_VALIDATEVISRGN
);
208 if (!IntGdiCleanDC(dce
->hDC
)) return 0;
210 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
212 /* don't keep around invalidated entries
213 * because SetDCState() disables hVisRgn updates
214 * by removing dirty bit. */
215 dce
->hwndCurrent
= 0;
216 dce
->DCXFlags
&= DCX_CACHE
;
217 dce
->DCXFlags
|= DCX_DCEEMPTY
;
220 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
221 TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %x \n", dce
->hDC
);
222 if (!GreSetDCOwner(dce
->hDC
, GDI_OBJ_HMGR_NONE
))
224 dce
->ptiOwner
= NULL
; // Reset ownership.
225 dce
->ppiOwner
= NULL
;
227 #if 0 // Need to research and fix before this is a "growing" issue.
231 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
234 if (!(pDCE
->DCXFlags
& DCX_DCEBUSY
))
235 { /* Free the unused cache DCEs. */
236 pDCE
= DceFreeDCE(pDCE
, TRUE
);
241 while (pLE
!= &LEDce
);
245 return 1; // Released!
249 DceUpdateVisRgn(DCE
*Dce
, PWND Window
, ULONG Flags
)
251 HANDLE hRgnVisible
= NULL
;
255 if (Flags
& DCX_PARENTCLIP
)
259 Parent
= Window
->spwndParent
;
266 if (Parent
->style
& WS_CLIPSIBLINGS
)
268 DcxFlags
= DCX_CLIPSIBLINGS
|
269 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
273 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
275 hRgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->head
.h
, Flags
);
277 else if (Window
== NULL
)
279 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
280 if (NULL
!= DesktopWindow
)
282 hRgnVisible
= IntSysCreateRectRgnIndirect(&DesktopWindow
->rcWindow
);
291 hRgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
295 if (Flags
& DCX_INTERSECTRGN
)
297 if(Dce
->hrgnClip
!= NULL
)
299 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_AND
);
303 if(hRgnVisible
!= NULL
)
305 GreDeleteObject(hRgnVisible
);
307 hRgnVisible
= IntSysCreateRectRgn(0, 0, 0, 0);
310 else if (Flags
& DCX_EXCLUDERGN
&& Dce
->hrgnClip
!= NULL
)
312 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_DIFF
);
315 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
316 GdiSelectVisRgn(Dce
->hDC
, hRgnVisible
);
320 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
323 if (hRgnVisible
!= NULL
)
325 GreDeleteObject(hRgnVisible
);
330 UserGetDCEx(PWND Wnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
335 BOOL UpdateClipOrigin
= FALSE
;
342 Flags
&= ~DCX_USESTYLE
;
346 if (Flags
& (DCX_WINDOW
| DCX_PARENTCLIP
)) Flags
|= DCX_CACHE
;
348 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set.
349 if (Flags
& DCX_USESTYLE
)
351 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
352 if (!(Flags
& DCX_WINDOW
)) // not window rectangle
354 if (Wnd
->pcls
->style
& CS_PARENTDC
)
356 Flags
|= DCX_PARENTCLIP
;
359 if (!(Flags
& DCX_CACHE
) && // Not on the cheap wine list.
360 !(Wnd
->pcls
->style
& CS_OWNDC
) )
362 if (!(Wnd
->pcls
->style
& CS_CLASSDC
))
363 // The window is not POWNED or has any CLASS, so we are looking for cheap wine.
367 if (Wnd
->pcls
->pdce
) hDC
= ((PDCE
)Wnd
->pcls
->pdce
)->hDC
;
368 TRACE("We have CLASS!!\n");
371 /* else // For Testing!
373 DPRINT1("We have POWNER!!\n");
374 if (Window->Dce) DPRINT1("We have POWNER with DCE!!\n");
377 if (Wnd
->style
& WS_CLIPSIBLINGS
)
379 Flags
|= DCX_CLIPSIBLINGS
;
382 if (Wnd
->style
& WS_CLIPCHILDREN
&&
383 !(Wnd
->style
& WS_MINIMIZE
))
385 Flags
|= DCX_CLIPCHILDREN
;
387 /* If minized with icon in the set, we are forced to be cheap! */
388 if (Wnd
->style
& WS_MINIMIZE
&&
396 if (Wnd
->style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
401 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
403 if (Flags
& DCX_NOCLIPCHILDREN
)
406 Flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
409 Parent
= (Wnd
? Wnd
->spwndParent
: NULL
);
411 if (NULL
== Wnd
|| !(Wnd
->style
& WS_CHILD
) || NULL
== Parent
)
413 Flags
&= ~DCX_PARENTCLIP
;
414 Flags
|= DCX_CLIPSIBLINGS
;
417 /* it seems parent clip is ignored when clipping siblings or children */
418 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
420 if (Flags
& DCX_PARENTCLIP
)
422 if ((Wnd
->style
& WS_VISIBLE
) &&
423 (Parent
->style
& WS_VISIBLE
))
425 Flags
&= ~DCX_CLIPCHILDREN
;
426 if (Parent
->style
& WS_CLIPSIBLINGS
)
428 Flags
|= DCX_CLIPSIBLINGS
;
433 // Window nz, check to see if we still own this or it is just cheap wine tonight.
434 if (!(Flags
& DCX_CACHE
))
436 if ( Wnd
->head
.pti
!= GetW32ThreadInfo())
437 Flags
|= DCX_CACHE
; // Ah~ Not Powned! Forced to be cheap~
440 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
442 if (Flags
& DCX_CACHE
)
443 { // Scan the cheap wine list for our match.
444 DCE
* DceEmpty
= NULL
;
445 DCE
* DceUnused
= NULL
;
446 KeEnterCriticalRegion();
448 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
451 // The reason for this you may ask?
452 // Well, it seems ReactOS calls GetDC with out first creating a desktop DC window!
453 // Need to test for null here. Not sure if this is a bug or a feature.
454 // First time use hax, need to use DceAllocDCE during window display init.
457 // The way I understand this, you can have more than one DC per window.
458 // Only one Owned if one was requested and saved and one Cached.
460 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
463 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
467 else if (Dce
->hwndCurrent
== (Wnd
? Wnd
->head
.h
: NULL
) &&
468 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
470 UpdateClipOrigin
= TRUE
;
474 pLE
= Dce
->List
.Flink
;
475 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
477 while (pLE
!= &LEDce
);
478 KeLeaveCriticalRegion();
480 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
484 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
486 if (!Dce
) return NULL
;
488 Dce
->hwndCurrent
= (Wnd
? Wnd
->head
.h
: NULL
);
490 else // If we are here, we are POWNED or having CLASS.
492 KeEnterCriticalRegion();
494 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
496 { // Check for Window handle than HDC match for CLASS.
497 if ((Dce
->hwndCurrent
== Wnd
->head
.h
) ||
500 pLE
= Dce
->List
.Flink
;
501 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
503 while (pLE
!= &LEDce
);
504 KeLeaveCriticalRegion();
506 if ( (Flags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) &&
507 (Dce
->DCXFlags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) )
509 DceDeleteClipRgn(Dce
);
512 // First time use hax, need to use DceAllocDCE during window display init.
518 if (!GreIsHandleValid(Dce
->hDC
))
520 ERR("FIXME: Got DCE with invalid hDC! 0x%x\n", Dce
->hDC
);
521 Dce
->hDC
= DceCreateDisplayDC();
522 /* FIXME: Handle error */
525 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
528 Bump it up! This prevents the random errors in wine dce tests and with
529 proper bits set in DCX_CACHECOMPAREMASK.
531 http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
532 http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
536 RemoveEntryList(&Dce
->List
);
537 InsertHeadList(&LEDce
, &Dce
->List
);
540 /* Introduced in rev 6691 and modified later. */
541 if ( (Flags
& DCX_INTERSECTUPDATE
) && !ClipRegion
)
543 Flags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
544 Dce
->DCXFlags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
545 ClipRegion
= Wnd
->hrgnUpdate
;
548 if (ClipRegion
== HRGN_WINDOW
)
550 if (!(Flags
& DCX_WINDOW
))
552 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Wnd
->rcClient
);
556 Dce
->hrgnClip
= IntSysCreateRectRgnIndirect(&Wnd
->rcWindow
);
558 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
560 else if (ClipRegion
!= NULL
)
562 if (Dce
->hrgnClip
!= NULL
)
564 ERR("Should not be called!!\n");
565 GreDeleteObject(Dce
->hrgnClip
);
566 Dce
->hrgnClip
= NULL
;
568 Dce
->hrgnClip
= ClipRegion
;
571 DceSetDrawable(Wnd
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
573 DceUpdateVisRgn(Dce
, Wnd
, Flags
);
575 if (Dce
->DCXFlags
& DCX_CACHE
)
577 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce
->hDC
);
578 // Need to set ownership so Sync dcattr will work.
579 GreSetDCOwner(Dce
->hDC
, GDI_OBJ_HMGR_POWNED
);
580 Dce
->ptiOwner
= GetW32ThreadInfo(); // Set the temp owning
584 Wnd
->ExStyle
& WS_EX_LAYOUTRTL
&&
585 !(Flags
& DCX_KEEPLAYOUT
) )
587 NtGdiSetLayout(Dce
->hDC
, -1, LAYOUT_RTL
);
590 if (Dce
->DCXFlags
& DCX_PROCESSOWNED
)
592 ppi
= PsGetCurrentProcessWin32Process();
593 ppi
->W32PF_flags
|= W32PF_OWNDCCLEANUP
;
594 Dce
->ptiOwner
= NULL
;
601 /***********************************************************************
605 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
611 if (NULL
== pdce
) return NULL
;
613 pLE
= pdce
->List
.Flink
;
614 ret
= CONTAINING_RECORD(pLE
, DCE
, List
);
616 pdce
->DCXFlags
|= DCX_INDESTROY
;
619 GreGetObjectOwner(pdce
->hDC
) != GDI_OBJ_HMGR_POWNED
)
621 TRACE("Change ownership for DCE! -> %x\n" , pdce
);
622 // Note: Windows sets W32PF_OWNDCCLEANUP and moves on.
623 if (GreIsHandleValid(pdce
->hDC
))
625 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
629 ERR("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",pdce
->hDC
);
635 if (GreGetObjectOwner(pdce
->hDC
) == GDI_OBJ_HMGR_PUBLIC
)
636 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
639 if (!Hit
) IntGdiDeleteDC(pdce
->hDC
, TRUE
);
641 if (pdce
->hrgnClip
&& !(pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
643 GreDeleteObject(pdce
->hrgnClip
);
644 pdce
->hrgnClip
= NULL
;
647 RemoveEntryList(&pdce
->List
);
649 if (IsListEmpty(&pdce
->List
))
651 ERR("List is Empty! DCE! -> %x\n" , pdce
);
655 ExFreePoolWithTag(pdce
, USERTAG_DCE
);
658 TRACE("Freed DCE's! %d \n", DCECount
);
663 /***********************************************************************
666 * Remove owned DCE and reset unreleased cache DCEs.
669 DceFreeWindowDCE(PWND Window
)
676 ERR("FreeWindowDCE No Entry! %d\n",DCECount
);
681 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
686 ERR("FreeWindowDCE No DCE Pointer!\n");
689 if (IsListEmpty(&pDCE
->List
))
691 ERR("FreeWindowDCE List is Empty!!!!\n");
694 if ( pDCE
->hwndCurrent
== Window
->head
.h
&&
695 !(pDCE
->DCXFlags
& DCX_DCEEMPTY
) )
697 if (!(pDCE
->DCXFlags
& DCX_CACHE
)) /* owned or Class DCE*/
699 if (Window
->pcls
->style
& CS_CLASSDC
) /* Test Class first */
701 if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE*/
702 DceDeleteClipRgn(pDCE
);
703 // Update and reset Vis Rgn and clear the dirty bit.
704 // Should release VisRgn than reset it to default.
705 DceUpdateVisRgn(pDCE
, Window
, pDCE
->DCXFlags
);
706 pDCE
->DCXFlags
= DCX_DCEEMPTY
|DCX_CACHE
;
707 pDCE
->hwndCurrent
= 0;
709 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %x \n", pDCE
->hDC
);
710 if (!GreSetDCOwner( pDCE
->hDC
, GDI_OBJ_HMGR_NONE
))
712 ERR("Fail Owner Switch hDC-> %x \n", pDCE
->hDC
);
715 /* Do not change owner so thread can clean up! */
717 else if (Window
->pcls
->style
& CS_OWNDC
) /* owned DCE*/
719 pDCE
= DceFreeDCE(pDCE
, FALSE
);
725 ERR("Not POWNED or CLASSDC hwndCurrent -> %x \n", pDCE
->hwndCurrent
);
726 // ASSERT(FALSE); /* bug 5320 */
731 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* shared cache DCE */
733 /* FIXME: AFAICS we are doing the right thing here so
734 * this should be a TRACE. But this is best left as an ERR
735 * because the 'application error' is likely to come from
736 * another part of Wine (i.e. it's our fault after all).
737 * We should change this to TRACE when ReactOS is more stable
740 ERR("[%p] GetDC() without ReleaseDC()!\n", Window
->head
.h
);
741 DceReleaseDC(pDCE
, FALSE
);
743 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
744 pDCE
->hwndCurrent
= 0;
747 pLE
= pDCE
->List
.Flink
;
748 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
750 while (pLE
!= &LEDce
);
754 DceFreeClassDCE(HDC hDC
)
759 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
764 if (pDCE
->hDC
== hDC
)
766 pDCE
= DceFreeDCE(pDCE
, TRUE
); // Might have gone cheap!
770 pLE
= pDCE
->List
.Flink
;
771 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
773 while (pLE
!= &LEDce
);
777 DceFreeThreadDCE(PTHREADINFO pti
)
782 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
787 if (pDCE
->ptiOwner
== pti
)
789 if (pDCE
->DCXFlags
& DCX_CACHE
)
791 pDCE
= DceFreeDCE(pDCE
, TRUE
);
796 pLE
= pDCE
->List
.Flink
;
797 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
799 while (pLE
!= &LEDce
);
808 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
813 pDCE
= DceFreeDCE(pDCE
, TRUE
);
816 while (pLE
!= &LEDce
);
820 DceResetActiveDCEs(PWND Window
)
834 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
839 if(pLE
== &LEDce
) break;
840 if (0 == (pDCE
->DCXFlags
& (DCX_DCEEMPTY
|DCX_INDESTROY
)))
842 if (Window
->head
.h
== pDCE
->hwndCurrent
)
844 CurrentWindow
= Window
;
848 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
849 if (NULL
== CurrentWindow
)
851 pLE
= pDCE
->List
.Flink
;
852 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
857 if (!GreIsHandleValid(pDCE
->hDC
) ||
858 (dc
= DC_LockDc(pDCE
->hDC
)) == NULL
)
860 pLE
= pDCE
->List
.Flink
;
861 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
864 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
866 if (pDCE
->DCXFlags
& DCX_WINDOW
)
868 DeltaX
= CurrentWindow
->rcWindow
.left
- dc
->ptlDCOrig
.x
;
869 DeltaY
= CurrentWindow
->rcWindow
.top
- dc
->ptlDCOrig
.y
;
870 dc
->ptlDCOrig
.x
= CurrentWindow
->rcWindow
.left
;
871 dc
->ptlDCOrig
.y
= CurrentWindow
->rcWindow
.top
;
875 DeltaX
= CurrentWindow
->rcClient
.left
- dc
->ptlDCOrig
.x
;
876 DeltaY
= CurrentWindow
->rcClient
.top
- dc
->ptlDCOrig
.y
;
877 dc
->ptlDCOrig
.x
= CurrentWindow
->rcClient
.left
;
878 dc
->ptlDCOrig
.y
= CurrentWindow
->rcClient
.top
;
880 if (NULL
!= dc
->rosdc
.hClipRgn
)
882 NtGdiOffsetRgn(dc
->rosdc
.hClipRgn
, DeltaX
, DeltaY
);
883 CLIPPING_UpdateGCRegion(dc
);
885 if (NULL
!= pDCE
->hrgnClip
)
887 NtGdiOffsetRgn(pDCE
->hrgnClip
, DeltaX
, DeltaY
);
892 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
894 if (Window
->head
.h
!= pDCE
->hwndCurrent
)
896 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
897 // UserDerefObject(CurrentWindow);
900 pLE
= pDCE
->List
.Flink
;
901 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
903 while (pLE
!= &LEDce
);
907 IntWindowFromDC(HDC hDc
)
914 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
919 if (Dce
->DCXFlags
& DCX_INDESTROY
)
922 Ret
= Dce
->hwndCurrent
;
925 pLE
= Dce
->List
.Flink
;
926 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
928 while (pLE
!= &LEDce
);
933 UserReleaseDC(PWND Window
, HDC hDc
, BOOL EndPaint
)
940 TRACE("%p %p\n", Window
, hDc
);
942 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
951 pLE
= dce
->List
.Flink
;
952 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
954 while (pLE
!= &LEDce
);
956 if ( Hit
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
958 nRet
= DceReleaseDC(dce
, EndPaint
);
965 UserGetWindowDC(PWND Wnd
)
967 return UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
971 UserGethWnd( HDC hdc
, PWNDOBJ
*pwndo
)
977 hWnd
= IntWindowFromDC(hdc
);
979 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
981 pWndgdi
= (WNDGDI
*)IntGetProp(Wnd
, AtomWndObj
);
983 if ( pWndgdi
&& pWndgdi
->Hwnd
== hWnd
)
985 if (pwndo
) *pwndo
= (PWNDOBJ
)pWndgdi
;
992 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
997 TRACE("Enter NtUserGetDCEx\n");
998 UserEnterExclusive();
1000 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
1004 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
1007 TRACE("Leave NtUserGetDCEx, ret=%i\n",_ret_
);
1015 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1016 * entire window, including title bar, menus, and scroll bars. A window device
1017 * context permits painting anywhere in a window, because the origin of the
1018 * device context is the upper-left corner of the window instead of the client
1025 NtUserGetWindowDC(HWND hWnd
)
1027 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1031 NtUserGetDC(HWND hWnd
)
1033 TRACE("NtUGetDC -> %x:%x\n", hWnd
, !hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1035 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1039 * Select logical palette into device context.
1040 * \param hDC handle to the device context
1041 * \param hpal handle to the palette
1042 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1043 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1044 * palette colors in the best way.
1045 * \return old palette
1047 * \todo implement ForceBackground == TRUE
1051 NtUserSelectPalette(HDC hDC
,
1053 BOOL ForceBackground
)
1056 UserEnterExclusive();
1057 // Implement window checks
1058 oldPal
= GdiSelectPalette( hDC
, hpal
, ForceBackground
);