wine/windows/scroll.c
Ulrich Weigand d4663668b8 Changed DC members w.hVisRgn, w.hClipRgn, amd w.hGCClipRgn to
coordinates relative to the device, not the DC origin. This is
necessary to correctly implement GetClipRgn16 and InquireVisRgn.
SelectVisRgn also expects region in device-relative coordinates.
Adapted the rest of Wine to this coordinate change.
Implemented ExtSelectClipRgn.
1998-10-11 18:47:02 +00:00

429 lines
13 KiB
C

/*
* Scroll windows and DCs
*
* Copyright David W. Metcalfe, 1993
* Alex Korobka 1995,1996
*
*
*/
#include <stdlib.h>
#include "windows.h"
#include "class.h"
#include "dc.h"
#include "win.h"
#include "gdi.h"
#include "dce.h"
#include "region.h"
#include "graphics.h"
#include "sysmetrics.h"
#include "debug.h"
/*************************************************************************
* ScrollWindow16 (USER.61)
*/
void WINAPI ScrollWindow16(HWND16 hwnd, INT16 dx, INT16 dy, const RECT16 *rect,
const RECT16 *clipRect )
{
RECT32 rect32, clipRect32;
if (rect) CONV_RECT16TO32( rect, &rect32 );
if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
ScrollWindow32( hwnd, dx, dy, rect ? &rect32 : NULL,
clipRect ? &clipRect32 : NULL );
}
/*************************************************************************
* ScrollWindow32 (USER32.450)
*
* FIXME: verify clipping region calculations
*/
BOOL32 WINAPI ScrollWindow32( HWND32 hwnd, INT32 dx, INT32 dy,
const RECT32 *rect, const RECT32 *clipRect )
{
HDC32 hdc;
HRGN32 hrgnUpdate,hrgnClip;
RECT32 rc, cliprc;
HWND32 hCaretWnd = CARET_GetHwnd();
WND* wndScroll = WIN_FindWndPtr( hwnd );
TRACE(scroll,"hwnd=%04x, dx=%d, dy=%d, lpRect =%p clipRect=%i,%i,%i,%i\n",
hwnd, dx, dy, rect,
clipRect ? clipRect->left : 0,
clipRect ? clipRect->top : 0,
clipRect ? clipRect->right : 0,
clipRect ? clipRect->bottom : 0 );
if ( !wndScroll || !WIN_IsWindowDrawable( wndScroll, TRUE ) ) return TRUE;
if ( !rect ) /* do not clip children */
{
GetClientRect32(hwnd, &rc);
hrgnClip = CreateRectRgnIndirect32( &rc );
if ((hCaretWnd == hwnd) || IsChild32(hwnd,hCaretWnd))
HideCaret32(hCaretWnd);
else hCaretWnd = 0;
hdc = GetDCEx32(hwnd, hrgnClip, DCX_CACHE | DCX_CLIPSIBLINGS);
DeleteObject32( hrgnClip );
}
else /* clip children */
{
CopyRect32(&rc, rect);
if (hCaretWnd == hwnd) HideCaret32(hCaretWnd);
else hCaretWnd = 0;
hdc = GetDCEx32( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
}
if (clipRect == NULL)
GetClientRect32(hwnd, &cliprc);
else
CopyRect32(&cliprc, clipRect);
hrgnUpdate = CreateRectRgn32( 0, 0, 0, 0 );
ScrollDC32( hdc, dx, dy, &rc, &cliprc, hrgnUpdate, NULL );
ReleaseDC32(hwnd, hdc);
if( !rect ) /* move child windows and update region */
{
WND* wndPtr;
if( wndScroll->hrgnUpdate > 1 )
OffsetRgn32( wndScroll->hrgnUpdate, dx, dy );
for (wndPtr = wndScroll->child; wndPtr; wndPtr = wndPtr->next)
SetWindowPos32(wndPtr->hwndSelf, 0, wndPtr->rectWindow.left + dx,
wndPtr->rectWindow.top + dy, 0,0, SWP_NOZORDER |
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
SWP_DEFERERASE );
}
PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_ALLCHILDREN |
RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW, RDW_C_USEHRGN );
DeleteObject32( hrgnUpdate );
if( hCaretWnd )
{
POINT32 pt;
GetCaretPos32(&pt);
pt.x += dx; pt.y += dy;
SetCaretPos32(pt.x, pt.y);
ShowCaret32(hCaretWnd);
}
return TRUE;
}
/*************************************************************************
* ScrollDC16 (USER.221)
*/
BOOL16 WINAPI ScrollDC16( HDC16 hdc, INT16 dx, INT16 dy, const RECT16 *rect,
const RECT16 *cliprc, HRGN16 hrgnUpdate,
LPRECT16 rcUpdate )
{
RECT32 rect32, clipRect32, rcUpdate32;
BOOL16 ret;
if (rect) CONV_RECT16TO32( rect, &rect32 );
if (cliprc) CONV_RECT16TO32( cliprc, &clipRect32 );
ret = ScrollDC32( hdc, dx, dy, rect ? &rect32 : NULL,
cliprc ? &clipRect32 : NULL, hrgnUpdate, &rcUpdate32 );
if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
return ret;
}
/*************************************************************************
* ScrollDC32 (USER32.449)
*
* Both 'rc' and 'prLClip' are in logical units but update info is
* returned in device coordinates.
*/
BOOL32 WINAPI ScrollDC32( HDC32 hdc, INT32 dx, INT32 dy, const RECT32 *rc,
const RECT32 *prLClip, HRGN32 hrgnUpdate,
LPRECT32 rcUpdate )
{
RECT32 rClip;
POINT32 src, dest;
INT32 ldx, ldy;
DC *dc = (DC *)GDI_GetObjPtr(hdc, DC_MAGIC);
TRACE(scroll,"%04x %d,%d hrgnUpdate=%04x rcUpdate = %p cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d)\n",
(HDC16)hdc, dx, dy, hrgnUpdate, rcUpdate,
prLClip ? prLClip->left : 0, prLClip ? prLClip->top : 0, prLClip ? prLClip->right : 0, prLClip ? prLClip->bottom : 0,
rc ? rc->left : 0, rc ? rc->top : 0, rc ? rc->right : 0, rc ? rc->bottom : 0 );
if ( !dc || !hdc ) return FALSE;
/*
TRACE(scroll,"\t[wndOrgX=%i, wndExtX=%i, vportOrgX=%i, vportExtX=%i]\n",
dc->wndOrgX, dc->wndExtX, dc->vportOrgX, dc->vportExtX );
TRACE(scroll,"\t[wndOrgY=%i, wndExtY=%i, vportOrgY=%i, vportExtY=%i]\n",
dc->wndOrgY, dc->wndExtY, dc->vportOrgY, dc->vportExtY );
*/
/* compute device clipping region */
if ( rc )
rClip = *rc;
else /* maybe we should just return FALSE? */
GetClipBox32( hdc, &rClip );
if (prLClip)
IntersectRect32(&rClip,&rClip,prLClip);
if( rClip.left >= rClip.right || rClip.top >= rClip.bottom )
{
GDI_HEAP_UNLOCK( hdc );
return FALSE;
}
SaveVisRgn( hdc );
IntersectVisRect( hdc, rClip.left, rClip.top,
rClip.right, rClip.bottom );
/* translate coordinates */
ldx = dx * dc->wndExtX / dc->vportExtX;
ldy = dy * dc->wndExtY / dc->vportExtY;
if (dx > 0)
dest.x = (src.x = rClip.left) + ldx;
else
src.x = (dest.x = rClip.left) - ldx;
if (dy > 0)
dest.y = (src.y = rClip.top) + ldy;
else
src.y = (dest.y = rClip.top) - ldy;
/* copy bits */
if( rClip.right - rClip.left > ldx &&
rClip.bottom - rClip.top > ldy )
{
ldx = rClip.right - rClip.left - ldx;
ldy = rClip.bottom - rClip.top - ldy;
if (!BitBlt32( hdc, dest.x, dest.y, ldx, ldy,
hdc, src.x, src.y, SRCCOPY))
{
GDI_HEAP_UNLOCK( hdc );
return FALSE;
}
}
/* restore clipping region */
RestoreVisRgn( hdc );
/* compute update areas */
if ( (hrgnUpdate || rcUpdate) && dc->w.hVisRgn )
{
HRGN32 hrgn = (hrgnUpdate) ? hrgnUpdate : CreateRectRgn32( 0,0,0,0 );
HRGN32 hrgnClip;
LPtoDP32( hdc, (LPPOINT32)&rClip, 2 );
OffsetRect32( &rClip, dc->w.DCOrgX, dc->w.DCOrgY );
hrgnClip = CreateRectRgnIndirect32( &rClip );
CombineRgn32( hrgn, dc->w.hVisRgn, hrgnClip, RGN_AND );
OffsetRgn32( hrgn, dx, dy );
CombineRgn32( hrgn, dc->w.hVisRgn, hrgn, RGN_DIFF );
CombineRgn32( hrgn, hrgn, hrgnClip, RGN_AND );
OffsetRgn32( hrgn, -dc->w.DCOrgX, -dc->w.DCOrgY );
if( rcUpdate ) GetRgnBox32( hrgnUpdate, rcUpdate );
if (!hrgnUpdate) DeleteObject32( hrgn );
DeleteObject32( hrgnClip );
}
GDI_HEAP_UNLOCK( hdc );
return TRUE;
}
/*************************************************************************
* ScrollWindowEx16 (USER.319)
*/
INT16 WINAPI ScrollWindowEx16( HWND16 hwnd, INT16 dx, INT16 dy,
const RECT16 *rect, const RECT16 *clipRect,
HRGN16 hrgnUpdate, LPRECT16 rcUpdate,
UINT16 flags )
{
RECT32 rect32, clipRect32, rcUpdate32;
BOOL16 ret;
if (rect) CONV_RECT16TO32( rect, &rect32 );
if (clipRect) CONV_RECT16TO32( clipRect, &clipRect32 );
ret = ScrollWindowEx32( hwnd, dx, dy, rect ? &rect32 : NULL,
clipRect ? &clipRect32 : NULL, hrgnUpdate,
(rcUpdate) ? &rcUpdate32 : NULL, flags );
if (rcUpdate) CONV_RECT32TO16( &rcUpdate32, rcUpdate );
return ret;
}
/*************************************************************************
* SCROLL_FixCaret
*/
static BOOL32 SCROLL_FixCaret(HWND32 hWnd, LPRECT32 lprc, UINT32 flags)
{
HWND32 hCaret = CARET_GetHwnd();
if( hCaret )
{
RECT32 rc;
CARET_GetRect( &rc );
if( hCaret == hWnd ||
(flags & SW_SCROLLCHILDREN && IsChild32(hWnd, hCaret)) )
{
POINT32 pt;
pt.x = rc.left; pt.y = rc.top;
MapWindowPoints32( hCaret, hWnd, (LPPOINT32)&rc, 2 );
if( IntersectRect32(lprc, lprc, &rc) )
{
HideCaret32(0);
lprc->left = pt.x; lprc->top = pt.y;
return TRUE;
}
}
}
return FALSE;
}
/*************************************************************************
* ScrollWindowEx32 (USER32.451)
*
* NOTE: Use this function instead of ScrollWindow32
*/
INT32 WINAPI ScrollWindowEx32( HWND32 hwnd, INT32 dx, INT32 dy,
const RECT32 *rect, const RECT32 *clipRect,
HRGN32 hrgnUpdate, LPRECT32 rcUpdate,
UINT32 flags )
{
INT32 retVal = NULLREGION;
BOOL32 bCaret = FALSE, bOwnRgn = TRUE;
RECT32 rc, cliprc;
WND* wnd = WIN_FindWndPtr( hwnd );
if( !wnd || !WIN_IsWindowDrawable( wnd, TRUE )) return ERROR;
if (rect == NULL) GetClientRect32(hwnd, &rc);
else rc = *rect;
if (clipRect) IntersectRect32(&cliprc,&rc,clipRect);
else cliprc = rc;
if (!IsRectEmpty32(&cliprc) && (dx || dy))
{
DC* dc;
HDC32 hDC;
BOOL32 bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
HRGN32 hrgnClip = CreateRectRgnIndirect32(&cliprc);
TRACE(scroll,"%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p \
cliprc = (%d,%d-%d,%d), rc=(%d,%d-%d,%d) %04x\n",
(HWND16)hwnd, dx, dy, hrgnUpdate, rcUpdate,
clipRect?clipRect->left:0, clipRect?clipRect->top:0, clipRect?clipRect->right:0, clipRect?clipRect->bottom:0,
rect?rect->left:0, rect?rect->top:0, rect ?rect->right:0, rect ?rect->bottom:0, (UINT16)flags );
rc = cliprc;
bCaret = SCROLL_FixCaret(hwnd, &rc, flags);
if( hrgnUpdate ) bOwnRgn = FALSE;
else if( bUpdate ) hrgnUpdate = CreateRectRgn32( 0, 0, 0, 0 );
hDC = GetDCEx32( hwnd, hrgnClip, DCX_CACHE | DCX_USESTYLE |
((flags & SW_SCROLLCHILDREN) ? DCX_NOCLIPCHILDREN : 0) );
if( (dc = (DC *)GDI_GetObjPtr(hDC, DC_MAGIC)) )
{
POINT32 dst, src;
if( dx > 0 ) dst.x = (src.x = dc->w.DCOrgX + cliprc.left) + dx;
else src.x = (dst.x = dc->w.DCOrgX + cliprc.left) - dx;
if( dy > 0 ) dst.y = (src.y = dc->w.DCOrgY + cliprc.top) + dy;
else src.y = (dst.y = dc->w.DCOrgY + cliprc.top) - dy;
if( bUpdate ) /* handles non-Wine windows hanging over the scrolled area */
TSXSetGraphicsExposures( display, dc->u.x.gc, True );
TSXSetFunction( display, dc->u.x.gc, GXcopy );
TSXCopyArea( display, dc->u.x.drawable, dc->u.x.drawable, dc->u.x.gc,
src.x, src.y, cliprc.right - cliprc.left - abs(dx),
cliprc.bottom - cliprc.top - abs(dy), dst.x, dst.y );
if( bUpdate )
TSXSetGraphicsExposures( display, dc->u.x.gc, False );
if( dc->w.hVisRgn && bUpdate )
{
OffsetRgn32( hrgnClip, dc->w.DCOrgX, dc->w.DCOrgY );
CombineRgn32( hrgnUpdate, dc->w.hVisRgn, hrgnClip, RGN_AND );
OffsetRgn32( hrgnUpdate, dx, dy );
CombineRgn32( hrgnUpdate, dc->w.hVisRgn, hrgnUpdate, RGN_DIFF );
CombineRgn32( hrgnUpdate, hrgnUpdate, hrgnClip, RGN_AND );
OffsetRgn32( hrgnUpdate, -dc->w.DCOrgX, -dc->w.DCOrgY );
if( rcUpdate ) GetRgnBox32( hrgnUpdate, rcUpdate );
}
ReleaseDC32(hwnd, hDC);
GDI_HEAP_UNLOCK( hDC );
}
if( wnd->hrgnUpdate > 1 )
{
if( rect || clipRect )
{
if( (CombineRgn32( hrgnClip, hrgnClip,
wnd->hrgnUpdate, RGN_AND ) != NULLREGION) )
{
CombineRgn32( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_DIFF );
OffsetRgn32( hrgnClip, dx, dy );
CombineRgn32( wnd->hrgnUpdate, wnd->hrgnUpdate, hrgnClip, RGN_OR );
}
}
else
OffsetRgn32( wnd->hrgnUpdate, dx, dy );
}
if( flags & SW_SCROLLCHILDREN )
{
RECT32 r;
WND* w;
for( w = wnd->child; w; w = w->next )
{
CONV_RECT16TO32( &w->rectWindow, &r );
if( !clipRect || IntersectRect32(&r, &r, &cliprc) )
SetWindowPos32(w->hwndSelf, 0, w->rectWindow.left + dx,
w->rectWindow.top + dy, 0,0, SWP_NOZORDER |
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW |
SWP_DEFERERASE );
}
}
if( flags & (SW_INVALIDATE | SW_ERASE) )
PAINT_RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
((flags & SW_ERASE) ? RDW_ERASENOW : 0) | ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ), 0 );
if( bCaret )
{
SetCaretPos32( rc.left + dx, rc.top + dy );
ShowCaret32(0);
}
if( bOwnRgn && hrgnUpdate ) DeleteObject32( hrgnUpdate );
DeleteObject32( hrgnClip );
}
return retVal;
}