1 /* $Id: windc.c,v 1.10 2003/05/04 15:41:40 gvg Exp $
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)
9 * 06-06-2001 CSH Created
12 /* INCLUDES ******************************************************************/
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>
29 /* GLOBALS *******************************************************************/
31 static PDCE FirstDce
= NULL
;
33 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
34 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
36 /* FUNCTIONS *****************************************************************/
39 DceOffsetVisRgn(HDC hDC
, HRGN hVisRgn
)
41 DC
*dc
= DC_HandleToPtr(hDC
);
46 W32kOffsetRgn(hVisRgn
, dc
->w
.DCOrgX
, dc
->w
.DCOrgY
);
51 DceGetVisRect(PWINDOW_OBJECT Window
, BOOL ClientArea
, RECT
* Rect
)
55 *Rect
= Window
->ClientRect
;
59 *Rect
= Window
->WindowRect
;
62 if (Window
->Style
& WS_VISIBLE
)
64 INT XOffset
= Rect
->left
;
65 INT YOffset
= Rect
->top
;
67 while ((Window
= Window
->Parent
) != NULL
)
69 if ((Window
->Style
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
71 W32kSetEmptyRect(Rect
);
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
)
85 W32kSetEmptyRect(Rect
);
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
);
93 W32kOffsetRect(Rect
, -XOffset
, -YOffset
);
96 W32kSetEmptyRect(Rect
);
101 DceAddClipRects(PWINDOW_OBJECT Parent
, PWINDOW_OBJECT End
,
102 HRGN ClipRgn
, PRECT Rect
, INT XOffset
, INT YOffset
)
104 PLIST_ENTRY ChildListEntry
;
105 PWINDOW_OBJECT Child
;
108 ChildListEntry
= Parent
->ChildrenListHead
.Flink
;
109 while (ChildListEntry
!= &Parent
->ChildrenListHead
)
111 Child
= CONTAINING_RECORD(ChildListEntry
, WINDOW_OBJECT
,
117 if (Child
->Style
& WS_VISIBLE
)
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
;
124 if (W32kIntersectRect(&Rect1
, &Rect1
, Rect
))
126 W32kUnionRectWithRgn(ClipRgn
, &Rect1
);
129 ChildListEntry
= ChildListEntry
->Flink
;
135 DceGetVisRgn(HWND hWnd
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
137 PWINDOW_OBJECT Window
;
138 PWINDOW_OBJECT Child
;
142 Window
= W32kGetWindowObject(hWnd
);
143 Child
= W32kGetWindowObject(hWndChild
);
145 if (Window
!= NULL
&& DceGetVisRect(Window
, !(Flags
& DCX_WINDOW
), &Rect
))
147 if ((VisRgn
= UnsafeW32kCreateRectRgnIndirect(&Rect
)) != NULL
)
149 HRGN ClipRgn
= W32kCreateRectRgn(0, 0, 0, 0);
150 INT XOffset
, YOffset
;
154 if (Flags
& DCX_CLIPCHILDREN
&&
155 !IsListEmpty(&Window
->ChildrenListHead
))
157 if (Flags
& DCX_WINDOW
)
159 XOffset
= Window
->ClientRect
.left
-
160 Window
->WindowRect
.left
;
161 YOffset
= Window
->ClientRect
.top
-
162 Window
->WindowRect
.top
;
166 XOffset
= YOffset
= 0;
168 DceAddClipRects(Window
, NULL
, ClipRgn
, &Rect
,
172 if (CFlags
& DCX_CLIPCHILDREN
&& Child
&&
173 !IsListEmpty(&Child
->ChildrenListHead
))
175 if (Flags
& DCX_WINDOW
)
177 XOffset
= Window
->ClientRect
.left
-
178 Window
->WindowRect
.left
;
179 YOffset
= Window
->ClientRect
.top
-
180 Window
->WindowRect
.top
;
184 XOffset
= YOffset
= 0;
187 XOffset
+= Child
->ClientRect
.left
;
188 YOffset
+= Child
->ClientRect
.top
;
190 DceAddClipRects(Child
, NULL
, ClipRgn
, &Rect
,
194 if (Flags
& DCX_WINDOW
)
196 XOffset
= -Window
->WindowRect
.left
;
197 YOffset
= -Window
->WindowRect
.top
;
201 XOffset
= -Window
->ClientRect
.left
;
202 YOffset
= -Window
->ClientRect
.top
;
205 if (Flags
& DCX_CLIPSIBLINGS
&& Window
->Parent
!= NULL
)
207 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
208 &Rect
, XOffset
, YOffset
);
211 while (Window
->Style
& WS_CHILD
)
213 Window
= Window
->Parent
;
214 XOffset
-= Window
->ClientRect
.left
;
215 YOffset
-= Window
->ClientRect
.top
;
216 if (Window
->Style
& WS_CLIPSIBLINGS
&&
217 Window
->Parent
!= NULL
)
219 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
220 &Rect
, XOffset
, YOffset
);
224 W32kCombineRgn(VisRgn
, VisRgn
, ClipRgn
, RGN_DIFF
);
225 W32kDeleteObject(ClipRgn
);
229 W32kDeleteObject(VisRgn
);
236 VisRgn
= W32kCreateRectRgn(0, 0, 0, 0);
238 W32kReleaseWindowObject(Window
);
239 W32kReleaseWindowObject(Child
);
244 NtUserReleaseDC(HWND hWnd
, HDC hDc
)
250 NtUserGetDC(HWND hWnd
)
252 return NtUserGetDCEx(hWnd
, NULL
, NULL
== hWnd
? DCX_CACHE
| DCX_WINDOW
: DCX_USESTYLE
);
255 DCE
* DceAllocDCE(HWND hWnd
, DCE_TYPE Type
)
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
;
268 if (Type
!= DCE_CACHE_DC
)
270 Dce
->DCXFlags
= DCX_DCEBUSY
;
273 PWINDOW_OBJECT WindowObject
;
275 WindowObject
= W32kGetWindowObject(hWnd
);
276 if (WindowObject
->Style
& WS_CLIPCHILDREN
)
278 Dce
->DCXFlags
|= DCX_CLIPCHILDREN
;
280 if (WindowObject
->Style
& WS_CLIPSIBLINGS
)
282 Dce
->DCXFlags
|= DCX_CLIPSIBLINGS
;
284 W32kReleaseWindowObject(WindowObject
);
289 Dce
->DCXFlags
= DCX_CACHE
| DCX_DCEEMPTY
;
296 DceSetDrawable(PWINDOW_OBJECT WindowObject
, HDC hDC
, ULONG Flags
,
299 DC
*dc
= DC_HandleToPtr(hDC
);
300 if (WindowObject
== NULL
)
307 if (Flags
& DCX_WINDOW
)
309 dc
->w
.DCOrgX
= WindowObject
->WindowRect
.left
;
310 dc
->w
.DCOrgY
= WindowObject
->WindowRect
.top
;
314 dc
->w
.DCOrgX
= WindowObject
->ClientRect
.left
;
315 dc
->w
.DCOrgY
= WindowObject
->ClientRect
.top
;
317 /* FIXME: Offset by parent's client rectangle. */
323 NtUserGetDCEx(HWND hWnd
, HANDLE hRegion
, ULONG Flags
)
325 PWINDOW_OBJECT Window
;
328 BOOL UpdateVisRgn
= TRUE
;
329 BOOL UpdateClipOrigin
= FALSE
;
330 HANDLE hRgnVisible
= NULL
;
334 Flags
&= ~DCX_USESTYLE
;
337 else if (NULL
== (Window
= W32kGetWindowObject(hWnd
)))
342 if (NULL
== Window
|| NULL
== Window
->Dce
)
348 if (Flags
& DCX_USESTYLE
)
350 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
352 if (Window
->Style
& WS_CLIPSIBLINGS
)
354 Flags
|= DCX_CLIPSIBLINGS
;
357 if (!(Flags
& DCX_WINDOW
))
359 if (Window
->Class
->Class
.style
& CS_PARENTDC
)
361 Flags
|= DCX_PARENTCLIP
;
364 if (Window
->Style
& WS_CLIPCHILDREN
&&
365 !(Window
->Style
& WS_MINIMIZE
))
367 Flags
|= DCX_CLIPCHILDREN
;
376 if (Flags
& DCX_NOCLIPCHILDREN
)
379 Flags
|= ~(DCX_PARENTCLIP
| DCX_CLIPCHILDREN
);
382 if (Flags
& DCX_WINDOW
)
384 Flags
= (Flags
& ~DCX_CLIPCHILDREN
) | DCX_CACHE
;
387 if (NULL
== Window
|| !(Window
->Style
& WS_CHILD
) || NULL
== Window
->Parent
)
389 Flags
&= ~DCX_PARENTCLIP
;
391 else if (Flags
& DCX_PARENTCLIP
)
394 if (!(Flags
& (DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
)))
396 if ((Window
->Style
& WS_VISIBLE
) &&
397 (Window
->Parent
->Style
& WS_VISIBLE
))
399 Flags
&= ~DCX_CLIPCHILDREN
;
400 if (Window
->Parent
->Style
& WS_CLIPSIBLINGS
)
402 Flags
|= DCX_CLIPSIBLINGS
;
408 DcxFlags
= Flags
& DCX_CACHECOMPAREMASK
;
410 if (Flags
& DCX_CACHE
)
412 DCE
* DceEmpty
= NULL
;
413 DCE
* DceUnused
= NULL
;
415 for (Dce
= FirstDce
; Dce
!= NULL
; Dce
= Dce
->next
)
417 if ((Dce
->DCXFlags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
420 if (Dce
->DCXFlags
& DCX_DCEEMPTY
)
424 else if (Dce
->hwndCurrent
== hWnd
&&
425 ((Dce
->DCXFlags
& DCX_CACHECOMPAREMASK
) == DcxFlags
))
427 UpdateVisRgn
= FALSE
;
428 UpdateClipOrigin
= TRUE
;
436 Dce
= (DceEmpty
== NULL
) ? DceEmpty
: DceUnused
;
441 Dce
= DceAllocDCE(NULL
, DCE_CACHE_DC
);
447 /* FIXME: Implement this. */
451 if (NULL
== Dce
&& NULL
!= Window
)
453 W32kReleaseWindowObject(Window
);
457 Dce
->hwndCurrent
= hWnd
;
458 Dce
->hClipRgn
= NULL
;
459 Dce
->DCXFlags
= DcxFlags
| (Flags
& DCX_WINDOWPAINT
) | DCX_DCEBUSY
;
461 DceSetDrawable(Window
, Dce
->hDC
, Flags
, UpdateClipOrigin
);
465 if (Flags
& DCX_PARENTCLIP
)
467 PWINDOW_OBJECT Parent
;
469 Parent
= Window
->Parent
;
471 if (Window
->Style
& WS_VISIBLE
&&
472 !(Parent
->Style
& WS_MINIMIZE
))
474 if (Parent
->Style
& WS_CLIPSIBLINGS
)
476 DcxFlags
= DCX_CLIPSIBLINGS
|
477 (Flags
& ~(DCX_CLIPCHILDREN
| DCX_WINDOW
));
482 ~(DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
| DCX_WINDOW
);
484 hRgnVisible
= DceGetVisRgn(Parent
->Self
, DcxFlags
,
485 Window
->Self
, Flags
);
486 if (Flags
& DCX_WINDOW
)
488 W32kOffsetRgn(hRgnVisible
, -Window
->WindowRect
.left
,
489 -Window
->WindowRect
.top
);
493 W32kOffsetRgn(hRgnVisible
, -Window
->ClientRect
.left
,
494 -Window
->ClientRect
.top
);
496 DceOffsetVisRgn(Dce
->hDC
, hRgnVisible
);
500 hRgnVisible
= W32kCreateRectRgn(0, 0, 0, 0);
505 if (hWnd
== W32kGetDesktopWindow())
508 W32kCreateRectRgn(0, 0,
509 NtUserGetSystemMetrics(SM_CXSCREEN
),
510 NtUserGetSystemMetrics(SM_CYSCREEN
));
514 hRgnVisible
= DceGetVisRgn(hWnd
, Flags
, 0, 0);
515 DceOffsetVisRgn(Dce
->hDC
, hRgnVisible
);
518 Dce
->DCXFlags
&= ~DCX_DCEDIRTY
;
519 W32kSelectVisRgn(Dce
->hDC
, hRgnVisible
);
523 if (Flags
& (DCX_EXCLUDERGN
| DCX_INTERSECTRGN
))
528 if (hRgnVisible
!= NULL
)
530 W32kDeleteObject(hRgnVisible
);
534 W32kReleaseWindowObject(Window
);
541 DCE_InternalDelete(PDCE Dce
)
547 FirstDce
= Dce
->next
;
552 for (PrevInList
= FirstDce
; NULL
!= PrevInList
; PrevInList
= PrevInList
->next
)
554 if (Dce
== PrevInList
->next
)
556 PrevInList
->next
= Dce
->next
;
560 assert(NULL
!= PrevInList
);
563 return NULL
!= PrevInList
;