Fixes crash when running without external shell32.dll.
[wine/multimedia.git] / windows / scroll.c
blob2db40ff23a7784a32e46f1ae9d2cd5448e9b68cf
1 /*
2 * Scroll windows and DCs
4 * Copyright David W. Metcalfe, 1993
5 * Alex Korobka 1995,1996
8 */
10 #include <stdlib.h>
11 #include "windows.h"
12 #include "class.h"
13 #include "dc.h"
14 #include "win.h"
15 #include "gdi.h"
16 #include "dce.h"
17 #include "region.h"
18 #include "sysmetrics.h"
19 #include "debug.h"
20 #include "x11drv.h"
22 /*************************************************************************
23 * ScrollWindow16 (USER.61)
25 void WINAPI ScrollWindow16(HWND16 hwnd, INT16 dx, INT16 dy, const RECT16 *rect,
26 const RECT16 *clipRect )
28 RECT32 rect32, clipRect32;
30 if (rect) CONV_RECT16TO32( rect, &rect32 );
31 if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
32 ScrollWindow32( hwnd, dx, dy, rect ? &rect32 : NULL,
33 clipRect ? &clipRect32 : NULL );
36 /*************************************************************************
37 * ScrollWindow32 (USER32.450)
39 * FIXME: verify clipping region calculations
41 BOOL32 WINAPI ScrollWindow32( HWND32 hwnd, INT32 dx, INT32 dy,
42 const RECT32 *rect, const RECT32 *clipRect )
44 HDC32 hdc;
45 HRGN32 hrgnUpdate,hrgnClip;
46 RECT32 rc, cliprc;
47 HWND32 hCaretWnd = CARET_GetHwnd();
48 WND* wndScroll = WIN_FindWndPtr( hwnd );
50 TRACE(scroll,"hwnd=%04x, dx=%d, dy=%d, lpRect =%p clipRect=%i,%i,%i,%i\n",
51 hwnd, dx, dy, rect,
52 clipRect ? clipRect->left : 0,
53 clipRect ? clipRect->top : 0,
54 clipRect ? clipRect->right : 0,
55 clipRect ? clipRect->bottom : 0 );
57 if ( !wndScroll || !WIN_IsWindowDrawable( wndScroll, TRUE ) ) return TRUE;
59 if ( !rect ) /* do not clip children */
61 GetClientRect32(hwnd, &rc);
62 hrgnClip = CreateRectRgnIndirect32( &rc );
64 if ((hCaretWnd == hwnd) || IsChild32(hwnd,hCaretWnd))
65 HideCaret32(hCaretWnd);
66 else hCaretWnd = 0;
68 hdc = GetDCEx32(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS);
69 DeleteObject32( hrgnClip );
71 else /* clip children */
73 CopyRect32(&rc, rect);
75 if (hCaretWnd == hwnd) HideCaret32(hCaretWnd);
76 else hCaretWnd = 0;
78 hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
81 if (clipRect == NULL)
82 GetClientRect32(hwnd, &cliprc);
83 else
84 CopyRect32(&cliprc, clipRect);
86 hrgnUpdate = CreateRectRgn32( 0, 0, 0, 0 );
87 ScrollDC32( hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL );
88 ReleaseDC32(hwnd, hdc);
90 if( !rect ) /* move child windows and update region */
92 WND* wndPtr;
94 if( wndScroll->hrgnUpdate > 1 )
95 OffsetRgn32( wndScroll->hrgnUpdate, dx, dy );
97 for (wndPtr = wndScroll->child; wndPtr; wndPtr = wndPtr->next)
98 SetWindowPos32(wndPtr->hwndSelf, 0, wndPtr->rectWindow.left + dx,
99 wndPtr->rectWindow.top + dy, 0,0, SWP_NOZORDER |
100 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
101 SWP_DEFERERASE );
104 PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_ALLCHILDREN |
105 RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW, RDW_C_USEHRGN );
107 DeleteObject32( hrgnUpdate );
108 if( hCaretWnd )
110 POINT32 pt;
111 GetCaretPos32(&pt);
112 pt.x += dx; pt.y += dy;
113 SetCaretPos32(pt.x, pt.y);
114 ShowCaret32(hCaretWnd);
116 return TRUE;
120 /*************************************************************************
121 * ScrollDC16 (USER.221)
123 BOOL16 WINAPI ScrollDC16( HDC16 hdc, INT16 dx, INT16 dy, const RECT16 *rect,
124 const RECT16 *cliprc, HRGN16 hrgnUpdate,
125 LPRECT16 rcUpdate )
127 RECT32 rect32, clipRect32, rcUpdate32;
128 BOOL16 ret;
130 if (rect) CONV_RECT16TO32( rect, &rect32 );
131 if (cliprc) CONV_RECT16TO32( cliprc, &clipRect32 );
132 ret = ScrollDC32( hdc, dx, dy, rect ? &rect32 : NULL,
133 cliprc ? &clipRect32 : NULL, hrgnUpdate, &rcUpdate32 );
134 if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
135 return ret;
139 /*************************************************************************
140 * ScrollDC32 (USER32.449)
142 * Both 'rc' and 'prLClip' are in logical units but update info is
143 * returned in device coordinates.
145 BOOL32 WINAPI ScrollDC32( HDC32 hdc, INT32 dx, INT32 dy, const RECT32 *rc,
146 const RECT32 *prLClip, HRGN32 hrgnUpdate,
147 LPRECT32 rcUpdate )
149 RECT32 rClip;
150 POINT32 src, dest;
151 INT32 ldx, ldy;
152 DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
154 TRACE(scroll,"%04x %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d)\n",
155 (HDC16)hdc, dx, dy, hrgnUpdate, rcUpdate,
156 prLClip ? prLClip->left : 0, prLClip ? prLClip->top : 0, prLClip ? prLClip->right : 0, prLClip ? prLClip->bottom : 0,
157 rc ? rc->left : 0, rc ? rc->top : 0, rc ? rc->right : 0, rc ? rc->bottom : 0 );
159 if ( !dc || !hdc ) return FALSE;
162 TRACE(scroll,"\t[wndOrgX=%i, wndExtX=%i, vportOrgX=%i, vportExtX=%i]\n",
163 dc->wndOrgX, dc->wndExtX, dc->vportOrgX, dc->vportExtX );
164 TRACE(scroll,"\t[wndOrgY=%i, wndExtY=%i, vportOrgY=%i, vportExtY=%i]\n",
165 dc->wndOrgY, dc->wndExtY, dc->vportOrgY, dc->vportExtY );
168 /* compute device clipping region */
170 if ( rc )
171 rClip = *rc;
172 else /* maybe we should just return FALSE? */
173 GetClipBox32( hdc, &rClip );
175 if (prLClip)
176 IntersectRect32(&rClip,&rClip,prLClip);
178 if( rClip.left >= rClip.right || rClip.top >= rClip.bottom )
180 GDI_HEAP_UNLOCK( hdc );
181 return FALSE;
184 SaveVisRgn( hdc );
185 IntersectVisRect( hdc, rClip.left, rClip.top,
186 rClip.right, rClip.bottom );
189 /* translate coordinates */
191 ldx = dx * dc->wndExtX / dc->vportExtX;
192 ldy = dy * dc->wndExtY / dc->vportExtY;
194 if (dx > 0)
195 dest.x = (src.x = rClip.left) + ldx;
196 else
197 src.x = (dest.x = rClip.left) - ldx;
199 if (dy > 0)
200 dest.y = (src.y = rClip.top) + ldy;
201 else
202 src.y = (dest.y = rClip.top) - ldy;
204 /* copy bits */
206 if( rClip.right - rClip.left > ldx &&
207 rClip.bottom - rClip.top > ldy )
209 ldx = rClip.right - rClip.left - ldx;
210 ldy = rClip.bottom - rClip.top - ldy;
212 if (!BitBlt32( hdc, dest.x, dest.y, ldx, ldy,
213 hdc, src.x, src.y, SRCCOPY))
215 GDI_HEAP_UNLOCK( hdc );
216 return FALSE;
220 /* restore clipping region */
222 RestoreVisRgn( hdc );
225 /* compute update areas */
227 if ( (hrgnUpdate || rcUpdate) && dc->w.hVisRgn )
229 HRGN32 hrgn = (hrgnUpdate) ? hrgnUpdate : CreateRectRgn32( 0,0,0,0 );
230 HRGN32 hrgnClip;
232 LPtoDP32( hdc, (LPPOINT32)&rClip, 2 );
233 OffsetRect32( &rClip, dc->w.DCOrgX, dc->w.DCOrgY );
234 hrgnClip = CreateRectRgnIndirect32( &rClip );
236 CombineRgn32( hrgn, dc->w.hVisRgn, hrgnClip, RGN_AND );
237 OffsetRgn32( hrgn, dx, dy );
238 CombineRgn32( hrgn, dc->w.hVisRgn, hrgn, RGN_DIFF );
239 CombineRgn32( hrgn, hrgn, hrgnClip, RGN_AND );
240 OffsetRgn32( hrgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
242 if( rcUpdate ) GetRgnBox32( hrgnUpdate, rcUpdate );
244 if (!hrgnUpdate) DeleteObject32( hrgn );
245 DeleteObject32( hrgnClip );
248 GDI_HEAP_UNLOCK( hdc );
249 return TRUE;
253 /*************************************************************************
254 * ScrollWindowEx16 (USER.319)
256 INT16 WINAPI ScrollWindowEx16( HWND16 hwnd, INT16 dx, INT16 dy,
257 const RECT16 *rect, const RECT16 *clipRect,
258 HRGN16 hrgnUpdate, LPRECT16 rcUpdate,
259 UINT16 flags )
261 RECT32 rect32, clipRect32, rcUpdate32;
262 BOOL16 ret;
264 if (rect) CONV_RECT16TO32( rect, &rect32 );
265 if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
266 ret = ScrollWindowEx32( hwnd, dx, dy, rect ? &rect32 : NULL,
267 clipRect ? &clipRect32 : NULL, hrgnUpdate,
268 (rcUpdate) ? &rcUpdate32 : NULL, flags );
269 if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
270 return ret;
273 /*************************************************************************
274 * SCROLL_FixCaret
276 static BOOL32 SCROLL_FixCaret(HWND32 hWnd, LPRECT32 lprc, UINT32 flags)
278 HWND32 hCaret = CARET_GetHwnd();
280 if( hCaret )
282 RECT32 rc;
283 CARET_GetRect( &rc );
284 if( hCaret == hWnd ||
285 (flags & SW_SCROLLCHILDREN && IsChild32(hWnd, hCaret)) )
287 POINT32 pt;
289 pt.x = rc.left; pt.y = rc.top;
290 MapWindowPoints32( hCaret, hWnd, (LPPOINT32)&rc, 2 );
291 if( IntersectRect32(lprc, lprc, &rc) )
293 HideCaret32(0);
294 lprc->left = pt.x; lprc->top = pt.y;
295 return TRUE;
299 return FALSE;
302 /*************************************************************************
303 * ScrollWindowEx32 (USER32.451)
305 * NOTE: Use this function instead of ScrollWindow32
307 INT32 WINAPI ScrollWindowEx32( HWND32 hwnd, INT32 dx, INT32 dy,
308 const RECT32 *rect, const RECT32 *clipRect,
309 HRGN32 hrgnUpdate, LPRECT32 rcUpdate,
310 UINT32 flags )
312 INT32 retVal = NULLREGION;
313 BOOL32 bCaret = FALSE, bOwnRgn = TRUE;
314 RECT32 rc, cliprc;
315 WND* wnd = WIN_FindWndPtr( hwnd );
317 if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) return ERROR;
319 if (rect == NULL) GetClientRect32(hwnd, &rc);
320 else rc = *rect;
322 if (clipRect) IntersectRect32(&cliprc,&rc,clipRect);
323 else cliprc = rc;
325 if (!IsRectEmpty32(&cliprc) && (dx || dy))
327 DC* dc;
328 HDC32 hDC;
329 BOOL32 bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
330 HRGN32 hrgnClip = CreateRectRgnIndirect32(&cliprc);
332 TRACE(scroll,"%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p \
333 cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
334 (HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
335 clipRect?clipRect->left:0, clipRect?clipRect->top:0, clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
336 rect?rect->left:0, rect?rect->top:0, rect ?rect->right:0, rect ?rect->bottom:0, (UINT16)flags );
338 rc = cliprc;
339 bCaret = SCROLL_FixCaret(hwnd, &rc, flags);
341 if( hrgnUpdate ) bOwnRgn = FALSE;
342 else if( bUpdate ) hrgnUpdate = CreateRectRgn32( 0, 0, 0, 0 );
344 hDC = GetDCEx32( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
345 ((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
346 if( (dc = (DC *)GDI_GetObjPtr(hDC, DC_MAGIC)) )
348 X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
349 POINT32 dst, src;
351 if( dx > 0 ) dst.x = (src.x = dc->w.DCOrgX + cliprc.left) + dx;
352 else src.x = (dst.x = dc->w.DCOrgX + cliprc.left) - dx;
354 if( dy > 0 ) dst.y = (src.y = dc->w.DCOrgY + cliprc.top) + dy;
355 else src.y = (dst.y = dc->w.DCOrgY + cliprc.top) - dy;
357 if ((cliprc.right - cliprc.left > abs(dx)) &&
358 (cliprc.bottom - cliprc.top > abs(dy)))
360 if (bUpdate) /* handles non-Wine windows hanging over the scrolled area */
361 TSXSetGraphicsExposures( display, physDev->gc, True );
362 TSXSetFunction( display, physDev->gc, GXcopy );
363 TSXCopyArea( display, physDev->drawable, physDev->drawable,
364 physDev->gc, src.x, src.y,
365 cliprc.right - cliprc.left - abs(dx),
366 cliprc.bottom - cliprc.top - abs(dy),
367 dst.x, dst.y );
368 if (bUpdate)
369 TSXSetGraphicsExposures( display, physDev->gc, False );
372 if( dc->w.hVisRgn && bUpdate )
374 OffsetRgn32( hrgnClip, dc->w.DCOrgX, dc->w.DCOrgY );
375 CombineRgn32( hrgnUpdate, dc->w.hVisRgn, hrgnClip, RGN_AND );
376 OffsetRgn32( hrgnUpdate, dx, dy );
377 CombineRgn32( hrgnUpdate, dc->w.hVisRgn, hrgnUpdate, RGN_DIFF );
378 CombineRgn32( hrgnUpdate, hrgnUpdate, hrgnClip, RGN_AND );
379 OffsetRgn32( hrgnUpdate, -dc->w.DCOrgX, -dc->w.DCOrgY );
381 if( rcUpdate ) GetRgnBox32( hrgnUpdate, rcUpdate );
383 ReleaseDC32(hwnd, hDC);
384 GDI_HEAP_UNLOCK( hDC );
387 if( wnd->hrgnUpdate > 1 )
389 if( rect || clipRect )
391 if( (CombineRgn32( hrgnClip, hrgnClip,
392 wnd->hrgnUpdate, RGN_AND ) != NULLREGION) )
394 CombineRgn32( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_DIFF );
395 OffsetRgn32( hrgnClip, dx, dy );
396 CombineRgn32( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_OR );
399 else
400 OffsetRgn32( wnd->hrgnUpdate, dx, dy );
403 if( flags & SW_SCROLLCHILDREN )
405 RECT32 r;
406 WND* w;
407 for( w = wnd->child; w; w = w->next )
409 CONV_RECT16TO32( &w->rectWindow, &r );
410 if( !clipRect || IntersectRect32(&r, &r, &cliprc) )
411 SetWindowPos32(w->hwndSelf, 0, w->rectWindow.left + dx,
412 w->rectWindow.top + dy, 0,0, SWP_NOZORDER |
413 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
414 SWP_DEFERERASE );
418 if( flags & (SW_INVALIDATE | SW_ERASE) )
419 PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
420 ((flags & SW_ERASE) ? RDW_ERASENOW : 0) | ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ), 0 );
422 if( bCaret )
424 SetCaretPos32( rc.left + dx, rc.top + dy );
425 ShowCaret32(0);
428 if( bOwnRgn && hrgnUpdate ) DeleteObject32( hrgnUpdate );
429 DeleteObject32( hrgnClip );
431 return retVal;