Release 941030
[wine] / windows / painting.c
1 /*
2  * Window painting functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include <X11/Xlib.h>
10
11 #include "win.h"
12 #include "message.h"
13 #include "gdi.h"
14
15   /* Last CTLCOLOR id */
16 #define CTLCOLOR_MAX   CTLCOLOR_STATIC
17
18
19 /***********************************************************************
20  *           BeginPaint    (USER.39)
21  */
22 HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lps ) 
23 {
24     HRGN hrgnUpdate;
25     WND * wndPtr = WIN_FindWndPtr( hwnd );
26     if (!wndPtr) return 0;
27
28     hrgnUpdate = wndPtr->hrgnUpdate;  /* Save update region */
29     if (!hrgnUpdate)    /* Create an empty region */
30         if (!(hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 ))) return 0;
31     
32     if (!(lps->hdc = GetDCEx( hwnd, hrgnUpdate,
33                               DCX_INTERSECTRGN | DCX_USESTYLE ))) return 0;
34     GetRgnBox( InquireVisRgn(lps->hdc), &lps->rcPaint );
35
36     if (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT))
37         MSG_DecPaintCount( wndPtr->hmemTaskQ );
38
39     wndPtr->hrgnUpdate = 0;
40     wndPtr->flags &= ~(WIN_NEEDS_BEGINPAINT | WIN_INTERNAL_PAINT);
41
42     SendMessage( hwnd, WM_NCPAINT, hrgnUpdate, 0 );
43     DeleteObject( hrgnUpdate );
44
45     if (!(wndPtr->flags & WIN_ERASE_UPDATERGN)) lps->fErase = TRUE;
46     else lps->fErase = !SendMessage( hwnd, WM_ERASEBKGND, lps->hdc, 0 );
47
48     return lps->hdc;
49 }
50
51
52 /***********************************************************************
53  *           EndPaint    (USER.40)
54  */
55 void EndPaint( HWND hwnd, LPPAINTSTRUCT lps )
56 {
57     ReleaseDC( hwnd, lps->hdc );
58 }
59
60
61 /***********************************************************************
62  *           FillWindow    (USER.324)
63  */
64 void FillWindow( HWND hwndParent, HWND hwnd, HDC hdc, HBRUSH hbrush )
65 {
66     RECT rect;
67     GetClientRect( hwnd, &rect );
68     PaintRect( hwndParent, hwnd, hdc, hbrush, &rect );
69 }
70
71
72 /***********************************************************************
73  *           PaintRect    (USER.325)
74  */
75 void PaintRect(HWND hwndParent, HWND hwnd, HDC hdc, HBRUSH hbrush, LPRECT rect)
76 {
77       /* Send WM_CTLCOLOR message if needed */
78
79     if (hbrush <= CTLCOLOR_MAX)
80     {
81         if (!hwndParent) return;
82         hbrush = (HBRUSH)SendMessage( hwndParent, WM_CTLCOLOR,
83                                       hdc, hwnd | (hbrush << 16) );
84     }
85     if (hbrush) FillRect( hdc, rect, hbrush );
86 }
87
88
89 /***********************************************************************
90  *           RedrawWindow    (USER.290)
91  */
92 BOOL RedrawWindow( HWND hwnd, LPRECT rectUpdate, HRGN hrgnUpdate, UINT flags )
93 {
94     HRGN tmpRgn, hrgn = 0;
95     RECT rectClient, rectWindow;
96     WND * wndPtr;
97
98     if (!hwnd) hwnd = GetDesktopWindow();
99     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
100     if (!(wndPtr->dwStyle & WS_VISIBLE) || (wndPtr->flags & WIN_NO_REDRAW))
101         return TRUE;  /* No redraw needed */
102
103     GetClientRect( hwnd, &rectClient );
104     rectWindow = wndPtr->rectWindow;
105     OffsetRect(&rectWindow, -wndPtr->rectClient.left, -wndPtr->rectClient.top);
106
107     if (flags & RDW_INVALIDATE)  /* Invalidate */
108     {
109         if (flags & RDW_ERASE) wndPtr->flags |= WIN_ERASE_UPDATERGN;
110
111         if (hrgnUpdate)  /* Invalidate a region */
112         {
113             if (flags & RDW_FRAME) tmpRgn = CreateRectRgnIndirect(&rectWindow);
114             else tmpRgn = CreateRectRgnIndirect( &rectClient );
115             if (!tmpRgn) return FALSE;
116             hrgn = CreateRectRgn( 0, 0, 0, 0 );
117             if (CombineRgn( hrgn, hrgnUpdate, tmpRgn, RGN_AND ) == NULLREGION)
118             {
119                 DeleteObject( hrgn );
120                 hrgn = 0;
121             }
122             DeleteObject( tmpRgn );
123         }
124         else  /* Invalidate a rectangle */
125         {
126             RECT rect;
127             if (flags & RDW_FRAME)
128             {
129                 if (rectUpdate) IntersectRect( &rect, rectUpdate, &rectWindow);
130                 else rect = rectWindow;
131             }
132             else
133             {
134                 if (rectUpdate) IntersectRect( &rect, rectUpdate, &rectClient);
135                 else rect = rectClient;
136             }
137             if (!IsRectEmpty(&rect)) hrgn = CreateRectRgnIndirect( &rect );
138         }
139
140           /* Set update region */
141
142         if (hrgn)
143         {
144             if (!wndPtr->hrgnUpdate)
145             {
146                 wndPtr->hrgnUpdate = hrgn;
147                 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
148                     MSG_IncPaintCount( wndPtr->hmemTaskQ );
149             }
150             else
151             {
152                 tmpRgn = CreateRectRgn( 0, 0, 0, 0 );
153                 CombineRgn( tmpRgn, wndPtr->hrgnUpdate, hrgn, RGN_OR );
154                 DeleteObject( wndPtr->hrgnUpdate );
155                 DeleteObject( hrgn );
156                 wndPtr->hrgnUpdate = tmpRgn;
157             }
158         }
159         flags |= RDW_FRAME;  /* Force invalidating the frame of children */
160     }
161     else if (flags & RDW_VALIDATE)  /* Validate */
162     {
163         if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_ERASE_UPDATERGN;
164         if (!(hrgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
165
166           /* Remove frame from update region */
167
168         if (wndPtr->hrgnUpdate && (flags & RDW_NOFRAME))
169         {
170             if (!(tmpRgn = CreateRectRgnIndirect( &rectClient )))
171                 return FALSE;
172             if (CombineRgn(hrgn,tmpRgn,wndPtr->hrgnUpdate,RGN_AND) == NULLREGION)
173             {
174                 DeleteObject( hrgn );
175                 hrgn = 0;
176             }
177             DeleteObject( tmpRgn );
178             DeleteObject( wndPtr->hrgnUpdate );
179             wndPtr->hrgnUpdate = hrgn;
180             hrgn = CreateRectRgn( 0, 0, 0, 0 );
181         }
182
183           /* Set update region */
184
185         if (wndPtr->hrgnUpdate)
186         {
187             int res;
188             if (hrgnUpdate)  /* Validate a region */
189             {
190                 res = CombineRgn(hrgn,wndPtr->hrgnUpdate,hrgnUpdate,RGN_DIFF);
191             }
192             else  /* Validate a rectangle */
193             {
194                 if (rectUpdate) tmpRgn = CreateRectRgnIndirect( rectUpdate );
195                 else tmpRgn = CreateRectRgnIndirect( &rectWindow );
196                 res = CombineRgn( hrgn, wndPtr->hrgnUpdate, tmpRgn, RGN_DIFF );
197                 DeleteObject( tmpRgn );
198             }
199             DeleteObject( wndPtr->hrgnUpdate );
200             if (res == NULLREGION)
201             {
202                 DeleteObject( hrgn );
203                 wndPtr->hrgnUpdate = 0;
204                 if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
205                     MSG_DecPaintCount( wndPtr->hmemTaskQ );
206             }
207             else wndPtr->hrgnUpdate = hrgn;
208         }
209     }
210
211       /* Set/clear internal paint flag */
212
213     if (flags & RDW_INTERNALPAINT)
214     {
215         if (!wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
216             MSG_IncPaintCount( wndPtr->hmemTaskQ );
217         wndPtr->flags |= WIN_INTERNAL_PAINT;        
218     }
219     else if (flags & RDW_NOINTERNALPAINT)
220     {
221         if (!wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
222             MSG_DecPaintCount( wndPtr->hmemTaskQ );
223         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
224     }
225
226       /* Erase/update window */
227
228     if (flags & RDW_UPDATENOW) UpdateWindow( hwnd );
229     else if (flags & RDW_ERASENOW)
230     {
231         HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate,
232                            DCX_INTERSECTRGN | DCX_USESTYLE );
233         if (hdc)
234         {
235             SendMessage( hwnd, WM_NCPAINT, wndPtr->hrgnUpdate, 0 );
236
237               /* Don't send WM_ERASEBKGND to icons */
238               /* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
239             if (!(wndPtr->dwStyle & WS_MINIMIZE)
240                 || !WIN_CLASS_INFO(wndPtr).hIcon)
241                 SendMessage( hwnd, WM_ERASEBKGND, hdc, 0 );
242             ReleaseDC( hwnd, hdc );
243         }
244     }
245
246       /* Recursively process children */
247
248     if (!(flags & RDW_NOCHILDREN) &&
249         ((flags && RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)))
250     {
251         if (hrgnUpdate)
252         {
253             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
254             if (!hrgn) return TRUE;
255             for (hwnd = wndPtr->hwndChild; (hwnd); hwnd = wndPtr->hwndNext)
256             {
257                 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) break;
258                 CombineRgn( hrgn, hrgnUpdate, 0, RGN_COPY );
259                 OffsetRgn( hrgn, -wndPtr->rectClient.left,
260                                  -wndPtr->rectClient.top );
261                 RedrawWindow( hwnd, NULL, hrgn, flags );
262             }
263             DeleteObject( hrgn );
264         }
265         else
266         {
267             RECT rect;          
268             for (hwnd = wndPtr->hwndChild; (hwnd); hwnd = wndPtr->hwndNext)
269             {
270                 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) break;
271                 if (rectUpdate)
272                 {
273                     rect = *rectUpdate;
274                     OffsetRect( &rect, -wndPtr->rectClient.left,
275                                        -wndPtr->rectClient.top );
276                     RedrawWindow( hwnd, &rect, 0, flags );
277                 }
278                 else RedrawWindow( hwnd, NULL, 0, flags );
279             }
280         }
281     }
282     return TRUE;
283 }
284
285
286 /***********************************************************************
287  *           UpdateWindow   (USER.124)
288  */
289 void UpdateWindow( HWND hwnd )
290 {
291     if (GetUpdateRect( hwnd, NULL, FALSE )) 
292     {
293         if (IsWindowVisible( hwnd )) SendMessage( hwnd, WM_PAINT, 0, 0 );
294     }
295 }
296
297
298 /***********************************************************************
299  *           InvalidateRgn   (USER.126)
300  */
301 void InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
302 {
303     RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
304 }
305
306
307 /***********************************************************************
308  *           InvalidateRect   (USER.125)
309  */
310 void InvalidateRect( HWND hwnd, LPRECT rect, BOOL erase )
311 {
312     RedrawWindow( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
313 }
314
315
316 /***********************************************************************
317  *           ValidateRgn   (USER.128)
318  */
319 void ValidateRgn( HWND hwnd, HRGN hrgn )
320 {
321     RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
322 }
323
324
325 /***********************************************************************
326  *           ValidateRect   (USER.127)
327  */
328 void ValidateRect( HWND hwnd, LPRECT rect )
329 {
330     RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
331 }
332
333
334 /***********************************************************************
335  *           GetUpdateRect   (USER.190)
336  */
337 BOOL GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
338 {
339     WND * wndPtr = WIN_FindWndPtr( hwnd );
340     if (!wndPtr) return FALSE;
341
342     if (rect)
343     {
344         if (wndPtr->hrgnUpdate)
345         {
346             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
347             if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE;
348             GetRgnBox( hrgn, rect );
349             DeleteObject( hrgn );
350         }
351         else SetRectEmpty( rect );
352     }
353     return (wndPtr->hrgnUpdate != 0);
354 }
355
356
357 /***********************************************************************
358  *           GetUpdateRgn   (USER.237)
359  */
360 int GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
361 {
362     HRGN hrgnClip;
363     int retval;
364     WND * wndPtr = WIN_FindWndPtr( hwnd );
365     if (!wndPtr) return ERROR;
366
367     if (!wndPtr->hrgnUpdate)
368     {
369         if (!(hrgnClip = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR;
370         retval = CombineRgn( hrgn, hrgnClip, 0, RGN_COPY );
371     }
372     else
373     {
374         hrgnClip = CreateRectRgn( 0, 0,
375                            wndPtr->rectClient.right-wndPtr->rectClient.left,
376                            wndPtr->rectClient.bottom-wndPtr->rectClient.top );
377         if (!hrgnClip) return ERROR;
378         retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, hrgnClip, RGN_AND );
379         if (erase)
380         {
381             HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate,
382                               DCX_INTERSECTRGN | DCX_USESTYLE );
383             if (hdc)
384             {
385                 SendMessage( hwnd, WM_ERASEBKGND, hdc, 0 );
386                 ReleaseDC( hwnd, hdc );
387             }
388         }       
389     }
390     DeleteObject( hrgnClip );
391     return retval;
392 }
393
394
395 /***********************************************************************
396  *           ExcludeUpdateRgn   (USER.238)
397  */
398 int ExcludeUpdateRgn( HDC hdc, HWND hwnd )
399 {
400     int retval = ERROR;
401     HRGN hrgn;
402     WND * wndPtr;
403
404     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
405     if ((hrgn = CreateRectRgn( 0, 0, 0, 0 )) != 0)
406     {
407         retval = CombineRgn( hrgn, InquireVisRgn(hdc),
408                              wndPtr->hrgnUpdate, RGN_DIFF );
409         if (retval) SelectVisRgn( hdc, hrgn );
410         DeleteObject( hrgn );
411     }
412     return retval;
413 }
414
415