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
->parent
)
337 wndPtr
= wndPtr
->parent
;
339 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
342 xoffset
+= wndPtr
->rectClient
.left
;
343 yoffset
+= wndPtr
->rectClient
.top
;
344 OffsetRect32( lprect
, wndPtr
->rectClient
.left
,
345 wndPtr
->rectClient
.top
);
347 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
348 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
349 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
350 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
351 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
352 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
355 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
356 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
357 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
358 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
360 OffsetRect32( lprect
, -xoffset
, -yoffset
);
365 SetRectEmpty32( lprect
);
370 /***********************************************************************
373 * Go through the linked list of windows from pWndStart to pWndEnd,
374 * adding to the clip region the intersection of the target rectangle
375 * with an offset window rectangle.
377 static BOOL32
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
378 HRGN32 hrgnClip
, LPRECT32 lpRect
, int x
, int y
)
382 if (pWndStart
->window
) return TRUE
; /* X itself will do the clipping */
384 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
386 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
388 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
389 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
390 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
391 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
393 if( IntersectRect32( &rect
, &rect
, lpRect
))
394 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
397 return (pWndStart
== pWndEnd
);
401 /***********************************************************************
404 * Return the visible region of a window, i.e. the client or window area
405 * clipped by the client area of all ancestors, and then optionally
406 * by siblings and children.
408 HRGN32
DCE_GetVisRgn( HWND32 hwnd
, WORD flags
)
412 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
414 /* Get visible rectangle and create a region with it. */
416 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
418 if((hrgnVis
= CreateRectRgnIndirect32( &rect
)))
420 HRGN32 hrgnClip
= CreateRectRgn32( 0, 0, 0, 0 );
421 INT32 xoffset
, yoffset
;
425 /* Compute obscured region for the visible rectangle by
426 * clipping children, siblings, and ancestors. Note that
427 * DCE_GetVisRect() returns a rectangle either in client
428 * or in window coordinates (for DCX_WINDOW request). */
430 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
432 if( flags
& DCX_WINDOW
)
434 /* adjust offsets since child window rectangles are
435 * in client coordinates */
437 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
438 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
441 xoffset
= yoffset
= 0;
443 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
444 &rect
, xoffset
, yoffset
);
447 /* sibling window rectangles are in client
448 * coordinates of the parent window */
450 if (flags
& DCX_WINDOW
)
452 xoffset
= -wndPtr
->rectWindow
.left
;
453 yoffset
= -wndPtr
->rectWindow
.top
;
457 xoffset
= -wndPtr
->rectClient
.left
;
458 yoffset
= -wndPtr
->rectClient
.top
;
461 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
462 DCE_AddClipRects( wndPtr
->parent
->child
,
463 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
465 /* Clip siblings of all ancestors that have the
466 * WS_CLIPSIBLINGS style
469 while (wndPtr
->dwStyle
& WS_CHILD
)
471 wndPtr
= wndPtr
->parent
;
472 xoffset
-= wndPtr
->rectClient
.left
;
473 yoffset
-= wndPtr
->rectClient
.top
;
474 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
476 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
477 hrgnClip
, &rect
, xoffset
, yoffset
);
481 /* Now once we've got a jumbo clip region we have
482 * to substract it from the visible rectangle.
485 CombineRgn32( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
486 DeleteObject32( hrgnClip
);
490 DeleteObject32( hrgnVis
);
496 hrgnVis
= CreateRectRgn32(0, 0, 0, 0); /* empty */
500 /***********************************************************************
503 * Change region from DC-origin relative coordinates to screen coords.
506 static void DCE_OffsetVisRgn( HDC32 hDC
, HRGN32 hVisRgn
)
509 if (!(dc
= (DC
*) GDI_GetObjPtr( hDC
, DC_MAGIC
))) return;
511 OffsetRgn32( hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
513 GDI_HEAP_UNLOCK( hDC
);
517 /***********************************************************************
520 * Set the drawable, origin and dimensions for the DC associated to
523 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
, BOOL32 bSetClipOrigin
)
525 if (!wndPtr
) /* Get a DC for the whole screen */
529 dc
->u
.x
.drawable
= rootWindow
;
530 TSXSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
534 if (flags
& DCX_WINDOW
)
536 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
537 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
541 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
542 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
544 while (!wndPtr
->window
)
546 wndPtr
= wndPtr
->parent
;
547 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
548 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
550 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
551 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
552 dc
->u
.x
.drawable
= wndPtr
->window
;
555 /* This is needed when we reuse a cached DC because
556 * SetDCState() called by ReleaseDC() screws up DC
557 * origins for child windows.
561 TSXSetClipOrigin( display
, dc
->u
.x
.gc
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
565 /***********************************************************************
568 * Translate given region from the wnd client to the DC coordinates
569 * and add it to the clipping region.
571 INT16
DCE_ExcludeRgn( HDC32 hDC
, WND
* wnd
, HRGN32 hRgn
)
576 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
579 MapWindowPoints32( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
580 if( dce
->DCXflags
& DCX_WINDOW
)
582 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
583 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
584 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
588 OffsetRgn32(hRgn
, pt
.x
, pt
.y
);
590 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
593 /***********************************************************************
594 * GetDCEx16 (USER.359)
596 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
598 return (HDC16
)GetDCEx32( hwnd
, hrgnClip
, flags
);
602 /***********************************************************************
603 * GetDCEx32 (USER32.231)
605 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
607 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
609 HDC32 WINAPI
GetDCEx32( HWND32 hwnd
, HRGN32 hrgnClip
, DWORD flags
)
611 HRGN32 hrgnVisible
= 0;
617 BOOL32 bUpdateVisRgn
= TRUE
;
618 BOOL32 bUpdateClipOrigin
= FALSE
;
620 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
621 hwnd
, hrgnClip
, (unsigned)flags
);
623 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
627 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
629 if (flags
& DCX_USESTYLE
)
631 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
633 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
634 flags
|= DCX_CLIPSIBLINGS
;
636 if ( !(flags
& DCX_WINDOW
) )
638 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
640 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
641 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
643 else flags
|= DCX_CACHE
;
646 if( flags
& DCX_NOCLIPCHILDREN
)
649 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
652 if (flags
& DCX_WINDOW
)
653 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
655 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
656 flags
&= ~DCX_PARENTCLIP
;
657 else if( flags
& DCX_PARENTCLIP
)
660 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
661 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
663 flags
&= ~DCX_CLIPCHILDREN
;
664 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
665 flags
|= DCX_CLIPSIBLINGS
;
669 /* find a suitable DCE */
671 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
672 DCX_CACHE
| DCX_WINDOW
);
674 if (flags
& DCX_CACHE
)
679 dceEmpty
= dceUnused
= NULL
;
681 /* Strategy: First, we attempt to find a non-empty but unused DCE with
682 * compatible flags. Next, we look for an empty entry. If the cache is
683 * full we have to purge one of the unused entries.
686 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
688 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
692 if (dce
->DCXflags
& DCX_DCEEMPTY
)
695 if ((dce
->hwndCurrent
== hwnd
) &&
696 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
697 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
699 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
700 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
701 bUpdateVisRgn
= FALSE
;
702 bUpdateClipOrigin
= TRUE
;
707 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
711 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
712 if( dce
->hwndCurrent
== hwnd
)
714 TRACE(dc
,"\tskipping hVisRgn update\n");
715 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
717 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
718 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
720 /* This is likely to be a nested BeginPaint(). */
722 if( dce
->hClipRgn
!= hrgnClip
)
724 FIXME(dc
,"new hrgnClip[%04x] smashes the previous[%04x]\n",
725 hrgnClip
, dce
->hClipRgn
);
726 DCE_DeleteClipRgn( dce
);
729 RestoreVisRgn(dce
->hDC
);
735 dce
->hwndCurrent
= hwnd
;
737 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
740 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
741 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
743 /* recompute visible region */
745 DCE_SetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
748 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
750 if (flags
& DCX_PARENTCLIP
)
752 WND
*parentPtr
= wndPtr
->parent
;
754 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
756 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
757 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
759 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
761 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
);
762 if( flags
& DCX_WINDOW
)
763 OffsetRgn32( hrgnVisible
, -wndPtr
->rectWindow
.left
,
764 -wndPtr
->rectWindow
.top
);
766 OffsetRgn32( hrgnVisible
, -wndPtr
->rectClient
.left
,
767 -wndPtr
->rectClient
.top
);
768 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
771 hrgnVisible
= CreateRectRgn32( 0, 0, 0, 0 );
774 if ((hwnd
== GetDesktopWindow32()) &&
775 (rootWindow
== DefaultRootWindow(display
)))
776 hrgnVisible
= CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN
,
777 SYSMETRICS_CYSCREEN
);
780 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
781 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
784 dc
->w
.flags
&= ~DC_DIRTY
;
785 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
786 SelectVisRgn( hdc
, hrgnVisible
);
789 TRACE(dc
,"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 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
803 CombineRgn32( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
804 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
805 CombineRgn32( hrgnVisible
, InquireVisRgn( hdc
), hrgnVisible
,
806 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
807 SelectVisRgn( hdc
, hrgnVisible
);
810 if( hrgnVisible
) DeleteObject32( hrgnVisible
);
812 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
813 hwnd
, hrgnClip
, flags
, hdc
);
818 /***********************************************************************
821 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
823 return (HDC16
)GetDC32( hwnd
);
827 /***********************************************************************
828 * GetDC32 (USER32.230)
833 HDC32 WINAPI
GetDC32(
834 HWND32 hwnd
/* handle of window */
837 return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE
| DCX_WINDOW
);
838 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
);
842 /***********************************************************************
843 * GetWindowDC16 (USER.67)
845 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
847 if (!hwnd
) hwnd
= GetDesktopWindow16();
848 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
852 /***********************************************************************
853 * GetWindowDC32 (USER32.304)
855 HDC32 WINAPI
GetWindowDC32( HWND32 hwnd
)
857 if (!hwnd
) hwnd
= GetDesktopWindow32();
858 return GetDCEx32( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
862 /***********************************************************************
863 * ReleaseDC16 (USER.68)
865 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
867 return (INT16
)ReleaseDC32( hwnd
, hdc
);
871 /***********************************************************************
872 * ReleaseDC32 (USER32.440)
878 INT32 WINAPI
ReleaseDC32(
879 HWND32 hwnd
/* Handle of window - ignored */,
880 HDC32 hdc
/* Handle of device context */
882 DCE
* dce
= firstDCE
;
884 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
886 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
889 if ( dce
->DCXflags
& DCX_DCEBUSY
)
890 return DCE_ReleaseDC( dce
);
894 /***********************************************************************
897 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
899 BOOL16 WINAPI
DCHook( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
902 DCE
*dce
= firstDCE
;;
904 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
906 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
911 case DCHC_INVALIDVISRGN
:
913 /* GDI code calls this when it detects that the
914 * DC is dirty (usually after SetHookFlags()). This
915 * means that we have to recompute the visible region.
918 if( dce
->DCXflags
& DCX_DCEBUSY
)
920 SetHookFlags(hDC
, DCHF_VALIDATEVISRGN
);
921 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
);
923 TRACE(dc
,"\tapplying saved clipRgn\n");
925 /* clip this region with saved clipping region */
927 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
928 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
931 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
932 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
933 SetRectRgn32(hVisRgn
,0,0,0,0);
935 CombineRgn32(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
936 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
938 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
939 DCE_OffsetVisRgn( hDC
, hVisRgn
);
940 SelectVisRgn(hDC
, hVisRgn
);
941 DeleteObject32( hVisRgn
);
943 else /* non-fatal but shouldn't happen */
944 WARN(dc
, "DC is not in use!\n");
947 case DCHC_DELETEDC
: /* FIXME: ?? */
951 FIXME(dc
,"unknown code\n");
957 /**********************************************************************
958 * WindowFromDC16 (USER.117)
960 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
962 return (HWND16
)WindowFromDC32( hDC
);
966 /**********************************************************************
967 * WindowFromDC32 (USER32.581)
969 HWND32 WINAPI
WindowFromDC32( HDC32 hDC
)
972 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
973 return dce
? dce
->hwndCurrent
: 0;
977 /***********************************************************************
978 * LockWindowUpdate16 (USER.294)
980 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
982 return LockWindowUpdate32( hwnd
);
986 /***********************************************************************
987 * LockWindowUpdate32 (USER32.378)
989 BOOL32 WINAPI
LockWindowUpdate32( HWND32 hwnd
)
991 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */