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 if (wndPtr->class->style & CS_PARENTDC)
119 /* Don't clip the output to the update region for CS_PARENTDC window */
120 lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
121 (bIcon ? DCX_WINDOW : 0) );
123 lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
124 DCX_WINDOWPAINT | DCX_USESTYLE |
125 (bIcon ? DCX_WINDOW : 0) );
127 dprintf_win(stddeb,"hdc = %04x\n", lps->hdc);
131 fprintf(stderr, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
135 GetRgnBox16( InquireVisRgn(lps->hdc), &lps->rcPaint );
136 DPtoLP16( lps->hdc, (LPPOINT16)&lps->rcPaint, 2 );
138 if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
140 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
141 lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
143 (WPARAM16)lps->hdc, 0 );
145 else lps->fErase = TRUE;
151 /***********************************************************************
152 * BeginPaint32 (USER32.9)
154 HDC32 BeginPaint32( HWND32 hwnd, PAINTSTRUCT32 *lps )
158 BeginPaint16( hwnd, &ps );
159 lps->hdc = (HDC32)ps.hdc;
160 lps->fErase = ps.fErase;
161 lps->rcPaint.top = ps.rcPaint.top;
162 lps->rcPaint.left = ps.rcPaint.left;
163 lps->rcPaint.right = ps.rcPaint.right;
164 lps->rcPaint.bottom = ps.rcPaint.bottom;
165 lps->fRestore = ps.fRestore;
166 lps->fIncUpdate = ps.fIncUpdate;
171 /***********************************************************************
172 * EndPaint16 (USER.40)
174 BOOL16 EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
176 ReleaseDC16( hwnd, lps->hdc );
182 /***********************************************************************
183 * EndPaint32 (USER32.175)
185 BOOL32 EndPaint32( HWND32 hwnd, const PAINTSTRUCT32 *lps )
187 ReleaseDC32( hwnd, lps->hdc );
193 /***********************************************************************
194 * FillWindow (USER.324)
196 void FillWindow( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
199 GetClientRect16( hwnd, &rect );
200 DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
201 PaintRect( hwndParent, hwnd, hdc, hbrush, &rect );
205 /***********************************************************************
206 * PaintRect (USER.325)
208 void PaintRect( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
209 HBRUSH16 hbrush, const RECT16 *rect)
211 /* Send WM_CTLCOLOR message if needed */
213 if ((UINT32)hbrush <= CTLCOLOR_MAX)
215 if (!hwndParent) return;
216 hbrush = (HBRUSH16)SendMessage32A( hwndParent,
217 WM_CTLCOLORMSGBOX + (UINT32)hbrush,
218 (WPARAM32)hdc, (LPARAM)hwnd );
220 if (hbrush) FillRect16( hdc, rect, hbrush );
224 /***********************************************************************
225 * GetControlBrush (USER.326)
227 HBRUSH16 GetControlBrush( HWND hwnd, HDC16 hdc, WORD control )
229 return (HBRUSH16)SendMessage32A( GetParent32(hwnd), WM_CTLCOLOR+control,
230 (WPARAM32)hdc, (LPARAM)hwnd );
234 /***********************************************************************
237 * Note: Windows uses WM_SYNCPAINT to cut down the number of intertask
238 * SendMessage() calls. From SDK:
239 * This message avoids lots of inter-app message traffic
240 * by switching to the other task and continuing the
244 * LOWORD(lParam) = hrgnClip
245 * HIWORD(lParam) = hwndSkip (not used; always NULL)
247 BOOL32 PAINT_RedrawWindow( HWND32 hwnd, const RECT32 *rectUpdate,
248 HRGN32 hrgnUpdate, UINT32 flags, UINT32 control )
255 if (!hwnd) hwnd = GetDesktopWindow32();
256 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
257 if (!IsWindowVisible(hwnd) || (wndPtr->flags & WIN_NO_REDRAW))
258 return TRUE; /* No redraw needed */
260 bIcon = (wndPtr->dwStyle & WS_MINIMIZE && wndPtr->class->hIcon);
263 dprintf_win(stddeb, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
264 hwnd, rectUpdate->left, rectUpdate->top,
265 rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags );
269 dprintf_win(stddeb, "RedrawWindow: %04x NULL %04x flags=%04x\n",
270 hwnd, hrgnUpdate, flags);
273 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 SetRectRgn( hrgn, wndPtr->rectWindow.left,
414 wndPtr->rectWindow.top,
415 wndPtr->rectWindow.right,
416 wndPtr->rectWindow.bottom );
417 if (!CombineRgn32( hrgn, hrgn, hrgnUpdate, RGN_AND ))
419 OffsetRgn32( hrgn, -wndPtr->rectClient.left,
420 -wndPtr->rectClient.top );
421 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, hrgn, flags,
424 DeleteObject32( hrgn );
425 if (control & RDW_C_DELETEHRGN) DeleteObject32( hrgnUpdate );
427 else for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
428 PAINT_RedrawWindow( wndPtr->hwndSelf, NULL, 0, flags, 0 );
435 /***********************************************************************
436 * RedrawWindow32 (USER32.425)
438 BOOL32 RedrawWindow32( HWND32 hwnd, const RECT32 *rectUpdate,
439 HRGN32 hrgnUpdate, UINT32 flags )
441 WND* wnd = WIN_FindWndPtr( hwnd );
443 /* check if there is something to redraw */
445 return ( wnd && WIN_IsWindowDrawable( wnd, !(flags & RDW_FRAME) ) )
446 ? PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 )
451 /***********************************************************************
452 * RedrawWindow16 (USER.290)
454 BOOL16 RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
455 HRGN16 hrgnUpdate, UINT16 flags )
460 CONV_RECT16TO32( rectUpdate, &r );
461 return (BOOL16)RedrawWindow32( (HWND32)hwnd, &r, hrgnUpdate, flags );
463 return (BOOL16)RedrawWindow32( (HWND32)hwnd, NULL, hrgnUpdate, flags );
467 /***********************************************************************
468 * UpdateWindow (USER.124) (USER32.566)
470 void UpdateWindow( HWND32 hwnd )
472 RedrawWindow32( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN );
476 /***********************************************************************
477 * InvalidateRgn (USER.126) (USER32.328)
479 void InvalidateRgn( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
481 RedrawWindow32(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
485 /***********************************************************************
486 * InvalidateRect16 (USER.125)
488 void InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
490 RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
494 /***********************************************************************
495 * InvalidateRect32 (USER32.327)
497 void InvalidateRect32( HWND32 hwnd, const RECT32 *rect, BOOL32 erase )
499 RedrawWindow32( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
503 /***********************************************************************
504 * ValidateRgn (USER.128) (USER32.571)
506 void ValidateRgn( HWND32 hwnd, HRGN32 hrgn )
508 RedrawWindow32( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
512 /***********************************************************************
513 * ValidateRect16 (USER.127)
515 void ValidateRect16( HWND16 hwnd, const RECT16 *rect )
517 RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
521 /***********************************************************************
522 * ValidateRect32 (USER32.570)
524 void ValidateRect32( HWND32 hwnd, const RECT32 *rect )
526 RedrawWindow32( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
530 /***********************************************************************
531 * GetUpdateRect16 (USER.190)
533 BOOL16 GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
538 if (!rect) return GetUpdateRect32( hwnd, NULL, erase );
539 ret = GetUpdateRect32( hwnd, &r, erase );
540 CONV_RECT32TO16( &r, rect );
545 /***********************************************************************
546 * GetUpdateRect32 (USER32.296)
548 BOOL32 GetUpdateRect32( HWND32 hwnd, LPRECT32 rect, BOOL32 erase )
550 WND * wndPtr = WIN_FindWndPtr( hwnd );
551 if (!wndPtr) return FALSE;
555 if (wndPtr->hrgnUpdate > 1)
557 HRGN32 hrgn = CreateRectRgn32( 0, 0, 0, 0 );
558 if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE;
559 GetRgnBox32( hrgn, rect );
560 DeleteObject32( hrgn );
562 else SetRectEmpty32( rect );
564 return (wndPtr->hrgnUpdate > 1);
568 /***********************************************************************
569 * GetUpdateRgn (USER.237) (USER32.297)
571 INT16 GetUpdateRgn( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
574 WND * wndPtr = WIN_FindWndPtr( hwnd );
575 if (!wndPtr) return ERROR;
577 if (wndPtr->hrgnUpdate <= 1)
579 SetRectRgn( hrgn, 0, 0, 0, 0 );
582 retval = CombineRgn32( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
583 if (erase) RedrawWindow32( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
588 /***********************************************************************
589 * ExcludeUpdateRgn (USER.238) (USER32.194)
591 INT16 ExcludeUpdateRgn( HDC32 hdc, HWND32 hwnd )
596 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
598 if (wndPtr->hrgnUpdate)
601 HRGN32 hrgn = CreateRectRgn32(wndPtr->rectWindow.left - wndPtr->rectClient.left,
602 wndPtr->rectWindow.top - wndPtr->rectClient.top,
603 wndPtr->rectClient.right - wndPtr->rectClient.left,
604 wndPtr->rectClient.bottom - wndPtr->rectClient.top);
605 if( wndPtr->hrgnUpdate > 1 )
606 CombineRgn32(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
608 /* do ugly coordinate translations in dce.c */
610 ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
611 DeleteObject32( hrgn );
614 return GetClipBox16(hdc, &rect);