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
31 #include "debugtools.h"
32 #include "wine/winbase16.h"
33 #include "wine/winuser16.h"
35 DEFAULT_DEBUG_CHANNEL(dc
)
37 #define NB_DCE 5 /* Number of DCEs created at startup */
39 static DCE
*firstDCE
= 0;
40 static HDC defaultDCstate
= 0;
42 static void DCE_DeleteClipRgn( DCE
* );
43 static INT
DCE_ReleaseDC( DCE
* );
46 /***********************************************************************
49 static void DCE_DumpCache(void)
59 DPRINTF("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
60 (unsigned)dce
, dce
->hwndCurrent
, (unsigned)dce
->DCXflags
,
61 (dce
->DCXflags
& DCX_CACHE
) ? "Cache" : "Owned",
62 (dce
->DCXflags
& DCX_DCEBUSY
) ? "InUse" : "" );
69 /***********************************************************************
74 DCE
*DCE_AllocDCE( HWND hWnd
, DCE_TYPE type
)
80 if (!(dce
= HeapAlloc( SystemHeap
, 0, sizeof(DCE
) ))) return NULL
;
81 if (!(dce
->hDC
= CreateDC16( "DISPLAY", NULL
, NULL
, NULL
)))
83 HeapFree( SystemHeap
, 0, dce
);
87 wnd
= WIN_FindWndPtr(hWnd
);
89 /* store DCE handle in DC hook data field */
91 hookProc
= (FARPROC16
)NE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
92 SetDCHook( dce
->hDC
, hookProc
, (DWORD
)dce
);
94 dce
->hwndCurrent
= hWnd
;
99 if( type
!= DCE_CACHE_DC
) /* owned or class DC */
101 dce
->DCXflags
= DCX_DCEBUSY
;
104 if( wnd
->dwStyle
& WS_CLIPCHILDREN
) dce
->DCXflags
|= DCX_CLIPCHILDREN
;
105 if( wnd
->dwStyle
& WS_CLIPSIBLINGS
) dce
->DCXflags
|= DCX_CLIPSIBLINGS
;
107 SetHookFlags16(dce
->hDC
,DCHF_INVALIDATEVISRGN
);
109 else dce
->DCXflags
= DCX_CACHE
| DCX_DCEEMPTY
;
111 WIN_ReleaseWndPtr(wnd
);
117 /***********************************************************************
120 DCE
* DCE_FreeDCE( DCE
*dce
)
124 if (!dce
) return NULL
;
130 while (*ppDCE
&& (*ppDCE
!= dce
)) ppDCE
= &(*ppDCE
)->next
;
131 if (*ppDCE
== dce
) *ppDCE
= dce
->next
;
133 SetDCHook(dce
->hDC
, NULL
, 0L);
135 DeleteDC( dce
->hDC
);
136 if( dce
->hClipRgn
&& !(dce
->DCXflags
& DCX_KEEPCLIPRGN
) )
137 DeleteObject(dce
->hClipRgn
);
138 HeapFree( SystemHeap
, 0, dce
);
145 /***********************************************************************
148 * Remove owned DCE and reset unreleased cache DCEs.
150 void DCE_FreeWindowDCE( WND
* pWnd
)
159 if( pDCE
->hwndCurrent
== pWnd
->hwndSelf
)
161 if( pDCE
== pWnd
->dce
) /* owned or Class DCE*/
163 if (pWnd
->class->style
& CS_OWNDC
) /* owned DCE*/
165 pDCE
= DCE_FreeDCE( pDCE
);
169 else if( pDCE
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
) ) /* Class DCE*/
171 DCE_DeleteClipRgn( pDCE
);
172 pDCE
->hwndCurrent
= 0;
177 if( pDCE
->DCXflags
& DCX_DCEBUSY
) /* shared cache DCE */
179 ERR("[%04x] GetDC() without ReleaseDC()!\n",
181 DCE_ReleaseDC( pDCE
);
184 pDCE
->DCXflags
&= DCX_CACHE
;
185 pDCE
->DCXflags
|= DCX_DCEEMPTY
;
186 pDCE
->hwndCurrent
= 0;
196 /***********************************************************************
199 static void DCE_DeleteClipRgn( DCE
* dce
)
201 dce
->DCXflags
&= ~(DCX_EXCLUDERGN
| DCX_INTERSECTRGN
| DCX_WINDOWPAINT
);
203 if( dce
->DCXflags
& DCX_KEEPCLIPRGN
)
204 dce
->DCXflags
&= ~DCX_KEEPCLIPRGN
;
206 if( dce
->hClipRgn
> 1 )
207 DeleteObject( dce
->hClipRgn
);
211 TRACE("\trestoring VisRgn\n");
213 RestoreVisRgn16(dce
->hDC
);
217 /***********************************************************************
220 static INT
DCE_ReleaseDC( DCE
* dce
)
222 if ((dce
->DCXflags
& (DCX_DCEEMPTY
| DCX_DCEBUSY
)) != DCX_DCEBUSY
) return 0;
224 /* restore previous visible region */
226 if ((dce
->DCXflags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
227 (dce
->DCXflags
& (DCX_CACHE
| DCX_WINDOWPAINT
)) )
228 DCE_DeleteClipRgn( dce
);
230 if (dce
->DCXflags
& DCX_CACHE
)
232 SetDCState16( dce
->hDC
, defaultDCstate
);
233 dce
->DCXflags
&= ~DCX_DCEBUSY
;
234 if (dce
->DCXflags
& DCX_DCEDIRTY
)
236 /* don't keep around invalidated entries
237 * because SetDCState() disables hVisRgn updates
238 * by removing dirty bit. */
240 dce
->hwndCurrent
= 0;
241 dce
->DCXflags
&= DCX_CACHE
;
242 dce
->DCXflags
|= DCX_DCEEMPTY
;
249 /***********************************************************************
252 * It is called from SetWindowPos() - we have to mark as dirty all busy
253 * DCEs for windows that have pWnd->parent as an ansector and whose client
254 * rect intersects with specified update rectangle. In addition, pWnd->parent
255 * DCEs may need to be updated if DCX_CLIPCHILDREN flag is set.
257 BOOL
DCE_InvalidateDCE(WND
* pWnd
, const RECT
* pRectUpdate
)
259 WND
* wndScope
= WIN_LockWndPtr(pWnd
->parent
);
260 WND
*pDesktop
= WIN_GetDesktop();
267 TRACE("scope hwnd = %04x, (%i,%i - %i,%i)\n",
268 wndScope
->hwndSelf
, pRectUpdate
->left
,pRectUpdate
->top
,
269 pRectUpdate
->right
,pRectUpdate
->bottom
);
273 /* walk all DCEs and fixup non-empty entries */
275 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
277 if( !(dce
->DCXflags
& DCX_DCEEMPTY
) )
279 WND
* wndCurrent
= WIN_FindWndPtr(dce
->hwndCurrent
);
284 INT xoffset
= 0, yoffset
= 0;
286 if( (wndCurrent
== wndScope
) && !(dce
->DCXflags
& DCX_CLIPCHILDREN
) )
288 /* child window positions don't bother us */
289 WIN_ReleaseWndPtr(wndCurrent
);
293 if( !Options
.desktopGeometry
&& wndCurrent
== pDesktop
)
295 /* don't bother with fake desktop */
296 WIN_ReleaseWndPtr(wndCurrent
);
300 /* check if DCE window is within the z-order scope */
302 for( wnd
= WIN_LockWndPtr(wndCurrent
); wnd
; WIN_UpdateWndPtr(&wnd
,wnd
->parent
))
304 if( wnd
== wndScope
)
308 wndRect
= wndCurrent
->rectWindow
;
310 OffsetRect( &wndRect
, xoffset
- wndCurrent
->rectClient
.left
,
311 yoffset
- wndCurrent
->rectClient
.top
);
313 if (pWnd
== wndCurrent
||
314 IntersectRect( &wndRect
, &wndRect
, pRectUpdate
))
316 if( !(dce
->DCXflags
& DCX_DCEBUSY
) )
318 /* Don't bother with visible regions of unused DCEs */
320 TRACE("\tpurged %08x dce [%04x]\n",
321 (unsigned)dce
, wndCurrent
->hwndSelf
);
323 dce
->hwndCurrent
= 0;
324 dce
->DCXflags
&= DCX_CACHE
;
325 dce
->DCXflags
|= DCX_DCEEMPTY
;
329 /* Set dirty bits in the hDC and DCE structs */
331 TRACE("\tfixed up %08x dce [%04x]\n",
332 (unsigned)dce
, wndCurrent
->hwndSelf
);
334 dce
->DCXflags
|= DCX_DCEDIRTY
;
335 SetHookFlags16(dce
->hDC
, DCHF_INVALIDATEVISRGN
);
339 WIN_ReleaseWndPtr(wnd
);
342 xoffset
+= wnd
->rectClient
.left
;
343 yoffset
+= wnd
->rectClient
.top
;
346 WIN_ReleaseWndPtr(wndCurrent
);
349 WIN_ReleaseWndPtr(wndScope
);
351 WIN_ReleaseDesktop();
355 /***********************************************************************
363 for (i
= 0; i
< NB_DCE
; i
++)
365 if (!(dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
))) return;
366 if (!defaultDCstate
) defaultDCstate
= GetDCState16( dce
->hDC
);
371 /***********************************************************************
374 * Calculate the visible rectangle of a window (i.e. the client or
375 * window area clipped by the client area of all ancestors) in the
376 * corresponding coordinates. Return FALSE if the visible region is empty.
378 static BOOL
DCE_GetVisRect( WND
*wndPtr
, BOOL clientArea
, RECT
*lprect
)
380 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
382 if (wndPtr
->dwStyle
& WS_VISIBLE
)
384 INT xoffset
= lprect
->left
;
385 INT yoffset
= lprect
->top
;
387 while( !(wndPtr
->flags
& WIN_NATIVE
) &&
388 ( wndPtr
= WIN_LockWndPtr(wndPtr
->parent
)) )
390 if ( (wndPtr
->dwStyle
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
392 WIN_ReleaseWndPtr(wndPtr
);
396 xoffset
+= wndPtr
->rectClient
.left
;
397 yoffset
+= wndPtr
->rectClient
.top
;
398 OffsetRect( lprect
, wndPtr
->rectClient
.left
,
399 wndPtr
->rectClient
.top
);
401 if( (wndPtr
->rectClient
.left
>= wndPtr
->rectClient
.right
) ||
402 (wndPtr
->rectClient
.top
>= wndPtr
->rectClient
.bottom
) ||
403 (lprect
->left
>= wndPtr
->rectClient
.right
) ||
404 (lprect
->right
<= wndPtr
->rectClient
.left
) ||
405 (lprect
->top
>= wndPtr
->rectClient
.bottom
) ||
406 (lprect
->bottom
<= wndPtr
->rectClient
.top
) )
408 WIN_ReleaseWndPtr(wndPtr
);
412 lprect
->left
= MAX( lprect
->left
, wndPtr
->rectClient
.left
);
413 lprect
->right
= MIN( lprect
->right
, wndPtr
->rectClient
.right
);
414 lprect
->top
= MAX( lprect
->top
, wndPtr
->rectClient
.top
);
415 lprect
->bottom
= MIN( lprect
->bottom
, wndPtr
->rectClient
.bottom
);
417 WIN_ReleaseWndPtr(wndPtr
);
419 OffsetRect( lprect
, -xoffset
, -yoffset
);
424 SetRectEmpty( lprect
);
429 /***********************************************************************
432 * Go through the linked list of windows from pWndStart to pWndEnd,
433 * adding to the clip region the intersection of the target rectangle
434 * with an offset window rectangle.
436 static BOOL
DCE_AddClipRects( WND
*pWndStart
, WND
*pWndEnd
,
437 HRGN hrgnClip
, LPRECT lpRect
, int x
, int y
)
441 if( pWndStart
->pDriver
->pIsSelfClipping( pWndStart
) )
442 return TRUE
; /* The driver itself will do the clipping */
444 for (WIN_LockWndPtr(pWndStart
); pWndStart
!= pWndEnd
; WIN_UpdateWndPtr(&pWndStart
,pWndStart
->next
))
446 if( !(pWndStart
->dwStyle
& WS_VISIBLE
) ) continue;
448 rect
.left
= pWndStart
->rectWindow
.left
+ x
;
449 rect
.top
= pWndStart
->rectWindow
.top
+ y
;
450 rect
.right
= pWndStart
->rectWindow
.right
+ x
;
451 rect
.bottom
= pWndStart
->rectWindow
.bottom
+ y
;
453 if( IntersectRect( &rect
, &rect
, lpRect
))
455 if(!REGION_UnionRectWithRgn( hrgnClip
, &rect
)) break;
458 WIN_ReleaseWndPtr(pWndStart
);
459 return (pWndStart
== pWndEnd
);
463 /***********************************************************************
466 * Return the visible region of a window, i.e. the client or window area
467 * clipped by the client area of all ancestors, and then optionally
468 * by siblings and children.
470 HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
, HWND hwndChild
, WORD cflags
)
474 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
475 WND
*childWnd
= WIN_FindWndPtr( hwndChild
);
477 /* Get visible rectangle and create a region with it. */
479 if (wndPtr
&& DCE_GetVisRect(wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
481 if((hrgnVis
= CreateRectRgnIndirect( &rect
)))
483 HRGN hrgnClip
= CreateRectRgn( 0, 0, 0, 0 );
484 INT xoffset
, yoffset
;
488 /* Compute obscured region for the visible rectangle by
489 * clipping children, siblings, and ancestors. Note that
490 * DCE_GetVisRect() returns a rectangle either in client
491 * or in window coordinates (for DCX_WINDOW request). */
493 if( (flags
& DCX_CLIPCHILDREN
) && wndPtr
->child
)
495 if( flags
& DCX_WINDOW
)
497 /* adjust offsets since child window rectangles are
498 * in client coordinates */
500 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
501 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
504 xoffset
= yoffset
= 0;
506 DCE_AddClipRects( wndPtr
->child
, NULL
, hrgnClip
,
507 &rect
, xoffset
, yoffset
);
510 /* We may need to clip children of child window, if a window with PARENTDC
511 * class style and CLIPCHILDREN window style (like in Free Agent 16
512 * preference dialogs) gets here, we take the region for the parent window
513 * but apparently still need to clip the children of the child window... */
515 if( (cflags
& DCX_CLIPCHILDREN
) && childWnd
&& childWnd
->child
)
517 if( flags
& DCX_WINDOW
)
519 /* adjust offsets since child window rectangles are
520 * in client coordinates */
522 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
523 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
526 xoffset
= yoffset
= 0;
528 /* client coordinates of child window */
529 xoffset
+= childWnd
->rectClient
.left
;
530 yoffset
+= childWnd
->rectClient
.top
;
532 DCE_AddClipRects( childWnd
->child
, NULL
, hrgnClip
,
533 &rect
, xoffset
, yoffset
);
536 /* sibling window rectangles are in client
537 * coordinates of the parent window */
539 if (flags
& DCX_WINDOW
)
541 xoffset
= -wndPtr
->rectWindow
.left
;
542 yoffset
= -wndPtr
->rectWindow
.top
;
546 xoffset
= -wndPtr
->rectClient
.left
;
547 yoffset
= -wndPtr
->rectClient
.top
;
550 if (flags
& DCX_CLIPSIBLINGS
&& wndPtr
->parent
)
551 DCE_AddClipRects( wndPtr
->parent
->child
,
552 wndPtr
, hrgnClip
, &rect
, xoffset
, yoffset
);
554 /* Clip siblings of all ancestors that have the
555 * WS_CLIPSIBLINGS style
558 while (wndPtr
->dwStyle
& WS_CHILD
)
560 WIN_UpdateWndPtr(&wndPtr
,wndPtr
->parent
);
561 xoffset
-= wndPtr
->rectClient
.left
;
562 yoffset
-= wndPtr
->rectClient
.top
;
563 if(wndPtr
->dwStyle
& WS_CLIPSIBLINGS
&& wndPtr
->parent
)
565 DCE_AddClipRects( wndPtr
->parent
->child
, wndPtr
,
566 hrgnClip
, &rect
, xoffset
, yoffset
);
570 /* Now once we've got a jumbo clip region we have
571 * to substract it from the visible rectangle.
574 CombineRgn( hrgnVis
, hrgnVis
, hrgnClip
, RGN_DIFF
);
575 DeleteObject( hrgnClip
);
579 DeleteObject( hrgnVis
);
585 hrgnVis
= CreateRectRgn(0, 0, 0, 0); /* empty */
586 WIN_ReleaseWndPtr(wndPtr
);
587 WIN_ReleaseWndPtr(childWnd
);
591 /***********************************************************************
594 * Change region from DC-origin relative coordinates to screen coords.
597 static void DCE_OffsetVisRgn( HDC hDC
, HRGN hVisRgn
)
600 if (!(dc
= (DC
*) GDI_GetObjPtr( hDC
, DC_MAGIC
))) return;
602 OffsetRgn( hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
604 GDI_HEAP_UNLOCK( hDC
);
607 /***********************************************************************
610 * Translate given region from the wnd client to the DC coordinates
611 * and add it to the clipping region.
613 INT16
DCE_ExcludeRgn( HDC hDC
, WND
* wnd
, HRGN hRgn
)
618 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
621 MapWindowPoints( wnd
->hwndSelf
, dce
->hwndCurrent
, &pt
, 1);
622 if( dce
->DCXflags
& DCX_WINDOW
)
624 wnd
= WIN_FindWndPtr(dce
->hwndCurrent
);
625 pt
.x
+= wnd
->rectClient
.left
- wnd
->rectWindow
.left
;
626 pt
.y
+= wnd
->rectClient
.top
- wnd
->rectWindow
.top
;
627 WIN_ReleaseWndPtr(wnd
);
631 OffsetRgn(hRgn
, pt
.x
, pt
.y
);
633 return ExtSelectClipRgn( hDC
, hRgn
, RGN_DIFF
);
637 /***********************************************************************
638 * GetDCEx16 (USER.359)
640 HDC16 WINAPI
GetDCEx16( HWND16 hwnd
, HRGN16 hrgnClip
, DWORD flags
)
642 return (HDC16
)GetDCEx( hwnd
, hrgnClip
, flags
);
646 /***********************************************************************
647 * GetDCEx32 (USER32.231)
649 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
651 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
653 HDC WINAPI
GetDCEx( HWND hwnd
, HRGN hrgnClip
, DWORD flags
)
655 HRGN hrgnVisible
= 0;
661 BOOL bUpdateVisRgn
= TRUE
;
662 BOOL bUpdateClipOrigin
= FALSE
;
664 TRACE("hwnd %04x, hrgnClip %04x, flags %08x\n",
665 hwnd
, hrgnClip
, (unsigned)flags
);
667 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
671 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
))) flags
|= DCX_CACHE
;
673 if (flags
& DCX_USESTYLE
)
675 flags
&= ~( DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
677 if( wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
678 flags
|= DCX_CLIPSIBLINGS
;
680 if ( !(flags
& DCX_WINDOW
) )
682 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
684 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
&&
685 !(wndPtr
->dwStyle
& WS_MINIMIZE
) ) flags
|= DCX_CLIPCHILDREN
;
687 else flags
|= DCX_CACHE
;
690 if( flags
& DCX_NOCLIPCHILDREN
)
693 flags
&= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
696 if (flags
& DCX_WINDOW
)
697 flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
699 if (!(wndPtr
->dwStyle
& WS_CHILD
) || !wndPtr
->parent
)
700 flags
&= ~DCX_PARENTCLIP
;
701 else if( flags
& DCX_PARENTCLIP
)
704 if( !(flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) )
705 if( (wndPtr
->dwStyle
& WS_VISIBLE
) && (wndPtr
->parent
->dwStyle
& WS_VISIBLE
) )
707 flags
&= ~DCX_CLIPCHILDREN
;
708 if( wndPtr
->parent
->dwStyle
& WS_CLIPSIBLINGS
)
709 flags
|= DCX_CLIPSIBLINGS
;
713 /* find a suitable DCE */
715 dcxFlags
= flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
716 DCX_CACHE
| DCX_WINDOW
);
718 if (flags
& DCX_CACHE
)
723 dceEmpty
= dceUnused
= NULL
;
725 /* Strategy: First, we attempt to find a non-empty but unused DCE with
726 * compatible flags. Next, we look for an empty entry. If the cache is
727 * full we have to purge one of the unused entries.
730 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
732 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
736 if (dce
->DCXflags
& DCX_DCEEMPTY
)
739 if ((dce
->hwndCurrent
== hwnd
) &&
740 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
741 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
743 TRACE("\tfound valid %08x dce [%04x], flags %08x\n",
744 (unsigned)dce
, hwnd
, (unsigned)dcxFlags
);
745 bUpdateVisRgn
= FALSE
;
746 bUpdateClipOrigin
= TRUE
;
752 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
754 /* if there's no dce empty or unused, allocate a new one */
757 dce
= DCE_AllocDCE( 0, DCE_CACHE_DC
);
762 dce
= (wndPtr
->class->style
& CS_OWNDC
) ? wndPtr
->dce
: wndPtr
->class->dce
;
763 if( dce
->hwndCurrent
== hwnd
)
765 TRACE("\tskipping hVisRgn update\n");
766 bUpdateVisRgn
= FALSE
; /* updated automatically, via DCHook() */
768 /* Abey - 16Jul99. to take care of the nested GetDC. first one
769 with DCX_EXCLUDERGN or DCX_INTERSECTRGN flags and the next
770 one with or without these flags. */
772 if(dce
->DCXflags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
))
774 /* This is likely to be a nested BeginPaint().
775 or a BeginPaint() followed by a GetDC()*/
777 if( dce
->hClipRgn
!= hrgnClip
)
779 FIXME("new hrgnClip[%04x] smashes the previous[%04x]\n",
780 hrgnClip
, dce
->hClipRgn
);
781 DCE_DeleteClipRgn( dce
);
784 RestoreVisRgn16(dce
->hDC
);
794 dce
->hwndCurrent
= hwnd
;
796 dce
->DCXflags
= dcxFlags
| (flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
799 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
)))
804 bUpdateVisRgn
= bUpdateVisRgn
|| (dc
->w
.flags
& DC_DIRTY
);
806 /* recompute visible region */
807 wndPtr
->pDriver
->pSetDrawable( wndPtr
, dc
, flags
, bUpdateClipOrigin
);
811 TRACE("updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
813 if (flags
& DCX_PARENTCLIP
)
815 WND
*parentPtr
= WIN_LockWndPtr(wndPtr
->parent
);
817 if( wndPtr
->dwStyle
& WS_VISIBLE
&& !(parentPtr
->dwStyle
& WS_MINIMIZE
) )
819 if( parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
820 dcxFlags
= DCX_CLIPSIBLINGS
| (flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
822 dcxFlags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
824 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, dcxFlags
,
825 wndPtr
->hwndSelf
, flags
);
826 if( flags
& DCX_WINDOW
)
827 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
828 -wndPtr
->rectWindow
.top
);
830 OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
831 -wndPtr
->rectClient
.top
);
832 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
835 hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
836 WIN_ReleaseWndPtr(parentPtr
);
839 if ((hwnd
== GetDesktopWindow()) && !DESKTOP_IsSingleWindow())
840 hrgnVisible
= CreateRectRgn( 0, 0, GetSystemMetrics(SM_CXSCREEN
), GetSystemMetrics(SM_CYSCREEN
) );
843 hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
, 0, 0 );
844 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
847 dc
->w
.flags
&= ~DC_DIRTY
;
848 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
849 SelectVisRgn16( hdc
, hrgnVisible
);
852 TRACE("no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce
, hwnd
);
854 /* apply additional region operation (if any) */
856 if( flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
) )
858 if( !hrgnVisible
) hrgnVisible
= CreateRectRgn( 0, 0, 0, 0 );
860 dce
->DCXflags
|= flags
& (DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
861 dce
->hClipRgn
= hrgnClip
;
863 TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgnClip
);
866 CombineRgn( hrgnVisible
, hrgnClip
, 0, RGN_COPY
);
867 DCE_OffsetVisRgn( hdc
, hrgnVisible
);
868 CombineRgn( hrgnVisible
, InquireVisRgn16( hdc
), hrgnVisible
,
869 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
870 SelectVisRgn16( hdc
, hrgnVisible
);
873 if( hrgnVisible
) DeleteObject( hrgnVisible
);
875 TRACE("(%04x,%04x,0x%lx): returning %04x\n",
876 hwnd
, hrgnClip
, flags
, hdc
);
878 WIN_ReleaseWndPtr(wndPtr
);
883 /***********************************************************************
886 HDC16 WINAPI
GetDC16( HWND16 hwnd
)
888 return (HDC16
)GetDC( hwnd
);
892 /***********************************************************************
893 * GetDC32 (USER32.230)
899 HWND hwnd
/* handle of window */
902 return GetDCEx( GetDesktopWindow(), 0, DCX_CACHE
| DCX_WINDOW
);
903 return GetDCEx( hwnd
, 0, DCX_USESTYLE
);
907 /***********************************************************************
908 * GetWindowDC16 (USER.67)
910 HDC16 WINAPI
GetWindowDC16( HWND16 hwnd
)
912 if (!hwnd
) hwnd
= GetDesktopWindow16();
913 return GetDCEx16( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
917 /***********************************************************************
918 * GetWindowDC32 (USER32.304)
920 HDC WINAPI
GetWindowDC( HWND hwnd
)
922 if (!hwnd
) hwnd
= GetDesktopWindow();
923 return GetDCEx( hwnd
, 0, DCX_USESTYLE
| DCX_WINDOW
);
927 /***********************************************************************
928 * ReleaseDC16 (USER.68)
930 INT16 WINAPI
ReleaseDC16( HWND16 hwnd
, HDC16 hdc
)
932 return (INT16
)ReleaseDC( hwnd
, hdc
);
936 /***********************************************************************
937 * ReleaseDC32 (USER32.440)
943 INT WINAPI
ReleaseDC(
944 HWND hwnd
/* Handle of window - ignored */,
945 HDC hdc
/* Handle of device context */
953 TRACE("%04x %04x\n", hwnd
, hdc
);
955 while (dce
&& (dce
->hDC
!= hdc
)) dce
= dce
->next
;
958 if ( dce
->DCXflags
& DCX_DCEBUSY
)
959 nRet
= DCE_ReleaseDC( dce
);
966 /***********************************************************************
969 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
971 BOOL16 WINAPI
DCHook16( HDC16 hDC
, WORD code
, DWORD data
, LPARAM lParam
)
975 DCE
*dce
= (DCE
*)data
;
979 TRACE("hDC = %04x, %i\n", hDC
, code
);
982 assert(dce
->hDC
== hDC
);
984 /* Grab the windows lock before doing anything else */
989 case DCHC_INVALIDVISRGN
:
991 /* GDI code calls this when it detects that the
992 * DC is dirty (usually after SetHookFlags()). This
993 * means that we have to recompute the visible region.
996 if( dce
->DCXflags
& DCX_DCEBUSY
)
999 /* Update stale DC in DCX */
1000 wndPtr
= WIN_FindWndPtr( dce
->hwndCurrent
);
1001 dc
= (DC
*) GDI_GetObjPtr( dce
->hDC
, DC_MAGIC
);
1003 wndPtr
->pDriver
->pSetDrawable( wndPtr
, dc
,dce
->DCXflags
,TRUE
);
1005 SetHookFlags16(hDC
, DCHF_VALIDATEVISRGN
);
1006 hVisRgn
= DCE_GetVisRgn(dce
->hwndCurrent
, dce
->DCXflags
, 0, 0);
1008 TRACE("\tapplying saved clipRgn\n");
1010 /* clip this region with saved clipping region */
1012 if ( (dce
->DCXflags
& DCX_INTERSECTRGN
&& dce
->hClipRgn
!= 1) ||
1013 ( dce
->DCXflags
& DCX_EXCLUDERGN
&& dce
->hClipRgn
) )
1016 if( (!dce
->hClipRgn
&& dce
->DCXflags
& DCX_INTERSECTRGN
) ||
1017 (dce
->hClipRgn
== 1 && dce
->DCXflags
& DCX_EXCLUDERGN
) )
1018 SetRectRgn(hVisRgn
,0,0,0,0);
1020 CombineRgn(hVisRgn
, hVisRgn
, dce
->hClipRgn
,
1021 (dce
->DCXflags
& DCX_EXCLUDERGN
)? RGN_DIFF
:RGN_AND
);
1023 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
1024 DCE_OffsetVisRgn( hDC
, hVisRgn
);
1025 SelectVisRgn16(hDC
, hVisRgn
);
1026 DeleteObject( hVisRgn
);
1027 WIN_ReleaseWndPtr( wndPtr
); /* Release WIN_FindWndPtr lock */
1029 else /* non-fatal but shouldn't happen */
1030 WARN("DC is not in use!\n");
1035 * Windows will not let you delete a DC that is busy
1036 * (between GetDC and ReleaseDC)
1039 if ( dce
->DCXflags
& DCX_DCEBUSY
)
1041 WARN("Application trying to delete a busy DC\n");
1047 FIXME("unknown code\n");
1050 WIN_UnlockWnds(); /* Release the wnd lock */
1055 /**********************************************************************
1056 * WindowFromDC16 (USER.117)
1058 HWND16 WINAPI
WindowFromDC16( HDC16 hDC
)
1060 return (HWND16
)WindowFromDC( hDC
);
1064 /**********************************************************************
1065 * WindowFromDC32 (USER32.581)
1067 HWND WINAPI
WindowFromDC( HDC hDC
)
1075 while (dce
&& (dce
->hDC
!= hDC
)) dce
= dce
->next
;
1077 hwnd
= dce
? dce
->hwndCurrent
: 0;
1084 /***********************************************************************
1085 * LockWindowUpdate16 (USER.294)
1087 BOOL16 WINAPI
LockWindowUpdate16( HWND16 hwnd
)
1089 return LockWindowUpdate( hwnd
);
1093 /***********************************************************************
1094 * LockWindowUpdate32 (USER32.378)
1096 BOOL WINAPI
LockWindowUpdate( HWND hwnd
)
1098 /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */