2 * Window painting functions
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
16 /* #define DEBUG_WIN */
19 /* Last CTLCOLOR id */
20 #define CTLCOLOR_MAX CTLCOLOR_STATIC
22 /***********************************************************************
26 void WIN_UpdateNCArea(WND
* wnd
, BOOL bUpdate
)
31 dprintf_nonclient(stddeb
,"NCUpdate: hwnd %04x, hrgnUpdate %04x\n",
32 wnd
->hwndSelf
, wnd
->hrgnUpdate
);
34 /* desktop window doesn't have nonclient area */
35 if(wnd
== WIN_GetDesktop())
37 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
41 if( wnd
->hrgnUpdate
> 1 )
43 ClientToScreen16(wnd
->hwndSelf
, &pt
);
45 hClip
= CreateRectRgn32( 0, 0, 0, 0 );
46 if (!CombineRgn32( hClip
, wnd
->hrgnUpdate
, 0, RGN_COPY
))
48 DeleteObject32(hClip
);
52 OffsetRgn32( hClip
, pt
.x
, pt
.y
);
56 /* exclude non-client area from update region */
57 HRGN32 hrgn
= CreateRectRgn32( 0, 0,
58 wnd
->rectClient
.right
- wnd
->rectClient
.left
,
59 wnd
->rectClient
.bottom
- wnd
->rectClient
.top
);
61 if (hrgn
&& (CombineRgn32( wnd
->hrgnUpdate
, wnd
->hrgnUpdate
,
62 hrgn
, RGN_AND
) == NULLREGION
))
64 DeleteObject32( wnd
->hrgnUpdate
);
68 DeleteObject32( hrgn
);
72 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
74 if ((wnd
->hwndSelf
== GetActiveWindow32()) &&
75 !(wnd
->flags
& WIN_NCACTIVATED
))
77 wnd
->flags
|= WIN_NCACTIVATED
;
78 if( hClip
> 1) DeleteObject32( hClip
);
82 if (hClip
) SendMessage16( wnd
->hwndSelf
, WM_NCPAINT
, hClip
, 0L );
84 if (hClip
> 1) DeleteObject32( hClip
);
88 /***********************************************************************
89 * BeginPaint16 (USER.39)
91 HDC16
BeginPaint16( HWND16 hwnd
, LPPAINTSTRUCT16 lps
)
95 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
96 if (!wndPtr
) return 0;
98 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
100 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
102 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
104 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
105 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
106 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
108 wndPtr
->hrgnUpdate
= 0;
109 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
113 dprintf_win(stddeb
,"hrgnUpdate = %04x, ", hrgnUpdate
);
115 /* When bIcon is TRUE hrgnUpdate is automatically in window coordinates
116 * (because rectClient == rectWindow for WS_MINIMIZE windows).
119 if (wndPtr
->class->style
& CS_PARENTDC
)
120 /* Don't clip the output to the update region for CS_PARENTDC window */
121 lps
->hdc
= GetDCEx16( hwnd
, 0, DCX_WINDOWPAINT
| DCX_USESTYLE
|
122 (bIcon
? DCX_WINDOW
: 0) );
124 lps
->hdc
= GetDCEx16(hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
|
125 DCX_WINDOWPAINT
| DCX_USESTYLE
|
126 (bIcon
? DCX_WINDOW
: 0) );
128 dprintf_win(stddeb
,"hdc = %04x\n", lps
->hdc
);
132 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
136 GetRgnBox16( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
137 DPtoLP16( lps
->hdc
, (LPPOINT16
)&lps
->rcPaint
, 2 );
139 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
141 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
142 lps
->fErase
= !SendMessage16(hwnd
, (bIcon
) ? WM_ICONERASEBKGND
144 (WPARAM16
)lps
->hdc
, 0 );
146 else lps
->fErase
= TRUE
;
152 /***********************************************************************
153 * BeginPaint32 (USER32.9)
155 HDC32
BeginPaint32( HWND32 hwnd
, PAINTSTRUCT32
*lps
)
159 BeginPaint16( hwnd
, &ps
);
160 lps
->hdc
= (HDC32
)ps
.hdc
;
161 lps
->fErase
= ps
.fErase
;
162 lps
->rcPaint
.top
= ps
.rcPaint
.top
;
163 lps
->rcPaint
.left
= ps
.rcPaint
.left
;
164 lps
->rcPaint
.right
= ps
.rcPaint
.right
;
165 lps
->rcPaint
.bottom
= ps
.rcPaint
.bottom
;
166 lps
->fRestore
= ps
.fRestore
;
167 lps
->fIncUpdate
= ps
.fIncUpdate
;
172 /***********************************************************************
173 * EndPaint16 (USER.40)
175 BOOL16
EndPaint16( HWND16 hwnd
, const PAINTSTRUCT16
* lps
)
177 ReleaseDC16( hwnd
, lps
->hdc
);
183 /***********************************************************************
184 * EndPaint32 (USER32.175)
186 BOOL32
EndPaint32( HWND32 hwnd
, const PAINTSTRUCT32
*lps
)
188 ReleaseDC32( hwnd
, lps
->hdc
);
194 /***********************************************************************
195 * FillWindow (USER.324)
197 void FillWindow( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
, HBRUSH16 hbrush
)
200 GetClientRect16( hwnd
, &rect
);
201 DPtoLP16( hdc
, (LPPOINT16
)&rect
, 2 );
202 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
206 /***********************************************************************
207 * PaintRect (USER.325)
209 void PaintRect( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
,
210 HBRUSH16 hbrush
, const RECT16
*rect
)
212 /* Send WM_CTLCOLOR message if needed */
214 if ((UINT32
)hbrush
<= CTLCOLOR_MAX
)
216 if (!hwndParent
) return;
217 hbrush
= (HBRUSH16
)SendMessage32A( hwndParent
,
218 WM_CTLCOLORMSGBOX
+ (UINT32
)hbrush
,
219 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
221 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
225 /***********************************************************************
226 * GetControlBrush (USER.326)
228 HBRUSH16
GetControlBrush( HWND16 hwnd
, HDC16 hdc
, UINT16 control
)
230 return (HBRUSH16
)SendMessage32A( GetParent32(hwnd
), WM_CTLCOLOR
+control
,
231 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
235 /***********************************************************************
238 * Note: Windows uses WM_SYNCPAINT to cut down the number of intertask
239 * SendMessage() calls. From SDK:
240 * This message avoids lots of inter-app message traffic
241 * by switching to the other task and continuing the
245 * LOWORD(lParam) = hrgnClip
246 * HIWORD(lParam) = hwndSkip (not used; always NULL)
248 BOOL32
PAINT_RedrawWindow( HWND32 hwnd
, const RECT32
*rectUpdate
,
249 HRGN32 hrgnUpdate
, UINT32 flags
, UINT32 control
)
257 if (!hwnd
) hwnd
= GetDesktopWindow32();
258 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
259 if (!IsWindowVisible32(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
260 return TRUE
; /* No redraw needed */
262 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
265 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
266 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
267 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
271 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
272 hwnd
, hrgnUpdate
, flags
);
275 GetClientRect32( hwnd
, &rectClient
);
277 if (flags
& RDW_INVALIDATE
) /* Invalidate */
279 int rgnNotEmpty
= COMPLEXREGION
;
281 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
283 if ((hrgn
= hrgnUpdate
) == 0)
284 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
286 rgnNotEmpty
= CombineRgn32( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
288 if (!hrgnUpdate
) DeleteObject32( hrgn
);
290 else /* No update region yet */
292 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
293 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
296 wndPtr
->hrgnUpdate
= CreateRectRgn32( 0, 0, 0, 0 );
297 rgnNotEmpty
= CombineRgn32( wndPtr
->hrgnUpdate
, hrgnUpdate
,
300 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
301 rectUpdate
: &rectClient
);
304 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
306 /* check for bogus update region */
307 if ( rgnNotEmpty
== NULLREGION
)
309 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
310 DeleteObject32( wndPtr
->hrgnUpdate
);
311 wndPtr
->hrgnUpdate
=0;
312 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
313 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
316 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
317 flags
|= RDW_FRAME
; /* Force children frame invalidation */
319 else if (flags
& RDW_VALIDATE
) /* Validate */
321 /* We need an update region in order to validate anything */
322 if (wndPtr
->hrgnUpdate
> 1)
324 if (!hrgnUpdate
&& !rectUpdate
)
326 /* Special case: validate everything */
327 DeleteObject32( wndPtr
->hrgnUpdate
);
328 wndPtr
->hrgnUpdate
= 0;
332 if ((hrgn
= hrgnUpdate
) == 0)
333 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
334 if (CombineRgn32( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
335 hrgn
, RGN_DIFF
) == NULLREGION
)
337 DeleteObject32( wndPtr
->hrgnUpdate
);
338 wndPtr
->hrgnUpdate
= 0;
340 if (!hrgnUpdate
) DeleteObject32( hrgn
);
342 if (!wndPtr
->hrgnUpdate
) /* No more update region */
343 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
344 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
346 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
347 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
350 /* Set/clear internal paint flag */
352 if (flags
& RDW_INTERNALPAINT
)
354 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
355 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
356 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
358 else if (flags
& RDW_NOINTERNALPAINT
)
360 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
361 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
362 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
365 /* Erase/update window */
367 if (flags
& RDW_UPDATENOW
)
369 if (wndPtr
->hrgnUpdate
) /* wm_painticon wparam is 1 */
370 SendMessage16( hwnd
, (bIcon
) ? WM_PAINTICON
: WM_PAINT
, bIcon
, 0 );
372 else if (flags
& RDW_ERASENOW
)
374 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
375 WIN_UpdateNCArea( wndPtr
, FALSE
);
377 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
379 HDC32 hdc
= GetDCEx32( hwnd
, wndPtr
->hrgnUpdate
,
380 DCX_INTERSECTRGN
| DCX_USESTYLE
|
381 DCX_KEEPCLIPRGN
| DCX_WINDOWPAINT
|
382 (bIcon
? DCX_WINDOW
: 0) );
385 if (SendMessage16( hwnd
, (bIcon
) ? WM_ICONERASEBKGND
388 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
389 ReleaseDC32( hwnd
, hdc
);
394 /* Recursively process children */
396 if (!(flags
& RDW_NOCHILDREN
) &&
397 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)) &&
398 !(wndPtr
->dwStyle
& WS_MINIMIZE
) )
400 if ( hrgnUpdate
|| rectUpdate
)
402 if (!(hrgn
= CreateRectRgn32( 0, 0, 0, 0 ))) return TRUE
;
405 control
|= (RDW_C_DELETEHRGN
| RDW_C_USEHRGN
);
406 if( !(hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
)) )
408 DeleteObject32( hrgn
);
412 list
= WIN_BuildWinArray( wndPtr
);
413 for (ppWnd
= list
; *ppWnd
; ppWnd
++)
416 if (!IsWindow(wndPtr
->hwndSelf
)) continue;
417 if (wndPtr
->dwStyle
& WS_VISIBLE
)
419 SetRectRgn( hrgn
, wndPtr
->rectWindow
.left
,
420 wndPtr
->rectWindow
.top
,
421 wndPtr
->rectWindow
.right
,
422 wndPtr
->rectWindow
.bottom
);
423 if (!CombineRgn32( hrgn
, hrgn
, hrgnUpdate
, RGN_AND
))
425 OffsetRgn32( hrgn
, -wndPtr
->rectClient
.left
,
426 -wndPtr
->rectClient
.top
);
427 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
,
431 HeapFree( SystemHeap
, 0, list
);
432 DeleteObject32( hrgn
);
433 if (control
& RDW_C_DELETEHRGN
) DeleteObject32( hrgnUpdate
);
437 list
= WIN_BuildWinArray( wndPtr
);
438 for (ppWnd
= list
; *ppWnd
; ppWnd
++)
441 if (IsWindow( wndPtr
->hwndSelf
))
442 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, 0, flags
, 0 );
444 HeapFree( SystemHeap
, 0, list
);
452 /***********************************************************************
453 * RedrawWindow32 (USER32.425)
455 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
456 HRGN32 hrgnUpdate
, UINT32 flags
)
458 WND
* wnd
= WIN_FindWndPtr( hwnd
);
460 /* check if there is something to redraw */
462 return ( wnd
&& WIN_IsWindowDrawable( wnd
, !(flags
& RDW_FRAME
) ) )
463 ? PAINT_RedrawWindow( hwnd
, rectUpdate
, hrgnUpdate
, flags
, 0 )
468 /***********************************************************************
469 * RedrawWindow16 (USER.290)
471 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
472 HRGN16 hrgnUpdate
, UINT16 flags
)
477 CONV_RECT16TO32( rectUpdate
, &r
);
478 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
480 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
484 /***********************************************************************
485 * UpdateWindow (USER.124) (USER32.566)
487 void UpdateWindow( HWND32 hwnd
)
489 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
493 /***********************************************************************
494 * InvalidateRgn16 (USER.126)
496 void InvalidateRgn16( HWND16 hwnd
, HRGN16 hrgn
, BOOL16 erase
)
498 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
502 /***********************************************************************
503 * InvalidateRgn32 (USER32.328)
505 void InvalidateRgn32( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
507 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
511 /***********************************************************************
512 * InvalidateRect16 (USER.125)
514 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
516 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
520 /***********************************************************************
521 * InvalidateRect32 (USER32.327)
523 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
525 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
529 /***********************************************************************
530 * ValidateRgn16 (USER.128)
532 void ValidateRgn16( HWND16 hwnd
, HRGN16 hrgn
)
534 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
538 /***********************************************************************
539 * ValidateRgn32 (USER32.571)
541 void ValidateRgn32( HWND32 hwnd
, HRGN32 hrgn
)
543 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
547 /***********************************************************************
548 * ValidateRect16 (USER.127)
550 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
552 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
556 /***********************************************************************
557 * ValidateRect32 (USER32.570)
559 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
561 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
565 /***********************************************************************
566 * GetUpdateRect16 (USER.190)
568 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
573 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
574 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
575 CONV_RECT32TO16( &r
, rect
);
580 /***********************************************************************
581 * GetUpdateRect32 (USER32.296)
583 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
585 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
586 if (!wndPtr
) return FALSE
;
590 if (wndPtr
->hrgnUpdate
> 1)
592 HRGN32 hrgn
= CreateRectRgn32( 0, 0, 0, 0 );
593 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
594 GetRgnBox32( hrgn
, rect
);
595 DeleteObject32( hrgn
);
597 else SetRectEmpty32( rect
);
599 return (wndPtr
->hrgnUpdate
> 1);
603 /***********************************************************************
604 * GetUpdateRgn (USER.237) (USER32.297)
606 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
609 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
610 if (!wndPtr
) return ERROR
;
612 if (wndPtr
->hrgnUpdate
<= 1)
614 SetRectRgn( hrgn
, 0, 0, 0, 0 );
617 retval
= CombineRgn32( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
618 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
623 /***********************************************************************
624 * ExcludeUpdateRgn (USER.238) (USER32.194)
626 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
631 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
633 if (wndPtr
->hrgnUpdate
)
636 HRGN32 hrgn
= CreateRectRgn32(wndPtr
->rectWindow
.left
- wndPtr
->rectClient
.left
,
637 wndPtr
->rectWindow
.top
- wndPtr
->rectClient
.top
,
638 wndPtr
->rectClient
.right
- wndPtr
->rectClient
.left
,
639 wndPtr
->rectClient
.bottom
- wndPtr
->rectClient
.top
);
640 if( wndPtr
->hrgnUpdate
> 1 )
641 CombineRgn32(hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
643 /* do ugly coordinate translations in dce.c */
645 ret
= DCE_ExcludeRgn( hdc
, wndPtr
, hrgn
);
646 DeleteObject32( hrgn
);
649 return GetClipBox16(hdc
, &rect
);