Only offset the rect if it's not empty, otherwise we might return negative
[reactos.git] / reactos / subsys / win32k / ntuser / painting.c
index 3cda722..575dc4e 100644 (file)
@@ -292,11 +292,13 @@ co_IntPaintWindows(PWINDOW_OBJECT Window, ULONG Flags)
       {
          for (phWnd = List; *phWnd; ++phWnd)
          {
-            Window = IntGetWindowObject(*phWnd);
+            Window = UserGetWindowObject(*phWnd);
             if (Window && (Window->Style & WS_VISIBLE))
             {
+               USER_REFERENCE_ENTRY Ref;
+               UserRefObjectCo(Window, &Ref);
                co_IntPaintWindows(Window, Flags);
-               ObmDereferenceObject(Window);
+               UserDerefObjectCo(Window);
             }
          }
          ExFreePool(List);
@@ -414,31 +416,21 @@ IntInvalidateWindows(PWINDOW_OBJECT Window, HRGN hRgn, ULONG Flags)
    if (!(Flags & RDW_NOCHILDREN) && !(Window->Style & WS_MINIMIZE) &&
          ((Flags & RDW_ALLCHILDREN) || !(Window->Style & WS_CLIPCHILDREN)))
    {
-      HWND *List, *phWnd;
       PWINDOW_OBJECT Child;
 
-      if ((List = IntWinListChildren(Window)))
+      for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
       {
-         for (phWnd = List; *phWnd; ++phWnd)
+         if (Child->Style & WS_VISIBLE)
          {
-            if(!(Child = UserGetWindowObject(*phWnd)))
-            {
-               continue;
-            }
-            
-            if (Child->Style & WS_VISIBLE)
-            {
-               /*
-                * Recursive call to update children UpdateRegion
-                */
-               HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
-               NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
-               IntInvalidateWindows(Child, hRgnTemp, Flags);
-               NtGdiDeleteObject(hRgnTemp);
-            }
-
+            /*
+             * Recursive call to update children UpdateRegion
+             */
+            HRGN hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
+            NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY);
+            IntInvalidateWindows(Child, hRgnTemp, Flags);
+            NtGdiDeleteObject(hRgnTemp);
          }
-         ExFreePool(List);
+
       }
    }
 
@@ -602,13 +594,28 @@ HWND FASTCALL
 IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
 {
    HWND hChild;
+   PWINDOW_OBJECT TempWindow;
 
-   while (Window != NULL)
+   for (; Window != NULL; Window = Window->NextSibling)
    {
-      /* FIXME: Transparent windows. */
-      if (IntIsWindowDirty(Window) &&
-          IntWndBelongsToThread(Window, Thread))
+      if (IntWndBelongsToThread(Window, Thread) &&
+          IntIsWindowDirty(Window))
       {
+         /* Make sure all non-transparent siblings are already drawn. */
+         if (Window->ExStyle & WS_EX_TRANSPARENT)
+         {
+            for (TempWindow = Window->NextSibling; TempWindow != NULL;
+                 TempWindow = TempWindow->NextSibling)
+            {
+               if (!(TempWindow->ExStyle & WS_EX_TRANSPARENT) &&
+                   IntWndBelongsToThread(TempWindow, Thread) &&
+                   IntIsWindowDirty(TempWindow))
+               {
+                  return TempWindow->hSelf;
+               }
+            }
+         }
+
          return Window->hSelf;
       }
 
@@ -618,8 +625,6 @@ IntFindWindowToRepaint(PWINDOW_OBJECT Window, PW32THREAD Thread)
          if (hChild != NULL)
             return hChild;
       }
-
-      Window = Window->NextSibling;
    }
 
    return NULL;
@@ -666,7 +671,7 @@ co_IntFixCaret(PWINDOW_OBJECT Window, LPRECT lprc, UINT flags)
 
    ASSERT_REFS_CO(Window);
 
-   Desktop = PsGetCurrentThread()->Tcb.Win32Thread->Desktop;
+   Desktop = ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->Desktop;
    CaretInfo = ((PUSER_MESSAGE_QUEUE)Desktop->ActiveMessageQueue)->CaretInfo;
    hWndCaret = CaretInfo->hWnd;
 
@@ -718,6 +723,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
    PROSRGNDATA Rgn;
    NTSTATUS Status;
    DECLARE_RETURN(HDC);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserBeginPaint\n");
    UserEnterExclusive();
@@ -727,7 +733,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
       RETURN( NULL);
    }
 
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
    
    co_UserHideCaret(Window);
 
@@ -751,7 +757,7 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
    Ps.hdc = UserGetDCEx(Window, Window->UpdateRegion, DCX_INTERSECTRGN | DCX_USESTYLE);
    if (!Ps.hdc)
    {
-      RETURN( NULL);
+      RETURN(NULL);
    }
 
    if (Window->UpdateRegion != NULL)
@@ -762,9 +768,13 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
       {
          UnsafeIntGetRgnBox(Rgn, &Ps.rcPaint);
          RGNDATA_UnlockRgn(Rgn);
-         IntGdiOffsetRect(&Ps.rcPaint,
-                          -Window->ClientRect.left,
-                          -Window->ClientRect.top);
+         IntGdiIntersectRect(&Ps.rcPaint, &Ps.rcPaint, &Window->ClientRect);
+         if (! IntGdiIsEmptyRect(&Ps.rcPaint))
+         {
+            IntGdiOffsetRect(&Ps.rcPaint,
+                             -Window->ClientRect.left,
+                             -Window->ClientRect.top);
+         }
       }
       else
       {
@@ -797,10 +807,10 @@ NtUserBeginPaint(HWND hWnd, PAINTSTRUCT* UnsafePs)
    if (! NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
-      RETURN( NULL);
+      RETURN(NULL);
    }
 
-   RETURN( Ps.hdc);
+   RETURN(Ps.hdc);
 
 CLEANUP:
    if (Window) UserDerefObjectCo(Window);
@@ -823,6 +833,7 @@ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
 {
    PWINDOW_OBJECT Window;
    DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserEndPaint\n");
    UserEnterExclusive();
@@ -834,7 +845,7 @@ NtUserEndPaint(HWND hWnd, CONST PAINTSTRUCT* lPs)
 
    UserReleaseDC(Window, lPs->hdc, TRUE);
 
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
    co_UserShowCaret(Window);
    UserDerefObjectCo(Window);
 
@@ -846,74 +857,12 @@ CLEANUP:
    END_CLEANUP;
 }
 
-/*
- * NtUserInvalidateRect
- *
- * Status
- *    @implemented
- */
-
-DWORD STDCALL
-NtUserInvalidateRect(HWND hWnd, CONST RECT *Rect, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, Rect, 0, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
-}
-
-/*
- * NtUserInvalidateRgn
- *
- * Status
- *    @implemented
- */
-
-DWORD STDCALL
-NtUserInvalidateRgn(HWND hWnd, HRGN Rgn, BOOL Erase)
-{
-   return NtUserRedrawWindow(hWnd, NULL, Rgn, RDW_INVALIDATE | (Erase ? RDW_ERASE : 0));
-}
-
-
-
-BOOL FASTCALL
-co_UserValidateRgn(PWINDOW_OBJECT Window, HRGN hRgn)
-{
-   return co_UserRedrawWindow(Window, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
-}
-
-/*
- * NtUserValidateRgn
- *
- * Status
- *    @implemented
- */
-
-BOOL STDCALL
-NtUserValidateRgn(HWND hWnd, HRGN hRgn)
-{
-   return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_VALIDATE | RDW_NOCHILDREN);
-}
-
-/*
- * NtUserUpdateWindow
- *
- * Status
- *    @implemented
- */
-
-BOOL STDCALL
-NtUserUpdateWindow(HWND hWnd)
-{
-   return NtUserRedrawWindow(hWnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
-}
-
-
-
-
 
 INT FASTCALL
 co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
 {
    int RegionType;
+   RECT Rect;
 
    ASSERT_REFS_CO(Window);
 
@@ -923,7 +872,10 @@ co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
    }
    else
    {
-      RegionType = NtGdiCombineRgn(hRgn, Window->UpdateRegion, hRgn, RGN_COPY);
+      Rect = Window->ClientRect;
+      IntIntersectWithParents(Window, &Rect);
+      NtGdiSetRectRgn(hRgn, Rect.left, Rect.top, Rect.right, Rect.bottom);
+      RegionType = NtGdiCombineRgn(hRgn, hRgn, Window->UpdateRegion, RGN_AND);
       NtGdiOffsetRgn(hRgn, -Window->ClientRect.left, -Window->ClientRect.top);
    }
 
@@ -934,6 +886,7 @@ co_UserGetUpdateRgn(PWINDOW_OBJECT Window, HRGN hRgn, BOOL bErase)
 
    return RegionType;
 }
+
 /*
  * NtUserGetUpdateRgn
  *
@@ -947,6 +900,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
    DECLARE_RETURN(INT);
    PWINDOW_OBJECT Window;
    INT ret;
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserGetUpdateRgn\n");
    UserEnterExclusive();
@@ -956,7 +910,7 @@ NtUserGetUpdateRgn(HWND hWnd, HRGN hRgn, BOOL bErase)
       RETURN(ERROR);
    }
 
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
    ret = co_UserGetUpdateRgn(Window, hRgn, bErase);
    UserDerefObjectCo(Window);
 
@@ -982,7 +936,6 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
    RECT Rect;
    INT RegionType;
    PROSRGNDATA RgnData;
-   BOOL AlwaysPaint;
    NTSTATUS Status;
    DECLARE_RETURN(BOOL);
 
@@ -991,7 +944,7 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
 
    if (!(Window = UserGetWindowObject(hWnd)))
    {
-      RETURN( ERROR);
+      RETURN(FALSE);
    }
 
    if (Window->UpdateRegion == NULL)
@@ -1000,18 +953,37 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
    }
    else
    {
-      RgnData = RGNDATA_LockRgn(Window->UpdateRegion);
-      ASSERT(RgnData != NULL);
-      RegionType = UnsafeIntGetRgnBox(RgnData, &Rect);
-      ASSERT(RegionType != ERROR);
-      RGNDATA_UnlockRgn(RgnData);
+      /* Get the update region bounding box. */
+      if (Window->UpdateRegion == (HRGN)1)
+      {
+         Rect = Window->ClientRect;
+      }
+      else
+      {
+         RgnData = RGNDATA_LockRgn(Window->UpdateRegion);
+         ASSERT(RgnData != NULL);
+         RegionType = UnsafeIntGetRgnBox(RgnData, &Rect);
+         RGNDATA_UnlockRgn(RgnData);
+
+         if (RegionType != ERROR && RegionType != NULLREGION)
+            IntGdiIntersectRect(&Rect, &Rect, &Window->ClientRect);
+      }
+
+      if (IntIntersectWithParents(Window, &Rect))
+      {
+         IntGdiOffsetRect(&Rect,
+                          -Window->ClientRect.left,
+                          -Window->ClientRect.top);
+      } else
+      {
+         Rect.left = Rect.top = Rect.right = Rect.bottom = 0;
+      }
    }
-   AlwaysPaint = (Window->Flags & WINDOWOBJECT_NEED_NCPAINT) ||
-                 (Window->Flags & WINDOWOBJECT_NEED_INTERNALPAINT);
 
-   if (bErase && Rect.left < Rect.right && Rect.top < Rect.bottom)
+   if (bErase && !IntGdiIsEmptyRect(&Rect))
    {
-      UserRefObjectCo(Window);
+      USER_REFERENCE_ENTRY Ref;
+      UserRefObjectCo(Window, &Ref);
       co_UserRedrawWindow(Window, NULL, NULL, RDW_ERASENOW | RDW_NOCHILDREN);
       UserDerefObjectCo(Window);
    }
@@ -1022,11 +994,11 @@ NtUserGetUpdateRect(HWND hWnd, LPRECT UnsafeRect, BOOL bErase)
       if (!NT_SUCCESS(Status))
       {
          SetLastWin32Error(ERROR_INVALID_PARAMETER);
-         RETURN( FALSE);
+         RETURN(FALSE);
       }
    }
 
-   RETURN( (Rect.left < Rect.right && Rect.top < Rect.bottom) || AlwaysPaint);
+   RETURN(!IntGdiIsEmptyRect(&Rect));
 
 CLEANUP:
    DPRINT("Leave NtUserGetUpdateRect, ret=%i\n",_ret_);
@@ -1049,6 +1021,7 @@ NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
    NTSTATUS Status;
    PWINDOW_OBJECT Wnd;
    DECLARE_RETURN(BOOL);
+   USER_REFERENCE_ENTRY Ref;
 
    DPRINT("Enter NtUserRedrawWindow\n");
    UserEnterExclusive();
@@ -1070,7 +1043,7 @@ NtUserRedrawWindow(HWND hWnd, CONST RECT *lprcUpdate, HRGN hrgnUpdate,
       }
    }
 
-   UserRefObjectCo(Wnd);
+   UserRefObjectCo(Wnd, &Ref);
 
    Status = co_UserRedrawWindow(Wnd, NULL == lprcUpdate ? NULL : &SafeUpdateRect,
                                 hrgnUpdate, flags);
@@ -1242,6 +1215,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
    BOOL bOwnRgn = TRUE;
    NTSTATUS Status;
    DECLARE_RETURN(DWORD);
+   USER_REFERENCE_ENTRY Ref, CaretRef;
 
    DPRINT("Enter NtUserScrollWindowEx\n");
    UserEnterExclusive();
@@ -1252,7 +1226,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
       Window = NULL; /* prevent deref at cleanup */
       RETURN( ERROR);
    }
-   UserRefObjectCo(Window);
+   UserRefObjectCo(Window, &Ref);
 
    IntGetClientRect(Window, &rc);
 
@@ -1328,6 +1302,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
          RECT r, dummy;
          POINT ClientOrigin;
          PWINDOW_OBJECT Wnd;
+         USER_REFERENCE_ENTRY WndRef;
 
          IntGetClientOrigin(Window, &ClientOrigin);
          for (i = 0; List[i]; i++)
@@ -1343,7 +1318,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
 
             if (! UnsafeRect || IntGdiIntersectRect(&dummy, &r, &rc))
             {
-               UserRefObjectCo(Wnd);
+               UserRefObjectCo(Wnd, &WndRef);
                co_WinPosSetWindowPos(Wnd, 0, r.left + dx, r.top + dy, 0, 0,
                                      SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
                                      SWP_NOREDRAW);
@@ -1365,7 +1340,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
 
    if ((CaretWnd = UserGetWindowObject(hwndCaret)))
    {
-      UserRefObjectCo(CaretWnd);
+      UserRefObjectCo(CaretWnd, &CaretRef);
 
       co_IntSetCaretPos(caretrc.left + dx, caretrc.top + dy);
       co_UserShowCaret(CaretWnd);
@@ -1373,7 +1348,7 @@ NtUserScrollWindowEx(HWND hWnd, INT dx, INT dy, const RECT *UnsafeRect,
       UserDerefObjectCo(CaretWnd);
    }
 
-   RETURN( Result);
+   RETURN(Result);
 
 CLEANUP:
    if (Window)