a6bcb6950c454f439cd8dcaad3d99f692a7effb1
[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.13 2003/07/10 00:24:04 chorns 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
44 #define NDEBUG
45 #include <debug.h>
46
47 /* GLOBALS *******************************************************************/
48
49 static PDCE FirstDce = NULL;
50
51 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
52 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
53
54 /* FUNCTIONS *****************************************************************/
55
56 VOID STATIC FASTCALL
57 DceOffsetVisRgn(HDC hDC, HRGN hVisRgn)
58 {
59 DC *dc = DC_HandleToPtr(hDC);
60 if (dc == NULL)
61 {
62 return;
63 }
64 W32kOffsetRgn(hVisRgn, dc->w.DCOrgX, dc->w.DCOrgY);
65 DC_ReleasePtr(hDC);
66 }
67
68 BOOL STATIC STDCALL
69 DceGetVisRect(PWINDOW_OBJECT Window, BOOL ClientArea, RECT* Rect)
70 {
71 if (ClientArea)
72 {
73 *Rect = Window->ClientRect;
74 }
75 else
76 {
77 *Rect = Window->WindowRect;
78 }
79
80 if (Window->Style & WS_VISIBLE)
81 {
82 INT XOffset = Rect->left;
83 INT YOffset = Rect->top;
84
85 while ((Window = Window->Parent) != NULL)
86 {
87 if ((Window->Style & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE)
88 {
89 W32kSetEmptyRect(Rect);
90 return(FALSE);
91 }
92 XOffset += Window->ClientRect.left;
93 YOffset += Window->ClientRect.top;
94 W32kOffsetRect(Rect, Window->ClientRect.left,
95 Window->ClientRect.top);
96 if (Window->ClientRect.left >= Window->ClientRect.right ||
97 Window->ClientRect.top >= Window->ClientRect.bottom ||
98 Rect->left >= Window->ClientRect.right ||
99 Rect->right <= Window->ClientRect.left ||
100 Rect->top >= Window->ClientRect.bottom ||
101 Rect->bottom <= Window->ClientRect.top)
102 {
103 W32kSetEmptyRect(Rect);
104 return(FALSE);
105 }
106 Rect->left = max(Rect->left, Window->ClientRect.left);
107 Rect->right = min(Rect->right, Window->ClientRect.right);
108 Rect->top = max(Rect->top, Window->ClientRect.top);
109 Rect->bottom = min(Rect->bottom, Window->ClientRect.bottom);
110 }
111 W32kOffsetRect(Rect, -XOffset, -YOffset);
112 return(TRUE);
113 }
114 W32kSetEmptyRect(Rect);
115 return(FALSE);
116 }
117
118 BOOL STDCALL
119 DceAddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End,
120 HRGN ClipRgn, PRECT Rect, INT XOffset, INT YOffset)
121 {
122 PLIST_ENTRY ChildListEntry;
123 PWINDOW_OBJECT Child;
124 RECT Rect1;
125
126
127 ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
128 ChildListEntry = Parent->ChildrenListHead.Flink;
129 while (ChildListEntry != &Parent->ChildrenListHead)
130 {
131 Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT,
132 SiblingListEntry);
133 if (Child == End)
134 {
135 ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
136 return(TRUE);
137 }
138 if (Child->Style & WS_VISIBLE)
139 {
140 Rect1.left = Child->WindowRect.left + XOffset;
141 Rect1.top = Child->WindowRect.top + YOffset;
142 Rect1.right = Child->WindowRect.right + XOffset;
143 Rect1.bottom = Child->WindowRect.bottom + YOffset;
144
145 if (W32kIntersectRect(&Rect1, &Rect1, Rect))
146 {
147 W32kUnionRectWithRgn(ClipRgn, &Rect1);
148 }
149 }
150 ChildListEntry = ChildListEntry->Flink;
151 }
152 ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
153 return(FALSE);
154 }
155
156 HRGN STDCALL
157 DceGetVisRgn(HWND hWnd, ULONG Flags, HWND hWndChild, ULONG CFlags)
158 {
159 PWINDOW_OBJECT Window;
160 PWINDOW_OBJECT Child;
161 HRGN VisRgn;
162 RECT Rect;
163
164 Window = W32kGetWindowObject(hWnd);
165 Child = W32kGetWindowObject(hWndChild);
166
167 if (Window != NULL && DceGetVisRect(Window, !(Flags & DCX_WINDOW), &Rect))
168 {
169 if ((VisRgn = UnsafeW32kCreateRectRgnIndirect(&Rect)) != NULL)
170 {
171 HRGN ClipRgn = W32kCreateRectRgn(0, 0, 0, 0);
172 INT XOffset, YOffset;
173
174 if (ClipRgn != NULL)
175 {
176 if (Flags & DCX_CLIPCHILDREN &&
177 !IsListEmpty(&Window->ChildrenListHead))
178 {
179 if (Flags & DCX_WINDOW)
180 {
181 XOffset = Window->ClientRect.left -
182 Window->WindowRect.left;
183 YOffset = Window->ClientRect.top -
184 Window->WindowRect.top;
185 }
186 else
187 {
188 XOffset = YOffset = 0;
189 }
190 DceAddClipRects(Window, NULL, ClipRgn, &Rect,
191 XOffset, YOffset);
192 }
193
194 if (CFlags & DCX_CLIPCHILDREN && Child &&
195 !IsListEmpty(&Child->ChildrenListHead))
196 {
197 if (Flags & DCX_WINDOW)
198 {
199 XOffset = Window->ClientRect.left -
200 Window->WindowRect.left;
201 YOffset = Window->ClientRect.top -
202 Window->WindowRect.top;
203 }
204 else
205 {
206 XOffset = YOffset = 0;
207 }
208
209 XOffset += Child->ClientRect.left;
210 YOffset += Child->ClientRect.top;
211
212 DceAddClipRects(Child, NULL, ClipRgn, &Rect,
213 XOffset, YOffset);
214 }
215
216 if (Flags & DCX_WINDOW)
217 {
218 XOffset = -Window->WindowRect.left;
219 YOffset = -Window->WindowRect.top;
220 }
221 else
222 {
223 XOffset = -Window->ClientRect.left;
224 YOffset = -Window->ClientRect.top;
225 }
226
227 if (Flags & DCX_CLIPSIBLINGS && Window->Parent != NULL)
228 {
229 DceAddClipRects(Window->Parent, Window, ClipRgn,
230 &Rect, XOffset, YOffset);
231 }
232
233 while (Window->Style & WS_CHILD)
234 {
235 Window = Window->Parent;
236 XOffset -= Window->ClientRect.left;
237 YOffset -= Window->ClientRect.top;
238 if (Window->Style & WS_CLIPSIBLINGS &&
239 Window->Parent != NULL)
240 {
241 DceAddClipRects(Window->Parent, Window, ClipRgn,
242 &Rect, XOffset, YOffset);
243 }
244 }
245
246 W32kCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
247 W32kDeleteObject(ClipRgn);
248 }
249 else
250 {
251 W32kDeleteObject(VisRgn);
252 VisRgn = 0;
253 }
254 }
255 }
256 else
257 {
258 VisRgn = W32kCreateRectRgn(0, 0, 0, 0);
259 }
260 W32kReleaseWindowObject(Window);
261 W32kReleaseWindowObject(Child);
262 return(VisRgn);
263 }
264
265 INT STDCALL
266 NtUserReleaseDC(HWND hWnd, HDC hDc)
267 {
268
269 }
270
271 HDC STDCALL
272 NtUserGetDC(HWND hWnd)
273 {
274 return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
275 }
276
277 DCE * FASTCALL DceAllocDCE(HWND hWnd, DCE_TYPE Type)
278 {
279 HDCE DceHandle;
280 DCE* Dce;
281
282 DceHandle = DCEOBJ_AllocDCE();
283 Dce = DCEOBJ_LockDCE(DceHandle);
284 Dce->hDC = W32kCreateDC(L"DISPLAY", NULL, NULL, NULL);
285 Dce->hwndCurrent = hWnd;
286 Dce->hClipRgn = NULL;
287 Dce->next = FirstDce;
288 FirstDce = Dce;
289
290 if (Type != DCE_CACHE_DC)
291 {
292 Dce->DCXFlags = DCX_DCEBUSY;
293 if (hWnd != NULL)
294 {
295 PWINDOW_OBJECT WindowObject;
296
297 WindowObject = W32kGetWindowObject(hWnd);
298 if (WindowObject->Style & WS_CLIPCHILDREN)
299 {
300 Dce->DCXFlags |= DCX_CLIPCHILDREN;
301 }
302 if (WindowObject->Style & WS_CLIPSIBLINGS)
303 {
304 Dce->DCXFlags |= DCX_CLIPSIBLINGS;
305 }
306 W32kReleaseWindowObject(WindowObject);
307 }
308 }
309 else
310 {
311 Dce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY;
312 }
313
314 return(Dce);
315 }
316
317 VOID STATIC STDCALL
318 DceSetDrawable(PWINDOW_OBJECT WindowObject, HDC hDC, ULONG Flags,
319 BOOL SetClipOrigin)
320 {
321 DC *dc = DC_HandleToPtr(hDC);
322 if (WindowObject == NULL)
323 {
324 dc->w.DCOrgX = 0;
325 dc->w.DCOrgY = 0;
326 }
327 else
328 {
329 if (Flags & DCX_WINDOW)
330 {
331 dc->w.DCOrgX = WindowObject->WindowRect.left;
332 dc->w.DCOrgY = WindowObject->WindowRect.top;
333 }
334 else
335 {
336 dc->w.DCOrgX = WindowObject->ClientRect.left;
337 dc->w.DCOrgY = WindowObject->ClientRect.top;
338 }
339 /* FIXME: Offset by parent's client rectangle. */
340 }
341 DC_ReleasePtr(hDC);
342 }
343
344 HDC STDCALL
345 NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
346 {
347 PWINDOW_OBJECT Window;
348 ULONG DcxFlags;
349 DCE* Dce;
350 BOOL UpdateVisRgn = TRUE;
351 BOOL UpdateClipOrigin = FALSE;
352 HANDLE hRgnVisible = NULL;
353
354 if (NULL == hWnd)
355 {
356 Flags &= ~DCX_USESTYLE;
357 Window = NULL;
358 }
359 else if (NULL == (Window = W32kGetWindowObject(hWnd)))
360 {
361 return(0);
362 }
363
364 if (NULL == Window || NULL == Window->Dce)
365 {
366 Flags |= DCX_CACHE;
367 }
368
369
370 if (Flags & DCX_USESTYLE)
371 {
372 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
373
374 if (Window->Style & WS_CLIPSIBLINGS)
375 {
376 Flags |= DCX_CLIPSIBLINGS;
377 }
378
379 if (!(Flags & DCX_WINDOW))
380 {
381 if (Window->Class->Class.style & CS_PARENTDC)
382 {
383 Flags |= DCX_PARENTCLIP;
384 }
385
386 if (Window->Style & WS_CLIPCHILDREN &&
387 !(Window->Style & WS_MINIMIZE))
388 {
389 Flags |= DCX_CLIPCHILDREN;
390 }
391 }
392 else
393 {
394 Flags |= DCX_CACHE;
395 }
396 }
397
398 if (Flags & DCX_NOCLIPCHILDREN)
399 {
400 Flags |= DCX_CACHE;
401 Flags |= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
402 }
403
404 if (Flags & DCX_WINDOW)
405 {
406 Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
407 }
408
409 if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Window->Parent)
410 {
411 Flags &= ~DCX_PARENTCLIP;
412 }
413 else if (Flags & DCX_PARENTCLIP)
414 {
415 Flags |= DCX_CACHE;
416 if (!(Flags & (DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS)))
417 {
418 if ((Window->Style & WS_VISIBLE) &&
419 (Window->Parent->Style & WS_VISIBLE))
420 {
421 Flags &= ~DCX_CLIPCHILDREN;
422 if (Window->Parent->Style & WS_CLIPSIBLINGS)
423 {
424 Flags |= DCX_CLIPSIBLINGS;
425 }
426 }
427 }
428 }
429
430 DcxFlags = Flags & DCX_CACHECOMPAREMASK;
431
432 if (Flags & DCX_CACHE)
433 {
434 DCE* DceEmpty = NULL;
435 DCE* DceUnused = NULL;
436
437 for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
438 {
439 if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
440 {
441 DceUnused = Dce;
442 if (Dce->DCXFlags & DCX_DCEEMPTY)
443 {
444 DceEmpty = Dce;
445 }
446 else if (Dce->hwndCurrent == hWnd &&
447 ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags))
448 {
449 UpdateVisRgn = FALSE;
450 UpdateClipOrigin = TRUE;
451 break;
452 }
453 }
454 }
455
456 if (Dce == NULL)
457 {
458 Dce = (DceEmpty == NULL) ? DceEmpty : DceUnused;
459 }
460
461 if (Dce == NULL)
462 {
463 Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
464 }
465 }
466 else
467 {
468 Dce = Window->Dce;
469 /* FIXME: Implement this. */
470 DbgBreakPoint();
471 }
472
473 if (NULL == Dce && NULL != Window)
474 {
475 W32kReleaseWindowObject(Window);
476 return(NULL);
477 }
478
479 Dce->hwndCurrent = hWnd;
480 Dce->hClipRgn = NULL;
481 Dce->DCXFlags = DcxFlags | (Flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
482
483 DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
484
485 if (UpdateVisRgn)
486 {
487 if (Flags & DCX_PARENTCLIP)
488 {
489 PWINDOW_OBJECT Parent;
490
491 Parent = Window->Parent;
492
493 if (Window->Style & WS_VISIBLE &&
494 !(Parent->Style & WS_MINIMIZE))
495 {
496 if (Parent->Style & WS_CLIPSIBLINGS)
497 {
498 DcxFlags = DCX_CLIPSIBLINGS |
499 (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
500 }
501 else
502 {
503 DcxFlags = Flags &
504 ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
505 }
506 hRgnVisible = DceGetVisRgn(Parent->Self, DcxFlags,
507 Window->Self, Flags);
508 if (Flags & DCX_WINDOW)
509 {
510 W32kOffsetRgn(hRgnVisible,
511 Parent->WindowRect.left - Window->WindowRect.left,
512 Parent->WindowRect.top - Window->WindowRect.top);
513 }
514 else
515 {
516 W32kOffsetRgn(hRgnVisible,
517 Parent->ClientRect.left - Window->ClientRect.left,
518 Parent->ClientRect.top - Window->ClientRect.top);
519 }
520 DceOffsetVisRgn(Dce->hDC, hRgnVisible);
521 }
522 else
523 {
524 hRgnVisible = W32kCreateRectRgn(0, 0, 0, 0);
525 }
526 }
527 else
528 {
529 if (hWnd == W32kGetDesktopWindow())
530 {
531 hRgnVisible =
532 W32kCreateRectRgn(0, 0,
533 NtUserGetSystemMetrics(SM_CXSCREEN),
534 NtUserGetSystemMetrics(SM_CYSCREEN));
535 }
536 else
537 {
538 hRgnVisible = DceGetVisRgn(hWnd, Flags, 0, 0);
539 DceOffsetVisRgn(Dce->hDC, hRgnVisible);
540 }
541 }
542
543 Dce->DCXFlags &= ~DCX_DCEDIRTY;
544 W32kSelectVisRgn(Dce->hDC, hRgnVisible);
545 }
546
547 if (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
548 {
549 DPRINT1("FIXME.\n");
550 }
551
552 if (hRgnVisible != NULL)
553 {
554 W32kDeleteObject(hRgnVisible);
555 }
556 if (NULL != Window)
557 {
558 W32kReleaseWindowObject(Window);
559 }
560
561 return(Dce->hDC);
562 }
563
564 BOOL FASTCALL
565 DCE_InternalDelete(PDCE Dce)
566 {
567 PDCE PrevInList;
568
569 if (Dce == FirstDce)
570 {
571 FirstDce = Dce->next;
572 PrevInList = Dce;
573 }
574 else
575 {
576 for (PrevInList = FirstDce; NULL != PrevInList; PrevInList = PrevInList->next)
577 {
578 if (Dce == PrevInList->next)
579 {
580 PrevInList->next = Dce->next;
581 break;
582 }
583 }
584 assert(NULL != PrevInList);
585 }
586
587 return NULL != PrevInList;
588 }
589
590
591 /* EOF */