2 * Window painting functions
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
14 /* #define DEBUG_WIN */
17 /* Last CTLCOLOR id */
18 #define CTLCOLOR_MAX CTLCOLOR_STATIC
20 /***********************************************************************
24 void WIN_UpdateNCArea(WND
* wnd
, BOOL bUpdate
)
29 dprintf_nonclient(stddeb
,"NCUpdate: hwnd %04x, hrgnUpdate %04x\n",
30 wnd
->hwndSelf
, wnd
->hrgnUpdate
);
32 /* desktop window doesn't have nonclient area */
33 if(wnd
== WIN_GetDesktop())
35 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
39 if( wnd
->hrgnUpdate
> 1 )
41 ClientToScreen16(wnd
->hwndSelf
, &pt
);
43 hClip
= CreateRectRgn( 0, 0, 0, 0 );
44 if (!CombineRgn(hClip
, wnd
->hrgnUpdate
, 0, RGN_COPY
) )
50 OffsetRgn(hClip
, pt
.x
, pt
.y
);
54 /* exclude non-client area from update region */
55 HRGN hrgn
= CreateRectRgn(0, 0, wnd
->rectClient
.right
- wnd
->rectClient
.left
,
56 wnd
->rectClient
.bottom
- wnd
->rectClient
.top
);
58 if (hrgn
&& (CombineRgn(wnd
->hrgnUpdate
, wnd
->hrgnUpdate
,
59 hrgn
, RGN_AND
) == NULLREGION
))
61 DeleteObject(wnd
->hrgnUpdate
);
69 wnd
->flags
&= ~WIN_NEEDS_NCPAINT
;
71 if ((wnd
->hwndSelf
== GetActiveWindow()) &&
72 !(wnd
->flags
& WIN_NCACTIVATED
))
74 wnd
->flags
|= WIN_NCACTIVATED
;
75 if( hClip
> 1) DeleteObject(hClip
);
79 if (hClip
) SendMessage16( wnd
->hwndSelf
, WM_NCPAINT
, hClip
, 0L );
81 if (hClip
> 1) DeleteObject( hClip
);
85 /***********************************************************************
86 * BeginPaint16 (USER.39)
88 HDC16
BeginPaint16( HWND16 hwnd
, LPPAINTSTRUCT16 lps
)
91 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
92 if (!wndPtr
) return 0;
94 wndPtr
->flags
&= ~WIN_NEEDS_BEGINPAINT
;
96 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
) WIN_UpdateNCArea( wndPtr
, TRUE
);
98 if (((hrgnUpdate
= wndPtr
->hrgnUpdate
) != 0) ||
99 (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
100 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
102 wndPtr
->hrgnUpdate
= 0;
103 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
107 lps
->hdc
= GetDCEx( hwnd
, hrgnUpdate
, DCX_INTERSECTRGN
| DCX_USESTYLE
);
108 if(hrgnUpdate
> 1) DeleteObject( hrgnUpdate
);
112 fprintf(stderr
, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd
);
116 GetRgnBox16( InquireVisRgn(lps
->hdc
), &lps
->rcPaint
);
117 DPtoLP16( lps
->hdc
, (LPPOINT16
)&lps
->rcPaint
, 2 );
119 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
121 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
122 lps
->fErase
= !SendMessage16(hwnd
, WM_ERASEBKGND
, (WPARAM
)lps
->hdc
, 0);
124 else lps
->fErase
= TRUE
;
130 /***********************************************************************
131 * BeginPaint32 (USER32.9)
133 HDC32
BeginPaint32( HWND32 hwnd
, PAINTSTRUCT32
*lps
)
137 BeginPaint16( hwnd
, &ps
);
138 lps
->hdc
= (HDC32
)ps
.hdc
;
139 lps
->fErase
= ps
.fErase
;
140 lps
->rcPaint
.top
= ps
.rcPaint
.top
;
141 lps
->rcPaint
.left
= ps
.rcPaint
.left
;
142 lps
->rcPaint
.right
= ps
.rcPaint
.right
;
143 lps
->rcPaint
.bottom
= ps
.rcPaint
.bottom
;
144 lps
->fRestore
= ps
.fRestore
;
145 lps
->fIncUpdate
= ps
.fIncUpdate
;
150 /***********************************************************************
151 * EndPaint16 (USER.40)
153 BOOL16
EndPaint16( HWND16 hwnd
, const PAINTSTRUCT16
* lps
)
155 ReleaseDC( hwnd
, lps
->hdc
);
161 /***********************************************************************
162 * EndPaint32 (USER32.175)
164 BOOL32
EndPaint32( HWND32 hwnd
, const PAINTSTRUCT32
*lps
)
166 ReleaseDC( hwnd
, (HDC16
)lps
->hdc
);
172 /***********************************************************************
173 * FillWindow (USER.324)
175 void FillWindow( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
, HBRUSH16 hbrush
)
178 GetClientRect16( hwnd
, &rect
);
179 DPtoLP16( hdc
, (LPPOINT16
)&rect
, 2 );
180 PaintRect( hwndParent
, hwnd
, hdc
, hbrush
, &rect
);
184 /***********************************************************************
185 * PaintRect (USER.325)
187 void PaintRect( HWND16 hwndParent
, HWND16 hwnd
, HDC16 hdc
,
188 HBRUSH16 hbrush
, const RECT16
*rect
)
190 /* Send WM_CTLCOLOR message if needed */
192 if ((DWORD
)hbrush
<= CTLCOLOR_MAX
)
194 if (!hwndParent
) return;
196 hbrush
= (HBRUSH
)SendMessage32A( hwndParent
,
197 WM_CTLCOLORMSGBOX
+(DWORD
)hbrush
,
198 (WPARAM
)hdc
, (LPARAM
)hwnd
);
200 hbrush
= (HBRUSH
)SendMessage16( hwndParent
, WM_CTLCOLOR
,
201 hdc
, MAKELONG( hwnd
, hbrush
) );
204 if (hbrush
) FillRect16( hdc
, rect
, hbrush
);
208 /***********************************************************************
209 * GetControlBrush (USER.326)
211 HBRUSH
GetControlBrush( HWND hwnd
, HDC hdc
, WORD control
)
214 return (HBRUSH
)SendMessage32A( GetParent(hwnd
), WM_CTLCOLOR
+control
,
215 (WPARAM
)hdc
, (LPARAM
)hwnd
);
217 return (HBRUSH
)SendMessage16( GetParent(hwnd
), WM_CTLCOLOR
,
218 hdc
, MAKELONG( hwnd
, control
) );
223 /***********************************************************************
224 * RedrawWindow32 (USER32.425)
226 BOOL32
RedrawWindow32( HWND32 hwnd
, const RECT32
*rectUpdate
,
227 HRGN32 hrgnUpdate
, UINT32 flags
)
233 if (!hwnd
) hwnd
= GetDesktopWindow();
234 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return FALSE
;
235 if (!IsWindowVisible(hwnd
) || (wndPtr
->flags
& WIN_NO_REDRAW
))
236 return TRUE
; /* No redraw needed */
240 dprintf_win(stddeb
, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
241 hwnd
, rectUpdate
->left
, rectUpdate
->top
,
242 rectUpdate
->right
, rectUpdate
->bottom
, hrgnUpdate
, flags
);
246 dprintf_win(stddeb
, "RedrawWindow: %04x NULL %04x flags=%04x\n",
247 hwnd
, hrgnUpdate
, flags
);
249 GetClientRect32( hwnd
, &rectClient
);
251 if (flags
& RDW_INVALIDATE
) /* Invalidate */
253 int rgnNotEmpty
= COMPLEXREGION
;
255 if (wndPtr
->hrgnUpdate
> 1) /* Is there already an update region? */
257 if ((hrgn
= hrgnUpdate
) == 0)
258 hrgn
= CreateRectRgnIndirect32( rectUpdate
? rectUpdate
:
260 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
, hrgn
, RGN_OR
);
261 if (!hrgnUpdate
) DeleteObject( hrgn
);
263 else /* No update region yet */
265 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
266 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
269 wndPtr
->hrgnUpdate
= CreateRectRgn( 0, 0, 0, 0 );
270 rgnNotEmpty
= CombineRgn( wndPtr
->hrgnUpdate
, hrgnUpdate
, 0, RGN_COPY
);
272 else wndPtr
->hrgnUpdate
= CreateRectRgnIndirect32( rectUpdate
?
273 rectUpdate
: &rectClient
);
276 if (flags
& RDW_FRAME
) wndPtr
->flags
|= WIN_NEEDS_NCPAINT
;
278 /* check for bogus update region */
279 if ( rgnNotEmpty
== NULLREGION
)
281 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
282 DeleteObject(wndPtr
->hrgnUpdate
);
283 wndPtr
->hrgnUpdate
=0;
284 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
285 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
288 if (flags
& RDW_ERASE
) wndPtr
->flags
|= WIN_NEEDS_ERASEBKGND
;
289 flags
|= RDW_FRAME
; /* Force invalidating the frame of children */
291 else if (flags
& RDW_VALIDATE
) /* Validate */
293 /* We need an update region in order to validate anything */
294 if (wndPtr
->hrgnUpdate
> 1)
296 if (!hrgnUpdate
&& !rectUpdate
)
298 /* Special case: validate everything */
299 DeleteObject( wndPtr
->hrgnUpdate
);
300 wndPtr
->hrgnUpdate
= 0;
304 if ((hrgn
= hrgnUpdate
) == 0)
305 hrgn
= CreateRectRgnIndirect32( rectUpdate
);
306 if (CombineRgn( wndPtr
->hrgnUpdate
, wndPtr
->hrgnUpdate
,
307 hrgn
, RGN_DIFF
) == NULLREGION
)
309 DeleteObject( wndPtr
->hrgnUpdate
);
310 wndPtr
->hrgnUpdate
= 0;
312 if (!hrgnUpdate
) DeleteObject( hrgn
);
314 if (!wndPtr
->hrgnUpdate
) /* No more update region */
315 if (!(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
316 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
318 if (flags
& RDW_NOFRAME
) wndPtr
->flags
&= ~WIN_NEEDS_NCPAINT
;
319 if (flags
& RDW_NOERASE
) wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
322 /* Set/clear internal paint flag */
324 if (flags
& RDW_INTERNALPAINT
)
326 if ( wndPtr
->hrgnUpdate
<= 1 && !(wndPtr
->flags
& WIN_INTERNAL_PAINT
))
327 QUEUE_IncPaintCount( wndPtr
->hmemTaskQ
);
328 wndPtr
->flags
|= WIN_INTERNAL_PAINT
;
330 else if (flags
& RDW_NOINTERNALPAINT
)
332 if ( wndPtr
->hrgnUpdate
<= 1 && (wndPtr
->flags
& WIN_INTERNAL_PAINT
))
333 QUEUE_DecPaintCount( wndPtr
->hmemTaskQ
);
334 wndPtr
->flags
&= ~WIN_INTERNAL_PAINT
;
337 /* Erase/update window */
339 if (flags
& RDW_UPDATENOW
)
341 if (wndPtr
->hrgnUpdate
) SendMessage16( hwnd
, WM_PAINT
, 0, 0 );
343 else if (flags
& RDW_ERASENOW
)
345 if (wndPtr
->flags
& WIN_NEEDS_NCPAINT
)
346 WIN_UpdateNCArea( wndPtr
, FALSE
);
348 if (wndPtr
->flags
& WIN_NEEDS_ERASEBKGND
)
350 HDC hdc
= GetDCEx( hwnd
, wndPtr
->hrgnUpdate
,
351 DCX_INTERSECTRGN
| DCX_USESTYLE
);
354 /* Don't send WM_ERASEBKGND to icons */
355 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
356 if (!(wndPtr
->dwStyle
& WS_MINIMIZE
) ||
357 !wndPtr
->class->hIcon
)
359 if (SendMessage16( hwnd
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0 ))
360 wndPtr
->flags
&= ~WIN_NEEDS_ERASEBKGND
;
362 ReleaseDC( hwnd
, hdc
);
367 /* Recursively process children */
369 if (!(flags
& RDW_NOCHILDREN
) &&
370 ((flags
& RDW_ALLCHILDREN
) || !(wndPtr
->dwStyle
& WS_CLIPCHILDREN
)))
374 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
375 if (!hrgn
) return TRUE
;
376 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
378 CombineRgn( hrgn
, hrgnUpdate
, 0, RGN_COPY
);
379 OffsetRgn( hrgn
, -wndPtr
->rectClient
.left
,
380 -wndPtr
->rectClient
.top
);
381 RedrawWindow32( wndPtr
->hwndSelf
, NULL
, hrgn
, flags
);
383 DeleteObject( hrgn
);
388 for (wndPtr
= wndPtr
->child
; wndPtr
; wndPtr
= wndPtr
->next
)
393 OffsetRect32( &rect
, -wndPtr
->rectClient
.left
,
394 -wndPtr
->rectClient
.top
);
395 RedrawWindow32( wndPtr
->hwndSelf
, &rect
, 0, flags
);
397 else RedrawWindow32( wndPtr
->hwndSelf
, NULL
, 0, flags
);
405 /***********************************************************************
406 * RedrawWindow16 (USER.290)
408 BOOL16
RedrawWindow16( HWND16 hwnd
, const RECT16
*rectUpdate
,
409 HRGN16 hrgnUpdate
, UINT16 flags
)
414 CONV_RECT16TO32( rectUpdate
, &r
);
415 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, &r
, hrgnUpdate
, flags
);
417 return (BOOL16
)RedrawWindow32( (HWND32
)hwnd
, NULL
, hrgnUpdate
, flags
);
421 /***********************************************************************
422 * UpdateWindow (USER.124) (USER32.566)
424 void UpdateWindow( HWND32 hwnd
)
426 RedrawWindow32( hwnd
, NULL
, 0, RDW_UPDATENOW
| RDW_NOCHILDREN
);
430 /***********************************************************************
431 * InvalidateRgn (USER.126) (USER32.328)
433 void InvalidateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
435 RedrawWindow32(hwnd
, NULL
, hrgn
, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0));
439 /***********************************************************************
440 * InvalidateRect16 (USER.125)
442 void InvalidateRect16( HWND16 hwnd
, const RECT16
*rect
, BOOL16 erase
)
444 RedrawWindow16( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
448 /***********************************************************************
449 * InvalidateRect32 (USER32.327)
451 void InvalidateRect32( HWND32 hwnd
, const RECT32
*rect
, BOOL32 erase
)
453 RedrawWindow32( hwnd
, rect
, 0, RDW_INVALIDATE
| (erase
? RDW_ERASE
: 0) );
457 /***********************************************************************
458 * ValidateRgn (USER.128) (USER32.571)
460 void ValidateRgn( HWND32 hwnd
, HRGN32 hrgn
)
462 RedrawWindow32( hwnd
, NULL
, hrgn
, RDW_VALIDATE
| RDW_NOCHILDREN
);
466 /***********************************************************************
467 * ValidateRect16 (USER.127)
469 void ValidateRect16( HWND16 hwnd
, const RECT16
*rect
)
471 RedrawWindow16( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
475 /***********************************************************************
476 * ValidateRect32 (USER32.570)
478 void ValidateRect32( HWND32 hwnd
, const RECT32
*rect
)
480 RedrawWindow32( hwnd
, rect
, 0, RDW_VALIDATE
| RDW_NOCHILDREN
);
484 /***********************************************************************
485 * GetUpdateRect16 (USER.190)
487 BOOL16
GetUpdateRect16( HWND16 hwnd
, LPRECT16 rect
, BOOL16 erase
)
492 if (!rect
) return GetUpdateRect32( hwnd
, NULL
, erase
);
493 ret
= GetUpdateRect32( hwnd
, &r
, erase
);
494 CONV_RECT32TO16( &r
, rect
);
499 /***********************************************************************
500 * GetUpdateRect32 (USER32.296)
502 BOOL32
GetUpdateRect32( HWND32 hwnd
, LPRECT32 rect
, BOOL32 erase
)
504 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
505 if (!wndPtr
) return FALSE
;
509 if (wndPtr
->hrgnUpdate
> 1)
511 HRGN hrgn
= CreateRectRgn( 0, 0, 0, 0 );
512 if (GetUpdateRgn( hwnd
, hrgn
, erase
) == ERROR
) return FALSE
;
513 GetRgnBox32( hrgn
, rect
);
514 DeleteObject( hrgn
);
516 else SetRectEmpty32( rect
);
518 return (wndPtr
->hrgnUpdate
> 1);
522 /***********************************************************************
523 * GetUpdateRgn (USER.237) (USER32.297)
525 INT16
GetUpdateRgn( HWND32 hwnd
, HRGN32 hrgn
, BOOL32 erase
)
528 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
529 if (!wndPtr
) return ERROR
;
531 if (wndPtr
->hrgnUpdate
<= 1)
533 SetRectRgn( hrgn
, 0, 0, 0, 0 );
536 retval
= CombineRgn( hrgn
, wndPtr
->hrgnUpdate
, 0, RGN_COPY
);
537 if (erase
) RedrawWindow32( hwnd
, NULL
, 0, RDW_ERASENOW
| RDW_NOCHILDREN
);
542 /***********************************************************************
543 * ExcludeUpdateRgn (USER.238) (USER32.194)
545 INT16
ExcludeUpdateRgn( HDC32 hdc
, HWND32 hwnd
)
547 INT16 retval
= ERROR
;
551 if (!(wndPtr
= WIN_FindWndPtr( hwnd
))) return ERROR
;
552 if ((hrgn
= CreateRectRgn( 0, 0, 0, 0 )) != 0)
554 retval
= CombineRgn( hrgn
, InquireVisRgn(hdc
),
555 (wndPtr
->hrgnUpdate
>1)?wndPtr
->hrgnUpdate
:0,
556 (wndPtr
->hrgnUpdate
>1)?RGN_DIFF
:RGN_COPY
);
557 if (retval
) SelectVisRgn( hdc
, hrgn
);
558 DeleteObject( hrgn
);