update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / windc.c
1 /*
2  *  ReactOS W32 Subsystem
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  */
19 /* $Id$
20  *
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)
26  * REVISION HISTORY:
27  *       06-06-2001  CSH  Created
28  */
29
30 /* INCLUDES ******************************************************************/
31
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>
43 #include <include/vis.h>
44
45 #define NDEBUG
46 #include <debug.h>
47
48 /* GLOBALS *******************************************************************/
49
50 static PDCE FirstDce = NULL;
51
52 #define DCX_CACHECOMPAREMASK (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | \
53                               DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)
54
55 /* FUNCTIONS *****************************************************************/
56
57 HRGN STDCALL
58 DceGetVisRgn(HWND hWnd, ULONG Flags, HWND hWndChild, ULONG CFlags)
59 {
60   PWINDOW_OBJECT Window;
61   PWINDOW_OBJECT Child;
62   HRGN VisRgn;
63   HRGN VisChild;
64   HRGN ChildRect;
65   HRGN ParentRect;
66
67   Window = IntGetWindowObject(hWnd);
68
69   if (NULL == Window)
70     {
71       return NULL;
72     }
73
74   VisRgn = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop, Window,
75                                     0 == (Flags & DCX_WINDOW),
76                                     0 != (Flags & DCX_CLIPCHILDREN),
77                                     0 != (Flags & DCX_CLIPSIBLINGS));
78   if (NULL != hWndChild && 0 != (CFlags & DCX_CLIPCHILDREN))
79     {
80       /* We need to filter out the child windows of hWndChild */
81       Child = IntGetWindowObject(hWnd);
82       if (NULL != Child)
83         {
84     if (Child->FirstChild)
85             {
86               /* Compute the visible region of the child */
87               VisChild = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
88                                                   Child, FALSE, TRUE, FALSE);
89               /* If the child doesn't obscure the whole window, we need to
90                  extend it. First compute the difference between window and child */
91               ChildRect = UnsafeIntCreateRectRgnIndirect(&(Child->ClientRect));
92               if (0 == (Flags & DCX_WINDOW))
93                 {
94                   ParentRect = UnsafeIntCreateRectRgnIndirect(&(Window->ClientRect));
95                 }
96               else
97                 {
98                   ParentRect = UnsafeIntCreateRectRgnIndirect(&(Window->WindowRect));
99                 }
100               NtGdiCombineRgn(ChildRect, ParentRect, ChildRect, RGN_DIFF);
101
102               /* Now actually extend the child by adding the difference */
103               NtGdiCombineRgn(VisChild, VisChild, ChildRect, RGN_OR);
104
105               /* Clip the childs children */
106               NtGdiCombineRgn(VisRgn, VisRgn, VisChild, RGN_AND);
107             }
108           IntReleaseWindowObject(Child);
109         }
110     }
111
112   IntReleaseWindowObject(Window);
113
114   return VisRgn;
115 }
116
117 INT STDCALL
118 NtUserReleaseDC(HWND hWnd, HDC hDc)
119 {
120   return 1;  
121 }
122
123 HDC STDCALL
124 NtUserGetDC(HWND hWnd)
125 {
126     return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
127 }
128
129 PDCE FASTCALL DceAllocDCE(HWND hWnd, DCE_TYPE Type)
130 {
131   HDCE DceHandle;
132   DCE* Dce;
133
134   DceHandle = DCEOBJ_AllocDCE();
135   Dce = DCEOBJ_LockDCE(DceHandle);
136   Dce->hDC = NtGdiCreateDC(L"DISPLAY", NULL, NULL, NULL);
137   Dce->hwndCurrent = hWnd;
138   Dce->hClipRgn = NULL;
139   Dce->next = FirstDce;
140   FirstDce = Dce;
141
142   if (Type != DCE_CACHE_DC)
143     {
144       Dce->DCXFlags = DCX_DCEBUSY;
145       if (hWnd != NULL)
146         {
147           PWINDOW_OBJECT WindowObject;
148
149           WindowObject = IntGetWindowObject(hWnd);
150           if (WindowObject->Style & WS_CLIPCHILDREN)
151             {
152               Dce->DCXFlags |= DCX_CLIPCHILDREN;
153             }
154           if (WindowObject->Style & WS_CLIPSIBLINGS)
155             {
156               Dce->DCXFlags |= DCX_CLIPSIBLINGS;
157             }
158           IntReleaseWindowObject(WindowObject);
159         }
160     }
161   else
162     {
163       Dce->DCXFlags = DCX_CACHE | DCX_DCEEMPTY;
164     }
165
166   return(Dce);
167 }
168
169 VOID STATIC STDCALL
170 DceSetDrawable(PWINDOW_OBJECT WindowObject, HDC hDC, ULONG Flags,
171                BOOL SetClipOrigin)
172 {
173   DC *dc = DC_LockDc(hDC);
174   if (WindowObject == NULL)
175     {
176       dc->w.DCOrgX = 0;
177       dc->w.DCOrgY = 0;
178     }
179   else
180     {
181       if (Flags & DCX_WINDOW)
182         {
183           dc->w.DCOrgX = WindowObject->WindowRect.left;
184           dc->w.DCOrgY = WindowObject->WindowRect.top;
185         }
186       else
187         {
188           dc->w.DCOrgX = WindowObject->ClientRect.left;
189           dc->w.DCOrgY = WindowObject->ClientRect.top;
190         }
191     }
192   DC_UnlockDc(hDC);
193 }
194
195
196 STATIC VOID FASTCALL
197 DceDeleteClipRgn(DCE* Dce)
198 {
199   Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
200
201   if (Dce->DCXFlags & DCX_KEEPCLIPRGN )
202     {
203       Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
204     }
205   else if (Dce->hClipRgn > (HRGN) 1)
206     {
207       NtGdiDeleteObject(Dce->hClipRgn);
208     }
209
210   Dce->hClipRgn = NULL;
211
212   /* make it dirty so that the vis rgn gets recomputed next time */
213   Dce->DCXFlags |= DCX_DCEDIRTY;
214 }
215
216 HDC STDCALL
217 NtUserGetDCEx(HWND hWnd, HANDLE ClipRegion, ULONG Flags)
218 {
219   PWINDOW_OBJECT Window;
220   ULONG DcxFlags;
221   DCE* Dce;
222   BOOL UpdateVisRgn = TRUE;
223   BOOL UpdateClipOrigin = FALSE;
224   HANDLE hRgnVisible = NULL;
225
226   if (NULL == hWnd)
227     {
228       Flags &= ~DCX_USESTYLE;
229       Window = NULL;
230     }
231   else if (NULL == (Window = IntGetWindowObject(hWnd)))
232     {
233       return(0);
234     }
235
236   if (NULL == Window || NULL == Window->Dce)
237     {
238       Flags |= DCX_CACHE;
239     }
240
241
242   if (Flags & DCX_USESTYLE)
243     {
244       Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
245
246       if (Window->Style & WS_CLIPSIBLINGS)
247         {
248           Flags |= DCX_CLIPSIBLINGS;
249         }
250
251       if (!(Flags & DCX_WINDOW))
252         {
253           if (Window->Class->style & CS_PARENTDC)
254             {
255               Flags |= DCX_PARENTCLIP;
256             }
257
258           if (Window->Style & WS_CLIPCHILDREN &&
259               !(Window->Style & WS_MINIMIZE))
260             {
261               Flags |= DCX_CLIPCHILDREN;
262             }
263         }
264       else
265         {
266           Flags |= DCX_CACHE;
267         }
268     }
269
270   if (Flags & DCX_NOCLIPCHILDREN)
271     {
272       Flags |= DCX_CACHE;
273       Flags |= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
274     }
275
276   if (Flags & DCX_WINDOW)
277     {
278       Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
279     }
280
281   if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Window->Parent)
282     {
283       Flags &= ~DCX_PARENTCLIP;
284     }
285   else if (Flags & DCX_PARENTCLIP)
286     {
287       Flags |= DCX_CACHE;
288       if (!(Flags & (DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS)))
289         {
290           if ((Window->Style & WS_VISIBLE) && 
291               (Window->Parent->Style & WS_VISIBLE))
292             {
293               Flags &= ~DCX_CLIPCHILDREN;
294               if (Window->Parent->Style & WS_CLIPSIBLINGS)
295                 {
296                   Flags |= DCX_CLIPSIBLINGS;
297                 }
298             }
299         }
300     }
301
302   DcxFlags = Flags & DCX_CACHECOMPAREMASK;
303
304   if (Flags & DCX_CACHE)
305     {
306       DCE* DceEmpty = NULL;
307       DCE* DceUnused = NULL;
308
309       for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
310         {
311           if ((Dce->DCXFlags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE)
312             {
313               DceUnused = Dce;
314               if (Dce->DCXFlags & DCX_DCEEMPTY)
315                 {
316                   DceEmpty = Dce;
317                 }
318               else if (Dce->hwndCurrent == hWnd &&
319                        ((Dce->DCXFlags & DCX_CACHECOMPAREMASK) == DcxFlags))
320                 {
321                   UpdateVisRgn = FALSE;
322                   UpdateClipOrigin = TRUE;
323                   break;
324                 }
325             }
326         }
327
328       if (Dce == NULL)
329         {
330           Dce = (DceEmpty == NULL) ? DceEmpty : DceUnused;
331         }
332
333       if (Dce == NULL)
334         {
335           Dce = DceAllocDCE(NULL, DCE_CACHE_DC);
336         }
337     }
338   else
339     {
340       Dce = Window->Dce;
341       /* FIXME: Implement this. */
342       DbgBreakPoint();
343     }
344
345   if (NULL == Dce && NULL != Window)
346     {
347       IntReleaseWindowObject(Window);
348       return(NULL);
349     }
350
351   Dce->hwndCurrent = hWnd;
352   Dce->hClipRgn = NULL;
353   Dce->DCXFlags = DcxFlags | (Flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
354
355   if (0 == (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && NULL != ClipRegion)
356     {
357       NtGdiDeleteObject(ClipRegion);
358       ClipRegion = NULL;
359     }
360
361   if (NULL != Dce->hClipRgn)
362     {
363       DceDeleteClipRgn(Dce);
364     }
365
366   if (NULL != ClipRegion)
367     {
368       Dce->hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
369       NtGdiCombineRgn(Dce->hClipRgn, ClipRegion, NULL, RGN_COPY);
370       NtGdiDeleteObject(ClipRegion);
371     }
372
373   DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
374
375   if (UpdateVisRgn)
376     {
377       if (Flags & DCX_PARENTCLIP)
378         {
379           PWINDOW_OBJECT Parent;
380
381           Parent = Window->Parent;
382
383           if (Window->Style & WS_VISIBLE &&
384               !(Parent->Style & WS_MINIMIZE))
385             {
386               if (Parent->Style & WS_CLIPSIBLINGS)
387                 {
388                   DcxFlags = DCX_CLIPSIBLINGS | 
389                     (Flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
390                 }
391               else
392                 {
393                   DcxFlags = Flags & 
394                     ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
395                 }
396               hRgnVisible = DceGetVisRgn(Parent->Self, DcxFlags, 
397                                          Window->Self, Flags);
398             }
399           else
400             {
401               hRgnVisible = NtGdiCreateRectRgn(0, 0, 0, 0);
402             }
403         }
404       else
405         {
406           if (hWnd == IntGetDesktopWindow())
407             {
408               hRgnVisible = 
409                 NtGdiCreateRectRgn(0, 0, 
410                                   NtUserGetSystemMetrics(SM_CXSCREEN),
411                                   NtUserGetSystemMetrics(SM_CYSCREEN));
412             }
413           else
414             {
415               hRgnVisible = DceGetVisRgn(hWnd, Flags, 0, 0);
416             }
417         }
418
419       if (0 != (Flags & DCX_INTERSECTRGN))
420         {
421           NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_AND);
422         }
423
424       if (0 != (Flags & DCX_EXCLUDERGN))
425         {
426           NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_DIFF);
427         }
428
429       Dce->DCXFlags &= ~DCX_DCEDIRTY;
430       NtGdiSelectVisRgn(Dce->hDC, hRgnVisible);
431     }
432
433   if (hRgnVisible != NULL)
434     {
435       NtGdiDeleteObject(hRgnVisible);
436     }
437   if (NULL != Window)
438     {
439       IntReleaseWindowObject(Window);
440     }
441
442   return(Dce->hDC);
443 }
444
445 BOOL FASTCALL
446 DCE_InternalDelete(PDCE Dce)
447 {
448   PDCE PrevInList;
449
450   if (Dce == FirstDce)
451     {
452       FirstDce = Dce->next;
453       PrevInList = Dce;
454     }
455   else
456     {
457       for (PrevInList = FirstDce; NULL != PrevInList; PrevInList = PrevInList->next)
458         {
459           if (Dce == PrevInList->next)
460             {
461               PrevInList->next = Dce->next;
462               break;
463             }
464         }
465       assert(NULL != PrevInList);
466     }
467
468   return NULL != PrevInList;
469 }
470
471 HWND FASTCALL
472 IntWindowFromDC(HDC hDc)
473 {
474   DCE *Dce;
475   for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
476   {
477     if(Dce->hDC == hDc)
478     {
479       return Dce->hwndCurrent;
480     }
481   }
482   return 0;
483 }
484   
485
486 /* EOF */