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