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 printf("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
50 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
, (dce
->DCXflags
& DCX_CACHE
) ?
51 "Cache" : "Owned", (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
56 /***********************************************************************
61 DCE
*DCE_AllocDCE( HWND32 hWnd
, DCE_TYPE type
)
64 if (!(dce
= HeapAlloc( SystemHeap
, 0, sizeof(DCE
) ))) return NULL
;
65 if (!(dce
->hDC
= CreateDC16( "DISPLAY", NULL
, NULL
, NULL
)))
67 HeapFree( SystemHeap
, 0, dce
);
71 /* store DCE handle in DC hook data field */
73 SetDCHook( dce
->hDC
, (FARPROC16
)DCHook
, (DWORD
)dce
);
75 dce
->hwndCurrent
= hWnd
;
80 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
82 dce
->DCXflags
= DCX_DCEBUSY
;
85 WND
* wnd
= WIN_FindWndPtr(hWnd
);
87 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
88 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
90 SetHookFlags(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
92 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
98 /***********************************************************************
101 DCE
* DCE_FreeDCE( DCE
*dce
)
103 DCE
**ppDCE
= &firstDCE
;
105 if (!dce
) return NULL
;
106 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
107 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
109 SetDCHook(dce
->hDC
, NULL
, 0L);
111 DeleteDC32( dce
->hDC
);
112 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
113 DeleteObject32(dce
->hClipRgn
);
114 HeapFree( SystemHeap
, 0, dce
);
118 /***********************************************************************
121 * Remove owned DCE and reset unreleased cache DCEs.
123 void DCE_FreeWindowDCE( WND
* pWnd
)
125 DCE
*pDCE
= firstDCE
;
129 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
131 if( pDCE
== pWnd
->dce
) /* owned DCE */
133 pDCE
= DCE_FreeDCE( pDCE
);
139 if(!(pDCE
->DCXflags
& DCX_CACHE
) ) /* class DCE */
141 if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) )
142 DCE_DeleteClipRgn( pDCE
);
144 else if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
146 fprintf(stderr
,"[%04x] GetDC() without ReleaseDC()!\n", pWnd
->hwndSelf
);
147 DCE_ReleaseDC( pDCE
);
150 pDCE
->DCXflags
&= DCX_CACHE
;
151 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
152 pDCE
->hwndCurrent
= 0;
160 /***********************************************************************
163 static void DCE_DeleteClipRgn( DCE
* dce
)
165 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
167 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
168 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
170 if( dce
->hClipRgn
> 1 )
171 DeleteObject32( dce
->hClipRgn
);
175 TRACE(dc
,"\trestoring VisRgn\n");
177 RestoreVisRgn(dce
->hDC
);
181 /***********************************************************************
184 static INT32
DCE_ReleaseDC( DCE
* dce
)
186 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
188 /* restore previous visible region */
190 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
191 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
192 DCE_DeleteClipRgn( dce
);
194 if (dce
->DCXflags
& DCX_CACHE
)
196 SetDCState( dce
->hDC
, defaultDCstate
);
197 dce
->DCXflags
&= ~DCX_DCEBUSY
;
198 if (dce
->DCXflags
& DCX_DCEDIRTY
)
200 /* don't keep around invalidated entries
201 * because SetDCState() disables hVisRgn updates
202 * by removing dirty bit. */
204 dce
->hwndCurrent
= 0;
205 dce
->DCXflags
&= DCX_CACHE
;
206 dce
->DCXflags
|= DCX_DCEEMPTY
;
213 /***********************************************************************
216 * It is called from SetWindowPos() - we have to mark as dirty all busy
217 * DCE's for windows that have pWnd->parent as an ansector and whose client
218 * rect intersects with specified update rectangle.
220 BOOL32
DCE_InvalidateDCE(WND
* pWnd
, const RECT32
* pRectUpdate
)
222 WND
* wndScope
= pWnd
->parent
;
229 TRACE(dc
,"scope hwnd = %04x, (%i,%i - %i,%i)\n",
230 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
231 pRectUpdate
->right
,pRectUpdate
->bottom
);
235 /* walk all DCEs and fixup non-empty entries */
237 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
239 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
241 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
243 if( wndCurrent
&& wndCurrent
!= WIN_GetDesktop() )
245 WND
* wnd
= wndCurrent
;
246 INT32 xoffset
= 0, yoffset
= 0;
248 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) ) continue;
250 /* check if DCE window is within the z-order scope */
252 for( wnd
= wndCurrent
; wnd
; wnd
= wnd
->parent
)
254 if( wnd
== wndScope
)
258 wndRect
= wndCurrent
->rectWindow
;
260 OffsetRect32( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
261 yoffset
- wndCurrent
->rectClient
.top
);
263 if (pWnd
== wndCurrent
||
264 IntersectRect32( &wndRect
, &wndRect
, pRectUpdate
))
266 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
268 /* Don't bother with visible regions of unused DCEs */
270 TRACE(dc
,"\tpurged %08x dce [%04x]\n",
271 (unsigned)dce
, wndCurrent
->hwndSelf
);
273 dce
->hwndCurrent
= 0;
274 dce
->DCXflags
&= DCX_CACHE
;
275 dce
->DCXflags
|= DCX_DCEEMPTY
;
279 /* Set dirty bits in the hDC and DCE structs */
281 TRACE(dc
,"\tfixed up %08x dce [%04x]\n",
282 (unsigned)dce
, wndCurrent
->hwndSelf
);
284 dce
->DCXflags
|= DCX_DCEDIRTY
;
285 SetHookFlags(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
291 xoffset
+= wnd
->rectClient
.left
;
292 yoffset
+= wnd
->rectClient
.top
;
301 /***********************************************************************
309 for (i
= 0; i
< NB_DCE
; i
++)
311 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
312 if (!defaultDCstate
) defaultDCstate
= GetDCState( dce
->hDC
);
317 /***********************************************************************
320 * Calculate the visible rectangle of a window (i.e. the client or
321 * window area clipped by the client area of all ancestors) in the
322 * corresponding coordinates. Return FALSE if the visible region is empty.
324 static BOOL32
DCE_GetVisRect( WND
*wndPtr
, BOOL32 clientArea
, RECT32
*lprect
)
326 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
328 if (wndPtr
->dwStyle
& WS_VISIBLE
)
330 INT32 xoffset
= lprect
->left
;
331 INT32 yoffset
= lprect
->top
;
333 while (wndPtr
->parent
)
335 wndPtr
= wndPtr
->parent
;
337 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
340 xoffset
+= wndPtr
->rectClient
.left
;
341 yoffset
+= wndPtr
->rectClient
.top
;
342 OffsetRect32( lprect
, wndPtr
->rectClient
.left
,
343 wndPtr
->rectClient
.top
);
345 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
346 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
347 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
348 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
349 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
350 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
353 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
354 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
355 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
356 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
358 OffsetRect32( lprect
, -xoffset
, -yoffset
);
363 SetRectEmpty32( lprect
);
368 /***********************************************************************
371 * Go through the linked list of windows from pWndStart to pWndEnd,
372 * adding to the clip region the intersection of the target rectangle
373 * with an offset window rectangle.
375 static BOOL32
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
376 HRGN32 hrgnClip
, LPRECT32 lpRect
, int x
, int y
)
380 if (pWndStart
->window
) return TRUE
; /* X itself will do the clipping */
382 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
384 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
386 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
387 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
388 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
389 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
391 if( IntersectRect32( &rect
, &rect
, lpRect
))
392 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
395 return (pWndStart
== pWndEnd
);
399 /***********************************************************************
402 * Return the visible region of a window, i.e. the client or window area
403 * clipped by the client area of all ancestors, and then optionally
404 * by siblings and children.
406 HRGN32
DCE_GetVisRgn( HWND32 hwnd
, WORD flags
)
410 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
412 /* Get visible rectangle and create a region with it. */
414 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
416 if((hrgnVis
= CreateRectRgnIndirect32( &rect
)))
418 HRGN32 hrgnClip
= CreateRectRgn32( 0, 0, 0, 0 );
419 INT32 xoffset
, yoffset
;
423 /* Compute obscured region for the visible rectangle by
424 * clipping children, siblings, and ancestors. Note that
425 * DCE_GetVisRect() returns a rectangle either in client
426 * or in window coordinates (for DCX_WINDOW request). */
428 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
430 if( flags
& DCX_WINDOW
)
432 /* adjust offsets since child window rectangles are
433 * in client coordinates */
435 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
436 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
439 xoffset
= yoffset
= 0;
441 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
442 &rect
, xoffset
, yoffset
);
445 /* sibling window rectangles are in client
446 * coordinates of the parent window */
448 if (flags
& DCX_WINDOW
)
450 xoffset
= -wndPtr
->rectWindow
.left
;
451 yoffset
= -wndPtr
->rectWindow
.top
;
455 xoffset
= -wndPtr
->rectClient
.left
;
456 yoffset
= -wndPtr
->rectClient
.top
;
459 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
460 DCE_AddClipRects( wndPtr
->parent
->child
,
461 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
463 /* Clip siblings of all ancestors that have the
464 * WS_CLIPSIBLINGS style
467 while (wndPtr
->dwStyle
& WS_CHILD
)
469 wndPtr
= wndPtr
->parent
;
470 xoffset
-= wndPtr
->rectClient
.left
;
471 yoffset
-= wndPtr
->rectClient
.top
;
472 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
474 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
475 hrgnClip
, &rect
, xoffset
, yoffset
);
479 /* Now once we've got a jumbo clip region we have
480 * to substract it from the visible rectangle.
483 CombineRgn32( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
484 DeleteObject32( hrgnClip
);
488 DeleteObject32( hrgnVis
);
494 hrgnVis
= CreateRectRgn32(0, 0, 0, 0); /* empty */
499 /***********************************************************************
502 * Set the drawable, origin and dimensions for the DC associated to
505 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
, BOOL32 bSetClipOrigin
)
507 if (!wndPtr
) /* Get a DC for the whole screen */
511 dc
->u
.x
.drawable
= rootWindow
;
512 TSXSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
516 if (flags
& DCX_WINDOW
)
518 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
519 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
523 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
524 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
526 while (!wndPtr
->window
)
528 wndPtr
= wndPtr
->parent
;
529 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
530 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
532 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
533 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
534 dc
->u
.x
.drawable
= wndPtr
->window
;
536 /* This is needed when we reuse a cached DC because
537 * SetDCState() called by ReleaseDC() screws up DC
538 * origins for child windows.
542 TSXSetClipOrigin( display
, dc
->u
.x
.gc
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
545 /***********************************************************************
548 * Translate given region from the wnd client to the DC coordinates
549 * and add it to the clipping region.
551 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
555 HRGN32 hRgnClip
= GetClipRgn16( hDC
);
558 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
561 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
562 if( dce
->DCXflags
& DCX_WINDOW
)
564 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
565 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
566 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
570 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
571 if( hRgnClip
) ret
= CombineRgn32( hRgnClip
, hRgnClip
, hRgn
, RGN_DIFF
);
574 hRgnClip
= InquireVisRgn( hDC
);
575 ret
= CombineRgn32( hRgn
, hRgnClip
, hRgn
, RGN_DIFF
);
576 SelectClipRgn32( hDC
, hRgn
);
581 /***********************************************************************
582 * GetDCEx16 (USER.359)
584 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
586 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
590 /***********************************************************************
591 * GetDCEx32 (USER32.230)
593 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
595 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
597 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
599 HRGN32 hrgnVisible
= 0;
605 BOOL32 bUpdateVisRgn
= TRUE
;
606 BOOL32 bUpdateClipOrigin
= FALSE
;
608 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
609 hwnd
, hrgnClip
, (unsigned)flags
);
611 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
615 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
617 if (flags
& DCX_USESTYLE
)
619 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
621 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
622 flags
|= DCX_CLIPSIBLINGS
;
624 if ( !(flags
& DCX_WINDOW
) )
626 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
628 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
629 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
631 else flags
|= DCX_CACHE
;
634 if( flags
& DCX_NOCLIPCHILDREN
)
637 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
640 if (flags
& DCX_WINDOW
)
641 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
643 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
644 flags
&= ~DCX_PARENTCLIP
;
645 else if( flags
& DCX_PARENTCLIP
)
648 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
649 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
651 flags
&= ~DCX_CLIPCHILDREN
;
652 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
653 flags
|= DCX_CLIPSIBLINGS
;
657 /* find a suitable DCE */
659 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
660 DCX_CACHE
| DCX_WINDOW
);
662 if (flags
& DCX_CACHE
)
667 dceEmpty
= dceUnused
= NULL
;
669 /* Strategy: First, we attempt to find a non-empty but unused DCE with
670 * compatible flags. Next, we look for an empty entry. If the cache is
671 * full we have to purge one of the unused entries.
674 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
676 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
680 if (dce
->DCXflags
& DCX_DCEEMPTY
)
683 if ((dce
->hwndCurrent
== hwnd
) &&
684 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
685 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
687 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
688 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
689 bUpdateVisRgn
= FALSE
;
690 bUpdateClipOrigin
= TRUE
;
695 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
699 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
700 if( dce
->hwndCurrent
== hwnd
)
702 TRACE(dc
,"\tskipping hVisRgn update\n");
703 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
705 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
706 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
708 /* This is likely to be a nested BeginPaint(). */
710 if( dce
->hClipRgn
!= hrgnClip
)
712 fprintf(stdnimp
,"GetDCEx: new hrgnClip [%04x] smashes the previous [%04x]!\n",
713 hrgnClip
, dce
->hClipRgn
);
714 DCE_DeleteClipRgn( dce
);
717 RestoreVisRgn(dce
->hDC
);
723 dce
->hwndCurrent
= hwnd
;
725 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
728 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
729 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
731 /* recompute visible region */
733 DCE_SetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
736 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
738 if (flags
& DCX_PARENTCLIP
)
740 WND
*parentPtr
= wndPtr
->parent
;
742 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
744 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
745 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
747 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
749 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
750 if( flags
& DCX_WINDOW
)
751 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
752 -wndPtr
->rectWindow
.top
);
754 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
755 -wndPtr
->rectClient
.top
);
758 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
761 if ((hwnd
== GetDesktopWindow32()) &&
762 (rootWindow
== DefaultRootWindow(display
)))
763 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
764 SYSMETRICS_CYSCREEN
);
765 else hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
767 dc
->w
.flags
&= ~DC_DIRTY
;
768 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
769 SelectVisRgn( hdc
, hrgnVisible
);
772 TRACE(dc
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
774 /* apply additional region operation (if any) */
776 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
778 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
780 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
781 dce
->hClipRgn
= hrgnClip
;
783 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
786 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnClip
,
787 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
788 SelectVisRgn( hdc
, hrgnVisible
);
791 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
793 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
794 hwnd
, hrgnClip
, flags
, hdc
);
799 /***********************************************************************
802 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
804 return (HDC16
)GetDC32( hwnd
);
808 /***********************************************************************
809 * GetDC32 (USER32.229)
814 HDC32 WINAPI
GetDC32(
815 HWND32 hwnd
/* handle of window */
818 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
819 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
823 /***********************************************************************
824 * GetWindowDC16 (USER.67)
826 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
828 if (!hwnd
) hwnd
= GetDesktopWindow16();
829 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
833 /***********************************************************************
834 * GetWindowDC32 (USER32.)
836 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
838 if (!hwnd
) hwnd
= GetDesktopWindow32();
839 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
843 /***********************************************************************
844 * ReleaseDC16 (USER.68)
846 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
848 return (INT16
)ReleaseDC32( hwnd
, hdc
);
852 /***********************************************************************
853 * ReleaseDC32 (USER32.439)
859 INT32 WINAPI
ReleaseDC32(
860 HWND32 hwnd
/* Handle of window - ignored */,
861 HDC32 hdc
/* Handle of device context */
863 DCE
* dce
= firstDCE
;
865 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
867 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
870 if ( dce
->DCXflags
& DCX_DCEBUSY
)
871 return DCE_ReleaseDC( dce
);
875 /***********************************************************************
878 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
880 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
883 DCE
*dce
= firstDCE
;;
885 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
887 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
892 case DCHC_INVALIDVISRGN
:
894 /* GDI code calls this when it detects that the
895 * DC is dirty (usually after SetHookFlags()). This
896 * means that we have to recompute the visible region.
899 if( dce
->DCXflags
& DCX_DCEBUSY
)
901 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
902 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
904 TRACE(dc
,"\tapplying saved clipRgn\n");
906 /* clip this region with saved clipping region */
908 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
909 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
912 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
913 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
914 SetRectRgn32(hVisRgn
,0,0,0,0);
916 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
917 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
919 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
920 SelectVisRgn(hDC
, hVisRgn
);
921 DeleteObject32( hVisRgn
);
923 else /* non-fatal but shouldn't happen */
924 WARN(dc
, "DC is not in use!\n");
927 case DCHC_DELETEDC
: /* FIXME: ?? */
931 fprintf(stdnimp
,"DCHook: unknown code\n");
937 /**********************************************************************
938 * WindowFromDC16 (USER32.580)
940 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
942 return (HWND16
)WindowFromDC32( hDC
);
946 /**********************************************************************
947 * WindowFromDC32 (USER32.580)
949 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
952 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
953 return dce
? dce
->hwndCurrent
: 0;
957 /***********************************************************************
958 * LockWindowUpdate16 (USER.294)
960 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
962 return LockWindowUpdate32( hwnd
);
966 /***********************************************************************
967 * LockWindowUpdate32 (USER32.377)
969 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
971 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */