update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / vis.c
diff --git a/subsys/win32k/ntuser/vis.c b/subsys/win32k/ntuser/vis.c
new file mode 100644 (file)
index 0000000..31fc153
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS kernel
+ * PURPOSE:          Visibility computations
+ * FILE:             subsys/win32k/ntuser/vis.c
+ * PROGRAMMER:       Ge van Geldorp (ge@gse.nl)
+ */
+
+#include <win32k/win32k.h>
+#include <include/painting.h>
+#include <include/rect.h>
+#include <include/vis.h>
+
+
+#define NDEBUG
+#include <win32k/debug1.h>
+#include <debug.h>
+
+BOOL STATIC FASTCALL
+VIS_GetVisRect(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
+               BOOLEAN ClientArea, RECT* Rect)
+{
+  PWINDOW_OBJECT DesktopWindow;
+
+  if (ClientArea)
+    {
+      *Rect = Window->ClientRect;
+    }
+  else
+    {
+      *Rect = Window->WindowRect;
+    }
+
+  if (0 == (Window->Style & WS_VISIBLE))
+    {
+      NtGdiSetEmptyRect(Rect);
+
+      return FALSE;
+    }
+
+  if (Window->Self == Desktop->DesktopWindow)
+    {
+      return TRUE;
+    }
+
+  if (0 != (Window->Style & WS_CHILD))
+    {
+      do
+       {
+         Window = Window->Parent;
+         if (WS_VISIBLE != (Window->Style & (WS_ICONIC | WS_VISIBLE)))
+           {
+             NtGdiSetEmptyRect(Rect);
+             return FALSE;
+           }
+         if (! NtGdiIntersectRect(Rect, Rect, &(Window->ClientRect)))
+           {
+             return FALSE;
+           }
+       }
+      while (0 != (Window->Style & WS_CHILD));
+    }
+
+  DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
+  if (NULL == DesktopWindow)
+    {
+      ASSERT(FALSE);
+      return FALSE;
+    }
+
+  if (! NtGdiIntersectRect(Rect, Rect, &(DesktopWindow->ClientRect)))
+    {
+      IntReleaseWindowObject(DesktopWindow);
+      return FALSE;
+    }
+  IntReleaseWindowObject(DesktopWindow);
+
+  return TRUE;
+}
+
+STATIC BOOL FASTCALL
+VIS_AddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End, 
+                HRGN ClipRgn, PRECT Rect)
+{
+  PWINDOW_OBJECT Child;
+  RECT Intersect;
+
+  ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
+  Child = Parent->FirstChild;
+  while (Child)
+  {
+    if (Child == End)
+    {
+      ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
+      return TRUE;
+    }
+    
+    if (Child->Style & WS_VISIBLE)
+    {
+      if (NtGdiIntersectRect(&Intersect, &Child->WindowRect, Rect))
+      {
+        UnsafeIntUnionRectWithRgn(ClipRgn, &Child->WindowRect);
+      }
+    }
+    
+    Child = Child->NextSibling;
+  }
+
+  ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
+
+  return FALSE;
+}
+
+HRGN FASTCALL
+VIS_ComputeVisibleRegion(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
+                         BOOLEAN ClientArea, BOOLEAN ClipChildren,
+                         BOOLEAN ClipSiblings)
+{
+  HRGN VisRgn;
+  RECT Rect;
+  HRGN ClipRgn;
+  PWINDOW_OBJECT DesktopWindow;
+  INT LeftOffset, TopOffset;
+
+  DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
+  if (NULL == DesktopWindow)
+    {
+      ASSERT(FALSE);
+      return NULL;
+    }
+
+  if (VIS_GetVisRect(Desktop, Window, ClientArea, &Rect))
+    {
+      VisRgn = UnsafeIntCreateRectRgnIndirect(&Rect);
+      if (NULL != VisRgn)
+       {
+         if (ClientArea)
+           {
+             LeftOffset = Window->ClientRect.left;
+             TopOffset = Window->ClientRect.top;
+           }
+         else
+           {
+             LeftOffset = Window->WindowRect.left;
+             TopOffset = Window->WindowRect.top;
+           }
+
+         ClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
+
+         if (ClipRgn != NULL)
+           {
+             if (ClipChildren && Window->FirstChild)
+               {
+                 VIS_AddClipRects(Window, NULL, ClipRgn, &Rect);
+               }
+
+             if (ClipSiblings && 0 != (Window->Style & WS_CHILD))
+               {
+                 VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect);
+               }
+             
+             while (0 != (Window->Style & WS_CHILD))
+               {
+                 if (0 != (Window->Style & WS_CLIPSIBLINGS))
+                   {
+                     VIS_AddClipRects(Window->Parent, Window, ClipRgn, &Rect);
+                   }
+                 Window = Window->Parent;
+               }
+
+             VIS_AddClipRects(DesktopWindow, Window, ClipRgn, &Rect);
+
+             NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
+             NtGdiDeleteObject(ClipRgn);
+             NtGdiOffsetRgn(VisRgn, -LeftOffset, -TopOffset);
+           }
+         else
+           {
+             NtGdiDeleteObject(VisRgn);
+             VisRgn = NULL;
+           }
+       }
+    }
+  else
+    {
+      VisRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
+    }
+
+  IntReleaseWindowObject(DesktopWindow);
+
+  return VisRgn;
+}
+
+/* FIXME: to be replaced by a normal window proc in CSRSS */
+VOID FASTCALL
+VIS_RepaintDesktop(HWND Desktop, HRGN RepaintRgn)
+{
+  HDC dc = NtUserGetDC(Desktop);
+  HBRUSH DesktopBrush = NtGdiCreateSolidBrush(RGB(58, 110, 165));
+  NtGdiFillRgn(dc, RepaintRgn, DesktopBrush);
+  NtGdiDeleteObject(DesktopBrush);
+  NtUserReleaseDC(Desktop, dc);
+}
+
+
+static VOID FASTCALL
+GetUncoveredArea(HRGN Uncovered, PWINDOW_OBJECT Parent, PWINDOW_OBJECT TargetChild,
+                 BOOL IncludeTarget)
+{
+  PWINDOW_OBJECT Child;
+  BOOL Passed;
+  HRGN Covered;
+
+  Passed = FALSE;
+  ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
+  Child = Parent->FirstChild;
+  while (! Passed && Child)
+    {
+      if (0 != (Child->Style & WS_VISIBLE) && (Child != TargetChild || IncludeTarget))
+       {
+         Covered = UnsafeIntCreateRectRgnIndirect(&Child->WindowRect);
+         NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF);
+         NtGdiDeleteObject(Covered);
+       }
+      if (Child == TargetChild)
+       {
+         Passed = TRUE;
+       }
+      Child = Child->NextSibling;
+    }
+  ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
+}
+
+VOID FASTCALL
+VIS_WindowLayoutChanged(PDESKTOP_OBJECT Desktop, PWINDOW_OBJECT Window,
+                        HRGN NewlyExposed)
+{
+  PWINDOW_OBJECT DesktopWindow;
+  PWINDOW_OBJECT Parent;
+  PWINDOW_OBJECT Sibling;
+  PWINDOW_OBJECT TopLevel;
+  HRGN Uncovered;
+  HRGN Repaint;
+  HRGN DirtyRgn;
+  HRGN ExposedWindow;
+  HRGN Covered;
+  INT RgnType;
+  POINT Offset;
+
+  DesktopWindow = IntGetWindowObject(Desktop->DesktopWindow);
+  Uncovered = UnsafeIntCreateRectRgnIndirect(&DesktopWindow->WindowRect);
+
+  if (Window->Style & WS_CHILD)
+    {
+      /* Determine our toplevel window */
+      TopLevel = Window;
+      while (TopLevel->Style & WS_CHILD)
+       {
+         TopLevel = TopLevel->Parent;
+       }
+
+      GetUncoveredArea(Uncovered, DesktopWindow, TopLevel, FALSE);
+      Parent = Window->Parent;
+    }
+  else
+    {
+      Parent = DesktopWindow;
+    }
+  GetUncoveredArea(Uncovered, Parent, Window, TRUE);
+
+  ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
+  Sibling = Window->NextSibling;
+  while (Sibling)
+    {
+      if (0 != (Sibling->Style & WS_VISIBLE))
+       {
+         Offset.x = - Sibling->WindowRect.left;
+         Offset.y = - Sibling->WindowRect.top;
+         DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Sibling->WindowRect, &Offset);
+         Offset.x = Window->WindowRect.left - Sibling->WindowRect.left;
+         Offset.y = Window->WindowRect.top - Sibling->WindowRect.top;
+         ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset);
+         RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND);
+         if (NULLREGION != RgnType && ERROR != RgnType)
+           {
+             PaintRedrawWindow(Sibling, NULL, DirtyRgn,
+                               RDW_INVALIDATE | RDW_FRAME | RDW_ERASE
+                               | RDW_ALLCHILDREN, RDW_EX_XYWINDOW);
+           }
+         Covered = UnsafeIntCreateRectRgnIndirect(&Sibling->WindowRect);
+         NtGdiCombineRgn(Uncovered, Uncovered, Covered, RGN_DIFF);
+         NtGdiDeleteObject(Covered);
+         NtGdiDeleteObject(ExposedWindow);
+         NtGdiDeleteObject(DirtyRgn);
+       }
+
+      Sibling = Sibling->NextSibling;
+    }
+  ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
+
+  if (Window->Style & WS_CHILD)
+    {
+      Offset.x = - Parent->WindowRect.left;
+      Offset.y = - Parent->WindowRect.top;
+      DirtyRgn = REGION_CropRgn(NULL, Uncovered, &Parent->WindowRect, &Offset);
+      Offset.x = Window->WindowRect.left - Parent->WindowRect.left;
+      Offset.y = Window->WindowRect.top - Parent->WindowRect.top;
+      ExposedWindow = REGION_CropRgn(NULL, NewlyExposed, NULL, &Offset);
+      RgnType = NtGdiCombineRgn(DirtyRgn, DirtyRgn, ExposedWindow, RGN_AND);
+      if (NULLREGION != RgnType && ERROR != RgnType)
+       {
+         PaintRedrawWindow(Parent, NULL, DirtyRgn,
+                           RDW_INVALIDATE | RDW_FRAME | RDW_ERASE
+                           | RDW_NOCHILDREN, RDW_EX_XYWINDOW);
+       }
+      NtGdiDeleteObject(ExposedWindow);
+      NtGdiDeleteObject(DirtyRgn);
+    }
+  else
+    {
+      Repaint = NtGdiCreateRectRgn(0, 0, 0, 0);
+      NtGdiCombineRgn(Repaint, NewlyExposed, NULL, RGN_COPY);
+      NtGdiOffsetRgn(Repaint, Window->WindowRect.left, Window->WindowRect.top);
+      NtGdiCombineRgn(Repaint, Repaint, Uncovered, RGN_AND);
+      VIS_RepaintDesktop(DesktopWindow->Self, Repaint);
+      NtGdiDeleteObject(Repaint);
+    }
+
+  NtGdiDeleteObject(Uncovered);
+}
+
+/* EOF */