gdiplus: First pen implementation.
[wine.git] / dlls / winex11.drv / scroll.c
blob70b2f4006ed55847c146f8b47095b649106bad00
1 /*
2 * Scroll windows and DCs
4 * Copyright 1993 David W. Metcalfe
5 * Copyright 1995, 1996 Alex Korobka
6 * Copyright 2001 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * 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
23 #include "config.h"
25 #include <stdarg.h>
26 #include <X11/Xlib.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
33 #include "x11drv.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
38 static void dump_region( const char *p, HRGN hrgn)
40 DWORD i, size;
41 RGNDATA *data = NULL;
42 RECT *rect;
44 if (!hrgn) {
45 TRACE( "%s null region\n", p );
46 return;
48 if (!(size = GetRegionData( hrgn, 0, NULL ))) {
49 return;
51 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
52 GetRegionData( hrgn, size, data );
53 TRACE("%s %d rects:", p, data->rdh.nCount );
54 for (i = 0, rect = (RECT *)data->Buffer; i<20 && i < data->rdh.nCount; i++, rect++)
55 TRACE( " %s", wine_dbgstr_rect( rect));
56 TRACE("\n");
57 HeapFree( GetProcessHeap(), 0, data );
60 /*************************************************************************
61 * ScrollDC (X11DRV.@)
63 BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *lprcScroll,
64 const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate )
66 RECT rcSrc, rcClip, offset;
67 INT dxdev, dydev, res;
68 HRGN DstRgn, clipRgn, visrgn;
69 INT code = X11DRV_START_EXPOSURES;
71 TRACE("dx,dy %d,%d rcScroll %s rcClip %s hrgnUpdate %p lprcUpdate %p\n",
72 dx, dy, wine_dbgstr_rect(lprcScroll), wine_dbgstr_rect(lprcClip),
73 hrgnUpdate, lprcUpdate);
74 /* enable X-exposure events */
75 if (hrgnUpdate || lprcUpdate)
76 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
77 /* get the visible region */
78 visrgn=CreateRectRgn( 0, 0, 0, 0);
79 GetRandomRgn( hdc, visrgn, SYSRGN);
80 if( !(GetVersion() & 0x80000000)) {
81 /* Window NT/2k/XP */
82 POINT org;
83 GetDCOrgEx(hdc, &org);
84 OffsetRgn( visrgn, -org.x, -org.y);
86 /* intersect with the clipping Region if the DC has one */
87 clipRgn = CreateRectRgn( 0, 0, 0, 0);
88 if (GetClipRgn( hdc, clipRgn) != 1) {
89 DeleteObject(clipRgn);
90 clipRgn=NULL;
91 } else
92 CombineRgn( visrgn, visrgn, clipRgn, RGN_AND);
93 /* only those pixels in the scroll rectangle that remain in the clipping
94 * rect are scrolled. */
95 if( lprcClip)
96 rcClip = *lprcClip;
97 else
98 GetClipBox( hdc, &rcClip);
99 rcSrc = rcClip;
100 OffsetRect( &rcClip, -dx, -dy);
101 IntersectRect( &rcSrc, &rcSrc, &rcClip);
102 /* if an scroll rectangle is specified, only the pixels within that
103 * rectangle are scrolled */
104 if( lprcScroll)
105 IntersectRect( &rcSrc, &rcSrc, lprcScroll);
106 /* now convert to device coordinates */
107 LPtoDP(hdc, (LPPOINT)&rcSrc, 2);
108 TRACE("source rect: %s\n", wine_dbgstr_rect(&rcSrc));
109 /* also dx and dy */
110 SetRect(&offset, 0, 0, dx, dy);
111 LPtoDP(hdc, (LPPOINT)&offset, 2);
112 dxdev = offset.right - offset.left;
113 dydev = offset.bottom - offset.top;
114 /* now intersect with the visible region to get the pixels that will
115 * actually scroll */
116 DstRgn = CreateRectRgnIndirect( &rcSrc);
117 res = CombineRgn( DstRgn, DstRgn, visrgn, RGN_AND);
118 /* and translate, giving the destination region */
119 OffsetRgn( DstRgn, dxdev, dydev);
120 if( TRACE_ON( scroll)) dump_region( "Destination scroll region: ", DstRgn);
121 /* if there are any, do it */
122 if( res > NULLREGION) {
123 RECT rect ;
124 /* clip to the destination region, so we can BitBlt with a simple
125 * bounding rectangle */
126 if( clipRgn)
127 ExtSelectClipRgn( hdc, DstRgn, RGN_AND);
128 else
129 SelectClipRgn( hdc, DstRgn);
130 GetRgnBox( DstRgn, &rect);
131 DPtoLP(hdc, (LPPOINT)&rect, 2);
132 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);
138 /* compute the update areas. This is the combined clip rectangle
139 * minus the scrolled region, and intersected with the visible
140 * region. */
141 if (hrgnUpdate || lprcUpdate)
143 HRGN hrgn = hrgnUpdate;
144 HRGN ExpRgn = 0;
146 /* collect all the exposures */
147 code = X11DRV_END_EXPOSURES;
148 ExtEscape( hdc, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code,
149 sizeof(ExpRgn), (LPSTR)&ExpRgn );
150 /* Intersect clip and scroll rectangles, allowing NULL values */
151 if( lprcScroll)
152 if( lprcClip)
153 IntersectRect( &rcClip, lprcClip, lprcScroll);
154 else
155 rcClip = *lprcScroll;
156 else
157 if( lprcClip)
158 rcClip = *lprcClip;
159 else
160 GetClipBox( hdc, &rcClip);
161 /* Convert the combined clip rectangle to device coordinates */
162 LPtoDP(hdc, (LPPOINT)&rcClip, 2);
163 if( hrgn )
164 SetRectRgn( hrgn, rcClip.left, rcClip.top, rcClip.right,
165 rcClip.bottom);
166 else
167 hrgn = CreateRectRgnIndirect( &rcClip);
168 CombineRgn( hrgn, hrgn, visrgn, RGN_AND);
169 CombineRgn( hrgn, hrgn, DstRgn, RGN_DIFF);
170 /* add the exposures to this */
171 if( ExpRgn) {
172 if( TRACE_ON( scroll)) dump_region( "Expose region: ", ExpRgn);
173 CombineRgn( hrgn, hrgn, ExpRgn, RGN_OR);
174 DeleteObject( ExpRgn);
176 if( TRACE_ON( scroll)) dump_region( "Update region: ", hrgn);
177 if( lprcUpdate) {
178 GetRgnBox( hrgn, lprcUpdate );
179 /* Put the lprcUpdate in logical coordinates */
180 DPtoLP( hdc, (LPPOINT)lprcUpdate, 2 );
181 TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate));
183 if( !hrgnUpdate)
184 DeleteObject( hrgn);
186 /* restore original clipping region */
187 SelectClipRgn( hdc, clipRgn);
188 DeleteObject( visrgn);
189 DeleteObject( DstRgn);
190 if( clipRgn) DeleteObject( clipRgn);
191 return TRUE;