2 * Window painting functions
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * FIXME: Do not repaint full nonclient area all the time. Instead, compute
7 * intersection with hrgnUpdate (which should be moved from client to
8 * window coords as well, lookup 'the pain' comment in the winpos.c).
18 /* Last CTLCOLOR id */
19 #define CTLCOLOR_MAX CTLCOLOR_STATIC
21 /***********************************************************************
25 void WIN_UpdateNCArea(WND* wnd, BOOL32 bUpdate)
30 TRACE(nonclient,"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 == GetActiveWindow32()) &&
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 WINAPI 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 TRACE(win,"hrgnUpdate = %04x, \n", hrgnUpdate);
114 /* When bIcon is TRUE hrgnUpdate is automatically in window coordinates
115 * (because rectClient == rectWindow for WS_MINIMIZE windows).
118 if (wndPtr->class->style & CS_PARENTDC)
120 /* Don't clip the output to the update region for CS_PARENTDC window */
122 DeleteObject32(hrgnUpdate);
123 lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
124 (bIcon ? DCX_WINDOW : 0) );
128 lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
129 DCX_WINDOWPAINT | DCX_USESTYLE |
130 (bIcon ? DCX_WINDOW : 0) );
133 TRACE(win,"hdc = %04x\n", lps->hdc);
137 WARN(win, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
141 GetClipBox16( lps->hdc, &lps->rcPaint );
143 TRACE(win,"box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
144 lps->rcPaint.right, lps->rcPaint.bottom );
146 if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
148 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
149 lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
151 (WPARAM16)lps->hdc, 0 );
153 else lps->fErase = TRUE;
159 /***********************************************************************
160 * BeginPaint32 (USER32.10)
162 HDC32 WINAPI BeginPaint32( HWND32 hwnd, PAINTSTRUCT32 *lps )
166 BeginPaint16( hwnd, &ps );
167 lps->hdc = (HDC32)ps.hdc;
168 lps->fErase = ps.fErase;
169 lps->rcPaint.top = ps.rcPaint.top;
170 lps->rcPaint.left = ps.rcPaint.left;
171 lps->rcPaint.right = ps.rcPaint.right;
172 lps->rcPaint.bottom = ps.rcPaint.bottom;
173 lps->fRestore = ps.fRestore;
174 lps->fIncUpdate = ps.fIncUpdate;
179 /***********************************************************************
180 * EndPaint16 (USER.40)
182 BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
184 ReleaseDC16( hwnd, lps->hdc );
190 /***********************************************************************
191 * EndPaint32 (USER32.176)
193 BOOL32 WINAPI EndPaint32( HWND32 hwnd, const PAINTSTRUCT32 *lps )
195 ReleaseDC32( hwnd, lps->hdc );
201 /***********************************************************************
202 * FillWindow (USER.324)
204 void WINAPI FillWindow( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
207 GetClientRect16( hwnd, &rect );
208 DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
209 PaintRect( hwndParent, hwnd, hdc, hbrush, &rect );
213 /***********************************************************************
214 * PAINT_GetControlBrush
216 static HBRUSH16 PAINT_GetControlBrush( HWND32 hParent, HWND32 hWnd, HDC16 hDC, UINT16 ctlType )
218 HBRUSH16 bkgBrush = (HBRUSH16)SendMessage32A( hParent, WM_CTLCOLORMSGBOX + ctlType,
219 (WPARAM32)hDC, (LPARAM)hWnd );
220 if( !IsGDIObject(bkgBrush) )
221 bkgBrush = DEFWND_ControlColor( hDC, ctlType );
226 /***********************************************************************
227 * PaintRect (USER.325)
229 void WINAPI PaintRect( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
230 HBRUSH16 hbrush, const RECT16 *rect)
232 if( hbrush <= CTLCOLOR_MAX )
234 hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
238 FillRect16( hdc, rect, hbrush );
242 /***********************************************************************
243 * GetControlBrush (USER.326)
245 HBRUSH16 WINAPI GetControlBrush( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
247 WND* wndPtr = WIN_FindWndPtr( hwnd );
249 if((ctlType <= CTLCOLOR_MAX) && wndPtr )
252 if( wndPtr->dwStyle & WS_POPUP ) parent = wndPtr->owner;
253 else parent = wndPtr->parent;
254 if( !parent ) parent = wndPtr;
255 return (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
261 /***********************************************************************
264 * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
265 * SendMessage() calls. This is a comment inside DefWindowProc() source
268 * This message avoids lots of inter-app message traffic
269 * by switching to the other task and continuing the
273 * LOWORD(lParam) = hrgnClip
274 * HIWORD(lParam) = hwndSkip (not used; always NULL)
276 * All in all, a prime candidate for a rewrite.
278 BOOL32 PAINT_RedrawWindow( HWND32 hwnd, const RECT32 *rectUpdate,
279 HRGN32 hrgnUpdate, UINT32 flags, UINT32 control )
287 if (!hwnd) hwnd = GetDesktopWindow32();
288 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
289 if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
290 return TRUE; /* No redraw needed */
292 bIcon = (wndPtr->dwStyle & WS_MINIMIZE && wndPtr->class->hIcon);
295 TRACE(win, "%04x %d,%d-%d,%d %04x flags=%04x\n",
296 hwnd, rectUpdate->left, rectUpdate->top,
297 rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags );
301 TRACE(win, "%04x NULL %04x flags=%04x\n", hwnd, hrgnUpdate, flags);
304 GetClientRect32( hwnd, &rectClient );
306 if (flags & RDW_INVALIDATE) /* Invalidate */
308 int rgnNotEmpty = COMPLEXREGION;
310 if (wndPtr->hrgnUpdate > 1) /* Is there already an update region? */
312 if ((hrgn = hrgnUpdate) == 0)
313 hrgn = CreateRectRgnIndirect32( rectUpdate ? rectUpdate :
315 rgnNotEmpty = CombineRgn32( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate,
317 if (!hrgnUpdate) DeleteObject32( hrgn );
319 else /* No update region yet */
321 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
322 QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
325 wndPtr->hrgnUpdate = CreateRectRgn32( 0, 0, 0, 0 );
326 rgnNotEmpty = CombineRgn32( wndPtr->hrgnUpdate, hrgnUpdate,
329 else wndPtr->hrgnUpdate = CreateRectRgnIndirect32( rectUpdate ?
330 rectUpdate : &rectClient );
333 if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
335 /* restrict update region to client area (FIXME: correct?) */
336 if (wndPtr->hrgnUpdate)
338 HRGN32 clientRgn = CreateRectRgnIndirect32( &rectClient );
339 rgnNotEmpty = CombineRgn32( wndPtr->hrgnUpdate, clientRgn,
340 wndPtr->hrgnUpdate, RGN_AND );
341 DeleteObject32( clientRgn );
344 /* check for bogus update region */
345 if ( rgnNotEmpty == NULLREGION )
347 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
348 DeleteObject32( wndPtr->hrgnUpdate );
349 wndPtr->hrgnUpdate=0;
350 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
351 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
354 if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
355 flags |= RDW_FRAME; /* Force children frame invalidation */
357 else if (flags & RDW_VALIDATE) /* Validate */
359 /* We need an update region in order to validate anything */
360 if (wndPtr->hrgnUpdate > 1)
362 if (!hrgnUpdate && !rectUpdate)
364 /* Special case: validate everything */
365 DeleteObject32( wndPtr->hrgnUpdate );
366 wndPtr->hrgnUpdate = 0;
370 if ((hrgn = hrgnUpdate) == 0)
371 hrgn = CreateRectRgnIndirect32( rectUpdate );
372 if (CombineRgn32( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate,
373 hrgn, RGN_DIFF ) == NULLREGION)
375 DeleteObject32( wndPtr->hrgnUpdate );
376 wndPtr->hrgnUpdate = 0;
378 if (!hrgnUpdate) DeleteObject32( hrgn );
380 if (!wndPtr->hrgnUpdate) /* No more update region */
381 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
382 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
384 if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
385 if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
388 /* Set/clear internal paint flag */
390 if (flags & RDW_INTERNALPAINT)
392 if ( wndPtr->hrgnUpdate <= 1 && !(wndPtr->flags & WIN_INTERNAL_PAINT))
393 QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
394 wndPtr->flags |= WIN_INTERNAL_PAINT;
396 else if (flags & RDW_NOINTERNALPAINT)
398 if ( wndPtr->hrgnUpdate <= 1 && (wndPtr->flags & WIN_INTERNAL_PAINT))
399 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
400 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
403 /* Erase/update window */
405 if (flags & RDW_UPDATENOW)
407 if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
408 SendMessage16( hwnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
410 else if (flags & RDW_ERASENOW)
412 if (wndPtr->flags & WIN_NEEDS_NCPAINT)
413 WIN_UpdateNCArea( wndPtr, FALSE);
415 if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
417 HDC32 hdc = GetDCEx32( hwnd, wndPtr->hrgnUpdate,
418 DCX_INTERSECTRGN | DCX_USESTYLE |
419 DCX_KEEPCLIPRGN | DCX_WINDOWPAINT |
420 (bIcon ? DCX_WINDOW : 0) );
423 if (SendMessage16( hwnd, (bIcon) ? WM_ICONERASEBKGND
426 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
427 ReleaseDC32( hwnd, hdc );
432 /* Recursively process children */
434 if (!(flags & RDW_NOCHILDREN) &&
435 ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) &&
436 !(wndPtr->dwStyle & WS_MINIMIZE) )
438 if ( hrgnUpdate || rectUpdate )
440 if (!(hrgn = CreateRectRgn32( 0, 0, 0, 0 ))) return TRUE;
443 control |= (RDW_C_DELETEHRGN | RDW_C_USEHRGN);
444 if( !(hrgnUpdate = CreateRectRgnIndirect32( rectUpdate )) )
446 DeleteObject32( hrgn );
450 if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
452 for (ppWnd = list; *ppWnd; ppWnd++)
455 if (!IsWindow32(wndPtr->hwndSelf)) continue;
456 if (wndPtr->dwStyle & WS_VISIBLE)
459 wndPtr->rectWindow.left, wndPtr->rectWindow.top,
460 wndPtr->rectWindow.right, wndPtr->rectWindow.bottom );
461 if (CombineRgn32( hrgn, hrgn, hrgnUpdate, RGN_AND ))
463 OffsetRgn32( hrgn, -wndPtr->rectClient.left,
464 -wndPtr->rectClient.top );
465 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, hrgn, flags,
470 HeapFree( SystemHeap, 0, list );
472 DeleteObject32( hrgn );
473 if (control & RDW_C_DELETEHRGN) DeleteObject32( hrgnUpdate );
477 if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
479 for (ppWnd = list; *ppWnd; ppWnd++)
482 if (IsWindow32( wndPtr->hwndSelf ))
483 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, flags, 0 );
485 HeapFree( SystemHeap, 0, list );
494 /***********************************************************************
495 * RedrawWindow32 (USER32.426)
497 BOOL32 WINAPI RedrawWindow32( HWND32 hwnd, const RECT32 *rectUpdate,
498 HRGN32 hrgnUpdate, UINT32 flags )
500 return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 );
504 /***********************************************************************
505 * RedrawWindow16 (USER.290)
507 BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
508 HRGN16 hrgnUpdate, UINT16 flags )
513 CONV_RECT16TO32( rectUpdate, &r );
514 return (BOOL16)RedrawWindow32( (HWND32)hwnd, &r, hrgnUpdate, flags );
516 return (BOOL16)PAINT_RedrawWindow( (HWND32)hwnd, NULL,
517 (HRGN32)hrgnUpdate, flags, 0 );
521 /***********************************************************************
522 * UpdateWindow16 (USER.124)
524 void WINAPI UpdateWindow16( HWND16 hwnd )
526 PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
529 /***********************************************************************
530 * UpdateWindow32 (USER32.567)
532 void WINAPI UpdateWindow32( HWND32 hwnd )
534 PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
537 /***********************************************************************
538 * InvalidateRgn16 (USER.126)
540 void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
542 PAINT_RedrawWindow((HWND32)hwnd, NULL, (HRGN32)hrgn,
543 RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
547 /***********************************************************************
548 * InvalidateRgn32 (USER32.329)
550 void WINAPI InvalidateRgn32( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
552 PAINT_RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
556 /***********************************************************************
557 * InvalidateRect16 (USER.125)
559 void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
561 RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
565 /***********************************************************************
566 * InvalidateRect32 (USER32.328)
568 void WINAPI InvalidateRect32( HWND32 hwnd, const RECT32 *rect, BOOL32 erase )
570 PAINT_RedrawWindow( hwnd, rect, 0,
571 RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
575 /***********************************************************************
576 * ValidateRgn16 (USER.128)
578 void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
580 PAINT_RedrawWindow( (HWND32)hwnd, NULL, (HRGN32)hrgn,
581 RDW_VALIDATE | RDW_NOCHILDREN, 0 );
585 /***********************************************************************
586 * ValidateRgn32 (USER32.572)
588 void WINAPI ValidateRgn32( HWND32 hwnd, HRGN32 hrgn )
590 PAINT_RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
594 /***********************************************************************
595 * ValidateRect16 (USER.127)
597 void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
599 RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
603 /***********************************************************************
604 * ValidateRect32 (USER32.571)
606 void WINAPI ValidateRect32( HWND32 hwnd, const RECT32 *rect )
608 PAINT_RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
612 /***********************************************************************
613 * GetUpdateRect16 (USER.190)
615 BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
620 if (!rect) return GetUpdateRect32( hwnd, NULL, erase );
621 ret = GetUpdateRect32( hwnd, &r, erase );
622 CONV_RECT32TO16( &r, rect );
627 /***********************************************************************
628 * GetUpdateRect32 (USER32.297)
630 BOOL32 WINAPI GetUpdateRect32( HWND32 hwnd, LPRECT32 rect, BOOL32 erase )
632 WND * wndPtr = WIN_FindWndPtr( hwnd );
633 if (!wndPtr) return FALSE;
637 if (wndPtr->hrgnUpdate > 1)
639 HRGN32 hrgn = CreateRectRgn32( 0, 0, 0, 0 );
640 if (GetUpdateRgn32( hwnd, hrgn, erase ) == ERROR) return FALSE;
641 GetRgnBox32( hrgn, rect );
642 DeleteObject32( hrgn );
644 else SetRectEmpty32( rect );
646 return (wndPtr->hrgnUpdate > 1);
650 /***********************************************************************
651 * GetUpdateRgn16 (USER.237)
653 INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
655 return GetUpdateRgn32( hwnd, hrgn, erase );
659 /***********************************************************************
660 * GetUpdateRgn32 (USER32.298)
662 INT32 WINAPI GetUpdateRgn32( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
665 WND * wndPtr = WIN_FindWndPtr( hwnd );
666 if (!wndPtr) return ERROR;
668 if (wndPtr->hrgnUpdate <= 1)
670 SetRectRgn32( hrgn, 0, 0, 0, 0 );
673 retval = CombineRgn32( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
674 if (erase) RedrawWindow32( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
679 /***********************************************************************
680 * ExcludeUpdateRgn16 (USER.238)
682 INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
684 return ExcludeUpdateRgn32( hdc, hwnd );
688 /***********************************************************************
689 * ExcludeUpdateRgn32 (USER32.195)
691 INT32 WINAPI ExcludeUpdateRgn32( HDC32 hdc, HWND32 hwnd )
696 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
698 if (wndPtr->hrgnUpdate)
701 HRGN32 hrgn = CreateRectRgn32(wndPtr->rectWindow.left - wndPtr->rectClient.left,
702 wndPtr->rectWindow.top - wndPtr->rectClient.top,
703 wndPtr->rectClient.right - wndPtr->rectClient.left,
704 wndPtr->rectClient.bottom - wndPtr->rectClient.top);
705 if( wndPtr->hrgnUpdate > 1 )
706 CombineRgn32(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
708 /* do ugly coordinate translations in dce.c */
710 ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
711 DeleteObject32( hrgn );
714 return GetClipBox32( hdc, &rect );