611e8b62be99d1066bfa6c53b959b1ab7380c231
[reactos.git] / reactos / subsys / win32k / ntuser / windc.c
1 /* $Id: windc.c,v 1.5 2002/08/27 23:29:40 dwelch 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/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>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 static PDCE firstDCE;
29
30 /* FUNCTIONS *****************************************************************/
31
32 VOID DCE_FreeWindowDCE(HWND);
33 INT DCE_ExcludeRgn(HDC, HWND, HRGN);
34 BOOL DCE_InvalidateDCE(HWND, const PRECTL);
35
36 BOOL STATIC
37 DceGetVisRect(PWINDOW_OBJECT Window, BOOL ClientArea, RECT* Rect)
38 {
39 if (ClientArea)
40 {
41 *Rect = Window->ClientRect;
42 }
43 else
44 {
45 *Rect = Window->WindowRect;
46 }
47
48 if (Window->Style & WS_VISIBLE)
49 {
50 INT XOffset = Rect->left;
51 INT YOffset = Rect->top;
52
53 while ((Window = Window->Parent) != NULL)
54 {
55 if ((Window->Style & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE)
56 {
57 W32kSetEmptyRect(Rect);
58 return(FALSE);
59 }
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)
70 {
71 W32kSetEmptyRect(Rect);
72 return(FALSE);
73 }
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);
78 }
79 W32kOffsetRect(Rect, -XOffset, -YOffset);
80 return(TRUE);
81 }
82 W32kSetEmptyRect(Rect);
83 return(FALSE);
84 }
85
86 BOOL
87 DceAddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End,
88 HRGN ClipRgn, PRECT Rect, INT XOffset, INT YOffset)
89 {
90 PLIST_ENTRY ChildListEntry;
91 PWINDOW_OBJECT Child;
92 RECT Rect1;
93
94 ChildListEntry = Parent->ChildrenListHead.Flink;
95 while (ChildListEntry != &Parent->ChildrenListHead)
96 {
97 Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT,
98 SiblingListEntry);
99 if (Child == End)
100 {
101 return(TRUE);
102 }
103 if (Child->Style & WS_VISIBLE)
104 {
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;
109
110 if (W32kIntersectRect(&Rect1, &Rect1, Rect))
111 {
112 W32kUnionRectWithRgn(ClipRgn, &Rect1);
113 }
114 }
115 ChildListEntry = ChildListEntry->Flink;
116 }
117 return(FALSE);
118 }
119
120 HRGN
121 DceGetVisRgn(HWND hWnd, ULONG Flags, HWND hWndChild, ULONG CFlags)
122 {
123 PWINDOW_OBJECT Window;
124 PWINDOW_OBJECT Child;
125 HRGN VisRgn;
126 RECT Rect;
127
128 Window = W32kGetWindowObject(hWnd);
129 Child = W32kGetWindowObject(hWndChild);
130
131 if (Window != NULL && DceGetVisRect(Window, !(Flags & DCX_WINDOW), &Rect))
132 {
133 if ((VisRgn = W32kCreateRectRgnIndirect(&Rect)) != NULL)
134 {
135 HRGN ClipRgn = W32kCreateRectRgn(0, 0, 0, 0);
136 INT XOffset, YOffset;
137
138 if (ClipRgn != NULL)
139 {
140 if (Flags & DCX_CLIPCHILDREN &&
141 !IsListEmpty(&Window->ChildrenListHead))
142 {
143 if (Flags & DCX_WINDOW)
144 {
145 XOffset = Window->ClientRect.left -
146 Window->WindowRect.left;
147 YOffset = Window->ClientRect.top -
148 Window->WindowRect.top;
149 }
150 else
151 {
152 XOffset = YOffset = 0;
153 }
154 DceAddClipRects(Window, NULL, ClipRgn, &Rect,
155 XOffset, YOffset);
156 }
157
158 if (CFlags & DCX_CLIPCHILDREN && Child &&
159 !IsListEmpty(&Child->ChildrenListHead))
160 {
161 if (Flags & DCX_WINDOW)
162 {
163 XOffset = Window->ClientRect.left -
164 Window->WindowRect.left;
165 YOffset = Window->ClientRect.top -
166 Window->WindowRect.top;
167 }
168 else
169 {
170 XOffset = YOffset = 0;
171 }
172
173 XOffset += Child->ClientRect.left;
174 YOffset += Child->ClientRect.top;
175
176 DceAddClipRects(Child, NULL, ClipRgn, &Rect,
177 XOffset, YOffset);
178 }
179
180 if (Flags & DCX_WINDOW)
181 {
182 XOffset = -Window->WindowRect.left;
183 YOffset = -Window->WindowRect.top;
184 }
185 else
186 {
187 XOffset = -Window->ClientRect.left;
188 YOffset = -Window->ClientRect.top;
189 }
190
191 if (Flags & DCX_CLIPSIBLINGS && Window->Parent != NULL)
192 {
193 DceAddClipRects(Window->Parent, Window, ClipRgn,
194 &Rect, XOffset, YOffset);
195 }
196
197 while (Window->Style & WS_CHILD)
198 {
199 Window = Window->Parent;
200 XOffset -= Window->ClientRect.left;
201 YOffset -= Window->ClientRect.top;
202 if (Window->Style & WS_CLIPSIBLINGS &&
203 Window->Parent != NULL)
204 {
205 DceAddClipRects(Window->Parent, Window, ClipRgn,
206 &Rect, XOffset, YOffset);
207 }
208 }
209
210 W32kCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
211 W32kDeleteObject(ClipRgn);
212 }
213 else
214 {
215 W32kDeleteObject(VisRgn);
216 VisRgn = 0;
217 }
218 }
219 }
220 else
221 {
222 VisRgn = W32kCreateRectRgn(0, 0, 0, 0);
223 }
224 W32kReleaseWindowObject(Window);
225 W32kReleaseWindowObject(Child);
226 return(VisRgn);
227 }
228
229 INT STDCALL
230 NtUserReleaseDC(HWND hWnd, HDC hDc)
231 {
232
233 }
234
235 DWORD
236 STDCALL
237 NtUserGetDC(HWND hWnd)
238 {
239 if (!hWnd)
240 return NtUserGetDCEx(0, 0, DCX_CACHE | DCX_WINDOW);
241 return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE);
242 }
243
244 HDC STDCALL
245 NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
246 {
247 HDC hdc = 0;
248 HDCE hdce;
249 PDCE dce;
250 DWORD dcxFlags = 0;
251 BOOL bUpdateVisRgn = TRUE;
252 BOOL bUpdateClipOrigin = FALSE;
253 HWND parent, full;
254 PWINDOW_OBJECT Window;
255
256 DPRINT("hWnd %04x, hRegion %04x, Flags %08x\n", hWnd, hRegion, (unsigned)Flags);
257
258 if (!hWnd) hWnd = W32kGetDesktopWindow();
259 if (!(Window = W32kGetWindowObject(hWnd))) return 0;
260
261 // fixup flags
262
263 if (Flags & (DCX_WINDOW | DCX_PARENTCLIP)) Flags |= DCX_CACHE;
264
265 if (Flags & DCX_USESTYLE)
266 {
267 Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
268
269 if(Window->Style & WS_CLIPSIBLINGS)
270 Flags |= DCX_CLIPSIBLINGS;
271
272 if (!(Flags & DCX_WINDOW))
273 {
274 if (Window->ExStyle & CS_PARENTDC) Flags |= DCX_PARENTCLIP;
275
276 if (Window->Style & WS_CLIPCHILDREN &&
277 !(Window->Style & WS_MINIMIZE)) Flags |= DCX_CLIPCHILDREN;
278 if (!Window->dce) Flags |= DCX_CACHE;
279 }
280 }
281
282 if (Flags & DCX_WINDOW) Flags &= ~DCX_CLIPCHILDREN;
283
284 parent = W32kGetParentWindow(hWnd);
285 if (!parent || (parent == W32kGetDesktopWindow()))
286 Flags = (Flags & ~DCX_PARENTCLIP) | DCX_CLIPSIBLINGS;
287
288 // it seems parent clip is ignored when clipping siblings or children
289 if (Flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) Flags &= ~DCX_PARENTCLIP;
290
291 if(Flags & DCX_PARENTCLIP)
292 {
293 LONG parent_style = NtUserGetWindowLong(parent, GWL_STYLE);
294 if((Window->Style & WS_VISIBLE) && (parent_style & WS_VISIBLE))
295 {
296 Flags &= ~DCX_CLIPCHILDREN;
297 if (parent_style & WS_CLIPSIBLINGS) Flags |= DCX_CLIPSIBLINGS;
298 }
299 }
300
301 // find a suitable DCE
302
303 dcxFlags = Flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
304 DCX_CACHE | DCX_WINDOW);
305
306 if (Flags & DCX_CACHE)
307 {
308 PDCE dceEmpty;
309 PDCE dceUnused;
310
311 dceEmpty = dceUnused = NULL;
312
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.
316 */
317
318 for (dce = firstDCE; (dce); dce = dce->next)
319 {
320 if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
321 {
322 dceUnused = dce;
323
324 if (dce->DCXflags & DCX_DCEEMPTY)
325 dceEmpty = dce;
326 else
327 if ((dce->hwndCurrent == hWnd) &&
328 ((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
329 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
330 {
331 DPRINT("Found valid %08x dce [%04x], flags %08x\n",
332 (unsigned)dce, hWnd, (unsigned)dcxFlags);
333 bUpdateVisRgn = FALSE;
334 bUpdateClipOrigin = TRUE;
335 break;
336 }
337 }
338 }
339
340 if (!dce) dce = (dceEmpty) ? dceEmpty : dceUnused;
341
342 // if there's no dce empty or unused, allocate a new one
343 if (!dce)
344 {
345 hdce = DCEOBJ_AllocDCE();
346 if (hdce == NULL)
347 {
348 return 0;
349 }
350 dce = DCEOBJ_LockDCE(hdce);
351 dce->type = DCE_CACHE_DC;
352 dce->hDC = W32kCreateDC(L"DISPLAY", NULL, NULL, NULL);
353 }
354 }
355 else
356 {
357 dce = Window->dce;
358 if (dce && dce->hwndCurrent == hWnd)
359 {
360 DPRINT("skipping hVisRgn update\n");
361 bUpdateVisRgn = FALSE; // updated automatically, via DCHook()
362 }
363 }
364 if (!dce)
365 {
366 hdc = 0;
367 goto END;
368 }
369
370 if (!(Flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) hRegion = 0;
371
372 if (((Flags ^ dce->DCXflags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
373 (dce->hClipRgn != hRegion))
374 {
375 // if the extra clip region has changed, get rid of the old one
376 /* DCE_DeleteClipRgn(dce); */
377 }
378
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;
386 hdc = dce->hDC;
387
388 /* if (bUpdateVisRgn) SetHookFlags(hdc, DCHF_INVALIDATEVISRGN); // force update */
389
390 /* if (!USER_Driver.pGetDC(hWnd, hdc, hRegion, Flags)) hdc = 0; */
391
392 DPRINT("(%04x,%04x,0x%lx): returning %04x\n", hWnd, hRegion, Flags, hdc);
393
394 END:
395 /* WIN_ReleasePtr(Window); */
396 return hdc;
397 }
398
399 /* EOF */