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
);
51 DceGetVisRgn(PWND Window
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
55 VisRgn
= VIS_ComputeVisibleRegion( Window
,
56 0 == (Flags
& DCX_WINDOW
),
57 0 != (Flags
& DCX_CLIPCHILDREN
),
58 0 != (Flags
& DCX_CLIPSIBLINGS
));
61 VisRgn
= IntSysCreateRectRgn(0, 0, 0, 0);
67 DceAllocDCE(PWND Window OPTIONAL
, DCE_TYPE Type
)
71 pDce
= ExAllocatePoolWithTag(PagedPool
, sizeof(DCE
), USERTAG_DCE
);
75 pDce
->hDC
= DceCreateDisplayDC();
78 ExFreePoolWithTag(pDce
, USERTAG_DCE
);
82 TRACE("Alloc DCE's! %d\n",DCECount
);
83 pDce
->hwndCurrent
= (Window
? Window
->head
.h
: NULL
);
84 pDce
->pwndOrg
= Window
;
85 pDce
->pwndClip
= Window
;
86 pDce
->hrgnClip
= NULL
;
87 pDce
->hrgnClipPublic
= NULL
;
88 pDce
->hrgnSavedVis
= NULL
;
89 pDce
->ppiOwner
= NULL
;
91 InsertTailList(&LEDce
, &pDce
->List
);
93 DCU_SetDcUndeletable(pDce
->hDC
);
95 if (Type
== DCE_WINDOW_DC
|| Type
== DCE_CLASS_DC
) // Window DCE have ownership.
97 pDce
->ptiOwner
= GetW32ThreadInfo();
101 TRACE("FREE DCATTR!!!! NOT DCE_WINDOW_DC!!!!! hDC-> %x\n", pDce
->hDC
);
102 GreSetDCOwner(pDce
->hDC
, GDI_OBJ_HMGR_NONE
);
103 pDce
->ptiOwner
= NULL
;
106 if (Type
== DCE_CACHE_DC
)
108 pDce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
112 pDce
->DCXFlags
= DCX_DCEBUSY
;
115 if (Type
== DCE_WINDOW_DC
)
117 if (Window
->style
& WS_CLIPCHILDREN
) pDce
->DCXFlags
|= DCX_CLIPCHILDREN
;
118 if (Window
->style
& WS_CLIPSIBLINGS
) pDce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
126 DceSetDrawable( PWND Window OPTIONAL
,
131 DC
*dc
= DC_LockDc(hDC
);
142 if (Flags
& DCX_WINDOW
)
144 dc
->ptlDCOrig
.x
= Window
->rcWindow
.left
;
145 dc
->ptlDCOrig
.y
= Window
->rcWindow
.top
;
149 dc
->ptlDCOrig
.x
= Window
->rcClient
.left
;
150 dc
->ptlDCOrig
.y
= Window
->rcClient
.top
;
158 DceDeleteClipRgn(DCE
* Dce
)
160 Dce
->DCXFlags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
);
162 if (Dce
->DCXFlags
& DCX_KEEPCLIPRGN
)
164 Dce
->DCXFlags
&= ~DCX_KEEPCLIPRGN
;
166 else if (Dce
->hrgnClip
!= NULL
)
168 GreDeleteObject(Dce
->hrgnClip
);
171 Dce
->hrgnClip
= NULL
;
173 /* Make it dirty so that the vis rgn gets recomputed next time */
174 Dce
->DCXFlags
|= DCX_DCEDIRTY
;
175 IntGdiSetHookFlags(Dce
->hDC
, DCHF_INVALIDATEVISRGN
);
179 DceUpdateVisRgn(DCE
*Dce
, PWND Window
, ULONG Flags
)
181 HANDLE hRgnVisible
= NULL
;
185 if (Flags
& DCX_PARENTCLIP
)
189 Parent
= Window
->spwndParent
;
196 if (Parent
->style
& WS_CLIPSIBLINGS
)
198 DcxFlags
= DCX_CLIPSIBLINGS
|
199 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
203 DcxFlags
= Flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
205 hRgnVisible
= DceGetVisRgn(Parent
, DcxFlags
, Window
->head
.h
, Flags
);
207 else if (Window
== NULL
)
209 DesktopWindow
= UserGetWindowObject(IntGetDesktopWindow());
210 if (NULL
!= DesktopWindow
)
212 hRgnVisible
= IntSysCreateRectRgnIndirect(&DesktopWindow
->rcWindow
);
221 hRgnVisible
= DceGetVisRgn(Window
, Flags
, 0, 0);
225 if (Flags
& DCX_INTERSECTRGN
)
227 if(Dce
->hrgnClip
!= NULL
)
229 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_AND
);
233 if(hRgnVisible
!= NULL
)
235 GreDeleteObject(hRgnVisible
);
237 hRgnVisible
= IntSysCreateRectRgn(0, 0, 0, 0);
240 else if (Flags
& DCX_EXCLUDERGN
&& Dce
->hrgnClip
!= NULL
)
242 NtGdiCombineRgn(hRgnVisible
, hRgnVisible
, Dce
->hrgnClip
, RGN_DIFF
);
245 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
246 GdiSelectVisRgn(Dce
->hDC
, hRgnVisible
);
250 IntEngWindowChanged(Window
, WOC_RGN_CLIENT
);
253 if (hRgnVisible
!= NULL
)
255 GreDeleteObject(hRgnVisible
);
260 DceReleaseDC(DCE
* dce
, BOOL EndPaint
)
262 if (DCX_DCEBUSY
!= (dce
->DCXFlags
& (DCX_INDESTROY
| DCX_DCEEMPTY
| DCX_DCEBUSY
)))
267 /* Restore previous visible region */
270 DceUpdateVisRgn(dce
, dce
->pwndOrg
, dce
->DCXFlags
);
273 if ((dce
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
274 ((dce
->DCXFlags
& DCX_CACHE
) || EndPaint
))
276 DceDeleteClipRgn(dce
);
279 if (dce
->DCXFlags
& DCX_CACHE
)
281 if (!(dce
->DCXFlags
& DCX_NORESETATTRS
))
284 if (!IntGdiCleanDC(dce
->hDC
)) return 0;
286 if (dce
->DCXFlags
& DCX_DCEDIRTY
)
288 /* Don't keep around invalidated entries
289 * because SetDCState() disables hVisRgn updates
290 * by removing dirty bit. */
291 dce
->hwndCurrent
= 0;
293 dce
->pwndClip
= NULL
;
294 dce
->DCXFlags
&= DCX_CACHE
;
295 dce
->DCXFlags
|= DCX_DCEEMPTY
;
298 dce
->DCXFlags
&= ~DCX_DCEBUSY
;
299 TRACE("Exit!!!!! DCX_CACHE!!!!!! hDC-> %x \n", dce
->hDC
);
300 if (!GreSetDCOwner(dce
->hDC
, GDI_OBJ_HMGR_NONE
))
302 dce
->ptiOwner
= NULL
; // Reset ownership.
303 dce
->ppiOwner
= NULL
;
305 #if 0 // Need to research and fix before this is a "growing" issue.
309 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
312 if (!(pDCE
->DCXFlags
& DCX_DCEBUSY
))
313 { /* Free the unused cache DCEs. */
314 pDCE
= DceFreeDCE(pDCE
, TRUE
);
319 while (pLE
!= &LEDce
);
323 return 1; // Released!
328 UserGetDCEx(PWND Wnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
333 BOOL UpdateClipOrigin
= FALSE
;
334 BOOL bUpdateVisRgn
= TRUE
;
341 Flags
&= ~DCX_USESTYLE
;
345 if (Flags
& (DCX_WINDOW
| DCX_PARENTCLIP
)) Flags
|= DCX_CACHE
;
347 // When GetDC is called with hWnd nz, DCX_CACHE & _WINDOW are clear w _USESTYLE set.
348 if (Flags
& DCX_USESTYLE
)
350 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
351 if (!(Flags
& DCX_WINDOW
)) // Not window rectangle
353 if (Wnd
->pcls
->style
& CS_PARENTDC
)
355 Flags
|= DCX_PARENTCLIP
;
358 if (!(Flags
& DCX_CACHE
) && // Not on the cheap wine list.
359 !(Wnd
->pcls
->style
& CS_OWNDC
) )
361 if (!(Wnd
->pcls
->style
& CS_CLASSDC
))
362 // The window is not POWNED or has any CLASS, so we are looking for cheap wine.
366 if (Wnd
->pcls
->pdce
) hDC
= ((PDCE
)Wnd
->pcls
->pdce
)->hDC
;
367 TRACE("We have CLASS!!\n");
371 if (Wnd
->style
& WS_CLIPSIBLINGS
)
373 Flags
|= DCX_CLIPSIBLINGS
;
376 if (Wnd
->style
& WS_CLIPCHILDREN
&&
377 !(Wnd
->style
& WS_MINIMIZE
))
379 Flags
|= DCX_CLIPCHILDREN
;
381 /* If minized with icon in the set, we are forced to be cheap! */
382 if (Wnd
->style
& WS_MINIMIZE
&&
390 if (Wnd
->style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
395 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
397 if (Flags
& DCX_NOCLIPCHILDREN
)
400 Flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
403 Parent
= (Wnd
? Wnd
->spwndParent
: NULL
);
405 if (NULL
== Wnd
|| !(Wnd
->style
& WS_CHILD
) || NULL
== Parent
)
407 Flags
&= ~DCX_PARENTCLIP
;
408 Flags
|= DCX_CLIPSIBLINGS
;
411 /* It seems parent clip is ignored when clipping siblings or children */
412 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
414 if (Flags
& DCX_PARENTCLIP
)
416 if ((Wnd
->style
& WS_VISIBLE
) &&
417 (Parent
->style
& WS_VISIBLE
))
419 Flags
&= ~DCX_CLIPCHILDREN
;
420 if (Parent
->style
& WS_CLIPSIBLINGS
)
422 Flags
|= DCX_CLIPSIBLINGS
;
427 // Window nz, check to see if we still own this or it is just cheap wine tonight.
428 if (!(Flags
& DCX_CACHE
))
430 if ( Wnd
->head
.pti
!= GetW32ThreadInfo())
431 Flags
|= DCX_CACHE
; // Ah~ Not Powned! Forced to be cheap~
434 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
436 if (Flags
& DCX_CACHE
)
437 { // Scan the cheap wine list for our match.
438 DCE
* DceEmpty
= NULL
;
439 DCE
* DceUnused
= NULL
;
440 KeEnterCriticalRegion();
442 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
445 // The reason for this you may ask?
446 // Well, it seems ReactOS calls GetDC without first creating a desktop DC window!
447 // Need to test for null here. Not sure if this is a bug or a feature.
448 // First time use hax, need to use DceAllocDCE during window display init.
451 // The way I understand this, you can have more than one DC per window.
452 // Only one Owned if one was requested and saved and one Cached.
454 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
457 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
461 else if (Dce
->hwndCurrent
== (Wnd
? Wnd
->head
.h
: NULL
) &&
462 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
464 UpdateClipOrigin
= TRUE
;
465 //bUpdateVisRgn = FALSE;
469 pLE
= Dce
->List
.Flink
;
470 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
472 while (pLE
!= &LEDce
);
473 KeLeaveCriticalRegion();
475 Dce
= (DceEmpty
== NULL
) ? DceUnused
: DceEmpty
;
479 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
481 if (!Dce
) return NULL
;
483 Dce
->hwndCurrent
= (Wnd
? Wnd
->head
.h
: NULL
);
484 Dce
->pwndOrg
= Dce
->pwndClip
= Wnd
;
486 else // If we are here, we are POWNED or having CLASS.
488 KeEnterCriticalRegion();
490 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
492 { // Check for Window handle than HDC match for CLASS.
493 if (Dce
->hwndCurrent
== Wnd
->head
.h
)
495 bUpdateVisRgn
= FALSE
;
498 if (Dce
->hDC
== hDC
) break;
499 pLE
= Dce
->List
.Flink
;
500 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
502 while (pLE
!= &LEDce
);
503 KeLeaveCriticalRegion();
505 if ( (Flags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) &&
506 (Dce
->DCXFlags
& (DCX_INTERSECTRGN
|DCX_EXCLUDERGN
)) )
508 DceDeleteClipRgn(Dce
);
511 // First time use hax, need to use DceAllocDCE during window display init.
517 if (!GreIsHandleValid(Dce
->hDC
))
519 ERR("FIXME: Got DCE with invalid hDC! 0x%x\n", Dce
->hDC
);
520 Dce
->hDC
= DceCreateDisplayDC();
521 /* FIXME: Handle error */
524 Dce
->DCXFlags
= Flags
| DCX_DCEBUSY
;
527 * Bump it up! This prevents the random errors in wine dce tests and with
528 * proper bits set in DCX_CACHECOMPAREMASK.
530 * http://www.reactos.org/archives/public/ros-dev/2008-July/010498.html
531 * http://www.reactos.org/archives/public/ros-dev/2008-July/010499.html
535 RemoveEntryList(&Dce
->List
);
536 InsertHeadList(&LEDce
, &Dce
->List
);
539 /* Introduced in rev 6691 and modified later. */
540 if ( (Flags
& DCX_INTERSECTUPDATE
) && !ClipRegion
)
542 Flags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
543 Dce
->DCXFlags
|= DCX_INTERSECTRGN
| DCX_KEEPCLIPRGN
;
544 ClipRegion
= Wnd
->hrgnUpdate
;
545 bUpdateVisRgn
= TRUE
;
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
;
559 bUpdateVisRgn
= TRUE
;
561 else if (ClipRegion
!= NULL
)
563 if (Dce
->hrgnClip
!= NULL
)
565 ERR("Should not be called!!\n");
566 GreDeleteObject(Dce
->hrgnClip
);
567 Dce
->hrgnClip
= NULL
;
569 Dce
->hrgnClip
= ClipRegion
;
570 bUpdateVisRgn
= TRUE
;
573 if (IntGdiSetHookFlags(Dce
->hDC
, DCHF_VALIDATEVISRGN
)) bUpdateVisRgn
= TRUE
;
575 DceSetDrawable(Wnd
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
577 if (bUpdateVisRgn
) DceUpdateVisRgn(Dce
, Wnd
, Flags
);
579 if (Dce
->DCXFlags
& DCX_CACHE
)
581 TRACE("ENTER!!!!!! DCX_CACHE!!!!!! hDC-> %x\n", Dce
->hDC
);
582 // Need to set ownership so Sync dcattr will work.
583 GreSetDCOwner(Dce
->hDC
, GDI_OBJ_HMGR_POWNED
);
584 Dce
->ptiOwner
= GetW32ThreadInfo(); // Set the temp owning
588 Wnd
->ExStyle
& WS_EX_LAYOUTRTL
&&
589 !(Flags
& DCX_KEEPLAYOUT
) )
591 NtGdiSetLayout(Dce
->hDC
, -1, LAYOUT_RTL
);
594 if (Dce
->DCXFlags
& DCX_PROCESSOWNED
)
596 ppi
= PsGetCurrentProcessWin32Process();
597 ppi
->W32PF_flags
|= W32PF_OWNDCCLEANUP
;
598 Dce
->ptiOwner
= NULL
;
605 /***********************************************************************
609 DceFreeDCE(PDCE pdce
, BOOLEAN Force
)
615 if (NULL
== pdce
) return NULL
;
617 pLE
= pdce
->List
.Flink
;
618 ret
= CONTAINING_RECORD(pLE
, DCE
, List
);
620 pdce
->DCXFlags
|= DCX_INDESTROY
;
623 GreGetObjectOwner(pdce
->hDC
) != GDI_OBJ_HMGR_POWNED
)
625 TRACE("Change ownership for DCE! -> %x\n" , pdce
);
626 // NOTE: Windows sets W32PF_OWNDCCLEANUP and moves on.
627 if (GreIsHandleValid(pdce
->hDC
))
629 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
633 ERR("Attempted to change ownership of an DCEhDC 0x%x currently being destroyed!!!\n",pdce
->hDC
);
639 if (GreGetObjectOwner(pdce
->hDC
) == GDI_OBJ_HMGR_PUBLIC
)
640 GreSetDCOwner(pdce
->hDC
, GDI_OBJ_HMGR_POWNED
);
643 if (!Hit
) IntGdiDeleteDC(pdce
->hDC
, TRUE
);
645 if (pdce
->hrgnClip
&& !(pdce
->DCXFlags
& DCX_KEEPCLIPRGN
))
647 GreDeleteObject(pdce
->hrgnClip
);
648 pdce
->hrgnClip
= NULL
;
651 RemoveEntryList(&pdce
->List
);
653 if (IsListEmpty(&pdce
->List
))
655 ERR("List is Empty! DCE! -> %x\n" , pdce
);
659 ExFreePoolWithTag(pdce
, USERTAG_DCE
);
662 TRACE("Freed DCE's! %d \n", DCECount
);
667 /***********************************************************************
670 * Remove owned DCE and reset unreleased cache DCEs.
673 DceFreeWindowDCE(PWND Window
)
680 ERR("FreeWindowDCE No Entry! %d\n",DCECount
);
685 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
690 ERR("FreeWindowDCE No DCE Pointer!\n");
693 if (IsListEmpty(&pDCE
->List
))
695 ERR("FreeWindowDCE List is Empty!!!!\n");
698 if ( pDCE
->hwndCurrent
== Window
->head
.h
&&
699 !(pDCE
->DCXFlags
& DCX_DCEEMPTY
) )
701 if (!(pDCE
->DCXFlags
& DCX_CACHE
)) /* Owned or Class DCE */
703 if (Window
->pcls
->style
& CS_CLASSDC
) /* Test Class first */
705 if (pDCE
->DCXFlags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) /* Class DCE */
706 DceDeleteClipRgn(pDCE
);
707 // Update and reset Vis Rgn and clear the dirty bit.
708 // Should release VisRgn than reset it to default.
709 DceUpdateVisRgn(pDCE
, Window
, pDCE
->DCXFlags
);
710 pDCE
->DCXFlags
= DCX_DCEEMPTY
|DCX_CACHE
;
711 pDCE
->hwndCurrent
= 0;
712 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
714 TRACE("POWNED DCE going Cheap!! DCX_CACHE!! hDC-> %x \n", pDCE
->hDC
);
715 if (!GreSetDCOwner( pDCE
->hDC
, GDI_OBJ_HMGR_NONE
))
717 ERR("Fail Owner Switch hDC-> %x \n", pDCE
->hDC
);
720 /* Do not change owner so thread can clean up! */
722 else if (Window
->pcls
->style
& CS_OWNDC
) /* Owned DCE */
724 pDCE
= DceFreeDCE(pDCE
, FALSE
);
730 ERR("Not POWNED or CLASSDC hwndCurrent -> %x \n", pDCE
->hwndCurrent
);
731 // ASSERT(FALSE); /* bug 5320 */
736 if (pDCE
->DCXFlags
& DCX_DCEBUSY
) /* Shared cache DCE */
738 /* FIXME: AFAICS we are doing the right thing here so
739 * this should be a TRACE. But this is best left as an ERR
740 * because the 'application error' is likely to come from
741 * another part of Wine (i.e. it's our fault after all).
742 * We should change this to TRACE when ReactOS is more stable
745 ERR("[%p] GetDC() without ReleaseDC()!\n", Window
->head
.h
);
746 DceReleaseDC(pDCE
, FALSE
);
748 pDCE
->DCXFlags
|= DCX_DCEEMPTY
;
749 pDCE
->hwndCurrent
= 0;
750 pDCE
->pwndOrg
= pDCE
->pwndClip
= NULL
;
753 pLE
= pDCE
->List
.Flink
;
754 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
756 while (pLE
!= &LEDce
);
760 DceFreeClassDCE(HDC hDC
)
765 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
770 if (pDCE
->hDC
== hDC
)
772 pDCE
= DceFreeDCE(pDCE
, TRUE
); // Might have gone cheap!
776 pLE
= pDCE
->List
.Flink
;
777 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
779 while (pLE
!= &LEDce
);
783 DceFreeThreadDCE(PTHREADINFO pti
)
788 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
793 if (pDCE
->ptiOwner
== pti
)
795 if (pDCE
->DCXFlags
& DCX_CACHE
)
797 pDCE
= DceFreeDCE(pDCE
, TRUE
);
802 pLE
= pDCE
->List
.Flink
;
803 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
805 while (pLE
!= &LEDce
);
814 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
819 pDCE
= DceFreeDCE(pDCE
, TRUE
);
822 while (pLE
!= &LEDce
);
826 DceResetActiveDCEs(PWND Window
)
840 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
845 if(pLE
== &LEDce
) break;
846 if (0 == (pDCE
->DCXFlags
& (DCX_DCEEMPTY
|DCX_INDESTROY
)))
848 if (Window
->head
.h
== pDCE
->hwndCurrent
)
850 CurrentWindow
= Window
;
854 if (!pDCE
->hwndCurrent
)
855 CurrentWindow
= NULL
;
857 CurrentWindow
= UserGetWindowObject(pDCE
->hwndCurrent
);
858 if (NULL
== CurrentWindow
)
860 pLE
= pDCE
->List
.Flink
;
861 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
866 if (!GreIsHandleValid(pDCE
->hDC
) ||
867 (dc
= DC_LockDc(pDCE
->hDC
)) == NULL
)
869 pLE
= pDCE
->List
.Flink
;
870 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
873 if (Window
== CurrentWindow
|| IntIsChildWindow(Window
, CurrentWindow
))
875 if (pDCE
->DCXFlags
& DCX_WINDOW
)
877 DeltaX
= CurrentWindow
->rcWindow
.left
- dc
->ptlDCOrig
.x
;
878 DeltaY
= CurrentWindow
->rcWindow
.top
- dc
->ptlDCOrig
.y
;
879 dc
->ptlDCOrig
.x
= CurrentWindow
->rcWindow
.left
;
880 dc
->ptlDCOrig
.y
= CurrentWindow
->rcWindow
.top
;
884 DeltaX
= CurrentWindow
->rcClient
.left
- dc
->ptlDCOrig
.x
;
885 DeltaY
= CurrentWindow
->rcClient
.top
- dc
->ptlDCOrig
.y
;
886 dc
->ptlDCOrig
.x
= CurrentWindow
->rcClient
.left
;
887 dc
->ptlDCOrig
.y
= CurrentWindow
->rcClient
.top
;
890 if (NULL
!= dc
->rosdc
.hClipRgn
)
892 NtGdiOffsetRgn(dc
->rosdc
.hClipRgn
, DeltaX
, DeltaY
);
893 CLIPPING_UpdateGCRegion(dc
);
895 if (NULL
!= pDCE
->hrgnClip
)
897 NtGdiOffsetRgn(pDCE
->hrgnClip
, DeltaX
, DeltaY
);
902 DceUpdateVisRgn(pDCE
, CurrentWindow
, pDCE
->DCXFlags
);
903 IntGdiSetHookFlags(pDCE
->hDC
, DCHF_VALIDATEVISRGN
);
905 if (Window
->head
.h
!= pDCE
->hwndCurrent
)
907 // IntEngWindowChanged(CurrentWindow, WOC_RGN_CLIENT);
908 // UserDerefObject(CurrentWindow);
911 pLE
= pDCE
->List
.Flink
;
912 pDCE
= CONTAINING_RECORD(pLE
, DCE
, List
);
914 while (pLE
!= &LEDce
);
918 IntWindowFromDC(HDC hDc
)
925 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
930 if (Dce
->DCXFlags
& DCX_INDESTROY
)
933 Ret
= Dce
->hwndCurrent
;
936 pLE
= Dce
->List
.Flink
;
937 Dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
939 while (pLE
!= &LEDce
);
944 UserReleaseDC(PWND Window
, HDC hDc
, BOOL EndPaint
)
951 TRACE("%p %p\n", Window
, hDc
);
953 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
962 pLE
= dce
->List
.Flink
;
963 dce
= CONTAINING_RECORD(pLE
, DCE
, List
);
965 while (pLE
!= &LEDce
);
967 if ( Hit
&& (dce
->DCXFlags
& DCX_DCEBUSY
))
969 nRet
= DceReleaseDC(dce
, EndPaint
);
976 UserGetWindowDC(PWND Wnd
)
978 return UserGetDCEx(Wnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
982 UserGethWnd( HDC hdc
, PWNDOBJ
*pwndo
)
989 hWnd
= IntWindowFromDC(hdc
);
991 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
993 pprop
= IntGetProp(Wnd
, AtomWndObj
);
995 pWndgdi
= (WNDGDI
*)pprop
->Data
;
997 if ( pWndgdi
&& pWndgdi
->Hwnd
== hWnd
)
999 if (pwndo
) *pwndo
= (PWNDOBJ
)pWndgdi
;
1006 NtUserGetDCEx(HWND hWnd OPTIONAL
, HANDLE ClipRegion
, ULONG Flags
)
1009 DECLARE_RETURN(HDC
);
1011 TRACE("Enter NtUserGetDCEx\n");
1012 UserEnterExclusive();
1014 if (hWnd
&& !(Wnd
= UserGetWindowObject(hWnd
)))
1018 RETURN( UserGetDCEx(Wnd
, ClipRegion
, Flags
));
1021 TRACE("Leave NtUserGetDCEx, ret=%i\n",_ret_
);
1029 * The NtUserGetWindowDC function retrieves the device context (DC) for the
1030 * entire window, including title bar, menus, and scroll bars. A window device
1031 * context permits painting anywhere in a window, because the origin of the
1032 * device context is the upper-left corner of the window instead of the client
1039 NtUserGetWindowDC(HWND hWnd
)
1041 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
1045 NtUserGetDC(HWND hWnd
)
1047 TRACE("NtUGetDC -> %x:%x\n", hWnd
, !hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1049 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
1053 * Select logical palette into device context.
1054 * \param hDC handle to the device context
1055 * \param hpal handle to the palette
1056 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
1057 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
1058 * palette colors in the best way.
1059 * \return old palette
1061 * \todo implement ForceBackground == TRUE
1065 NtUserSelectPalette(HDC hDC
,
1067 BOOL ForceBackground
)
1070 UserEnterExclusive();
1071 // Implement window checks
1072 oldPal
= GdiSelectPalette( hDC
, hpal
, ForceBackground
);