This patch depends on the previous patch I've sent. It moves scrolling functions to x11drv to USER. The X11DRV was dealing with two scroll functions: ScrollDC ScrollWindowEx The first one had no X11DRV dependency, while the second one can now be implemented in USER directly with the help of the newly exported {Start,End}GraphicsExposures functions. Mind you that the driver can still provide functions for these operations, if it thinks it can do a better job than the USER. If the driver does not provide an implemention for these functions, USER will default to its own implementation. Oh, BTW, you should also do: cvs rm -f dlls/x11drv/scroll.c after applying this patch. ChangeLog Move scroll from x11drv to USER, and make scrolling functions optional in a USER driver. Index: dlls/x11drv/Makefile.in =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/Makefile.in,v retrieving revision 1.26 diff -u -r1.26 Makefile.in --- dlls/x11drv/Makefile.in 6 Sep 2002 18:51:32 -0000 1.26 +++ dlls/x11drv/Makefile.in 21 Sep 2002 05:14:53 -0000 @@ -30,7 +30,6 @@ event.c \ keyboard.c \ mouse.c \ - scroll.c \ window.c \ winpos.c \ x11ddraw.c \ Index: dlls/x11drv/x11drv.spec =================================================================== RCS file: /var/cvs/wine/dlls/x11drv/x11drv.spec,v retrieving revision 1.39 diff -u -r1.39 x11drv.spec --- dlls/x11drv/x11drv.spec 27 Aug 2002 19:19:49 -0000 1.39 +++ dlls/x11drv/x11drv.spec 21 Sep 2002 05:59:48 -0000 @@ -79,8 +79,6 @@ @ cdecl GetDC(long long long long) X11DRV_GetDC @ cdecl ForceWindowRaise(long) X11DRV_ForceWindowRaise @ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx -@ cdecl ScrollDC(long long long ptr ptr long ptr) X11DRV_ScrollDC -@ 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 Index: windows/scroll.c =================================================================== RCS file: /var/cvs/wine/windows/scroll.c,v retrieving revision 1.37 diff -u -r1.37 scroll.c --- windows/scroll.c 20 Sep 2002 19:35:54 -0000 1.37 +++ windows/scroll.c 21 Sep 2002 05:54:49 -0000 @@ -1,8 +1,10 @@ /* * Scroll windows and DCs * - * Copyright David W. Metcalfe, 1993 - * Alex Korobka 1995,1996 + * Copyright 1993 David W. Metcalfe + * Copyright 1995, 1996 Alex Korobka + * Copyright 2001 Alexandre Julliard + * Copyright 2002 Dimitrie O. Paun * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -95,19 +97,176 @@ /************************************************************************* + * USER_ScrollDC [Internal] + * + * Internal implementation of the ScrollDC function. + */ +static BOOL USER_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc, + const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate ) +{ + RECT rect, rClip, rDst; + + /* compute device clipping region (in device coordinates) */ + + if (rc) rect = *rc; + else GetClipBox( hdc, &rect ); + + if (clipRect) + { + rClip = *clipRect; + IntersectRect( &rClip, &rect, &rClip ); + } + else rClip = rect; + + rDst = rClip; + OffsetRect( &rDst, dx, dy ); + IntersectRect( &rDst, &rDst, &rClip ); + + if (!IsRectEmpty(&rDst)) + { + /* copy bits */ + if (!BitBlt( hdc, rDst.left, rDst.top, + rDst.right - rDst.left, rDst.bottom - rDst.top, + hdc, rDst.left - dx, rDst.top - dy, SRCCOPY)) + return FALSE; + } + + /* compute update areas */ + + if (hrgnUpdate || rcUpdate) + { + HRGN hrgn = hrgnUpdate, hrgn2; + + /* map everything to device coordinates */ + LPtoDP( hdc, (LPPOINT)&rClip, 2 ); + LPtoDP( hdc, (LPPOINT)&rDst, 2 ); + + hrgn2 = CreateRectRgnIndirect( &rDst ); + if (hrgn) SetRectRgn( hrgn, rClip.left, rClip.top, rClip.right, rClip.bottom ); + else hrgn = CreateRectRgn( rClip.left, rClip.top, rClip.right, rClip.bottom ); + CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF ); + + if( rcUpdate ) + { + GetRgnBox( hrgn, rcUpdate ); + + /* Put the rcUpdate in logical coordinate */ + DPtoLP( hdc, (LPPOINT)rcUpdate, 2 ); + } + if (!hrgnUpdate) DeleteObject( hrgn ); + DeleteObject( hrgn2 ); + } + return TRUE; +} + +/************************************************************************* * ScrollDC (USER32.@) * * Only the hrgnUpdate is return in device coordinate. * rcUpdate must be returned in logical coordinate to comply with win API. + * FIXME: the doc explicitly states the opposite, to be checked * */ BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc, - const RECT *prLClip, HRGN hrgnUpdate, - LPRECT rcUpdate ) + const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate ) { + TRACE( "%04x %d,%d hrgnUpdate=%04x rcUpdate = %p\n", hdc, dx, dy, hrgnUpdate, rcUpdate ); + + if (clipRect) TRACE( "cliprc = (%d,%d,%d,%d)\n", + clipRect->left, clipRect->top, clipRect->right, clipRect->bottom ); + + if (rc) TRACE( "rc = (%d,%d,%d,%d)\n", rc->left, rc->top, rc->right, rc->bottom ); + if (USER_Driver.pScrollDC) - return USER_Driver.pScrollDC( hdc, dx, dy, rc, prLClip, hrgnUpdate, rcUpdate ); - return FALSE; + return USER_Driver.pScrollDC( hdc, dx, dy, rc, clipRect, hrgnUpdate, rcUpdate ); + else + return USER_ScrollDC( hdc, dx, dy, rc, clipRect, hrgnUpdate, rcUpdate ); +} + +/************************************************************************* + * USER_ScrollWindowEx [Internal] + * + * 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. + */ +static INT USER_ScrollWindowEx( 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 hrgnClip = CreateRectRgnIndirect(clipRect); + HRGN hrgnTemp; + HDC hDC; + + TRACE( "%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p rect=(%d,%d-%d,%d) %04x\n", + hwnd, dx, dy, hrgnUpdate, rcUpdate, + rect->left, rect->top, rect->right, rect->bottom, flags ); + TRACE( "clipRect = (%d,%d,%d,%d)\n", + clipRect->left, clipRect->top, clipRect->right, clipRect->bottom ); + + if( hrgnUpdate ) bOwnRgn = FALSE; + else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ); + + hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE ); + if (hDC) + { + HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 ); + USER_Driver.pStartGraphicsExposures( hDC ); + ScrollDC( hDC, dx, dy, rect, clipRect, hrgnUpdate, rcUpdate ); + USER_Driver.pEndGraphicsExposures( hDC, hrgn ); + ReleaseDC( hwnd, hDC ); + if (bUpdate) CombineRgn( hrgnUpdate, hrgnUpdate, hrgn, RGN_OR ); + else RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE ); + DeleteObject( hrgn ); + } + + /* Take into account the fact that some damages may have occured during the scroll */ + hrgnTemp = CreateRectRgn( 0, 0, 0, 0 ); + retVal = GetUpdateRgn( hwnd, hrgnTemp, FALSE ); + if (retVal != NULLREGION) + { + OffsetRgn( hrgnTemp, dx, dy ); + CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND ); + RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE ); + } + 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, rect)) + 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 ); + DeleteObject( hrgnClip ); + + return retVal; } @@ -142,7 +301,8 @@ result = USER_Driver.pScrollWindowEx( hwnd, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate, flags ); else - result = ERROR; /* FIXME: we should have a fallback implementation */ + result = USER_ScrollWindowEx( hwnd, dx, dy, &rc, &cliprc, + hrgnUpdate, rcUpdate, flags ); if( hwndCaret ) { @@ -155,3 +315,4 @@ return result; } +