1 /* $Id: windc.c,v 1.5 2002/08/27 23:29:40 dwelch 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/userobj.h>
17 #include <include/class.h>
18 #include <include/error.h>
19 #include <include/winsta.h>
20 #include <include/msgqueue.h>
21 #include <include/window.h>
22 #include <include/rect.h>
23 #include <include/dce.h>
30 /* FUNCTIONS *****************************************************************/
32 VOID
DCE_FreeWindowDCE(HWND
);
33 INT
DCE_ExcludeRgn(HDC
, HWND
, HRGN
);
34 BOOL
DCE_InvalidateDCE(HWND
, const PRECTL
);
37 DceGetVisRect(PWINDOW_OBJECT Window
, BOOL ClientArea
, RECT
* Rect
)
41 *Rect
= Window
->ClientRect
;
45 *Rect
= Window
->WindowRect
;
48 if (Window
->Style
& WS_VISIBLE
)
50 INT XOffset
= Rect
->left
;
51 INT YOffset
= Rect
->top
;
53 while ((Window
= Window
->Parent
) != NULL
)
55 if ((Window
->Style
& (WS_ICONIC
| WS_VISIBLE
)) != WS_VISIBLE
)
57 W32kSetEmptyRect(Rect
);
60 XOffset
+= Window
->ClientRect
.left
;
61 YOffset
+= Window
->ClientRect
.top
;
62 W32kOffsetRect(Rect
, Window
->ClientRect
.left
,
63 Window
->ClientRect
.top
);
64 if (Window
->ClientRect
.left
>= Window
->ClientRect
.right
||
65 Window
->ClientRect
.top
>= Window
->ClientRect
.bottom
||
66 Rect
->left
>= Window
->ClientRect
.right
||
67 Rect
->right
<= Window
->ClientRect
.left
||
68 Rect
->top
>= Window
->ClientRect
.bottom
||
69 Rect
->bottom
<= Window
->ClientRect
.top
)
71 W32kSetEmptyRect(Rect
);
74 Rect
->left
= max(Rect
->left
, Window
->ClientRect
.left
);
75 Rect
->right
= min(Rect
->right
, Window
->ClientRect
.right
);
76 Rect
->top
= max(Rect
->top
, Window
->ClientRect
.top
);
77 Rect
->bottom
= min(Rect
->bottom
, Window
->ClientRect
.bottom
);
79 W32kOffsetRect(Rect
, -XOffset
, -YOffset
);
82 W32kSetEmptyRect(Rect
);
87 DceAddClipRects(PWINDOW_OBJECT Parent
, PWINDOW_OBJECT End
,
88 HRGN ClipRgn
, PRECT Rect
, INT XOffset
, INT YOffset
)
90 PLIST_ENTRY ChildListEntry
;
94 ChildListEntry
= Parent
->ChildrenListHead
.Flink
;
95 while (ChildListEntry
!= &Parent
->ChildrenListHead
)
97 Child
= CONTAINING_RECORD(ChildListEntry
, WINDOW_OBJECT
,
103 if (Child
->Style
& WS_VISIBLE
)
105 Rect1
.left
= Child
->WindowRect
.left
+ XOffset
;
106 Rect1
.top
= Child
->WindowRect
.top
+ YOffset
;
107 Rect1
.right
= Child
->WindowRect
.right
+ XOffset
;
108 Rect1
.bottom
= Child
->WindowRect
.bottom
+ YOffset
;
110 if (W32kIntersectRect(&Rect1
, &Rect1
, Rect
))
112 W32kUnionRectWithRgn(ClipRgn
, &Rect1
);
115 ChildListEntry
= ChildListEntry
->Flink
;
121 DceGetVisRgn(HWND hWnd
, ULONG Flags
, HWND hWndChild
, ULONG CFlags
)
123 PWINDOW_OBJECT Window
;
124 PWINDOW_OBJECT Child
;
128 Window
= W32kGetWindowObject(hWnd
);
129 Child
= W32kGetWindowObject(hWndChild
);
131 if (Window
!= NULL
&& DceGetVisRect(Window
, !(Flags
& DCX_WINDOW
), &Rect
))
133 if ((VisRgn
= W32kCreateRectRgnIndirect(&Rect
)) != NULL
)
135 HRGN ClipRgn
= W32kCreateRectRgn(0, 0, 0, 0);
136 INT XOffset
, YOffset
;
140 if (Flags
& DCX_CLIPCHILDREN
&&
141 !IsListEmpty(&Window
->ChildrenListHead
))
143 if (Flags
& DCX_WINDOW
)
145 XOffset
= Window
->ClientRect
.left
-
146 Window
->WindowRect
.left
;
147 YOffset
= Window
->ClientRect
.top
-
148 Window
->WindowRect
.top
;
152 XOffset
= YOffset
= 0;
154 DceAddClipRects(Window
, NULL
, ClipRgn
, &Rect
,
158 if (CFlags
& DCX_CLIPCHILDREN
&& Child
&&
159 !IsListEmpty(&Child
->ChildrenListHead
))
161 if (Flags
& DCX_WINDOW
)
163 XOffset
= Window
->ClientRect
.left
-
164 Window
->WindowRect
.left
;
165 YOffset
= Window
->ClientRect
.top
-
166 Window
->WindowRect
.top
;
170 XOffset
= YOffset
= 0;
173 XOffset
+= Child
->ClientRect
.left
;
174 YOffset
+= Child
->ClientRect
.top
;
176 DceAddClipRects(Child
, NULL
, ClipRgn
, &Rect
,
180 if (Flags
& DCX_WINDOW
)
182 XOffset
= -Window
->WindowRect
.left
;
183 YOffset
= -Window
->WindowRect
.top
;
187 XOffset
= -Window
->ClientRect
.left
;
188 YOffset
= -Window
->ClientRect
.top
;
191 if (Flags
& DCX_CLIPSIBLINGS
&& Window
->Parent
!= NULL
)
193 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
194 &Rect
, XOffset
, YOffset
);
197 while (Window
->Style
& WS_CHILD
)
199 Window
= Window
->Parent
;
200 XOffset
-= Window
->ClientRect
.left
;
201 YOffset
-= Window
->ClientRect
.top
;
202 if (Window
->Style
& WS_CLIPSIBLINGS
&&
203 Window
->Parent
!= NULL
)
205 DceAddClipRects(Window
->Parent
, Window
, ClipRgn
,
206 &Rect
, XOffset
, YOffset
);
210 W32kCombineRgn(VisRgn
, VisRgn
, ClipRgn
, RGN_DIFF
);
211 W32kDeleteObject(ClipRgn
);
215 W32kDeleteObject(VisRgn
);
222 VisRgn
= W32kCreateRectRgn(0, 0, 0, 0);
224 W32kReleaseWindowObject(Window
);
225 W32kReleaseWindowObject(Child
);
230 NtUserReleaseDC(HWND hWnd
, HDC hDc
)
237 NtUserGetDC(HWND hWnd
)
240 return NtUserGetDCEx(0, 0, DCX_CACHE
| DCX_WINDOW
);
241 return NtUserGetDCEx(hWnd
, 0, DCX_USESTYLE
);
245 NtUserGetDCEx(HWND hWnd
, HANDLE hRegion
, ULONG Flags
)
251 BOOL bUpdateVisRgn
= TRUE
;
252 BOOL bUpdateClipOrigin
= FALSE
;
254 PWINDOW_OBJECT Window
;
256 DPRINT("hWnd %04x, hRegion %04x, Flags %08x\n", hWnd
, hRegion
, (unsigned)Flags
);
258 if (!hWnd
) hWnd
= W32kGetDesktopWindow();
259 if (!(Window
= W32kGetWindowObject(hWnd
))) return 0;
263 if (Flags
& (DCX_WINDOW
| DCX_PARENTCLIP
)) Flags
|= DCX_CACHE
;
265 if (Flags
& DCX_USESTYLE
)
267 Flags
&= ~(DCX_CLIPCHILDREN
| DCX_CLIPSIBLINGS
| DCX_PARENTCLIP
);
269 if(Window
->Style
& WS_CLIPSIBLINGS
)
270 Flags
|= DCX_CLIPSIBLINGS
;
272 if (!(Flags
& DCX_WINDOW
))
274 if (Window
->ExStyle
& CS_PARENTDC
) Flags
|= DCX_PARENTCLIP
;
276 if (Window
->Style
& WS_CLIPCHILDREN
&&
277 !(Window
->Style
& WS_MINIMIZE
)) Flags
|= DCX_CLIPCHILDREN
;
278 if (!Window
->dce
) Flags
|= DCX_CACHE
;
282 if (Flags
& DCX_WINDOW
) Flags
&= ~DCX_CLIPCHILDREN
;
284 parent
= W32kGetParentWindow(hWnd
);
285 if (!parent
|| (parent
== W32kGetDesktopWindow()))
286 Flags
= (Flags
& ~DCX_PARENTCLIP
) | DCX_CLIPSIBLINGS
;
288 // it seems parent clip is ignored when clipping siblings or children
289 if (Flags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
)) Flags
&= ~DCX_PARENTCLIP
;
291 if(Flags
& DCX_PARENTCLIP
)
293 LONG parent_style
= NtUserGetWindowLong(parent
, GWL_STYLE
);
294 if((Window
->Style
& WS_VISIBLE
) && (parent_style
& WS_VISIBLE
))
296 Flags
&= ~DCX_CLIPCHILDREN
;
297 if (parent_style
& WS_CLIPSIBLINGS
) Flags
|= DCX_CLIPSIBLINGS
;
301 // find a suitable DCE
303 dcxFlags
= Flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
304 DCX_CACHE
| DCX_WINDOW
);
306 if (Flags
& DCX_CACHE
)
311 dceEmpty
= dceUnused
= NULL
;
313 /* Strategy: First, we attempt to find a non-empty but unused DCE with
314 * compatible flags. Next, we look for an empty entry. If the cache is
315 * full we have to purge one of the unused entries.
318 for (dce
= firstDCE
; (dce
); dce
= dce
->next
)
320 if ((dce
->DCXflags
& (DCX_CACHE
| DCX_DCEBUSY
)) == DCX_CACHE
)
324 if (dce
->DCXflags
& DCX_DCEEMPTY
)
327 if ((dce
->hwndCurrent
== hWnd
) &&
328 ((dce
->DCXflags
& (DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
329 DCX_CACHE
| DCX_WINDOW
| DCX_PARENTCLIP
)) == dcxFlags
))
331 DPRINT("Found valid %08x dce [%04x], flags %08x\n",
332 (unsigned)dce
, hWnd
, (unsigned)dcxFlags
);
333 bUpdateVisRgn
= FALSE
;
334 bUpdateClipOrigin
= TRUE
;
340 if (!dce
) dce
= (dceEmpty
) ? dceEmpty
: dceUnused
;
342 // if there's no dce empty or unused, allocate a new one
345 hdce
= DCEOBJ_AllocDCE();
350 dce
= DCEOBJ_LockDCE(hdce
);
351 dce
->type
= DCE_CACHE_DC
;
352 dce
->hDC
= W32kCreateDC(L
"DISPLAY", NULL
, NULL
, NULL
);
358 if (dce
&& dce
->hwndCurrent
== hWnd
)
360 DPRINT("skipping hVisRgn update\n");
361 bUpdateVisRgn
= FALSE
; // updated automatically, via DCHook()
370 if (!(Flags
& (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
))) hRegion
= 0;
372 if (((Flags
^ dce
->DCXflags
) & (DCX_INTERSECTRGN
| DCX_EXCLUDERGN
)) &&
373 (dce
->hClipRgn
!= hRegion
))
375 // if the extra clip region has changed, get rid of the old one
376 /* DCE_DeleteClipRgn(dce); */
379 dce
->hwndCurrent
= hWnd
;
380 dce
->hClipRgn
= hRegion
;
381 dce
->DCXflags
= Flags
& (DCX_PARENTCLIP
| DCX_CLIPSIBLINGS
| DCX_CLIPCHILDREN
|
382 DCX_CACHE
| DCX_WINDOW
| DCX_WINDOWPAINT
|
383 DCX_KEEPCLIPRGN
| DCX_INTERSECTRGN
| DCX_EXCLUDERGN
);
384 dce
->DCXflags
|= DCX_DCEBUSY
;
385 dce
->DCXflags
&= ~DCX_DCEDIRTY
;
388 /* if (bUpdateVisRgn) SetHookFlags(hdc, DCHF_INVALIDATEVISRGN); // force update */
390 /* if (!USER_Driver.pGetDC(hWnd, hdc, hRegion, Flags)) hdc = 0; */
392 DPRINT("(%04x,%04x,0x%lx): returning %04x\n", hWnd
, hRegion
, Flags
, hdc
);
395 /* WIN_ReleasePtr(Window); */