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