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 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
43 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
46 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
47 DeleteObject( hrgnUpdate
);
50 fprintf( stderr
, "GetDCEx() failed in BeginPaint(), hwnd="NPFMT
"\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 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
60 lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)lps
->hdc
, 0 );
62 else lps
->fErase
= TRUE
;
68 /***********************************************************************
71 BOOL
EndPaint( HWND hwnd
, const PAINTSTRUCT
* lps
)
73 ReleaseDC( hwnd
, lps
->hdc
);
78 /***********************************************************************
79 * FillWindow (USER.324)
81 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
84 GetClientRect( hwnd
, &rect
);
85 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
86 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
90 /***********************************************************************
91 * PaintRect (USER.325)
93 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
95 /* Send WM_CTLCOLOR message if needed */
97 if ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
99 if (!hwndParent
) return;
101 hbrush
= (HBRUSH
)SendMessage( hwndParent
,
102 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
103 (WPARAM
)hdc
, (LPARAM
)hwnd
);
105 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
106 hdc
, MAKELONG( hwnd
, hbrush
) );
109 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
113 /***********************************************************************
114 * GetControlBrush (USER.326)
116 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
119 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
+control
,
120 (WPARAM
)hdc
, (LPARAM
)hwnd
);
122 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
,
123 hdc
, MAKELONG( hwnd
, control
) );
128 /***********************************************************************
129 * RedrawWindow (USER.290)
131 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
137 if (!hwnd
) hwnd
= GetDesktopWindow();
138 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
139 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
140 return TRUE
; /* No redraw needed */
144 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" %ld,%ld-%ld,%ld "NPFMT
" flags=%04x\n",
145 hwnd
, (LONG
)rectUpdate
->left
, (LONG
)rectUpdate
->top
,
146 (LONG
)rectUpdate
->right
, (LONG
)rectUpdate
->bottom
, hrgnUpdate
, flags
);
150 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" NULL "NPFMT
" flags=%04x\n",
151 hwnd
, hrgnUpdate
, flags
);
153 GetClientRect( hwnd
, &rectClient
);
155 if (flags
& RDW_INVALIDATE
) /* Invalidate */
157 if (wndPtr
->hrgnUpdate
) /* Is there already an update region? */
159 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
160 if ((hrgn
= hrgnUpdate
) == 0)
161 hrgn
= CreateRectRgnIndirect( rectUpdate
? rectUpdate
:
163 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
164 DeleteObject( wndPtr
->hrgnUpdate
);
165 wndPtr
->hrgnUpdate
= tmpRgn
;
166 if (!hrgnUpdate
) DeleteObject( hrgn
);
168 else /* No update region yet */
170 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
171 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
174 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
175 CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
177 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect( rectUpdate
?
178 rectUpdate
: &rectClient
);
180 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
181 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
182 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
184 else if (flags
& RDW_VALIDATE
) /* Validate */
186 /* We need an update region in order to validate anything */
187 if (wndPtr
->hrgnUpdate
)
189 if (!hrgnUpdate
&& !rectUpdate
)
191 /* Special case: validate everything */
192 DeleteObject( wndPtr
->hrgnUpdate
);
193 wndPtr
->hrgnUpdate
= 0;
197 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
198 if ((hrgn
= hrgnUpdate
) == 0)
199 hrgn
= CreateRectRgnIndirect( rectUpdate
);
200 if (CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
,
201 hrgn
, RGN_DIFF
) == NULLREGION
)
203 DeleteObject( tmpRgn
);
206 DeleteObject( wndPtr
->hrgnUpdate
);
207 wndPtr
->hrgnUpdate
= tmpRgn
;
208 if (!hrgnUpdate
) DeleteObject( hrgn
);
210 if (!wndPtr
->hrgnUpdate
) /* No more update region */
211 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
212 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
214 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
215 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
218 /* Set/clear internal paint flag */
220 if (flags
& RDW_INTERNALPAINT
)
222 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
223 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
224 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
226 else if (flags
& RDW_NOINTERNALPAINT
)
228 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
229 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
230 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
233 /* Erase/update window */
235 if (flags
& RDW_UPDATENOW
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
236 else if (flags
& RDW_ERASENOW
)
238 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
240 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
241 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
243 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
245 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
246 DCX_INTERSECTRGN
| DCX_USESTYLE
);
249 /* Don't send WM_ERASEBKGND to icons */
250 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
251 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
252 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
254 if (SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
255 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
257 ReleaseDC( hwnd
, hdc
);
262 /* Recursively process children */
264 if (!(flags
& RDW_NOCHILDREN
) &&
265 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
269 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
270 if (!hrgn
) return TRUE
;
271 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
273 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
274 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
275 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
276 -wndPtr
->rectClient
.top
);
277 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
279 DeleteObject( hrgn
);
284 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
286 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
290 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
291 -wndPtr
->rectClient
.top
);
292 RedrawWindow( hwnd
, &rect
, 0, flags
);
294 else RedrawWindow( hwnd
, NULL
, 0, flags
);
302 /***********************************************************************
303 * UpdateWindow (USER.124)
305 void UpdateWindow( HWND hwnd
)
307 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
311 /***********************************************************************
312 * InvalidateRgn (USER.126)
314 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
316 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
320 /***********************************************************************
321 * InvalidateRect (USER.125)
323 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
325 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
329 /***********************************************************************
330 * ValidateRgn (USER.128)
332 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
334 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
338 /***********************************************************************
339 * ValidateRect (USER.127)
341 void ValidateRect( HWND hwnd
, LPRECT rect
)
343 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
347 /***********************************************************************
348 * GetUpdateRect (USER.190)
350 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
352 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
353 if (!wndPtr
) return FALSE
;
357 if (wndPtr
->hrgnUpdate
)
359 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
360 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
361 GetRgnBox( hrgn
, rect
);
362 DeleteObject( hrgn
);
364 else SetRectEmpty( rect
);
366 return (wndPtr
->hrgnUpdate
!= 0);
370 /***********************************************************************
371 * GetUpdateRgn (USER.237)
373 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
376 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
377 if (!wndPtr
) return ERROR
;
379 if (!wndPtr
->hrgnUpdate
)
381 SetRectRgn( hrgn
, 0, 0, 0, 0 );
384 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
385 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
390 /***********************************************************************
391 * ExcludeUpdateRgn (USER.238)
393 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
399 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
400 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
402 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
403 wndPtr
->hrgnUpdate
, RGN_DIFF
);
404 if (retval
) SelectVisRgn( hdc
, hrgn
);
405 DeleteObject( hrgn
);