New debug scheme with explicit debug channels declaration.
[wine.git] / windows / scroll.c
blob24183843a349098ce0df27a27f9f877c6874e4a9
1 /*
2 * Scroll windows and DCs
4 * Copyright David W. Metcalfe, 1993
5 * Alex Korobka 1995,1996
8 */
10 #include <stdlib.h>
12 #include "winuser.h"
13 #include "class.h"
14 #include "dc.h"
15 #include "win.h"
16 #include "gdi.h"
17 #include "dce.h"
18 #include "region.h"
19 #include "sysmetrics.h"
20 #include "debug.h"
22 DEFAULT_DEBUG_CHANNEL(scroll)
24 /*************************************************************************
25 * ScrollWindow16 (USER.61)
27 void WINAPI ScrollWindow16(HWND16 hwnd, INT16 dx, INT16 dy, const RECT16 *rect,
28 const RECT16 *clipRect )
30 RECT rect32, clipRect32;
32 if (rect) CONV_RECT16TO32( rect, &rect32 );
33 if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
34 ScrollWindow( hwnd, dx, dy, rect ? &rect32 : NULL,
35 clipRect ? &clipRect32 : NULL );
38 /*************************************************************************
39 * ScrollWindow32 (USER32.450)
42 BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy,
43 const RECT *rect, const RECT *clipRect )
45 return
46 (ERROR != ScrollWindowEx( hwnd, dx, dy, rect, clipRect, 0, NULL,
47 (rect ? 0 : SW_SCROLLCHILDREN) |
48 SW_INVALIDATE ));
51 /*************************************************************************
52 * ScrollDC16 (USER.221)
54 BOOL16 WINAPI ScrollDC16( HDC16 hdc, INT16 dx, INT16 dy, const RECT16 *rect,
55 const RECT16 *cliprc, HRGN16 hrgnUpdate,
56 LPRECT16 rcUpdate )
58 RECT rect32, clipRect32, rcUpdate32;
59 BOOL16 ret;
61 if (rect) CONV_RECT16TO32( rect, &rect32 );
62 if (cliprc) CONV_RECT16TO32( cliprc, &clipRect32 );
63 ret = ScrollDC( hdc, dx, dy, rect ? &rect32 : NULL,
64 cliprc ? &clipRect32 : NULL, hrgnUpdate, &rcUpdate32 );
65 if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
66 return ret;
70 /*************************************************************************
71 * ScrollDC32 (USER32.449)
73 * Only the hrgnUpdate is return in device coordinate.
74 * rcUpdate must be returned in logical coordinate to comply with win API.
77 BOOL WINAPI ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc,
78 const RECT *prLClip, HRGN hrgnUpdate,
79 LPRECT rcUpdate )
81 RECT rect, rClip, rSrc;
82 POINT src, dest;
83 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
85 TRACE(scroll,"%04x %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d)\n",
86 (HDC16)hdc, dx, dy, hrgnUpdate, rcUpdate,
87 prLClip ? prLClip->left : 0, prLClip ? prLClip->top : 0, prLClip ? prLClip->right : 0, prLClip ? prLClip->bottom : 0,
88 rc ? rc->left : 0, rc ? rc->top : 0, rc ? rc->right : 0, rc ? rc->bottom : 0 );
90 if ( !dc || !hdc ) return FALSE;
93 TRACE(scroll,"\t[wndOrgX=%i, wndExtX=%i, vportOrgX=%i, vportExtX=%i]\n",
94 dc->wndOrgX, dc->wndExtX, dc->vportOrgX, dc->vportExtX );
95 TRACE(scroll,"\t[wndOrgY=%i, wndExtY=%i, vportOrgY=%i, vportExtY=%i]\n",
96 dc->wndOrgY, dc->wndExtY, dc->vportOrgY, dc->vportExtY );
99 /* compute device clipping region */
101 if ( rc )
102 rect = *rc;
103 else /* maybe we should just return FALSE? */
104 GetClipBox( hdc, &rect );
106 if (prLClip)
107 IntersectRect( &rClip,&rect,prLClip );
108 else
109 rClip = rect;
111 rSrc = rClip;
112 OffsetRect( &rSrc, -dx, -dy );
113 IntersectRect( &rSrc, &rSrc, &rect );
115 if(dc->w.hVisRgn)
117 if (!IsRectEmpty(&rSrc))
119 dest.x = (src.x = rSrc.left) + dx;
120 dest.y = (src.y = rSrc.top) + dy;
122 /* copy bits */
124 if (!BitBlt( hdc, dest.x, dest.y,
125 rSrc.right - rSrc.left, rSrc.bottom - rSrc.top,
126 hdc, src.x, src.y, SRCCOPY))
128 GDI_HEAP_UNLOCK( hdc );
129 return FALSE;
133 /* compute update areas */
135 if (hrgnUpdate || rcUpdate)
137 HRGN hrgn =
138 (hrgnUpdate) ? hrgnUpdate : CreateRectRgn( 0,0,0,0 );
139 HRGN hrgn2;
141 dx = XLPTODP ( dc, rect.left + dx) - XLPTODP ( dc, rect.left);
142 dy = YLPTODP ( dc, rect.top + dy) - YLPTODP ( dc, rect.top);
143 LPtoDP( hdc, (LPPOINT)&rect, 2 );
144 LPtoDP( hdc, (LPPOINT)&rClip, 2 );
145 hrgn2 = CreateRectRgnIndirect( &rect );
146 OffsetRgn( hrgn2, dc->w.DCOrgX, dc->w.DCOrgY );
147 CombineRgn( hrgn2, hrgn2, dc->w.hVisRgn, RGN_AND );
148 OffsetRgn( hrgn2, -dc->w.DCOrgX, -dc->w.DCOrgY );
149 SetRectRgn( hrgn, rClip.left, rClip.top,
150 rClip.right, rClip.bottom );
151 CombineRgn( hrgn, hrgn, hrgn2, RGN_AND );
152 OffsetRgn( hrgn2, dx, dy );
153 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
155 if( rcUpdate )
157 GetRgnBox( hrgn, rcUpdate );
159 //Put the rcUpdate in logical coordinate
160 DPtoLP( hdc, (LPPOINT)rcUpdate, 2 );
162 if (!hrgnUpdate) DeleteObject( hrgn );
163 DeleteObject( hrgn2 );
167 else
169 if (hrgnUpdate) SetRectRgn(hrgnUpdate, 0, 0, 0, 0);
170 if (rcUpdate) SetRectEmpty(rcUpdate);
173 GDI_HEAP_UNLOCK( hdc );
174 return TRUE;
178 /*************************************************************************
179 * ScrollWindowEx16 (USER.319)
181 INT16 WINAPI ScrollWindowEx16( HWND16 hwnd, INT16 dx, INT16 dy,
182 const RECT16 *rect, const RECT16 *clipRect,
183 HRGN16 hrgnUpdate, LPRECT16 rcUpdate,
184 UINT16 flags )
186 RECT rect32, clipRect32, rcUpdate32;
187 BOOL16 ret;
189 if (rect) CONV_RECT16TO32( rect, &rect32 );
190 if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
191 ret = ScrollWindowEx( hwnd, dx, dy, rect ? &rect32 : NULL,
192 clipRect ? &clipRect32 : NULL, hrgnUpdate,
193 (rcUpdate) ? &rcUpdate32 : NULL, flags );
194 if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
195 return ret;
198 /*************************************************************************
199 * SCROLL_FixCaret
201 static BOOL SCROLL_FixCaret(HWND hWnd, LPRECT lprc, UINT flags)
203 HWND hCaret = CARET_GetHwnd();
205 if( hCaret )
207 RECT rc;
208 CARET_GetRect( &rc );
209 if( hCaret == hWnd ||
210 (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
212 POINT pt;
214 pt.x = rc.left; pt.y = rc.top;
215 MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
216 if( IntersectRect(lprc, lprc, &rc) )
218 HideCaret(0);
219 lprc->left = pt.x; lprc->top = pt.y;
220 return TRUE;
224 return FALSE;
227 /*************************************************************************
228 * ScrollWindowEx32 (USER32.451)
230 * NOTE: Use this function instead of ScrollWindow32
232 INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy,
233 const RECT *rect, const RECT *clipRect,
234 HRGN hrgnUpdate, LPRECT rcUpdate,
235 UINT flags )
237 INT retVal = NULLREGION;
238 BOOL bCaret = FALSE, bOwnRgn = TRUE;
239 RECT rc, cliprc;
240 WND* wnd = WIN_FindWndPtr( hwnd );
242 if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE ))
244 retVal = ERROR;
245 goto END;
248 GetClientRect(hwnd, &rc);
249 if (rect) IntersectRect(&rc, &rc, rect);
251 if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
252 else cliprc = rc;
254 if (!IsRectEmpty(&cliprc) && (dx || dy))
256 DC* dc;
257 HDC hDC;
258 BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
259 HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
260 HRGN hrgnTemp = CreateRectRgnIndirect(&rc);
261 RECT caretrc;
263 TRACE(scroll,"%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p \
264 cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
265 (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
266 clipRect?clipRect->left:0, clipRect?clipRect->top:0, clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
267 rc.left, rc.top, rc.right, rc.bottom, (UINT16)flags );
269 caretrc = rc;
270 bCaret = SCROLL_FixCaret(hwnd, &caretrc, flags);
272 if( hrgnUpdate ) bOwnRgn = FALSE;
273 else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
275 hDC = GetDCEx( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
276 DCX_KEEPCLIPRGN | DCX_INTERSECTRGN |
277 ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
278 if( (dc = (DC *)GDI_GetObjPtr(hDC, DC_MAGIC)) )
280 if (dc->w.hVisRgn) {
281 wnd->pDriver->pSurfaceCopy(wnd,dc,dx,dy,&rc,bUpdate);
283 if( bUpdate )
285 OffsetRgn( hrgnTemp, dc->w.DCOrgX, dc->w.DCOrgY );
286 CombineRgn( hrgnTemp, hrgnTemp, dc->w.hVisRgn,
287 RGN_AND );
288 OffsetRgn( hrgnTemp, -dc->w.DCOrgX, -dc->w.DCOrgY );
289 CombineRgn( hrgnUpdate, hrgnTemp, hrgnClip,
290 RGN_AND );
291 OffsetRgn( hrgnTemp, dx, dy );
292 retVal =
293 CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp,
294 RGN_DIFF );
296 if( rcUpdate ) GetRgnBox( hrgnUpdate, rcUpdate );
299 ReleaseDC(hwnd, hDC);
300 GDI_HEAP_UNLOCK( hDC );
303 if( wnd->hrgnUpdate > 1 )
305 /* Takes into account the fact that some damages may have
306 occured during the scroll. */
307 CombineRgn( hrgnTemp, wnd->hrgnUpdate, 0, RGN_COPY );
308 OffsetRgn( hrgnTemp, dx, dy );
309 CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
310 CombineRgn( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnTemp, RGN_OR );
313 if( flags & SW_SCROLLCHILDREN )
315 RECT r;
316 WND* w;
317 for( w =WIN_LockWndPtr(wnd->child); w; WIN_UpdateWndPtr(&w, w->next))
319 CONV_RECT16TO32( &w->rectWindow, &r );
320 if( IntersectRect(&r, &r, &rc) )
321 SetWindowPos(w->hwndSelf, 0, w->rectWindow.left + dx,
322 w->rectWindow.top + dy, 0,0, SWP_NOZORDER |
323 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
324 SWP_DEFERERASE );
328 if( flags & (SW_INVALIDATE | SW_ERASE) )
329 PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
330 ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ), 0 );
332 if( bCaret )
334 SetCaretPos( caretrc.left + dx, caretrc.top + dy );
335 ShowCaret(0);
338 if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
339 DeleteObject( hrgnClip );
340 DeleteObject( hrgnTemp );
342 END:
343 WIN_ReleaseWndPtr(wnd);
344 return retVal;