ScrollDC

Ulrich Czekalla ulrich.czekalla at utoronto.ca
Mon Jun 14 21:25:18 CDT 2004


ChangeLog:
        Ulrich Czekalla <ulrich at codeweavers.com>
        ScrollDC should take into account overlapped windows. With this
        change ScrollWindowEx can be moved out of X11drv.
-------------- next part --------------
Index: dlls/user/user_main.c
===================================================================
RCS file: /home/wine/wine/dlls/user/user_main.c,v
retrieving revision 1.67
diff -u -r1.67 user_main.c
--- dlls/user/user_main.c	21 Apr 2004 22:30:08 -0000	1.67
+++ dlls/user/user_main.c	15 Jun 2004 01:48:57 -0000
@@ -110,7 +110,7 @@
     GET_USER_FUNC(ForceWindowRaise);
     GET_USER_FUNC(MsgWaitForMultipleObjectsEx);
     GET_USER_FUNC(ReleaseDC);
-    GET_USER_FUNC(ScrollWindowEx);
+    GET_USER_FUNC(ScrollDC);
     GET_USER_FUNC(SetFocus);
     GET_USER_FUNC(SetParent);
     GET_USER_FUNC(SetWindowPos);
Index: dlls/user/tests/win.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/win.c,v
retrieving revision 1.28
diff -u -r1.28 win.c
--- dlls/user/tests/win.c	3 Jun 2004 00:08:55 -0000	1.28
+++ dlls/user/tests/win.c	15 Jun 2004 01:48:57 -0000
@@ -1665,6 +1665,47 @@
     ok( GetActiveWindow() != hwnd2, "Window %p is still active\n", hwnd2 );
 }
 
+static void test_window_invalidation()
+{
+    HDC hdc;
+    HWND hwnd1, hwnd2;
+    HRGN hrgn1, hrgn2, hrgnUpdate;
+    RECT rc1, rc2, rcUpdate;
+
+    hwnd1 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window",
+                               WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                               WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE,
+                               100, 100, 200, 200,
+                               0, 0, 0, NULL);
+    hwnd2 = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window 2",
+                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+                                WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE,
+                                200, 200, 100, 50,
+                                0, 0, 0, NULL);
+
+    /* test ScrollDC */
+    GetClientRect(hwnd1, &rc1);
+    GetWindowRect(hwnd2, &rc2);
+    ScreenToClient(hwnd1, &rc2);
+
+    hdc = GetDC(hwnd1);
+    hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
+    ScrollDC(hdc, 0, -10, NULL, NULL, hrgnUpdate, &rcUpdate);
+
+    hrgn1 = CreateRectRgn(rc1.left, rc1.bottom - 10, rc1.right, rc1.bottom);
+    hrgn2 = CreateRectRgn(rc2.left, rc2.top - 10, rc1.right, rc2.top);
+    CombineRgn(hrgn1, hrgn1, hrgn2, RGN_OR);
+
+    ok (EqualRgn(hrgn1, hrgnUpdate), "ScrollDC returned incorrect uncovered region\n");
+
+    DeleteObject(hrgn1);
+    DeleteObject(hrgn2);
+    DeleteObject(hrgnUpdate);
+
+    DestroyWindow(hwnd1);
+    DestroyWindow(hwnd2);
+}
+
 START_TEST(win)
 {
     pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" );
@@ -1714,6 +1755,8 @@
     test_SetActiveWindow(hwndMain);
 
     test_children_zorder(hwndMain);
+
+    test_window_invalidation();
 
     UnhookWindowsHookEx(hhook);
 }
Index: dlls/x11drv/scroll.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/scroll.c,v
retrieving revision 1.19
diff -u -r1.19 scroll.c
--- dlls/x11drv/scroll.c	14 Jan 2004 04:53:11 -0000	1.19
+++ dlls/x11drv/scroll.c	15 Jun 2004 01:48:57 -0000
@@ -38,98 +38,94 @@
 
 
 /*************************************************************************
- *		ScrollWindowEx   (X11DRV.@)
- *
- * Note: contrary to what the doc says, pixels that are scrolled from the
- *      outside of clipRect to the inside are NOT painted.
- *
- * Parameter are the same as in ScrollWindowEx, with the additional
- * requirement that rect and clipRect are _valid_ pointers, to
- * rectangles _within_ the client are. Moreover, there is something
- * to scroll.
+ *		ScrollDC   (X11DRV.@)
  */
-INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
-                           const RECT *rect, const RECT *clipRect,
-                           HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
+BOOL WINAPI X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
+                      const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
+
 {
-    INT   retVal;
-    BOOL  bOwnRgn = TRUE;
-    BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
-    HRGN  hrgnTemp;
-    HDC   hDC;
-    RECT  rc, cliprc;
-
-    TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n",
-           hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags );
-    TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect));
-
-    GetClientRect(hwnd, &rc);
-    if (rect) IntersectRect(&rc, &rc, rect);
+    RECT rSrc, rClipped_src, rClip, rDst, offset;
+    INT code = X11DRV_START_EXPOSURES;
+
+    if (hrgnUpdate || lprcUpdate)
+        ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
 
-    if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
-    else cliprc = rc;
+    /* compute device clipping region (in device coordinates) */
 
-    if( hrgnUpdate ) bOwnRgn = FALSE;
-    else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
+    if (lprcScroll) rSrc = *lprcScroll;
+    else GetClipBox( hdc, &rSrc );
+    LPtoDP(hdc, (LPPOINT)&rSrc, 2);
+
+    if (lprcClip) rClip = *lprcClip;
+    else GetClipBox( hdc, &rClip );
+    LPtoDP(hdc, (LPPOINT)&rClip, 2);
+
+    IntersectRect( &rClipped_src, &rSrc, &rClip );
+    TRACE("rSrc %s rClip %s clipped rSrc %s\n", wine_dbgstr_rect(&rSrc),
+          wine_dbgstr_rect(&rClip), wine_dbgstr_rect(&rClipped_src));
+
+    rDst = rClipped_src;
+    SetRect(&offset, 0, 0, dx, dy);
+    LPtoDP(hdc, (LPPOINT)&offset, 2);
+    OffsetRect( &rDst, offset.right - offset.left,  offset.bottom - offset.top );
+    TRACE("rDst before clipping %s\n", wine_dbgstr_rect(&rDst));
+    IntersectRect( &rDst, &rDst, &rClip );
+    TRACE("rDst after clipping %s\n", wine_dbgstr_rect(&rDst));
 
-    hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
-    if (hDC)
+    if (!IsRectEmpty(&rDst))
     {
-        enum x11drv_escape_codes code = X11DRV_START_EXPOSURES;
-        HRGN hrgn = 0;
+        /* copy bits */
+        RECT rDst_lp = rDst, rSrc_lp = rDst;
 
-        ExtEscape( hDC, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
-        ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
-        code = X11DRV_END_EXPOSURES;
-        ExtEscape( hDC, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(hrgn), (LPSTR)&hrgn );
-        ReleaseDC( hwnd, hDC );
-        if (hrgn)
-        {
-            if (bUpdate) CombineRgn( hrgnUpdate, hrgnUpdate, hrgn, RGN_OR );
-            else RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
-            DeleteObject( hrgn );
-        }
+        OffsetRect( &rSrc_lp, offset.left - offset.right, offset.top - offset.bottom );
+        DPtoLP(hdc, (LPPOINT)&rDst_lp, 2);
+        DPtoLP(hdc, (LPPOINT)&rSrc_lp, 2);
+
+        if (!BitBlt( hdc, rDst_lp.left, rDst_lp.top,
+                     rDst_lp.right - rDst_lp.left, rDst_lp.bottom - rDst_lp.top,
+                     hdc, rSrc_lp.left, rSrc_lp.top, SRCCOPY))
+            return FALSE;
     }
 
-    /* Take into account the fact that some damage may have occurred during the scroll */
-    hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
-    retVal = GetUpdateRgn( hwnd, hrgnTemp, FALSE );
-    if (retVal != NULLREGION)
-    {
-        HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
-        OffsetRgn( hrgnTemp, dx, dy );
-        CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
-        RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
-        DeleteObject( hrgnClip );
-    }
-    DeleteObject( hrgnTemp );
+    /* compute update areas.  This is the clipped source or'ed with the unclipped source translated minus the
+     clipped src translated (rDst) all clipped to rClip */
 
-    if( flags & SW_SCROLLCHILDREN )
+    if (hrgnUpdate || lprcUpdate)
     {
-        HWND *list = WIN_ListChildren( hwnd );
-        if (list)
+        HRGN hrgn = hrgnUpdate, hrgn2, hrgn3 = 0;
+
+        code = X11DRV_END_EXPOSURES;
+        ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, sizeof(hrgn3), (LPSTR)&hrgn3 );
+
+        if (hrgn) SetRectRgn( hrgn, rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom );
+        else hrgn = CreateRectRgn( rClipped_src.left, rClipped_src.top, rClipped_src.right, rClipped_src.bottom );
+
+        hrgn2 = CreateRectRgnIndirect( &rSrc );
+        OffsetRgn(hrgn2, offset.right - offset.left,  offset.bottom - offset.top );
+        CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
+
+        SetRectRgn( hrgn2, rDst.left, rDst.top, rDst.right, rDst.bottom );
+        CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
+
+        SetRectRgn( hrgn2, rClip.left, rClip.top, rClip.right, rClip.bottom );
+        CombineRgn( hrgn, hrgn, hrgn2, RGN_AND );
+
+        if (hrgn3)
         {
-            int i;
-            RECT r, dummy;
-            for (i = 0; list[i]; i++)
-            {
-                GetWindowRect( list[i], &r );
-                MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
-                if (!rect || IntersectRect(&dummy, &r, &rc))
-                    SetWindowPos( list[i], 0, r.left + dx, r.top  + dy, 0, 0,
-                                  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
-                                  SWP_NOREDRAW | SWP_DEFERERASE );
-            }
-            HeapFree( GetProcessHeap(), 0, list );
+            CombineRgn( hrgn, hrgn, hrgn3, RGN_OR );
+            DeleteObject( hrgn3 );
         }
-    }
 
-    if( flags & (SW_INVALIDATE | SW_ERASE) )
-        RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
-                      ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
-                      ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
-
-    if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
-    
-    return retVal;
+        if( lprcUpdate )
+        {
+            GetRgnBox( hrgn, lprcUpdate );
+
+            /* Put the lprcUpdate in logical coordinate */
+            DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
+            TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
+        }
+        if (!hrgnUpdate) DeleteObject( hrgn );
+        DeleteObject( hrgn2 );
+    }
+    return TRUE;
 }
Index: dlls/x11drv/x11drv.spec
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.spec,v
retrieving revision 1.58
diff -u -r1.58 x11drv.spec
--- dlls/x11drv/x11drv.spec	17 May 2004 21:08:31 -0000	1.58
+++ dlls/x11drv/x11drv.spec	15 Jun 2004 01:48:57 -0000
@@ -98,7 +98,7 @@
 @ cdecl RegisterClipboardFormat(str) X11DRV_RegisterClipboardFormat
 @ cdecl ReleaseDC(long long) X11DRV_ReleaseDC
 @ cdecl ResetSelectionOwner(long long) X11DRV_ResetSelectionOwner
-@ cdecl ScrollWindowEx(long long long ptr ptr long ptr long) X11DRV_ScrollWindowEx
+@ cdecl ScrollDC(long long long ptr ptr long ptr) X11DRV_ScrollDC
 @ cdecl SetClipboardData(long long long long) X11DRV_SetClipboardData
 @ cdecl SetFocus(long) X11DRV_SetFocus
 @ cdecl SetParent(long long) X11DRV_SetParent
Index: include/user.h
===================================================================
RCS file: /home/wine/wine/include/user.h,v
retrieving revision 1.64
diff -u -r1.64 user.h
--- include/user.h	6 May 2004 23:40:30 -0000	1.64
+++ include/user.h	15 Jun 2004 01:48:57 -0000
@@ -113,7 +113,7 @@
     void   (*pForceWindowRaise)(HWND);
     DWORD  (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,DWORD,DWORD,DWORD);
     void   (*pReleaseDC)(HWND,HDC);
-    INT    (*pScrollWindowEx)(HWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
+    BOOL   (*pScrollDC)(HDC, INT, INT, const RECT *, const RECT *, HRGN, LPRECT);
     void   (*pSetFocus)(HWND);
     HWND   (*pSetParent)(HWND,HWND);
     BOOL   (*pSetWindowPos)(WINDOWPOS *);
Index: windows/scroll.c
===================================================================
RCS file: /home/wine/wine/windows/scroll.c,v
retrieving revision 1.42
diff -u -r1.42 scroll.c
--- windows/scroll.c	12 Jan 2004 21:15:16 -0000	1.42
+++ windows/scroll.c	15 Jun 2004 01:48:57 -0000
@@ -60,6 +60,93 @@
     return 0;
 }
 
+/*************************************************************************
+ *		scroll_window
+ *
+ * Note: contrary to what the doc says, pixels that are scrolled from the
+ *      outside of clipRect to the inside are NOT painted.
+ *
+ * Parameter are the same as in ScrollWindowEx, with the additional
+ * requirement that rect and clipRect are _valid_ pointers, to
+ * rectangles _within_ the client are. Moreover, there is something
+ * to scroll.
+ */
+INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect,
+        const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
+{
+    INT   retVal;
+    BOOL  bOwnRgn = TRUE;
+    BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
+    HRGN  hrgnTemp;
+    HDC   hDC;
+    RECT  rc, cliprc;
+
+    TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n",
+           hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags );
+    TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect));
+
+    GetClientRect(hwnd, &rc);
+    if (rect) IntersectRect(&rc, &rc, rect);
+
+    if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
+    else cliprc = rc;
+
+    if( hrgnUpdate ) bOwnRgn = FALSE;
+    else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
+
+    hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
+    if (hDC)
+    {
+        ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
+
+        ReleaseDC( hwnd, hDC );
+
+        if (!bUpdate)
+            RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE );
+    }
+
+    /* Take into account the fact that some damage may have occurred during the scroll */
+    hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
+    retVal = GetUpdateRgn( hwnd, hrgnTemp, FALSE );
+    if (retVal != NULLREGION)
+    {
+        HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
+        OffsetRgn( hrgnTemp, dx, dy );
+        CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
+        RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
+        DeleteObject( hrgnClip );
+    }
+    DeleteObject( hrgnTemp );
+
+    if( flags & SW_SCROLLCHILDREN )
+    {
+        HWND *list = WIN_ListChildren( hwnd );
+        if (list)
+        {
+            int i;
+            RECT r, dummy;
+            for (i = 0; list[i]; i++)
+            {
+                GetWindowRect( list[i], &r );
+                MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
+                if (!rect || IntersectRect(&dummy, &r, &rc))
+                    SetWindowPos( list[i], 0, r.left + dx, r.top  + dy, 0, 0,
+                                  SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
+                                  SWP_NOREDRAW | SWP_DEFERERASE );
+            }
+            HeapFree( GetProcessHeap(), 0, list );
+        }
+    }
+
+    if( flags & (SW_INVALIDATE | SW_ERASE) )
+        RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
+                      ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
+                      ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
+
+    if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
+
+    return retVal;
+}
 
 /*************************************************************************
  *		ScrollWindow (USER32.@)
@@ -90,8 +177,10 @@
     if (lprcClip) TRACE( "lprcClip = %s\n", wine_dbgstr_rect(lprcClip));
     if (lprcScroll) TRACE( "lprcScroll = %s\n", wine_dbgstr_rect(lprcScroll));
 
-    /* compute device clipping region (in device coordinates) */
+    if (USER_Driver.pScrollDC)
+        return USER_Driver.pScrollDC( hdc, dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate );
 
+    /* compute device clipping region (in device coordinates) */
     if (lprcScroll) rSrc = *lprcScroll;
     else GetClipBox( hdc, &rSrc );
     LPtoDP(hdc, (LPPOINT)&rSrc, 2);
@@ -189,12 +278,9 @@
         RECT caretrc = rc;
         HWND hwndCaret = fix_caret(hwnd, &caretrc, flags);
 
-	if (USER_Driver.pScrollWindowEx)
-            result = USER_Driver.pScrollWindowEx( hwnd, dx, dy, rect, clipRect,
-                                                  hrgnUpdate, rcUpdate, flags );
-	else
-	    result = ERROR; /* FIXME: we should have a fallback implementation */
-	
+        result = scroll_window( hwnd, dx, dy, rect, clipRect,
+                hrgnUpdate, rcUpdate, flags );
+
         if( hwndCaret )
         {
             SetCaretPos( caretrc.left + dx, caretrc.top + dy );


More information about the wine-patches mailing list