Changes for multiple window support
[reactos.git] / reactos / subsys / win32k / ntuser / windc.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: windc.c,v 1.15 2003/07/17 07:49:15 gvg Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <win32k/region.h>
35 #include <win32k/userobj.h>
36 #include <include/class.h>
37 #include <include/error.h>
38 #include <include/winsta.h>
39 #include <include/msgqueue.h>
40 #include <include/window.h>
41 #include <include/rect.h>
42 #include <include/dce.h>
43 #include <include/vis.h>
44
45 #define NDEBUG
46 #include <debug.h>
47
48 /* GLOBALS *******************************************************************/
49
50 static PDCE FirstDce = NULL;
51
52 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
53 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
54
55 /* FUNCTIONS *****************************************************************/
56
57 HRGN STDCALL
58 DceGetVisRgn(HWND hWnd, ULONG Flags, HWND hWndChild, ULONG CFlags)
59 {
60 PWINDOW_OBJECT Window;
61 PWINDOW_OBJECT Child;
62 HRGN VisRgn;
63 HRGN VisChild;
64 HRGN ChildRect;
65 HRGN ParentRect;
66
67 Window = W32kGetWindowObject(hWnd);
68
69 if (NULL == Window)
70 {
71 return NULL;
72 }
73
74 VisRgn = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop, Window,
75 0 == (Flags & DCX_WINDOW),
76 0 != (Flags & DCX_CLIPCHILDREN),
77 0 != (Flags & DCX_CLIPSIBLINGS));
78 if (NULL != hWndChild && 0 != (CFlags & DCX_CLIPCHILDREN))
79 {
80 /* We need to filter out the child windows of hWndChild */
81 Child = W32kGetWindowObject(hWnd);
82 if (NULL != Child)
83 {
84 if (! IsListEmpty(&Child->ChildrenListHead))
85 {
86 /* Compute the visible region of the child */
87 VisChild = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
88 Child, FALSE, TRUE, FALSE);
89 /* If the child doesn't obscure the whole window, we need to
90 extend it. First compute the difference between window and child */
91 ChildRect = UnsafeW32kCreateRectRgnIndirect(&(Child->ClientRect));
92 if (0 == (Flags & DCX_WINDOW))
93 {
94 ParentRect = UnsafeW32kCreateRectRgnIndirect(&(Window->ClientRect));
95 }
96 else
97 {
98 ParentRect = UnsafeW32kCreateRectRgnIndirect(&(Window->WindowRect));
99 }
100 W32kCombineRgn(ChildRect, ParentRect, ChildRect, RGN_DIFF);
101
102 /* Now actually extend the child by adding the difference */
103 W32kCombineRgn(VisChild, VisChild, ChildRect, RGN_OR);
104
105 /* Clip the childs children */
106 W32kCombineRgn(VisRgn, VisRgn, VisChild, RGN_AND);
107 }
108 W32kReleaseWindowObject(Child);
109 }
110 }
111
112 W32kReleaseWindowObject(Window);
113
114 return VisRgn;
115 }
116
117 INT STDCALL
118 NtUserReleaseDC(HWND hWnd, HDC hDc)
119 {
120 return 1;
121 }
122
123 HDC STDCALL
124 NtUserGetDC(HWND hWnd)
125 {
126 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
127 }
128
129 PDCE FASTCALL DceAllocDCE(HWND hWnd, DCE_TYPE Type)
130 {
131 HDCE DceHandle;
132 DCE* Dce;
133
134 DceHandle = DCEOBJ_AllocDCE();
135 Dce = DCEOBJ_LockDCE(DceHandle);
136 Dce->hDC = W32kCreateDC(L"DISPLAY", NULL, NULL, NULL);
137 Dce->hwndCurrent = hWnd;
138 Dce->hClipRgn = NULL;
139 Dce->next = FirstDce;
140 FirstDce = Dce;
141
142 if (Type != DCE_CACHE_DC)
143 {
144 Dce->DCXFlags = DCX_DCEBUSY;
145 if (hWnd != NULL)
146 {
147 PWINDOW_OBJECT WindowObject;
148
149 WindowObject = W32kGetWindowObject(hWnd);
150 if (WindowObject->Style & WS_CLIPCHILDREN)
151 {
152 Dce->DCXFlags |= DCX_CLIPCHILDREN;
153 }
154 if (WindowObject->Style & WS_CLIPSIBLINGS)
155 {
156 Dce->DCXFlags |= DCX_CLIPSIBLINGS;
157 }
158 W32kReleaseWindowObject(WindowObject);
159 }
160 }
161 else
162 {
163 Dce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY;
164 }
165
166 return(Dce);
167 }
168
169 VOID STATIC STDCALL
170 DceSetDrawable(PWINDOW_OBJECT WindowObject, HDC hDC, ULONG Flags,
171 BOOL SetClipOrigin)
172 {
173 DC *dc = DC_HandleToPtr(hDC);
174 if (WindowObject == NULL)
175 {
176 dc->w.DCOrgX = 0;
177 dc->w.DCOrgY = 0;
178 }
179 else
180 {
181 if (Flags & DCX_WINDOW)
182 {
183 dc->w.DCOrgX = WindowObject->WindowRect.left;
184 dc->w.DCOrgY = WindowObject->WindowRect.top;
185 }
186 else
187 {
188 dc->w.DCOrgX = WindowObject->ClientRect.left;
189 dc->w.DCOrgY = WindowObject->ClientRect.top;
190 }
191 /* FIXME: Offset by parent's client rectangle. */
192 }
193 DC_ReleasePtr(hDC);
194 }
195
196 HDC STDCALL
197 NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
198 {
199 PWINDOW_OBJECT Window;
200 ULONG DcxFlags;
201 DCE* Dce;
202 BOOL UpdateVisRgn = TRUE;
203 BOOL UpdateClipOrigin = FALSE;
204 HANDLE hRgnVisible = NULL;
205
206 if (NULL == hWnd)
207 {
208 Flags &= ~DCX_USESTYLE;
209 Window = NULL;
210 }
211 else if (NULL == (Window = W32kGetWindowObject(hWnd)))
212 {
213 return(0);
214 }
215
216 if (NULL == Window || NULL == Window->Dce)
217 {
218 Flags |= DCX_CACHE;
219 }
220
221
222 if (Flags & DCX_USESTYLE)
223 {
224 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
225
226 if (Window->Style & WS_CLIPSIBLINGS)
227 {
228 Flags |= DCX_CLIPSIBLINGS;
229 }
230
231 if (!(Flags & DCX_WINDOW))
232 {
233 if (Window->Class->Class.style & CS_PARENTDC)
234 {
235 Flags |= DCX_PARENTCLIP;
236 }
237
238 if (Window->Style & WS_CLIPCHILDREN &&
239 !(Window->Style & WS_MINIMIZE))
240 {
241 Flags |= DCX_CLIPCHILDREN;
242 }
243 }
244 else
245 {
246 Flags |= DCX_CACHE;
247 }
248 }
249
250 if (Flags & DCX_NOCLIPCHILDREN)
251 {
252 Flags |= DCX_CACHE;
253 Flags |= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
254 }
255
256 if (Flags & DCX_WINDOW)
257 {
258 Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
259 }
260
261 if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Window->Parent)
262 {
263 Flags &= ~DCX_PARENTCLIP;
264 }
265 else if (Flags & DCX_PARENTCLIP)
266 {
267 Flags |= DCX_CACHE;
268 if (!(Flags & (DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS)))
269 {
270 if ((Window->Style & WS_VISIBLE) &&
271 (Window->Parent->Style & WS_VISIBLE))
272 {
273 Flags &= ~DCX_CLIPCHILDREN;
274 if (Window->Parent->Style & WS_CLIPSIBLINGS)
275 {
276 Flags |= DCX_CLIPSIBLINGS;
277 }
278 }
279 }
280 }
281
282 DcxFlags = Flags & DCX_CACHECOMPAREMASK;
283
284 if (Flags & DCX_CACHE)
285 {
286 DCE* DceEmpty = NULL;
287 DCE* DceUnused = NULL;
288
289 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
290 {
291 if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
292 {
293 DceUnused = Dce;
294 if (Dce->DCXFlags & DCX_DCEEMPTY)
295 {
296 DceEmpty = Dce;
297 }
298 else if (Dce->hwndCurrent == hWnd &&
299 ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags))
300 {
301 UpdateVisRgn = FALSE;
302 UpdateClipOrigin = TRUE;
303 break;
304 }
305 }
306 }
307
308 if (Dce == NULL)
309 {
310 Dce = (DceEmpty == NULL) ? DceEmpty : DceUnused;
311 }
312
313 if (Dce == NULL)
314 {
315 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
316 }
317 }
318 else
319 {
320 Dce = Window->Dce;
321 /* FIXME: Implement this. */
322 DbgBreakPoint();
323 }
324
325 if (NULL == Dce && NULL != Window)
326 {
327 W32kReleaseWindowObject(Window);
328 return(NULL);
329 }
330
331 Dce->hwndCurrent = hWnd;
332 Dce->hClipRgn = NULL;
333 Dce->DCXFlags = DcxFlags | (Flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
334
335 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
336
337 if (UpdateVisRgn)
338 {
339 if (Flags & DCX_PARENTCLIP)
340 {
341 PWINDOW_OBJECT Parent;
342
343 Parent = Window->Parent;
344
345 if (Window->Style & WS_VISIBLE &&
346 !(Parent->Style & WS_MINIMIZE))
347 {
348 if (Parent->Style & WS_CLIPSIBLINGS)
349 {
350 DcxFlags = DCX_CLIPSIBLINGS |
351 (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
352 }
353 else
354 {
355 DcxFlags = Flags &
356 ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
357 }
358 hRgnVisible = DceGetVisRgn(Parent->Self, DcxFlags,
359 Window->Self, Flags);
360 }
361 else
362 {
363 hRgnVisible = W32kCreateRectRgn(0, 0, 0, 0);
364 }
365 }
366 else
367 {
368 if (hWnd == W32kGetDesktopWindow())
369 {
370 hRgnVisible =
371 W32kCreateRectRgn(0, 0,
372 NtUserGetSystemMetrics(SM_CXSCREEN),
373 NtUserGetSystemMetrics(SM_CYSCREEN));
374 }
375 else
376 {
377 hRgnVisible = DceGetVisRgn(hWnd, Flags, 0, 0);
378 }
379 }
380
381 Dce->DCXFlags &= ~DCX_DCEDIRTY;
382 W32kSelectVisRgn(Dce->hDC, hRgnVisible);
383 }
384
385 if (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
386 {
387 DPRINT1("FIXME.\n");
388 }
389
390 if (hRgnVisible != NULL)
391 {
392 W32kDeleteObject(hRgnVisible);
393 }
394 if (NULL != Window)
395 {
396 W32kReleaseWindowObject(Window);
397 }
398
399 return(Dce->hDC);
400 }
401
402 BOOL FASTCALL
403 DCE_InternalDelete(PDCE Dce)
404 {
405 PDCE PrevInList;
406
407 if (Dce == FirstDce)
408 {
409 FirstDce = Dce->next;
410 PrevInList = Dce;
411 }
412 else
413 {
414 for (PrevInList = FirstDce; NULL != PrevInList; PrevInList = PrevInList->next)
415 {
416 if (Dce == PrevInList->next)
417 {
418 PrevInList->next = Dce->next;
419 break;
420 }
421 }
422 assert(NULL != PrevInList);
423 }
424
425 return NULL != PrevInList;
426 }
427
428
429 /* EOF */