4 * Copyright 1993 Alexandre Julliard
6 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
14 #include "sysmetrics.h"
16 /* #define DEBUG_DC */
19 #define NB_DCE 5 /* Number of DCEs created at startup */
21 static HANDLE firstDCE
= 0;
22 static HDC defaultDCstate
= 0;
25 /***********************************************************************
30 HANDLE
DCE_AllocDCE( DCE_TYPE type
)
33 HANDLE handle
= USER_HEAP_ALLOC( GMEM_MOVEABLE
, sizeof(DCE
) );
34 if (!handle
) return 0;
35 dce
= (DCE
*) USER_HEAP_ADDR( handle
);
36 if (!(dce
->hdc
= CreateDC( "DISPLAY", NULL
, NULL
, NULL
)))
38 USER_HEAP_FREE( handle
);
43 dce
->inUse
= (type
!= DCE_CACHE_DC
);
46 dce
->hNext
= firstDCE
;
52 /***********************************************************************
55 void DCE_FreeDCE( HANDLE hdce
)
58 HANDLE
*handle
= &firstDCE
;
60 if (!(dce
= (DCE
*) USER_HEAP_ADDR( hdce
))) return;
61 while (*handle
&& (*handle
!= hdce
))
63 DCE
* prev
= (DCE
*) USER_HEAP_ADDR( *handle
);
64 handle
= &prev
->hNext
;
66 if (*handle
== hdce
) *handle
= dce
->hNext
;
68 USER_HEAP_FREE( hdce
);
72 /***********************************************************************
81 for (i
= 0; i
< NB_DCE
; i
++)
83 if (!(handle
= DCE_AllocDCE( DCE_CACHE_DC
))) return;
84 dce
= (DCE
*) USER_HEAP_ADDR( handle
);
85 if (!defaultDCstate
) defaultDCstate
= GetDCState( dce
->hdc
);
90 /***********************************************************************
93 * Calc the visible rectangle of a window, i.e. the client or
94 * window area clipped by the client area of all ancestors.
95 * Return FALSE if the visible region is empty.
97 static BOOL
DCE_GetVisRect( WND
*wndPtr
, BOOL clientArea
, RECT
*lprect
)
101 *lprect
= clientArea
? wndPtr
->rectClient
: wndPtr
->rectWindow
;
102 xoffset
= lprect
->left
;
103 yoffset
= lprect
->top
;
105 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
107 SetRectEmpty( lprect
); /* Clip everything */
111 while (wndPtr
->hwndParent
)
113 WND
*parentPtr
= WIN_FindWndPtr( wndPtr
->hwndParent
);
114 if (!(parentPtr
->dwStyle
& WS_VISIBLE
) ||
115 (parentPtr
->flags
& WIN_NO_REDRAW
) ||
116 (parentPtr
->dwStyle
& WS_ICONIC
))
118 SetRectEmpty( lprect
); /* Clip everything */
121 xoffset
+= parentPtr
->rectClient
.left
;
122 yoffset
+= parentPtr
->rectClient
.top
;
123 OffsetRect( lprect
, parentPtr
->rectClient
.left
,
124 parentPtr
->rectClient
.top
);
126 /* Warning!! we assume that IntersectRect() handles the case */
127 /* where the destination is the same as one of the sources. */
128 if (!IntersectRect( lprect
, lprect
, &parentPtr
->rectClient
))
129 return FALSE
; /* Visible rectangle is empty */
132 OffsetRect( lprect
, -xoffset
, -yoffset
);
137 /***********************************************************************
140 * Go through the linked list of windows from hwndStart to hwndEnd,
141 * removing from the given region the rectangle of each window offset
142 * by a given amount. The new region is returned, and the original one
143 * is destroyed. Used to implement DCX_CLIPSIBLINGS and
144 * DCX_CLIPCHILDREN styles.
146 static HRGN
DCE_ClipWindows( HWND hwndStart
, HWND hwndEnd
,
147 HRGN hrgn
, int xoffset
, int yoffset
)
149 HRGN hrgnTmp
, hrgnNew
;
152 if (!hwndStart
) return hrgn
;
153 for (; hwndStart
!= hwndEnd
; hwndStart
= wndPtr
->hwndNext
)
155 hrgnTmp
= hrgnNew
= 0;
156 wndPtr
= WIN_FindWndPtr( hwndStart
);
157 if (!(wndPtr
->dwStyle
& WS_VISIBLE
)) continue;
158 if (!(hrgnTmp
= CreateRectRgn( 0, 0, 0, 0 ))) break;
159 if (!(hrgnNew
= CreateRectRgn( wndPtr
->rectWindow
.left
+ xoffset
,
160 wndPtr
->rectWindow
.top
+ yoffset
,
161 wndPtr
->rectWindow
.right
+ xoffset
,
162 wndPtr
->rectWindow
.bottom
+ yoffset
)))
164 if (!CombineRgn( hrgnTmp
, hrgn
, hrgnNew
, RGN_DIFF
)) break;
165 DeleteObject( hrgn
);
166 DeleteObject( hrgnNew
);
169 if (hwndStart
!= hwndEnd
) /* something went wrong */
171 if (hrgnTmp
) DeleteObject( hrgnTmp
);
172 if (hrgnNew
) DeleteObject( hrgnNew
);
173 if (hrgn
) DeleteObject( hrgn
);
180 /***********************************************************************
183 * Return the visible region of a window, i.e. the client or window area
184 * clipped by the client area of all ancestors, and then optionally
185 * by siblings and children.
187 static HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
)
191 int xoffset
, yoffset
;
192 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
194 /* Get visible rectangle and create a region with it */
196 if (!DCE_GetVisRect( wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
198 return CreateRectRgn( 0, 0, 0, 0 ); /* Visible region is empty */
200 if (!(hrgn
= CreateRectRgnIndirect( &rect
))) return 0;
202 /* Clip all children from the visible region */
204 if (flags
& DCX_CLIPCHILDREN
)
206 if (flags
& DCX_WINDOW
)
208 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
209 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
211 else xoffset
= yoffset
= 0;
212 hrgn
= DCE_ClipWindows( wndPtr
->hwndChild
, 0, hrgn
, xoffset
, yoffset
);
216 /* Clip siblings placed above this window */
218 if (flags
& DCX_WINDOW
)
220 xoffset
= -wndPtr
->rectWindow
.left
;
221 yoffset
= -wndPtr
->rectWindow
.top
;
225 xoffset
= -wndPtr
->rectClient
.left
;
226 yoffset
= -wndPtr
->rectClient
.top
;
228 if (flags
& DCX_CLIPSIBLINGS
)
230 hrgn
= DCE_ClipWindows( GetWindow( wndPtr
->hwndParent
, GW_CHILD
),
231 hwnd
, hrgn
, xoffset
, yoffset
);
235 /* Clip siblings of all ancestors that have the WS_CLIPSIBLINGS style */
237 while (wndPtr
->dwStyle
& WS_CHILD
)
239 hwnd
= wndPtr
->hwndParent
;
240 wndPtr
= WIN_FindWndPtr( hwnd
);
241 xoffset
-= wndPtr
->rectClient
.left
;
242 yoffset
-= wndPtr
->rectClient
.top
;
243 hrgn
= DCE_ClipWindows( GetWindow( wndPtr
->hwndParent
, GW_CHILD
),
244 hwnd
, hrgn
, xoffset
, yoffset
);
251 /***********************************************************************
254 * Set the drawable, origin and dimensions for the DC associated to
257 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
)
259 if (!wndPtr
) /* Get a DC for the whole screen */
263 dc
->u
.x
.drawable
= rootWindow
;
264 XSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
268 if (flags
& DCX_WINDOW
)
270 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
271 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
275 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
276 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
278 while (!wndPtr
->window
)
280 wndPtr
= WIN_FindWndPtr( wndPtr
->hwndParent
);
281 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
282 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
284 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
285 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
286 dc
->u
.x
.drawable
= wndPtr
->window
;
291 /***********************************************************************
294 /* Unimplemented flags: DCX_LOCKWINDOWUPDATE
296 HDC
GetDCEx( HWND hwnd
, HRGN hrgnClip
, DWORD flags
)
307 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
311 if (flags
& DCX_USESTYLE
)
313 /* Set the flags according to the window style. */
314 /* Not sure if this is the real meaning of the DCX_USESTYLE flag... */
315 flags
&= ~(DCX_CACHE
| DCX_CLIPCHILDREN
|
316 DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
319 if (!(WIN_CLASS_STYLE(wndPtr
) & (CS_OWNDC
| CS_CLASSDC
)))
321 if (WIN_CLASS_STYLE(wndPtr
) & CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
322 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
) flags
|= DCX_CLIPCHILDREN
;
323 if (wndPtr
->dwStyle
& WS_CLIPSIBLINGS
) flags
|= DCX_CLIPSIBLINGS
;
325 else flags
|= DCX_CACHE
;
328 /* Can only use PARENTCLIP on child windows */
329 if (!wndPtr
|| !(wndPtr
->dwStyle
& WS_CHILD
)) flags
&= ~DCX_PARENTCLIP
;
331 /* Whole window DC implies using cache DC and not clipping children */
332 if (flags
& DCX_WINDOW
) flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
334 if (flags
& DCX_CACHE
)
336 for (hdce
= firstDCE
; (hdce
); hdce
= dce
->hNext
)
338 if (!(dce
= (DCE
*) USER_HEAP_ADDR( hdce
))) return 0;
339 if ((dce
->type
== DCE_CACHE_DC
) && (!dce
->inUse
)) break;
342 else hdce
= wndPtr
->hdce
;
345 dce
= (DCE
*) USER_HEAP_ADDR( hdce
);
346 dce
->hwndCurrent
= hwnd
;
352 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
354 DCE_SetDrawable( wndPtr
, dc
, flags
);
357 if (flags
& DCX_PARENTCLIP
) /* Get a VisRgn for the parent */
359 WND
*parentPtr
= WIN_FindWndPtr( wndPtr
->hwndParent
);
360 DWORD newflags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
362 if (parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
363 newflags
|= DCX_CLIPSIBLINGS
;
364 hrgnVisible
= DCE_GetVisRgn( wndPtr
->hwndParent
, newflags
);
365 if (flags
& DCX_WINDOW
)
366 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
367 -wndPtr
->rectWindow
.top
);
368 else OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
369 -wndPtr
->rectClient
.top
);
371 else hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
373 else /* Get a VisRgn for the whole screen */
375 hrgnVisible
= CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN
,
376 SYSMETRICS_CYSCREEN
);
379 /* Intersect VisRgn with the given region */
381 if ((flags
& DCX_INTERSECTRGN
) || (flags
& DCX_EXCLUDERGN
))
383 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
386 CombineRgn( hrgn
, hrgnVisible
, hrgnClip
,
387 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
388 DeleteObject( hrgnVisible
);
392 SelectVisRgn( hdc
, hrgnVisible
);
393 DeleteObject( hrgnVisible
);
395 dprintf_dc(stddeb
, "GetDCEx(%d,%d,0x%lx): returning %d\n",
396 hwnd
, hrgnClip
, flags
, hdc
);
401 /***********************************************************************
404 HDC
GetDC( HWND hwnd
)
406 return GetDCEx( hwnd
, 0, DCX_USESTYLE
);
410 /***********************************************************************
411 * GetWindowDC (USER.67)
413 HDC
GetWindowDC( HWND hwnd
)
415 int flags
= DCX_CACHE
| DCX_WINDOW
;
419 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
420 /* if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; */
421 if (wndPtr
->dwStyle
& WS_CLIPSIBLINGS
) flags
|= DCX_CLIPSIBLINGS
;
423 return GetDCEx( hwnd
, 0, flags
);
427 /***********************************************************************
428 * ReleaseDC (USER.68)
430 int ReleaseDC( HWND hwnd
, HDC hdc
)
435 dprintf_dc(stddeb
, "ReleaseDC: %d %d\n", hwnd
, hdc
);
437 for (hdce
= firstDCE
; (hdce
); hdce
= dce
->hNext
)
439 if (!(dce
= (DCE
*) USER_HEAP_ADDR( hdce
))) return 0;
440 if (dce
->inUse
&& (dce
->hdc
== hdc
)) break;
444 if (dce
->type
== DCE_CACHE_DC
)
446 SetDCState( dce
->hdc
, defaultDCstate
);