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
20 /***********************************************************************
24 void WIN_UpdateNCArea(WND
* wnd
, BOOL bUpdate
)
29 dprintf_nonclient(stddeb
,"NCUpdate: hwnd %04x, hrgnUpdate %04x\n",
30 wnd
->hwndSelf
, wnd
->hrgnUpdate
);
32 /* desktop window doesn't have nonclient area */
33 if(wnd
== WIN_GetDesktop())
35 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
39 if( wnd
->hrgnUpdate
> 1 )
41 ClientToScreen(wnd
->hwndSelf
, &pt
);
43 hClip
= CreateRectRgn( 0, 0, 0, 0 );
44 if (!CombineRgn(hClip
, wnd
->hrgnUpdate
, 0, RGN_COPY
) )
50 OffsetRgn(hClip
, pt
.x
, pt
.y
);
54 /* exclude non-client area from update region */
55 HRGN hrgn
= CreateRectRgn(0, 0, wnd
->rectClient
.right
- wnd
->rectClient
.left
,
56 wnd
->rectClient
.bottom
- wnd
->rectClient
.top
);
58 if (hrgn
&& (CombineRgn(wnd
->hrgnUpdate
, wnd
->hrgnUpdate
,
59 hrgn
, RGN_AND
) == NULLREGION
))
61 DeleteObject(wnd
->hrgnUpdate
);
69 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
71 if ((wnd
->hwndSelf
== GetActiveWindow()) &&
72 !(wnd
->flags
& WIN_NCACTIVATED
))
74 wnd
->flags
|= WIN_NCACTIVATED
;
75 if( hClip
> 1) DeleteObject(hClip
);
79 if (hClip
) SendMessage( wnd
->hwndSelf
, WM_NCPAINT
, hClip
, 0L );
81 if (hClip
> 1) DeleteObject( hClip
);
85 /***********************************************************************
86 * BeginPaint (USER.39)
88 HDC
BeginPaint( HWND hwnd
, LPPAINTSTRUCT lps
)
91 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
92 if (!wndPtr
) return 0;
94 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
96 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
98 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
99 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
100 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
102 wndPtr
->hrgnUpdate
= 0;
103 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
107 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
108 if(hrgnUpdate
> 1) DeleteObject( hrgnUpdate
);
112 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
116 GetRgnBox( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
117 DPtoLP( lps
->hdc
, (LPPOINT
)&lps
->rcPaint
, 2 );
119 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
121 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
122 lps
->fErase
= !SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)lps
->hdc
, 0 );
124 else lps
->fErase
= TRUE
;
130 /***********************************************************************
133 BOOL
EndPaint( HWND hwnd
, const PAINTSTRUCT
* lps
)
135 ReleaseDC( hwnd
, lps
->hdc
);
141 /***********************************************************************
142 * FillWindow (USER.324)
144 void FillWindow( HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
)
147 GetClientRect( hwnd
, &rect
);
148 DPtoLP( hdc
, (LPPOINT
)&rect
, 2 );
149 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
153 /***********************************************************************
154 * PaintRect (USER.325)
156 void PaintRect(HWND hwndParent
, HWND hwnd
, HDC hdc
, HBRUSH hbrush
, LPRECT rect
)
158 /* Send WM_CTLCOLOR message if needed */
160 if ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
162 if (!hwndParent
) return;
164 hbrush
= (HBRUSH
)SendMessage( hwndParent
,
165 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
166 (WPARAM
)hdc
, (LPARAM
)hwnd
);
168 hbrush
= (HBRUSH
)SendMessage( hwndParent
, WM_CTLCOLOR
,
169 hdc
, MAKELONG( hwnd
, hbrush
) );
172 if (hbrush
) FillRect( hdc
, rect
, hbrush
);
176 /***********************************************************************
177 * GetControlBrush (USER.326)
179 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
182 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
+control
,
183 (WPARAM
)hdc
, (LPARAM
)hwnd
);
185 return (HBRUSH
)SendMessage( GetParent(hwnd
), WM_CTLCOLOR
,
186 hdc
, MAKELONG( hwnd
, control
) );
191 /***********************************************************************
192 * RedrawWindow (USER.290)
194 BOOL
RedrawWindow( HWND hwnd
, LPRECT rectUpdate
, HRGN hrgnUpdate
, UINT flags
)
200 if (!hwnd
) hwnd
= GetDesktopWindow();
201 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
202 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
203 return TRUE
; /* No redraw needed */
207 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
208 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
209 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
213 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
214 hwnd
, hrgnUpdate
, flags
);
216 GetClientRect( hwnd
, &rectClient
);
218 if (flags
& RDW_INVALIDATE
) /* Invalidate */
220 int rgnNotEmpty
= COMPLEXREGION
;
222 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
224 if ((hrgn
= hrgnUpdate
) == 0)
225 hrgn
= CreateRectRgnIndirect( rectUpdate
? rectUpdate
:
227 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
228 if (!hrgnUpdate
) DeleteObject( hrgn
);
230 else /* No update region yet */
232 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
233 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
236 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
237 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
239 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect( rectUpdate
?
240 rectUpdate
: &rectClient
);
243 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
245 /* check for bogus update region */
246 if ( rgnNotEmpty
== NULLREGION
)
248 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
249 DeleteObject(wndPtr
->hrgnUpdate
);
250 wndPtr
->hrgnUpdate
=0;
251 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
252 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
255 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
256 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
258 else if (flags
& RDW_VALIDATE
) /* Validate */
260 /* We need an update region in order to validate anything */
261 if (wndPtr
->hrgnUpdate
> 1)
263 if (!hrgnUpdate
&& !rectUpdate
)
265 /* Special case: validate everything */
266 DeleteObject( wndPtr
->hrgnUpdate
);
267 wndPtr
->hrgnUpdate
= 0;
271 if ((hrgn
= hrgnUpdate
) == 0)
272 hrgn
= CreateRectRgnIndirect( rectUpdate
);
273 if (CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
274 hrgn
, RGN_DIFF
) == NULLREGION
)
276 DeleteObject( wndPtr
->hrgnUpdate
);
277 wndPtr
->hrgnUpdate
= 0;
279 if (!hrgnUpdate
) DeleteObject( hrgn
);
281 if (!wndPtr
->hrgnUpdate
) /* No more update region */
282 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
283 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
285 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
286 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
289 /* Set/clear internal paint flag */
291 if (flags
& RDW_INTERNALPAINT
)
293 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
294 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
295 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
297 else if (flags
& RDW_NOINTERNALPAINT
)
299 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
300 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
301 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
304 /* Erase/update window */
306 if (flags
& RDW_UPDATENOW
)
308 if (wndPtr
->hrgnUpdate
) SendMessage( hwnd
, WM_PAINT
, 0, 0 );
310 else if (flags
& RDW_ERASENOW
)
312 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
313 WIN_UpdateNCArea( wndPtr
, FALSE
);
315 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
317 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
318 DCX_INTERSECTRGN
| DCX_USESTYLE
);
321 /* Don't send WM_ERASEBKGND to icons */
322 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
323 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
) ||
324 !wndPtr
->class->hIcon
)
326 if (SendMessage( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
327 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
329 ReleaseDC( hwnd
, hdc
);
334 /* Recursively process children */
336 if (!(flags
& RDW_NOCHILDREN
) &&
337 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
341 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
342 if (!hrgn
) return TRUE
;
343 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
345 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
346 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
347 -wndPtr
->rectClient
.top
);
348 RedrawWindow( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
);
350 DeleteObject( hrgn
);
355 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
360 OffsetRect( &rect
, -wndPtr
->rectClient
.left
,
361 -wndPtr
->rectClient
.top
);
362 RedrawWindow( wndPtr
->hwndSelf
, &rect
, 0, flags
);
364 else RedrawWindow( wndPtr
->hwndSelf
, NULL
, 0, flags
);
372 /***********************************************************************
373 * UpdateWindow (USER.124)
375 void UpdateWindow( HWND hwnd
)
377 RedrawWindow( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
381 /***********************************************************************
382 * InvalidateRgn (USER.126)
384 void InvalidateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
386 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
390 /***********************************************************************
391 * InvalidateRect (USER.125)
393 void InvalidateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
395 RedrawWindow( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
399 /***********************************************************************
400 * ValidateRgn (USER.128)
402 void ValidateRgn( HWND hwnd
, HRGN hrgn
)
404 RedrawWindow( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
408 /***********************************************************************
409 * ValidateRect (USER.127)
411 void ValidateRect( HWND hwnd
, LPRECT rect
)
413 RedrawWindow( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
417 /***********************************************************************
418 * GetUpdateRect (USER.190)
420 BOOL
GetUpdateRect( HWND hwnd
, LPRECT rect
, BOOL erase
)
422 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
423 if (!wndPtr
) return FALSE
;
427 if (wndPtr
->hrgnUpdate
> 1)
429 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
430 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
431 GetRgnBox( hrgn
, rect
);
432 DeleteObject( hrgn
);
434 else SetRectEmpty( rect
);
436 return (wndPtr
->hrgnUpdate
> 1);
440 /***********************************************************************
441 * GetUpdateRgn (USER.237)
443 int GetUpdateRgn( HWND hwnd
, HRGN hrgn
, BOOL erase
)
446 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
447 if (!wndPtr
) return ERROR
;
449 if (wndPtr
->hrgnUpdate
<= 1)
451 SetRectRgn( hrgn
, 0, 0, 0, 0 );
454 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
455 if (erase
) RedrawWindow( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
460 /***********************************************************************
461 * ExcludeUpdateRgn (USER.238)
463 int ExcludeUpdateRgn( HDC hdc
, HWND hwnd
)
469 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
470 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
472 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
473 (wndPtr
->hrgnUpdate
>1)?wndPtr
->hrgnUpdate
:0,
474 (wndPtr
->hrgnUpdate
>1)?RGN_DIFF
:RGN_COPY
);
475 if (retval
) SelectVisRgn( hdc
, hrgn
);
476 DeleteObject( hrgn
);