31fc15350388f1a0abe49f01d6f840bedeedd22b
[reactos.git] / subsys / win32k / ntuser / vis.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:          Visibility computations
24  * FILE:             subsys/win32k/ntuser/vis.c
25  * PROGRAMMER:       Ge van Geldorp (ge@gse.nl)
26  */
27
28 #include <win32k/win32k.h>
29 #include <include/painting.h>
30 #include <include/rect.h>
31 #include <include/vis.h>
32
33
34 #define NDEBUG
35 #include <win32k/debug1.h>
36 #include <debug.h>
37
38 BOOL STATIC FASTCALL
39 VIS_GetVisRect(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
40                BOOLEAN ClientArea, RECT* Rect)
41 {
42   PWINDOW_OBJECT DesktopWindow;
43
44   if (ClientArea)
45     {
46       *Rect = Window->ClientRect;
47     }
48   else
49     {
50       *Rect = Window->WindowRect;
51     }
52
53   if (0 == (Window->Style & WS_VISIBLE))
54     {
55       NtGdiSetEmptyRect(Rect);
56
57       return FALSE;
58     }
59
60   if (Window->Self == Desktop->DesktopWindow)
61     {
62       return TRUE;
63     }
64
65   if (0 != (Window->Style & WS_CHILD))
66     {
67       do
68         {
69           Window = Window->Parent;
70           if (WS_VISIBLE != (Window->Style & (WS_ICONIC | WS_VISIBLE)))
71             {
72               NtGdiSetEmptyRect(Rect);
73               return FALSE;
74             }
75           if (! NtGdiIntersectRect(Rect, Rect, &(Window->ClientRect)))
76             {
77               return FALSE;
78             }
79         }
80       while (0 != (Window->Style & WS_CHILD));
81     }
82
83   DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
84   if (NULL == DesktopWindow)
85     {
86       ASSERT(FALSE);
87       return FALSE;
88     }
89
90   if (! NtGdiIntersectRect(Rect, Rect, &(DesktopWindow->ClientRect)))
91     {
92       IntReleaseWindowObject(DesktopWindow);
93       return FALSE;
94     }
95   IntReleaseWindowObject(DesktopWindow);
96
97   return TRUE;
98 }
99
100 STATIC BOOL FASTCALL
101 VIS_AddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End, 
102                  HRGN ClipRgn, PRECT Rect)
103 {
104   PWINDOW_OBJECT Child;
105   RECT Intersect;
106
107   ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
108   Child = Parent->FirstChild;
109   while (Child)
110   {
111     if (Child == End)
112     {
113       ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
114       return TRUE;
115     }
116     
117     if (Child->Style & WS_VISIBLE)
118     {
119       if (NtGdiIntersectRect(&Intersect, &Child->WindowRect, Rect))
120       {
121         UnsafeIntUnionRectWithRgn(ClipRgn, &Child->WindowRect);
122       }
123     }
124     
125     Child = Child->NextSibling;
126   }
127
128   ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
129
130   return FALSE;
131 }
132
133 HRGN FASTCALL
134 VIS_ComputeVisibleRegion(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
135                          BOOLEAN ClientArea, BOOLEAN ClipChildren,
136                          BOOLEAN ClipSiblings)
137 {
138   HRGN VisRgn;
139   RECT Rect;
140   HRGN ClipRgn;
141   PWINDOW_OBJECT DesktopWindow;
142   INT LeftOffset, TopOffset;
143
144   DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
145   if (NULL == DesktopWindow)
146     {
147       ASSERT(FALSE);
148       return NULL;
149     }
150
151   if (VIS_GetVisRect(Desktop, Window, ClientArea, &Rect))
152     {
153       VisRgn = UnsafeIntCreateRectRgnIndirect(&Rect);
154       if (NULL != VisRgn)
155         {
156           if (ClientArea)
157             {
158               LeftOffset = Window->ClientRect.left;
159               TopOffset = Window->ClientRect.top;
160             }
161           else
162             {
163               LeftOffset = Window->WindowRect.left;
164               TopOffset = Window->WindowRect.top;
165             }
166
167           ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
168
169           if (ClipRgn != NULL)
170             {
171               if (ClipChildren && Window->FirstChild)
172                 {
173                   VIS_AddClipRects(Window, NULL, ClipRgn, &Rect);
174                 }
175
176               if (ClipSiblings && 0 != (Window->Style & WS_CHILD))
177                 {
178                   VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect);
179                 }
180               
181               while (0 != (Window->Style & WS_CHILD))
182                 {
183                   if (0 != (Window->Style & WS_CLIPSIBLINGS))
184                     {
185                       VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect);
186                     }
187                   Window = Window->Parent;
188                 }
189
190               VIS_AddClipRects(DesktopWindow, Window, ClipRgn, &Rect);
191
192               NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
193               NtGdiDeleteObject(ClipRgn);
194               NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset);
195             }
196           else
197             {
198               NtGdiDeleteObject(VisRgn);
199               VisRgn = NULL;
200             }
201         }
202     }
203   else
204     {
205       VisRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
206     }
207
208   IntReleaseWindowObject(DesktopWindow);
209
210   return VisRgn;
211 }
212
213 /* FIXME: to be replaced by a normal window proc in CSRSS */
214 VOID FASTCALL
215 VIS_RepaintDesktop(HWND Desktop, HRGN RepaintRgn)
216 {
217   HDC dc = NtUserGetDC(Desktop);
218   HBRUSH DesktopBrush = NtGdiCreateSolidBrush(RGB(58, 110, 165));
219   NtGdiFillRgn(dc, RepaintRgn, DesktopBrush);
220   NtGdiDeleteObject(DesktopBrush);
221   NtUserReleaseDC(Desktop, dc);
222 }
223
224
225 static VOID FASTCALL
226 GetUncoveredArea(HRGN Uncovered, PWINDOW_OBJECT Parent, PWINDOW_OBJECT TargetChild,
227                  BOOL IncludeTarget)
228 {
229   PWINDOW_OBJECT Child;
230   BOOL Passed;
231   HRGN Covered;
232
233   Passed = FALSE;
234   ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
235   Child = Parent->FirstChild;
236   while (! Passed && Child)
237     {
238       if (0 != (Child->Style & WS_VISIBLE) && (Child != TargetChild || IncludeTarget))
239         {
240           Covered = UnsafeIntCreateRectRgnIndirect(&Child->WindowRect);
241           NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF);
242           NtGdiDeleteObject(Covered);
243         }
244       if (Child == TargetChild)
245         {
246           Passed = TRUE;
247         }
248       Child = Child->NextSibling;
249     }
250   ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
251 }
252  
253
254 VOID FASTCALL
255 VIS_WindowLayoutChanged(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
256                         HRGN NewlyExposed)
257 {
258   PWINDOW_OBJECT DesktopWindow;
259   PWINDOW_OBJECT Parent;
260   PWINDOW_OBJECT Sibling;
261   PWINDOW_OBJECT TopLevel;
262   HRGN Uncovered;
263   HRGN Repaint;
264   HRGN DirtyRgn;
265   HRGN ExposedWindow;
266   HRGN Covered;
267   INT RgnType;
268   POINT Offset;
269
270   DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
271   Uncovered = UnsafeIntCreateRectRgnIndirect(&DesktopWindow->WindowRect);
272
273   if (Window->Style & WS_CHILD)
274     {
275       /* Determine our toplevel window */
276       TopLevel = Window;
277       while (TopLevel->Style & WS_CHILD)
278         {
279           TopLevel = TopLevel->Parent;
280         }
281
282       GetUncoveredArea(Uncovered, DesktopWindow, TopLevel, FALSE);
283       Parent = Window->Parent;
284     }
285   else
286     {
287       Parent = DesktopWindow;
288     }
289   GetUncoveredArea(Uncovered, Parent, Window, TRUE);
290
291   ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
292   Sibling = Window->NextSibling;
293   while (Sibling)
294     {
295       if (0 != (Sibling->Style & WS_VISIBLE))
296         {
297           Offset.x = - Sibling->WindowRect.left;
298           Offset.y = - Sibling->WindowRect.top;
299           DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Sibling->WindowRect, &Offset);
300           Offset.x = Window->WindowRect.left - Sibling->WindowRect.left;
301           Offset.y = Window->WindowRect.top - Sibling->WindowRect.top;
302           ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset);
303           RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND);
304           if (NULLREGION != RgnType && ERROR != RgnType)
305             {
306               PaintRedrawWindow(Sibling, NULL, DirtyRgn,
307                                 RDW_INVALIDATE | RDW_FRAME | RDW_ERASE
308                                 | RDW_ALLCHILDREN, RDW_EX_XYWINDOW);
309             }
310           Covered = UnsafeIntCreateRectRgnIndirect(&Sibling->WindowRect);
311           NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF);
312           NtGdiDeleteObject(Covered);
313           NtGdiDeleteObject(ExposedWindow);
314           NtGdiDeleteObject(DirtyRgn);
315         }
316
317       Sibling = Sibling->NextSibling;
318     }
319   ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
320
321   if (Window->Style & WS_CHILD)
322     {
323       Offset.x = - Parent->WindowRect.left;
324       Offset.y = - Parent->WindowRect.top;
325       DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Parent->WindowRect, &Offset);
326       Offset.x = Window->WindowRect.left - Parent->WindowRect.left;
327       Offset.y = Window->WindowRect.top - Parent->WindowRect.top;
328       ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset);
329       RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND);
330       if (NULLREGION != RgnType && ERROR != RgnType)
331         {
332           PaintRedrawWindow(Parent, NULL, DirtyRgn,
333                             RDW_INVALIDATE | RDW_FRAME | RDW_ERASE
334                             | RDW_NOCHILDREN, RDW_EX_XYWINDOW);
335         }
336       NtGdiDeleteObject(ExposedWindow);
337       NtGdiDeleteObject(DirtyRgn);
338     }
339   else
340     {
341       Repaint = NtGdiCreateRectRgn(0, 0, 0, 0);
342       NtGdiCombineRgn(Repaint, NewlyExposed, NULL, RGN_COPY);
343       NtGdiOffsetRgn(Repaint, Window->WindowRect.left, Window->WindowRect.top);
344       NtGdiCombineRgn(Repaint, Repaint, Uncovered, RGN_AND);
345       VIS_RepaintDesktop(DesktopWindow->Self, Repaint);
346       NtGdiDeleteObject(Repaint);
347     }
348
349   NtGdiDeleteObject(Uncovered);
350 }
351
352 /* EOF */