193 lines
6.7 KiB
C
193 lines
6.7 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( const 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 rcScroll %s rcClip %s hrgnUpdate %p lprcUpdate %p\n",
|
|
dx, dy, wine_dbgstr_rect(lprcScroll), wine_dbgstr_rect(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. */
|
|
if( lprcClip)
|
|
rcClip = *lprcClip;
|
|
else
|
|
GetClipBox( hdc, &rcClip);
|
|
rcSrc = rcClip;
|
|
OffsetRect( &rcClip, -dx, -dy);
|
|
IntersectRect( &rcSrc, &rcSrc, &rcClip);
|
|
/* if an scroll rectangle is specified, only the pixels within that
|
|
* rectangle are scrolled */
|
|
if( lprcScroll)
|
|
IntersectRect( &rcSrc, &rcSrc, lprcScroll);
|
|
/* now convert to device coordinates */
|
|
LPtoDP(hdc, (LPPOINT)&rcSrc, 2);
|
|
TRACE("source rect: %s\n", wine_dbgstr_rect(&rcSrc));
|
|
/* 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);
|
|
TRACE("destination rect: %s\n", wine_dbgstr_rect(&rect));
|
|
|
|
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 );
|
|
/* Intersect clip and scroll rectangles, allowing NULL values */
|
|
if( lprcScroll)
|
|
if( lprcClip)
|
|
IntersectRect( &rcClip, lprcClip, lprcScroll);
|
|
else
|
|
rcClip = *lprcScroll;
|
|
else
|
|
if( lprcClip)
|
|
rcClip = *lprcClip;
|
|
else
|
|
GetClipBox( hdc, &rcClip);
|
|
/* Convert 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);
|
|
}
|
|
/* restore original clipping region */
|
|
SelectClipRgn( hdc, clipRgn);
|
|
DeleteObject( visrgn);
|
|
DeleteObject( DstRgn);
|
|
if( clipRgn) DeleteObject( clipRgn);
|
|
return TRUE;
|
|
}
|