Use INVALID_FILE_ATTRIBUTES to test for failure of
[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  * 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.
12  *
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.
17  *
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
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26
27 #include "ts_xlib.h"
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33
34 #include "x11drv.h"
35 #include "win.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
39
40
41 /*************************************************************************
42  *              ScrollDC   (X11DRV.@)
43  *
44  * Only the hrgnUpdate is returned in device coordinates.
45  * rcUpdate must be returned in logical coordinates to comply with win API.
46  * FIXME: the doc explicitly states the opposite, to be checked
47  */
48 BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *rc,
49                       const RECT *clipRect, HRGN hrgnUpdate, LPRECT rcUpdate )
50 {
51     RECT rect, rClip, rDst;
52
53     TRACE( "%p %d,%d hrgnUpdate=%p rcUpdate = %p\n", hdc, dx, dy, hrgnUpdate, rcUpdate );
54     if (clipRect) TRACE( "cliprc = (%ld,%ld,%ld,%ld)\n",
55                          clipRect->left, clipRect->top, clipRect->right, clipRect->bottom );
56     if (rc) TRACE( "rc = (%ld,%ld,%ld,%ld)\n", rc->left, rc->top, rc->right, rc->bottom );
57
58     /* compute device clipping region (in device coordinates) */
59
60     if (rc) rect = *rc;
61     else GetClipBox( hdc, &rect );
62
63     if (clipRect)
64     {
65         rClip = *clipRect;
66         IntersectRect( &rClip, &rect, &rClip );
67     }
68     else rClip = rect;
69
70     rDst = rClip;
71     OffsetRect( &rDst, dx,  dy );
72     IntersectRect( &rDst, &rDst, &rClip );
73
74     if (!IsRectEmpty(&rDst))
75     {
76         /* copy bits */
77         if (!BitBlt( hdc, rDst.left, rDst.top,
78                      rDst.right - rDst.left, rDst.bottom - rDst.top,
79                      hdc, rDst.left - dx, rDst.top - dy, SRCCOPY))
80             return FALSE;
81     }
82
83     /* compute update areas */
84
85     if (hrgnUpdate || rcUpdate)
86     {
87         HRGN hrgn = hrgnUpdate, hrgn2;
88
89         /* map everything to device coordinates */
90         LPtoDP( hdc, (LPPOINT)&rClip, 2 );
91         LPtoDP( hdc, (LPPOINT)&rDst, 2 );
92
93         hrgn2 = CreateRectRgnIndirect( &rDst );
94         if (hrgn) SetRectRgn( hrgn, rClip.left, rClip.top, rClip.right, rClip.bottom );
95         else hrgn = CreateRectRgn( rClip.left, rClip.top, rClip.right, rClip.bottom );
96         CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
97
98         if( rcUpdate )
99         {
100             GetRgnBox( hrgn, rcUpdate );
101
102             /* Put the rcUpdate in logical coordinate */
103             DPtoLP( hdc, (LPPOINT)rcUpdate, 2 );
104         }
105         if (!hrgnUpdate) DeleteObject( hrgn );
106         DeleteObject( hrgn2 );
107     }
108     return TRUE;
109 }
110
111
112 /*************************************************************************
113  *              ScrollWindowEx   (X11DRV.@)
114  *
115  * Note: contrary to what the doc says, pixels that are scrolled from the
116  *      outside of clipRect to the inside are NOT painted.
117  *
118  * Parameter are the same as in ScrollWindowEx, with the additional
119  * requirement that rect and clipRect are _valid_ pointers, to
120  * rectangles _within_ the client are. Moreover, there is something
121  * to scroll.
122  */
123 INT X11DRV_ScrollWindowEx( HWND hwnd, INT dx, INT dy,
124                            const RECT *rect, const RECT *clipRect,
125                            HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags )
126 {
127     INT   retVal;
128     BOOL  bOwnRgn = TRUE;
129     BOOL  bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
130     HRGN  hrgnTemp;
131     HDC   hDC;
132     RECT  rc, cliprc;
133
134     TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n",
135            hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags );
136     TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect));
137
138     GetClientRect(hwnd, &rc);
139     if (rect) IntersectRect(&rc, &rc, rect);
140
141     if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
142     else cliprc = rc;
143
144     if( hrgnUpdate ) bOwnRgn = FALSE;
145     else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
146
147     hDC = GetDCEx( hwnd, 0, DCX_CACHE | DCX_USESTYLE );
148     if (hDC)
149     {
150         HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
151         X11DRV_StartGraphicsExposures( hDC );
152         X11DRV_ScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
153         X11DRV_EndGraphicsExposures( hDC, hrgn );
154         ReleaseDC( hwnd, hDC );
155         if (bUpdate) CombineRgn( hrgnUpdate, hrgnUpdate, hrgn, RGN_OR );
156         else RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
157         DeleteObject( hrgn );
158     }
159
160     /* Take into account the fact that some damage may have occurred during the scroll */
161     hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
162     retVal = GetUpdateRgn( hwnd, hrgnTemp, FALSE );
163     if (retVal != NULLREGION)
164     {
165         HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
166         OffsetRgn( hrgnTemp, dx, dy );
167         CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
168         RedrawWindow( hwnd, NULL, hrgnTemp, RDW_INVALIDATE | RDW_ERASE );
169         DeleteObject( hrgnClip );
170     }
171     DeleteObject( hrgnTemp );
172
173     if( flags & SW_SCROLLCHILDREN )
174     {
175         HWND *list = WIN_ListChildren( hwnd );
176         if (list)
177         {
178             int i;
179             RECT r, dummy;
180             for (i = 0; list[i]; i++)
181             {
182                 GetWindowRect( list[i], &r );
183                 MapWindowPoints( 0, hwnd, (POINT *)&r, 2 );
184                 if (!rect || IntersectRect(&dummy, &r, &rc))
185                     SetWindowPos( list[i], 0, r.left + dx, r.top  + dy, 0, 0,
186                                   SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
187                                   SWP_NOREDRAW | SWP_DEFERERASE );
188             }
189             HeapFree( GetProcessHeap(), 0, list );
190         }
191     }
192
193     if( flags & (SW_INVALIDATE | SW_ERASE) )
194         RedrawWindow( hwnd, NULL, hrgnUpdate, RDW_INVALIDATE | RDW_ERASE |
195                       ((flags & SW_ERASE) ? RDW_ERASENOW : 0) |
196                       ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
197
198     if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
199     
200     return retVal;
201 }