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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(scroll
);
39 /*************************************************************************
42 static BOOL
fix_caret(HWND hWnd
, LPRECT lprc
, UINT flags
)
44 HWND hCaret
= CARET_GetHwnd();
51 (flags
& SW_SCROLLCHILDREN
&& IsChild(hWnd
, hCaret
)) )
56 MapWindowPoints( hCaret
, hWnd
, (LPPOINT
)&rc
, 2 );
57 if( IntersectRect(lprc
, lprc
, &rc
) )
70 /*************************************************************************
73 * Only the hrgnUpdate is returned in device coordinates.
74 * rcUpdate must be returned in logical coordinates to comply with win API.
75 * FIXME: the doc explicitly states the opposite, to be checked
77 BOOL
X11DRV_ScrollDC( HDC hdc
, INT dx
, INT dy
, const RECT
*rc
,
78 const RECT
*clipRect
, HRGN hrgnUpdate
, LPRECT rcUpdate
)
80 RECT rect
, rClip
, rDst
;
82 TRACE( "%04x %d,%d hrgnUpdate=%04x rcUpdate = %p\n", hdc
, dx
, dy
, hrgnUpdate
, rcUpdate
);
83 if (clipRect
) TRACE( "cliprc = (%d,%d,%d,%d)\n",
84 clipRect
->left
, clipRect
->top
, clipRect
->right
, clipRect
->bottom
);
85 if (rc
) TRACE( "rc = (%d,%d,%d,%d)\n", rc
->left
, rc
->top
, rc
->right
, rc
->bottom
);
87 /* compute device clipping region (in device coordinates) */
90 else GetClipBox( hdc
, &rect
);
95 IntersectRect( &rClip
, &rect
, &rClip
);
100 OffsetRect( &rDst
, dx
, dy
);
101 IntersectRect( &rDst
, &rDst
, &rClip
);
103 if (!IsRectEmpty(&rDst
))
106 if (!BitBlt( hdc
, rDst
.left
, rDst
.top
,
107 rDst
.right
- rDst
.left
, rDst
.bottom
- rDst
.top
,
108 hdc
, rDst
.left
- dx
, rDst
.top
- dy
, SRCCOPY
))
112 /* compute update areas */
114 if (hrgnUpdate
|| rcUpdate
)
116 HRGN hrgn
= hrgnUpdate
, hrgn2
;
118 /* map everything to device coordinates */
119 LPtoDP( hdc
, (LPPOINT
)&rClip
, 2 );
120 LPtoDP( hdc
, (LPPOINT
)&rDst
, 2 );
122 hrgn2
= CreateRectRgnIndirect( &rDst
);
123 if (hrgn
) SetRectRgn( hrgn
, rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
124 else hrgn
= CreateRectRgn( rClip
.left
, rClip
.top
, rClip
.right
, rClip
.bottom
);
125 CombineRgn( hrgn
, hrgn
, hrgn2
, RGN_DIFF
);
129 GetRgnBox( hrgn
, rcUpdate
);
131 /* Put the rcUpdate in logical coordinate */
132 DPtoLP( hdc
, (LPPOINT
)rcUpdate
, 2 );
134 if (!hrgnUpdate
) DeleteObject( hrgn
);
135 DeleteObject( hrgn2
);
141 /*************************************************************************
142 * ScrollWindowEx (X11DRV.@)
144 * Note: contrary to what the doc says, pixels that are scrolled from the
145 * outside of clipRect to the inside are NOT painted.
147 INT
X11DRV_ScrollWindowEx( HWND hwnd
, INT dx
, INT dy
,
148 const RECT
*rect
, const RECT
*clipRect
,
149 HRGN hrgnUpdate
, LPRECT rcUpdate
, UINT flags
)
151 INT retVal
= NULLREGION
;
152 BOOL bCaret
= FALSE
, bOwnRgn
= TRUE
;
155 if (!WIN_IsWindowDrawable( hwnd
, TRUE
)) return ERROR
;
156 hwnd
= WIN_GetFullHandle( hwnd
);
158 GetClientRect(hwnd
, &rc
);
159 if (rect
) IntersectRect(&rc
, &rc
, rect
);
161 if (clipRect
) IntersectRect(&cliprc
,&rc
,clipRect
);
164 if (!IsRectEmpty(&cliprc
) && (dx
|| dy
))
167 BOOL bUpdate
= (rcUpdate
|| hrgnUpdate
|| flags
& (SW_INVALIDATE
| SW_ERASE
));
168 HRGN hrgnClip
= CreateRectRgnIndirect(&cliprc
);
172 TRACE( "%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p rc=(%d,%d-%d,%d) %04x\n",
173 hwnd
, dx
, dy
, hrgnUpdate
, rcUpdate
,
174 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, flags
);
175 if (clipRect
) TRACE( "cliprc = (%d,%d,%d,%d)\n",
176 clipRect
->left
, clipRect
->top
,
177 clipRect
->right
, clipRect
->bottom
);
180 bCaret
= fix_caret(hwnd
, &caretrc
, flags
);
182 if( hrgnUpdate
) bOwnRgn
= FALSE
;
183 else if( bUpdate
) hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
185 hDC
= GetDCEx( hwnd
, 0, DCX_CACHE
| DCX_USESTYLE
);
188 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
189 X11DRV_StartGraphicsExposures( hDC
);
190 X11DRV_ScrollDC( hDC
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
191 X11DRV_EndGraphicsExposures( hDC
, hrgn
);
192 ReleaseDC( hwnd
, hDC
);
193 if (bUpdate
) CombineRgn( hrgnUpdate
, hrgnUpdate
, hrgn
, RGN_OR
);
194 else RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| RDW_ERASE
);
195 DeleteObject( hrgn
);
198 /* Take into account the fact that some damages may have occured during the scroll */
199 hrgnTemp
= CreateRectRgn( 0, 0, 0, 0 );
200 if (GetUpdateRgn( hwnd
, hrgnTemp
, FALSE
) != NULLREGION
)
202 OffsetRgn( hrgnTemp
, dx
, dy
);
203 CombineRgn( hrgnTemp
, hrgnTemp
, hrgnClip
, RGN_AND
);
204 RedrawWindow( hwnd
, NULL
, hrgnTemp
, RDW_INVALIDATE
| RDW_ERASE
);
206 DeleteObject( hrgnTemp
);
208 if( flags
& SW_SCROLLCHILDREN
)
210 HWND
*list
= WIN_ListChildren( hwnd
);
216 for (i
= 0; list
[i
]; i
++)
218 GetWindowRect( list
[i
], &r
);
219 MapWindowPoints( 0, hwnd
, (POINT
*)&r
, 2 );
220 if (!rect
|| IntersectRect(&dummy
, &r
, &rc
))
221 SetWindowPos( list
[i
], 0, r
.left
+ dx
, r
.top
+ dy
, 0, 0,
222 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
|
223 SWP_NOREDRAW
| SWP_DEFERERASE
);
225 HeapFree( GetProcessHeap(), 0, list
);
229 if( flags
& (SW_INVALIDATE
| SW_ERASE
) )
230 RedrawWindow( hwnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
231 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0) |
232 ((flags
& SW_SCROLLCHILDREN
) ? RDW_ALLCHILDREN
: 0 ) );
236 SetCaretPos( caretrc
.left
+ dx
, caretrc
.top
+ dy
);
240 if( bOwnRgn
&& hrgnUpdate
) DeleteObject( hrgnUpdate
);
241 DeleteObject( hrgnClip
);