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 ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
201 if (!hwndParent
) return;
203 hbrush
= (HBRUSH
)SendMessage32A( hwndParent
,
204 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
205 (WPARAM
)hdc
, (LPARAM
)hwnd
);
207 hbrush
= (HBRUSH
)SendMessage16( hwndParent
, WM_CTLCOLOR
,
208 hdc
, MAKELONG( hwnd
, hbrush
) );
211 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
215 /***********************************************************************
216 * GetControlBrush (USER.326)
218 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
221 return (HBRUSH
)SendMessage32A( GetParent(hwnd
), WM_CTLCOLOR
+control
,
222 (WPARAM
)hdc
, (LPARAM
)hwnd
);
224 return (HBRUSH
)SendMessage16( GetParent(hwnd
), WM_CTLCOLOR
,
225 hdc
, MAKELONG( hwnd
, control
) );
230 /***********************************************************************
231 * RedrawWindow32 (USER32.425)
233 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
234 HRGN32 hrgnUpdate
, UINT32 flags
)
240 if (!hwnd
) hwnd
= GetDesktopWindow();
241 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
242 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
243 return TRUE
; /* No redraw needed */
247 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
248 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
249 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
253 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
254 hwnd
, hrgnUpdate
, flags
);
256 GetClientRect32( hwnd
, &rectClient
);
258 if (flags
& RDW_INVALIDATE
) /* Invalidate */
260 int rgnNotEmpty
= COMPLEXREGION
;
262 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
264 if ((hrgn
= hrgnUpdate
) == 0)
265 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
267 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
268 if (!hrgnUpdate
) DeleteObject( hrgn
);
270 else /* No update region yet */
272 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
273 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
276 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
277 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
279 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
280 rectUpdate
: &rectClient
);
283 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
285 /* check for bogus update region */
286 if ( rgnNotEmpty
== NULLREGION
)
288 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
289 DeleteObject(wndPtr
->hrgnUpdate
);
290 wndPtr
->hrgnUpdate
=0;
291 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
292 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
295 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
296 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
298 else if (flags
& RDW_VALIDATE
) /* Validate */
300 /* We need an update region in order to validate anything */
301 if (wndPtr
->hrgnUpdate
> 1)
303 if (!hrgnUpdate
&& !rectUpdate
)
305 /* Special case: validate everything */
306 DeleteObject( wndPtr
->hrgnUpdate
);
307 wndPtr
->hrgnUpdate
= 0;
311 if ((hrgn
= hrgnUpdate
) == 0)
312 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
313 if (CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
314 hrgn
, RGN_DIFF
) == NULLREGION
)
316 DeleteObject( wndPtr
->hrgnUpdate
);
317 wndPtr
->hrgnUpdate
= 0;
319 if (!hrgnUpdate
) DeleteObject( hrgn
);
321 if (!wndPtr
->hrgnUpdate
) /* No more update region */
322 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
323 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
325 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
326 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
329 /* Set/clear internal paint flag */
331 if (flags
& RDW_INTERNALPAINT
)
333 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
334 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
335 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
337 else if (flags
& RDW_NOINTERNALPAINT
)
339 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
340 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
341 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
344 /* Erase/update window */
346 if (flags
& RDW_UPDATENOW
)
348 if (wndPtr
->hrgnUpdate
) SendMessage16( hwnd
, WM_PAINT
, 0, 0 );
350 else if (flags
& RDW_ERASENOW
)
352 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
353 WIN_UpdateNCArea( wndPtr
, FALSE
);
355 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
357 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
358 DCX_INTERSECTRGN
| DCX_USESTYLE
| DCX_KEEPCLIPRGN
| DCX_WINDOWPAINT
);
361 /* Don't send WM_ERASEBKGND to icons */
362 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
363 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
) ||
364 !wndPtr
->class->hIcon
)
366 if (SendMessage16( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
367 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
369 ReleaseDC( hwnd
, hdc
);
374 /* Recursively process children */
376 if (!(flags
& RDW_NOCHILDREN
) &&
377 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
381 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
382 if (!hrgn
) return TRUE
;
383 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
385 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
386 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
387 -wndPtr
->rectClient
.top
);
388 RedrawWindow32( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
);
390 DeleteObject( hrgn
);
395 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
400 OffsetRect32( &rect
, -wndPtr
->rectClient
.left
,
401 -wndPtr
->rectClient
.top
);
402 RedrawWindow32( wndPtr
->hwndSelf
, &rect
, 0, flags
);
404 else RedrawWindow32( wndPtr
->hwndSelf
, NULL
, 0, flags
);
412 /***********************************************************************
413 * RedrawWindow16 (USER.290)
415 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
416 HRGN16 hrgnUpdate
, UINT16 flags
)
421 CONV_RECT16TO32( rectUpdate
, &r
);
422 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
424 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
428 /***********************************************************************
429 * UpdateWindow (USER.124) (USER32.566)
431 void UpdateWindow( HWND32 hwnd
)
433 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
437 /***********************************************************************
438 * InvalidateRgn (USER.126) (USER32.328)
440 void InvalidateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
442 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0));
446 /***********************************************************************
447 * InvalidateRect16 (USER.125)
449 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
451 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
455 /***********************************************************************
456 * InvalidateRect32 (USER32.327)
458 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
460 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
464 /***********************************************************************
465 * ValidateRgn (USER.128) (USER32.571)
467 void ValidateRgn( HWND32 hwnd
, HRGN32 hrgn
)
469 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
473 /***********************************************************************
474 * ValidateRect16 (USER.127)
476 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
478 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
482 /***********************************************************************
483 * ValidateRect32 (USER32.570)
485 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
487 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
491 /***********************************************************************
492 * GetUpdateRect16 (USER.190)
494 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
499 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
500 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
501 CONV_RECT32TO16( &r
, rect
);
506 /***********************************************************************
507 * GetUpdateRect32 (USER32.296)
509 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
511 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
512 if (!wndPtr
) return FALSE
;
516 if (wndPtr
->hrgnUpdate
> 1)
518 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
519 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
520 GetRgnBox32( hrgn
, rect
);
521 DeleteObject( hrgn
);
523 else SetRectEmpty32( rect
);
525 return (wndPtr
->hrgnUpdate
> 1);
529 /***********************************************************************
530 * GetUpdateRgn (USER.237) (USER32.297)
532 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
535 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
536 if (!wndPtr
) return ERROR
;
538 if (wndPtr
->hrgnUpdate
<= 1)
540 SetRectRgn( hrgn
, 0, 0, 0, 0 );
543 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
544 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
549 /***********************************************************************
550 * ExcludeUpdateRgn (USER.238) (USER32.194)
552 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
554 INT16 retval
= ERROR
;
558 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
559 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
561 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
562 (wndPtr
->hrgnUpdate
>1)?wndPtr
->hrgnUpdate
:0,
563 (wndPtr
->hrgnUpdate
>1)?RGN_DIFF
:RGN_COPY
);
564 if (retval
) SelectVisRgn( hdc
, hrgn
);
565 DeleteObject( hrgn
);