Release 950216
[wine.git] / windows / dce.c
blob3148ba2a5822d656bf927e219a552320cf14e588
1 /*
2 * USER DCE functions
4 * Copyright 1993 Alexandre Julliard
6 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
7 */
9 #include "dce.h"
10 #include "class.h"
11 #include "win.h"
12 #include "gdi.h"
13 #include "user.h"
14 #include "sysmetrics.h"
15 #include "stddebug.h"
16 /* #define DEBUG_DC */
17 #include "debug.h"
19 #define NB_DCE 5 /* Number of DCEs created at startup */
21 static HANDLE firstDCE = 0;
22 static HDC defaultDCstate = 0;
25 /***********************************************************************
26 * DCE_AllocDCE
28 * Allocate a new DCE.
30 HANDLE DCE_AllocDCE( DCE_TYPE type )
32 DCE * dce;
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 );
39 return 0;
41 dce->hwndCurrent = 0;
42 dce->type = type;
43 dce->inUse = (type != DCE_CACHE_DC);
44 dce->xOrigin = 0;
45 dce->yOrigin = 0;
46 dce->hNext = firstDCE;
47 firstDCE = handle;
48 return handle;
52 /***********************************************************************
53 * DCE_FreeDCE
55 void DCE_FreeDCE( HANDLE hdce )
57 DCE * dce;
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;
67 DeleteDC( dce->hdc );
68 USER_HEAP_FREE( hdce );
72 /***********************************************************************
73 * DCE_Init
75 void DCE_Init()
77 int i;
78 HANDLE handle;
79 DCE * dce;
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 /***********************************************************************
91 * DCE_GetVisRect
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 )
99 int xoffset, yoffset;
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 */
108 return FALSE;
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 */
119 return FALSE;
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 */
130 wndPtr = parentPtr;
132 OffsetRect( lprect, -xoffset, -yoffset );
133 return TRUE;
137 /***********************************************************************
138 * DCE_ClipWindows
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;
150 WND *wndPtr;
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 )))
163 break;
164 if (!CombineRgn( hrgnTmp, hrgn, hrgnNew, RGN_DIFF )) break;
165 DeleteObject( hrgn );
166 DeleteObject( hrgnNew );
167 hrgn = hrgnTmp;
169 if (hwndStart != hwndEnd) /* something went wrong */
171 if (hrgnTmp) DeleteObject( hrgnTmp );
172 if (hrgnNew) DeleteObject( hrgnNew );
173 if (hrgn) DeleteObject( hrgn );
174 return 0;
176 return hrgn;
180 /***********************************************************************
181 * DCE_GetVisRgn
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 )
189 RECT rect;
190 HRGN hrgn;
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 );
213 if (!hrgn) return 0;
216 /* Clip siblings placed above this window */
218 if (flags & DCX_WINDOW)
220 xoffset = -wndPtr->rectWindow.left;
221 yoffset = -wndPtr->rectWindow.top;
223 else
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 );
232 if (!hrgn) return 0;
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 );
245 if (!hrgn) return 0;
247 return hrgn;
251 /***********************************************************************
252 * DCE_SetDrawable
254 * Set the drawable, origin and dimensions for the DC associated to
255 * a given window.
257 static void DCE_SetDrawable( WND *wndPtr, DC *dc, WORD flags )
259 if (!wndPtr) /* Get a DC for the whole screen */
261 dc->w.DCOrgX = 0;
262 dc->w.DCOrgY = 0;
263 dc->u.x.drawable = rootWindow;
264 XSetSubwindowMode( display, dc->u.x.gc, IncludeInferiors );
266 else
268 if (flags & DCX_WINDOW)
270 dc->w.DCOrgX = wndPtr->rectWindow.left;
271 dc->w.DCOrgY = wndPtr->rectWindow.top;
273 else
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 /***********************************************************************
292 * GetDCEx (USER.359)
294 /* Unimplemented flags: DCX_LOCKWINDOWUPDATE
296 HDC GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
298 HANDLE hdce;
299 HRGN hrgnVisible;
300 HDC hdc = 0;
301 DCE * dce;
302 DC * dc;
303 WND * wndPtr;
305 if (hwnd)
307 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
309 else wndPtr = NULL;
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);
317 if (wndPtr)
319 if (!(WIN_CLASS_STYLE(wndPtr) & (CS_OWNDC | CS_CLASSDC)))
320 flags |= DCX_CACHE;
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;
344 if (!hdce) return 0;
345 dce = (DCE *) USER_HEAP_ADDR( hdce );
346 dce->hwndCurrent = hwnd;
347 dce->inUse = TRUE;
348 hdc = dce->hdc;
350 /* Initialize DC */
352 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
354 DCE_SetDrawable( wndPtr, dc, flags );
355 if (hwnd)
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 |
361 DCX_WINDOW);
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 );
384 if (hrgn)
386 CombineRgn( hrgn, hrgnVisible, hrgnClip,
387 (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
388 DeleteObject( hrgnVisible );
389 hrgnVisible = hrgn;
392 SelectVisRgn( hdc, hrgnVisible );
393 DeleteObject( hrgnVisible );
395 dprintf_dc(stddeb, "GetDCEx(%d,%d,0x%lx): returning %d\n",
396 hwnd, hrgnClip, flags, hdc);
397 return hdc;
401 /***********************************************************************
402 * GetDC (USER.66)
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;
416 if (hwnd)
418 WND * wndPtr;
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 )
432 HANDLE hdce;
433 DCE * dce = NULL;
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;
442 if (!hdce) return 0;
444 if (dce->type == DCE_CACHE_DC)
446 SetDCState( dce->hdc, defaultDCstate );
447 dce->inUse = FALSE;
449 return 1;