Release 960506
[wine/multimedia.git] / windows / painting.c
blob935652358988f665b636fbb143e3a3c790d6f3ad
1 /*
2 * Window painting functions
4 * Copyright 1993, 1994, 1995 Alexandre Julliard
5 */
7 #include <stdio.h>
8 #include <X11/Xlib.h>
10 #include "win.h"
11 #include "queue.h"
12 #include "gdi.h"
13 #include "stddebug.h"
14 /* #define DEBUG_WIN */
15 #include "debug.h"
17 /* Last CTLCOLOR id */
18 #define CTLCOLOR_MAX CTLCOLOR_STATIC
20 /***********************************************************************
21 * WIN_UpdateNCArea
24 void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
26 POINT pt = {0, 0};
27 HRGN hClip = 1;
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;
36 return;
39 if( wnd->hrgnUpdate > 1 )
41 ClientToScreen(wnd->hwndSelf, &pt);
43 hClip = CreateRectRgn( 0, 0, 0, 0 );
44 if (!CombineRgn(hClip, wnd->hrgnUpdate, 0, RGN_COPY) )
46 DeleteObject(hClip);
47 hClip = 1;
49 else
50 OffsetRgn(hClip, pt.x, pt.y);
52 if (bUpdate)
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);
62 wnd->hrgnUpdate = 1;
65 DeleteObject( hrgn );
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);
76 hClip = 1;
79 if (hClip) SendMessage( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
81 if (hClip > 1) DeleteObject( hClip );
85 /***********************************************************************
86 * BeginPaint (USER.39)
88 HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lps )
90 HRGN hrgnUpdate;
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;
105 HideCaret( hwnd );
107 lps->hdc = GetDCEx( hwnd, hrgnUpdate, DCX_INTERSECTRGN | DCX_USESTYLE );
108 if(hrgnUpdate > 1) DeleteObject( hrgnUpdate );
110 if (!lps->hdc)
112 fprintf(stderr, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
113 return 0;
116 GetRgnBox( InquireVisRgn(lps->hdc), &lps->rcPaint );
117 DPtoLP( lps->hdc, (LPPOINT)&lps->rcPaint, 2 );
119 if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
121 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
122 lps->fErase = !SendMessage( hwnd, WM_ERASEBKGND, (WPARAM)lps->hdc, 0 );
124 else lps->fErase = TRUE;
126 return lps->hdc;
130 /***********************************************************************
131 * EndPaint (USER.40)
133 BOOL EndPaint( HWND hwnd, const PAINTSTRUCT* lps )
135 ReleaseDC( hwnd, lps->hdc );
136 ShowCaret( hwnd );
137 return TRUE;
141 /***********************************************************************
142 * FillWindow (USER.324)
144 void FillWindow( HWND hwndParent, HWND hwnd, HDC hdc, HBRUSH hbrush )
146 RECT rect;
147 GetClientRect( hwnd, &rect );
148 DPtoLP( hdc, (LPPOINT)&rect, 2 );
149 PaintRect( hwndParent, hwnd, hdc, hbrush, &rect );
153 /***********************************************************************
154 * PaintRect (USER.325)
156 void PaintRect(HWND hwndParent, HWND hwnd, HDC hdc, HBRUSH hbrush, LPRECT rect)
158 /* Send WM_CTLCOLOR message if needed */
160 if ((DWORD)hbrush <= CTLCOLOR_MAX)
162 if (!hwndParent) return;
163 #ifdef WINELIB32
164 hbrush = (HBRUSH)SendMessage( hwndParent,
165 WM_CTLCOLORMSGBOX+(DWORD)hbrush,
166 (WPARAM)hdc, (LPARAM)hwnd );
167 #else
168 hbrush = (HBRUSH)SendMessage( hwndParent, WM_CTLCOLOR,
169 hdc, MAKELONG( hwnd, hbrush ) );
170 #endif
172 if (hbrush) FillRect( hdc, rect, hbrush );
176 /***********************************************************************
177 * GetControlBrush (USER.326)
179 HBRUSH GetControlBrush( HWND hwnd, HDC hdc, WORD control )
181 #ifdef WINELIB32
182 return (HBRUSH)SendMessage( GetParent(hwnd), WM_CTLCOLOR+control,
183 (WPARAM)hdc, (LPARAM)hwnd );
184 #else
185 return (HBRUSH)SendMessage( GetParent(hwnd), WM_CTLCOLOR,
186 hdc, MAKELONG( hwnd, control ) );
187 #endif
191 /***********************************************************************
192 * RedrawWindow (USER.290)
194 BOOL RedrawWindow( HWND hwnd, LPRECT rectUpdate, HRGN hrgnUpdate, UINT flags )
196 HRGN hrgn;
197 RECT rectClient;
198 WND * wndPtr;
200 if (!hwnd) hwnd = GetDesktopWindow();
201 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
202 if (!IsWindowVisible(hwnd) || (wndPtr->flags & WIN_NO_REDRAW))
203 return TRUE; /* No redraw needed */
205 if (rectUpdate)
207 dprintf_win(stddeb, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
208 hwnd, rectUpdate->left, rectUpdate->top,
209 rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags );
211 else
213 dprintf_win(stddeb, "RedrawWindow: %04x NULL %04x flags=%04x\n",
214 hwnd, hrgnUpdate, flags);
216 GetClientRect( hwnd, &rectClient );
218 if (flags & RDW_INVALIDATE) /* Invalidate */
220 int rgnNotEmpty = COMPLEXREGION;
222 if (wndPtr->hrgnUpdate > 1) /* Is there already an update region? */
224 if ((hrgn = hrgnUpdate) == 0)
225 hrgn = CreateRectRgnIndirect( rectUpdate ? rectUpdate :
226 &rectClient );
227 rgnNotEmpty = CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hrgn, RGN_OR );
228 if (!hrgnUpdate) DeleteObject( hrgn );
230 else /* No update region yet */
232 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
233 QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
234 if (hrgnUpdate)
236 wndPtr->hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
237 rgnNotEmpty = CombineRgn( wndPtr->hrgnUpdate, hrgnUpdate, 0, RGN_COPY );
239 else wndPtr->hrgnUpdate = CreateRectRgnIndirect( rectUpdate ?
240 rectUpdate : &rectClient );
243 if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
245 /* check for bogus update region */
246 if ( rgnNotEmpty == NULLREGION )
248 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
249 DeleteObject(wndPtr->hrgnUpdate);
250 wndPtr->hrgnUpdate=0;
251 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
252 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
254 else
255 if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
256 flags |= RDW_FRAME; /* Force invalidating the frame of children */
258 else if (flags & RDW_VALIDATE) /* Validate */
260 /* We need an update region in order to validate anything */
261 if (wndPtr->hrgnUpdate > 1)
263 if (!hrgnUpdate && !rectUpdate)
265 /* Special case: validate everything */
266 DeleteObject( wndPtr->hrgnUpdate );
267 wndPtr->hrgnUpdate = 0;
269 else
271 if ((hrgn = hrgnUpdate) == 0)
272 hrgn = CreateRectRgnIndirect( rectUpdate );
273 if (CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate,
274 hrgn, RGN_DIFF ) == NULLREGION)
276 DeleteObject( wndPtr->hrgnUpdate );
277 wndPtr->hrgnUpdate = 0;
279 if (!hrgnUpdate) DeleteObject( hrgn );
281 if (!wndPtr->hrgnUpdate) /* No more update region */
282 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
283 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
285 if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
286 if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
289 /* Set/clear internal paint flag */
291 if (flags & RDW_INTERNALPAINT)
293 if ( wndPtr->hrgnUpdate <= 1 && !(wndPtr->flags & WIN_INTERNAL_PAINT))
294 QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
295 wndPtr->flags |= WIN_INTERNAL_PAINT;
297 else if (flags & RDW_NOINTERNALPAINT)
299 if ( wndPtr->hrgnUpdate <= 1 && (wndPtr->flags & WIN_INTERNAL_PAINT))
300 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
301 wndPtr->flags &= ~WIN_INTERNAL_PAINT;
304 /* Erase/update window */
306 if (flags & RDW_UPDATENOW)
308 if (wndPtr->hrgnUpdate) SendMessage( hwnd, WM_PAINT, 0, 0 );
310 else if (flags & RDW_ERASENOW)
312 if (wndPtr->flags & WIN_NEEDS_NCPAINT)
313 WIN_UpdateNCArea( wndPtr, FALSE);
315 if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
317 HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate,
318 DCX_INTERSECTRGN | DCX_USESTYLE );
319 if (hdc)
321 /* Don't send WM_ERASEBKGND to icons */
322 /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
323 if (!(wndPtr->dwStyle & WS_MINIMIZE) ||
324 !wndPtr->class->hIcon)
326 if (SendMessage( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ))
327 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
329 ReleaseDC( hwnd, hdc );
334 /* Recursively process children */
336 if (!(flags & RDW_NOCHILDREN) &&
337 ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)))
339 if (hrgnUpdate)
341 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
342 if (!hrgn) return TRUE;
343 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
345 CombineRgn( hrgn, hrgnUpdate, 0, RGN_COPY );
346 OffsetRgn( hrgn, -wndPtr->rectClient.left,
347 -wndPtr->rectClient.top );
348 RedrawWindow( wndPtr->hwndSelf, NULL, hrgn, flags );
350 DeleteObject( hrgn );
352 else
354 RECT rect;
355 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
357 if (rectUpdate)
359 rect = *rectUpdate;
360 OffsetRect( &rect, -wndPtr->rectClient.left,
361 -wndPtr->rectClient.top );
362 RedrawWindow( wndPtr->hwndSelf, &rect, 0, flags );
364 else RedrawWindow( wndPtr->hwndSelf, NULL, 0, flags );
368 return TRUE;
372 /***********************************************************************
373 * UpdateWindow (USER.124)
375 void UpdateWindow( HWND hwnd )
377 RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN );
381 /***********************************************************************
382 * InvalidateRgn (USER.126)
384 void InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
386 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
390 /***********************************************************************
391 * InvalidateRect (USER.125)
393 void InvalidateRect( HWND hwnd, LPRECT rect, BOOL erase )
395 RedrawWindow( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
399 /***********************************************************************
400 * ValidateRgn (USER.128)
402 void ValidateRgn( HWND hwnd, HRGN hrgn )
404 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
408 /***********************************************************************
409 * ValidateRect (USER.127)
411 void ValidateRect( HWND hwnd, LPRECT rect )
413 RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
417 /***********************************************************************
418 * GetUpdateRect (USER.190)
420 BOOL GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
422 WND * wndPtr = WIN_FindWndPtr( hwnd );
423 if (!wndPtr) return FALSE;
425 if (rect)
427 if (wndPtr->hrgnUpdate > 1)
429 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
430 if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE;
431 GetRgnBox( hrgn, rect );
432 DeleteObject( hrgn );
434 else SetRectEmpty( rect );
436 return (wndPtr->hrgnUpdate > 1);
440 /***********************************************************************
441 * GetUpdateRgn (USER.237)
443 int GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
445 int retval;
446 WND * wndPtr = WIN_FindWndPtr( hwnd );
447 if (!wndPtr) return ERROR;
449 if (wndPtr->hrgnUpdate <= 1)
451 SetRectRgn( hrgn, 0, 0, 0, 0 );
452 return NULLREGION;
454 retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
455 if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
456 return retval;
460 /***********************************************************************
461 * ExcludeUpdateRgn (USER.238)
463 int ExcludeUpdateRgn( HDC hdc, HWND hwnd )
465 int retval = ERROR;
466 HRGN hrgn;
467 WND * wndPtr;
469 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
470 if ((hrgn = CreateRectRgn( 0, 0, 0, 0 )) != 0)
472 retval = CombineRgn( hrgn, InquireVisRgn(hdc),
473 (wndPtr->hrgnUpdate>1)?wndPtr->hrgnUpdate:0,
474 (wndPtr->hrgnUpdate>1)?RGN_DIFF:RGN_COPY);
475 if (retval) SelectVisRgn( hdc, hrgn );
476 DeleteObject( hrgn );
478 return retval;