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"
31 #define NB_DCE 5 /* Number of DCEs created at startup */
33 static DCE
*firstDCE
= 0;
34 static HDC32 defaultDCstate
= 0;
36 static void DCE_DeleteClipRgn( DCE
* );
37 static INT32
DCE_ReleaseDC( DCE
* );
40 /***********************************************************************
43 static void DCE_DumpCache(void)
50 DUMP("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
51 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
,
52 (dce
->DCXflags
& DCX_CACHE
) ? "Cache" : "Owned",
53 (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 ERR(dc
,"[%04x] GetDC() without ReleaseDC()!\n",
150 DCE_ReleaseDC( pDCE
);
153 pDCE
->DCXflags
&= DCX_CACHE
;
154 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
155 pDCE
->hwndCurrent
= 0;
163 /***********************************************************************
166 static void DCE_DeleteClipRgn( DCE
* dce
)
168 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
170 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
171 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
173 if( dce
->hClipRgn
> 1 )
174 DeleteObject32( dce
->hClipRgn
);
178 TRACE(dc
,"\trestoring VisRgn\n");
180 RestoreVisRgn(dce
->hDC
);
184 /***********************************************************************
187 static INT32
DCE_ReleaseDC( DCE
* dce
)
189 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
191 /* restore previous visible region */
193 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
194 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
195 DCE_DeleteClipRgn( dce
);
197 if (dce
->DCXflags
& DCX_CACHE
)
199 SetDCState( dce
->hDC
, defaultDCstate
);
200 dce
->DCXflags
&= ~DCX_DCEBUSY
;
201 if (dce
->DCXflags
& DCX_DCEDIRTY
)
203 /* don't keep around invalidated entries
204 * because SetDCState() disables hVisRgn updates
205 * by removing dirty bit. */
207 dce
->hwndCurrent
= 0;
208 dce
->DCXflags
&= DCX_CACHE
;
209 dce
->DCXflags
|= DCX_DCEEMPTY
;
216 /***********************************************************************
219 * It is called from SetWindowPos() - we have to mark as dirty all busy
220 * DCE's for windows that have pWnd->parent as an ansector and whose client
221 * rect intersects with specified update rectangle.
223 BOOL32
DCE_InvalidateDCE(WND
* pWnd
, const RECT32
* pRectUpdate
)
225 WND
* wndScope
= pWnd
->parent
;
232 TRACE(dc
,"scope hwnd = %04x, (%i,%i - %i,%i)\n",
233 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
234 pRectUpdate
->right
,pRectUpdate
->bottom
);
238 /* walk all DCEs and fixup non-empty entries */
240 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
242 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
244 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
246 if( wndCurrent
&& wndCurrent
!= WIN_GetDesktop() )
248 WND
* wnd
= wndCurrent
;
249 INT32 xoffset
= 0, yoffset
= 0;
251 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) ) continue;
253 /* check if DCE window is within the z-order scope */
255 for( wnd
= wndCurrent
; wnd
; wnd
= wnd
->parent
)
257 if( wnd
== wndScope
)
261 wndRect
= wndCurrent
->rectWindow
;
263 OffsetRect32( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
264 yoffset
- wndCurrent
->rectClient
.top
);
266 if (pWnd
== wndCurrent
||
267 IntersectRect32( &wndRect
, &wndRect
, pRectUpdate
))
269 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
271 /* Don't bother with visible regions of unused DCEs */
273 TRACE(dc
,"\tpurged %08x dce [%04x]\n",
274 (unsigned)dce
, wndCurrent
->hwndSelf
);
276 dce
->hwndCurrent
= 0;
277 dce
->DCXflags
&= DCX_CACHE
;
278 dce
->DCXflags
|= DCX_DCEEMPTY
;
282 /* Set dirty bits in the hDC and DCE structs */
284 TRACE(dc
,"\tfixed up %08x dce [%04x]\n",
285 (unsigned)dce
, wndCurrent
->hwndSelf
);
287 dce
->DCXflags
|= DCX_DCEDIRTY
;
288 SetHookFlags(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
294 xoffset
+= wnd
->rectClient
.left
;
295 yoffset
+= wnd
->rectClient
.top
;
304 /***********************************************************************
312 for (i
= 0; i
< NB_DCE
; i
++)
314 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
315 if (!defaultDCstate
) defaultDCstate
= GetDCState( dce
->hDC
);
320 /***********************************************************************
323 * Calculate the visible rectangle of a window (i.e. the client or
324 * window area clipped by the client area of all ancestors) in the
325 * corresponding coordinates. Return FALSE if the visible region is empty.
327 static BOOL32
DCE_GetVisRect( WND
*wndPtr
, BOOL32 clientArea
, RECT32
*lprect
)
329 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
331 if (wndPtr
->dwStyle
& WS_VISIBLE
)
333 INT32 xoffset
= lprect
->left
;
334 INT32 yoffset
= lprect
->top
;
336 while (wndPtr
->parent
)
338 wndPtr
= wndPtr
->parent
;
340 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
343 xoffset
+= wndPtr
->rectClient
.left
;
344 yoffset
+= wndPtr
->rectClient
.top
;
345 OffsetRect32( lprect
, wndPtr
->rectClient
.left
,
346 wndPtr
->rectClient
.top
);
348 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
349 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
350 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
351 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
352 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
353 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
356 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
357 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
358 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
359 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
361 OffsetRect32( lprect
, -xoffset
, -yoffset
);
366 SetRectEmpty32( lprect
);
371 /***********************************************************************
374 * Go through the linked list of windows from pWndStart to pWndEnd,
375 * adding to the clip region the intersection of the target rectangle
376 * with an offset window rectangle.
378 static BOOL32
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
379 HRGN32 hrgnClip
, LPRECT32 lpRect
, int x
, int y
)
383 if (pWndStart
->window
) return TRUE
; /* X 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
);
518 /***********************************************************************
521 * Set the drawable, origin and dimensions for the DC associated to
524 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
, BOOL32 bSetClipOrigin
)
526 X11DRV_PDEVICE
*physDev
= (X11DRV_PDEVICE
*)dc
->physDev
;
528 if (!wndPtr
) /* Get a DC for the whole screen */
532 physDev
->drawable
= rootWindow
;
533 TSXSetSubwindowMode( display
, physDev
->gc
, IncludeInferiors
);
537 if (flags
& DCX_WINDOW
)
539 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
540 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
544 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
545 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
547 while (!wndPtr
->window
)
549 wndPtr
= wndPtr
->parent
;
550 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
551 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
553 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
554 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
555 physDev
->drawable
= wndPtr
->window
;
558 /* This is needed when we reuse a cached DC because
559 * SetDCState() called by ReleaseDC() screws up DC
560 * origins for child windows.
564 TSXSetClipOrigin( display
, physDev
->gc
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
568 /***********************************************************************
571 * Translate given region from the wnd client to the DC coordinates
572 * and add it to the clipping region.
574 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
579 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
582 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
583 if( dce
->DCXflags
& DCX_WINDOW
)
585 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
586 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
587 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
591 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
593 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
596 /***********************************************************************
597 * GetDCEx16 (USER.359)
599 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
601 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
605 /***********************************************************************
606 * GetDCEx32 (USER32.231)
608 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
610 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
612 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
614 HRGN32 hrgnVisible
= 0;
620 BOOL32 bUpdateVisRgn
= TRUE
;
621 BOOL32 bUpdateClipOrigin
= FALSE
;
623 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
624 hwnd
, hrgnClip
, (unsigned)flags
);
626 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
630 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
632 if (flags
& DCX_USESTYLE
)
634 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
636 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
637 flags
|= DCX_CLIPSIBLINGS
;
639 if ( !(flags
& DCX_WINDOW
) )
641 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
643 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
644 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
646 else flags
|= DCX_CACHE
;
649 if( flags
& DCX_NOCLIPCHILDREN
)
652 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
655 if (flags
& DCX_WINDOW
)
656 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
658 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
659 flags
&= ~DCX_PARENTCLIP
;
660 else if( flags
& DCX_PARENTCLIP
)
663 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
664 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
666 flags
&= ~DCX_CLIPCHILDREN
;
667 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
668 flags
|= DCX_CLIPSIBLINGS
;
672 /* find a suitable DCE */
674 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
675 DCX_CACHE
| DCX_WINDOW
);
677 if (flags
& DCX_CACHE
)
682 dceEmpty
= dceUnused
= NULL
;
684 /* Strategy: First, we attempt to find a non-empty but unused DCE with
685 * compatible flags. Next, we look for an empty entry. If the cache is
686 * full we have to purge one of the unused entries.
689 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
691 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
695 if (dce
->DCXflags
& DCX_DCEEMPTY
)
698 if ((dce
->hwndCurrent
== hwnd
) &&
699 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
700 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
702 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
703 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
704 bUpdateVisRgn
= FALSE
;
705 bUpdateClipOrigin
= TRUE
;
710 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
714 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
715 if( dce
->hwndCurrent
== hwnd
)
717 TRACE(dc
,"\tskipping hVisRgn update\n");
718 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
720 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
721 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
723 /* This is likely to be a nested BeginPaint(). */
725 if( dce
->hClipRgn
!= hrgnClip
)
727 FIXME(dc
,"new hrgnClip[%04x] smashes the previous[%04x]\n",
728 hrgnClip
, dce
->hClipRgn
);
729 DCE_DeleteClipRgn( dce
);
732 RestoreVisRgn(dce
->hDC
);
738 dce
->hwndCurrent
= hwnd
;
740 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
743 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
744 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
746 /* recompute visible region */
748 DCE_SetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
751 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
753 if (flags
& DCX_PARENTCLIP
)
755 WND
*parentPtr
= wndPtr
->parent
;
757 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
759 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
760 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
762 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
764 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
765 if( flags
& DCX_WINDOW
)
766 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
767 -wndPtr
->rectWindow
.top
);
769 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
770 -wndPtr
->rectClient
.top
);
771 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
774 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
777 if ((hwnd
== GetDesktopWindow32()) &&
778 (rootWindow
== DefaultRootWindow(display
)))
779 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
780 SYSMETRICS_CYSCREEN
);
783 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
784 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
787 dc
->w
.flags
&= ~DC_DIRTY
;
788 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
789 SelectVisRgn( hdc
, hrgnVisible
);
792 TRACE(dc
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
794 /* apply additional region operation (if any) */
796 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
798 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
800 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
801 dce
->hClipRgn
= hrgnClip
;
803 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
806 CombineRgn32( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
807 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
808 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnVisible
,
809 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
810 SelectVisRgn( hdc
, hrgnVisible
);
813 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
815 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
816 hwnd
, hrgnClip
, flags
, hdc
);
821 /***********************************************************************
824 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
826 return (HDC16
)GetDC32( hwnd
);
830 /***********************************************************************
831 * GetDC32 (USER32.230)
836 HDC32 WINAPI
GetDC32(
837 HWND32 hwnd
/* handle of window */
840 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
841 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
845 /***********************************************************************
846 * GetWindowDC16 (USER.67)
848 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
850 if (!hwnd
) hwnd
= GetDesktopWindow16();
851 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
855 /***********************************************************************
856 * GetWindowDC32 (USER32.304)
858 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
860 if (!hwnd
) hwnd
= GetDesktopWindow32();
861 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
865 /***********************************************************************
866 * ReleaseDC16 (USER.68)
868 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
870 return (INT16
)ReleaseDC32( hwnd
, hdc
);
874 /***********************************************************************
875 * ReleaseDC32 (USER32.440)
881 INT32 WINAPI
ReleaseDC32(
882 HWND32 hwnd
/* Handle of window - ignored */,
883 HDC32 hdc
/* Handle of device context */
885 DCE
* dce
= firstDCE
;
887 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
889 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
892 if ( dce
->DCXflags
& DCX_DCEBUSY
)
893 return DCE_ReleaseDC( dce
);
897 /***********************************************************************
900 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
902 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
905 DCE
*dce
= firstDCE
;;
907 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
909 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
914 case DCHC_INVALIDVISRGN
:
916 /* GDI code calls this when it detects that the
917 * DC is dirty (usually after SetHookFlags()). This
918 * means that we have to recompute the visible region.
921 if( dce
->DCXflags
& DCX_DCEBUSY
)
923 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
924 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
926 TRACE(dc
,"\tapplying saved clipRgn\n");
928 /* clip this region with saved clipping region */
930 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
931 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
934 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
935 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
936 SetRectRgn32(hVisRgn
,0,0,0,0);
938 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
939 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
941 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
942 DCE_OffsetVisRgn( hDC
, hVisRgn
);
943 SelectVisRgn(hDC
, hVisRgn
);
944 DeleteObject32( hVisRgn
);
946 else /* non-fatal but shouldn't happen */
947 WARN(dc
, "DC is not in use!\n");
950 case DCHC_DELETEDC
: /* FIXME: ?? */
954 FIXME(dc
,"unknown code\n");
960 /**********************************************************************
961 * WindowFromDC16 (USER.117)
963 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
965 return (HWND16
)WindowFromDC32( hDC
);
969 /**********************************************************************
970 * WindowFromDC32 (USER32.581)
972 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
975 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
976 return dce
? dce
->hwndCurrent
: 0;
980 /***********************************************************************
981 * LockWindowUpdate16 (USER.294)
983 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
985 return LockWindowUpdate32( hwnd
);
989 /***********************************************************************
990 * LockWindowUpdate32 (USER32.378)
992 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
994 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */