2 * Scroll windows and DCs
4 * Copyright David W. Metcalfe, 1993
15 #include "sysmetrics.h"
17 /* #define DEBUG_SCROLL */
20 extern HRGN
DCE_GetVisRgn(HWND
, WORD
); /* windows/dce.c */
21 extern HWND
CARET_GetHwnd(); /* windows/caret.c */
22 extern void CLIPPING_UpdateGCRegion(DC
* ); /* objects/clipping.c */
27 /* -----------------------------------------------------------------------
28 * SCROLL_TraceChildren
30 * Returns a region invalidated by children, siblings, and/or ansectors
31 * in the window rectangle or client rectangle
33 * dcx can have DCX_WINDOW, DCX_CLIPCHILDREN, DCX_CLIPSIBLINGS set
36 HRGN
SCROLL_TraceChildren( WND
* wndScroll
, short dx
, short dy
, WORD dcx
)
39 HRGN hUpdateRgn
,hCombineRgn
;
41 if( !wndScroll
|| ( !dx
&& !dy
) ) return 0;
43 if( dcx
& DCX_WINDOW
)
44 hRgnWnd
= CreateRectRgnIndirect16(&wndScroll
->rectWindow
);
47 RECT32 rect
= { 0, 0, wndScroll
->rectClient
.right
- wndScroll
->rectClient
.left
,
48 wndScroll
->rectClient
.bottom
- wndScroll
->rectClient
.top
};
50 hRgnWnd
= CreateRectRgnIndirect32(&rect
);
53 hUpdateRgn
= DCE_GetVisRgn( wndScroll
->hwndSelf
, dcx
);
54 hCombineRgn
= CreateRectRgn(0,0,0,0);
56 if( !hUpdateRgn
|| !hCombineRgn
)
58 DeleteObject( hUpdateRgn
? hUpdateRgn
: hCombineRgn
);
59 DeleteObject(hRgnWnd
);
63 OffsetRgn( hUpdateRgn
, dx
, dy
);
64 CombineRgn(hCombineRgn
, hRgnWnd
, hUpdateRgn
, RGN_DIFF
);
66 DeleteObject(hRgnWnd
);
67 DeleteObject(hUpdateRgn
);
73 /* ----------------------------------------------------------------------
74 * SCROLL_ScrollChildren
76 BOOL
SCROLL_ScrollChildren( WND
* wndScroll
, short dx
, short dy
)
82 if( !wndScroll
|| ( !dx
&& !dy
)) return 0;
84 dprintf_scroll(stddeb
,"SCROLL_ScrollChildren: hwnd %04x dx=%i dy=%i\n",wndScroll
->hwndSelf
,dx
,dy
);
86 /* get a region in client rect invalidated by siblings and ansectors */
87 hUpdateRgn
= SCROLL_TraceChildren(wndScroll
, dx
, dy
, DCX_CLIPSIBLINGS
);
89 /* update children coordinates */
90 for (wndPtr
= wndScroll
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
92 /* we can check if window intersects with clipRect parameter
93 * and do not move it if not - just a thought. - AK
95 SetWindowPos(wndPtr
->hwndSelf
, 0, wndPtr
->rectWindow
.left
+ dx
,
96 wndPtr
->rectWindow
.top
+ dy
, 0,0, SWP_NOZORDER
|
97 SWP_NOSIZE
| SWP_NOACTIVATE
| SWP_NOREDRAW
|
101 /* invalidate uncovered region and paint frames */
102 b
= RedrawWindow32( wndScroll
->hwndSelf
, NULL
, hUpdateRgn
,
103 RDW_INVALIDATE
| RDW_FRAME
| RDW_ERASE
| RDW_ERASENOW
| RDW_ALLCHILDREN
);
105 DeleteObject( hUpdateRgn
);
110 /*************************************************************************
111 * ScrollWindow (USER.61)
114 void ScrollWindow(HWND hwnd
, short dx
, short dy
, LPRECT16 rect
, LPRECT16 clipRect
)
117 HRGN hrgnUpdate
,hrgnClip
;
119 HWND hCaretWnd
= CARET_GetHwnd();
120 WND
* wndScroll
= WIN_FindWndPtr( hwnd
);
122 dprintf_scroll(stddeb
,"ScrollWindow: dx=%d, dy=%d, lpRect =%08lx clipRect=%i,%i,%i,%i\n",
123 dx
, dy
, (LONG
)rect
, (int)((clipRect
)?clipRect
->left
:0),
124 (int)((clipRect
)?clipRect
->top
:0),
125 (int)((clipRect
)?clipRect
->right
:0),
126 (int)((clipRect
)?clipRect
->bottom
:0));
128 /* if rect is NULL children have to be moved */
131 GetClientRect16(hwnd
, &rc
);
132 hrgnClip
= CreateRectRgnIndirect16( &rc
);
134 if ((hCaretWnd
== hwnd
) || IsChild(hwnd
,hCaretWnd
))
135 HideCaret(hCaretWnd
);
138 /* children will be Blt'ed too */
139 hdc
= GetDCEx(hwnd
, hrgnClip
, DCX_CACHE
| DCX_CLIPSIBLINGS
);
140 DeleteObject(hrgnClip
);
144 GetClientRect16(hwnd
,&rc
);
145 dprintf_scroll(stddeb
,"\trect=%i %i %i %i client=%i %i %i %i\n",
146 (int)rect
->left
,(int)rect
->top
,(int)rect
->right
,
147 (int)rect
->bottom
,(int)rc
.left
,(int)rc
.top
,
148 (int)rc
.right
,(int)rc
.bottom
);
150 if (hCaretWnd
== hwnd
) HideCaret(hCaretWnd
);
152 CopyRect16(&rc
, rect
);
156 if (clipRect
== NULL
)
157 GetClientRect16(hwnd
, &cliprc
);
159 CopyRect16(&cliprc
, clipRect
);
161 /* move window update region (if any) */
163 if( wndScroll
->hrgnUpdate
> 1 )
164 OffsetRgn( wndScroll
->hrgnUpdate
, dx
, dy
);
166 hrgnUpdate
= CreateRectRgn(0, 0, 0, 0);
167 ScrollDC(hdc
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, NULL
);
168 ReleaseDC(hwnd
, hdc
);
172 /* FIXME: this doesn't take into account hrgnUpdate */
174 if( !SCROLL_ScrollChildren( wndScroll
, dx
,dy
) )
175 InvalidateRgn(hwnd
, hrgnUpdate
, TRUE
);
179 HRGN hrgnInv
= SCROLL_TraceChildren( wndScroll
,dx
,dy
,DCX_CLIPCHILDREN
|
183 CombineRgn(hrgnUpdate
,hrgnInv
,hrgnUpdate
,RGN_OR
);
184 DeleteObject(hrgnInv
);
187 RedrawWindow32( hwnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
| RDW_ERASENOW
);
190 DeleteObject(hrgnUpdate
);
191 if( hCaretWnd
) ShowCaret(hCaretWnd
);
195 /*************************************************************************
196 * ScrollDC (USER.221)
199 BOOL
ScrollDC(HDC hdc
, short dx
, short dy
, LPRECT16 rc
, LPRECT16 cliprc
,
200 HRGN hrgnUpdate
, LPRECT16 rcUpdate
)
203 HRGN hrgnScrollClip
= 0;
207 DC
*dc
= (DC
*)GDI_GetObjPtr(hdc
, DC_MAGIC
);
209 dprintf_scroll(stddeb
,"ScrollDC: dx=%d dy=%d, hrgnUpdate=%04x rcUpdate = %p cliprc = %p, rc=%d %d %d %d\n",
210 dx
, dy
, hrgnUpdate
, rcUpdate
, cliprc
, rc
? rc
->left
: 0,
211 rc
? rc
->top
: 0, rc
? rc
->right
: 0, rc
? rc
->bottom
: 0 );
213 if (rc
== NULL
|| !hdc
|| !dc
)
216 /* set clipping region */
219 IntersectRect16(&rectClip
,rc
,cliprc
);
223 if( rectClip
.left
>= rectClip
.right
|| rectClip
.top
>= rectClip
.bottom
)
226 hrgnClip
= GetClipRgn(hdc
);
227 hrgnScrollClip
= CreateRectRgnIndirect16(&rectClip
);
231 /* call UpdateGCRegion directly to avoid
232 * one more temporary region
235 CombineRgn( hrgnScrollClip
, hrgnClip
, 0, RGN_COPY
);
236 SetRectRgn( hrgnClip
, rectClip
.left
, rectClip
.top
, rectClip
.right
, rectClip
.bottom
);
238 CLIPPING_UpdateGCRegion( dc
);
241 SelectClipRgn( hdc
, hrgnScrollClip
);
243 /* translate coordinates */
247 src
.x
= XDPTOLP(dc
, rc
->left
);
248 dest
.x
= XDPTOLP(dc
, rc
->left
+ abs(dx
));
252 src
.x
= XDPTOLP(dc
, rc
->left
+ abs(dx
));
253 dest
.x
= XDPTOLP(dc
, rc
->left
);
257 src
.y
= YDPTOLP(dc
, rc
->top
);
258 dest
.y
= YDPTOLP(dc
, rc
->top
+ abs(dy
));
262 src
.y
= YDPTOLP(dc
, rc
->top
+ abs(dy
));
263 dest
.y
= YDPTOLP(dc
, rc
->top
);
266 width
= rc
->right
- rc
->left
- abs(dx
);
267 height
= rc
->bottom
- rc
->top
- abs(dy
);
271 if (!BitBlt(hdc
, dest
.x
, dest
.y
, width
, height
, hdc
, src
.x
, src
.y
,
275 /* compute update areas */
282 hrgn1
= CreateRectRgn(rc
->left
, rc
->top
, rc
->left
+dx
, rc
->bottom
);
284 hrgn1
= CreateRectRgn(rc
->right
+dx
, rc
->top
, rc
->right
,
287 hrgn1
= CreateRectRgn(0, 0, 0, 0);
290 hrgn2
= CreateRectRgn(rc
->left
, rc
->top
, rc
->right
, rc
->top
+dy
);
292 hrgn2
= CreateRectRgn(rc
->left
, rc
->bottom
+dy
, rc
->right
,
295 hrgn2
= CreateRectRgn(0, 0, 0, 0);
297 RgnType
= CombineRgn(hrgnUpdate
, hrgn1
, hrgn2
, RGN_OR
);
300 if (rcUpdate
) GetRgnBox16( hrgnUpdate
, rcUpdate
);
307 if( dx
> 0 ) rx
.right
= rc
->left
+dx
;
308 else if (dx
< 0) rx
.left
= rc
->right
+dx
;
309 else SetRectEmpty16( &rx
);
311 if( dy
> 0 ) ry
.bottom
= rc
->top
+dy
;
312 else if (dy
< 0) ry
.top
= rc
->bottom
+dy
;
313 else SetRectEmpty16( &ry
);
315 UnionRect16( rcUpdate
, &rx
, &ry
);
318 /* restore clipping region */
320 SelectClipRgn( hdc
, (hrgnClip
)?hrgnScrollClip
:0 );
321 DeleteObject( hrgnScrollClip
);
327 /*************************************************************************
328 * ScrollWindowEx (USER.319)
332 * SCROLL_TraceChildren can help
335 int ScrollWindowEx(HWND hwnd
, short dx
, short dy
, LPRECT16 rect
, LPRECT16 clipRect
,
336 HRGN hrgnUpdate
, LPRECT16 rcUpdate
, WORD flags
)
341 dprintf_scroll(stddeb
,"ScrollWindowEx: dx=%d, dy=%d, wFlags=%04x\n",dx
, dy
, flags
);
346 GetClientRect16(hwnd
, &rc
);
348 CopyRect16(&rc
, rect
);
349 if (clipRect
== NULL
)
350 GetClientRect16(hwnd
, &cliprc
);
352 CopyRect16(&cliprc
, clipRect
);
354 ScrollDC(hdc
, dx
, dy
, &rc
, &cliprc
, hrgnUpdate
, rcUpdate
);
356 if (flags
| SW_INVALIDATE
)
358 RedrawWindow32( hwnd
, NULL
, hrgnUpdate
, RDW_INVALIDATE
| RDW_ERASE
|
359 ((flags
& SW_ERASE
) ? RDW_ERASENOW
: 0));
362 ReleaseDC(hwnd
, hdc
);