Release 960521
[wine.git] / windows / dce.c
blob572843425530067afd67dc6289e7bd78027ada9b
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( 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 );
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_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;
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_LIN_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, RECT16 *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 SetRectEmpty16( lprect ); /* Clip everything */
108 return FALSE;
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 */
119 return FALSE;
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 );
132 return TRUE;
136 /***********************************************************************
137 * DCE_ClipWindows
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 )
148 HRGN hrgnNew;
150 if (!pWndStart) return hrgn;
151 if (!(hrgnNew = CreateRectRgn( 0, 0, 0, 0 )))
153 DeleteObject( hrgn );
154 return 0;
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 );
169 return 0;
171 return hrgn;
175 /***********************************************************************
176 * DCE_GetVisRgn
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 )
184 RECT16 rect;
185 HRGN hrgn;
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 );
208 if (!hrgn) return 0;
211 /* Clip siblings placed above this window */
213 if (flags & DCX_WINDOW)
215 xoffset = -wndPtr->rectWindow.left;
216 yoffset = -wndPtr->rectWindow.top;
218 else
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 );
227 if (!hrgn) return 0;
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 );
239 if (!hrgn) return 0;
241 return hrgn;
245 /***********************************************************************
246 * DCE_SetDrawable
248 * Set the drawable, origin and dimensions for the DC associated to
249 * a given window.
251 static void DCE_SetDrawable( WND *wndPtr, DC *dc, WORD flags )
253 if (!wndPtr) /* Get a DC for the whole screen */
255 dc->w.DCOrgX = 0;
256 dc->w.DCOrgY = 0;
257 dc->u.x.drawable = rootWindow;
258 XSetSubwindowMode( display, dc->u.x.gc, IncludeInferiors );
260 else
262 if (flags & DCX_WINDOW)
264 dc->w.DCOrgX = wndPtr->rectWindow.left;
265 dc->w.DCOrgY = wndPtr->rectWindow.top;
267 else
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 /***********************************************************************
286 * GetDCEx (USER.359)
288 /* Unimplemented flags: DCX_LOCKWINDOWUPDATE
290 HDC GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
292 HANDLE hdce;
293 HRGN hrgnVisible;
294 HDC hdc = 0;
295 DCE * dce;
296 DC * dc;
297 WND * wndPtr;
299 if (hwnd)
301 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
303 else wndPtr = NULL;
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);
311 if (wndPtr)
313 if (!(wndPtr->class->style & (CS_OWNDC | CS_CLASSDC)))
314 flags |= DCX_CACHE;
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;
338 if (!hdce) return 0;
339 dce = (DCE *) USER_HEAP_LIN_ADDR( hdce );
340 dce->hwndCurrent = hwnd;
341 dce->inUse = TRUE;
342 hdc = dce->hdc;
344 /* Initialize DC */
346 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
348 DCE_SetDrawable( wndPtr, dc, flags );
349 if (hwnd)
351 if (flags & DCX_PARENTCLIP) /* Get a VisRgn for the parent */
353 WND *parentPtr = wndPtr->parent;
354 DWORD newflags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
355 DCX_WINDOW);
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);
385 return hdc;
389 /***********************************************************************
390 * GetDC (USER.66)
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;
404 if (hwnd)
406 WND * wndPtr;
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 )
420 HANDLE hdce;
421 DCE * dce = NULL;
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;
430 if (!hdce) return 0;
432 if (dce->type == DCE_CACHE_DC)
434 SetDCState( dce->hdc, defaultDCstate );
435 dce->inUse = FALSE;
437 return 1;