update for HEAD-2003091401
[reactos.git] / subsys / win32k / ntuser / windc.c
index 7f34d4f..18eb07e 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ *  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
@@ -22,6 +40,7 @@
 #include <include/window.h>
 #include <include/rect.h>
 #include <include/dce.h>
+#include <include/vis.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -35,233 +54,86 @@ static PDCE FirstDce = NULL;
 
 /* FUNCTIONS *****************************************************************/
 
-VOID STATIC
-DceOffsetVisRgn(HDC hDC, HRGN hVisRgn)
-{
-  DC *dc = DC_HandleToPtr(hDC);
-  if (dc == NULL)
-    {
-      return;
-    }
-  W32kOffsetRgn(hVisRgn, dc->w.DCOrgX, dc->w.DCOrgY);
-  DC_ReleasePtr(hDC);
-}
-
-BOOL STATIC
-DceGetVisRect(PWINDOW_OBJECT Window, BOOL ClientArea, RECT* Rect)
-{
-  if (ClientArea)
-    {
-      *Rect = Window->ClientRect;
-    }
-  else
-    {
-      *Rect = Window->WindowRect;
-    }
-
-  if (Window->Style & WS_VISIBLE)
-    {
-      INT XOffset = Rect->left;
-      INT YOffset = Rect->top;
-
-      while ((Window = Window->Parent) != NULL)
-       {
-         if ((Window->Style & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE)
-           {
-             W32kSetEmptyRect(Rect);
-             return(FALSE);
-           }
-         XOffset += Window->ClientRect.left;
-         YOffset += Window->ClientRect.top;
-         W32kOffsetRect(Rect, Window->ClientRect.left, 
-                        Window->ClientRect.top);
-         if (Window->ClientRect.left >= Window->ClientRect.right ||
-             Window->ClientRect.top >= Window->ClientRect.bottom ||
-             Rect->left >= Window->ClientRect.right ||
-             Rect->right <= Window->ClientRect.left ||
-             Rect->top >= Window->ClientRect.bottom ||
-             Rect->bottom <= Window->ClientRect.top)
-           {
-             W32kSetEmptyRect(Rect);
-             return(FALSE);
-           }
-         Rect->left = max(Rect->left, Window->ClientRect.left);
-         Rect->right = min(Rect->right, Window->ClientRect.right);
-         Rect->top = max(Rect->top, Window->ClientRect.top);
-         Rect->bottom = min(Rect->bottom, Window->ClientRect.bottom);
-       }
-      W32kOffsetRect(Rect, -XOffset, -YOffset);
-      return(TRUE);
-    }
-  W32kSetEmptyRect(Rect);
-  return(FALSE);
-}
-
-BOOL
-DceAddClipRects(PWINDOW_OBJECT Parent, PWINDOW_OBJECT End, 
-               HRGN ClipRgn, PRECT Rect, INT XOffset, INT YOffset)
-{
-  PLIST_ENTRY ChildListEntry;
-  PWINDOW_OBJECT Child;
-  RECT Rect1;
-
-  ChildListEntry = Parent->ChildrenListHead.Flink;
-  while (ChildListEntry != &Parent->ChildrenListHead)
-    {
-      Child = CONTAINING_RECORD(ChildListEntry, WINDOW_OBJECT, 
-                               SiblingListEntry);
-      if (Child == End)
-       {
-         return(TRUE);
-       }
-      if (Child->Style & WS_VISIBLE)
-       {
-         Rect1.left = Child->WindowRect.left + XOffset;
-         Rect1.top = Child->WindowRect.top + YOffset;
-         Rect1.right = Child->WindowRect.right + XOffset;
-         Rect1.bottom = Child->WindowRect.bottom + YOffset;
-
-         if (W32kIntersectRect(&Rect1, &Rect1, Rect))
-           {
-             W32kUnionRectWithRgn(ClipRgn, &Rect1);
-           }
-       }
-      ChildListEntry = ChildListEntry->Flink;
-    }
-  return(FALSE);
-}
-
-HRGN 
+HRGN STDCALL
 DceGetVisRgn(HWND hWnd, ULONG Flags, HWND hWndChild, ULONG CFlags)
 {
   PWINDOW_OBJECT Window;
   PWINDOW_OBJECT Child;
   HRGN VisRgn;
-  RECT Rect;
+  HRGN VisChild;
+  HRGN ChildRect;
+  HRGN ParentRect;
 
-  Window = W32kGetWindowObject(hWnd);
-  Child = W32kGetWindowObject(hWndChild);
+  Window = IntGetWindowObject(hWnd);
 
-  if (Window != NULL && DceGetVisRect(Window, !(Flags & DCX_WINDOW), &Rect))
+  if (NULL == Window)
     {
-      if ((VisRgn = UnsafeW32kCreateRectRgnIndirect(&Rect)) != NULL)
-       {
-         HRGN ClipRgn = W32kCreateRectRgn(0, 0, 0, 0);
-         INT XOffset, YOffset;
+      return NULL;
+    }
 
-         if (ClipRgn != NULL)
+  VisRgn = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop, Window,
+                                    0 == (Flags & DCX_WINDOW),
+                                    0 != (Flags & DCX_CLIPCHILDREN),
+                                    0 != (Flags & DCX_CLIPSIBLINGS));
+  if (NULL != hWndChild && 0 != (CFlags & DCX_CLIPCHILDREN))
+    {
+      /* We need to filter out the child windows of hWndChild */
+      Child = IntGetWindowObject(hWnd);
+      if (NULL != Child)
+       {
+    if (Child->FirstChild)
            {
-             if (Flags & DCX_CLIPCHILDREN && 
-                 !IsListEmpty(&Window->ChildrenListHead))
+             /* Compute the visible region of the child */
+             VisChild = VIS_ComputeVisibleRegion(PsGetWin32Thread()->Desktop,
+                                                 Child, FALSE, TRUE, FALSE);
+             /* If the child doesn't obscure the whole window, we need to
+                 extend it. First compute the difference between window and child */
+             ChildRect = UnsafeIntCreateRectRgnIndirect(&(Child->ClientRect));
+             if (0 == (Flags & DCX_WINDOW))
                {
-                 if (Flags & DCX_WINDOW)
-                   {
-                     XOffset = Window->ClientRect.left -
-                       Window->WindowRect.left;
-                     YOffset = Window->ClientRect.top -
-                       Window->WindowRect.top;
-                   }           
-                 else
-                   {
-                     XOffset = YOffset = 0;
-                   }
-                 DceAddClipRects(Window, NULL, ClipRgn, &Rect,
-                                 XOffset, YOffset);
-               }
-
-             if (CFlags & DCX_CLIPCHILDREN && Child &&
-                 !IsListEmpty(&Child->ChildrenListHead))
-               {
-                 if (Flags & DCX_WINDOW)
-                   {
-                     XOffset = Window->ClientRect.left -
-                       Window->WindowRect.left;
-                     YOffset = Window->ClientRect.top -
-                       Window->WindowRect.top;
-                   }
-                 else
-                   {
-                     XOffset = YOffset = 0;
-                   }
-
-                 XOffset += Child->ClientRect.left;
-                 YOffset += Child->ClientRect.top;
-
-                 DceAddClipRects(Child, NULL, ClipRgn, &Rect,
-                                 XOffset, YOffset);
-               }
-
-             if (Flags & DCX_WINDOW)
-               {
-                 XOffset = -Window->WindowRect.left;
-                 YOffset = -Window->WindowRect.top;
+                 ParentRect = UnsafeIntCreateRectRgnIndirect(&(Window->ClientRect));
                }
              else
                {
-                 XOffset = -Window->ClientRect.left;
-                 YOffset = -Window->ClientRect.top;
+                 ParentRect = UnsafeIntCreateRectRgnIndirect(&(Window->WindowRect));
                }
+             NtGdiCombineRgn(ChildRect, ParentRect, ChildRect, RGN_DIFF);
 
-             if (Flags & DCX_CLIPSIBLINGS && Window->Parent != NULL)
-               {
-                 DceAddClipRects(Window->Parent, Window, ClipRgn,
-                                 &Rect, XOffset, YOffset);
-               }
-             
-             while (Window->Style & WS_CHILD)
-               {
-                 Window = Window->Parent;
-                 XOffset -= Window->ClientRect.left;
-                 YOffset -= Window->ClientRect.top;
-                 if (Window->Style & WS_CLIPSIBLINGS && 
-                     Window->Parent != NULL)
-                   {
-                     DceAddClipRects(Window->Parent, Window, ClipRgn,
-                                     &Rect, XOffset, YOffset);
-                   }
-               }
+             /* Now actually extend the child by adding the difference */
+             NtGdiCombineRgn(VisChild, VisChild, ChildRect, RGN_OR);
 
-             W32kCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
-             W32kDeleteObject(ClipRgn);
-           }
-         else
-           {
-             W32kDeleteObject(VisRgn);
-             VisRgn = 0;
+             /* Clip the childs children */
+             NtGdiCombineRgn(VisRgn, VisRgn, VisChild, RGN_AND);
            }
+         IntReleaseWindowObject(Child);
        }
     }
-  else
-    {
-      VisRgn = W32kCreateRectRgn(0, 0, 0, 0);
-    }
-  W32kReleaseWindowObject(Window);
-  W32kReleaseWindowObject(Child);
-  return(VisRgn);
+
+  IntReleaseWindowObject(Window);
+
+  return VisRgn;
 }
 
 INT STDCALL
 NtUserReleaseDC(HWND hWnd, HDC hDc)
 {
-  
+  return 1;  
 }
 
 HDC STDCALL
 NtUserGetDC(HWND hWnd)
 {
-    if (!hWnd)
-        return NtUserGetDCEx(0, 0, DCX_CACHE | DCX_WINDOW);
-    return NtUserGetDCEx(hWnd, 0, DCX_USESTYLE);
+    return NtUserGetDCEx(hWnd, NULL, NULL == hWnd ? DCX_CACHE | DCX_WINDOW : DCX_USESTYLE);
 }
 
-DCE* DceAllocDCE(HWND hWnd, DCE_TYPE Type)
+PDCE FASTCALL DceAllocDCE(HWND hWnd, DCE_TYPE Type)
 {
   HDCE DceHandle;
   DCE* Dce;
 
   DceHandle = DCEOBJ_AllocDCE();
   Dce = DCEOBJ_LockDCE(DceHandle);
-  Dce->hDC = W32kCreateDC(L"DISPLAY", NULL, NULL, NULL);
+  Dce->hDC = NtGdiCreateDC(L"DISPLAY", NULL, NULL, NULL);
   Dce->hwndCurrent = hWnd;
   Dce->hClipRgn = NULL;
   Dce->next = FirstDce;
@@ -274,7 +146,7 @@ DCE* DceAllocDCE(HWND hWnd, DCE_TYPE Type)
        {
          PWINDOW_OBJECT WindowObject;
 
-         WindowObject = W32kGetWindowObject(hWnd);
+         WindowObject = IntGetWindowObject(hWnd);
          if (WindowObject->Style & WS_CLIPCHILDREN)
            {
              Dce->DCXFlags |= DCX_CLIPCHILDREN;
@@ -283,7 +155,7 @@ DCE* DceAllocDCE(HWND hWnd, DCE_TYPE Type)
            {
              Dce->DCXFlags |= DCX_CLIPSIBLINGS;
            }
-         W32kReleaseWindowObject(WindowObject);
+         IntReleaseWindowObject(WindowObject);
        }
     }
   else
@@ -294,11 +166,11 @@ DCE* DceAllocDCE(HWND hWnd, DCE_TYPE Type)
   return(Dce);
 }
 
-VOID STATIC
+VOID STATIC STDCALL
 DceSetDrawable(PWINDOW_OBJECT WindowObject, HDC hDC, ULONG Flags,
               BOOL SetClipOrigin)
 {
-  DC *dc = DC_HandleToPtr(hDC);
+  DC *dc = DC_LockDc(hDC);
   if (WindowObject == NULL)
     {
       dc->w.DCOrgX = 0;
@@ -316,13 +188,33 @@ DceSetDrawable(PWINDOW_OBJECT WindowObject, HDC hDC, ULONG Flags,
          dc->w.DCOrgX = WindowObject->ClientRect.left;
          dc->w.DCOrgY = WindowObject->ClientRect.top;
        }
-      /* FIXME: Offset by parent's client rectangle. */
     }
-  DC_ReleasePtr(hDC);
+  DC_UnlockDc(hDC);
+}
+
+
+STATIC VOID FASTCALL
+DceDeleteClipRgn(DCE* Dce)
+{
+  Dce->DCXFlags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
+
+  if (Dce->DCXFlags & DCX_KEEPCLIPRGN )
+    {
+      Dce->DCXFlags &= ~DCX_KEEPCLIPRGN;
+    }
+  else if (Dce->hClipRgn > (HRGN) 1)
+    {
+      NtGdiDeleteObject(Dce->hClipRgn);
+    }
+
+  Dce->hClipRgn = NULL;
+
+  /* make it dirty so that the vis rgn gets recomputed next time */
+  Dce->DCXFlags |= DCX_DCEDIRTY;
 }
 
 HDC STDCALL
-NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
+NtUserGetDCEx(HWND hWnd, HANDLE ClipRegion, ULONG Flags)
 {
   PWINDOW_OBJECT Window;
   ULONG DcxFlags;
@@ -331,16 +223,22 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
   BOOL UpdateClipOrigin = FALSE;
   HANDLE hRgnVisible = NULL;
 
-  if ((Window = W32kGetWindowObject(hWnd)) == NULL)
+  if (NULL == hWnd)
+    {
+      Flags &= ~DCX_USESTYLE;
+      Window = NULL;
+    }
+  else if (NULL == (Window = IntGetWindowObject(hWnd)))
     {
       return(0);
     }
 
-  if (Window->Dce == NULL)
+  if (NULL == Window || NULL == Window->Dce)
     {
       Flags |= DCX_CACHE;
     }
 
+
   if (Flags & DCX_USESTYLE)
     {
       Flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
@@ -352,7 +250,7 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
 
       if (!(Flags & DCX_WINDOW))
        {
-         if (Window->Class->Class.style & CS_PARENTDC)
+         if (Window->Class->style & CS_PARENTDC)
            {
              Flags |= DCX_PARENTCLIP;
            }
@@ -380,7 +278,7 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
       Flags = (Flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
     }
 
-  if (!(Window->Style & WS_CHILD) || Window->Parent == NULL)
+  if (NULL == Window || !(Window->Style & WS_CHILD) || NULL == Window->Parent)
     {
       Flags &= ~DCX_PARENTCLIP;
     }
@@ -444,9 +342,9 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
       DbgBreakPoint();
     }
 
-  if (Dce == NULL)
+  if (NULL == Dce && NULL != Window)
     {
-      W32kReleaseWindowObject(Window);
+      IntReleaseWindowObject(Window);
       return(NULL);
     }
 
@@ -454,6 +352,24 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
   Dce->hClipRgn = NULL;
   Dce->DCXFlags = DcxFlags | (Flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
 
+  if (0 == (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) && NULL != ClipRegion)
+    {
+      NtGdiDeleteObject(ClipRegion);
+      ClipRegion = NULL;
+    }
+
+  if (NULL != Dce->hClipRgn)
+    {
+      DceDeleteClipRgn(Dce);
+    }
+
+  if (NULL != ClipRegion)
+    {
+      Dce->hClipRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
+      NtGdiCombineRgn(Dce->hClipRgn, ClipRegion, NULL, RGN_COPY);
+      NtGdiDeleteObject(ClipRegion);
+    }
+
   DceSetDrawable(Window, Dce->hDC, Flags, UpdateClipOrigin);
 
   if (UpdateVisRgn)
@@ -479,57 +395,54 @@ NtUserGetDCEx(HWND hWnd, HANDLE hRegion, ULONG Flags)
                }
              hRgnVisible = DceGetVisRgn(Parent->Self, DcxFlags, 
                                         Window->Self, Flags);
-             if (Flags & DCX_WINDOW)
-               {
-                 W32kOffsetRgn(hRgnVisible, -Window->WindowRect.left,
-                               -Window->WindowRect.top);
-               }
-             else
-               {
-                 W32kOffsetRgn(hRgnVisible, -Window->ClientRect.left,
-                               -Window->ClientRect.top);
-               }
-             DceOffsetVisRgn(Dce->hDC, hRgnVisible);
            }
          else
            {
-             hRgnVisible = W32kCreateRectRgn(0, 0, 0, 0);
+             hRgnVisible = NtGdiCreateRectRgn(0, 0, 0, 0);
            }
        }
       else
        {
-         if (hWnd == W32kGetDesktopWindow())
+         if (hWnd == IntGetDesktopWindow())
            {
              hRgnVisible = 
-               W32kCreateRectRgn(0, 0, 
+               NtGdiCreateRectRgn(0, 0, 
                                  NtUserGetSystemMetrics(SM_CXSCREEN),
                                  NtUserGetSystemMetrics(SM_CYSCREEN));
            }
          else
            {
              hRgnVisible = DceGetVisRgn(hWnd, Flags, 0, 0);
-             DceOffsetVisRgn(Dce->hDC, hRgnVisible);
            }
+       }
+
+      if (0 != (Flags & DCX_INTERSECTRGN))
+       {
+         NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_AND);
+       }
 
-         Dce->DCXFlags &= ~DCX_DCEDIRTY;
-         W32kSelectVisRgn(Dce->hDC, hRgnVisible);
+      if (0 != (Flags & DCX_EXCLUDERGN))
+       {
+         NtGdiCombineRgn(hRgnVisible, hRgnVisible, Dce->hClipRgn, RGN_DIFF);
        }
-    }
 
-  if (Flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
-    {
-      DPRINT1("FIXME.\n");
+      Dce->DCXFlags &= ~DCX_DCEDIRTY;
+      NtGdiSelectVisRgn(Dce->hDC, hRgnVisible);
     }
 
   if (hRgnVisible != NULL)
     {
-      W32kDeleteObject(hRgnVisible);
+      NtGdiDeleteObject(hRgnVisible);
+    }
+  if (NULL != Window)
+    {
+      IntReleaseWindowObject(Window);
     }
-  W32kReleaseWindowObject(Window);
+
   return(Dce->hDC);
 }
 
-BOOL
+BOOL FASTCALL
 DCE_InternalDelete(PDCE Dce)
 {
   PDCE PrevInList;
@@ -554,6 +467,20 @@ DCE_InternalDelete(PDCE Dce)
 
   return NULL != PrevInList;
 }
+
+HWND FASTCALL
+IntWindowFromDC(HDC hDc)
+{
+  DCE *Dce;
+  for (Dce = FirstDce; Dce != NULL; Dce = Dce->next)
+  {
+    if(Dce->hDC == hDc)
+    {
+      return Dce->hwndCurrent;
+    }
+  }
+  return 0;
+}
   
 
 /* EOF */