scroll.c 6.73 KB
Newer Older
1 2 3 4 5 6
/*
 * Scroll windows and DCs
 *
 * Copyright 1993  David W. Metcalfe
 * Copyright 1995, 1996 Alex Korobka
 * Copyright 2001 Alexandre Julliard
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 22 23 24
 */

#include "config.h"

25
#include <stdarg.h>
26
#include <X11/Xlib.h>
27

28
#include "windef.h"
29 30 31 32 33
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"

#include "x11drv.h"
34
#include "wine/debug.h"
35

36
WINE_DEFAULT_DEBUG_CHANNEL(scroll);
37

38
static void dump_region( const char *p, HRGN hrgn)
39 40 41 42 43 44 45 46 47 48 49 50 51 52
{
    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 );
53
    TRACE("%s %d rects:", p, data->rdh.nCount );
54 55 56 57 58
    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 );
}
59 60

/*************************************************************************
61
 *		ScrollDC   (X11DRV.@)
62
 */
63 64
BOOL CDECL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
                            const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
65
{
66 67 68
    RECT rcSrc, rcClip, offset;
    INT dxdev, dydev, res;
    HRGN DstRgn, clipRgn, visrgn;
69
    INT code = X11DRV_START_EXPOSURES;
70

71 72 73
    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);
74
    /* enable X-exposure events */
75 76
    if (hrgnUpdate || lprcUpdate)
        ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    /* 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
94 95 96
     * rect are scrolled. */
    if( lprcClip) 
        rcClip = *lprcClip;
97
    else
98
        GetClipBox( hdc, &rcClip);
99
    rcSrc = rcClip;
100 101 102 103 104 105
    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);
106 107
    /* now convert to device coordinates */
    LPtoDP(hdc, (LPPOINT)&rcSrc, 2);
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
108
    TRACE("source rect: %s\n", wine_dbgstr_rect(&rcSrc));
109
    /* also dx and dy */
110 111
    SetRect(&offset, 0, 0, dx, dy);
    LPtoDP(hdc, (LPPOINT)&offset, 2);
112
    dxdev = offset.right - offset.left;
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
113
    dydev = offset.bottom - offset.top;
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    /* 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);
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
132 133
        TRACE("destination rect: %s\n", wine_dbgstr_rect(&rect));

134
        BitBlt( hdc, rect.left, rect.top,
135
                    rect.right - rect.left, rect.bottom - rect.top,
136
                    hdc, rect.left - dx, rect.top - dy, SRCCOPY);
137
    }
138 139 140
    /* compute the update areas.  This is the combined clip rectangle
     * minus the scrolled region, and intersected with the visible
     * region. */
141
    if (hrgnUpdate || lprcUpdate)
142
    {
143 144
        HRGN hrgn = hrgnUpdate;
        HRGN ExpRgn = 0;
145

146
        /* collect all the exposures */
147
        code = X11DRV_END_EXPOSURES;
148 149
        ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code,
                sizeof(ExpRgn), (LPSTR)&ExpRgn );
150 151 152 153 154 155 156 157 158 159 160
        /* 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);
Dmitry Timoshkov's avatar
Dmitry Timoshkov committed
161
        /* Convert the combined clip rectangle to device coordinates */
162 163 164 165 166 167 168 169 170 171 172 173 174
        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);
175
        }
176 177
        if( TRACE_ON( scroll)) dump_region( "Update region: ", hrgn);
        if( lprcUpdate) {
178
            GetRgnBox( hrgn, lprcUpdate );
179
            /* Put the lprcUpdate in logical coordinates */
180 181 182
            DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
            TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
        }
183 184
        if( !hrgnUpdate)
            DeleteObject( hrgn);
185
    }
186
    /* restore original clipping region */
187 188 189 190
    SelectClipRgn( hdc, clipRgn);
    DeleteObject( visrgn);
    DeleteObject( DstRgn);
    if( clipRgn) DeleteObject( clipRgn);
191
    return TRUE;
192
}