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 );