2 * Window painting functions
4 * Copyright 1993, 1994, 1995 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 * GetControlBrush (USER.326)
109 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
111 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
,
112 hdc
, MAKELONG( hwnd
, control
) );
116 /***********************************************************************
117 * RedrawWindow (USER.290)
119 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
125 if (!hwnd
) hwnd
= GetDesktopWindow();
126 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
127 if (!(wndPtr
->dwStyle
& WS_VISIBLE
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
128 return TRUE
; /* No redraw needed */
132 dprintf_win( stddeb
, "RedrawWindow: %x %d,%d-%d,%d %x flags=%04x\n",
133 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
134 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
138 dprintf_win( stddeb
, "RedrawWindow: %x NULL %x flags=%04x\n",
139 hwnd
, hrgnUpdate
, flags
);
141 GetClientRect( hwnd
, &rectClient
);
143 if (flags
& RDW_INVALIDATE
) /* Invalidate */
145 if (wndPtr
->hrgnUpdate
) /* Is there already an update region? */
147 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
148 if ((hrgn
= hrgnUpdate
) == 0)
149 hrgn
= CreateRectRgnIndirect( rectUpdate
? rectUpdate
:
151 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
152 DeleteObject( wndPtr
->hrgnUpdate
);
153 wndPtr
->hrgnUpdate
= tmpRgn
;
154 if (!hrgnUpdate
) DeleteObject( hrgn
);
156 else /* No update region yet */
158 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
159 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
162 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
163 CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
165 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect( rectUpdate
?
166 rectUpdate
: &rectClient
);
168 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
169 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
170 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
172 else if (flags
& RDW_VALIDATE
) /* Validate */
174 /* We need an update region in order to validate anything */
175 if (wndPtr
->hrgnUpdate
)
177 if (!hrgnUpdate
&& !rectUpdate
)
179 /* Special case: validate everything */
180 DeleteObject( wndPtr
->hrgnUpdate
);
181 wndPtr
->hrgnUpdate
= 0;
185 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
186 if ((hrgn
= hrgnUpdate
) == 0)
187 hrgn
= CreateRectRgnIndirect( rectUpdate
);
188 if (CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
,
189 hrgn
, RGN_DIFF
) == NULLREGION
)
191 DeleteObject( tmpRgn
);
194 DeleteObject( wndPtr
->hrgnUpdate
);
195 wndPtr
->hrgnUpdate
= tmpRgn
;
196 if (!hrgnUpdate
) DeleteObject( hrgn
);
198 if (!wndPtr
->hrgnUpdate
) /* No more update region */
199 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
200 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
202 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
203 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
206 /* Set/clear internal paint flag */
208 if (flags
& RDW_INTERNALPAINT
)
210 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
211 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
212 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
214 else if (flags
& RDW_NOINTERNALPAINT
)
216 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
217 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
218 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
221 /* Erase/update window */
223 if (flags
& RDW_UPDATENOW
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
224 else if (flags
& RDW_ERASENOW
)
226 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
228 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
229 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
231 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
233 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
234 DCX_INTERSECTRGN
| DCX_USESTYLE
);
237 /* Don't send WM_ERASEBKGND to icons */
238 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
239 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
240 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
242 if (SendMessage( hwnd
, WM_ERASEBKGND
, hdc
, 0 ))
243 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
245 ReleaseDC( hwnd
, hdc
);
250 /* Recursively process children */
252 if (!(flags
& RDW_NOCHILDREN
) &&
253 ((flags
&& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
257 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
258 if (!hrgn
) return TRUE
;
259 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
261 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
262 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
263 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
264 -wndPtr
->rectClient
.top
);
265 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
267 DeleteObject( hrgn
);
272 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
274 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
278 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
279 -wndPtr
->rectClient
.top
);
280 RedrawWindow( hwnd
, &rect
, 0, flags
);
282 else RedrawWindow( hwnd
, NULL
, 0, flags
);
290 /***********************************************************************
291 * UpdateWindow (USER.124)
293 void UpdateWindow( HWND hwnd
)
295 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
299 /***********************************************************************
300 * InvalidateRgn (USER.126)
302 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
304 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
308 /***********************************************************************
309 * InvalidateRect (USER.125)
311 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
313 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
317 /***********************************************************************
318 * ValidateRgn (USER.128)
320 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
322 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
326 /***********************************************************************
327 * ValidateRect (USER.127)
329 void ValidateRect( HWND hwnd
, LPRECT rect
)
331 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
335 /***********************************************************************
336 * GetUpdateRect (USER.190)
338 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
340 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
341 if (!wndPtr
) return FALSE
;
345 if (wndPtr
->hrgnUpdate
)
347 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
348 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
349 GetRgnBox( hrgn
, rect
);
350 DeleteObject( hrgn
);
352 else SetRectEmpty( rect
);
354 return (wndPtr
->hrgnUpdate
!= 0);
358 /***********************************************************************
359 * GetUpdateRgn (USER.237)
361 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
364 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
365 if (!wndPtr
) return ERROR
;
367 if (!wndPtr
->hrgnUpdate
)
369 SetRectRgn( hrgn
, 0, 0, 0, 0 );
372 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
373 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
378 /***********************************************************************
379 * ExcludeUpdateRgn (USER.238)
381 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
387 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
388 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
390 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
391 wndPtr
->hrgnUpdate
, RGN_DIFF
);
392 if (retval
) SelectVisRgn( hdc
, hrgn
);
393 DeleteObject( hrgn
);