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