Release 960521
[wine.git] / windows / painting.c
blob10bdb97372432a07c691c591448566423ed17bbf
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 POINT16 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 ClientToScreen16(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) 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 )
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 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;
126 return lps->hdc;
130 /***********************************************************************
131 * BeginPaint32 (USER32.9)
133 HDC32 BeginPaint32( HWND32 hwnd, PAINTSTRUCT32 *lps )
135 PAINTSTRUCT16 ps;
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;
146 return lps->hdc;
150 /***********************************************************************
151 * EndPaint16 (USER.40)
153 BOOL16 EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
155 ReleaseDC( hwnd, lps->hdc );
156 ShowCaret( hwnd );
157 return TRUE;
161 /***********************************************************************
162 * EndPaint32 (USER32.175)
164 BOOL32 EndPaint32( HWND32 hwnd, const PAINTSTRUCT32 *lps )
166 ReleaseDC( hwnd, (HDC16)lps->hdc );
167 ShowCaret( hwnd );
168 return TRUE;
172 /***********************************************************************
173 * FillWindow (USER.324)
175 void FillWindow( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
177 RECT16 rect;
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;
195 #ifdef WINELIB32
196 hbrush = (HBRUSH)SendMessage32A( hwndParent,
197 WM_CTLCOLORMSGBOX+(DWORD)hbrush,
198 (WPARAM)hdc, (LPARAM)hwnd );
199 #else
200 hbrush = (HBRUSH)SendMessage16( hwndParent, WM_CTLCOLOR,
201 hdc, MAKELONG( hwnd, hbrush ) );
202 #endif
204 if (hbrush) FillRect16( hdc, rect, hbrush );
208 /***********************************************************************
209 * GetControlBrush (USER.326)
211 HBRUSH GetControlBrush( HWND hwnd, HDC hdc, WORD control )
213 #ifdef WINELIB32
214 return (HBRUSH)SendMessage32A( GetParent(hwnd), WM_CTLCOLOR+control,
215 (WPARAM)hdc, (LPARAM)hwnd );
216 #else
217 return (HBRUSH)SendMessage16( GetParent(hwnd), WM_CTLCOLOR,
218 hdc, MAKELONG( hwnd, control ) );
219 #endif
223 /***********************************************************************
224 * RedrawWindow32 (USER32.425)
226 BOOL32 RedrawWindow32( HWND32 hwnd, const RECT32 *rectUpdate,
227 HRGN32 hrgnUpdate, UINT32 flags )
229 HRGN hrgn;
230 RECT32 rectClient;
231 WND * wndPtr;
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 */
238 if (rectUpdate)
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 );
244 else
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 :
259 &rectClient );
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 );
267 if (hrgnUpdate)
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 );
287 else
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;
302 else
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 );
352 if (hdc)
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)))
372 if (hrgnUpdate)
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 );
385 else
387 RECT32 rect;
388 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
390 if (rectUpdate)
392 rect = *rectUpdate;
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 );
401 return TRUE;
405 /***********************************************************************
406 * RedrawWindow16 (USER.290)
408 BOOL16 RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
409 HRGN16 hrgnUpdate, UINT16 flags )
411 if (rectUpdate)
413 RECT32 r;
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 )
489 RECT32 r;
490 BOOL16 ret;
492 if (!rect) return GetUpdateRect32( hwnd, NULL, erase );
493 ret = GetUpdateRect32( hwnd, &r, erase );
494 CONV_RECT32TO16( &r, rect );
495 return ret;
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;
507 if (rect)
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 )
527 INT16 retval;
528 WND * wndPtr = WIN_FindWndPtr( hwnd );
529 if (!wndPtr) return ERROR;
531 if (wndPtr->hrgnUpdate <= 1)
533 SetRectRgn( hrgn, 0, 0, 0, 0 );
534 return NULLREGION;
536 retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
537 if (erase) RedrawWindow32( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
538 return retval;
542 /***********************************************************************
543 * ExcludeUpdateRgn (USER.238) (USER32.194)
545 INT16 ExcludeUpdateRgn( HDC32 hdc, HWND32 hwnd )
547 INT16 retval = ERROR;
548 HRGN hrgn;
549 WND * wndPtr;
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 );
560 return retval;