4 * Copyright 1993 Alexandre Julliard
5 * 1996,1997 Alex Korobka
8 * Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs
9 * have to be updated dynamically.
13 * DCX_DCEEMPTY - dce is uninitialized
14 * DCX_DCEBUSY - dce is in use
15 * DCX_DCEDIRTY - ReleaseDC() should wipe instead of caching
16 * DCX_KEEPCLIPRGN - ReleaseDC() should not delete the clipping region
17 * DCX_WINDOWPAINT - BeginPaint() is in effect
27 #include "sysmetrics.h"
30 #define NB_DCE 5 /* Number of DCEs created at startup */
32 static DCE
*firstDCE
= 0;
33 static HDC32 defaultDCstate
= 0;
35 static void DCE_DeleteClipRgn( DCE
* );
36 static INT32
DCE_ReleaseDC( DCE
* );
39 /***********************************************************************
42 static void DCE_DumpCache(void)
49 DUMP("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
50 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
,
51 (dce
->DCXflags
& DCX_CACHE
) ? "Cache" : "Owned",
52 (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
57 /***********************************************************************
62 DCE
*DCE_AllocDCE( HWND32 hWnd
, DCE_TYPE type
)
65 if (!(dce
= HeapAlloc( SystemHeap
, 0, sizeof(DCE
) ))) return NULL
;
66 if (!(dce
->hDC
= CreateDC16( "DISPLAY", NULL
, NULL
, NULL
)))
68 HeapFree( SystemHeap
, 0, dce
);
72 /* store DCE handle in DC hook data field */
74 SetDCHook( dce
->hDC
, (FARPROC16
)DCHook
, (DWORD
)dce
);
76 dce
->hwndCurrent
= hWnd
;
81 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
83 dce
->DCXflags
= DCX_DCEBUSY
;
86 WND
* wnd
= WIN_FindWndPtr(hWnd
);
88 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
89 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
91 SetHookFlags(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
93 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
99 /***********************************************************************
102 DCE
* DCE_FreeDCE( DCE
*dce
)
104 DCE
**ppDCE
= &firstDCE
;
106 if (!dce
) return NULL
;
107 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
108 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
110 SetDCHook(dce
->hDC
, NULL
, 0L);
112 DeleteDC32( dce
->hDC
);
113 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
114 DeleteObject32(dce
->hClipRgn
);
115 HeapFree( SystemHeap
, 0, dce
);
119 /***********************************************************************
122 * Remove owned DCE and reset unreleased cache DCEs.
124 void DCE_FreeWindowDCE( WND
* pWnd
)
126 DCE
*pDCE
= firstDCE
;
130 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
132 if( pDCE
== pWnd
->dce
) /* owned DCE */
134 pDCE
= DCE_FreeDCE( pDCE
);
140 if(!(pDCE
->DCXflags
& DCX_CACHE
) ) /* class DCE */
142 if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) )
143 DCE_DeleteClipRgn( pDCE
);
145 else if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
147 ERR(cd
,"[%04x] GetDC() without ReleaseDC()!\n",
149 DCE_ReleaseDC( pDCE
);
152 pDCE
->DCXflags
&= DCX_CACHE
;
153 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
154 pDCE
->hwndCurrent
= 0;
162 /***********************************************************************
165 static void DCE_DeleteClipRgn( DCE
* dce
)
167 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
169 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
170 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
172 if( dce
->hClipRgn
> 1 )
173 DeleteObject32( dce
->hClipRgn
);
177 TRACE(dc
,"\trestoring VisRgn\n");
179 RestoreVisRgn(dce
->hDC
);
183 /***********************************************************************
186 static INT32
DCE_ReleaseDC( DCE
* dce
)
188 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
190 /* restore previous visible region */
192 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
193 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
194 DCE_DeleteClipRgn( dce
);
196 if (dce
->DCXflags
& DCX_CACHE
)
198 SetDCState( dce
->hDC
, defaultDCstate
);
199 dce
->DCXflags
&= ~DCX_DCEBUSY
;
200 if (dce
->DCXflags
& DCX_DCEDIRTY
)
202 /* don't keep around invalidated entries
203 * because SetDCState() disables hVisRgn updates
204 * by removing dirty bit. */
206 dce
->hwndCurrent
= 0;
207 dce
->DCXflags
&= DCX_CACHE
;
208 dce
->DCXflags
|= DCX_DCEEMPTY
;
215 /***********************************************************************
218 * It is called from SetWindowPos() - we have to mark as dirty all busy
219 * DCE's for windows that have pWnd->parent as an ansector and whose client
220 * rect intersects with specified update rectangle.
222 BOOL32
DCE_InvalidateDCE(WND
* pWnd
, const RECT32
* pRectUpdate
)
224 WND
* wndScope
= pWnd
->parent
;
231 TRACE(dc
,"scope hwnd = %04x, (%i,%i - %i,%i)\n",
232 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
233 pRectUpdate
->right
,pRectUpdate
->bottom
);
237 /* walk all DCEs and fixup non-empty entries */
239 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
241 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
243 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
245 if( wndCurrent
&& wndCurrent
!= WIN_GetDesktop() )
247 WND
* wnd
= wndCurrent
;
248 INT32 xoffset
= 0, yoffset
= 0;
250 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) ) continue;
252 /* check if DCE window is within the z-order scope */
254 for( wnd
= wndCurrent
; wnd
; wnd
= wnd
->parent
)
256 if( wnd
== wndScope
)
260 wndRect
= wndCurrent
->rectWindow
;
262 OffsetRect32( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
263 yoffset
- wndCurrent
->rectClient
.top
);
265 if (pWnd
== wndCurrent
||
266 IntersectRect32( &wndRect
, &wndRect
, pRectUpdate
))
268 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
270 /* Don't bother with visible regions of unused DCEs */
272 TRACE(dc
,"\tpurged %08x dce [%04x]\n",
273 (unsigned)dce
, wndCurrent
->hwndSelf
);
275 dce
->hwndCurrent
= 0;
276 dce
->DCXflags
&= DCX_CACHE
;
277 dce
->DCXflags
|= DCX_DCEEMPTY
;
281 /* Set dirty bits in the hDC and DCE structs */
283 TRACE(dc
,"\tfixed up %08x dce [%04x]\n",
284 (unsigned)dce
, wndCurrent
->hwndSelf
);
286 dce
->DCXflags
|= DCX_DCEDIRTY
;
287 SetHookFlags(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
293 xoffset
+= wnd
->rectClient
.left
;
294 yoffset
+= wnd
->rectClient
.top
;
303 /***********************************************************************
311 for (i
= 0; i
< NB_DCE
; i
++)
313 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
314 if (!defaultDCstate
) defaultDCstate
= GetDCState( dce
->hDC
);
319 /***********************************************************************
322 * Calculate the visible rectangle of a window (i.e. the client or
323 * window area clipped by the client area of all ancestors) in the
324 * corresponding coordinates. Return FALSE if the visible region is empty.
326 static BOOL32
DCE_GetVisRect( WND
*wndPtr
, BOOL32 clientArea
, RECT32
*lprect
)
328 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
330 if (wndPtr
->dwStyle
& WS_VISIBLE
)
332 INT32 xoffset
= lprect
->left
;
333 INT32 yoffset
= lprect
->top
;
335 while (wndPtr
->parent
)
337 wndPtr
= wndPtr
->parent
;
339 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
342 xoffset
+= wndPtr
->rectClient
.left
;
343 yoffset
+= wndPtr
->rectClient
.top
;
344 OffsetRect32( lprect
, wndPtr
->rectClient
.left
,
345 wndPtr
->rectClient
.top
);
347 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
348 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
349 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
350 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
351 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
352 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
355 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
356 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
357 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
358 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
360 OffsetRect32( lprect
, -xoffset
, -yoffset
);
365 SetRectEmpty32( lprect
);
370 /***********************************************************************
373 * Go through the linked list of windows from pWndStart to pWndEnd,
374 * adding to the clip region the intersection of the target rectangle
375 * with an offset window rectangle.
377 static BOOL32
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
378 HRGN32 hrgnClip
, LPRECT32 lpRect
, int x
, int y
)
382 if (pWndStart
->window
) return TRUE
; /* X itself will do the clipping */
384 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
386 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
388 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
389 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
390 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
391 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
393 if( IntersectRect32( &rect
, &rect
, lpRect
))
394 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
397 return (pWndStart
== pWndEnd
);
401 /***********************************************************************
404 * Return the visible region of a window, i.e. the client or window area
405 * clipped by the client area of all ancestors, and then optionally
406 * by siblings and children.
408 HRGN32
DCE_GetVisRgn( HWND32 hwnd
, WORD flags
)
412 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
414 /* Get visible rectangle and create a region with it. */
416 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
418 if((hrgnVis
= CreateRectRgnIndirect32( &rect
)))
420 HRGN32 hrgnClip
= CreateRectRgn32( 0, 0, 0, 0 );
421 INT32 xoffset
, yoffset
;
425 /* Compute obscured region for the visible rectangle by
426 * clipping children, siblings, and ancestors. Note that
427 * DCE_GetVisRect() returns a rectangle either in client
428 * or in window coordinates (for DCX_WINDOW request). */
430 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
432 if( flags
& DCX_WINDOW
)
434 /* adjust offsets since child window rectangles are
435 * in client coordinates */
437 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
438 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
441 xoffset
= yoffset
= 0;
443 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
444 &rect
, xoffset
, yoffset
);
447 /* sibling window rectangles are in client
448 * coordinates of the parent window */
450 if (flags
& DCX_WINDOW
)
452 xoffset
= -wndPtr
->rectWindow
.left
;
453 yoffset
= -wndPtr
->rectWindow
.top
;
457 xoffset
= -wndPtr
->rectClient
.left
;
458 yoffset
= -wndPtr
->rectClient
.top
;
461 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
462 DCE_AddClipRects( wndPtr
->parent
->child
,
463 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
465 /* Clip siblings of all ancestors that have the
466 * WS_CLIPSIBLINGS style
469 while (wndPtr
->dwStyle
& WS_CHILD
)
471 wndPtr
= wndPtr
->parent
;
472 xoffset
-= wndPtr
->rectClient
.left
;
473 yoffset
-= wndPtr
->rectClient
.top
;
474 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
476 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
477 hrgnClip
, &rect
, xoffset
, yoffset
);
481 /* Now once we've got a jumbo clip region we have
482 * to substract it from the visible rectangle.
485 CombineRgn32( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
486 DeleteObject32( hrgnClip
);
490 DeleteObject32( hrgnVis
);
496 hrgnVis
= CreateRectRgn32(0, 0, 0, 0); /* empty */
501 /***********************************************************************
504 * Set the drawable, origin and dimensions for the DC associated to
507 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
, BOOL32 bSetClipOrigin
)
509 if (!wndPtr
) /* Get a DC for the whole screen */
513 dc
->u
.x
.drawable
= rootWindow
;
514 TSXSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
518 if (flags
& DCX_WINDOW
)
520 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
521 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
525 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
526 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
528 while (!wndPtr
->window
)
530 wndPtr
= wndPtr
->parent
;
531 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
532 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
534 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
535 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
536 dc
->u
.x
.drawable
= wndPtr
->window
;
538 /* This is needed when we reuse a cached DC because
539 * SetDCState() called by ReleaseDC() screws up DC
540 * origins for child windows.
544 TSXSetClipOrigin( display
, dc
->u
.x
.gc
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
547 /***********************************************************************
550 * Translate given region from the wnd client to the DC coordinates
551 * and add it to the clipping region.
553 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
557 HRGN32 hRgnClip
= GetClipRgn16( hDC
);
560 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
563 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
564 if( dce
->DCXflags
& DCX_WINDOW
)
566 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
567 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
568 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
572 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
573 if( hRgnClip
) ret
= CombineRgn32( hRgnClip
, hRgnClip
, hRgn
, RGN_DIFF
);
576 hRgnClip
= InquireVisRgn( hDC
);
577 ret
= CombineRgn32( hRgn
, hRgnClip
, hRgn
, RGN_DIFF
);
578 SelectClipRgn32( hDC
, hRgn
);
583 /***********************************************************************
584 * GetDCEx16 (USER.359)
586 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
588 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
592 /***********************************************************************
593 * GetDCEx32 (USER32.230)
595 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
597 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
599 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
601 HRGN32 hrgnVisible
= 0;
607 BOOL32 bUpdateVisRgn
= TRUE
;
608 BOOL32 bUpdateClipOrigin
= FALSE
;
610 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
611 hwnd
, hrgnClip
, (unsigned)flags
);
613 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
617 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
619 if (flags
& DCX_USESTYLE
)
621 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
623 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
624 flags
|= DCX_CLIPSIBLINGS
;
626 if ( !(flags
& DCX_WINDOW
) )
628 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
630 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
631 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
633 else flags
|= DCX_CACHE
;
636 if( flags
& DCX_NOCLIPCHILDREN
)
639 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
642 if (flags
& DCX_WINDOW
)
643 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
645 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
646 flags
&= ~DCX_PARENTCLIP
;
647 else if( flags
& DCX_PARENTCLIP
)
650 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
651 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
653 flags
&= ~DCX_CLIPCHILDREN
;
654 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
655 flags
|= DCX_CLIPSIBLINGS
;
659 /* find a suitable DCE */
661 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
662 DCX_CACHE
| DCX_WINDOW
);
664 if (flags
& DCX_CACHE
)
669 dceEmpty
= dceUnused
= NULL
;
671 /* Strategy: First, we attempt to find a non-empty but unused DCE with
672 * compatible flags. Next, we look for an empty entry. If the cache is
673 * full we have to purge one of the unused entries.
676 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
678 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
682 if (dce
->DCXflags
& DCX_DCEEMPTY
)
685 if ((dce
->hwndCurrent
== hwnd
) &&
686 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
687 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
689 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
690 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
691 bUpdateVisRgn
= FALSE
;
692 bUpdateClipOrigin
= TRUE
;
697 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
701 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
702 if( dce
->hwndCurrent
== hwnd
)
704 TRACE(dc
,"\tskipping hVisRgn update\n");
705 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
707 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
708 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
710 /* This is likely to be a nested BeginPaint(). */
712 if( dce
->hClipRgn
!= hrgnClip
)
714 FIXME(dc
,"new hrgnClip[%04x] smashes the previous[%04x]\n",
715 hrgnClip
, dce
->hClipRgn
);
716 DCE_DeleteClipRgn( dce
);
719 RestoreVisRgn(dce
->hDC
);
725 dce
->hwndCurrent
= hwnd
;
727 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
730 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
731 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
733 /* recompute visible region */
735 DCE_SetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
738 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
740 if (flags
& DCX_PARENTCLIP
)
742 WND
*parentPtr
= wndPtr
->parent
;
744 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
746 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
747 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
749 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
751 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
752 if( flags
& DCX_WINDOW
)
753 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
754 -wndPtr
->rectWindow
.top
);
756 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
757 -wndPtr
->rectClient
.top
);
760 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
763 if ((hwnd
== GetDesktopWindow32()) &&
764 (rootWindow
== DefaultRootWindow(display
)))
765 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
766 SYSMETRICS_CYSCREEN
);
767 else hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
769 dc
->w
.flags
&= ~DC_DIRTY
;
770 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
771 SelectVisRgn( hdc
, hrgnVisible
);
774 TRACE(dc
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
776 /* apply additional region operation (if any) */
778 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
780 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
782 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
783 dce
->hClipRgn
= hrgnClip
;
785 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
788 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnClip
,
789 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
790 SelectVisRgn( hdc
, hrgnVisible
);
793 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
795 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
796 hwnd
, hrgnClip
, flags
, hdc
);
801 /***********************************************************************
804 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
806 return (HDC16
)GetDC32( hwnd
);
810 /***********************************************************************
811 * GetDC32 (USER32.229)
816 HDC32 WINAPI
GetDC32(
817 HWND32 hwnd
/* handle of window */
820 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
821 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
825 /***********************************************************************
826 * GetWindowDC16 (USER.67)
828 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
830 if (!hwnd
) hwnd
= GetDesktopWindow16();
831 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
835 /***********************************************************************
836 * GetWindowDC32 (USER32.)
838 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
840 if (!hwnd
) hwnd
= GetDesktopWindow32();
841 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
845 /***********************************************************************
846 * ReleaseDC16 (USER.68)
848 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
850 return (INT16
)ReleaseDC32( hwnd
, hdc
);
854 /***********************************************************************
855 * ReleaseDC32 (USER32.439)
861 INT32 WINAPI
ReleaseDC32(
862 HWND32 hwnd
/* Handle of window - ignored */,
863 HDC32 hdc
/* Handle of device context */
865 DCE
* dce
= firstDCE
;
867 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
869 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
872 if ( dce
->DCXflags
& DCX_DCEBUSY
)
873 return DCE_ReleaseDC( dce
);
877 /***********************************************************************
880 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
882 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
885 DCE
*dce
= firstDCE
;;
887 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
889 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
894 case DCHC_INVALIDVISRGN
:
896 /* GDI code calls this when it detects that the
897 * DC is dirty (usually after SetHookFlags()). This
898 * means that we have to recompute the visible region.
901 if( dce
->DCXflags
& DCX_DCEBUSY
)
903 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
904 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
906 TRACE(dc
,"\tapplying saved clipRgn\n");
908 /* clip this region with saved clipping region */
910 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
911 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
914 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
915 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
916 SetRectRgn32(hVisRgn
,0,0,0,0);
918 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
919 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
921 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
922 SelectVisRgn(hDC
, hVisRgn
);
923 DeleteObject32( hVisRgn
);
925 else /* non-fatal but shouldn't happen */
926 WARN(dc
, "DC is not in use!\n");
929 case DCHC_DELETEDC
: /* FIXME: ?? */
933 FIXME(dc
,"unknown code\n");
939 /**********************************************************************
940 * WindowFromDC16 (USER32.580)
942 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
944 return (HWND16
)WindowFromDC32( hDC
);
948 /**********************************************************************
949 * WindowFromDC32 (USER32.580)
951 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
954 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
955 return dce
? dce
->hwndCurrent
: 0;
959 /***********************************************************************
960 * LockWindowUpdate16 (USER.294)
962 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
964 return LockWindowUpdate32( hwnd
);
968 /***********************************************************************
969 * LockWindowUpdate32 (USER32.377)
971 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
973 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */