2 * Window painting functions
4 * Copyright 1993 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993";
14 /* Last CTLCOLOR id */
15 #define CTLCOLOR_MAX CTLCOLOR_STATIC
18 /***********************************************************************
19 * BeginPaint (USER.39)
21 HDC
BeginPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
24 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
25 if (!wndPtr
) return 0;
27 hrgnUpdate
= wndPtr
->hrgnUpdate
; /* Save update region */
28 if (!hrgnUpdate
) /* Create an empty region */
29 if (!(hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 ))) return 0;
31 if (!(lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
,
32 DCX_INTERSECTRGN
| DCX_USESTYLE
))) return 0;
33 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
35 if (wndPtr
->hrgnUpdate
|| (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
36 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
38 wndPtr
->hrgnUpdate
= 0;
39 wndPtr
->flags
&= ~(WIN_NEEDS_BEGINPAINT
| WIN_INTERNAL_PAINT
);
41 SendMessage( hwnd
, WM_NCPAINT
, hrgnUpdate
, 0 );
42 DeleteObject( hrgnUpdate
);
44 if (!(wndPtr
->flags
& WIN_ERASE_UPDATERGN
)) lps
->fErase
= TRUE
;
45 else lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, lps
->hdc
, 0 );
51 /***********************************************************************
54 void EndPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
56 ReleaseDC( hwnd
, lps
->hdc
);
60 /***********************************************************************
61 * FillWindow (USER.324)
63 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
66 GetClientRect( hwnd
, &rect
);
67 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
71 /***********************************************************************
72 * PaintRect (USER.325)
74 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
76 /* Send WM_CTLCOLOR message if needed */
78 if (hbrush
<= CTLCOLOR_MAX
)
80 if (!hwndParent
) return;
81 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
82 hdc
, hwnd
| (hbrush
<< 16) );
84 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
88 /***********************************************************************
89 * RedrawWindow (USER.290)
91 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
93 HRGN tmpRgn
, hrgn
= 0;
94 RECT rectClient
, rectWindow
;
97 if (!hwnd
) hwnd
= GetDesktopWindow();
98 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
100 GetClientRect( hwnd
, &rectClient
);
101 rectWindow
= wndPtr
->rectWindow
;
102 OffsetRect(&rectWindow
, -wndPtr
->rectClient
.left
, -wndPtr
->rectClient
.top
);
104 if (flags
& RDW_INVALIDATE
) /* Invalidate */
106 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_ERASE_UPDATERGN
;
108 if (hrgnUpdate
) /* Invalidate a region */
110 if (flags
& RDW_FRAME
) tmpRgn
= CreateRectRgnIndirect(&rectWindow
);
111 else tmpRgn
= CreateRectRgnIndirect( &rectClient
);
112 if (!tmpRgn
) return FALSE
;
113 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
114 if (CombineRgn( hrgn
, hrgnUpdate
, tmpRgn
, RGN_AND
) == NULLREGION
)
116 DeleteObject( hrgn
);
119 DeleteObject( tmpRgn
);
121 else /* Invalidate a rectangle */
124 if (flags
& RDW_FRAME
)
126 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectWindow
);
127 else rect
= rectWindow
;
131 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectClient
);
132 else rect
= rectClient
;
134 if (!IsRectEmpty(&rect
)) hrgn
= CreateRectRgnIndirect( &rect
);
137 /* Set update region */
141 if (!wndPtr
->hrgnUpdate
)
143 wndPtr
->hrgnUpdate
= hrgn
;
144 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
145 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
149 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
150 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
151 DeleteObject( wndPtr
->hrgnUpdate
);
152 DeleteObject( hrgn
);
153 wndPtr
->hrgnUpdate
= tmpRgn
;
156 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
158 else if (flags
& RDW_VALIDATE
) /* Validate */
160 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_ERASE_UPDATERGN
;
161 if (!(hrgn
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
163 /* Remove frame from update region */
165 if (wndPtr
->hrgnUpdate
&& (flags
& RDW_NOFRAME
))
167 if (!(tmpRgn
= CreateRectRgnIndirect( &rectClient
)))
169 if (CombineRgn(hrgn
,tmpRgn
,wndPtr
->hrgnUpdate
,RGN_AND
) == NULLREGION
)
171 DeleteObject( hrgn
);
174 DeleteObject( tmpRgn
);
175 DeleteObject( wndPtr
->hrgnUpdate
);
176 wndPtr
->hrgnUpdate
= hrgn
;
177 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
180 /* Set update region */
182 if (wndPtr
->hrgnUpdate
)
185 if (hrgnUpdate
) /* Validate a region */
187 res
= CombineRgn(hrgn
,wndPtr
->hrgnUpdate
,hrgnUpdate
,RGN_DIFF
);
189 else /* Validate a rectangle */
191 if (rectUpdate
) tmpRgn
= CreateRectRgnIndirect( rectUpdate
);
192 else tmpRgn
= CreateRectRgnIndirect( &rectWindow
);
193 res
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, tmpRgn
, RGN_DIFF
);
194 DeleteObject( tmpRgn
);
196 DeleteObject( wndPtr
->hrgnUpdate
);
197 if (res
== NULLREGION
)
199 DeleteObject( hrgn
);
200 wndPtr
->hrgnUpdate
= 0;
201 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
202 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
204 else wndPtr
->hrgnUpdate
= hrgn
;
208 /* Set/clear internal paint flag */
210 if (flags
& RDW_INTERNALPAINT
)
212 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
213 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
214 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
216 else if (flags
& RDW_NOINTERNALPAINT
)
218 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
219 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
220 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
223 /* Erase/update window */
225 if (flags
& RDW_UPDATENOW
) UpdateWindow( hwnd
);
226 else if (flags
& RDW_ERASENOW
)
228 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
229 DCX_INTERSECTRGN
| DCX_USESTYLE
);
232 SendMessage( hwnd
, WM_NCPAINT
, wndPtr
->hrgnUpdate
, 0 );
233 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
234 ReleaseDC( hwnd
, hdc
);
238 /* Recursively process children */
240 if (!(flags
& RDW_NOCHILDREN
) &&
241 ((flags
&& RDW_ALLCHILDREN
) || (wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
245 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
246 if (!hrgn
) return TRUE
;
247 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
249 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
250 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
251 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
252 -wndPtr
->rectClient
.top
);
253 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
255 DeleteObject( hrgn
);
260 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
262 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
266 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
267 -wndPtr
->rectClient
.top
);
268 RedrawWindow( hwnd
, &rect
, 0, flags
);
270 else RedrawWindow( hwnd
, NULL
, 0, flags
);
278 /***********************************************************************
279 * UpdateWindow (USER.124)
281 void UpdateWindow( HWND hwnd
)
283 if (GetUpdateRect( hwnd
, NULL
, FALSE
))
285 if (IsWindowVisible( hwnd
)) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
290 /***********************************************************************
291 * InvalidateRgn (USER.126)
293 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
295 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
299 /***********************************************************************
300 * InvalidateRect (USER.125)
302 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
304 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
308 /***********************************************************************
309 * ValidateRgn (USER.128)
311 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
313 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
317 /***********************************************************************
318 * ValidateRect (USER.127)
320 void ValidateRect( HWND hwnd
, LPRECT rect
)
322 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
326 /***********************************************************************
327 * GetUpdateRect (USER.190)
329 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
331 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
332 if (!wndPtr
) return FALSE
;
336 if (wndPtr
->hrgnUpdate
)
338 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
339 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
340 GetRgnBox( hrgn
, rect
);
341 DeleteObject( hrgn
);
343 else SetRectEmpty( rect
);
345 return (wndPtr
->hrgnUpdate
!= 0);
349 /***********************************************************************
350 * GetUpdateRgn (USER.237)
352 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
356 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
357 if (!wndPtr
) return ERROR
;
359 if (!wndPtr
->hrgnUpdate
)
361 if (!(hrgnClip
= CreateRectRgn( 0, 0, 0, 0 ))) return ERROR
;
362 retval
= CombineRgn( hrgn
, hrgnClip
, 0, RGN_COPY
);
366 hrgnClip
= CreateRectRgn( 0, 0,
367 wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
368 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
);
369 if (!hrgnClip
) return ERROR
;
370 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, hrgnClip
, RGN_AND
);
373 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
374 DCX_INTERSECTRGN
| DCX_USESTYLE
);
377 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
378 ReleaseDC( hwnd
, hdc
);
382 DeleteObject( hrgnClip
);
387 /***********************************************************************
388 * ExcludeUpdateRgn (USER.238)
390 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
396 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
397 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
399 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
400 wndPtr
->hrgnUpdate
, RGN_DIFF
);
401 if (retval
) SelectVisRgn( hdc
, hrgn
);
402 DeleteObject( hrgn
);