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