2 * Window painting functions
4 * Copyright 1993 Alexandre Julliard
7 static char Copyright
[] = "Copyright Alexandre Julliard, 1993";
16 /* Last CTLCOLOR id */
17 #define CTLCOLOR_MAX CTLCOLOR_STATIC
20 /***********************************************************************
21 * BeginPaint (USER.39)
23 HDC
BeginPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
26 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
27 if (!wndPtr
) return 0;
29 hrgnUpdate
= wndPtr
->hrgnUpdate
; /* Save update region */
30 if (!hrgnUpdate
) /* Create an empty region */
31 if (!(hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 ))) return 0;
33 if (wndPtr
->hrgnUpdate
|| (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
34 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
36 wndPtr
->hrgnUpdate
= 0;
37 wndPtr
->flags
&= ~(WIN_NEEDS_BEGINPAINT
| WIN_INTERNAL_PAINT
);
39 if (!(lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
,
40 DCX_INTERSECTRGN
| DCX_USESTYLE
)))
42 fprintf( stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%d\n", hwnd
);
43 DeleteObject( hrgnUpdate
);
46 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
47 DPtoLP( lps
->hdc
, (LPPOINT
)&lps
->rcPaint
, 2 );
49 SendMessage( hwnd
, WM_NCPAINT
, hrgnUpdate
, 0 );
50 DeleteObject( hrgnUpdate
);
52 if (!(wndPtr
->flags
& WIN_ERASE_UPDATERGN
)) lps
->fErase
= TRUE
;
53 else lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, lps
->hdc
, 0 );
59 /***********************************************************************
62 void EndPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
64 ReleaseDC( hwnd
, lps
->hdc
);
68 /***********************************************************************
69 * FillWindow (USER.324)
71 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
74 GetClientRect( hwnd
, &rect
);
75 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
76 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
80 /***********************************************************************
81 * PaintRect (USER.325)
83 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
85 /* Send WM_CTLCOLOR message if needed */
87 if (hbrush
<= CTLCOLOR_MAX
)
89 if (!hwndParent
) return;
90 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
91 hdc
, hwnd
| (hbrush
<< 16) );
93 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
97 /***********************************************************************
98 * RedrawWindow (USER.290)
100 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
102 HRGN tmpRgn
, hrgn
= 0;
103 RECT rectClient
, rectWindow
;
106 if (!hwnd
) hwnd
= GetDesktopWindow();
107 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
108 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
109 return TRUE
; /* No redraw needed */
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 );
245 /* Don't send WM_ERASEBKGND to icons */
246 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
247 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
248 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
249 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
250 ReleaseDC( hwnd
, hdc
);
254 /* Recursively process children */
256 if (!(flags
& RDW_NOCHILDREN
) &&
257 ((flags
&& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
261 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
262 if (!hrgn
) return TRUE
;
263 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
265 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
266 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
267 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
268 -wndPtr
->rectClient
.top
);
269 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
271 DeleteObject( hrgn
);
276 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
278 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
282 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
283 -wndPtr
->rectClient
.top
);
284 RedrawWindow( hwnd
, &rect
, 0, flags
);
286 else RedrawWindow( hwnd
, NULL
, 0, flags
);
294 /***********************************************************************
295 * UpdateWindow (USER.124)
297 void UpdateWindow( HWND hwnd
)
299 if (GetUpdateRect( hwnd
, NULL
, FALSE
))
301 if (IsWindowVisible( hwnd
)) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
306 /***********************************************************************
307 * InvalidateRgn (USER.126)
309 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
311 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
315 /***********************************************************************
316 * InvalidateRect (USER.125)
318 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
320 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
324 /***********************************************************************
325 * ValidateRgn (USER.128)
327 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
329 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
333 /***********************************************************************
334 * ValidateRect (USER.127)
336 void ValidateRect( HWND hwnd
, LPRECT rect
)
338 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
342 /***********************************************************************
343 * GetUpdateRect (USER.190)
345 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
347 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
348 if (!wndPtr
) return FALSE
;
352 if (wndPtr
->hrgnUpdate
)
354 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
355 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
356 GetRgnBox( hrgn
, rect
);
357 DeleteObject( hrgn
);
359 else SetRectEmpty( rect
);
361 return (wndPtr
->hrgnUpdate
!= 0);
365 /***********************************************************************
366 * GetUpdateRgn (USER.237)
368 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
372 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
373 if (!wndPtr
) return ERROR
;
375 if (!wndPtr
->hrgnUpdate
)
377 if (!(hrgnClip
= CreateRectRgn( 0, 0, 0, 0 ))) return ERROR
;
378 retval
= CombineRgn( hrgn
, hrgnClip
, 0, RGN_COPY
);
382 hrgnClip
= CreateRectRgn( 0, 0,
383 wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
384 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
);
385 if (!hrgnClip
) return ERROR
;
386 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, hrgnClip
, RGN_AND
);
389 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
390 DCX_INTERSECTRGN
| DCX_USESTYLE
);
393 SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 );
394 ReleaseDC( hwnd
, hdc
);
398 DeleteObject( hrgnClip
);
403 /***********************************************************************
404 * ExcludeUpdateRgn (USER.238)
406 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
412 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
413 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
415 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
416 wndPtr
->hrgnUpdate
, RGN_DIFF
);
417 if (retval
) SelectVisRgn( hdc
, hrgn
);
418 DeleteObject( hrgn
);