2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
19 /* $Id: windc.c,v 1.13 2003/07/10 00:24:04 chorns Exp $
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)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
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>
47 /* GLOBALS *******************************************************************/
49 static PDCE FirstDce
= NULL
;
51 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
52 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
54 /* FUNCTIONS *****************************************************************/
57 DceOffsetVisRgn(HDC hDC
, HRGN hVisRgn
)
59 DC
*dc
= DC_HandleToPtr(hDC
);
64 W32kOffsetRgn(hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
69 DceGetVisRect(PWINDOW_OBJECT Window
, BOOL ClientArea
, RECT
* Rect
)
73 *Rect
= Window
->ClientRect
;
77 *Rect
= Window
->WindowRect
;
80 if (Window
->Style
& WS_VISIBLE
)
82 INT XOffset
= Rect
->left
;
83 INT YOffset
= Rect
->top
;
85 while ((Window
= Window
->Parent
) != NULL
)
87 if ((Window
->Style
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
89 W32kSetEmptyRect(Rect
);
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
)
103 W32kSetEmptyRect(Rect
);
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
);
111 W32kOffsetRect(Rect
, -XOffset
, -YOffset
);
114 W32kSetEmptyRect(Rect
);
119 DceAddClipRects(PWINDOW_OBJECT Parent
, PWINDOW_OBJECT End
,
120 HRGN ClipRgn
, PRECT Rect
, INT XOffset
, INT YOffset
)
122 PLIST_ENTRY ChildListEntry
;
123 PWINDOW_OBJECT Child
;
127 ExAcquireFastMutexUnsafe(&Parent
->ChildrenListLock
);
128 ChildListEntry
= Parent
->ChildrenListHead
.Flink
;
129 while (ChildListEntry
!= &Parent
->ChildrenListHead
)
131 Child
= CONTAINING_RECORD(ChildListEntry
, WINDOW_OBJECT
,
135 ExReleaseFastMutexUnsafe(&Parent
->ChildrenListLock
);
138 if (Child
->Style
& WS_VISIBLE
)
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
;
145 if (W32kIntersectRect(&Rect1
, &Rect1
, Rect
))
147 W32kUnionRectWithRgn(ClipRgn
, &Rect1
);
150 ChildListEntry
= ChildListEntry
->Flink
;
152 ExReleaseFastMutexUnsafe(&Parent
->ChildrenListLock
);
157 DceGetVisRgn(HWND hWnd
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
159 PWINDOW_OBJECT Window
;
160 PWINDOW_OBJECT Child
;
164 Window
= W32kGetWindowObject(hWnd
);
165 Child
= W32kGetWindowObject(hWndChild
);
167 if (Window
!= NULL
&& DceGetVisRect(Window
, !(Flags
& DCX_WINDOW
), &Rect
))
169 if ((VisRgn
= UnsafeW32kCreateRectRgnIndirect(&Rect
)) != NULL
)
171 HRGN ClipRgn
= W32kCreateRectRgn(0, 0, 0, 0);
172 INT XOffset
, YOffset
;
176 if (Flags
& DCX_CLIPCHILDREN
&&
177 !IsListEmpty(&Window
->ChildrenListHead
))
179 if (Flags
& DCX_WINDOW
)
181 XOffset
= Window
->ClientRect
.left
-
182 Window
->WindowRect
.left
;
183 YOffset
= Window
->ClientRect
.top
-
184 Window
->WindowRect
.top
;
188 XOffset
= YOffset
= 0;
190 DceAddClipRects(Window
, NULL
, ClipRgn
, &Rect
,
194 if (CFlags
& DCX_CLIPCHILDREN
&& Child
&&
195 !IsListEmpty(&Child
->ChildrenListHead
))
197 if (Flags
& DCX_WINDOW
)
199 XOffset
= Window
->ClientRect
.left
-
200 Window
->WindowRect
.left
;
201 YOffset
= Window
->ClientRect
.top
-
202 Window
->WindowRect
.top
;
206 XOffset
= YOffset
= 0;
209 XOffset
+= Child
->ClientRect
.left
;
210 YOffset
+= Child
->ClientRect
.top
;
212 DceAddClipRects(Child
, NULL
, ClipRgn
, &Rect
,
216 if (Flags
& DCX_WINDOW
)
218 XOffset
= -Window
->WindowRect
.left
;
219 YOffset
= -Window
->WindowRect
.top
;
223 XOffset
= -Window
->ClientRect
.left
;
224 YOffset
= -Window
->ClientRect
.top
;
227 if (Flags
& DCX_CLIPSIBLINGS
&& Window
->Parent
!= NULL
)
229 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
230 &Rect
, XOffset
, YOffset
);
233 while (Window
->Style
& WS_CHILD
)
235 Window
= Window
->Parent
;
236 XOffset
-= Window
->ClientRect
.left
;
237 YOffset
-= Window
->ClientRect
.top
;
238 if (Window
->Style
& WS_CLIPSIBLINGS
&&
239 Window
->Parent
!= NULL
)
241 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
242 &Rect
, XOffset
, YOffset
);
246 W32kCombineRgn(VisRgn
, VisRgn
, ClipRgn
, RGN_DIFF
);
247 W32kDeleteObject(ClipRgn
);
251 W32kDeleteObject(VisRgn
);
258 VisRgn
= W32kCreateRectRgn(0, 0, 0, 0);
260 W32kReleaseWindowObject(Window
);
261 W32kReleaseWindowObject(Child
);
266 NtUserReleaseDC(HWND hWnd
, HDC hDc
)
272 NtUserGetDC(HWND hWnd
)
274 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
277 DCE
* FASTCALL
DceAllocDCE(HWND hWnd
, DCE_TYPE Type
)
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
;
290 if (Type
!= DCE_CACHE_DC
)
292 Dce
->DCXFlags
= DCX_DCEBUSY
;
295 PWINDOW_OBJECT WindowObject
;
297 WindowObject
= W32kGetWindowObject(hWnd
);
298 if (WindowObject
->Style
& WS_CLIPCHILDREN
)
300 Dce
->DCXFlags
|= DCX_CLIPCHILDREN
;
302 if (WindowObject
->Style
& WS_CLIPSIBLINGS
)
304 Dce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
306 W32kReleaseWindowObject(WindowObject
);
311 Dce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
318 DceSetDrawable(PWINDOW_OBJECT WindowObject
, HDC hDC
, ULONG Flags
,
321 DC
*dc
= DC_HandleToPtr(hDC
);
322 if (WindowObject
== NULL
)
329 if (Flags
& DCX_WINDOW
)
331 dc
->w
.DCOrgX
= WindowObject
->WindowRect
.left
;
332 dc
->w
.DCOrgY
= WindowObject
->WindowRect
.top
;
336 dc
->w
.DCOrgX
= WindowObject
->ClientRect
.left
;
337 dc
->w
.DCOrgY
= WindowObject
->ClientRect
.top
;
339 /* FIXME: Offset by parent's client rectangle. */
345 NtUserGetDCEx(HWND hWnd
, HANDLE hRegion
, ULONG Flags
)
347 PWINDOW_OBJECT Window
;
350 BOOL UpdateVisRgn
= TRUE
;
351 BOOL UpdateClipOrigin
= FALSE
;
352 HANDLE hRgnVisible
= NULL
;
356 Flags
&= ~DCX_USESTYLE
;
359 else if (NULL
== (Window
= W32kGetWindowObject(hWnd
)))
364 if (NULL
== Window
|| NULL
== Window
->Dce
)
370 if (Flags
& DCX_USESTYLE
)
372 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
374 if (Window
->Style
& WS_CLIPSIBLINGS
)
376 Flags
|= DCX_CLIPSIBLINGS
;
379 if (!(Flags
& DCX_WINDOW
))
381 if (Window
->Class
->Class
.style
& CS_PARENTDC
)
383 Flags
|= DCX_PARENTCLIP
;
386 if (Window
->Style
& WS_CLIPCHILDREN
&&
387 !(Window
->Style
& WS_MINIMIZE
))
389 Flags
|= DCX_CLIPCHILDREN
;
398 if (Flags
& DCX_NOCLIPCHILDREN
)
401 Flags
|= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
404 if (Flags
& DCX_WINDOW
)
406 Flags
= (Flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
409 if (NULL
== Window
|| !(Window
->Style
& WS_CHILD
) || NULL
== Window
->Parent
)
411 Flags
&= ~DCX_PARENTCLIP
;
413 else if (Flags
& DCX_PARENTCLIP
)
416 if (!(Flags
& (DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
)))
418 if ((Window
->Style
& WS_VISIBLE
) &&
419 (Window
->Parent
->Style
& WS_VISIBLE
))
421 Flags
&= ~DCX_CLIPCHILDREN
;
422 if (Window
->Parent
->Style
& WS_CLIPSIBLINGS
)
424 Flags
|= DCX_CLIPSIBLINGS
;
430 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
432 if (Flags
& DCX_CACHE
)
434 DCE
* DceEmpty
= NULL
;
435 DCE
* DceUnused
= NULL
;
437 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
439 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
442 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
446 else if (Dce
->hwndCurrent
== hWnd
&&
447 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
449 UpdateVisRgn
= FALSE
;
450 UpdateClipOrigin
= TRUE
;
458 Dce
= (DceEmpty
== NULL
) ? DceEmpty
: DceUnused
;
463 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
469 /* FIXME: Implement this. */
473 if (NULL
== Dce
&& NULL
!= Window
)
475 W32kReleaseWindowObject(Window
);
479 Dce
->hwndCurrent
= hWnd
;
480 Dce
->hClipRgn
= NULL
;
481 Dce
->DCXFlags
= DcxFlags
| (Flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
483 DceSetDrawable(Window
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
487 if (Flags
& DCX_PARENTCLIP
)
489 PWINDOW_OBJECT Parent
;
491 Parent
= Window
->Parent
;
493 if (Window
->Style
& WS_VISIBLE
&&
494 !(Parent
->Style
& WS_MINIMIZE
))
496 if (Parent
->Style
& WS_CLIPSIBLINGS
)
498 DcxFlags
= DCX_CLIPSIBLINGS
|
499 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
504 ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
506 hRgnVisible
= DceGetVisRgn(Parent
->Self
, DcxFlags
,
507 Window
->Self
, Flags
);
508 if (Flags
& DCX_WINDOW
)
510 W32kOffsetRgn(hRgnVisible
,
511 Parent
->WindowRect
.left
- Window
->WindowRect
.left
,
512 Parent
->WindowRect
.top
- Window
->WindowRect
.top
);
516 W32kOffsetRgn(hRgnVisible
,
517 Parent
->ClientRect
.left
- Window
->ClientRect
.left
,
518 Parent
->ClientRect
.top
- Window
->ClientRect
.top
);
520 DceOffsetVisRgn(Dce
->hDC
, hRgnVisible
);
524 hRgnVisible
= W32kCreateRectRgn(0, 0, 0, 0);
529 if (hWnd
== W32kGetDesktopWindow())
532 W32kCreateRectRgn(0, 0,
533 NtUserGetSystemMetrics(SM_CXSCREEN
),
534 NtUserGetSystemMetrics(SM_CYSCREEN
));
538 hRgnVisible
= DceGetVisRgn(hWnd
, Flags
, 0, 0);
539 DceOffsetVisRgn(Dce
->hDC
, hRgnVisible
);
543 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
544 W32kSelectVisRgn(Dce
->hDC
, hRgnVisible
);
547 if (Flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
))
552 if (hRgnVisible
!= NULL
)
554 W32kDeleteObject(hRgnVisible
);
558 W32kReleaseWindowObject(Window
);
565 DCE_InternalDelete(PDCE Dce
)
571 FirstDce
= Dce
->next
;
576 for (PrevInList
= FirstDce
; NULL
!= PrevInList
; PrevInList
= PrevInList
->next
)
578 if (Dce
== PrevInList
->next
)
580 PrevInList
->next
= Dce
->next
;
584 assert(NULL
!= PrevInList
);
587 return NULL
!= PrevInList
;