Commit 06a60621 authored by Ulrich Czekalla's avatar Ulrich Czekalla Committed by Alexandre Julliard

ScrollDC should take into account overlapped windows. With this change

ScrollWindowEx can be moved out of X11drv.
parent a98f0dff
......@@ -110,7 +110,7 @@ static BOOL load_driver(void)
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);
......
......@@ -38,98 +38,94 @@ WINE_DEFAULT_DEBUG_CHANNEL(scroll);
/*************************************************************************
* 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;
RECT rSrc, rClipped_src, rClip, rDst, offset;
INT code = X11DRV_START_EXPOSURES;
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));
if (hrgnUpdate || lprcUpdate)
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
GetClientRect(hwnd, &rc);
if (rect) IntersectRect(&rc, &rc, rect);
/* compute device clipping region (in device coordinates) */
if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
else cliprc = rc;
if (lprcScroll) rSrc = *lprcScroll;
else GetClipBox( hdc, &rSrc );
LPtoDP(hdc, (LPPOINT)&rSrc, 2);
if( hrgnUpdate ) bOwnRgn = FALSE;
else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
if (lprcClip) rClip = *lprcClip;
else GetClipBox( hdc, &rClip );
LPtoDP(hdc, (LPPOINT)&rClip, 2);
hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
if (hDC)
{
enum x11drv_escape_codes code = X11DRV_START_EXPOSURES;
HRGN hrgn = 0;
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));
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 );
}
}
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));
/* 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)
if (!IsRectEmpty(&rDst))
{
HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
OffsetRgn( hrgnTemp, dx, dy );
CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
DeleteObject( hrgnClip );
/* copy bits */
RECT rDst_lp = rDst, rSrc_lp = rDst;
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;
}
DeleteObject( hrgnTemp );
if( flags & SW_SCROLLCHILDREN )
/* 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 (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( lprcUpdate )
{
GetRgnBox( hrgn, lprcUpdate );
if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
return retVal;
/* 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;
}
......@@ -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
......
......@@ -113,7 +113,7 @@ typedef struct tagUSER_DRIVER {
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 *);
......
......@@ -60,6 +60,93 @@ static HWND fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
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.
*/
static 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 @@ BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
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 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy,
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 );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment