2 * Window painting functions
4 * Copyright 1993 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993";
15 /* Last CTLCOLOR id */
16 #define CTLCOLOR_MAX CTLCOLOR_STATIC
19 /***********************************************************************
20 * BeginPaint (USER.39)
22 HDC
BeginPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
25 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
26 if (!wndPtr
) return 0;
28 hrgnUpdate
= wndPtr
->hrgnUpdate
; /* Save update region */
29 if (!hrgnUpdate
) /* Create an empty region */
30 if (!(hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 ))) return 0;
32 if (!(lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
,
33 DCX_INTERSECTRGN
| DCX_USESTYLE
))) return 0;
34 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
36 if (wndPtr
->hrgnUpdate
|| (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
37 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
39 wndPtr
->hrgnUpdate
= 0;
40 wndPtr
->flags
&= ~(WIN_NEEDS_BEGINPAINT
| WIN_INTERNAL_PAINT
);
42 SendMessage( hwnd
, WM_NCPAINT
, hrgnUpdate
, 0 );
43 DeleteObject( hrgnUpdate
);
45 if (!(wndPtr
->flags
& WIN_ERASE_UPDATERGN
)) lps
->fErase
= TRUE
;
46 else lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, lps
->hdc
, 0 );
52 /***********************************************************************
55 void EndPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
57 ReleaseDC( hwnd
, lps
->hdc
);
61 /***********************************************************************
62 * FillWindow (USER.324)
64 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
67 GetClientRect( hwnd
, &rect
);
68 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
72 /***********************************************************************
73 * PaintRect (USER.325)
75 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
77 /* Send WM_CTLCOLOR message if needed */
79 if (hbrush
<= CTLCOLOR_MAX
)
81 if (!hwndParent
) return;
82 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
83 hdc
, hwnd
| (hbrush
<< 16) );
85 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
89 /***********************************************************************
90 * RedrawWindow (USER.290)
92 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
94 HRGN tmpRgn
, hrgn
= 0;
95 RECT rectClient
, rectWindow
;
98 if (!hwnd
) hwnd
= GetDesktopWindow();
99 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
100 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
101 return TRUE
; /* No redraw needed */
104 * I can't help but feel that this belongs somewhere upstream...
106 * Don't redraw the window if it is iconified and we have an
107 * icon to draw for it
109 /* if (IsIconic(hwnd) && wndPtr->hIcon) return FALSE; */
111 GetClientRect( hwnd
, &rectClient
);
112 rectWindow
= wndPtr
->rectWindow
;
113 OffsetRect(&rectWindow
, -wndPtr
->rectClient
.left
, -wndPtr
->rectClient
.top
);
115 if (flags
& RDW_INVALIDATE
) /* Invalidate */
117 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_ERASE_UPDATERGN
;
119 if (hrgnUpdate
) /* Invalidate a region */
121 if (flags
& RDW_FRAME
) tmpRgn
= CreateRectRgnIndirect(&rectWindow
);
122 else tmpRgn
= CreateRectRgnIndirect( &rectClient
);
123 if (!tmpRgn
) return FALSE
;
124 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
125 if (CombineRgn( hrgn
, hrgnUpdate
, tmpRgn
, RGN_AND
) == NULLREGION
)
127 DeleteObject( hrgn
);
130 DeleteObject( tmpRgn
);
132 else /* Invalidate a rectangle */
135 if (flags
& RDW_FRAME
)
137 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectWindow
);
138 else rect
= rectWindow
;
142 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectClient
);
143 else rect
= rectClient
;
145 if (!IsRectEmpty(&rect
)) hrgn
= CreateRectRgnIndirect( &rect
);
148 /* Set update region */
152 if (!wndPtr
->hrgnUpdate
)
154 wndPtr
->hrgnUpdate
= hrgn
;
155 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
156 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
160 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
161 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
162 DeleteObject( wndPtr
->hrgnUpdate
);
163 DeleteObject( hrgn
);
164 wndPtr
->hrgnUpdate
= tmpRgn
;
167 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
169 else if (flags
& RDW_VALIDATE
) /* Validate */
171 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_ERASE_UPDATERGN
;
172 if (!(hrgn
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
174 /* Remove frame from update region */
176 if (wndPtr
->hrgnUpdate
&& (flags
& RDW_NOFRAME
))
178 if (!(tmpRgn
= CreateRectRgnIndirect( &rectClient
)))
180 if (CombineRgn(hrgn
,tmpRgn
,wndPtr
->hrgnUpdate
,RGN_AND
) == NULLREGION
)
182 DeleteObject( hrgn
);
185 DeleteObject( tmpRgn
);
186 DeleteObject( wndPtr
->hrgnUpdate
);
187 wndPtr
->hrgnUpdate
= hrgn
;
188 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
191 /* Set update region */
193 if (wndPtr
->hrgnUpdate
)
196 if (hrgnUpdate
) /* Validate a region */
198 res
= CombineRgn(hrgn
,wndPtr
->hrgnUpdate
,hrgnUpdate
,RGN_DIFF
);
200 else /* Validate a rectangle */
202 if (rectUpdate
) tmpRgn
= CreateRectRgnIndirect( rectUpdate
);
203 else tmpRgn
= CreateRectRgnIndirect( &rectWindow
);
204 res
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, tmpRgn
, RGN_DIFF
);
205 DeleteObject( tmpRgn
);
207 DeleteObject( wndPtr
->hrgnUpdate
);
208 if (res
== NULLREGION
)
210 DeleteObject( hrgn
);
211 wndPtr
->hrgnUpdate
= 0;
212 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
213 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
215 else wndPtr
->hrgnUpdate
= hrgn
;
219 /* Set/clear internal paint flag */
221 if (flags
& RDW_INTERNALPAINT
)
223 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
224 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
225 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
227 else if (flags
& RDW_NOINTERNALPAINT
)
229 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
230 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
231 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
234 /* Erase/update window */
236 if (flags
& RDW_UPDATENOW
) UpdateWindow( hwnd
);
237 else if (flags
& RDW_ERASENOW
)
239 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
240 DCX_INTERSECTRGN
| DCX_USESTYLE
);
243 SendMessage( hwnd
, WM_NCPAINT
, wndPtr
->hrgnUpdate
, 0 );
244 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
245 ReleaseDC( hwnd
, hdc
);
249 /* Recursively process children */
251 if (!(flags
& RDW_NOCHILDREN
) &&
252 ((flags
&& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
256 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
257 if (!hrgn
) return TRUE
;
258 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
260 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
261 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
262 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
263 -wndPtr
->rectClient
.top
);
264 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
266 DeleteObject( hrgn
);
271 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
273 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
277 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
278 -wndPtr
->rectClient
.top
);
279 RedrawWindow( hwnd
, &rect
, 0, flags
);
281 else RedrawWindow( hwnd
, NULL
, 0, flags
);
289 /***********************************************************************
290 * UpdateWindow (USER.124)
292 void UpdateWindow( HWND hwnd
)
294 if (GetUpdateRect( hwnd
, NULL
, FALSE
))
296 if (IsWindowVisible( hwnd
)) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
301 /***********************************************************************
302 * InvalidateRgn (USER.126)
304 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
306 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
310 /***********************************************************************
311 * InvalidateRect (USER.125)
313 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
315 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
319 /***********************************************************************
320 * ValidateRgn (USER.128)
322 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
324 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
328 /***********************************************************************
329 * ValidateRect (USER.127)
331 void ValidateRect( HWND hwnd
, LPRECT rect
)
333 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
337 /***********************************************************************
338 * GetUpdateRect (USER.190)
340 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
342 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
343 if (!wndPtr
) return FALSE
;
347 if (wndPtr
->hrgnUpdate
)
349 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
350 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
351 GetRgnBox( hrgn
, rect
);
352 DeleteObject( hrgn
);
354 else SetRectEmpty( rect
);
356 return (wndPtr
->hrgnUpdate
!= 0);
360 /***********************************************************************
361 * GetUpdateRgn (USER.237)
363 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
367 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
368 if (!wndPtr
) return ERROR
;
370 if (!wndPtr
->hrgnUpdate
)
372 if (!(hrgnClip
= CreateRectRgn( 0, 0, 0, 0 ))) return ERROR
;
373 retval
= CombineRgn( hrgn
, hrgnClip
, 0, RGN_COPY
);
377 hrgnClip
= CreateRectRgn( 0, 0,
378 wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
379 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
);
380 if (!hrgnClip
) return ERROR
;
381 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, hrgnClip
, RGN_AND
);
384 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
385 DCX_INTERSECTRGN
| DCX_USESTYLE
);
388 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
389 ReleaseDC( hwnd
, hdc
);
393 DeleteObject( hrgnClip
);
398 /***********************************************************************
399 * ExcludeUpdateRgn (USER.238)
401 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
407 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
408 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
410 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
411 wndPtr
->hrgnUpdate
, RGN_DIFF
);
412 if (retval
) SelectVisRgn( hdc
, hrgn
);
413 DeleteObject( hrgn
);