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(dc
,"[%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
->dwStyle
& WS_CHILD
)
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
->pDriver
->pIsSelfClipping( pWndStart
) )
383 return TRUE
; /* The driver itself will do the clipping */
385 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
387 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
389 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
390 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
391 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
392 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
394 if( IntersectRect32( &rect
, &rect
, lpRect
))
395 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
398 return (pWndStart
== pWndEnd
);
402 /***********************************************************************
405 * Return the visible region of a window, i.e. the client or window area
406 * clipped by the client area of all ancestors, and then optionally
407 * by siblings and children.
409 HRGN32
DCE_GetVisRgn( HWND32 hwnd
, WORD flags
)
413 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
415 /* Get visible rectangle and create a region with it. */
417 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
419 if((hrgnVis
= CreateRectRgnIndirect32( &rect
)))
421 HRGN32 hrgnClip
= CreateRectRgn32( 0, 0, 0, 0 );
422 INT32 xoffset
, yoffset
;
426 /* Compute obscured region for the visible rectangle by
427 * clipping children, siblings, and ancestors. Note that
428 * DCE_GetVisRect() returns a rectangle either in client
429 * or in window coordinates (for DCX_WINDOW request). */
431 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
433 if( flags
& DCX_WINDOW
)
435 /* adjust offsets since child window rectangles are
436 * in client coordinates */
438 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
439 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
442 xoffset
= yoffset
= 0;
444 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
445 &rect
, xoffset
, yoffset
);
448 /* sibling window rectangles are in client
449 * coordinates of the parent window */
451 if (flags
& DCX_WINDOW
)
453 xoffset
= -wndPtr
->rectWindow
.left
;
454 yoffset
= -wndPtr
->rectWindow
.top
;
458 xoffset
= -wndPtr
->rectClient
.left
;
459 yoffset
= -wndPtr
->rectClient
.top
;
462 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
463 DCE_AddClipRects( wndPtr
->parent
->child
,
464 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
466 /* Clip siblings of all ancestors that have the
467 * WS_CLIPSIBLINGS style
470 while (wndPtr
->dwStyle
& WS_CHILD
)
472 wndPtr
= wndPtr
->parent
;
473 xoffset
-= wndPtr
->rectClient
.left
;
474 yoffset
-= wndPtr
->rectClient
.top
;
475 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
477 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
478 hrgnClip
, &rect
, xoffset
, yoffset
);
482 /* Now once we've got a jumbo clip region we have
483 * to substract it from the visible rectangle.
486 CombineRgn32( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
487 DeleteObject32( hrgnClip
);
491 DeleteObject32( hrgnVis
);
497 hrgnVis
= CreateRectRgn32(0, 0, 0, 0); /* empty */
501 /***********************************************************************
504 * Change region from DC-origin relative coordinates to screen coords.
507 static void DCE_OffsetVisRgn( HDC32 hDC
, HRGN32 hVisRgn
)
510 if (!(dc
= (DC
*) GDI_GetObjPtr( hDC
, DC_MAGIC
))) return;
512 OffsetRgn32( hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
514 GDI_HEAP_UNLOCK( hDC
);
517 /***********************************************************************
520 * Translate given region from the wnd client to the DC coordinates
521 * and add it to the clipping region.
523 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
528 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
531 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
532 if( dce
->DCXflags
& DCX_WINDOW
)
534 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
535 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
536 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
540 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
542 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
545 /***********************************************************************
546 * GetDCEx16 (USER.359)
548 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
550 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
554 /***********************************************************************
555 * GetDCEx32 (USER32.231)
557 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
559 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
561 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
563 HRGN32 hrgnVisible
= 0;
569 BOOL32 bUpdateVisRgn
= TRUE
;
570 BOOL32 bUpdateClipOrigin
= FALSE
;
572 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
573 hwnd
, hrgnClip
, (unsigned)flags
);
575 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
579 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
581 if (flags
& DCX_USESTYLE
)
583 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
585 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
586 flags
|= DCX_CLIPSIBLINGS
;
588 if ( !(flags
& DCX_WINDOW
) )
590 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
592 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
593 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
595 else flags
|= DCX_CACHE
;
598 if( flags
& DCX_NOCLIPCHILDREN
)
601 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
604 if (flags
& DCX_WINDOW
)
605 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
607 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
608 flags
&= ~DCX_PARENTCLIP
;
609 else if( flags
& DCX_PARENTCLIP
)
612 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
613 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
615 flags
&= ~DCX_CLIPCHILDREN
;
616 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
617 flags
|= DCX_CLIPSIBLINGS
;
621 /* find a suitable DCE */
623 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
624 DCX_CACHE
| DCX_WINDOW
);
626 if (flags
& DCX_CACHE
)
631 dceEmpty
= dceUnused
= NULL
;
633 /* Strategy: First, we attempt to find a non-empty but unused DCE with
634 * compatible flags. Next, we look for an empty entry. If the cache is
635 * full we have to purge one of the unused entries.
638 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
640 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
644 if (dce
->DCXflags
& DCX_DCEEMPTY
)
647 if ((dce
->hwndCurrent
== hwnd
) &&
648 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
649 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
651 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
652 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
653 bUpdateVisRgn
= FALSE
;
654 bUpdateClipOrigin
= TRUE
;
659 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
663 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
664 if( dce
->hwndCurrent
== hwnd
)
666 TRACE(dc
,"\tskipping hVisRgn update\n");
667 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
669 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
670 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
672 /* This is likely to be a nested BeginPaint(). */
674 if( dce
->hClipRgn
!= hrgnClip
)
676 FIXME(dc
,"new hrgnClip[%04x] smashes the previous[%04x]\n",
677 hrgnClip
, dce
->hClipRgn
);
678 DCE_DeleteClipRgn( dce
);
681 RestoreVisRgn(dce
->hDC
);
687 dce
->hwndCurrent
= hwnd
;
689 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
692 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
693 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
695 /* recompute visible region */
697 wndPtr
->pDriver
->pSetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
700 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
702 if (flags
& DCX_PARENTCLIP
)
704 WND
*parentPtr
= wndPtr
->parent
;
706 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
708 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
709 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
711 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
713 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
714 if( flags
& DCX_WINDOW
)
715 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
716 -wndPtr
->rectWindow
.top
);
718 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
719 -wndPtr
->rectClient
.top
);
720 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
723 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
726 if ((hwnd
== GetDesktopWindow32()) &&
727 (rootWindow
== DefaultRootWindow(display
)))
728 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
729 SYSMETRICS_CYSCREEN
);
732 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
733 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
736 dc
->w
.flags
&= ~DC_DIRTY
;
737 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
738 SelectVisRgn( hdc
, hrgnVisible
);
741 TRACE(dc
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
743 /* apply additional region operation (if any) */
745 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
747 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
749 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
750 dce
->hClipRgn
= hrgnClip
;
752 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
755 CombineRgn32( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
756 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
757 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnVisible
,
758 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
759 SelectVisRgn( hdc
, hrgnVisible
);
762 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
764 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
765 hwnd
, hrgnClip
, flags
, hdc
);
770 /***********************************************************************
773 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
775 return (HDC16
)GetDC32( hwnd
);
779 /***********************************************************************
780 * GetDC32 (USER32.230)
785 HDC32 WINAPI
GetDC32(
786 HWND32 hwnd
/* handle of window */
789 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
790 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
794 /***********************************************************************
795 * GetWindowDC16 (USER.67)
797 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
799 if (!hwnd
) hwnd
= GetDesktopWindow16();
800 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
804 /***********************************************************************
805 * GetWindowDC32 (USER32.304)
807 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
809 if (!hwnd
) hwnd
= GetDesktopWindow32();
810 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
814 /***********************************************************************
815 * ReleaseDC16 (USER.68)
817 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
819 return (INT16
)ReleaseDC32( hwnd
, hdc
);
823 /***********************************************************************
824 * ReleaseDC32 (USER32.440)
830 INT32 WINAPI
ReleaseDC32(
831 HWND32 hwnd
/* Handle of window - ignored */,
832 HDC32 hdc
/* Handle of device context */
834 DCE
* dce
= firstDCE
;
836 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
838 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
841 if ( dce
->DCXflags
& DCX_DCEBUSY
)
842 return DCE_ReleaseDC( dce
);
846 /***********************************************************************
849 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
851 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
854 DCE
*dce
= firstDCE
;;
856 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
858 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
863 case DCHC_INVALIDVISRGN
:
865 /* GDI code calls this when it detects that the
866 * DC is dirty (usually after SetHookFlags()). This
867 * means that we have to recompute the visible region.
870 if( dce
->DCXflags
& DCX_DCEBUSY
)
872 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
873 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
875 TRACE(dc
,"\tapplying saved clipRgn\n");
877 /* clip this region with saved clipping region */
879 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
880 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
883 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
884 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
885 SetRectRgn32(hVisRgn
,0,0,0,0);
887 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
888 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
890 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
891 DCE_OffsetVisRgn( hDC
, hVisRgn
);
892 SelectVisRgn(hDC
, hVisRgn
);
893 DeleteObject32( hVisRgn
);
895 else /* non-fatal but shouldn't happen */
896 WARN(dc
, "DC is not in use!\n");
899 case DCHC_DELETEDC
: /* FIXME: ?? */
903 FIXME(dc
,"unknown code\n");
909 /**********************************************************************
910 * WindowFromDC16 (USER.117)
912 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
914 return (HWND16
)WindowFromDC32( hDC
);
918 /**********************************************************************
919 * WindowFromDC32 (USER32.581)
921 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
924 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
925 return dce
? dce
->hwndCurrent
: 0;
929 /***********************************************************************
930 * LockWindowUpdate16 (USER.294)
932 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
934 return LockWindowUpdate32( hwnd
);
938 /***********************************************************************
939 * LockWindowUpdate32 (USER32.378)
941 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
943 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */