When including 'wine/port.h', include it first.
[wine] / dlls / x11drv / scroll.c
1 /*
2  * Scroll windows and DCs
3  *
4  * Copyright 1993  David W. Metcalfe
5  * Copyright 1995, 1996 Alex Korobka
6  * Copyright 2001 Alexandre Julliard
7  */
8
9 #include "config.h"
10
11 #include "ts_xlib.h"
12 #include "ts_xutil.h"
13
14 #include "winbase.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17
18 #include "x11drv.h"
19 #include "win.h"
20 #include "debugtools.h"
21
22 DEFAULT_DEBUG_CHANNEL(x11drv);
23
24
25 /*************************************************************************
26  *             fix_caret
27  */
28 static BOOL fix_caret(HWND hWnd, LPRECT lprc, UINT flags)
29 {
30    HWND hCaret = CARET_GetHwnd();
31
32    if( hCaret )
33    {
34        RECT rc;
35        CARET_GetRect( &rc );
36        if( hCaret == hWnd ||
37           (flags & SW_SCROLLCHILDREN && IsChild(hWnd, hCaret)) )
38        {
39            POINT pt;
40            pt.x = rc.left;
41            pt.y = rc.top;
42            MapWindowPoints( hCaret, hWnd, (LPPOINT)&rc, 2 );
43            if( IntersectRect(lprc, lprc, &rc) )
44            {
45                HideCaret(0);
46                lprc->left = pt.x;
47                lprc->top = pt.y;
48                return TRUE;
49            }
50        }
51    }
52    return FALSE;
53 }
54
55
56 /*************************************************************************
57  *              ScrollDC   (X11DRV.@)
58  * 
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
62  */
63 BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc,
64                       const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate )
65 {
66     RECT rect, rClip, rSrc;
67
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 );
72
73     /* compute device clipping region (in device coordinates) */
74
75     if (rc) rect = *rc;
76     else GetClipBox( hdc, &rect );
77
78     if (clipRect)
79     {
80         rClip = *clipRect;
81         IntersectRect( &rClip, &rect, &rClip );
82     }
83     else rClip = rect;
84
85     rSrc = rClip;
86     OffsetRect( &rSrc, -dx, -dy );
87     IntersectRect( &rSrc, &rSrc, &rect );
88
89     if (!IsRectEmpty(&rSrc))
90     {
91         /* copy bits */
92         if (!BitBlt( hdc, rSrc.left + dx, rSrc.top + dy,
93                      rSrc.right - rSrc.left, rSrc.bottom - rSrc.top,
94                      hdc, rSrc.left, rSrc.top, SRCCOPY))
95             return FALSE;
96     }
97
98     /* compute update areas */
99
100     if (hrgnUpdate || rcUpdate)
101     {
102         HRGN hrgn = hrgnUpdate, hrgn2;
103         POINT pt;
104
105         /* map everything to device coordinates */
106         pt.x = rect.left + dx;
107         pt.y = rect.top + dy;
108         LPtoDP( hdc, &pt, 1 );
109         LPtoDP( hdc, (LPPOINT)&rect, 2 );
110         LPtoDP( hdc, (LPPOINT)&rClip, 2 );
111         dx = pt.x - rect.left;
112         dy = pt.y - rect.top;
113
114         hrgn2 = CreateRectRgnIndirect( &rect );
115         if (hrgn) SetRectRgn( hrgn, rClip.left, rClip.top, rClip.right, rClip.bottom );
116         else hrgn = CreateRectRgn( rClip.left, rClip.top, rClip.right, rClip.bottom );
117         CombineRgn( hrgn, hrgn, hrgn2, RGN_AND );
118         OffsetRgn( hrgn2, dx, dy );
119         CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
120
121         if( rcUpdate )
122         {
123             GetRgnBox( hrgn, rcUpdate );
124
125             /* Put the rcUpdate in logical coordinate */
126             DPtoLP( hdc, (LPPOINT)rcUpdate, 2 );
127         }
128         if (!hrgnUpdate) DeleteObject( hrgn );
129         DeleteObject( hrgn2 );
130     }
131     return TRUE;
132 }
133
134
135 /*************************************************************************
136  *              ScrollWindowEx   (X11DRV.@)
137  */
138 INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
139                            const RECT *rect, const RECT *clipRect,
140                            HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
141 {
142     INT  retVal = NULLREGION;
143     BOOL bCaret = FALSE, bOwnRgn = TRUE;
144     RECT rc, cliprc;
145     WND*   wnd = WIN_FindWndPtr( hwnd );
146
147     if (!wnd) return ERROR;
148     if (!WIN_IsWindowDrawable( wnd, TRUE ))
149     {
150         WIN_ReleaseWndPtr( wnd );
151         return ERROR;
152     }
153     hwnd = wnd->hwndSelf;  /* make it a full handle */
154     WIN_ReleaseWndPtr( wnd );
155
156     GetClientRect(hwnd, &rc);
157     if (rect) IntersectRect(&rc, &rc, rect);
158
159     if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
160     else cliprc = rc;
161
162     if (!IsRectEmpty(&cliprc) && (dx || dy))
163     {
164         HDC   hDC;
165         BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
166         HRGN  hrgnClip = CreateRectRgnIndirect(&cliprc);
167         HRGN  hrgnTemp;
168         RECT  caretrc;
169
170         TRACE( "%04x, %d,%d hrgnUpdate=%04x rcUpdate = %p rc=(%d,%d-%d,%d) %04x\n",
171                hwnd, dx, dy, hrgnUpdate, rcUpdate,
172                rc.left, rc.top, rc.right, rc.bottom, flags );
173         if (clipRect) TRACE( "cliprc = (%d,%d,%d,%d)\n",
174                              clipRect->left, clipRect->top,
175                              clipRect->right, clipRect->bottom );
176
177         caretrc = rc;
178         bCaret = fix_caret(hwnd, &caretrc, flags);
179
180         if( hrgnUpdate ) bOwnRgn = FALSE;
181         else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
182
183         hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
184         if (hDC)
185         {
186             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
187             X11DRV_StartGraphicsExposures( hDC );
188             X11DRV_ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
189             X11DRV_EndGraphicsExposures( hDC, hrgn );
190             ReleaseDC( hwnd, hDC );
191             if (bUpdate) CombineRgn( hrgnUpdate, hrgnUpdate, hrgn, RGN_OR );
192             else RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
193             DeleteObject( hrgn );
194         }
195
196         /* Take into account the fact that some damages may have occured during the scroll */
197         hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
198         if (GetUpdateRgn( hwnd, hrgnTemp, FALSE ) != NULLREGION)
199         {
200             OffsetRgn( hrgnTemp, dx, dy );
201             CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
202             RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
203         }
204         DeleteObject( hrgnTemp );
205
206         if( flags & SW_SCROLLCHILDREN )
207         {
208             HWND *list = WIN_ListChildren( hwnd );
209
210             if (list)
211             {
212                 int i;
213                 RECT r, dummy;
214                 for (i = 0; list[i]; i++)
215                 {
216                     GetWindowRect( list[i], &r );
217                     MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
218                     if (!rect || IntersectRect(&dummy, &r, &rc))
219                         SetWindowPos( list[i], 0, r.left + dx, r.top  + dy, 0, 0,
220                                       SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
221                                       SWP_NOREDRAW | SWP_DEFERERASE );
222                 }
223                 HeapFree( GetProcessHeap(), 0, list );
224             }
225         }
226
227         if( flags & (SW_INVALIDATE | SW_ERASE) )
228             RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
229                           ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
230                           ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
231
232         if( bCaret )
233         {
234             SetCaretPos( caretrc.left + dx, caretrc.top + dy );
235             ShowCaret(0);
236         }
237
238         if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
239         DeleteObject( hrgnClip );
240     }
241     return retVal;
242 }