4 * Copyright 1993 Alexandre Julliard
7 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
14 #include "sysmetrics.h"
16 /* #define DEBUG_DC /* */
17 /* #undef DEBUG_DC /* */
21 #define NB_DCE 5 /* Number of DCEs created at startup */
23 extern Display * display;
25 static HANDLE firstDCE = 0;
26 static HDC defaultDCstate = 0;
29 /***********************************************************************
34 HANDLE DCE_AllocDCE( DCE_TYPE type )
37 HANDLE handle = USER_HEAP_ALLOC( GMEM_MOVEABLE, sizeof(DCE) );
38 if (!handle) return 0;
39 dce = (DCE *) USER_HEAP_ADDR( handle );
40 if (!(dce->hdc = CreateDC( "DISPLAY", NULL, NULL, NULL )))
42 USER_HEAP_FREE( handle );
47 dce->inUse = (type != DCE_CACHE_DC);
50 dce->hNext = firstDCE;
56 /***********************************************************************
59 void DCE_FreeDCE( HANDLE hdce )
62 HANDLE *handle = &firstDCE;
64 if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return;
65 while (*handle && (*handle != hdce))
67 DCE * prev = (DCE *) USER_HEAP_ADDR( *handle );
68 handle = &prev->hNext;
70 if (*handle == hdce) *handle = dce->hNext;
72 USER_HEAP_FREE( hdce );
76 /***********************************************************************
85 for (i = 0; i < NB_DCE; i++)
87 if (!(handle = DCE_AllocDCE( DCE_CACHE_DC ))) return;
88 dce = (DCE *) USER_HEAP_ADDR( handle );
89 if (!defaultDCstate) defaultDCstate = GetDCState( dce->hdc );
94 /***********************************************************************
97 * Calc the visible rectangle of a window, i.e. the client or
98 * window area clipped by the client area of all ancestors.
99 * Return FALSE if the visible region is empty.
101 static BOOL DCE_GetVisRect( WND *wndPtr, BOOL clientArea, RECT *lprect )
103 int xoffset, yoffset;
105 *lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
106 xoffset = lprect->left;
107 yoffset = lprect->top;
109 if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
111 SetRectEmpty( lprect ); /* Clip everything */
115 while (wndPtr->hwndParent)
117 WND *parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
118 if (!(parentPtr->dwStyle & WS_VISIBLE) ||
119 (parentPtr->flags & WIN_NO_REDRAW) ||
120 (parentPtr->dwStyle & WS_ICONIC))
122 SetRectEmpty( lprect ); /* Clip everything */
125 xoffset += parentPtr->rectClient.left;
126 yoffset += parentPtr->rectClient.top;
127 OffsetRect( lprect, parentPtr->rectClient.left,
128 parentPtr->rectClient.top );
130 /* Warning!! we assume that IntersectRect() handles the case */
131 /* where the destination is the same as one of the sources. */
132 if (!IntersectRect( lprect, lprect, &parentPtr->rectClient ))
133 return FALSE; /* Visible rectangle is empty */
136 OffsetRect( lprect, -xoffset, -yoffset );
141 /***********************************************************************
144 * Go through the linked list of windows from hwndStart to hwndEnd,
145 * removing from the given region the rectangle of each window offset
146 * by a given amount. The new region is returned, and the original one
147 * is destroyed. Used to implement DCX_CLIPSIBLINGS and
148 * DCX_CLIPCHILDREN styles.
150 static HRGN DCE_ClipWindows( HWND hwndStart, HWND hwndEnd,
151 HRGN hrgn, int xoffset, int yoffset )
153 HRGN hrgnTmp, hrgnNew;
156 if (!hwndStart) return hrgn;
157 for (; hwndStart != hwndEnd; hwndStart = wndPtr->hwndNext)
159 hrgnTmp = hrgnNew = 0;
160 wndPtr = WIN_FindWndPtr( hwndStart );
161 if (!(wndPtr->dwStyle & WS_VISIBLE)) continue;
162 if (!(hrgnTmp = CreateRectRgn( 0, 0, 0, 0 ))) break;
163 if (!(hrgnNew = CreateRectRgn( wndPtr->rectWindow.left + xoffset,
164 wndPtr->rectWindow.top + yoffset,
165 wndPtr->rectWindow.right + xoffset,
166 wndPtr->rectWindow.bottom + yoffset )))
168 if (!CombineRgn( hrgnTmp, hrgn, hrgnNew, RGN_DIFF )) break;
169 DeleteObject( hrgn );
170 DeleteObject( hrgnNew );
173 if (hwndStart != hwndEnd) /* something went wrong */
175 if (hrgnTmp) DeleteObject( hrgnTmp );
176 if (hrgnNew) DeleteObject( hrgnNew );
177 if (hrgn) DeleteObject( hrgn );
184 /***********************************************************************
187 * Return the visible region of a window, i.e. the client or window area
188 * clipped by the client area of all ancestors, and then optionally
189 * by siblings and children.
191 static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags )
195 int xoffset, yoffset;
196 WND *wndPtr = WIN_FindWndPtr( hwnd );
198 /* Get visible rectangle and create a region with it */
200 if (!DCE_GetVisRect( wndPtr, !(flags & DCX_WINDOW), &rect ))
202 return CreateRectRgn( 0, 0, 0, 0 ); /* Visible region is empty */
204 if (!(hrgn = CreateRectRgnIndirect( &rect ))) return 0;
206 /* Clip all children from the visible region */
208 if (flags & DCX_CLIPCHILDREN)
210 if (flags & DCX_WINDOW)
212 xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
213 yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
215 else xoffset = yoffset = 0;
216 hrgn = DCE_ClipWindows( wndPtr->hwndChild, 0, hrgn, xoffset, yoffset );
220 /* Clip siblings placed above this window */
222 if (flags & DCX_WINDOW)
224 xoffset = -wndPtr->rectWindow.left;
225 yoffset = -wndPtr->rectWindow.top;
229 xoffset = -wndPtr->rectClient.left;
230 yoffset = -wndPtr->rectClient.top;
232 if (flags & DCX_CLIPSIBLINGS)
234 hrgn = DCE_ClipWindows( GetWindow( wndPtr->hwndParent, GW_CHILD ),
235 hwnd, hrgn, xoffset, yoffset );
239 /* Clip siblings of all ancestors that have the WS_CLIPSIBLINGS style */
241 while (wndPtr->dwStyle & WS_CHILD)
243 hwnd = wndPtr->hwndParent;
244 wndPtr = WIN_FindWndPtr( hwnd );
245 xoffset -= wndPtr->rectClient.left;
246 yoffset -= wndPtr->rectClient.top;
247 hrgn = DCE_ClipWindows( GetWindow( wndPtr->hwndParent, GW_CHILD ),
248 hwnd, hrgn, xoffset, yoffset );
255 /***********************************************************************
258 * Set the drawable, origin and dimensions for the DC associated to
261 static void DCE_SetDrawable( WND *wndPtr, DC *dc, WORD flags )
263 if (!wndPtr) /* Get a DC for the whole screen */
267 dc->w.DCSizeX = SYSMETRICS_CXSCREEN;
268 dc->w.DCSizeY = SYSMETRICS_CYSCREEN;
269 dc->u.x.drawable = rootWindow;
270 XSetSubwindowMode( display, dc->u.x.gc, IncludeInferiors );
274 if (flags & DCX_WINDOW)
276 dc->w.DCOrgX = wndPtr->rectWindow.left;
277 dc->w.DCOrgY = wndPtr->rectWindow.top;
278 dc->w.DCSizeX = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
279 dc->w.DCSizeY = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
283 dc->w.DCOrgX = wndPtr->rectClient.left;
284 dc->w.DCOrgY = wndPtr->rectClient.top;
285 dc->w.DCSizeX = wndPtr->rectClient.right - wndPtr->rectClient.left;
286 dc->w.DCSizeY = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
288 while (!wndPtr->window)
290 wndPtr = WIN_FindWndPtr( wndPtr->hwndParent );
291 dc->w.DCOrgX += wndPtr->rectClient.left;
292 dc->w.DCOrgY += wndPtr->rectClient.top;
294 dc->w.DCOrgX -= wndPtr->rectWindow.left;
295 dc->w.DCOrgY -= wndPtr->rectWindow.top;
296 dc->u.x.drawable = wndPtr->window;
301 /***********************************************************************
304 /* Unimplemented flags: DCX_LOCKWINDOWUPDATE
306 HDC GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
317 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
321 if (flags & DCX_USESTYLE)
323 /* Set the flags according to the window style. */
324 /* Not sure if this is the real meaning of the DCX_USESTYLE flag... */
325 flags &= ~(DCX_CACHE | DCX_CLIPCHILDREN |
326 DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
329 if (!(WIN_CLASS_STYLE(wndPtr) & (CS_OWNDC | CS_CLASSDC)))
331 if (WIN_CLASS_STYLE(wndPtr) & CS_PARENTDC) flags |= DCX_PARENTCLIP;
332 if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN;
333 if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
335 else flags |= DCX_CACHE;
338 /* Can only use PARENTCLIP on child windows */
339 if (!wndPtr || !(wndPtr->dwStyle & WS_CHILD)) flags &= ~DCX_PARENTCLIP;
341 /* Whole window DC implies children are not clipped */
342 if (flags & DCX_WINDOW) flags &= ~DCX_CLIPCHILDREN;
344 if (flags & DCX_CACHE)
346 for (hdce = firstDCE; (hdce); hdce = dce->hNext)
348 if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return 0;
349 if ((dce->type == DCE_CACHE_DC) && (!dce->inUse)) break;
352 else hdce = wndPtr->hdce;
355 dce = (DCE *) USER_HEAP_ADDR( hdce );
356 dce->hwndCurrent = hwnd;
362 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
364 DCE_SetDrawable( wndPtr, dc, flags );
367 if (flags & DCX_PARENTCLIP) /* Get a VisRgn for the parent */
369 WND *parentPtr = WIN_FindWndPtr( wndPtr->hwndParent );
370 DWORD newflags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
372 if (parentPtr->dwStyle & WS_CLIPSIBLINGS)
373 newflags |= DCX_CLIPSIBLINGS;
374 hrgnVisible = DCE_GetVisRgn( wndPtr->hwndParent, newflags );
375 if (flags & DCX_WINDOW)
376 OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left,
377 -wndPtr->rectWindow.top );
378 else OffsetRgn( hrgnVisible, -wndPtr->rectClient.left,
379 -wndPtr->rectClient.top );
381 else hrgnVisible = DCE_GetVisRgn( hwnd, flags );
383 else /* Get a VisRgn for the whole screen */
385 hrgnVisible = CreateRectRgn( 0, 0, SYSMETRICS_CXSCREEN,
386 SYSMETRICS_CYSCREEN);
389 /* Intersect VisRgn with the given region */
391 if ((flags & DCX_INTERSECTRGN) || (flags & DCX_EXCLUDERGN))
393 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
396 CombineRgn( hrgn, hrgnVisible, hrgnClip,
397 (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
398 DeleteObject( hrgnVisible );
402 SelectVisRgn( hdc, hrgnVisible );
403 DeleteObject( hrgnVisible );
405 dprintf_dc(stddeb, "GetDCEx(%d,%d,0x%x): returning %d\n",
406 hwnd, hrgnClip, flags, hdc);
411 /***********************************************************************
414 HDC GetDC( HWND hwnd )
416 return GetDCEx( hwnd, 0, DCX_USESTYLE );
420 /***********************************************************************
421 * GetWindowDC (USER.67)
423 HDC GetWindowDC( HWND hwnd )
425 int flags = DCX_CACHE | DCX_WINDOW;
429 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
430 /* if (wndPtr->dwStyle & WS_CLIPCHILDREN) flags |= DCX_CLIPCHILDREN; */
431 if (wndPtr->dwStyle & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
433 return GetDCEx( hwnd, 0, flags );
437 /***********************************************************************
438 * ReleaseDC (USER.68)
440 int ReleaseDC( HWND hwnd, HDC hdc )
445 dprintf_dc(stddeb, "ReleaseDC: %d %d\n", hwnd, hdc );
447 for (hdce = firstDCE; (hdce); hdce = dce->hNext)
449 if (!(dce = (DCE *) USER_HEAP_ADDR( hdce ))) return 0;
450 if (dce->inUse && (dce->hdc == hdc)) break;
454 if (dce->type == DCE_CACHE_DC)
456 SetDCState( dce->hdc, defaultDCstate );