2 * Scroll windows and DCs
4 * Copyright 1993 David W. Metcalfe
5 * Copyright 1995, 1996 Alex Korobka
6 * Copyright 2001 Alexandre Julliard
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(scroll);
25 /*************************************************************************
28 static BOOL fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
30 HWND hCaret = CARET_GetHwnd();
37 (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
42 MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
43 if( IntersectRect(lprc, lprc, &rc) )
56 /*************************************************************************
59 * Only the hrgnUpdate is returned in device coordinates.
60 * rcUpdate must be returned in logical coordinates to comply with win API.
61 * FIXME: the doc explicitly states the opposite, to be checked
63 BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc,
64 const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate )
66 RECT rect, rClip, rDst;
68 TRACE( "%04x %d,%d hrgnUpdate=%04x rcUpdate = %p\n", hdc, dx, dy, hrgnUpdate, rcUpdate );
69 if (clipRect) TRACE( "cliprc = (%d,%d,%d,%d)\n",
70 clipRect->left, clipRect->top, clipRect->right, clipRect->bottom );
71 if (rc) TRACE( "rc = (%d,%d,%d,%d)\n", rc->left, rc->top, rc->right, rc->bottom );
73 /* compute device clipping region (in device coordinates) */
76 else GetClipBox( hdc, &rect );
81 IntersectRect( &rClip, &rect, &rClip );
86 OffsetRect( &rDst, dx, dy );
87 IntersectRect( &rDst, &rDst, &rClip );
89 if (!IsRectEmpty(&rDst))
92 if (!BitBlt( hdc, rDst.left, rDst.top,
93 rDst.right - rDst.left, rDst.bottom - rDst.top,
94 hdc, rDst.left - dx, rDst.top - dy, SRCCOPY))
98 /* compute update areas */
100 if (hrgnUpdate || rcUpdate)
102 HRGN hrgn = hrgnUpdate, hrgn2;
104 /* map everything to device coordinates */
105 LPtoDP( hdc, (LPPOINT)&rClip, 2 );
106 LPtoDP( hdc, (LPPOINT)&rDst, 2 );
108 hrgn2 = CreateRectRgnIndirect( &rDst );
109 if (hrgn) SetRectRgn( hrgn, rClip.left, rClip.top, rClip.right, rClip.bottom );
110 else hrgn = CreateRectRgn( rClip.left, rClip.top, rClip.right, rClip.bottom );
111 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
115 GetRgnBox( hrgn, rcUpdate );
117 /* Put the rcUpdate in logical coordinate */
118 DPtoLP( hdc, (LPPOINT)rcUpdate, 2 );
120 if (!hrgnUpdate) DeleteObject( hrgn );
121 DeleteObject( hrgn2 );
127 /*************************************************************************
128 * ScrollWindowEx (X11DRV.@)
130 * Note: contrary to what the doc says, pixels that are scrolled from the
131 * outside of clipRect to the inside are NOT painted.
133 INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
134 const RECT *rect, const RECT *clipRect,
135 HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
137 INT retVal = NULLREGION;
138 BOOL bCaret = FALSE, bOwnRgn = TRUE;
141 if (!WIN_IsWindowDrawable( hwnd, TRUE )) return ERROR;
142 hwnd = WIN_GetFullHandle( hwnd );
144 GetClientRect(hwnd, &rc);
145 if (rect) IntersectRect(&rc, &rc, rect);
147 if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
150 if (!IsRectEmpty(&cliprc) && (dx || dy))
153 BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
154 HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
158 TRACE( "%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p rc=(%d,%d-%d,%d) %04x\n",
159 hwnd, dx, dy, hrgnUpdate, rcUpdate,
160 rc.left, rc.top, rc.right, rc.bottom, flags );
161 if (clipRect) TRACE( "cliprc = (%d,%d,%d,%d)\n",
162 clipRect->left, clipRect->top,
163 clipRect->right, clipRect->bottom );
166 bCaret = fix_caret(hwnd, &caretrc, flags);
168 if( hrgnUpdate ) bOwnRgn = FALSE;
169 else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
171 hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
174 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
175 X11DRV_StartGraphicsExposures( hDC );
176 X11DRV_ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
177 X11DRV_EndGraphicsExposures( hDC, hrgn );
178 ReleaseDC( hwnd, hDC );
179 if (bUpdate) CombineRgn( hrgnUpdate, hrgnUpdate, hrgn, RGN_OR );
180 else RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
181 DeleteObject( hrgn );
184 /* Take into account the fact that some damages may have occured during the scroll */
185 hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
186 if (GetUpdateRgn( hwnd, hrgnTemp, FALSE ) != NULLREGION)
188 OffsetRgn( hrgnTemp, dx, dy );
189 CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
190 RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
192 DeleteObject( hrgnTemp );
194 if( flags & SW_SCROLLCHILDREN )
196 HWND *list = WIN_ListChildren( hwnd );
202 for (i = 0; list[i]; i++)
204 GetWindowRect( list[i], &r );
205 MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
206 if (!rect || IntersectRect(&dummy, &r, &rc))
207 SetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0,
208 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
209 SWP_NOREDRAW | SWP_DEFERERASE );
211 HeapFree( GetProcessHeap(), 0, list );
215 if( flags & (SW_INVALIDATE | SW_ERASE) )
216 RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
217 ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
218 ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
222 SetCaretPos( caretrc.left + dx, caretrc.top + dy );
226 if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
227 DeleteObject( hrgnClip );