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
26 #include "debugtools.h"
29 #include "wine/winbase16.h"
30 #include "wine/winuser16.h"
32 DEFAULT_DEBUG_CHANNEL(dc
);
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)
56 DPRINTF("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
57 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
,
58 (dce
->DCXflags
& DCX_CACHE
) ? "Cache" : "Owned",
59 (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
66 /***********************************************************************
71 DCE
*DCE_AllocDCE( HWND hWnd
, DCE_TYPE type
)
77 if (!(dce
= HeapAlloc( GetProcessHeap(), 0, sizeof(DCE
) ))) return NULL
;
78 if (!(dce
->hDC
= CreateDCA( "DISPLAY", NULL
, NULL
, NULL
)))
80 HeapFree( GetProcessHeap(), 0, dce
);
84 wnd
= WIN_FindWndPtr(hWnd
);
86 /* store DCE handle in DC hook data field */
88 hookProc
= GetProcAddress16( GetModuleHandle16("USER"), (LPCSTR
)362 );
89 SetDCHook( dce
->hDC
, hookProc
, (DWORD
)dce
);
91 dce
->hwndCurrent
= hWnd
;
96 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
98 dce
->DCXflags
= DCX_DCEBUSY
;
101 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
102 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
104 SetHookFlags16(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
106 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
108 WIN_ReleaseWndPtr(wnd
);
114 /***********************************************************************
117 DCE
* DCE_FreeDCE( DCE
*dce
)
121 if (!dce
) return NULL
;
127 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
128 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
130 SetDCHook(dce
->hDC
, NULL
, 0L);
132 DeleteDC( dce
->hDC
);
133 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
134 DeleteObject(dce
->hClipRgn
);
135 HeapFree( GetProcessHeap(), 0, dce
);
142 /***********************************************************************
145 * Remove owned DCE and reset unreleased cache DCEs.
147 void DCE_FreeWindowDCE( WND
* pWnd
)
156 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
158 if( pDCE
== pWnd
->dce
) /* owned or Class DCE*/
160 if (pWnd
->clsStyle
& CS_OWNDC
) /* owned DCE*/
162 pDCE
= DCE_FreeDCE( pDCE
);
166 else if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) ) /* Class DCE*/
168 DCE_DeleteClipRgn( pDCE
);
169 pDCE
->hwndCurrent
= 0;
174 if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
176 /* FIXME: AFAICS we are doing the right thing here so
177 * this should be a WARN. But this is best left as an ERR
178 * because the 'application error' is likely to come from
179 * another part of Wine (i.e. it's our fault after all).
180 * We should change this to WARN when Wine is more stable
183 ERR("[%04x] GetDC() without ReleaseDC()!\n",
185 DCE_ReleaseDC( pDCE
);
188 pDCE
->DCXflags
&= DCX_CACHE
;
189 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
190 pDCE
->hwndCurrent
= 0;
200 /***********************************************************************
203 static void DCE_DeleteClipRgn( DCE
* dce
)
205 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
207 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
208 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
210 if( dce
->hClipRgn
> 1 )
211 DeleteObject( dce
->hClipRgn
);
215 TRACE("\trestoring VisRgn\n");
217 RestoreVisRgn16(dce
->hDC
);
221 /***********************************************************************
224 static INT
DCE_ReleaseDC( DCE
* dce
)
226 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
228 /* restore previous visible region */
230 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
231 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
232 DCE_DeleteClipRgn( dce
);
234 if (dce
->DCXflags
& DCX_CACHE
)
236 SetDCState16( dce
->hDC
, defaultDCstate
);
237 dce
->DCXflags
&= ~DCX_DCEBUSY
;
238 if (dce
->DCXflags
& DCX_DCEDIRTY
)
240 /* don't keep around invalidated entries
241 * because SetDCState() disables hVisRgn updates
242 * by removing dirty bit. */
244 dce
->hwndCurrent
= 0;
245 dce
->DCXflags
&= DCX_CACHE
;
246 dce
->DCXflags
|= DCX_DCEEMPTY
;
253 /***********************************************************************
256 * It is called from SetWindowPos() and EVENT_MapNotify - we have to
257 * mark as dirty all busy DCEs for windows that have pWnd->parent as
258 * an ancestor and whose client rect intersects with specified update
259 * rectangle. In addition, pWnd->parent DCEs may need to be updated if
260 * DCX_CLIPCHILDREN flag is set. */
261 BOOL
DCE_InvalidateDCE(WND
* pWnd
, const RECT
* pRectUpdate
)
263 WND
* wndScope
= WIN_LockWndPtr(pWnd
->parent
);
264 WND
*pDesktop
= WIN_GetDesktop();
271 TRACE("scope hwnd = %04x, (%i,%i - %i,%i)\n",
272 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
273 pRectUpdate
->right
,pRectUpdate
->bottom
);
277 /* walk all DCEs and fixup non-empty entries */
279 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
281 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
283 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
288 INT xoffset
= 0, yoffset
= 0;
290 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) )
292 /* child window positions don't bother us */
293 WIN_ReleaseWndPtr(wndCurrent
);
297 if (wndCurrent
== pDesktop
&& !(wndCurrent
->flags
& WIN_NATIVE
))
299 /* don't bother with fake desktop */
300 WIN_ReleaseWndPtr(wndCurrent
);
304 /* check if DCE window is within the z-order scope */
306 for( wnd
= WIN_LockWndPtr(wndCurrent
); wnd
; WIN_UpdateWndPtr(&wnd
,wnd
->parent
))
308 if( wnd
== wndScope
)
312 wndRect
= wndCurrent
->rectWindow
;
314 OffsetRect( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
315 yoffset
- wndCurrent
->rectClient
.top
);
317 if (pWnd
== wndCurrent
||
318 IntersectRect( &wndRect
, &wndRect
, pRectUpdate
))
320 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
322 /* Don't bother with visible regions of unused DCEs */
324 TRACE("\tpurged %08x dce [%04x]\n",
325 (unsigned)dce
, wndCurrent
->hwndSelf
);
327 dce
->hwndCurrent
= 0;
328 dce
->DCXflags
&= DCX_CACHE
;
329 dce
->DCXflags
|= DCX_DCEEMPTY
;
333 /* Set dirty bits in the hDC and DCE structs */
335 TRACE("\tfixed up %08x dce [%04x]\n",
336 (unsigned)dce
, wndCurrent
->hwndSelf
);
338 dce
->DCXflags
|= DCX_DCEDIRTY
;
339 SetHookFlags16(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
343 WIN_ReleaseWndPtr(wnd
);
346 xoffset
+= wnd
->rectClient
.left
;
347 yoffset
+= wnd
->rectClient
.top
;
350 WIN_ReleaseWndPtr(wndCurrent
);
353 WIN_ReleaseWndPtr(wndScope
);
355 WIN_ReleaseDesktop();
359 /***********************************************************************
367 for (i
= 0; i
< NB_DCE
; i
++)
369 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
370 if (!defaultDCstate
) defaultDCstate
= GetDCState16( dce
->hDC
);
375 /***********************************************************************
378 * Calculate the visible rectangle of a window (i.e. the client or
379 * window area clipped by the client area of all ancestors) in the
380 * corresponding coordinates. Return FALSE if the visible region is empty.
382 static BOOL
DCE_GetVisRect( WND
*wndPtr
, BOOL clientArea
, RECT
*lprect
)
384 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
386 if (wndPtr
->dwStyle
& WS_VISIBLE
)
388 INT xoffset
= lprect
->left
;
389 INT yoffset
= lprect
->top
;
391 while( !(wndPtr
->flags
& WIN_NATIVE
) &&
392 ( wndPtr
= WIN_LockWndPtr(wndPtr
->parent
)) )
394 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
396 WIN_ReleaseWndPtr(wndPtr
);
400 xoffset
+= wndPtr
->rectClient
.left
;
401 yoffset
+= wndPtr
->rectClient
.top
;
402 OffsetRect( lprect
, wndPtr
->rectClient
.left
,
403 wndPtr
->rectClient
.top
);
405 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
406 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
407 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
408 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
409 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
410 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
412 WIN_ReleaseWndPtr(wndPtr
);
416 lprect
->left
= max( lprect
->left
, wndPtr
->rectClient
.left
);
417 lprect
->right
= min( lprect
->right
, wndPtr
->rectClient
.right
);
418 lprect
->top
= max( lprect
->top
, wndPtr
->rectClient
.top
);
419 lprect
->bottom
= min( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
421 WIN_ReleaseWndPtr(wndPtr
);
423 OffsetRect( lprect
, -xoffset
, -yoffset
);
428 SetRectEmpty( lprect
);
433 /***********************************************************************
436 * Go through the linked list of windows from pWndStart to pWndEnd,
437 * adding to the clip region the intersection of the target rectangle
438 * with an offset window rectangle.
440 static BOOL
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
441 HRGN hrgnClip
, LPRECT lpRect
, int x
, int y
)
445 if( pWndStart
->pDriver
->pIsSelfClipping( pWndStart
) )
446 return TRUE
; /* The driver itself will do the clipping */
448 for (WIN_LockWndPtr(pWndStart
); (pWndStart
&& (pWndStart
!= pWndEnd
)); WIN_UpdateWndPtr(&pWndStart
,pWndStart
->next
))
450 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
452 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
453 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
454 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
455 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
457 if( IntersectRect( &rect
, &rect
, lpRect
))
459 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
)) break;
462 WIN_ReleaseWndPtr(pWndStart
);
463 return (pWndStart
== pWndEnd
);
467 /***********************************************************************
470 * Return the visible region of a window, i.e. the client or window area
471 * clipped by the client area of all ancestors, and then optionally
472 * by siblings and children.
474 HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
, HWND hwndChild
, WORD cflags
)
478 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
479 WND
*childWnd
= WIN_FindWndPtr( hwndChild
);
481 /* Get visible rectangle and create a region with it. */
483 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
485 if((hrgnVis
= CreateRectRgnIndirect( &rect
)))
487 HRGN hrgnClip
= CreateRectRgn( 0, 0, 0, 0 );
488 INT xoffset
, yoffset
;
492 /* Compute obscured region for the visible rectangle by
493 * clipping children, siblings, and ancestors. Note that
494 * DCE_GetVisRect() returns a rectangle either in client
495 * or in window coordinates (for DCX_WINDOW request). */
497 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
499 if( flags
& DCX_WINDOW
)
501 /* adjust offsets since child window rectangles are
502 * in client coordinates */
504 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
505 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
508 xoffset
= yoffset
= 0;
510 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
511 &rect
, xoffset
, yoffset
);
514 /* We may need to clip children of child window, if a window with PARENTDC
515 * class style and CLIPCHILDREN window style (like in Free Agent 16
516 * preference dialogs) gets here, we take the region for the parent window
517 * but apparently still need to clip the children of the child window... */
519 if( (cflags
& DCX_CLIPCHILDREN
) && childWnd
&& childWnd
->child
)
521 if( flags
& DCX_WINDOW
)
523 /* adjust offsets since child window rectangles are
524 * in client coordinates */
526 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
527 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
530 xoffset
= yoffset
= 0;
532 /* client coordinates of child window */
533 xoffset
+= childWnd
->rectClient
.left
;
534 yoffset
+= childWnd
->rectClient
.top
;
536 DCE_AddClipRects( childWnd
->child
, NULL
, hrgnClip
,
537 &rect
, xoffset
, yoffset
);
540 /* sibling window rectangles are in client
541 * coordinates of the parent window */
543 if (flags
& DCX_WINDOW
)
545 xoffset
= -wndPtr
->rectWindow
.left
;
546 yoffset
= -wndPtr
->rectWindow
.top
;
550 xoffset
= -wndPtr
->rectClient
.left
;
551 yoffset
= -wndPtr
->rectClient
.top
;
554 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
555 DCE_AddClipRects( wndPtr
->parent
->child
,
556 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
558 /* Clip siblings of all ancestors that have the
559 * WS_CLIPSIBLINGS style
562 while (wndPtr
->parent
)
564 WIN_UpdateWndPtr(&wndPtr
,wndPtr
->parent
);
565 xoffset
-= wndPtr
->rectClient
.left
;
566 yoffset
-= wndPtr
->rectClient
.top
;
567 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
569 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
570 hrgnClip
, &rect
, xoffset
, yoffset
);
574 /* Now once we've got a jumbo clip region we have
575 * to substract it from the visible rectangle.
578 CombineRgn( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
579 DeleteObject( hrgnClip
);
583 DeleteObject( hrgnVis
);
589 hrgnVis
= CreateRectRgn(0, 0, 0, 0); /* empty */
590 WIN_ReleaseWndPtr(wndPtr
);
591 WIN_ReleaseWndPtr(childWnd
);
595 /***********************************************************************
598 * Change region from DC-origin relative coordinates to screen coords.
601 static void DCE_OffsetVisRgn( HDC hDC
, HRGN hVisRgn
)
604 if (!(dc
= DC_GetDCPtr( hDC
))) return;
606 OffsetRgn( hVisRgn
, dc
->DCOrgX
, dc
->DCOrgY
);
608 GDI_ReleaseObj( hDC
);
611 /***********************************************************************
614 * Translate given region from the wnd client to the DC coordinates
615 * and add it to the clipping region.
617 INT
DCE_ExcludeRgn( HDC hDC
, WND
* wnd
, HRGN hRgn
)
622 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
625 MapWindowPoints( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
626 if( dce
->DCXflags
& DCX_WINDOW
)
628 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
629 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
630 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
631 WIN_ReleaseWndPtr(wnd
);
635 OffsetRgn(hRgn
, pt
.x
, pt
.y
);
637 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
641 /***********************************************************************
644 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
646 return (HDC16
)GetDCEx( hwnd
, hrgnClip
, flags
);
650 /***********************************************************************
653 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
655 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
657 HDC WINAPI
GetDCEx( HWND hwnd
, HRGN hrgnClip
, DWORD flags
)
659 HRGN hrgnVisible
= 0;
665 BOOL bUpdateVisRgn
= TRUE
;
666 BOOL bUpdateClipOrigin
= FALSE
;
668 TRACE("hwnd %04x, hrgnClip %04x, flags %08x\n",
669 hwnd
, hrgnClip
, (unsigned)flags
);
671 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
675 if (!wndPtr
->dce
) flags
|= DCX_CACHE
;
677 if (flags
& DCX_USESTYLE
)
679 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
681 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
682 flags
|= DCX_CLIPSIBLINGS
;
684 if ( !(flags
& DCX_WINDOW
) )
686 if (wndPtr
->clsStyle
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
688 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
689 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
691 else flags
|= DCX_CACHE
;
694 if( flags
& DCX_NOCLIPCHILDREN
)
697 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
700 if (flags
& DCX_WINDOW
)
701 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
703 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
704 flags
&= ~DCX_PARENTCLIP
;
705 else if( flags
& DCX_PARENTCLIP
)
708 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
709 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
711 flags
&= ~DCX_CLIPCHILDREN
;
712 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
713 flags
|= DCX_CLIPSIBLINGS
;
717 /* find a suitable DCE */
719 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
720 DCX_CACHE
| DCX_WINDOW
);
722 if (flags
& DCX_CACHE
)
727 dceEmpty
= dceUnused
= NULL
;
729 /* Strategy: First, we attempt to find a non-empty but unused DCE with
730 * compatible flags. Next, we look for an empty entry. If the cache is
731 * full we have to purge one of the unused entries.
734 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
736 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
740 if (dce
->DCXflags
& DCX_DCEEMPTY
)
743 if ((dce
->hwndCurrent
== hwnd
) &&
744 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
745 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
747 TRACE("\tfound valid %08x dce [%04x], flags %08x\n",
748 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
749 bUpdateVisRgn
= FALSE
;
750 bUpdateClipOrigin
= TRUE
;
756 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
758 /* if there's no dce empty or unused, allocate a new one */
761 dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
);
767 if( dce
->hwndCurrent
== hwnd
)
769 TRACE("\tskipping hVisRgn update\n");
770 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
772 /* Abey - 16Jul99. to take care of the nested GetDC. first one
773 with DCX_EXCLUDERGN or DCX_INTERSECTRGN flags and the next
774 one with or without these flags. */
776 if(dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
))
778 /* This is likely to be a nested BeginPaint().
779 or a BeginPaint() followed by a GetDC()*/
781 if( dce
->hClipRgn
!= hrgnClip
)
783 FIXME("new hrgnClip[%04x] smashes the previous[%04x]\n",
784 hrgnClip
, dce
->hClipRgn
);
785 DCE_DeleteClipRgn( dce
);
788 RestoreVisRgn16(dce
->hDC
);
798 dce
->hwndCurrent
= hwnd
;
800 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
803 if (!(dc
= DC_GetDCPtr( hdc
)))
808 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->flags
& DC_DIRTY
);
810 /* recompute visible region */
811 wndPtr
->pDriver
->pSetDrawable( wndPtr
, hdc
, flags
, bUpdateClipOrigin
);
812 dc
->flags
&= ~DC_DIRTY
;
813 GDI_ReleaseObj( hdc
);
817 TRACE("updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
819 if (flags
& DCX_PARENTCLIP
)
821 WND
*parentPtr
= WIN_LockWndPtr(wndPtr
->parent
);
823 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
825 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
826 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
828 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
830 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
,
831 wndPtr
->hwndSelf
, flags
);
832 if( flags
& DCX_WINDOW
)
833 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
834 -wndPtr
->rectWindow
.top
);
836 OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
837 -wndPtr
->rectClient
.top
);
838 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
841 hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
842 WIN_ReleaseWndPtr(parentPtr
);
845 if ((hwnd
== GetDesktopWindow()) && !USER_Driver
.pIsSingleWindow())
846 hrgnVisible
= CreateRectRgn( 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
) );
849 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
, 0, 0 );
850 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
853 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
854 SelectVisRgn16( hdc
, hrgnVisible
);
857 TRACE("no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
859 /* apply additional region operation (if any) */
861 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
863 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
865 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
866 dce
->hClipRgn
= hrgnClip
;
868 TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
871 CombineRgn( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
872 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
873 CombineRgn( hrgnVisible
, InquireVisRgn16( hdc
), hrgnVisible
,
874 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
875 SelectVisRgn16( hdc
, hrgnVisible
);
878 if( hrgnVisible
) DeleteObject( hrgnVisible
);
880 TRACE("(%04x,%04x,0x%lx): returning %04x\n",
881 hwnd
, hrgnClip
, flags
, hdc
);
883 WIN_ReleaseWndPtr(wndPtr
);
888 /***********************************************************************
891 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
893 return (HDC16
)GetDC( hwnd
);
897 /***********************************************************************
904 HWND hwnd
/* [in] handle of window */
907 return GetDCEx( GetDesktopWindow(), 0, DCX_CACHE
| DCX_WINDOW
);
908 return GetDCEx( hwnd
, 0, DCX_USESTYLE
);
912 /***********************************************************************
913 * GetWindowDC (USER.67)
915 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
917 if (!hwnd
) hwnd
= GetDesktopWindow16();
918 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
922 /***********************************************************************
923 * GetWindowDC (USER32.@)
925 HDC WINAPI
GetWindowDC( HWND hwnd
)
927 if (!hwnd
) hwnd
= GetDesktopWindow();
928 return GetDCEx( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
932 /***********************************************************************
933 * ReleaseDC (USER.68)
935 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
937 return (INT16
)ReleaseDC( hwnd
, hdc
);
941 /***********************************************************************
942 * ReleaseDC (USER32.@)
948 INT WINAPI
ReleaseDC(
949 HWND hwnd
/* [in] Handle of window - ignored */,
950 HDC hdc
/* [in] Handle of device context */
958 TRACE("%04x %04x\n", hwnd
, hdc
);
960 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
963 if ( dce
->DCXflags
& DCX_DCEBUSY
)
964 nRet
= DCE_ReleaseDC( dce
);
971 /***********************************************************************
974 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
976 BOOL16 WINAPI
DCHook16( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
980 DCE
*dce
= (DCE
*)data
;
983 TRACE("hDC = %04x, %i\n", hDC
, code
);
986 assert(dce
->hDC
== hDC
);
988 /* Grab the windows lock before doing anything else */
993 case DCHC_INVALIDVISRGN
:
995 /* GDI code calls this when it detects that the
996 * DC is dirty (usually after SetHookFlags()). This
997 * means that we have to recompute the visible region.
1000 if( dce
->DCXflags
& DCX_DCEBUSY
)
1003 /* Update stale DC in DCX */
1004 wndPtr
= WIN_FindWndPtr( dce
->hwndCurrent
);
1005 if (wndPtr
) wndPtr
->pDriver
->pSetDrawable( wndPtr
, dce
->hDC
, dce
->DCXflags
, TRUE
);
1007 SetHookFlags16(hDC
, DCHF_VALIDATEVISRGN
);
1008 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
, 0, 0);
1010 TRACE("\tapplying saved clipRgn\n");
1012 /* clip this region with saved clipping region */
1014 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
1015 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
1018 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
1019 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
1020 SetRectRgn(hVisRgn
,0,0,0,0);
1022 CombineRgn(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
1023 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
1025 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
1026 DCE_OffsetVisRgn( hDC
, hVisRgn
);
1027 SelectVisRgn16(hDC
, hVisRgn
);
1028 DeleteObject( hVisRgn
);
1029 WIN_ReleaseWndPtr( wndPtr
); /* Release WIN_FindWndPtr lock */
1031 else /* non-fatal but shouldn't happen */
1032 WARN("DC is not in use!\n");
1037 * Windows will not let you delete a DC that is busy
1038 * (between GetDC and ReleaseDC)
1041 if ( dce
->DCXflags
& DCX_DCEBUSY
)
1043 WARN("Application trying to delete a busy DC\n");
1049 FIXME("unknown code\n");
1052 WIN_UnlockWnds(); /* Release the wnd lock */
1057 /**********************************************************************
1058 * WindowFromDC (USER.117)
1060 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
1062 return (HWND16
)WindowFromDC( hDC
);
1066 /**********************************************************************
1067 * WindowFromDC (USER32.@)
1069 HWND WINAPI
WindowFromDC( HDC hDC
)
1077 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
1079 hwnd
= dce
? dce
->hwndCurrent
: 0;
1086 /***********************************************************************
1087 * LockWindowUpdate (USER.294)
1089 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
1091 return LockWindowUpdate( hwnd
);
1095 /***********************************************************************
1096 * LockWindowUpdate (USER32.@)
1098 BOOL WINAPI
LockWindowUpdate( HWND hwnd
)
1100 FIXME("DCX_LOCKWINDOWUPDATE is unimplemented\n");