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
);
42 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
44 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
45 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
48 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
49 DeleteObject( hrgnUpdate
);
52 fprintf( stderr
, "GetDCEx() failed in BeginPaint(), hwnd="NPFMT
"\n", hwnd
);
56 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
57 DPtoLP( lps
->hdc
, (LPPOINT
)&lps
->rcPaint
, 2 );
59 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
61 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
62 lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)lps
->hdc
, 0 );
64 else lps
->fErase
= TRUE
;
70 /***********************************************************************
73 BOOL
EndPaint( HWND hwnd
, const PAINTSTRUCT
* lps
)
75 ReleaseDC( hwnd
, lps
->hdc
);
81 /***********************************************************************
82 * FillWindow (USER.324)
84 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
87 GetClientRect( hwnd
, &rect
);
88 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
89 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
93 /***********************************************************************
94 * PaintRect (USER.325)
96 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
98 /* Send WM_CTLCOLOR message if needed */
100 if ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
102 if (!hwndParent
) return;
104 hbrush
= (HBRUSH
)SendMessage( hwndParent
,
105 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
106 (WPARAM
)hdc
, (LPARAM
)hwnd
);
108 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
109 hdc
, MAKELONG( hwnd
, hbrush
) );
112 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
116 /***********************************************************************
117 * GetControlBrush (USER.326)
119 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
122 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
+control
,
123 (WPARAM
)hdc
, (LPARAM
)hwnd
);
125 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
,
126 hdc
, MAKELONG( hwnd
, control
) );
131 /***********************************************************************
132 * RedrawWindow (USER.290)
134 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
140 if (!hwnd
) hwnd
= GetDesktopWindow();
141 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
142 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
143 return TRUE
; /* No redraw needed */
147 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" %ld,%ld-%ld,%ld "NPFMT
" flags=%04x\n",
148 hwnd
, (LONG
)rectUpdate
->left
, (LONG
)rectUpdate
->top
,
149 (LONG
)rectUpdate
->right
, (LONG
)rectUpdate
->bottom
, hrgnUpdate
, flags
);
153 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" NULL "NPFMT
" flags=%04x\n",
154 hwnd
, hrgnUpdate
, flags
);
156 GetClientRect( hwnd
, &rectClient
);
158 if (flags
& RDW_INVALIDATE
) /* Invalidate */
160 if (wndPtr
->hrgnUpdate
) /* Is there already an update region? */
162 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
163 if ((hrgn
= hrgnUpdate
) == 0)
164 hrgn
= CreateRectRgnIndirect( rectUpdate
? rectUpdate
:
166 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
167 DeleteObject( wndPtr
->hrgnUpdate
);
168 wndPtr
->hrgnUpdate
= tmpRgn
;
169 if (!hrgnUpdate
) DeleteObject( hrgn
);
171 else /* No update region yet */
173 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
174 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
177 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
178 CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
180 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect( rectUpdate
?
181 rectUpdate
: &rectClient
);
183 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
184 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
185 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
187 else if (flags
& RDW_VALIDATE
) /* Validate */
189 /* We need an update region in order to validate anything */
190 if (wndPtr
->hrgnUpdate
)
192 if (!hrgnUpdate
&& !rectUpdate
)
194 /* Special case: validate everything */
195 DeleteObject( wndPtr
->hrgnUpdate
);
196 wndPtr
->hrgnUpdate
= 0;
200 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
201 if ((hrgn
= hrgnUpdate
) == 0)
202 hrgn
= CreateRectRgnIndirect( rectUpdate
);
203 if (CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
,
204 hrgn
, RGN_DIFF
) == NULLREGION
)
206 DeleteObject( tmpRgn
);
209 DeleteObject( wndPtr
->hrgnUpdate
);
210 wndPtr
->hrgnUpdate
= tmpRgn
;
211 if (!hrgnUpdate
) DeleteObject( hrgn
);
213 if (!wndPtr
->hrgnUpdate
) /* No more update region */
214 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
215 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
217 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
218 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
221 /* Set/clear internal paint flag */
223 if (flags
& RDW_INTERNALPAINT
)
225 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
226 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
227 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
229 else if (flags
& RDW_NOINTERNALPAINT
)
231 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
232 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
233 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
236 /* Erase/update window */
238 if (flags
& RDW_UPDATENOW
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
239 else if (flags
& RDW_ERASENOW
)
241 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
243 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
244 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
246 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
248 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
249 DCX_INTERSECTRGN
| DCX_USESTYLE
);
252 /* Don't send WM_ERASEBKGND to icons */
253 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
254 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
255 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
257 if (SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
258 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
260 ReleaseDC( hwnd
, hdc
);
265 /* Recursively process children */
267 if (!(flags
& RDW_NOCHILDREN
) &&
268 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
272 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
273 if (!hrgn
) return TRUE
;
274 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
276 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
277 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
278 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
279 -wndPtr
->rectClient
.top
);
280 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
282 DeleteObject( hrgn
);
287 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
289 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
293 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
294 -wndPtr
->rectClient
.top
);
295 RedrawWindow( hwnd
, &rect
, 0, flags
);
297 else RedrawWindow( hwnd
, NULL
, 0, flags
);
305 /***********************************************************************
306 * UpdateWindow (USER.124)
308 void UpdateWindow( HWND hwnd
)
310 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
314 /***********************************************************************
315 * InvalidateRgn (USER.126)
317 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
319 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
323 /***********************************************************************
324 * InvalidateRect (USER.125)
326 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
328 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
332 /***********************************************************************
333 * ValidateRgn (USER.128)
335 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
337 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
341 /***********************************************************************
342 * ValidateRect (USER.127)
344 void ValidateRect( HWND hwnd
, LPRECT rect
)
346 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
350 /***********************************************************************
351 * GetUpdateRect (USER.190)
353 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
355 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
356 if (!wndPtr
) return FALSE
;
360 if (wndPtr
->hrgnUpdate
)
362 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
363 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
364 GetRgnBox( hrgn
, rect
);
365 DeleteObject( hrgn
);
367 else SetRectEmpty( rect
);
369 return (wndPtr
->hrgnUpdate
!= 0);
373 /***********************************************************************
374 * GetUpdateRgn (USER.237)
376 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
379 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
380 if (!wndPtr
) return ERROR
;
382 if (!wndPtr
->hrgnUpdate
)
384 SetRectRgn( hrgn
, 0, 0, 0, 0 );
387 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
388 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
393 /***********************************************************************
394 * ExcludeUpdateRgn (USER.238)
396 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
402 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
403 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
405 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
406 wndPtr
->hrgnUpdate
, RGN_DIFF
);
407 if (retval
) SelectVisRgn( hdc
, hrgn
);
408 DeleteObject( hrgn
);