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 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 ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
98 if (!hwndParent
) return;
100 hbrush
= (HBRUSH
)SendMessage( hwndParent
,
101 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
102 (WPARAM
)hdc
, (LPARAM
)hwnd
);
104 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
105 hdc
, MAKELONG( hwnd
, hbrush
) );
108 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
112 /***********************************************************************
113 * GetControlBrush (USER.326)
115 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
118 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
+control
,
119 (WPARAM
)hdc
, (LPARAM
)hwnd
);
121 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
,
122 hdc
, MAKELONG( hwnd
, control
) );
127 /***********************************************************************
128 * RedrawWindow (USER.290)
130 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
136 if (!hwnd
) hwnd
= GetDesktopWindow();
137 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
138 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
139 return TRUE
; /* No redraw needed */
143 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" %d,%d-%d,%d "NPFMT
" flags=%04x\n",
144 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
145 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
149 dprintf_win( stddeb
, "RedrawWindow: "NPFMT
" NULL "NPFMT
" flags=%04x\n",
150 hwnd
, hrgnUpdate
, flags
);
152 GetClientRect( hwnd
, &rectClient
);
154 if (flags
& RDW_INVALIDATE
) /* Invalidate */
156 if (wndPtr
->hrgnUpdate
) /* Is there already an update region? */
158 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
159 if ((hrgn
= hrgnUpdate
) == 0)
160 hrgn
= CreateRectRgnIndirect( rectUpdate
? rectUpdate
:
162 CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
163 DeleteObject( wndPtr
->hrgnUpdate
);
164 wndPtr
->hrgnUpdate
= tmpRgn
;
165 if (!hrgnUpdate
) DeleteObject( hrgn
);
167 else /* No update region yet */
169 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
170 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
173 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
174 CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
176 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect( rectUpdate
?
177 rectUpdate
: &rectClient
);
179 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
180 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
181 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
183 else if (flags
& RDW_VALIDATE
) /* Validate */
185 /* We need an update region in order to validate anything */
186 if (wndPtr
->hrgnUpdate
)
188 if (!hrgnUpdate
&& !rectUpdate
)
190 /* Special case: validate everything */
191 DeleteObject( wndPtr
->hrgnUpdate
);
192 wndPtr
->hrgnUpdate
= 0;
196 tmpRgn
= CreateRectRgn( 0, 0, 0, 0 );
197 if ((hrgn
= hrgnUpdate
) == 0)
198 hrgn
= CreateRectRgnIndirect( rectUpdate
);
199 if (CombineRgn( tmpRgn
, wndPtr
->hrgnUpdate
,
200 hrgn
, RGN_DIFF
) == NULLREGION
)
202 DeleteObject( tmpRgn
);
205 DeleteObject( wndPtr
->hrgnUpdate
);
206 wndPtr
->hrgnUpdate
= tmpRgn
;
207 if (!hrgnUpdate
) DeleteObject( hrgn
);
209 if (!wndPtr
->hrgnUpdate
) /* No more update region */
210 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
211 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
213 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
214 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
217 /* Set/clear internal paint flag */
219 if (flags
& RDW_INTERNALPAINT
)
221 if (!wndPtr
->hrgnUpdate
&& !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
222 MSG_IncPaintCount( wndPtr
->hmemTaskQ
);
223 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
225 else if (flags
& RDW_NOINTERNALPAINT
)
227 if (!wndPtr
->hrgnUpdate
&& (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
228 MSG_DecPaintCount( wndPtr
->hmemTaskQ
);
229 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
232 /* Erase/update window */
234 if (flags
& RDW_UPDATENOW
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
235 else if (flags
& RDW_ERASENOW
)
237 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
239 wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
240 SendMessage( hwnd
, WM_NCPAINT
, 0, 0 );
242 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
244 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
245 DCX_INTERSECTRGN
| DCX_USESTYLE
);
248 /* Don't send WM_ERASEBKGND to icons */
249 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
250 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
)
251 || !WIN_CLASS_INFO(wndPtr
).hIcon
)
253 if (SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
254 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
256 ReleaseDC( hwnd
, hdc
);
261 /* Recursively process children */
263 if (!(flags
& RDW_NOCHILDREN
) &&
264 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
268 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
269 if (!hrgn
) return TRUE
;
270 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
272 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
273 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
274 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
275 -wndPtr
->rectClient
.top
);
276 RedrawWindow( hwnd
, NULL
, hrgn
, flags
);
278 DeleteObject( hrgn
);
283 for (hwnd
= wndPtr
->hwndChild
; (hwnd
); hwnd
= wndPtr
->hwndNext
)
285 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) break;
289 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
290 -wndPtr
->rectClient
.top
);
291 RedrawWindow( hwnd
, &rect
, 0, flags
);
293 else RedrawWindow( hwnd
, NULL
, 0, flags
);
301 /***********************************************************************
302 * UpdateWindow (USER.124)
304 void UpdateWindow( HWND hwnd
)
306 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
310 /***********************************************************************
311 * InvalidateRgn (USER.126)
313 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
315 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
319 /***********************************************************************
320 * InvalidateRect (USER.125)
322 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
324 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
328 /***********************************************************************
329 * ValidateRgn (USER.128)
331 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
333 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
337 /***********************************************************************
338 * ValidateRect (USER.127)
340 void ValidateRect( HWND hwnd
, LPRECT rect
)
342 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
346 /***********************************************************************
347 * GetUpdateRect (USER.190)
349 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
351 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
352 if (!wndPtr
) return FALSE
;
356 if (wndPtr
->hrgnUpdate
)
358 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
359 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
360 GetRgnBox( hrgn
, rect
);
361 DeleteObject( hrgn
);
363 else SetRectEmpty( rect
);
365 return (wndPtr
->hrgnUpdate
!= 0);
369 /***********************************************************************
370 * GetUpdateRgn (USER.237)
372 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
375 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
376 if (!wndPtr
) return ERROR
;
378 if (!wndPtr
->hrgnUpdate
)
380 SetRectRgn( hrgn
, 0, 0, 0, 0 );
383 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
384 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
389 /***********************************************************************
390 * ExcludeUpdateRgn (USER.238)
392 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
398 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
399 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
401 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
402 wndPtr
->hrgnUpdate
, RGN_DIFF
);
403 if (retval
) SelectVisRgn( hdc
, hrgn
);
404 DeleteObject( hrgn
);