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 HRGN32 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
)
93 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
94 if (!wndPtr
) return 0;
96 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
98 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
100 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
102 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
103 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
104 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
106 wndPtr
->hrgnUpdate
= 0;
107 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
111 dprintf_win(stddeb
,"hrgnUpdate = %04x, ", hrgnUpdate
);
113 /* When bIcon is TRUE hrgnUpdate is automatically in window coordinates
114 * (because rectClient == rectWindow for WS_MINIMIZE windows).
117 lps
->hdc
= GetDCEx16(hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_WINDOWPAINT
|
118 DCX_USESTYLE
| (bIcon
? DCX_WINDOW
: 0) );
120 dprintf_win(stddeb
,"hdc = %04x\n", lps
->hdc
);
124 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
128 GetRgnBox16( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
129 DPtoLP16( lps
->hdc
, (LPPOINT16
)&lps
->rcPaint
, 2 );
131 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
133 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
134 lps
->fErase
= !SendMessage16(hwnd
, (bIcon
) ? WM_ICONERASEBKGND
136 (WPARAM16
)lps
->hdc
, 0 );
138 else lps
->fErase
= TRUE
;
144 /***********************************************************************
145 * BeginPaint32 (USER32.9)
147 HDC32
BeginPaint32( HWND32 hwnd
, PAINTSTRUCT32
*lps
)
151 BeginPaint16( hwnd
, &ps
);
152 lps
->hdc
= (HDC32
)ps
.hdc
;
153 lps
->fErase
= ps
.fErase
;
154 lps
->rcPaint
.top
= ps
.rcPaint
.top
;
155 lps
->rcPaint
.left
= ps
.rcPaint
.left
;
156 lps
->rcPaint
.right
= ps
.rcPaint
.right
;
157 lps
->rcPaint
.bottom
= ps
.rcPaint
.bottom
;
158 lps
->fRestore
= ps
.fRestore
;
159 lps
->fIncUpdate
= ps
.fIncUpdate
;
164 /***********************************************************************
165 * EndPaint16 (USER.40)
167 BOOL16
EndPaint16( HWND16 hwnd
, const PAINTSTRUCT16
* lps
)
169 ReleaseDC16( hwnd
, lps
->hdc
);
175 /***********************************************************************
176 * EndPaint32 (USER32.175)
178 BOOL32
EndPaint32( HWND32 hwnd
, const PAINTSTRUCT32
*lps
)
180 ReleaseDC32( hwnd
, lps
->hdc
);
186 /***********************************************************************
187 * FillWindow (USER.324)
189 void FillWindow( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
, HBRUSH16 hbrush
)
192 GetClientRect16( hwnd
, &rect
);
193 DPtoLP16( hdc
, (LPPOINT16
)&rect
, 2 );
194 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
198 /***********************************************************************
199 * PaintRect (USER.325)
201 void PaintRect( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
,
202 HBRUSH16 hbrush
, const RECT16
*rect
)
204 /* Send WM_CTLCOLOR message if needed */
206 if ((UINT32
)hbrush
<= CTLCOLOR_MAX
)
208 if (!hwndParent
) return;
209 hbrush
= (HBRUSH16
)SendMessage32A( hwndParent
,
210 WM_CTLCOLORMSGBOX
+ (UINT32
)hbrush
,
211 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
213 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
217 /***********************************************************************
218 * GetControlBrush (USER.326)
220 HBRUSH16
GetControlBrush( HWND hwnd
, HDC16 hdc
, WORD control
)
222 return (HBRUSH16
)SendMessage32A( GetParent32(hwnd
), WM_CTLCOLOR
+control
,
223 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
227 /***********************************************************************
230 * Note: Windows uses WM_SYNCPAINT to cut down the number of intertask
231 * SendMessage() calls. From SDK:
232 * This message avoids lots of inter-app message traffic
233 * by switching to the other task and continuing the
237 * LOWORD(lParam) = hrgnClip
238 * HIWORD(lParam) = hwndSkip (not used; always NULL)
240 BOOL32
PAINT_RedrawWindow( HWND32 hwnd
, const RECT32
*rectUpdate
,
241 HRGN32 hrgnUpdate
, UINT32 flags
, UINT32 control
)
248 if (!hwnd
) hwnd
= GetDesktopWindow32();
249 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
250 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
251 return TRUE
; /* No redraw needed */
253 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
256 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
257 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
258 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
262 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
263 hwnd
, hrgnUpdate
, flags
);
266 if (wndPtr
->class->style
& CS_PARENTDC
)
268 GetClientRect32( wndPtr
->parent
->hwndSelf
, &rectClient
);
269 OffsetRect32( &rectClient
, -wndPtr
->rectClient
.left
,
270 -wndPtr
->rectClient
.top
);
272 else GetClientRect32( hwnd
, &rectClient
);
274 if (flags
& RDW_INVALIDATE
) /* Invalidate */
276 int rgnNotEmpty
= COMPLEXREGION
;
278 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
280 if ((hrgn
= hrgnUpdate
) == 0)
281 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
283 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
284 if (!hrgnUpdate
) DeleteObject( hrgn
);
286 else /* No update region yet */
288 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
289 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
292 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
293 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
295 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
296 rectUpdate
: &rectClient
);
299 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
301 /* check for bogus update region */
302 if ( rgnNotEmpty
== NULLREGION
)
304 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
305 DeleteObject(wndPtr
->hrgnUpdate
);
306 wndPtr
->hrgnUpdate
=0;
307 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
308 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
311 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
312 flags
|= RDW_FRAME
; /* Force children frame invalidation */
314 else if (flags
& RDW_VALIDATE
) /* Validate */
316 /* We need an update region in order to validate anything */
317 if (wndPtr
->hrgnUpdate
> 1)
319 if (!hrgnUpdate
&& !rectUpdate
)
321 /* Special case: validate everything */
322 DeleteObject( wndPtr
->hrgnUpdate
);
323 wndPtr
->hrgnUpdate
= 0;
327 if ((hrgn
= hrgnUpdate
) == 0)
328 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
329 if (CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
330 hrgn
, RGN_DIFF
) == NULLREGION
)
332 DeleteObject( wndPtr
->hrgnUpdate
);
333 wndPtr
->hrgnUpdate
= 0;
335 if (!hrgnUpdate
) DeleteObject( hrgn
);
337 if (!wndPtr
->hrgnUpdate
) /* No more update region */
338 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
339 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
341 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
342 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
345 /* Set/clear internal paint flag */
347 if (flags
& RDW_INTERNALPAINT
)
349 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
350 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
351 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
353 else if (flags
& RDW_NOINTERNALPAINT
)
355 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
356 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
357 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
360 /* Erase/update window */
362 if (flags
& RDW_UPDATENOW
)
364 if (wndPtr
->hrgnUpdate
) /* wm_painticon wparam is 1 */
365 SendMessage16( hwnd
, (bIcon
) ? WM_PAINTICON
: WM_PAINT
, bIcon
, 0 );
367 else if (flags
& RDW_ERASENOW
)
369 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
370 WIN_UpdateNCArea( wndPtr
, FALSE
);
372 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
374 HDC32 hdc
= GetDCEx32( hwnd
, wndPtr
->hrgnUpdate
,
375 DCX_INTERSECTRGN
| DCX_USESTYLE
|
376 DCX_KEEPCLIPRGN
| DCX_WINDOWPAINT
|
377 (bIcon
? DCX_WINDOW
: 0) );
380 if (SendMessage16( hwnd
, (bIcon
) ? WM_ICONERASEBKGND
383 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
384 ReleaseDC32( hwnd
, hdc
);
389 /* Recursively process children */
391 if (!(flags
& RDW_NOCHILDREN
) &&
392 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)) &&
393 !(wndPtr
->dwStyle
& WS_MINIMIZE
) )
395 if ( hrgnUpdate
|| rectUpdate
)
397 if( !(hrgn
= CreateRectRgn( 0, 0, 0, 0 )) ) return TRUE
;
400 control
|= (RDW_C_DELETEHRGN
| RDW_C_USEHRGN
);
401 if( !(hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
)) )
403 DeleteObject( hrgn
);
407 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
408 if( wndPtr
->dwStyle
& WS_VISIBLE
)
410 if (wndPtr
->class->style
& CS_PARENTDC
)
412 if (!CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
))
417 SetRectRgn( hrgn
, wndPtr
->rectWindow
.left
,
418 wndPtr
->rectWindow
.top
,
419 wndPtr
->rectWindow
.right
,
420 wndPtr
->rectWindow
.bottom
);
421 if (!CombineRgn( hrgn
, hrgn
, hrgnUpdate
, RGN_AND
))
425 if( control
& RDW_C_USEHRGN
&&
426 wndPtr
->dwStyle
& WS_CLIPSIBLINGS
)
427 CombineRgn( hrgnUpdate
, hrgnUpdate
, hrgn
, RGN_DIFF
);
430 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
431 -wndPtr
->rectClient
.top
);
432 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
, RDW_C_USEHRGN
);
434 DeleteObject( hrgn
);
435 if( control
& RDW_C_DELETEHRGN
) DeleteObject( hrgnUpdate
);
437 else for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
438 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, 0, flags
, 0 );
445 /***********************************************************************
446 * RedrawWindow32 (USER32.425)
448 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
449 HRGN32 hrgnUpdate
, UINT32 flags
)
451 WND
* wnd
= WIN_FindWndPtr( hwnd
);
453 /* check if there is something to redraw */
455 return ( wnd
&& WIN_IsWindowDrawable( wnd
, !(flags
& RDW_FRAME
) ) )
456 ? PAINT_RedrawWindow( hwnd
, rectUpdate
, hrgnUpdate
, flags
, 0 )
461 /***********************************************************************
462 * RedrawWindow16 (USER.290)
464 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
465 HRGN16 hrgnUpdate
, UINT16 flags
)
470 CONV_RECT16TO32( rectUpdate
, &r
);
471 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
473 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
477 /***********************************************************************
478 * UpdateWindow (USER.124) (USER32.566)
480 void UpdateWindow( HWND32 hwnd
)
482 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
486 /***********************************************************************
487 * InvalidateRgn (USER.126) (USER32.328)
489 void InvalidateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
491 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
495 /***********************************************************************
496 * InvalidateRect16 (USER.125)
498 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
500 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
504 /***********************************************************************
505 * InvalidateRect32 (USER32.327)
507 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
509 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
513 /***********************************************************************
514 * ValidateRgn (USER.128) (USER32.571)
516 void ValidateRgn( HWND32 hwnd
, HRGN32 hrgn
)
518 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
522 /***********************************************************************
523 * ValidateRect16 (USER.127)
525 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
527 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
531 /***********************************************************************
532 * ValidateRect32 (USER32.570)
534 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
536 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
540 /***********************************************************************
541 * GetUpdateRect16 (USER.190)
543 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
548 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
549 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
550 CONV_RECT32TO16( &r
, rect
);
555 /***********************************************************************
556 * GetUpdateRect32 (USER32.296)
558 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
560 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
561 if (!wndPtr
) return FALSE
;
565 if (wndPtr
->hrgnUpdate
> 1)
567 HRGN32 hrgn
= CreateRectRgn( 0, 0, 0, 0 );
568 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
569 GetRgnBox32( hrgn
, rect
);
570 DeleteObject( hrgn
);
572 else SetRectEmpty32( rect
);
574 return (wndPtr
->hrgnUpdate
> 1);
578 /***********************************************************************
579 * GetUpdateRgn (USER.237) (USER32.297)
581 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
584 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
585 if (!wndPtr
) return ERROR
;
587 if (wndPtr
->hrgnUpdate
<= 1)
589 SetRectRgn( hrgn
, 0, 0, 0, 0 );
592 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
593 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
598 /***********************************************************************
599 * ExcludeUpdateRgn (USER.238) (USER32.194)
601 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
603 INT16 retval
= ERROR
;
607 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
608 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
610 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
611 (wndPtr
->hrgnUpdate
>1)?wndPtr
->hrgnUpdate
:0,
612 (wndPtr
->hrgnUpdate
>1)?RGN_DIFF
:RGN_COPY
);
613 if (retval
) SelectVisRgn( hdc
, hrgn
);
614 DeleteObject( hrgn
);