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
= CreateRectRgn32( 0, 0, 0, 0 );
45 if (!CombineRgn32( hClip
, wnd
->hrgnUpdate
, 0, RGN_COPY
))
47 DeleteObject32(hClip
);
51 OffsetRgn32( hClip
, pt
.x
, pt
.y
);
55 /* exclude non-client area from update region */
56 HRGN32 hrgn
= CreateRectRgn32( 0, 0,
57 wnd
->rectClient
.right
- wnd
->rectClient
.left
,
58 wnd
->rectClient
.bottom
- wnd
->rectClient
.top
);
60 if (hrgn
&& (CombineRgn32( wnd
->hrgnUpdate
, wnd
->hrgnUpdate
,
61 hrgn
, RGN_AND
) == NULLREGION
))
63 DeleteObject32( wnd
->hrgnUpdate
);
67 DeleteObject32( hrgn
);
71 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
73 if ((wnd
->hwndSelf
== GetActiveWindow()) &&
74 !(wnd
->flags
& WIN_NCACTIVATED
))
76 wnd
->flags
|= WIN_NCACTIVATED
;
77 if( hClip
> 1) DeleteObject32( hClip
);
81 if (hClip
) SendMessage16( wnd
->hwndSelf
, WM_NCPAINT
, hClip
, 0L );
83 if (hClip
> 1) DeleteObject32( hClip
);
87 /***********************************************************************
88 * BeginPaint16 (USER.39)
90 HDC16
BeginPaint16( HWND16 hwnd
, LPPAINTSTRUCT16 lps
)
94 WND
*wndPtr
= WIN_FindWndPtr( hwnd
);
95 if (!wndPtr
) return 0;
97 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
99 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
101 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
103 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
104 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
105 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
107 wndPtr
->hrgnUpdate
= 0;
108 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
112 dprintf_win(stddeb
,"hrgnUpdate = %04x, ", hrgnUpdate
);
114 /* When bIcon is TRUE hrgnUpdate is automatically in window coordinates
115 * (because rectClient == rectWindow for WS_MINIMIZE windows).
118 lps
->hdc
= GetDCEx16(hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_WINDOWPAINT
|
119 DCX_USESTYLE
| (bIcon
? DCX_WINDOW
: 0) );
121 dprintf_win(stddeb
,"hdc = %04x\n", lps
->hdc
);
125 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
129 GetRgnBox16( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
130 DPtoLP16( lps
->hdc
, (LPPOINT16
)&lps
->rcPaint
, 2 );
132 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
134 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
135 lps
->fErase
= !SendMessage16(hwnd
, (bIcon
) ? WM_ICONERASEBKGND
137 (WPARAM16
)lps
->hdc
, 0 );
139 else lps
->fErase
= TRUE
;
145 /***********************************************************************
146 * BeginPaint32 (USER32.9)
148 HDC32
BeginPaint32( HWND32 hwnd
, PAINTSTRUCT32
*lps
)
152 BeginPaint16( hwnd
, &ps
);
153 lps
->hdc
= (HDC32
)ps
.hdc
;
154 lps
->fErase
= ps
.fErase
;
155 lps
->rcPaint
.top
= ps
.rcPaint
.top
;
156 lps
->rcPaint
.left
= ps
.rcPaint
.left
;
157 lps
->rcPaint
.right
= ps
.rcPaint
.right
;
158 lps
->rcPaint
.bottom
= ps
.rcPaint
.bottom
;
159 lps
->fRestore
= ps
.fRestore
;
160 lps
->fIncUpdate
= ps
.fIncUpdate
;
165 /***********************************************************************
166 * EndPaint16 (USER.40)
168 BOOL16
EndPaint16( HWND16 hwnd
, const PAINTSTRUCT16
* lps
)
170 ReleaseDC16( hwnd
, lps
->hdc
);
176 /***********************************************************************
177 * EndPaint32 (USER32.175)
179 BOOL32
EndPaint32( HWND32 hwnd
, const PAINTSTRUCT32
*lps
)
181 ReleaseDC32( hwnd
, lps
->hdc
);
187 /***********************************************************************
188 * FillWindow (USER.324)
190 void FillWindow( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
, HBRUSH16 hbrush
)
193 GetClientRect16( hwnd
, &rect
);
194 DPtoLP16( hdc
, (LPPOINT16
)&rect
, 2 );
195 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
199 /***********************************************************************
200 * PaintRect (USER.325)
202 void PaintRect( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
,
203 HBRUSH16 hbrush
, const RECT16
*rect
)
205 /* Send WM_CTLCOLOR message if needed */
207 if ((UINT32
)hbrush
<= CTLCOLOR_MAX
)
209 if (!hwndParent
) return;
210 hbrush
= (HBRUSH16
)SendMessage32A( hwndParent
,
211 WM_CTLCOLORMSGBOX
+ (UINT32
)hbrush
,
212 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
214 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
218 /***********************************************************************
219 * GetControlBrush (USER.326)
221 HBRUSH16
GetControlBrush( HWND hwnd
, HDC16 hdc
, WORD control
)
223 return (HBRUSH16
)SendMessage32A( GetParent32(hwnd
), WM_CTLCOLOR
+control
,
224 (WPARAM32
)hdc
, (LPARAM
)hwnd
);
228 /***********************************************************************
231 * Note: Windows uses WM_SYNCPAINT to cut down the number of intertask
232 * SendMessage() calls. From SDK:
233 * This message avoids lots of inter-app message traffic
234 * by switching to the other task and continuing the
238 * LOWORD(lParam) = hrgnClip
239 * HIWORD(lParam) = hwndSkip (not used; always NULL)
241 BOOL32
PAINT_RedrawWindow( HWND32 hwnd
, const RECT32
*rectUpdate
,
242 HRGN32 hrgnUpdate
, UINT32 flags
, UINT32 control
)
249 if (!hwnd
) hwnd
= GetDesktopWindow32();
250 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
251 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
252 return TRUE
; /* No redraw needed */
254 bIcon
= (wndPtr
->dwStyle
& WS_MINIMIZE
&& wndPtr
->class->hIcon
);
257 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
258 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
259 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
263 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
264 hwnd
, hrgnUpdate
, flags
);
267 if (wndPtr
->class->style
& CS_PARENTDC
)
269 GetClientRect32( wndPtr
->parent
->hwndSelf
, &rectClient
);
270 OffsetRect32( &rectClient
, -wndPtr
->rectClient
.left
,
271 -wndPtr
->rectClient
.top
);
273 else GetClientRect32( hwnd
, &rectClient
);
275 if (flags
& RDW_INVALIDATE
) /* Invalidate */
277 int rgnNotEmpty
= COMPLEXREGION
;
279 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
281 if ((hrgn
= hrgnUpdate
) == 0)
282 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
284 rgnNotEmpty
= CombineRgn32( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
286 if (!hrgnUpdate
) DeleteObject32( hrgn
);
288 else /* No update region yet */
290 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
291 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
294 wndPtr
->hrgnUpdate
= CreateRectRgn32( 0, 0, 0, 0 );
295 rgnNotEmpty
= CombineRgn32( wndPtr
->hrgnUpdate
, hrgnUpdate
,
298 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
299 rectUpdate
: &rectClient
);
302 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
304 /* check for bogus update region */
305 if ( rgnNotEmpty
== NULLREGION
)
307 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
308 DeleteObject32( wndPtr
->hrgnUpdate
);
309 wndPtr
->hrgnUpdate
=0;
310 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
311 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
314 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
315 flags
|= RDW_FRAME
; /* Force children frame invalidation */
317 else if (flags
& RDW_VALIDATE
) /* Validate */
319 /* We need an update region in order to validate anything */
320 if (wndPtr
->hrgnUpdate
> 1)
322 if (!hrgnUpdate
&& !rectUpdate
)
324 /* Special case: validate everything */
325 DeleteObject32( wndPtr
->hrgnUpdate
);
326 wndPtr
->hrgnUpdate
= 0;
330 if ((hrgn
= hrgnUpdate
) == 0)
331 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
332 if (CombineRgn32( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
333 hrgn
, RGN_DIFF
) == NULLREGION
)
335 DeleteObject32( wndPtr
->hrgnUpdate
);
336 wndPtr
->hrgnUpdate
= 0;
338 if (!hrgnUpdate
) DeleteObject32( hrgn
);
340 if (!wndPtr
->hrgnUpdate
) /* No more update region */
341 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
342 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
344 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
345 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
348 /* Set/clear internal paint flag */
350 if (flags
& RDW_INTERNALPAINT
)
352 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
353 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
354 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
356 else if (flags
& RDW_NOINTERNALPAINT
)
358 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
359 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
360 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
363 /* Erase/update window */
365 if (flags
& RDW_UPDATENOW
)
367 if (wndPtr
->hrgnUpdate
) /* wm_painticon wparam is 1 */
368 SendMessage16( hwnd
, (bIcon
) ? WM_PAINTICON
: WM_PAINT
, bIcon
, 0 );
370 else if (flags
& RDW_ERASENOW
)
372 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
373 WIN_UpdateNCArea( wndPtr
, FALSE
);
375 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
377 HDC32 hdc
= GetDCEx32( hwnd
, wndPtr
->hrgnUpdate
,
378 DCX_INTERSECTRGN
| DCX_USESTYLE
|
379 DCX_KEEPCLIPRGN
| DCX_WINDOWPAINT
|
380 (bIcon
? DCX_WINDOW
: 0) );
383 if (SendMessage16( hwnd
, (bIcon
) ? WM_ICONERASEBKGND
386 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
387 ReleaseDC32( hwnd
, hdc
);
392 /* Recursively process children */
394 if (!(flags
& RDW_NOCHILDREN
) &&
395 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)) &&
396 !(wndPtr
->dwStyle
& WS_MINIMIZE
) )
398 if ( hrgnUpdate
|| rectUpdate
)
400 if (!(hrgn
= CreateRectRgn32( 0, 0, 0, 0 ))) return TRUE
;
403 control
|= (RDW_C_DELETEHRGN
| RDW_C_USEHRGN
);
404 if( !(hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
)) )
406 DeleteObject32( hrgn
);
410 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
411 if( wndPtr
->dwStyle
& WS_VISIBLE
)
413 if (wndPtr
->class->style
& CS_PARENTDC
)
415 if (!CombineRgn32( hrgn
, hrgnUpdate
, 0, RGN_COPY
))
420 SetRectRgn( hrgn
, wndPtr
->rectWindow
.left
,
421 wndPtr
->rectWindow
.top
,
422 wndPtr
->rectWindow
.right
,
423 wndPtr
->rectWindow
.bottom
);
424 if (!CombineRgn32( hrgn
, hrgn
, hrgnUpdate
, RGN_AND
))
427 OffsetRgn32( hrgn
, -wndPtr
->rectClient
.left
,
428 -wndPtr
->rectClient
.top
);
429 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
, RDW_C_USEHRGN
);
431 DeleteObject32( hrgn
);
432 if (control
& RDW_C_DELETEHRGN
) DeleteObject32( hrgnUpdate
);
434 else for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
435 PAINT_RedrawWindow( wndPtr
->hwndSelf
, NULL
, 0, flags
, 0 );
442 /***********************************************************************
443 * RedrawWindow32 (USER32.425)
445 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
446 HRGN32 hrgnUpdate
, UINT32 flags
)
448 WND
* wnd
= WIN_FindWndPtr( hwnd
);
450 /* check if there is something to redraw */
452 return ( wnd
&& WIN_IsWindowDrawable( wnd
, !(flags
& RDW_FRAME
) ) )
453 ? PAINT_RedrawWindow( hwnd
, rectUpdate
, hrgnUpdate
, flags
, 0 )
458 /***********************************************************************
459 * RedrawWindow16 (USER.290)
461 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
462 HRGN16 hrgnUpdate
, UINT16 flags
)
467 CONV_RECT16TO32( rectUpdate
, &r
);
468 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
470 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
474 /***********************************************************************
475 * UpdateWindow (USER.124) (USER32.566)
477 void UpdateWindow( HWND32 hwnd
)
479 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
483 /***********************************************************************
484 * InvalidateRgn (USER.126) (USER32.328)
486 void InvalidateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
488 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
492 /***********************************************************************
493 * InvalidateRect16 (USER.125)
495 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
497 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
501 /***********************************************************************
502 * InvalidateRect32 (USER32.327)
504 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
506 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
510 /***********************************************************************
511 * ValidateRgn (USER.128) (USER32.571)
513 void ValidateRgn( HWND32 hwnd
, HRGN32 hrgn
)
515 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
519 /***********************************************************************
520 * ValidateRect16 (USER.127)
522 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
524 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
528 /***********************************************************************
529 * ValidateRect32 (USER32.570)
531 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
533 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
537 /***********************************************************************
538 * GetUpdateRect16 (USER.190)
540 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
545 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
546 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
547 CONV_RECT32TO16( &r
, rect
);
552 /***********************************************************************
553 * GetUpdateRect32 (USER32.296)
555 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
557 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
558 if (!wndPtr
) return FALSE
;
562 if (wndPtr
->hrgnUpdate
> 1)
564 HRGN32 hrgn
= CreateRectRgn32( 0, 0, 0, 0 );
565 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
566 GetRgnBox32( hrgn
, rect
);
567 DeleteObject32( hrgn
);
569 else SetRectEmpty32( rect
);
571 return (wndPtr
->hrgnUpdate
> 1);
575 /***********************************************************************
576 * GetUpdateRgn (USER.237) (USER32.297)
578 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
581 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
582 if (!wndPtr
) return ERROR
;
584 if (wndPtr
->hrgnUpdate
<= 1)
586 SetRectRgn( hrgn
, 0, 0, 0, 0 );
589 retval
= CombineRgn32( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
590 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
595 /***********************************************************************
596 * ExcludeUpdateRgn (USER.238) (USER32.194)
598 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
600 INT32 retval
= ERROR
;
604 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
605 if ((hrgn
= CreateRectRgn32( 0, 0, 0, 0 )) != 0)
607 retval
= CombineRgn32( hrgn
, InquireVisRgn(hdc
),
608 (wndPtr
->hrgnUpdate
>1) ? wndPtr
->hrgnUpdate
: 0,
609 (wndPtr
->hrgnUpdate
>1) ? RGN_DIFF
: RGN_COPY
);
610 if (retval
) SelectVisRgn( hdc
, hrgn
);
611 DeleteObject32( hrgn
);