2 * Window painting functions
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
15 /* #define DEBUG_WIN */
18 /* Last CTLCOLOR id */
19 #define CTLCOLOR_MAX CTLCOLOR_STATIC
21 /***********************************************************************
25 void WIN_UpdateNCArea(WND
* wnd
, BOOL bUpdate
)
30 dprintf_nonclient(stddeb
,"NCUpdate: hwnd %04x, hrgnUpdate %04x\n",
31 wnd
->hwndSelf
, wnd
->hrgnUpdate
);
33 /* desktop window doesn't have nonclient area */
34 if(wnd
== WIN_GetDesktop())
36 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
40 if( wnd
->hrgnUpdate
> 1 )
42 ClientToScreen16(wnd
->hwndSelf
, &pt
);
44 hClip
= CreateRectRgn( 0, 0, 0, 0 );
45 if (!CombineRgn(hClip
, wnd
->hrgnUpdate
, 0, RGN_COPY
) )
51 OffsetRgn(hClip
, pt
.x
, pt
.y
);
55 /* exclude non-client area from update region */
56 HRGN hrgn
= CreateRectRgn(0, 0, wnd
->rectClient
.right
- wnd
->rectClient
.left
,
57 wnd
->rectClient
.bottom
- wnd
->rectClient
.top
);
59 if (hrgn
&& (CombineRgn(wnd
->hrgnUpdate
, wnd
->hrgnUpdate
,
60 hrgn
, RGN_AND
) == NULLREGION
))
62 DeleteObject(wnd
->hrgnUpdate
);
70 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
72 if ((wnd
->hwndSelf
== GetActiveWindow()) &&
73 !(wnd
->flags
& WIN_NCACTIVATED
))
75 wnd
->flags
|= WIN_NCACTIVATED
;
76 if( hClip
> 1) DeleteObject(hClip
);
80 if (hClip
) SendMessage16( wnd
->hwndSelf
, WM_NCPAINT
, hClip
, 0L );
82 if (hClip
> 1) DeleteObject( hClip
);
86 /***********************************************************************
87 * BeginPaint16 (USER.39)
89 HDC16
BeginPaint16( HWND16 hwnd
, LPPAINTSTRUCT16 lps
)
92 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
93 if (!wndPtr
) return 0;
95 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
97 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
99 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
100 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
101 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
103 wndPtr
->hrgnUpdate
= 0;
104 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
108 dprintf_win(stddeb
,"hrgnUpdate = %04x, ", hrgnUpdate
);
110 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_WINDOWPAINT
| DCX_USESTYLE
);
112 dprintf_win(stddeb
,"hdc = %04x\n", lps
->hdc
);
114 /* pseudocode from "Internals" doesn't delete hrgnUpdate - yet another clue
115 that ReleaseDC should take care of it (hence DCX_KEEPCLIPRGN) */
119 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
123 GetRgnBox16( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
124 DPtoLP16( lps
->hdc
, (LPPOINT16
)&lps
->rcPaint
, 2 );
126 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
128 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
129 lps
->fErase
= !SendMessage16(hwnd
, WM_ERASEBKGND
, (WPARAM
)lps
->hdc
, 0);
131 else lps
->fErase
= TRUE
;
137 /***********************************************************************
138 * BeginPaint32 (USER32.9)
140 HDC32
BeginPaint32( HWND32 hwnd
, PAINTSTRUCT32
*lps
)
144 BeginPaint16( hwnd
, &ps
);
145 lps
->hdc
= (HDC32
)ps
.hdc
;
146 lps
->fErase
= ps
.fErase
;
147 lps
->rcPaint
.top
= ps
.rcPaint
.top
;
148 lps
->rcPaint
.left
= ps
.rcPaint
.left
;
149 lps
->rcPaint
.right
= ps
.rcPaint
.right
;
150 lps
->rcPaint
.bottom
= ps
.rcPaint
.bottom
;
151 lps
->fRestore
= ps
.fRestore
;
152 lps
->fIncUpdate
= ps
.fIncUpdate
;
157 /***********************************************************************
158 * EndPaint16 (USER.40)
160 BOOL16
EndPaint16( HWND16 hwnd
, const PAINTSTRUCT16
* lps
)
162 ReleaseDC( hwnd
, lps
->hdc
);
168 /***********************************************************************
169 * EndPaint32 (USER32.175)
171 BOOL32
EndPaint32( HWND32 hwnd
, const PAINTSTRUCT32
*lps
)
173 ReleaseDC( hwnd
, (HDC16
)lps
->hdc
);
179 /***********************************************************************
180 * FillWindow (USER.324)
182 void FillWindow( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
, HBRUSH16 hbrush
)
185 GetClientRect16( hwnd
, &rect
);
186 DPtoLP16( hdc
, (LPPOINT16
)&rect
, 2 );
187 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
191 /***********************************************************************
192 * PaintRect (USER.325)
194 void PaintRect( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
,
195 HBRUSH16 hbrush
, const RECT16
*rect
)
197 /* Send WM_CTLCOLOR message if needed */
199 if ((UINT32
)hbrush
<= CTLCOLOR_MAX
)
201 if (!hwndParent
) return;
202 hbrush
= (HBRUSH
)SendMessage32A( hwndParent
,
203 WM_CTLCOLORMSGBOX
+ (UINT32
)hbrush
,
204 (WPARAM
)hdc
, (LPARAM
)hwnd
);
206 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
210 /***********************************************************************
211 * GetControlBrush (USER.326)
213 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
215 return (HBRUSH
)SendMessage32A( GetParent(hwnd
), WM_CTLCOLOR
+control
,
216 (WPARAM
)hdc
, (LPARAM
)hwnd
);
220 /***********************************************************************
221 * RedrawWindow32 (USER32.425)
223 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
224 HRGN32 hrgnUpdate
, UINT32 flags
)
230 if (!hwnd
) hwnd
= GetDesktopWindow();
231 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
232 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
233 return TRUE
; /* No redraw needed */
237 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
238 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
239 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
243 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
244 hwnd
, hrgnUpdate
, flags
);
246 GetClientRect32( hwnd
, &rectClient
);
248 if (flags
& RDW_INVALIDATE
) /* Invalidate */
250 int rgnNotEmpty
= COMPLEXREGION
;
252 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
254 if ((hrgn
= hrgnUpdate
) == 0)
255 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
257 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
258 if (!hrgnUpdate
) DeleteObject( hrgn
);
260 else /* No update region yet */
262 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
263 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
266 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
267 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
269 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
270 rectUpdate
: &rectClient
);
273 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
275 /* check for bogus update region */
276 if ( rgnNotEmpty
== NULLREGION
)
278 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
279 DeleteObject(wndPtr
->hrgnUpdate
);
280 wndPtr
->hrgnUpdate
=0;
281 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
282 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
285 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
286 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
288 else if (flags
& RDW_VALIDATE
) /* Validate */
290 /* We need an update region in order to validate anything */
291 if (wndPtr
->hrgnUpdate
> 1)
293 if (!hrgnUpdate
&& !rectUpdate
)
295 /* Special case: validate everything */
296 DeleteObject( wndPtr
->hrgnUpdate
);
297 wndPtr
->hrgnUpdate
= 0;
301 if ((hrgn
= hrgnUpdate
) == 0)
302 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
303 if (CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
304 hrgn
, RGN_DIFF
) == NULLREGION
)
306 DeleteObject( wndPtr
->hrgnUpdate
);
307 wndPtr
->hrgnUpdate
= 0;
309 if (!hrgnUpdate
) DeleteObject( hrgn
);
311 if (!wndPtr
->hrgnUpdate
) /* No more update region */
312 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
313 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
315 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
316 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
319 /* Set/clear internal paint flag */
321 if (flags
& RDW_INTERNALPAINT
)
323 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
324 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
325 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
327 else if (flags
& RDW_NOINTERNALPAINT
)
329 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
330 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
331 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
334 /* Erase/update window */
336 if (flags
& RDW_UPDATENOW
)
338 if (wndPtr
->hrgnUpdate
) SendMessage16( hwnd
, WM_PAINT
, 0, 0 );
340 else if (flags
& RDW_ERASENOW
)
342 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
343 WIN_UpdateNCArea( wndPtr
, FALSE
);
345 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
347 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
348 DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
| DCX_WINDOWPAINT
);
351 /* Don't send WM_ERASEBKGND to icons */
352 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
353 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
) ||
354 !wndPtr
->class->hIcon
)
356 if (SendMessage16( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
357 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
359 ReleaseDC( hwnd
, hdc
);
364 /* Recursively process children */
366 if (!(flags
& RDW_NOCHILDREN
) &&
367 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
371 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
372 if (!hrgn
) return TRUE
;
373 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
375 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
376 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
377 -wndPtr
->rectClient
.top
);
378 RedrawWindow32( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
);
380 DeleteObject( hrgn
);
385 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
390 OffsetRect32( &rect
, -wndPtr
->rectClient
.left
,
391 -wndPtr
->rectClient
.top
);
392 RedrawWindow32( wndPtr
->hwndSelf
, &rect
, 0, flags
);
394 else RedrawWindow32( wndPtr
->hwndSelf
, NULL
, 0, flags
);
402 /***********************************************************************
403 * RedrawWindow16 (USER.290)
405 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
406 HRGN16 hrgnUpdate
, UINT16 flags
)
411 CONV_RECT16TO32( rectUpdate
, &r
);
412 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
414 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
418 /***********************************************************************
419 * UpdateWindow (USER.124) (USER32.566)
421 void UpdateWindow( HWND32 hwnd
)
423 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
427 /***********************************************************************
428 * InvalidateRgn (USER.126) (USER32.328)
430 void InvalidateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
432 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0));
436 /***********************************************************************
437 * InvalidateRect16 (USER.125)
439 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
441 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
445 /***********************************************************************
446 * InvalidateRect32 (USER32.327)
448 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
450 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
454 /***********************************************************************
455 * ValidateRgn (USER.128) (USER32.571)
457 void ValidateRgn( HWND32 hwnd
, HRGN32 hrgn
)
459 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
463 /***********************************************************************
464 * ValidateRect16 (USER.127)
466 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
468 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
472 /***********************************************************************
473 * ValidateRect32 (USER32.570)
475 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
477 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
481 /***********************************************************************
482 * GetUpdateRect16 (USER.190)
484 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
489 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
490 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
491 CONV_RECT32TO16( &r
, rect
);
496 /***********************************************************************
497 * GetUpdateRect32 (USER32.296)
499 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
501 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
502 if (!wndPtr
) return FALSE
;
506 if (wndPtr
->hrgnUpdate
> 1)
508 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
509 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
510 GetRgnBox32( hrgn
, rect
);
511 DeleteObject( hrgn
);
513 else SetRectEmpty32( rect
);
515 return (wndPtr
->hrgnUpdate
> 1);
519 /***********************************************************************
520 * GetUpdateRgn (USER.237) (USER32.297)
522 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
525 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
526 if (!wndPtr
) return ERROR
;
528 if (wndPtr
->hrgnUpdate
<= 1)
530 SetRectRgn( hrgn
, 0, 0, 0, 0 );
533 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
534 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
539 /***********************************************************************
540 * ExcludeUpdateRgn (USER.238) (USER32.194)
542 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
544 INT16 retval
= ERROR
;
548 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
549 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
551 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
552 (wndPtr
->hrgnUpdate
>1)?wndPtr
->hrgnUpdate
:0,
553 (wndPtr
->hrgnUpdate
>1)?RGN_DIFF
:RGN_COPY
);
554 if (retval
) SelectVisRgn( hdc
, hrgn
);
555 DeleteObject( hrgn
);