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( sizeof(DCE
) );
34 if (!handle
) return 0;
35 dce
= (DCE
*) USER_HEAP_LIN_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_LIN_ADDR( hdce
))) return;
61 while (*handle
&& (*handle
!= hdce
))
63 DCE
* prev
= (DCE
*) USER_HEAP_LIN_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_LIN_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
, RECT16
*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 SetRectEmpty16( lprect
); /* Clip everything */
111 while (wndPtr
->parent
)
113 wndPtr
= wndPtr
->parent
;
114 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) ||
115 (wndPtr
->flags
& WIN_NO_REDRAW
) ||
116 (wndPtr
->dwStyle
& WS_ICONIC
))
118 SetRectEmpty16( lprect
); /* Clip everything */
121 xoffset
+= wndPtr
->rectClient
.left
;
122 yoffset
+= wndPtr
->rectClient
.top
;
123 OffsetRect16( lprect
, wndPtr
->rectClient
.left
,
124 wndPtr
->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 (!IntersectRect16( lprect
, lprect
, &wndPtr
->rectClient
))
129 return FALSE
; /* Visible rectangle is empty */
131 OffsetRect16( lprect
, -xoffset
, -yoffset
);
136 /***********************************************************************
139 * Go through the linked list of windows from hwndStart to hwndEnd,
140 * removing from the given region the rectangle of each window offset
141 * by a given amount. The new region is returned, and the original one
142 * is destroyed. Used to implement DCX_CLIPSIBLINGS and
143 * DCX_CLIPCHILDREN styles.
145 static HRGN
DCE_ClipWindows( WND
*pWndStart
, WND
*pWndEnd
,
146 HRGN hrgn
, int xoffset
, int yoffset
)
150 if (!pWndStart
) return hrgn
;
151 if (!(hrgnNew
= CreateRectRgn( 0, 0, 0, 0 )))
153 DeleteObject( hrgn
);
156 for (; pWndStart
!= pWndEnd
; pWndStart
= pWndStart
->next
)
158 if (!(pWndStart
->dwStyle
& WS_VISIBLE
)) continue;
159 SetRectRgn( hrgnNew
, pWndStart
->rectWindow
.left
+ xoffset
,
160 pWndStart
->rectWindow
.top
+ yoffset
,
161 pWndStart
->rectWindow
.right
+ xoffset
,
162 pWndStart
->rectWindow
.bottom
+ yoffset
);
163 if (!CombineRgn( hrgn
, hrgn
, hrgnNew
, RGN_DIFF
)) break;
165 DeleteObject( hrgnNew
);
166 if (pWndStart
!= pWndEnd
) /* something went wrong */
168 DeleteObject( hrgn
);
175 /***********************************************************************
178 * Return the visible region of a window, i.e. the client or window area
179 * clipped by the client area of all ancestors, and then optionally
180 * by siblings and children.
182 HRGN
DCE_GetVisRgn( HWND hwnd
, WORD flags
)
186 int xoffset
, yoffset
;
187 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
189 /* Get visible rectangle and create a region with it */
191 if (!DCE_GetVisRect( wndPtr
, !(flags
& DCX_WINDOW
), &rect
))
193 return CreateRectRgn( 0, 0, 0, 0 ); /* Visible region is empty */
195 if (!(hrgn
= CreateRectRgnIndirect16( &rect
))) return 0;
197 /* Clip all children from the visible region */
199 if (flags
& DCX_CLIPCHILDREN
)
201 if (flags
& DCX_WINDOW
)
203 xoffset
= wndPtr
->rectClient
.left
- wndPtr
->rectWindow
.left
;
204 yoffset
= wndPtr
->rectClient
.top
- wndPtr
->rectWindow
.top
;
206 else xoffset
= yoffset
= 0;
207 hrgn
= DCE_ClipWindows( wndPtr
->child
, NULL
, hrgn
, xoffset
, yoffset
);
211 /* Clip siblings placed above this window */
213 if (flags
& DCX_WINDOW
)
215 xoffset
= -wndPtr
->rectWindow
.left
;
216 yoffset
= -wndPtr
->rectWindow
.top
;
220 xoffset
= -wndPtr
->rectClient
.left
;
221 yoffset
= -wndPtr
->rectClient
.top
;
223 if (flags
& DCX_CLIPSIBLINGS
)
225 hrgn
= DCE_ClipWindows( wndPtr
->parent
? wndPtr
->parent
->child
: NULL
,
226 wndPtr
, hrgn
, xoffset
, yoffset
);
230 /* Clip siblings of all ancestors that have the WS_CLIPSIBLINGS style */
232 while (wndPtr
->dwStyle
& WS_CHILD
)
234 wndPtr
= wndPtr
->parent
;
235 xoffset
-= wndPtr
->rectClient
.left
;
236 yoffset
-= wndPtr
->rectClient
.top
;
237 hrgn
= DCE_ClipWindows( wndPtr
->parent
->child
, wndPtr
,
238 hrgn
, xoffset
, yoffset
);
245 /***********************************************************************
248 * Set the drawable, origin and dimensions for the DC associated to
251 static void DCE_SetDrawable( WND
*wndPtr
, DC
*dc
, WORD flags
)
253 if (!wndPtr
) /* Get a DC for the whole screen */
257 dc
->u
.x
.drawable
= rootWindow
;
258 XSetSubwindowMode( display
, dc
->u
.x
.gc
, IncludeInferiors
);
262 if (flags
& DCX_WINDOW
)
264 dc
->w
.DCOrgX
= wndPtr
->rectWindow
.left
;
265 dc
->w
.DCOrgY
= wndPtr
->rectWindow
.top
;
269 dc
->w
.DCOrgX
= wndPtr
->rectClient
.left
;
270 dc
->w
.DCOrgY
= wndPtr
->rectClient
.top
;
272 while (!wndPtr
->window
)
274 wndPtr
= wndPtr
->parent
;
275 dc
->w
.DCOrgX
+= wndPtr
->rectClient
.left
;
276 dc
->w
.DCOrgY
+= wndPtr
->rectClient
.top
;
278 dc
->w
.DCOrgX
-= wndPtr
->rectWindow
.left
;
279 dc
->w
.DCOrgY
-= wndPtr
->rectWindow
.top
;
280 dc
->u
.x
.drawable
= wndPtr
->window
;
285 /***********************************************************************
288 /* Unimplemented flags: DCX_LOCKWINDOWUPDATE
290 HDC
GetDCEx( HWND hwnd
, HRGN hrgnClip
, DWORD flags
)
301 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
305 if (flags
& DCX_USESTYLE
)
307 /* Set the flags according to the window style. */
308 /* Not sure if this is the real meaning of the DCX_USESTYLE flag... */
309 flags
&= ~(DCX_CACHE
| DCX_CLIPCHILDREN
|
310 DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
313 if (!(wndPtr
->class->style
& (CS_OWNDC
| CS_CLASSDC
)))
315 if (wndPtr
->class->style
& CS_PARENTDC
) flags
|= DCX_PARENTCLIP
;
316 if (wndPtr
->dwStyle
& WS_CLIPCHILDREN
) flags
|= DCX_CLIPCHILDREN
;
317 if (wndPtr
->dwStyle
& WS_CLIPSIBLINGS
) flags
|= DCX_CLIPSIBLINGS
;
319 else flags
|= DCX_CACHE
;
322 /* Can only use PARENTCLIP on child windows */
323 if (!wndPtr
|| !(wndPtr
->dwStyle
& WS_CHILD
)) flags
&= ~DCX_PARENTCLIP
;
325 /* Whole window DC implies using cache DC and not clipping children */
326 if (flags
& DCX_WINDOW
) flags
= (flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
328 if (flags
& DCX_CACHE
)
330 for (hdce
= firstDCE
; (hdce
); hdce
= dce
->hNext
)
332 if (!(dce
= (DCE
*) USER_HEAP_LIN_ADDR( hdce
))) return 0;
333 if ((dce
->type
== DCE_CACHE_DC
) && (!dce
->inUse
)) break;
336 else hdce
= wndPtr
->hdce
;
339 dce
= (DCE
*) USER_HEAP_LIN_ADDR( hdce
);
340 dce
->hwndCurrent
= hwnd
;
346 if (!(dc
= (DC
*) GDI_GetObjPtr( hdc
, DC_MAGIC
))) return 0;
348 DCE_SetDrawable( wndPtr
, dc
, flags
);
351 if (flags
& DCX_PARENTCLIP
) /* Get a VisRgn for the parent */
353 WND
*parentPtr
= wndPtr
->parent
;
354 DWORD newflags
= flags
& ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
356 if (parentPtr
->dwStyle
& WS_CLIPSIBLINGS
)
357 newflags
|= DCX_CLIPSIBLINGS
;
358 hrgnVisible
= DCE_GetVisRgn( parentPtr
->hwndSelf
, newflags
);
359 if (flags
& DCX_WINDOW
)
360 OffsetRgn( hrgnVisible
, -wndPtr
->rectWindow
.left
,
361 -wndPtr
->rectWindow
.top
);
362 else OffsetRgn( hrgnVisible
, -wndPtr
->rectClient
.left
,
363 -wndPtr
->rectClient
.top
);
365 else hrgnVisible
= DCE_GetVisRgn( hwnd
, flags
);
367 else /* Get a VisRgn for the whole screen */
369 hrgnVisible
= CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN
,
370 SYSMETRICS_CYSCREEN
);
373 /* Intersect VisRgn with the given region */
375 if ((flags
& DCX_INTERSECTRGN
) || (flags
& DCX_EXCLUDERGN
))
377 CombineRgn( hrgnVisible
, hrgnVisible
, hrgnClip
,
378 (flags
& DCX_INTERSECTRGN
) ? RGN_AND
: RGN_DIFF
);
380 SelectVisRgn( hdc
, hrgnVisible
);
381 DeleteObject( hrgnVisible
);
383 dprintf_dc(stddeb
, "GetDCEx(%04x,%04x,0x%lx): returning %04x\n",
384 hwnd
, hrgnClip
, flags
, hdc
);
389 /***********************************************************************
392 HDC
GetDC( HWND hwnd
)
394 return GetDCEx( hwnd
, 0, DCX_USESTYLE
);
398 /***********************************************************************
399 * GetWindowDC (USER.67)
401 HDC
GetWindowDC( HWND hwnd
)
403 int flags
= DCX_CACHE
| DCX_WINDOW
;
407 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return 0;
408 /* if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; */
409 if (wndPtr
->dwStyle
& WS_CLIPSIBLINGS
) flags
|= DCX_CLIPSIBLINGS
;
411 return GetDCEx( hwnd
, 0, flags
);
415 /***********************************************************************
416 * ReleaseDC (USER.68)
418 int ReleaseDC( HWND hwnd
, HDC hdc
)
423 dprintf_dc(stddeb
, "ReleaseDC: %04x %04x\n", hwnd
, hdc
);
425 for (hdce
= firstDCE
; (hdce
); hdce
= dce
->hNext
)
427 if (!(dce
= (DCE
*) USER_HEAP_LIN_ADDR( hdce
))) return 0;
428 if (dce
->inUse
&& (dce
->hdc
== hdc
)) break;
432 if (dce
->type
== DCE_CACHE_DC
)
434 SetDCState( dce
->hdc
, defaultDCstate
);