2 * Window painting functions
4 * Copyright 1993 Alexandre Julliard
14 /* #define DEBUG_WIN */
17 /* Last CTLCOLOR id */
18 #define CTLCOLOR_MAX CTLCOLOR_STATIC
21 /***********************************************************************
22 * BeginPaint (USER.39)
24 HDC
BeginPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
27 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
28 if (!wndPtr
) return 0;
30 hrgnUpdate
= wndPtr
->hrgnUpdate
; /* Save update region */
31 if (!hrgnUpdate
) /* Create an empty region */
32 if (!(hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 ))) return 0;
34 if (wndPtr
->hrgnUpdate
|| (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
35 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
37 wndPtr
->hrgnUpdate
= 0;
38 wndPtr
->flags
&= ~(WIN_NEEDS_BEGINPAINT
| WIN_INTERNAL_PAINT
);
40 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
42 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
43 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
46 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
47 DeleteObject( hrgnUpdate
);
50 fprintf( stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%x\n", hwnd
);
54 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
55 DPtoLP( lps
->hdc
, (LPPOINT
)&lps
->rcPaint
, 2 );
57 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
59 lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, lps
->hdc
, 0 );
60 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
62 else lps
->fErase
= TRUE
;
68 /***********************************************************************
71 void EndPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
73 ReleaseDC( hwnd
, lps
->hdc
);
77 /***********************************************************************
78 * FillWindow (USER.324)
80 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
83 GetClientRect( hwnd
, &rect
);
84 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
85 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
89 /***********************************************************************
90 * PaintRect (USER.325)
92 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
94 /* Send WM_CTLCOLOR message if needed */
96 if (hbrush
<= CTLCOLOR_MAX
)
98 if (!hwndParent
) return;
99 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
100 hdc
, MAKELONG( hwnd
, hbrush
) );
102 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
106 /***********************************************************************
107 * RedrawWindow (USER.290)
109 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
111 HRGN tmpRgn
, hrgn
= 0;
112 RECT rectClient
, rectWindow
;
115 if (!hwnd
) hwnd
= GetDesktopWindow();
116 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
117 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
118 return TRUE
; /* No redraw needed */
122 dprintf_win( stddeb
, "RedrawWindow: %x %d,%d-%d,%d %x flags=%04x\n",
123 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
124 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
128 dprintf_win( stddeb
, "RedrawWindow: %x NULL %x flags=%04x\n",
129 hwnd
, hrgnUpdate
, flags
);
131 GetClientRect( hwnd
, &rectClient
);
132 rectWindow
= wndPtr
->rectWindow
;
133 OffsetRect(&rectWindow
, -wndPtr
->rectClient
.left
, -wndPtr
->rectClient
.top
);
135 if (flags
& RDW_INVALIDATE
) /* Invalidate */
137 if (hrgnUpdate
) /* Invalidate a region */
139 if (flags
& RDW_FRAME
) tmpRgn
= CreateRectRgnIndirect(&rectWindow
);
140 else tmpRgn
= CreateRectRgnIndirect( &rectClient
);
141 if (!tmpRgn
) return FALSE
;
142 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
143 if (CombineRgn( hrgn
, hrgnUpdate
, tmpRgn
, RGN_AND
) == NULLREGION
)
145 DeleteObject( hrgn
);
148 DeleteObject( tmpRgn
);
150 else /* Invalidate a rectangle */
153 if (flags
& RDW_FRAME
)
155 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectWindow
);
156 else rect
= rectWindow
;
160 if (rectUpdate
) IntersectRect( &rect
, rectUpdate
, &rectClient
);
161 else rect
= rectClient
;
163 if (!IsRectEmpty(&rect
)) hrgn
= CreateRectRgnIndirect( &rect
);
166 /* Set update region */
170 if (!wndPtr
->hrgnUpdate
)
172 wndPtr
->hrgnUpdate
= hrgn
;
173 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
174 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
178 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
179 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
180 DeleteObject( wndPtr
->hrgnUpdate
);
181 DeleteObject( hrgn
);
182 wndPtr
->hrgnUpdate
= tmpRgn
;
185 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
186 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
187 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
189 else if (flags
& RDW_VALIDATE
) /* Validate */
191 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
192 if (!(hrgn
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
194 /* Remove frame from update region */
196 if (wndPtr
->hrgnUpdate
&& (flags
& RDW_NOFRAME
))
198 if (!(tmpRgn
= CreateRectRgnIndirect( &rectClient
)))
200 if (CombineRgn(hrgn
,tmpRgn
,wndPtr
->hrgnUpdate
,RGN_AND
) == NULLREGION
)
202 DeleteObject( hrgn
);
205 DeleteObject( tmpRgn
);
206 DeleteObject( wndPtr
->hrgnUpdate
);
207 wndPtr
->hrgnUpdate
= hrgn
;
208 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
211 /* Set update region */
213 if (wndPtr
->hrgnUpdate
)
216 if (hrgnUpdate
) /* Validate a region */
218 res
= CombineRgn(hrgn
,wndPtr
->hrgnUpdate
,hrgnUpdate
,RGN_DIFF
);
220 else /* Validate a rectangle */
222 if (rectUpdate
) tmpRgn
= CreateRectRgnIndirect( rectUpdate
);
223 else tmpRgn
= CreateRectRgnIndirect( &rectWindow
);
224 res
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, tmpRgn
, RGN_DIFF
);
225 DeleteObject( tmpRgn
);
227 DeleteObject( wndPtr
->hrgnUpdate
);
228 if (res
== NULLREGION
)
230 DeleteObject( hrgn
);
231 wndPtr
->hrgnUpdate
= 0;
232 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
233 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
235 else wndPtr
->hrgnUpdate
= hrgn
;
239 /* Set/clear internal paint flag */
241 if (flags
& RDW_INTERNALPAINT
)
243 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
244 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
245 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
247 else if (flags
& RDW_NOINTERNALPAINT
)
249 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
250 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
251 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
254 /* Erase/update window */
256 if (flags
& RDW_UPDATENOW
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
257 else if (flags
& RDW_ERASENOW
)
259 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
261 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
262 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
264 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
266 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
267 DCX_INTERSECTRGN
| DCX_USESTYLE
);
270 /* Don't send WM_ERASEBKGND to icons */
271 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
272 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
273 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
275 if (SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 ))
276 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
278 ReleaseDC( hwnd
, hdc
);
283 /* Recursively process children */
285 if (!(flags
& RDW_NOCHILDREN
) &&
286 ((flags
&& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
290 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
291 if (!hrgn
) return TRUE
;
292 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
294 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
295 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
296 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
297 -wndPtr
->rectClient
.top
);
298 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
300 DeleteObject( hrgn
);
305 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
307 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
311 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
312 -wndPtr
->rectClient
.top
);
313 RedrawWindow( hwnd
, &rect
, 0, flags
);
315 else RedrawWindow( hwnd
, NULL
, 0, flags
);
323 /***********************************************************************
324 * UpdateWindow (USER.124)
326 void UpdateWindow( HWND hwnd
)
328 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
332 /***********************************************************************
333 * InvalidateRgn (USER.126)
335 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
337 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
341 /***********************************************************************
342 * InvalidateRect (USER.125)
344 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
346 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
350 /***********************************************************************
351 * ValidateRgn (USER.128)
353 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
355 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
359 /***********************************************************************
360 * ValidateRect (USER.127)
362 void ValidateRect( HWND hwnd
, LPRECT rect
)
364 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
368 /***********************************************************************
369 * GetUpdateRect (USER.190)
371 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
373 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
374 if (!wndPtr
) return FALSE
;
378 if (wndPtr
->hrgnUpdate
)
380 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
381 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
382 GetRgnBox( hrgn
, rect
);
383 DeleteObject( hrgn
);
385 else SetRectEmpty( rect
);
387 return (wndPtr
->hrgnUpdate
!= 0);
391 /***********************************************************************
392 * GetUpdateRgn (USER.237)
394 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
398 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
399 if (!wndPtr
) return ERROR
;
401 if (!wndPtr
->hrgnUpdate
)
403 SetRectRgn( hrgn
, 0, 0, 0, 0 );
406 hrgnClip
= CreateRectRgn( 0, 0,
407 wndPtr
->rectClient
.right
-wndPtr
->rectClient
.left
,
408 wndPtr
->rectClient
.bottom
-wndPtr
->rectClient
.top
);
409 if (!hrgnClip
) return ERROR
;
410 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, hrgnClip
, RGN_AND
);
411 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
412 DeleteObject( hrgnClip
);
417 /***********************************************************************
418 * ExcludeUpdateRgn (USER.238)
420 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
426 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
427 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
429 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
430 wndPtr
->hrgnUpdate
, RGN_DIFF
);
431 if (retval
) SelectVisRgn( hdc
, hrgn
);
432 DeleteObject( hrgn
);