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
29 #include "sysmetrics.h"
32 #include "wine/winuser16.h"
34 #define NB_DCE 5 /* Number of DCEs created at startup */
36 static DCE
*firstDCE
= 0;
37 static HDC defaultDCstate
= 0;
39 static void DCE_DeleteClipRgn( DCE
* );
40 static INT
DCE_ReleaseDC( DCE
* );
43 /***********************************************************************
46 static void DCE_DumpCache(void)
53 DUMP("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
54 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
,
55 (dce
->DCXflags
& DCX_CACHE
) ? "Cache" : "Owned",
56 (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
61 /***********************************************************************
66 DCE
*DCE_AllocDCE( HWND hWnd
, DCE_TYPE type
)
69 if (!(dce
= HeapAlloc( SystemHeap
, 0, sizeof(DCE
) ))) return NULL
;
70 if (!(dce
->hDC
= CreateDC16( "DISPLAY", NULL
, NULL
, NULL
)))
72 HeapFree( SystemHeap
, 0, dce
);
76 /* store DCE handle in DC hook data field */
78 SetDCHook( dce
->hDC
, (FARPROC16
)DCHook16
, (DWORD
)dce
);
80 dce
->hwndCurrent
= hWnd
;
85 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
87 dce
->DCXflags
= DCX_DCEBUSY
;
90 WND
* wnd
= WIN_FindWndPtr(hWnd
);
92 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
93 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
95 WIN_ReleaseWndPtr(wnd
);
97 SetHookFlags16(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
99 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
105 /***********************************************************************
108 DCE
* DCE_FreeDCE( DCE
*dce
)
110 DCE
**ppDCE
= &firstDCE
;
112 if (!dce
) return NULL
;
113 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
114 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
116 SetDCHook(dce
->hDC
, NULL
, 0L);
118 DeleteDC( dce
->hDC
);
119 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
120 DeleteObject(dce
->hClipRgn
);
121 HeapFree( SystemHeap
, 0, dce
);
125 /***********************************************************************
128 * Remove owned DCE and reset unreleased cache DCEs.
130 void DCE_FreeWindowDCE( WND
* pWnd
)
132 DCE
*pDCE
= firstDCE
;
136 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
138 if( pDCE
== pWnd
->dce
) /* owned DCE */
140 pDCE
= DCE_FreeDCE( pDCE
);
146 if(!(pDCE
->DCXflags
& DCX_CACHE
) ) /* class DCE */
148 if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) )
149 DCE_DeleteClipRgn( pDCE
);
151 else if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
153 ERR(dc
,"[%04x] GetDC() without ReleaseDC()!\n",
155 DCE_ReleaseDC( pDCE
);
158 pDCE
->DCXflags
&= DCX_CACHE
;
159 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
160 pDCE
->hwndCurrent
= 0;
168 /***********************************************************************
171 static void DCE_DeleteClipRgn( DCE
* dce
)
173 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
175 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
176 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
178 if( dce
->hClipRgn
> 1 )
179 DeleteObject( dce
->hClipRgn
);
183 TRACE(dc
,"\trestoring VisRgn\n");
185 RestoreVisRgn16(dce
->hDC
);
189 /***********************************************************************
192 static INT
DCE_ReleaseDC( DCE
* dce
)
194 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
196 /* restore previous visible region */
198 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
199 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
200 DCE_DeleteClipRgn( dce
);
202 if (dce
->DCXflags
& DCX_CACHE
)
204 SetDCState16( dce
->hDC
, defaultDCstate
);
205 dce
->DCXflags
&= ~DCX_DCEBUSY
;
206 if (dce
->DCXflags
& DCX_DCEDIRTY
)
208 /* don't keep around invalidated entries
209 * because SetDCState() disables hVisRgn updates
210 * by removing dirty bit. */
212 dce
->hwndCurrent
= 0;
213 dce
->DCXflags
&= DCX_CACHE
;
214 dce
->DCXflags
|= DCX_DCEEMPTY
;
221 /***********************************************************************
224 * It is called from SetWindowPos() - we have to mark as dirty all busy
225 * DCE's for windows that have pWnd->parent as an ansector and whose client
226 * rect intersects with specified update rectangle.
228 BOOL
DCE_InvalidateDCE(WND
* pWnd
, const RECT
* pRectUpdate
)
230 WND
* wndScope
= pWnd
->parent
;
237 TRACE(dc
,"scope hwnd = %04x, (%i,%i - %i,%i)\n",
238 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
239 pRectUpdate
->right
,pRectUpdate
->bottom
);
243 /* walk all DCEs and fixup non-empty entries */
245 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
247 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
249 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
251 if( wndCurrent
&& wndCurrent
!= WIN_GetDesktop() )
254 INT xoffset
= 0, yoffset
= 0;
256 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) )
258 WIN_ReleaseWndPtr(wndCurrent
);
262 /* check if DCE window is within the z-order scope */
264 for( wnd
= WIN_LockWndPtr(wndCurrent
); wnd
; WIN_UpdateWndPtr(&wnd
,wnd
->parent
))
266 if( wnd
== wndScope
)
270 wndRect
= wndCurrent
->rectWindow
;
272 OffsetRect( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
273 yoffset
- wndCurrent
->rectClient
.top
);
275 if (pWnd
== wndCurrent
||
276 IntersectRect( &wndRect
, &wndRect
, pRectUpdate
))
278 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
280 /* Don't bother with visible regions of unused DCEs */
282 TRACE(dc
,"\tpurged %08x dce [%04x]\n",
283 (unsigned)dce
, wndCurrent
->hwndSelf
);
285 dce
->hwndCurrent
= 0;
286 dce
->DCXflags
&= DCX_CACHE
;
287 dce
->DCXflags
|= DCX_DCEEMPTY
;
291 /* Set dirty bits in the hDC and DCE structs */
293 TRACE(dc
,"\tfixed up %08x dce [%04x]\n",
294 (unsigned)dce
, wndCurrent
->hwndSelf
);
296 dce
->DCXflags
|= DCX_DCEDIRTY
;
297 SetHookFlags16(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
303 xoffset
+= wnd
->rectClient
.left
;
304 yoffset
+= wnd
->rectClient
.top
;
307 WIN_ReleaseWndPtr(wndCurrent
);
308 WIN_ReleaseDesktop();
315 /***********************************************************************
323 for (i
= 0; i
< NB_DCE
; i
++)
325 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
326 if (!defaultDCstate
) defaultDCstate
= GetDCState16( dce
->hDC
);
331 /***********************************************************************
334 * Calculate the visible rectangle of a window (i.e. the client or
335 * window area clipped by the client area of all ancestors) in the
336 * corresponding coordinates. Return FALSE if the visible region is empty.
338 static BOOL
DCE_GetVisRect( WND
*wndPtr
, BOOL clientArea
, RECT
*lprect
)
340 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
342 if (wndPtr
->dwStyle
& WS_VISIBLE
)
344 INT xoffset
= lprect
->left
;
345 INT yoffset
= lprect
->top
;
347 while (wndPtr
->dwStyle
& WS_CHILD
)
349 wndPtr
= WIN_LockWndPtr(wndPtr
->parent
);
351 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
353 WIN_ReleaseWndPtr(wndPtr
);
357 xoffset
+= wndPtr
->rectClient
.left
;
358 yoffset
+= wndPtr
->rectClient
.top
;
359 OffsetRect( lprect
, wndPtr
->rectClient
.left
,
360 wndPtr
->rectClient
.top
);
362 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
363 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
364 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
365 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
366 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
367 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
369 WIN_ReleaseWndPtr(wndPtr
);
373 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
374 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
375 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
376 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
378 WIN_ReleaseWndPtr(wndPtr
);
380 OffsetRect( lprect
, -xoffset
, -yoffset
);
385 SetRectEmpty( lprect
);
390 /***********************************************************************
393 * Go through the linked list of windows from pWndStart to pWndEnd,
394 * adding to the clip region the intersection of the target rectangle
395 * with an offset window rectangle.
397 static BOOL
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
398 HRGN hrgnClip
, LPRECT lpRect
, int x
, int y
)
402 if( pWndStart
->pDriver
->pIsSelfClipping( pWndStart
) )
403 return TRUE
; /* The driver itself will do the clipping */
405 for (; pWndStart
!= pWndEnd
; pWndStart
= WIN_LockWndPtr(pWndStart
->next
))
407 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) )
409 WIN_ReleaseWndPtr(pWndStart
);
413 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
414 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
415 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
416 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
418 if( IntersectRect( &rect
, &rect
, lpRect
))
419 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
))
421 WIN_ReleaseWndPtr(pWndStart
);
424 WIN_ReleaseWndPtr(pWndStart
);
426 return (pWndStart
== pWndEnd
);
430 /***********************************************************************
433 * Return the visible region of a window, i.e. the client or window area
434 * clipped by the client area of all ancestors, and then optionally
435 * by siblings and children.
437 HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
, HWND hwndChild
, WORD cflags
)
441 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
442 WND
*childWnd
= WIN_FindWndPtr( hwndChild
);
444 /* Get visible rectangle and create a region with it. */
446 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
448 if((hrgnVis
= CreateRectRgnIndirect( &rect
)))
450 HRGN hrgnClip
= CreateRectRgn( 0, 0, 0, 0 );
451 INT xoffset
, yoffset
;
455 /* Compute obscured region for the visible rectangle by
456 * clipping children, siblings, and ancestors. Note that
457 * DCE_GetVisRect() returns a rectangle either in client
458 * or in window coordinates (for DCX_WINDOW request). */
460 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
462 if( flags
& DCX_WINDOW
)
464 /* adjust offsets since child window rectangles are
465 * in client coordinates */
467 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
468 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
471 xoffset
= yoffset
= 0;
473 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
474 &rect
, xoffset
, yoffset
);
477 /* We may need to clip children of child window, if a window with PARENTDC
478 * class style and CLIPCHILDREN window style (like in Free Agent 16
479 * preference dialogs) gets here, we take the region for the parent window
480 * but apparently still need to clip the children of the child window... */
482 if( (cflags
& DCX_CLIPCHILDREN
) && childWnd
&& childWnd
->child
)
484 if( flags
& DCX_WINDOW
)
486 /* adjust offsets since child window rectangles are
487 * in client coordinates */
489 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
490 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
493 xoffset
= yoffset
= 0;
495 /* client coordinates of child window */
496 xoffset
+= childWnd
->rectClient
.left
;
497 yoffset
+= childWnd
->rectClient
.top
;
499 DCE_AddClipRects( childWnd
->child
, NULL
, hrgnClip
,
500 &rect
, xoffset
, yoffset
);
503 /* sibling window rectangles are in client
504 * coordinates of the parent window */
506 if (flags
& DCX_WINDOW
)
508 xoffset
= -wndPtr
->rectWindow
.left
;
509 yoffset
= -wndPtr
->rectWindow
.top
;
513 xoffset
= -wndPtr
->rectClient
.left
;
514 yoffset
= -wndPtr
->rectClient
.top
;
517 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
518 DCE_AddClipRects( wndPtr
->parent
->child
,
519 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
521 /* Clip siblings of all ancestors that have the
522 * WS_CLIPSIBLINGS style
525 while (wndPtr
->dwStyle
& WS_CHILD
)
527 WIN_UpdateWndPtr(&wndPtr
,wndPtr
->parent
);
528 xoffset
-= wndPtr
->rectClient
.left
;
529 yoffset
-= wndPtr
->rectClient
.top
;
530 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
532 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
533 hrgnClip
, &rect
, xoffset
, yoffset
);
537 /* Now once we've got a jumbo clip region we have
538 * to substract it from the visible rectangle.
541 CombineRgn( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
542 DeleteObject( hrgnClip
);
546 DeleteObject( hrgnVis
);
552 hrgnVis
= CreateRectRgn(0, 0, 0, 0); /* empty */
553 WIN_ReleaseWndPtr(wndPtr
);
554 WIN_ReleaseWndPtr(childWnd
);
558 /***********************************************************************
561 * Change region from DC-origin relative coordinates to screen coords.
564 static void DCE_OffsetVisRgn( HDC hDC
, HRGN hVisRgn
)
567 if (!(dc
= (DC
*) GDI_GetObjPtr( hDC
, DC_MAGIC
))) return;
569 OffsetRgn( hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
571 GDI_HEAP_UNLOCK( hDC
);
574 /***********************************************************************
577 * Translate given region from the wnd client to the DC coordinates
578 * and add it to the clipping region.
580 INT16
DCE_ExcludeRgn( HDC hDC
, WND
* wnd
, HRGN hRgn
)
585 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
588 MapWindowPoints( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
589 if( dce
->DCXflags
& DCX_WINDOW
)
591 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
592 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
593 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
594 WIN_ReleaseWndPtr(wnd
);
598 OffsetRgn(hRgn
, pt
.x
, pt
.y
);
600 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
603 /***********************************************************************
604 * GetDCEx16 (USER.359)
606 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
608 return (HDC16
)GetDCEx( hwnd
, hrgnClip
, flags
);
612 /***********************************************************************
613 * GetDCEx32 (USER32.231)
615 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
617 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
619 HDC WINAPI
GetDCEx( HWND hwnd
, HRGN hrgnClip
, DWORD flags
)
621 HRGN hrgnVisible
= 0;
627 BOOL bUpdateVisRgn
= TRUE
;
628 BOOL bUpdateClipOrigin
= FALSE
;
630 TRACE(dc
,"hwnd %04x, hrgnClip %04x, flags %08x\n",
631 hwnd
, hrgnClip
, (unsigned)flags
);
633 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
637 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
639 if (flags
& DCX_USESTYLE
)
641 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
643 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
644 flags
|= DCX_CLIPSIBLINGS
;
646 if ( !(flags
& DCX_WINDOW
) )
648 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
650 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
651 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
653 else flags
|= DCX_CACHE
;
656 if( flags
& DCX_NOCLIPCHILDREN
)
659 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
662 if (flags
& DCX_WINDOW
)
663 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
665 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
666 flags
&= ~DCX_PARENTCLIP
;
667 else if( flags
& DCX_PARENTCLIP
)
670 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
671 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
673 flags
&= ~DCX_CLIPCHILDREN
;
674 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
675 flags
|= DCX_CLIPSIBLINGS
;
679 /* find a suitable DCE */
681 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
682 DCX_CACHE
| DCX_WINDOW
);
684 if (flags
& DCX_CACHE
)
689 dceEmpty
= dceUnused
= NULL
;
691 /* Strategy: First, we attempt to find a non-empty but unused DCE with
692 * compatible flags. Next, we look for an empty entry. If the cache is
693 * full we have to purge one of the unused entries.
696 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
698 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
702 if (dce
->DCXflags
& DCX_DCEEMPTY
)
705 if ((dce
->hwndCurrent
== hwnd
) &&
706 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
707 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
709 TRACE(dc
,"\tfound valid %08x dce [%04x], flags %08x\n",
710 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
711 bUpdateVisRgn
= FALSE
;
712 bUpdateClipOrigin
= TRUE
;
717 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
719 /* if there's no dce empty or unused, allocate a new one */
722 dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
);
727 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
728 if( dce
->hwndCurrent
== hwnd
)
730 TRACE(dc
,"\tskipping hVisRgn update\n");
731 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
733 if( (dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) &&
734 (flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
)) )
736 /* This is likely to be a nested BeginPaint(). */
738 if( dce
->hClipRgn
!= hrgnClip
)
740 FIXME(dc
,"new hrgnClip[%04x] smashes the previous[%04x]\n",
741 hrgnClip
, dce
->hClipRgn
);
742 DCE_DeleteClipRgn( dce
);
745 RestoreVisRgn16(dce
->hDC
);
755 dce
->hwndCurrent
= hwnd
;
757 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
760 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
)))
765 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
767 /* recompute visible region */
769 wndPtr
->pDriver
->pSetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
772 TRACE(dc
,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
774 if (flags
& DCX_PARENTCLIP
)
776 WND
*parentPtr
= WIN_LockWndPtr(wndPtr
->parent
);
778 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
780 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
781 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
783 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
785 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
,
786 wndPtr
->hwndSelf
, flags
);
787 if( flags
& DCX_WINDOW
)
788 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
789 -wndPtr
->rectWindow
.top
);
791 OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
792 -wndPtr
->rectClient
.top
);
793 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
796 hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
797 WIN_ReleaseWndPtr(parentPtr
);
800 if ((hwnd
== GetDesktopWindow()) &&
801 (X11DRV_WND_GetXRootWindow(wndPtr
) == DefaultRootWindow(display
)))
802 hrgnVisible
= CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN
,
803 SYSMETRICS_CYSCREEN
);
806 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
, 0, 0 );
807 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
810 dc
->w
.flags
&= ~DC_DIRTY
;
811 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
812 SelectVisRgn16( hdc
, hrgnVisible
);
815 TRACE(dc
,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
817 /* apply additional region operation (if any) */
819 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
821 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
823 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
824 dce
->hClipRgn
= hrgnClip
;
826 TRACE(dc
, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
829 CombineRgn( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
830 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
831 CombineRgn( hrgnVisible
, InquireVisRgn16( hdc
), hrgnVisible
,
832 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
833 SelectVisRgn16( hdc
, hrgnVisible
);
836 if( hrgnVisible
) DeleteObject( hrgnVisible
);
838 TRACE(dc
, "(%04x,%04x,0x%lx): returning %04x\n",
839 hwnd
, hrgnClip
, flags
, hdc
);
841 WIN_ReleaseWndPtr(wndPtr
);
846 /***********************************************************************
849 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
851 return (HDC16
)GetDC( hwnd
);
855 /***********************************************************************
856 * GetDC32 (USER32.230)
862 HWND hwnd
/* handle of window */
865 return GetDCEx( GetDesktopWindow(), 0, DCX_CACHE
| DCX_WINDOW
);
866 return GetDCEx( hwnd
, 0, DCX_USESTYLE
);
870 /***********************************************************************
871 * GetWindowDC16 (USER.67)
873 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
875 if (!hwnd
) hwnd
= GetDesktopWindow16();
876 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
880 /***********************************************************************
881 * GetWindowDC32 (USER32.304)
883 HDC WINAPI
GetWindowDC( HWND hwnd
)
885 if (!hwnd
) hwnd
= GetDesktopWindow();
886 return GetDCEx( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
890 /***********************************************************************
891 * ReleaseDC16 (USER.68)
893 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
895 return (INT16
)ReleaseDC( hwnd
, hdc
);
899 /***********************************************************************
900 * ReleaseDC32 (USER32.440)
906 INT WINAPI
ReleaseDC(
907 HWND hwnd
/* Handle of window - ignored */,
908 HDC hdc
/* Handle of device context */
910 DCE
* dce
= firstDCE
;
912 TRACE(dc
, "%04x %04x\n", hwnd
, hdc
);
914 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
917 if ( dce
->DCXflags
& DCX_DCEBUSY
)
918 return DCE_ReleaseDC( dce
);
922 /***********************************************************************
925 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
927 BOOL16 WINAPI
DCHook16( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
930 DCE
*dce
= firstDCE
;;
932 TRACE(dc
,"hDC = %04x, %i\n", hDC
, code
);
934 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
939 case DCHC_INVALIDVISRGN
:
941 /* GDI code calls this when it detects that the
942 * DC is dirty (usually after SetHookFlags()). This
943 * means that we have to recompute the visible region.
946 if( dce
->DCXflags
& DCX_DCEBUSY
)
948 SetHookFlags16(hDC
, DCHF_VALIDATEVISRGN
);
949 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
, 0, 0);
951 TRACE(dc
,"\tapplying saved clipRgn\n");
953 /* clip this region with saved clipping region */
955 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
956 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
959 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
960 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
961 SetRectRgn(hVisRgn
,0,0,0,0);
963 CombineRgn(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
964 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
966 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
967 DCE_OffsetVisRgn( hDC
, hVisRgn
);
968 SelectVisRgn16(hDC
, hVisRgn
);
969 DeleteObject( hVisRgn
);
971 else /* non-fatal but shouldn't happen */
972 WARN(dc
, "DC is not in use!\n");
975 case DCHC_DELETEDC
: /* FIXME: ?? */
979 FIXME(dc
,"unknown code\n");
985 /**********************************************************************
986 * WindowFromDC16 (USER.117)
988 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
990 return (HWND16
)WindowFromDC( hDC
);
994 /**********************************************************************
995 * WindowFromDC32 (USER32.581)
997 HWND WINAPI
WindowFromDC( HDC hDC
)
1000 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
1001 return dce
? dce
->hwndCurrent
: 0;
1005 /***********************************************************************
1006 * LockWindowUpdate16 (USER.294)
1008 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
1010 return LockWindowUpdate( hwnd
);
1014 /***********************************************************************
1015 * LockWindowUpdate32 (USER32.378)
1017 BOOL WINAPI
LockWindowUpdate( HWND hwnd
)
1019 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */