Moved ScrollWindowEx implementation to the graphics driver.

diff --git a/dlls/ttydrv/wnd.c b/dlls/ttydrv/wnd.c
index 1a31cc8..bb10699 100644
--- a/dlls/ttydrv/wnd.c
+++ b/dlls/ttydrv/wnd.c
@@ -18,7 +18,6 @@
 WND_DRIVER TTYDRV_WND_Driver =
 {
   TTYDRV_WND_ForceWindowRaise,
-  TTYDRV_WND_ScrollWindow,
   TTYDRV_WND_SetHostAttr
 };
 
@@ -98,16 +97,6 @@
   FIXME("(%p): stub\n", wndPtr);
 }
 
-/*****************************************************************
- *		 TTYDRV_WND_ScrollWindow
- */
-void TTYDRV_WND_ScrollWindow( WND *wndPtr, HDC hdc, INT dx, INT dy, 
-                              const RECT *clipRect, BOOL bUpdate)
-{
-  FIXME("(%p, %x, %d, %d, %p, %d): stub\n", 
-	wndPtr, hdc, dx, dy, clipRect, bUpdate);
-}
-
 /***********************************************************************
  *              TTYDRV_WND_SetHostAttr
  */
diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c
index cb4f9e8..2690e8d 100644
--- a/dlls/user/user_main.c
+++ b/dlls/user/user_main.c
@@ -88,6 +88,7 @@
     GET_USER_FUNC(DestroyWindow);
     GET_USER_FUNC(GetDC);
     GET_USER_FUNC(EnableWindow);
+    GET_USER_FUNC(ScrollWindowEx);
     GET_USER_FUNC(SetFocus);
     GET_USER_FUNC(SetParent);
     GET_USER_FUNC(SetWindowPos);
diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c
index c5ca2b8..4a417a9 100644
--- a/dlls/x11drv/window.c
+++ b/dlls/x11drv/window.c
@@ -18,6 +18,7 @@
 #include "debugtools.h"
 #include "x11drv.h"
 #include "win.h"
+#include "dce.h"
 #include "options.h"
 
 DEFAULT_DEBUG_CHANNEL(win);
@@ -631,3 +632,154 @@
     WIN_ReleaseWndPtr( wndPtr );
     return old;
 }
+
+
+/*************************************************************************
+ *             fix_caret
+ */
+static BOOL fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
+{
+   HWND hCaret = CARET_GetHwnd();
+
+   if( hCaret )
+   {
+       RECT rc;
+       CARET_GetRect( &rc );
+       if( hCaret == hWnd ||
+          (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
+       {
+           POINT pt;
+           pt.x = rc.left;
+           pt.y = rc.top;
+           MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
+           if( IntersectRect(lprc, lprc, &rc) )
+           {
+               HideCaret(0);
+               lprc->left = pt.x;
+               lprc->top = pt.y;
+               return TRUE;
+           }
+       }
+   }
+   return FALSE;
+}
+
+
+/*************************************************************************
+ *		ScrollWindowEx   (X11DRV.@)
+ */
+INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
+                           const RECT *rect, const RECT *clipRect,
+                           HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
+{
+    INT  retVal = NULLREGION;
+    BOOL bCaret = FALSE, bOwnRgn = TRUE;
+    RECT rc, cliprc;
+    WND*   wnd = WIN_FindWndPtr( hwnd );
+
+    if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE ))
+    {
+        retVal = ERROR;
+        goto END;
+    }
+
+    GetClientRect(hwnd, &rc);
+    if (rect) IntersectRect(&rc, &rc, rect);
+
+    if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
+    else cliprc = rc;
+
+    if (!IsRectEmpty(&cliprc) && (dx || dy))
+    {
+        HDC   hDC;
+        BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
+        HRGN  hrgnClip = CreateRectRgnIndirect(&cliprc);
+        HRGN  hrgnTemp = CreateRectRgnIndirect(&rc);
+        RECT  caretrc;
+
+        TRACE("%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
+              (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
+              clipRect?clipRect->left:0, clipRect?clipRect->top:0,
+              clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
+              rc.left, rc.top, rc.right, rc.bottom, (UINT16)flags );
+
+        caretrc = rc;
+        bCaret = fix_caret(hwnd, &caretrc, flags);
+
+        if( hrgnUpdate ) bOwnRgn = FALSE;
+        else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
+
+        hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
+                         DCX_KEEPCLIPRGN | DCX_INTERSECTRGN |
+                       ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
+        if (hDC)
+        {
+            X11DRV_WND_SurfaceCopy(wnd,hDC,dx,dy,&rc,bUpdate);
+            if( bUpdate )
+            {
+                DC* dc;
+
+                if( (dc = DC_GetDCPtr(hDC)) )
+                {
+                    OffsetRgn( hrgnTemp, dc->DCOrgX, dc->DCOrgY );
+                    CombineRgn( hrgnTemp, hrgnTemp, dc->hVisRgn,
+                                RGN_AND );
+                    OffsetRgn( hrgnTemp, -dc->DCOrgX, -dc->DCOrgY );
+                    CombineRgn( hrgnUpdate, hrgnTemp, hrgnClip,
+                                RGN_AND );
+                    OffsetRgn( hrgnTemp, dx, dy );
+                    retVal =
+                        CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp,
+                                    RGN_DIFF );
+
+                    if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
+                    GDI_ReleaseObj( hDC );
+                }
+            }
+            ReleaseDC(hwnd, hDC);
+        }
+
+        if( wnd->hrgnUpdate > 1 )
+        {
+            /* Takes into account the fact that some damages may have
+               occured during the scroll. */
+            CombineRgn( hrgnTemp, wnd->hrgnUpdate, 0, RGN_COPY );
+            OffsetRgn( hrgnTemp, dx, dy );
+            CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
+            CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnTemp, RGN_OR );
+        }
+
+        if( flags & SW_SCROLLCHILDREN )
+        {
+            RECT r;
+            WND *w;
+            for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next))
+            {
+                r = w->rectWindow;
+                if( !rect || IntersectRect(&r, &r, &rc) )
+                    SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
+                                 w->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
+                                 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
+                                 SWP_DEFERERASE );
+            }
+        }
+
+        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( bCaret )
+        {
+            SetCaretPos( caretrc.left + dx, caretrc.top + dy );
+            ShowCaret(0);
+        }
+
+        if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
+        DeleteObject( hrgnClip );
+        DeleteObject( hrgnTemp );
+    }
+END:
+    WIN_ReleaseWndPtr(wnd);
+    return retVal;
+}
diff --git a/dlls/x11drv/x11drv.spec b/dlls/x11drv/x11drv.spec
index 92e8466..abfdac3 100644
--- a/dlls/x11drv/x11drv.spec
+++ b/dlls/x11drv/x11drv.spec
@@ -32,6 +32,7 @@
 @ cdecl DestroyWindow(long) X11DRV_DestroyWindow
 @ cdecl GetDC(long long long long) X11DRV_GetDC
 @ cdecl EnableWindow(long long) X11DRV_EnableWindow
+@ cdecl ScrollWindowEx(long long long ptr ptr long ptr long) X11DRV_ScrollWindowEx
 @ cdecl SetFocus(long) X11DRV_SetFocus
 @ cdecl SetParent(long long) X11DRV_SetParent
 @ cdecl SetWindowPos(ptr) X11DRV_SetWindowPos
diff --git a/include/user.h b/include/user.h
index 494f7f3..6837989 100644
--- a/include/user.h
+++ b/include/user.h
@@ -75,6 +75,7 @@
     BOOL   (*pDestroyWindow)(HWND);
     BOOL   (*pGetDC)(HWND,HDC,HRGN,DWORD);
     BOOL   (*pEnableWindow)(HWND,BOOL);
+    INT    (*pScrollWindowEx)(HWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT);
     void   (*pSetFocus)(HWND);
     HWND   (*pSetParent)(HWND,HWND);
     BOOL   (*pSetWindowPos)(WINDOWPOS *);
diff --git a/include/win.h b/include/win.h
index 310b4c9..2ccf79d 100644
--- a/include/win.h
+++ b/include/win.h
@@ -71,7 +71,6 @@
 typedef struct tagWND_DRIVER
 {
     void   (*pForceWindowRaise)(WND *);
-    void   (*pSurfaceCopy)(WND *, HDC, INT, INT, const RECT *, BOOL);
     BOOL   (*pSetHostAttr)(WND *, INT haKey, INT value);
 } WND_DRIVER;
 
diff --git a/windows/scroll.c b/windows/scroll.c
index 9afd2f0..dba6111 100644
--- a/windows/scroll.c
+++ b/windows/scroll.c
@@ -17,6 +17,7 @@
 #include "gdi.h"
 #include "dce.h"
 #include "region.h"
+#include "user.h"
 #include "debugtools.h"
 
 DEFAULT_DEBUG_CHANNEL(scroll);
@@ -204,34 +205,6 @@
     return ret;
 }
 
-/*************************************************************************
- *             SCROLL_FixCaret
- */
-static BOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags)
-{
-   HWND hCaret = CARET_GetHwnd();
-
-   if( hCaret )
-   {
-       RECT	rc;
-       CARET_GetRect( &rc );
-       if( hCaret == hWnd ||
-          (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
-       {
-           POINT     pt;
-
-           pt.x = rc.left; pt.y = rc.top;
-           MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
-           if( IntersectRect(lprc, lprc, &rc) )
-           {
-               HideCaret(0);
-  	       lprc->left = pt.x; lprc->top = pt.y;
-	       return TRUE;
-           }
-       }
-   }
-   return FALSE;
-}
 
 /*************************************************************************
  *		ScrollWindowEx (USER32.@)
@@ -243,114 +216,8 @@
                                HRGN hrgnUpdate, LPRECT rcUpdate,
                                UINT flags )
 {
-    INT  retVal = NULLREGION;
-    BOOL bCaret = FALSE, bOwnRgn = TRUE;
-    RECT rc, cliprc;
-    WND*   wnd = WIN_FindWndPtr( hwnd );
-
-    if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE ))
-    {
-        retVal = ERROR;
-        goto END;
-    }
-
-    GetClientRect(hwnd, &rc);
-    if (rect) IntersectRect(&rc, &rc, rect);
-
-    if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
-    else cliprc = rc;
-
-    if (!IsRectEmpty(&cliprc) && (dx || dy))
-    {
-	HDC	hDC;
-	BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
-	HRGN  hrgnClip = CreateRectRgnIndirect(&cliprc);
-        HRGN  hrgnTemp = CreateRectRgnIndirect(&rc);
-        RECT  caretrc;
-
-        TRACE("%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
-              (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
-              clipRect?clipRect->left:0, clipRect?clipRect->top:0,
-              clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
-              rc.left, rc.top, rc.right, rc.bottom, (UINT16)flags );
-
-        caretrc = rc; 
-	bCaret = SCROLL_FixCaret(hwnd, &caretrc, flags);
-
-	if( hrgnUpdate ) bOwnRgn = FALSE;
-        else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
-
-	hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
-                         DCX_KEEPCLIPRGN | DCX_INTERSECTRGN |
-		       ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
-	if (hDC)
-	{
-                wnd->pDriver->pSurfaceCopy(wnd,hDC,dx,dy,&rc,bUpdate);
-                if( bUpdate )
-                    {
-                DC*	dc;
-
-                if( (dc = DC_GetDCPtr(hDC)) )
-                {
-                        OffsetRgn( hrgnTemp, dc->DCOrgX, dc->DCOrgY );
-                        CombineRgn( hrgnTemp, hrgnTemp, dc->hVisRgn,
-                                      RGN_AND );
-                        OffsetRgn( hrgnTemp, -dc->DCOrgX, -dc->DCOrgY );
-                        CombineRgn( hrgnUpdate, hrgnTemp, hrgnClip,
-                                      RGN_AND );
-                        OffsetRgn( hrgnTemp, dx, dy );
-                        retVal =
-                            CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp,
-                                          RGN_DIFF );
-
-                        if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
-                        GDI_ReleaseObj( hDC );
-                    }
-            }
-            ReleaseDC(hwnd, hDC);
-        }
-
-	if( wnd->hrgnUpdate > 1 )
-	{
-            /* Takes into account the fact that some damages may have
-               occured during the scroll. */
-            CombineRgn( hrgnTemp, wnd->hrgnUpdate, 0, RGN_COPY );
-            OffsetRgn( hrgnTemp, dx, dy );
-            CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
-            CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnTemp, RGN_OR );
-	}
-
-	if( flags & SW_SCROLLCHILDREN )
-	{
-	    RECT	r;
-	    WND* 	w;
-	    for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next))
-	    {
-                r = w->rectWindow;
-	         if( !rect || IntersectRect(&r, &r, &rc) )
-		     SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
-				    w->rectWindow.top  + dy, 0,0, SWP_NOZORDER |
-				    SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
-				    SWP_DEFERERASE );
-	    }
-	}
-
-	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( bCaret )
-	{
-	    SetCaretPos( caretrc.left + dx, caretrc.top + dy );
-	    ShowCaret(0);
-	}
-
-	if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
-	DeleteObject( hrgnClip );
-        DeleteObject( hrgnTemp );
-    }
-END:
-    WIN_ReleaseWndPtr(wnd);
-    return retVal;
+    if (USER_Driver.pScrollWindowEx)
+        return USER_Driver.pScrollWindowEx( hwnd, dx, dy, rect, clipRect,
+                                            hrgnUpdate, rcUpdate, flags );
+    return ERROR;
 }
diff --git a/windows/x11drv/wnd.c b/windows/x11drv/wnd.c
index facff76..187b9cb 100644
--- a/windows/x11drv/wnd.c
+++ b/windows/x11drv/wnd.c
@@ -41,7 +41,6 @@
 WND_DRIVER X11DRV_WND_Driver =
 {
   X11DRV_WND_ForceWindowRaise,
-  X11DRV_WND_SurfaceCopy,
   X11DRV_WND_SetHostAttr
 };