mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-01 22:50:08 +00:00
a807c5efce
within the visible region, clipped to the clipping region if that exists. Add the destination of pixels coming from the outside of this region to the update region. With tests that depend on this.
181 lines
6.3 KiB
C
181 lines
6.3 KiB
C
/*
|
|
* Scroll windows and DCs
|
|
*
|
|
* Copyright 1993 David W. Metcalfe
|
|
* Copyright 1995, 1996 Alex Korobka
|
|
* Copyright 2001 Alexandre Julliard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdarg.h>
|
|
#include <X11/Xlib.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
|
|
#include "x11drv.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(scroll);
|
|
|
|
static void dump_region( char *p, HRGN hrgn)
|
|
{
|
|
DWORD i, size;
|
|
RGNDATA *data = NULL;
|
|
RECT *rect;
|
|
|
|
if (!hrgn) {
|
|
TRACE( "%s null region\n", p );
|
|
return;
|
|
}
|
|
if (!(size = GetRegionData( hrgn, 0, NULL ))) {
|
|
return;
|
|
}
|
|
if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
|
|
GetRegionData( hrgn, size, data );
|
|
TRACE("%s %ld rects:", p, data->rdh.nCount );
|
|
for (i = 0, rect = (RECT *)data->Buffer; i<20 && i < data->rdh.nCount; i++, rect++)
|
|
TRACE( " %s", wine_dbgstr_rect( rect));
|
|
TRACE("\n");
|
|
HeapFree( GetProcessHeap(), 0, data );
|
|
}
|
|
|
|
/*************************************************************************
|
|
* ScrollDC (X11DRV.@)
|
|
*/
|
|
BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
|
|
const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
|
|
{
|
|
RECT rcSrc, rcClip, offset;
|
|
INT dxdev, dydev, res;
|
|
HRGN DstRgn, clipRgn, visrgn;
|
|
INT code = X11DRV_START_EXPOSURES;
|
|
|
|
TRACE("dx,dy %d,%d lprcScroll %p lprcClip %p hrgnUpdate %p lprcUpdate %p\n",
|
|
dx, dy, lprcScroll, lprcClip, hrgnUpdate, lprcUpdate);
|
|
/* enable X-exposure events */
|
|
if (hrgnUpdate || lprcUpdate)
|
|
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
|
|
/* get the visible region */
|
|
visrgn=CreateRectRgn( 0, 0, 0, 0);
|
|
GetRandomRgn( hdc, visrgn, SYSRGN);
|
|
if( !(GetVersion() & 0x80000000)) {
|
|
/* Window NT/2k/XP */
|
|
POINT org;
|
|
GetDCOrgEx(hdc, &org);
|
|
OffsetRgn( visrgn, -org.x, -org.y);
|
|
}
|
|
/* intersect with the clipping Region if the DC has one */
|
|
clipRgn = CreateRectRgn( 0, 0, 0, 0);
|
|
if (GetClipRgn( hdc, clipRgn) != 1) {
|
|
DeleteObject(clipRgn);
|
|
clipRgn=NULL;
|
|
} else
|
|
CombineRgn( visrgn, visrgn, clipRgn, RGN_AND);
|
|
/* only those pixels in the scroll rectangle that remain in the clipping
|
|
* rect are scrolled. So first combine Scroll and Clipping rectangles,
|
|
* if available */
|
|
if( lprcScroll)
|
|
if( lprcClip)
|
|
IntersectRect( &rcClip, lprcClip, lprcScroll);
|
|
else
|
|
rcClip = *lprcScroll;
|
|
else
|
|
if( lprcClip)
|
|
rcClip = *lprcClip;
|
|
else
|
|
GetClipBox( hdc, &rcClip);
|
|
/* Then clip again to get the source rectangle that will remain in the
|
|
* clipping rect */
|
|
rcSrc = rcClip;
|
|
OffsetRect( &rcSrc, -dx, -dy);
|
|
IntersectRect( &rcSrc, &rcSrc, &rcClip);
|
|
/* now convert to device coordinates */
|
|
LPtoDP(hdc, (LPPOINT)&rcSrc, 2);
|
|
/* also dx and dy */
|
|
SetRect(&offset, 0, 0, dx, dy);
|
|
LPtoDP(hdc, (LPPOINT)&offset, 2);
|
|
dxdev = offset.right - offset.left;
|
|
dydev= offset.bottom - offset.top;
|
|
/* now intersect with the visible region to get the pixels that will
|
|
* actually scroll */
|
|
DstRgn = CreateRectRgnIndirect( &rcSrc);
|
|
res = CombineRgn( DstRgn, DstRgn, visrgn, RGN_AND);
|
|
/* and translate, giving the destination region */
|
|
OffsetRgn( DstRgn, dxdev, dydev);
|
|
if( TRACE_ON( scroll)) dump_region( "Destination scroll region: ", DstRgn);
|
|
/* if there are any, do it */
|
|
if( res > NULLREGION) {
|
|
RECT rect ;
|
|
/* clip to the destination region, so we can BitBlt with a simple
|
|
* bounding rectangle */
|
|
if( clipRgn)
|
|
ExtSelectClipRgn( hdc, DstRgn, RGN_AND);
|
|
else
|
|
SelectClipRgn( hdc, DstRgn);
|
|
GetRgnBox( DstRgn, &rect);
|
|
DPtoLP(hdc, (LPPOINT)&rect, 2);
|
|
BitBlt( hdc, rect.left, rect.top,
|
|
rect.right - rect.left, rect.bottom -rect.top,
|
|
hdc, rect.left - dx, rect.top - dy, SRCCOPY);
|
|
}
|
|
/* compute the update areas. This is the combined clip rectangle
|
|
* minus the scrolled region, and intersected with the visible
|
|
* region. */
|
|
if (hrgnUpdate || lprcUpdate)
|
|
{
|
|
HRGN hrgn = hrgnUpdate;
|
|
HRGN ExpRgn = 0;
|
|
|
|
/* collect all the exposures */
|
|
code = X11DRV_END_EXPOSURES;
|
|
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code,
|
|
sizeof(ExpRgn), (LPSTR)&ExpRgn );
|
|
/* Covert the combined clip rectangle to device coordinates */
|
|
LPtoDP(hdc, (LPPOINT)&rcClip, 2);
|
|
if( hrgn )
|
|
SetRectRgn( hrgn, rcClip.left, rcClip.top, rcClip.right,
|
|
rcClip.bottom);
|
|
else
|
|
hrgn = CreateRectRgnIndirect( &rcClip);
|
|
CombineRgn( hrgn, hrgn, visrgn, RGN_AND);
|
|
CombineRgn( hrgn, hrgn, DstRgn, RGN_DIFF);
|
|
/* add the exposures to this */
|
|
if( ExpRgn) {
|
|
if( TRACE_ON( scroll)) dump_region( "Expose region: ", ExpRgn);
|
|
CombineRgn( hrgn, hrgn, ExpRgn, RGN_OR);
|
|
DeleteObject( ExpRgn);
|
|
}
|
|
if( TRACE_ON( scroll)) dump_region( "Update region: ", hrgn);
|
|
if( lprcUpdate) {
|
|
GetRgnBox( hrgn, lprcUpdate );
|
|
/* Put the lprcUpdate in logical coordinates */
|
|
DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
|
|
TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
|
|
}
|
|
if( !hrgnUpdate)
|
|
DeleteObject( hrgn);
|
|
}
|
|
SelectClipRgn( hdc, clipRgn);
|
|
DeleteObject( visrgn);
|
|
DeleteObject( DstRgn);
|
|
if( clipRgn) DeleteObject( clipRgn);
|
|
return TRUE;
|
|
}
|