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"
29 /* #define DEBUG_DC */
32 #define NB_DCE 5 /* Number of DCEs created at startup */
34 static DCE
*firstDCE
= 0;
35 static HDC32 defaultDCstate
= 0;
37 static void DCE_DeleteClipRgn( DCE
* );
38 static INT32
DCE_ReleaseDC( DCE
* );
41 /***********************************************************************
44 static void DCE_DumpCache(void)
51 printf("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
52 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
, (dce
->DCXflags
& DCX_CACHE
) ?
53 "Cache" : "Owned", (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
58 /***********************************************************************
63 DCE
*DCE_AllocDCE( HWND32 hWnd
, DCE_TYPE type
)
66 if (!(dce
= HeapAlloc( SystemHeap
, 0, sizeof(DCE
) ))) return NULL
;
67 if (!(dce
->hDC
= CreateDC16( "DISPLAY", NULL
, NULL
, NULL
)))
69 HeapFree( SystemHeap
, 0, dce
);
73 /* store DCE handle in DC hook data field */
75 SetDCHook( dce
->hDC
, (FARPROC16
)DCHook
, (DWORD
)dce
);
77 dce
->hwndCurrent
= hWnd
;
82 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
84 dce
->DCXflags
= DCX_DCEBUSY
;
87 WND
* wnd
= WIN_FindWndPtr(hWnd
);
89 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
90 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
92 SetHookFlags(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
94 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
100 /***********************************************************************
103 DCE
* DCE_FreeDCE( DCE
*dce
)
105 DCE
**ppDCE
= &firstDCE
;
107 if (!dce
) return NULL
;
108 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
109 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
111 SetDCHook(dce
->hDC
, NULL
, 0L);
113 DeleteDC32( dce
->hDC
);
114 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
115 DeleteObject32(dce
->hClipRgn
);
116 HeapFree( SystemHeap
, 0, dce
);
120 /***********************************************************************
123 * Remove owned DCE and reset unreleased cache DCEs.
125 void DCE_FreeWindowDCE( WND
* pWnd
)
127 DCE
*pDCE
= firstDCE
;
131 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
133 if( pDCE
== pWnd
->dce
) /* owned DCE */
135 pDCE
= DCE_FreeDCE( pDCE
);
141 if(!(pDCE
->DCXflags
& DCX_CACHE
) ) /* class DCE */
143 if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) )
144 DCE_DeleteClipRgn( pDCE
);
146 else if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
148 fprintf(stderr
,"[%04x] GetDC() without ReleaseDC()!\n", pWnd
->hwndSelf
);
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
);
176 RestoreVisRgn(dce
->hDC
);
180 /***********************************************************************
183 static INT32
DCE_ReleaseDC( DCE
* dce
)
185 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
187 /* restore previous visible region */
189 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
190 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
191 DCE_DeleteClipRgn( dce
);
193 if (dce
->DCXflags
& DCX_CACHE
)
195 SetDCState( dce
->hDC
, defaultDCstate
);
196 dce
->DCXflags
&= ~DCX_DCEBUSY
;
197 if (dce
->DCXflags
& DCX_DCEDIRTY
)
199 /* don't keep around invalidated entries
200 * because SetDCState() disables hVisRgn updates
201 * by removing dirty bit. */
203 dce
->hwndCurrent
= 0;
204 dce
->DCXflags
&= DCX_CACHE
;
205 dce
->DCXflags
|= DCX_DCEEMPTY
;
212 /***********************************************************************
215 * It is called from SetWindowPos() - we have to mark as dirty all busy
216 * DCE's for windows whose client rect intersects with specified update
217 * rectangle. wndScope is the immediate parent of the window(s) that
218 * was(were) moved and(or) resized.
220 BOOL32
DCE_InvalidateDCE(WND
* wndScope
, const RECT32
* pRectUpdate
)
228 dprintf_dc(stddeb
,"InvalidateDCE: scope hwnd = %04x, (%i,%i - %i,%i)\n",
229 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
230 pRectUpdate
->right
,pRectUpdate
->bottom
);
231 if( debugging_dc
) DCE_DumpCache();
233 /* walk all DCEs and fixup non-empty entries */
235 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
237 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
239 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
241 if( wndCurrent
&& wndCurrent
!= WIN_GetDesktop() )
243 WND
* wnd
= wndCurrent
;
244 INT32 xoffset
= 0, yoffset
= 0;
246 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) ) continue;
248 /* check if DCE window is within the z-order scope */
250 for( wnd
= wndCurrent
; wnd
; wnd
= wnd
->parent
)
252 if( wnd
== wndScope
)
256 wndRect
= wndCurrent
->rectWindow
;
258 OffsetRect32( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
259 yoffset
- wndCurrent
->rectClient
.top
);
260 if (IntersectRect32( &wndRect
, &wndRect
, pRectUpdate
))
262 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
264 /* Don't bother with visible regions of unused DCEs */
266 dprintf_dc(stddeb
,"\tpurged %08x dce [%04x]\n",
267 (unsigned)dce
, wndCurrent
->hwndSelf
);
269 dce
->hwndCurrent
= 0;
270 dce
->DCXflags
&= DCX_CACHE
;
271 dce
->DCXflags
|= DCX_DCEEMPTY
;
275 /* Set dirty bits in the hDC and DCE structs */
277 dprintf_dc(stddeb
,"\tfixed up %08x dce [%04x]\n",
278 (unsigned)dce
, wndCurrent
->hwndSelf
);
280 dce
->DCXflags
|= DCX_DCEDIRTY
;
281 SetHookFlags(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
287 xoffset
+= wnd
->rectClient
.left
;
288 yoffset
+= wnd
->rectClient
.top
;
297 /***********************************************************************
305 for (i
= 0; i
< NB_DCE
; i
++)
307 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
308 if (!defaultDCstate
) defaultDCstate
= GetDCState( dce
->hDC
);
313 /***********************************************************************
316 * Calculate the visible rectangle of a window (i.e. the client or
317 * window area clipped by the client area of all ancestors) in the
318 * corresponding coordinates. Return FALSE if the visible region is empty.
320 static BOOL32
DCE_GetVisRect( WND
*wndPtr
, BOOL32 clientArea
, RECT32
*lprect
)
322 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
324 if (wndPtr
->dwStyle
& WS_VISIBLE
)
326 INT32 xoffset
= lprect
->left
;
327 INT32 yoffset
= lprect
->top
;
329 while (wndPtr
->parent
)
331 wndPtr
= wndPtr
->parent
;
333 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
336 xoffset
+= wndPtr
->rectClient
.left
;
337 yoffset
+= wndPtr
->rectClient
.top
;
338 OffsetRect32( lprect
, wndPtr
->rectClient
.left
,
339 wndPtr
->rectClient
.top
);
341 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
342 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
343 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
344 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
345 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
346 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
349 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
350 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
351 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
352 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
354 OffsetRect32( lprect
, -xoffset
, -yoffset
);
359 SetRectEmpty32( lprect
);
364 /***********************************************************************
367 * Go through the linked list of windows from pWndStart to pWndEnd,
368 * adding to the clip region the intersection of the target rectangle
369 * with an offset window rectangle.
371 static BOOL32
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
372 HRGN32 hrgnClip
, LPRECT32 lpRect
, int x
, int y
)
376 if (pWndStart
->window
) return TRUE
; /* X itself will do the clipping */
378 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
380 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
382 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
383 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
384 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
385 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
387 if( IntersectRect32( &rect
, &rect
, lpRect
))
388 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
391 return (pWndStart
== pWndEnd
);
395 /***********************************************************************
398 * Return the visible region of a window, i.e. the client or window area
399 * clipped by the client area of all ancestors, and then optionally
400 * by siblings and children.
402 HRGN32
DCE_GetVisRgn( HWND32 hwnd
, WORD flags
)
406 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
408 /* Get visible rectangle and create a region with it. */
410 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
412 if((hrgnVis
= CreateRectRgnIndirect32( &rect
)))
414 HRGN32 hrgnClip
= CreateRectRgn32( 0, 0, 0, 0 );
415 INT32 xoffset
, yoffset
;
419 /* Compute obscured region for the visible rectangle by
420 * clipping children, siblings, and ancestors. Note that
421 * DCE_GetVisRect() returns a rectangle either in client
422 * or in window coordinates (for DCX_WINDOW request). */
424 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
426 if( flags
& DCX_WINDOW
)
428 /* adjust offsets since child window rectangles are
429 * in client coordinates */
431 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
432 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
435 xoffset
= yoffset
= 0;
437 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
438 &rect
, xoffset
, yoffset
);
441 /* sibling window rectangles are in client
442 * coordinates of the parent window */
444 if (flags
& DCX_WINDOW
)
446 xoffset
= -wndPtr
->rectWindow
.left
;
447 yoffset
= -wndPtr
->rectWindow
.top
;
451 xoffset
= -wndPtr
->rectClient
.left
;
452 yoffset
= -wndPtr
->rectClient
.top
;
455 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
456 DCE_AddClipRects( wndPtr
->parent
->child
,
457 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
459 /* Clip siblings of all ancestors that have the
460 * WS_CLIPSIBLINGS style
463 while (wndPtr
->dwStyle
& WS_CHILD
)
465 wndPtr
= wndPtr
->parent
;
466 xoffset
-= wndPtr
->rectClient
.left
;
467 yoffset
-= wndPtr
->rectClient
.top
;
468 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
470 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
471 hrgnClip
, &rect
, xoffset
, yoffset
);
475 /* Now once we've got a jumbo clip region we have
476 * to substract it from the visible rectangle.
479 CombineRgn32( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
480 DeleteObject32( hrgnClip
);
484 DeleteObject32( hrgnVis
);
490 hrgnVis
= CreateRectRgn32(0, 0, 0, 0); /* empty */
495 /***********************************************************************
498 * Set the drawable, origin and dimensions for the DC associated to
501 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
, BOOL32 bSetClipOrigin
)
503 if (!wndPtr
) /* Get a DC for the whole screen */
507 dc
->u
.x
.drawable
= rootWindow
;
508 XSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
512 if (flags
& DCX_WINDOW
)
514 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
515 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
519 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
520 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
522 while (!wndPtr
->window
)
524 wndPtr
= wndPtr
->parent
;
525 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
526 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
528 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
529 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
530 dc
->u
.x
.drawable
= wndPtr
->window
;
532 /* This is needed when we reuse a cached DC because
533 * SetDCState() called by ReleaseDC() screws up DC
534 * origins for child windows.
538 XSetClipOrigin( display
, dc
->u
.x
.gc
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
541 /***********************************************************************
544 * Translate given region from the wnd client to the DC coordinates
545 * and add it to the clipping region.
547 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
551 HRGN32 hRgnClip
= GetClipRgn16( hDC
);
554 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
557 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
558 if( dce
->DCXflags
& DCX_WINDOW
)
560 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
561 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
562 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
566 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
567 if( hRgnClip
) ret
= CombineRgn32( hRgnClip
, hRgnClip
, hRgn
, RGN_DIFF
);
570 hRgnClip
= InquireVisRgn( hDC
);
571 ret
= CombineRgn32( hRgn
, hRgnClip
, hRgn
, RGN_DIFF
);
572 SelectClipRgn32( hDC
, hRgn
);
577 /***********************************************************************
578 * GetDCEx16 (USER.359)
580 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
582 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
586 /***********************************************************************
587 * GetDCEx32 (USER32.230)
589 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
591 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
593 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
595 HRGN32 hrgnVisible
= 0;
601 BOOL32 bUpdateVisRgn
= TRUE
;
602 BOOL32 bUpdateClipOrigin
= FALSE
;
604 dprintf_dc(stddeb
,"GetDCEx: hwnd %04x, hrgnClip %04x, flags %08x\n",
605 hwnd
, hrgnClip
, (unsigned)flags
);
607 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
611 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
613 if (flags
& DCX_USESTYLE
)
615 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
617 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
618 flags
|= DCX_CLIPSIBLINGS
;
620 if ( !(flags
& DCX_WINDOW
) )
622 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
624 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
625 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
627 else flags
|= DCX_CACHE
;
630 if( flags
& DCX_NOCLIPCHILDREN
)
633 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
636 if (flags
& DCX_WINDOW
)
637 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
639 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
640 flags
&= ~DCX_PARENTCLIP
;
641 else if( flags
& DCX_PARENTCLIP
)
644 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
645 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
647 flags
&= ~DCX_CLIPCHILDREN
;
648 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
649 flags
|= DCX_CLIPSIBLINGS
;
653 /* find a suitable DCE */
655 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
656 DCX_CACHE
| DCX_WINDOW
);
658 if (flags
& DCX_CACHE
)
663 dceEmpty
= dceUnused
= NULL
;
665 /* Strategy: First, we attempt to find a non-empty but unused DCE with
666 * compatible flags. Next, we look for an empty entry. If the cache is
667 * full we have to purge one of the unused entries.
670 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
672 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
676 if (dce
->DCXflags
& DCX_DCEEMPTY
)
679 if ((dce
->hwndCurrent
== hwnd
) &&
680 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
681 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
683 dprintf_dc(stddeb
,"\tfound valid %08x dce [%04x], flags %08x\n",
684 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
685 bUpdateVisRgn
= FALSE
;
686 bUpdateClipOrigin
= TRUE
;
691 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
695 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
696 if( dce
->hwndCurrent
== hwnd
)
698 dprintf_dc(stddeb
,"\tskipping hVisRgn update\n");
699 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
701 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
702 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
704 /* This is likely to be a nested BeginPaint(). */
706 if( dce
->hClipRgn
!= hrgnClip
)
708 fprintf(stdnimp
,"GetDCEx: new hrgnClip [%04x] smashes the previous [%04x]!\n",
709 hrgnClip
, dce
->hClipRgn
);
710 DCE_DeleteClipRgn( dce
);
713 RestoreVisRgn(dce
->hDC
);
719 dce
->hwndCurrent
= hwnd
;
721 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
724 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
725 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
727 /* recompute visible region */
729 DCE_SetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
732 dprintf_dc(stddeb
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
734 if (flags
& DCX_PARENTCLIP
)
736 WND
*parentPtr
= wndPtr
->parent
;
738 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
740 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
741 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
743 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
745 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
746 if( flags
& DCX_WINDOW
)
747 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
748 -wndPtr
->rectWindow
.top
);
750 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
751 -wndPtr
->rectClient
.top
);
754 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
757 if ((hwnd
== GetDesktopWindow32()) &&
758 (rootWindow
== DefaultRootWindow(display
)))
759 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
760 SYSMETRICS_CYSCREEN
);
761 else hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
764 if( wndPtr
->parent
&& wndPtr
->window
)
766 /* Problem - X doesn't discard save under buffers when
767 * the old data is invalidated by the new graphics output.
769 * FIXME: Instead of overriding we should try to discard
770 * save_unders by calling XSetWindowAttributes().
771 * And we should do it for the child window GetDCEx()
774 WND
* wnd
= wndPtr
->parent
->child
;
777 for( ; wnd
&& (wnd
!= wndPtr
); wnd
= wnd
->next
) {
778 if( wnd
->class->style
& CS_SAVEBITS
&&
779 wnd
->dwStyle
& WS_VISIBLE
&&
780 IntersectRect32(&rect
, &wndPtr
->rectClient
, &wnd
->rectClient
) )
781 wnd
->flags
|= WIN_SAVEUNDER_OVERRIDE
;
784 dc
->w
.flags
&= ~DC_DIRTY
;
785 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
786 SelectVisRgn( hdc
, hrgnVisible
);
789 dprintf_dc(stddeb
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
791 /* apply additional region operation (if any) */
793 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
795 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
797 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
798 dce
->hClipRgn
= hrgnClip
;
800 dprintf_dc(stddeb
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
803 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnClip
,
804 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
805 SelectVisRgn( hdc
, hrgnVisible
);
808 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
810 dprintf_dc(stddeb
, "GetDCEx(%04x,%04x,0x%lx): returning %04x\n",
811 hwnd
, hrgnClip
, flags
, hdc
);
816 /***********************************************************************
819 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
821 return (HDC16
)GetDC32( hwnd
);
825 /***********************************************************************
826 * GetDC32 (USER32.229)
828 HDC32 WINAPI
GetDC32( HWND32 hwnd
)
831 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
832 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
836 /***********************************************************************
837 * GetWindowDC16 (USER.67)
839 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
841 if (!hwnd
) hwnd
= GetDesktopWindow16();
842 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
846 /***********************************************************************
847 * GetWindowDC32 (USER32.)
849 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
851 if (!hwnd
) hwnd
= GetDesktopWindow32();
852 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
856 /***********************************************************************
857 * ReleaseDC16 (USER.68)
859 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
861 return (INT32
)ReleaseDC32( hwnd
, hdc
);
865 /***********************************************************************
866 * ReleaseDC32 (USER32.439)
868 INT32 WINAPI
ReleaseDC32( HWND32 hwnd
, HDC32 hdc
)
870 DCE
* dce
= firstDCE
;
872 dprintf_dc(stddeb
, "ReleaseDC: %04x %04x\n", hwnd
, hdc
);
874 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
877 if ( dce
->DCXflags
& DCX_DCEBUSY
)
878 return DCE_ReleaseDC( dce
);
882 /***********************************************************************
885 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
887 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
890 DCE
*dce
= firstDCE
;;
892 dprintf_dc(stddeb
,"DCHook: hDC = %04x, %i\n", hDC
, code
);
894 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
899 case DCHC_INVALIDVISRGN
:
901 /* GDI code calls this when it detects that the
902 * DC is dirty (usually after SetHookFlags()). This
903 * means that we have to recompute the visible region.
906 if( dce
->DCXflags
& DCX_DCEBUSY
)
908 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
909 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
911 dprintf_dc(stddeb
,"\tapplying saved clipRgn\n");
913 /* clip this region with saved clipping region */
915 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
916 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
919 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
920 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
921 SetRectRgn32(hVisRgn
,0,0,0,0);
923 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
924 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
926 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
927 SelectVisRgn(hDC
, hVisRgn
);
928 DeleteObject32( hVisRgn
);
930 else /* non-fatal but shouldn't happen */
931 dprintf_dc(stddeb
,"DCHook: DC is not in use!\n");
934 case DCHC_DELETEDC
: /* FIXME: ?? */
938 fprintf(stdnimp
,"DCHook: unknown code\n");
944 /**********************************************************************
945 * WindowFromDC16 (USER32.580)
947 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
949 return (HWND16
)WindowFromDC32( hDC
);
953 /**********************************************************************
954 * WindowFromDC32 (USER32.580)
956 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
959 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
960 return dce
? dce
->hwndCurrent
: 0;
964 /***********************************************************************
965 * LockWindowUpdate16 (USER.294)
967 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
969 return LockWindowUpdate32( hwnd
);
973 /***********************************************************************
974 * LockWindowUpdate32 (USER32.377)
976 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
978 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */