2 * PROJECT: ReactOS Win32k subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/user/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 PLIST_ENTRY ListEntry
;
57 ListEntry
= LEDce
.Flink
;
58 while (ListEntry
!= &LEDce
)
60 dce
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
61 ListEntry
= ListEntry
->Flink
;
71 DceGetVisRgn(PWND Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
74 Rgn
= VIS_ComputeVisibleRegion( Window
,
75 0 == (Flags
& DCX_WINDOW
),
76 0 != (Flags
& DCX_CLIPCHILDREN
),
77 0 != (Flags
& DCX_CLIPSIBLINGS
));
78 /* Caller expects a non-null region */
80 Rgn
= IntSysCreateRectpRgn(0, 0, 0, 0);
85 DceAllocDCE(PWND Window OPTIONAL
, DCE_TYPE Type
)
89 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), USERTAG_DCE
);
93 pDce
->hDC
= DceCreateDisplayDC();
96 ExFreePoolWithTag(pDce
, USERTAG_DCE
);
100 TRACE("Alloc DCE's! %d\n",DCECount
);
101 pDce
->hwndCurrent
= (Window
? Window
->head
.h
: NULL
);
102 pDce
->pwndOrg
= Window
;
103 pDce
->pwndClip
= Window
;
104 pDce
->hrgnClip
= NULL
;
105 pDce
->hrgnClipPublic
= NULL
;
106 pDce
->hrgnSavedVis
= NULL
;
107 pDce
->ppiOwner
= NULL
;
109 InsertTailList(&LEDce
, &pDce
->List
);
111 DCU_SetDcUndeletable(pDce
->hDC
);
113 if (Type
== DCE_WINDOW_DC
|| Type
== DCE_CLASS_DC
) // Window DCE have ownership.
115 pDce
->ptiOwner
= GetW32ThreadInfo();
119 TRACE("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %p\n", pDce
->hDC
);
120 GreSetDCOwner(pDce
->hDC
, GDI_OBJ_HMGR_NONE
);
121 pDce
->ptiOwner
= NULL
;
124 if (Type
== DCE_CACHE_DC
)
126 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
130 pDce
->DCXFlags
= DCX_DCEBUSY
;
133 if (Type
== DCE_WINDOW_DC
)
135 if (Window
->style
& WS_CLIPCHILDREN
) pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
136 if (Window
->style
& WS_CLIPSIBLINGS
) pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
144 DceSetDrawable( PWND Window OPTIONAL
,
153 if (Flags
& DCX_WINDOW
)
155 rect
= Window
->rcWindow
;
159 rect
= Window
->rcClient
;
163 /* Set DC Origin and Window Rectangle */
164 GreSetDCOrg( hDC
, rect
.left
, rect
.top
, &rect
);
169 DceDeleteClipRgn(DCE
* Dce
)
171 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
173 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
175 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
177 else if (Dce
->hrgnClip
!= NULL
)
179 GreDeleteObject(Dce
->hrgnClip
);
182 Dce
->hrgnClip
= NULL
;
184 /* Make it dirty so that the vis rgn gets recomputed next time */
185 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
186 IntGdiSetHookFlags(Dce
->hDC
, DCHF_INVALIDATEVISRGN
);
191 DceUpdateVisRgn(DCE
*Dce
, PWND Window
, ULONG Flags
)
193 PREGION RgnVisible
= NULL
;
197 if (Flags
& DCX_PARENTCLIP
)
201 Parent
= Window
->spwndParent
;
208 if (Parent
->style
& WS_CLIPSIBLINGS
)
210 DcxFlags
= DCX_CLIPSIBLINGS
|
211 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
215 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
217 RgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->head
.h
, Flags
);
219 else if (Window
== NULL
)
221 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
222 if (NULL
!= DesktopWindow
)
224 RgnVisible
= IntSysCreateRectpRgnIndirect(&DesktopWindow
->rcWindow
);
233 RgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
237 if (Flags
& DCX_INTERSECTRGN
)
239 PREGION RgnClip
= NULL
;
241 if (Dce
->hrgnClip
!= NULL
)
242 RgnClip
= REGION_LockRgn(Dce
->hrgnClip
);
246 IntGdiCombineRgn(RgnVisible
, RgnVisible
, RgnClip
, RGN_AND
);
247 REGION_UnlockRgn(RgnClip
);
251 if (RgnVisible
!= NULL
)
253 REGION_Delete(RgnVisible
);
255 RgnVisible
= IntSysCreateRectpRgn(0, 0, 0, 0);
258 else if ((Flags
& DCX_EXCLUDERGN
) && Dce
->hrgnClip
!= NULL
)
260 PREGION RgnClip
= REGION_LockRgn(Dce
->hrgnClip
);
261 IntGdiCombineRgn(RgnVisible
, RgnVisible
, RgnClip
, RGN_DIFF
);
262 REGION_UnlockRgn(RgnClip
);
265 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
266 GdiSelectVisRgn(Dce
->hDC
, RgnVisible
);
267 /* Tell GDI driver */
269 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
271 if (RgnVisible
!= NULL
)
273 REGION_Delete(RgnVisible
);
278 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
280 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_INDESTROY
| DCX_DCEEMPTY
| DCX_DCEBUSY
)))
285 /* Restore previous visible region */
288 DceUpdateVisRgn(dce
, dce
->pwndOrg
, dce
->DCXFlags
);
291 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
292 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
294 DceDeleteClipRgn(dce
);
297 if (dce
->DCXFlags
& DCX_CACHE
)
299 if (!(dce
->DCXFlags
& DCX_NORESETATTRS
))
302 if (!IntGdiCleanDC(dce
->hDC
)) return 0;
304 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
306 /* Don't keep around invalidated entries
307 * because SetDCState() disables hVisRgn updates
308 * by removing dirty bit. */
309 dce
->hwndCurrent
= 0;
311 dce
->pwndClip
= NULL
;
312 dce
->DCXFlags
&= DCX_CACHE
;
313 dce
->DCXFlags
|= DCX_DCEEMPTY
;
316 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
317 TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %p \n", dce
->hDC
);
318 if (!GreSetDCOwner(dce
->hDC
, GDI_OBJ_HMGR_NONE
))
320 dce
->ptiOwner
= NULL
; // Reset ownership.
321 dce
->ppiOwner
= NULL
;
323 #if 0 // Need to research and fix before this is a "growing" issue.
326 ListEntry
= LEDce
.Flink
;
327 while (ListEntry
!= &LEDce
)
329 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
330 ListEntry
= ListEntry
->Flink
;
331 if (!(pDCE
->DCXFlags
& DCX_DCEBUSY
))
332 { /* Free the unused cache DCEs. */
333 DceFreeDCE(pDCE
, TRUE
);
339 return 1; // Released!
344 UserGetDCEx(PWND Wnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
349 BOOL UpdateClipOrigin
= FALSE
;
350 BOOL bUpdateVisRgn
= TRUE
;
353 PLIST_ENTRY ListEntry
;
357 Flags
&= ~DCX_USESTYLE
;
361 if (Flags
& DCX_PARENTCLIP
) Flags
|= DCX_CACHE
;
363 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set.
364 if (Flags
& DCX_USESTYLE
)
366 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
367 if (!(Flags
& DCX_WINDOW
)) // Not window rectangle
369 if (Wnd
->pcls
->style
& CS_PARENTDC
)
371 Flags
|= DCX_PARENTCLIP
;
374 if (!(Flags
& DCX_CACHE
) && // Not on the cheap wine list.
375 !(Wnd
->pcls
->style
& CS_OWNDC
) )
377 if (!(Wnd
->pcls
->style
& CS_CLASSDC
))
378 // The window is not POWNED or has any CLASS, so we are looking for cheap wine.
382 if (Wnd
->pcls
->pdce
) hDC
= ((PDCE
)Wnd
->pcls
->pdce
)->hDC
;
383 TRACE("We have CLASS!!\n");
387 if (Wnd
->style
& WS_CLIPSIBLINGS
)
389 Flags
|= DCX_CLIPSIBLINGS
;
392 if (Wnd
->style
& WS_CLIPCHILDREN
&&
393 !(Wnd
->style
& WS_MINIMIZE
))
395 Flags
|= DCX_CLIPCHILDREN
;
397 /* If minized with icon in the set, we are forced to be cheap! */
398 if (Wnd
->style
& WS_MINIMIZE
&& Wnd
->pcls
->spicn
)
405 if (Wnd
->style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
410 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
412 if (Flags
& DCX_NOCLIPCHILDREN
)
415 Flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
418 Parent
= (Wnd
? Wnd
->spwndParent
: NULL
);
420 if (NULL
== Wnd
|| !(Wnd
->style
& WS_CHILD
) || NULL
== Parent
)
422 Flags
&= ~DCX_PARENTCLIP
;
423 Flags
|= DCX_CLIPSIBLINGS
;
426 /* It seems parent clip is ignored when clipping siblings or children */
427 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
429 if (Flags
& DCX_PARENTCLIP
)
431 if ((Wnd
->style
& WS_VISIBLE
) &&
432 (Parent
->style
& WS_VISIBLE
))
434 Flags
&= ~DCX_CLIPCHILDREN
;
435 if (Parent
->style
& WS_CLIPSIBLINGS
)
437 Flags
|= DCX_CLIPSIBLINGS
;
442 // Window nz, check to see if we still own this or it is just cheap wine tonight.
443 if (!(Flags
& DCX_CACHE
))
445 if ( Wnd
->head
.pti
!= GetW32ThreadInfo())
446 Flags
|= DCX_CACHE
; // Ah~ Not Powned! Forced to be cheap~
449 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
451 if (Flags
& DCX_CACHE
)
452 { // Scan the cheap wine list for our match.
453 DCE
* DceEmpty
= NULL
;
454 DCE
* DceUnused
= NULL
;
455 KeEnterCriticalRegion();
456 ListEntry
= LEDce
.Flink
;
457 while (ListEntry
!= &LEDce
)
459 Dce
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
460 ListEntry
= ListEntry
->Flink
;
462 // The way I understand this, you can have more than one DC per window.
463 // Only one Owned if one was requested and saved and one Cached.
465 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
468 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
472 else if (Dce
->hwndCurrent
== (Wnd
? Wnd
->head
.h
: NULL
) &&
473 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
475 UpdateClipOrigin
= TRUE
;
479 Dce
= NULL
; // Loop issue?
481 KeLeaveCriticalRegion();
483 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
487 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
489 if (Dce
== NULL
) return NULL
;
491 Dce
->hwndCurrent
= (Wnd
? Wnd
->head
.h
: NULL
);
492 Dce
->pwndOrg
= Dce
->pwndClip
= Wnd
;
494 else // If we are here, we are POWNED or having CLASS.
496 KeEnterCriticalRegion();
497 ListEntry
= LEDce
.Flink
;
498 while (ListEntry
!= &LEDce
)
500 Dce
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
501 ListEntry
= ListEntry
->Flink
;
503 // Skip Cache DCE entries.
504 if (!(Dce
->DCXFlags
& DCX_CACHE
))
506 // Check for Window handle than HDC match for CLASS.
507 if (Dce
->hwndCurrent
== Wnd
->head
.h
)
509 bUpdateVisRgn
= FALSE
;
512 else if (Dce
->hDC
== hDC
) break;
514 Dce
= NULL
; // Loop issue?
516 KeLeaveCriticalRegion();
523 if ( (Flags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) &&
524 (Dce
->DCXFlags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) )
526 DceDeleteClipRgn(Dce
);
529 // First time use hax, need to use DceAllocDCE during window display init.
535 if (!GreIsHandleValid(Dce
->hDC
))
537 ERR("FIXME: Got DCE with invalid hDC! %p\n", Dce
->hDC
);
538 Dce
->hDC
= DceCreateDisplayDC();
539 /* FIXME: Handle error */
542 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
545 * Bump it up! This prevents the random errors in wine dce tests and with
546 * proper bits set in DCX_CACHECOMPAREMASK.
548 * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
549 * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
551 RemoveEntryList(&Dce
->List
);
552 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
= Wnd
->hrgnUpdate
;
560 bUpdateVisRgn
= TRUE
;
563 if (ClipRegion
== HRGN_WINDOW
)
565 if (!(Flags
& DCX_WINDOW
))
567 Dce
->hrgnClip
= NtGdiCreateRectRgn(
571 Wnd
->rcClient
.bottom
);
575 Dce
->hrgnClip
= NtGdiCreateRectRgn(
579 Wnd
->rcWindow
.bottom
);
581 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
582 bUpdateVisRgn
= TRUE
;
584 else if (ClipRegion
!= NULL
)
586 if (Dce
->hrgnClip
!= NULL
)
588 ERR("Should not be called!!\n");
589 GreDeleteObject(Dce
->hrgnClip
);
590 Dce
->hrgnClip
= NULL
;
592 Dce
->hrgnClip
= ClipRegion
;
593 bUpdateVisRgn
= TRUE
;
596 if (IntGdiSetHookFlags(Dce
->hDC
, DCHF_VALIDATEVISRGN
)) bUpdateVisRgn
= TRUE
;
598 DceSetDrawable(Wnd
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
600 if (bUpdateVisRgn
) DceUpdateVisRgn(Dce
, Wnd
, Flags
);
602 if (Dce
->DCXFlags
& DCX_CACHE
)
604 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %p\n", Dce
->hDC
);
605 // Need to set ownership so Sync dcattr will work.
606 GreSetDCOwner(Dce
->hDC
, GDI_OBJ_HMGR_POWNED
);
607 Dce
->ptiOwner
= GetW32ThreadInfo(); // Set the temp owning
611 Wnd
->ExStyle
& WS_EX_LAYOUTRTL
&&
612 !(Flags
& DCX_KEEPLAYOUT
) )
614 NtGdiSetLayout(Dce
->hDC
, -1, LAYOUT_RTL
);
617 if (Dce
->DCXFlags
& DCX_PROCESSOWNED
)
619 ppi
= PsGetCurrentProcessWin32Process();
620 ppi
->W32PF_flags
|= W32PF_OWNDCCLEANUP
;
621 Dce
->ptiOwner
= NULL
;
628 /***********************************************************************
632 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
636 ASSERT(pdce
!= NULL
);
637 if (NULL
== pdce
) return;
639 pdce
->DCXFlags
|= DCX_INDESTROY
;
642 GreGetObjectOwner(pdce
->hDC
) != GDI_OBJ_HMGR_POWNED
)
644 TRACE("Change ownership for DCE! -> %p\n" , pdce
);
645 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on.
646 if (GreIsHandleValid(pdce
->hDC
))
648 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
652 ERR("Attempted to change ownership of an DCEhDC %p currently being destroyed!!!\n",
659 if (GreGetObjectOwner(pdce
->hDC
) == GDI_OBJ_HMGR_PUBLIC
)
660 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
663 if (!Hit
) IntGdiDeleteDC(pdce
->hDC
, TRUE
);
665 if (pdce
->hrgnClip
&& !(pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
667 GreDeleteObject(pdce
->hrgnClip
);
668 pdce
->hrgnClip
= NULL
;
671 RemoveEntryList(&pdce
->List
);
673 ExFreePoolWithTag(pdce
, USERTAG_DCE
);
676 TRACE("Freed DCE's! %d \n", DCECount
);
679 /***********************************************************************
682 * Remove owned DCE and reset unreleased cache DCEs.
685 DceFreeWindowDCE(PWND Window
)
688 PLIST_ENTRY ListEntry
;
692 ERR("FreeWindowDCE No Entry! %d\n",DCECount
);
696 ListEntry
= LEDce
.Flink
;
697 while (ListEntry
!= &LEDce
)
699 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
700 ListEntry
= ListEntry
->Flink
;
701 if ( pDCE
->hwndCurrent
== Window
->head
.h
&&
702 !(pDCE
->DCXFlags
& DCX_DCEEMPTY
) )
704 if (!(pDCE
->DCXFlags
& DCX_CACHE
)) /* Owned or Class DCE */
706 if (Window
->pcls
->style
& CS_CLASSDC
) /* Test Class first */
708 if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE */
709 DceDeleteClipRgn(pDCE
);
710 // Update and reset Vis Rgn and clear the dirty bit.
711 // Should release VisRgn than reset it to default.
712 DceUpdateVisRgn(pDCE
, Window
, pDCE
->DCXFlags
);
713 pDCE
->DCXFlags
= DCX_DCEEMPTY
|DCX_CACHE
;
714 pDCE
->hwndCurrent
= 0;
715 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
717 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %p \n",
719 if (!GreSetDCOwner( pDCE
->hDC
, GDI_OBJ_HMGR_NONE
))
721 ERR("Fail Owner Switch hDC-> %p \n", pDCE
->hDC
);
724 /* Do not change owner so thread can clean up! */
726 else if (Window
->pcls
->style
& CS_OWNDC
) /* Owned DCE */
728 DceFreeDCE(pDCE
, FALSE
);
733 ERR("Not POWNED or CLASSDC hwndCurrent -> %p \n",
735 // ASSERT(FALSE); /* bug 5320 */
740 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* Shared cache DCE */
742 /* FIXME: AFAICS we are doing the right thing here so
743 * this should be a TRACE. But this is best left as an ERR
744 * because the 'application error' is likely to come from
745 * another part of Wine (i.e. it's our fault after all).
746 * We should change this to TRACE when ReactOS is more stable
749 ERR("[%p] GetDC() without ReleaseDC()!\n", Window
->head
.h
);
750 DceReleaseDC(pDCE
, FALSE
);
752 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
753 pDCE
->hwndCurrent
= 0;
754 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
761 DceFreeClassDCE(PDCE pdceClass
)
764 PLIST_ENTRY ListEntry
;
766 ListEntry
= LEDce
.Flink
;
767 while (ListEntry
!= &LEDce
)
769 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
770 ListEntry
= ListEntry
->Flink
;
771 if (pDCE
== pdceClass
)
773 DceFreeDCE(pDCE
, TRUE
); // Might have gone cheap!
779 DceFreeThreadDCE(PTHREADINFO pti
)
782 PLIST_ENTRY ListEntry
;
784 ListEntry
= LEDce
.Flink
;
785 while (ListEntry
!= &LEDce
)
787 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
788 ListEntry
= ListEntry
->Flink
;
789 if (pDCE
->ptiOwner
== pti
)
791 if (pDCE
->DCXFlags
& DCX_CACHE
)
793 DceFreeDCE(pDCE
, TRUE
);
803 PLIST_ENTRY ListEntry
;
805 ListEntry
= LEDce
.Flink
;
806 while (ListEntry
!= &LEDce
)
808 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
809 ListEntry
= ListEntry
->Flink
;
810 DceFreeDCE(pDCE
, TRUE
);
815 DceResetActiveDCEs(PWND Window
)
822 PLIST_ENTRY ListEntry
;
829 ListEntry
= LEDce
.Flink
;
830 while (ListEntry
!= &LEDce
)
832 pDCE
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
833 ListEntry
= ListEntry
->Flink
;
834 if (0 == (pDCE
->DCXFlags
& (DCX_DCEEMPTY
|DCX_INDESTROY
)))
836 if (Window
->head
.h
== pDCE
->hwndCurrent
)
838 CurrentWindow
= Window
;
842 if (!pDCE
->hwndCurrent
)
843 CurrentWindow
= NULL
;
845 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
846 if (NULL
== CurrentWindow
)
852 if (!GreIsHandleValid(pDCE
->hDC
) ||
853 (dc
= DC_LockDc(pDCE
->hDC
)) == NULL
)
857 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
859 if (pDCE
->DCXFlags
& DCX_WINDOW
)
861 DeltaX
= CurrentWindow
->rcWindow
.left
- dc
->ptlDCOrig
.x
;
862 DeltaY
= CurrentWindow
->rcWindow
.top
- dc
->ptlDCOrig
.y
;
863 dc
->ptlDCOrig
.x
= CurrentWindow
->rcWindow
.left
;
864 dc
->ptlDCOrig
.y
= CurrentWindow
->rcWindow
.top
;
868 DeltaX
= CurrentWindow
->rcClient
.left
- dc
->ptlDCOrig
.x
;
869 DeltaY
= CurrentWindow
->rcClient
.top
- dc
->ptlDCOrig
.y
;
870 dc
->ptlDCOrig
.x
= CurrentWindow
->rcClient
.left
;
871 dc
->ptlDCOrig
.y
= CurrentWindow
->rcClient
.top
;
874 if (NULL
!= dc
->dclevel
.prgnClip
)
876 REGION_bOffsetRgn(dc
->dclevel
.prgnClip
, DeltaX
, DeltaY
);
877 dc
->fs
|= DC_FLAG_DIRTY_RAO
;
879 if (NULL
!= pDCE
->hrgnClip
)
881 NtGdiOffsetRgn(pDCE
->hrgnClip
, DeltaX
, DeltaY
);
886 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
887 IntGdiSetHookFlags(pDCE
->hDC
, DCHF_VALIDATEVISRGN
);
893 IntWindowFromDC(HDC hDc
)
896 PLIST_ENTRY ListEntry
;
899 ListEntry
= LEDce
.Flink
;
900 while (ListEntry
!= &LEDce
)
902 Dce
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
903 ListEntry
= ListEntry
->Flink
;
906 if (Dce
->DCXFlags
& DCX_INDESTROY
)
909 Ret
= Dce
->hwndCurrent
;
917 UserReleaseDC(PWND Window
, HDC hDc
, BOOL EndPaint
)
920 PLIST_ENTRY ListEntry
;
924 TRACE("%p %p\n", Window
, hDc
);
925 ListEntry
= LEDce
.Flink
;
926 while (ListEntry
!= &LEDce
)
928 dce
= CONTAINING_RECORD(ListEntry
, DCE
, List
);
929 ListEntry
= ListEntry
->Flink
;
937 if ( Hit
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
939 nRet
= DceReleaseDC(dce
, EndPaint
);
946 UserGetWindowDC(PWND Wnd
)
948 return UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
952 UserGethWnd( HDC hdc
, PWNDOBJ
*pwndo
)
958 hWnd
= IntWindowFromDC(hdc
);
960 if (hWnd
&& (Wnd
= UserGetWindowObject(hWnd
)))
962 Clip
= (EWNDOBJ
*)UserGetProp(Wnd
, AtomWndObj
, TRUE
);
964 if ( Clip
&& Clip
->Hwnd
== hWnd
)
966 if (pwndo
) *pwndo
= (PWNDOBJ
)Clip
;
973 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
978 TRACE("Enter NtUserGetDCEx: hWnd %p, ClipRegion %p, Flags %x.\n",
979 hWnd
, ClipRegion
, Flags
);
980 UserEnterExclusive();
982 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
986 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
989 TRACE("Leave NtUserGetDCEx, ret=%p\n", _ret_
);
997 * The NtUserGetWindowDC function retrieves the device context (DC) for the
998 * entire window, including title bar, menus, and scroll bars. A window device
999 * context permits painting anywhere in a window, because the origin of the
1000 * device context is the upper-left corner of the window instead of the client
1007 NtUserGetWindowDC(HWND hWnd
)
1009 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1013 NtUserGetDC(HWND hWnd
)
1015 TRACE("NtUGetDC -> %p:%x\n", hWnd
, !hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1017 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1021 * Select logical palette into device context.
1022 * \param hDC handle to the device context
1023 * \param hpal handle to the palette
1024 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1025 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1026 * palette colors in the best way.
1027 * \return old palette
1029 * \todo implement ForceBackground == TRUE
1033 NtUserSelectPalette(HDC hDC
,
1035 BOOL ForceBackground
)
1038 UserEnterExclusive();
1039 // Implement window checks
1040 oldPal
= GdiSelectPalette( hDC
, hpal
, ForceBackground
);