The paint rectangle return in the PAINTSTRUCT in BeginPaint should
[wine] / windows / painting.c
1 /*
2  * Window painting functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *                       1999 Alex Korobka
6  */
7
8 #include "region.h"
9 #include "win.h"
10 #include "queue.h"
11 #include "dce.h"
12 #include "heap.h"
13 #include "debugtools.h"
14 #include "wine/winuser16.h"
15
16 DECLARE_DEBUG_CHANNEL(nonclient)
17 DECLARE_DEBUG_CHANNEL(win)
18
19 /* client rect in window coordinates */
20
21 #define GETCLIENTRECTW( wnd, r )        (r).left = (wnd)->rectClient.left - (wnd)->rectWindow.left; \
22                                         (r).top = (wnd)->rectClient.top - (wnd)->rectWindow.top; \
23                                         (r).right = (wnd)->rectClient.right - (wnd)->rectWindow.left; \
24                                         (r).bottom = (wnd)->rectClient.bottom - (wnd)->rectWindow.top
25
26   /* Last CTLCOLOR id */
27 #define CTLCOLOR_MAX   CTLCOLOR_STATIC
28
29
30 /***********************************************************************
31  *           WIN_HaveToDelayNCPAINT
32  *
33  * Currently, in the Wine painting mechanism, the WM_NCPAINT message
34  * is generated as soon as a region intersecting the non-client area 
35  * of a window is invalidated.
36  *
37  * This technique will work fine for all windows whose parents
38  * have the WS_CLIPCHILDREN style. When the parents have that style,
39  * they are not going to override the contents of their children.
40  * However, when the parent doesn't have that style, Windows relies
41  * on a "painter's algorithm" to display the contents of the windows.
42  * That is, windows are painted from back to front. This includes the
43  * non-client area.
44  *
45  * This method looks at the current state of a window to determine
46  * if the sending of the WM_NCPAINT message should be delayed until 
47  * the BeginPaint call.
48  *
49  * PARAMS:
50  *   wndPtr   - A Locked window pointer to the window we're
51  *              examining.
52  *   uncFlags - This is the flag passed to the WIN_UpdateNCRgn
53  *              function. This is a shortcut for the cases when
54  *              we already know when to avoid scanning all the
55  *              parents of a window. If you already know that this
56  *              window's NCPAINT should be delayed, set the 
57  *              UNC_DELAY_NCPAINT flag for this parameter. 
58  *
59  *              This shortcut behavior is implemented in the
60  *              RDW_Paint() method.
61  * 
62  */
63 static BOOL WIN_HaveToDelayNCPAINT(
64   WND* wndPtr, 
65   UINT uncFlags)
66 {
67   WND* parentWnd = NULL;
68
69   /*
70    * Test the shortcut first. (duh)
71    */
72   if (uncFlags & UNC_DELAY_NCPAINT)
73     return TRUE;
74
75   /*
76    * The UNC_IN_BEGINPAINT flag is set in the BeginPaint
77    * method only. This is another shortcut to avoid going
78    * up the parent's chain of the window to finally
79    * figure-out that none of them has an invalid region.
80    */
81   if (uncFlags & UNC_IN_BEGINPAINT)
82     return FALSE;
83
84   /*
85    * Scan all the parents of this window to find a window
86    * that doesn't have the WS_CLIPCHILDREN style and that
87    * has an invalid region. 
88    */
89   parentWnd = WIN_LockWndPtr(wndPtr->parent);
90
91   while (parentWnd!=NULL)
92   {
93     if ( ((parentWnd->dwStyle & WS_CLIPCHILDREN) == 0) &&
94          (parentWnd->hrgnUpdate != 0) )
95     {
96       WIN_ReleaseWndPtr(parentWnd);
97       return TRUE;
98     }
99
100     WIN_UpdateWndPtr(&parentWnd, parentWnd->parent);    
101   }
102
103   WIN_ReleaseWndPtr(parentWnd);
104
105   return FALSE;
106 }
107
108 /***********************************************************************
109  *           WIN_UpdateNCRgn
110  *
111  *  Things to do:
112  *      Send WM_NCPAINT if required (when nonclient is invalid or UNC_ENTIRE flag is set)
113  *      Crop hrgnUpdate to a client rect, especially if it 1.
114  *      If UNC_REGION is set return update region for the client rect.
115  *
116  *  NOTE: UNC_REGION is mainly for the RDW_Paint() chunk that sends WM_ERASEBKGND message.
117  *        The trick is that when the returned region handle may be different from hRgn.
118  *        In this case the old hRgn must be considered gone. BUT, if the returned value
119  *        is 1 then the hRgn is preserved and RDW_Paint() will have to get 
120  *        a DC without extra clipping region.
121  */
122 HRGN WIN_UpdateNCRgn(WND* wnd, HRGN hRgn, UINT uncFlags )
123 {
124     RECT  r;
125     HRGN  hClip = 0;
126     HRGN  hrgnRet = 0;
127
128     TRACE_(nonclient)("hwnd %04x [%04x] hrgn %04x, unc %04x, ncf %i\n", 
129                       wnd->hwndSelf, wnd->hrgnUpdate, hRgn, uncFlags, wnd->flags & WIN_NEEDS_NCPAINT);
130
131     /* desktop window doesn't have a nonclient area */
132     if(wnd == WIN_GetDesktop()) 
133     {
134         wnd->flags &= ~WIN_NEEDS_NCPAINT;
135         if( wnd->hrgnUpdate > 1 )
136             hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
137         else 
138         {
139             hrgnRet = wnd->hrgnUpdate;
140         }
141         WIN_ReleaseDesktop();
142         return hrgnRet;
143     }
144     WIN_ReleaseDesktop();
145
146     if ((wnd->hwndSelf == GetForegroundWindow()) &&
147         !(wnd->flags & WIN_NCACTIVATED) )
148     {
149         wnd->flags |= WIN_NCACTIVATED;
150         uncFlags |= UNC_ENTIRE; 
151     }
152
153     /*
154      * If the window's non-client area needs to be painted, 
155      */
156     if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) &&
157          !WIN_HaveToDelayNCPAINT(wnd, uncFlags) )
158     {
159             RECT r2, r3;
160
161             wnd->flags &= ~WIN_NEEDS_NCPAINT;  
162             GETCLIENTRECTW( wnd, r );
163
164             TRACE_(nonclient)( "\tclient box (%i,%i-%i,%i), hrgnUpdate %04x\n", 
165                                 r.left, r.top, r.right, r.bottom, wnd->hrgnUpdate );
166             if( wnd->hrgnUpdate > 1 )
167             {
168                 /* Check if update rgn overlaps with nonclient area */
169
170                 GetRgnBox( wnd->hrgnUpdate, &r2 );
171                 UnionRect( &r3, &r2, &r );
172                 if( r3.left != r.left || r3.top != r.top || 
173                     r3.right != r.right || r3.bottom != r.bottom ) /* it does */
174                 {
175                     /* crop hrgnUpdate, save old one in hClip - the only
176                      * case that places a valid region handle in hClip */
177
178                     hClip = wnd->hrgnUpdate;
179                     wnd->hrgnUpdate = REGION_CropRgn( hRgn, hClip, &r, NULL );
180                     if( uncFlags & UNC_REGION ) hrgnRet = hClip;
181                 }
182
183                 if( uncFlags & UNC_CHECK )
184                 {
185                     GetRgnBox( wnd->hrgnUpdate, &r3 );
186                     if( IsRectEmpty( &r3 ) )
187                     {
188                         /* delete the update region since all invalid 
189                          * parts were in the nonclient area */
190
191                         DeleteObject( wnd->hrgnUpdate );
192                         wnd->hrgnUpdate = 0;
193                         if(!(wnd->flags & WIN_INTERNAL_PAINT))
194                             QUEUE_DecPaintCount( wnd->hmemTaskQ );
195
196                         wnd->flags &= ~WIN_NEEDS_ERASEBKGND;
197                     }
198                 }
199
200                 if(!hClip && wnd->hrgnUpdate ) goto copyrgn;
201             }
202             else 
203             if( wnd->hrgnUpdate == 1 )/* entire window */
204             {
205                 if( uncFlags & UNC_UPDATE ) wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
206                 if( uncFlags & UNC_REGION ) hrgnRet = 1;
207                 uncFlags |= UNC_ENTIRE;
208             }
209     }
210     else /* no WM_NCPAINT unless forced */
211     {
212         if( wnd->hrgnUpdate >  1 )
213         {
214 copyrgn:
215             if( uncFlags & UNC_REGION )
216                 hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
217         }
218         else
219         if( wnd->hrgnUpdate == 1 && (uncFlags & UNC_UPDATE) )
220         {
221             GETCLIENTRECTW( wnd, r ); 
222             wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
223             if( uncFlags & UNC_REGION ) hrgnRet = 1;
224         }
225     }
226
227     if(!hClip && (uncFlags & UNC_ENTIRE) )
228     {
229         /* still don't do anything if there is no nonclient area */
230         hClip = (memcmp( &wnd->rectWindow, &wnd->rectClient, sizeof(RECT) ) != 0);
231     }
232
233     if( hClip ) /* NOTE: WM_NCPAINT allows wParam to be 1 */
234     {
235         if ( hClip == hrgnRet && hrgnRet > 1 ) {
236             hClip = CreateRectRgn( 0, 0, 0, 0 );
237             CombineRgn( hClip, hrgnRet, 0, RGN_COPY );
238         }
239
240         SendMessageA( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
241         if( (hClip > 1) && (hClip != hRgn) && (hClip != hrgnRet) )
242             DeleteObject( hClip );
243         /*
244          * Since all Window locks are suspended while processing the WM_NCPAINT
245          * we want to make sure the window still exists before continuing.
246          */
247         if (!IsWindow(wnd->hwndSelf))
248         {
249           DeleteObject(hrgnRet);
250           hrgnRet=0;
251         }
252     }
253
254     TRACE_(nonclient)("returning %04x (hClip = %04x, hrgnUpdate = %04x)\n", hrgnRet, hClip, wnd->hrgnUpdate );
255
256     return hrgnRet;
257 }
258
259
260 /***********************************************************************
261  *           BeginPaint16    (USER.39)
262  */
263 HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) 
264 {
265     BOOL bIcon;
266     HRGN hrgnUpdate;
267     RECT16 clipRect, clientRect;
268     WND *wndPtr = WIN_FindWndPtr( hwnd );
269     if (!wndPtr) return 0;
270
271     bIcon = (wndPtr->dwStyle & WS_MINIMIZE && GetClassWord(wndPtr->hwndSelf, GCW_HICON));
272
273     wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
274
275     /* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */
276     WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
277
278     /*
279      * Make sure the window is still a window. All window locks are suspended
280      * when the WM_NCPAINT is sent.
281      */
282     if (!IsWindow(wndPtr->hwndSelf))
283     {
284         WIN_ReleaseWndPtr(wndPtr);
285         return 0;
286     }
287
288     if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT))
289         QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
290
291     wndPtr->hrgnUpdate = 0;
292     wndPtr->flags &= ~WIN_INTERNAL_PAINT;
293
294     HideCaret( hwnd );
295
296     TRACE_(win)("hrgnUpdate = %04x, \n", hrgnUpdate);
297
298     if (GetClassWord16(wndPtr->hwndSelf, GCW_STYLE) & CS_PARENTDC)
299     {
300         /* Don't clip the output to the update region for CS_PARENTDC window */
301         if( hrgnUpdate ) 
302             DeleteObject(hrgnUpdate);
303         lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
304                               (bIcon ? DCX_WINDOW : 0) );
305     }
306     else
307     {
308         if( hrgnUpdate ) /* convert to client coordinates */
309             OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left,
310                                    wndPtr->rectWindow.top - wndPtr->rectClient.top );
311         lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
312                              DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) );
313         /* ReleaseDC() in EndPaint() will delete the region */
314     }
315
316     TRACE_(win)("hdc = %04x\n", lps->hdc);
317
318     if (!lps->hdc)
319     {
320         WARN_(win)("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
321         WIN_ReleaseWndPtr(wndPtr);
322         return 0;
323     }
324
325     /* It is possible that the clip box is bigger than the window itself,
326        if CS_PARENTDC flag is set. Windows never return a paint rect bigger
327        than the window itself, so we need to intersect the cliprect with
328        the window  */
329     
330 /*    GetClipBox16( lps->hdc, &lps->rcPaint );*/
331     GetClipBox16( lps->hdc, &clipRect );
332     GetClientRect16( hwnd, &clientRect );
333     IntersectRect16(&lps->rcPaint, &clientRect, &clipRect);
334
335     TRACE_(win)("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
336                     lps->rcPaint.right, lps->rcPaint.bottom );
337
338     if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
339     {
340         wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
341         lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
342                                                    : WM_ERASEBKGND,
343                                      (WPARAM16)lps->hdc, 0 );
344     }
345     else lps->fErase = TRUE;
346
347     WIN_ReleaseWndPtr(wndPtr);
348     return lps->hdc;
349 }
350
351
352 /***********************************************************************
353  *           BeginPaint32    (USER32.10)
354  */
355 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
356 {
357     PAINTSTRUCT16 ps;
358
359     BeginPaint16( hwnd, &ps );
360     lps->hdc            = (HDC)ps.hdc;
361     lps->fErase         = ps.fErase;
362     lps->rcPaint.top    = ps.rcPaint.top;
363     lps->rcPaint.left   = ps.rcPaint.left;
364     lps->rcPaint.right  = ps.rcPaint.right;
365     lps->rcPaint.bottom = ps.rcPaint.bottom;
366     lps->fRestore       = ps.fRestore;
367     lps->fIncUpdate     = ps.fIncUpdate;
368     return lps->hdc;
369 }
370
371
372 /***********************************************************************
373  *           EndPaint16    (USER.40)
374  */
375 BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
376 {
377     ReleaseDC16( hwnd, lps->hdc );
378     ShowCaret( hwnd );
379     return TRUE;
380 }
381
382
383 /***********************************************************************
384  *           EndPaint32    (USER32.176)
385  */
386 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
387 {
388     ReleaseDC( hwnd, lps->hdc );
389     ShowCaret( hwnd );
390     return TRUE;
391 }
392
393
394 /***********************************************************************
395  *           FillWindow    (USER.324)
396  */
397 void WINAPI FillWindow16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
398 {
399     RECT16 rect;
400     GetClientRect16( hwnd, &rect );
401     DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
402     PaintRect16( hwndParent, hwnd, hdc, hbrush, &rect );
403 }
404
405
406 /***********************************************************************
407  *           PAINT_GetControlBrush
408  */
409 static HBRUSH16 PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC16 hDC, UINT16 ctlType )
410 {
411     HBRUSH16 bkgBrush = (HBRUSH16)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
412                                                              (WPARAM)hDC, (LPARAM)hWnd );
413     if( !IsGDIObject16(bkgBrush) )
414         bkgBrush = DEFWND_ControlColor( hDC, ctlType );
415     return bkgBrush;
416 }
417
418
419 /***********************************************************************
420  *           PaintRect    (USER.325)
421  */
422 void WINAPI PaintRect16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
423                        HBRUSH16 hbrush, const RECT16 *rect)
424 {
425     if( hbrush <= CTLCOLOR_MAX ) 
426     {
427         if( hwndParent )
428             hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
429         else 
430             return;
431     }
432     if( hbrush ) 
433         FillRect16( hdc, rect, hbrush );
434 }
435
436
437 /***********************************************************************
438  *           GetControlBrush    (USER.326)
439  */
440 HBRUSH16 WINAPI GetControlBrush16( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
441 {
442     WND* wndPtr = WIN_FindWndPtr( hwnd );
443     HBRUSH16 retvalue;
444
445     if((ctlType <= CTLCOLOR_MAX) && wndPtr )
446     {
447         WND* parent;
448         if( wndPtr->dwStyle & WS_POPUP ) parent = WIN_LockWndPtr(wndPtr->owner);
449         else parent = WIN_LockWndPtr(wndPtr->parent);
450         if( !parent ) parent = wndPtr;
451         retvalue = (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
452         WIN_ReleaseWndPtr(parent);
453         goto END;
454     }
455     retvalue = (HBRUSH16)0;
456 END:
457     WIN_ReleaseWndPtr(wndPtr);
458     return retvalue;
459 }
460
461
462 /***********************************************************************
463  *              RDW_ValidateParent [RDW_UpdateRgns() helper] 
464  *
465  *  Validate the portions of parent that are covered by a validated child
466  *  wndPtr = child
467  */
468 void  RDW_ValidateParent(WND *wndChild)  
469 {
470     WND *wndParent = WIN_LockWndPtr(wndChild->parent);
471     WND *wndDesktop = WIN_GetDesktop();
472
473     if ((wndParent) && (wndParent != wndDesktop) && !(wndParent->dwStyle & WS_CLIPCHILDREN))
474     {
475         HRGN hrg;
476         if (wndChild->hrgnUpdate == 1 )
477         {
478             RECT r;
479
480             r.left = 0;
481             r.top = 0;
482             r.right = wndChild->rectWindow.right - wndChild->rectWindow.left;
483             r.bottom = wndChild->rectWindow.bottom - wndChild->rectWindow.top;
484
485             hrg = CreateRectRgnIndirect( &r );
486         }
487         else
488            hrg = wndChild->hrgnUpdate;
489         if (wndParent->hrgnUpdate != 0)
490         {
491             POINT ptOffset;
492             RECT rect, rectParent;
493             if( wndParent->hrgnUpdate == 1 )
494             {
495                RECT r;
496
497                r.left = 0;
498                r.top = 0;
499                r.right = wndParent->rectWindow.right - wndParent->rectWindow.left;
500                r.bottom = wndParent->rectWindow.bottom - wndParent->rectWindow.top;
501
502                wndParent->hrgnUpdate = CreateRectRgnIndirect( &r );
503             }
504             /* we must offset the child region by the offset of the child rect in the parent */
505             GetWindowRect(wndParent->hwndSelf, &rectParent);
506             GetWindowRect(wndChild->hwndSelf, &rect);
507             ptOffset.x = rect.left - rectParent.left;
508             ptOffset.y = rect.top - rectParent.top;
509             OffsetRgn( hrg, ptOffset.x, ptOffset.y );
510             CombineRgn( wndParent->hrgnUpdate, wndParent->hrgnUpdate, hrg, RGN_DIFF );
511             OffsetRgn( hrg, -ptOffset.x, -ptOffset.y );
512         }
513         if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg );
514     }
515     WIN_ReleaseWndPtr(wndParent);
516     WIN_ReleaseDesktop();
517 }
518
519 /***********************************************************************
520  *              RDW_UpdateRgns [RedrawWindow() helper] 
521  *
522  *  Walks the window tree and adds/removes parts of the hRgn to/from update
523  *  regions of windows that overlap it. Also, manages internal paint flags.
524  *
525  *  NOTE: Walks the window tree so the caller must lock it.
526  *        MUST preserve hRgn (can modify but then has to restore).
527  */
528 static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel )
529 {
530     /* 
531      * Called only when one of the following is set:
532      * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
533      */
534
535     BOOL bHadOne =  wndPtr->hrgnUpdate && hRgn;
536     BOOL bChildren =  ( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
537                         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) );
538     RECT r;
539
540     r.left = 0;
541     r.top = 0;
542     r.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
543     r.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
544
545     TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags );
546
547     if( flags & RDW_INVALIDATE )
548     {
549         if( hRgn > 1 )
550         {
551             switch( wndPtr->hrgnUpdate )
552             {
553                 default:
554                         CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_OR );
555                         /* fall through */
556                 case 0:
557                         wndPtr->hrgnUpdate = REGION_CropRgn( wndPtr->hrgnUpdate, 
558                                                              wndPtr->hrgnUpdate ? wndPtr->hrgnUpdate : hRgn, 
559                                                              &r, NULL );
560                         if( !bHadOne )
561                         {
562                             GetRgnBox( wndPtr->hrgnUpdate, &r );
563                             if( IsRectEmpty( &r ) )
564                             {
565                                 DeleteObject( wndPtr->hrgnUpdate );
566                                 wndPtr->hrgnUpdate = 0;
567                                 goto OUT;
568                             }
569                         }
570                         break;
571                 case 1: /* already an entire window */
572                         break;
573             }
574         }
575         else if( hRgn == 1 )
576         {
577             if( wndPtr->hrgnUpdate > 1 )
578                 DeleteObject( wndPtr->hrgnUpdate );
579             wndPtr->hrgnUpdate = 1;
580         }
581         else
582             hRgn = wndPtr->hrgnUpdate;  /* this is a trick that depends on code in PAINT_RedrawWindow() */
583
584         if( !bHadOne && !(wndPtr->flags & WIN_INTERNAL_PAINT) )
585             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
586
587         if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
588         if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
589         flags    |= RDW_FRAME;
590     }
591     else if( flags & RDW_VALIDATE )
592     {
593         if( wndPtr->hrgnUpdate )
594         {
595             if( hRgn > 1 )
596             {
597                 if( wndPtr->hrgnUpdate == 1 )
598                     wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r );
599
600                 if( CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_DIFF )
601                     == NULLREGION )
602                     goto EMPTY;
603             }
604             else /* validate everything */
605             {
606                 if( wndPtr->hrgnUpdate > 1 )
607                 {
608 EMPTY:
609                     DeleteObject( wndPtr->hrgnUpdate );
610                 }
611                 wndPtr->hrgnUpdate = 0;
612             }
613
614             if( !wndPtr->hrgnUpdate )
615             {
616                 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
617                 if( !(wndPtr->flags & WIN_INTERNAL_PAINT) )
618                     QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
619             }
620         }
621
622         if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
623         if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
624
625     }
626
627     if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW))
628         RDW_ValidateParent(wndPtr); /* validate parent covered by region */
629
630     /* in/validate child windows that intersect with the region if it
631      * is a valid handle. */
632
633     if( flags & (RDW_INVALIDATE | RDW_VALIDATE) )
634     {
635         if( hRgn > 1 && bChildren )
636         {
637             WND* wnd = wndPtr->child;
638             POINT ptTotal, prevOrigin = {0,0};
639             POINT ptClient;
640
641             ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
642             ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
643
644             for( ptTotal.x = ptTotal.y = 0; wnd; wnd = wnd->next )
645             {
646                 if( wnd->dwStyle & WS_VISIBLE )
647                 {
648                     POINT ptOffset;
649
650                     r.left = wnd->rectWindow.left + ptClient.x;
651                     r.right = wnd->rectWindow.right + ptClient.x;
652                     r.top = wnd->rectWindow.top + ptClient.y;
653                     r.bottom = wnd->rectWindow.bottom + ptClient.y;
654
655                     ptOffset.x = r.left - prevOrigin.x; 
656                     ptOffset.y = r.top - prevOrigin.y;
657                     OffsetRect( &r, -ptTotal.x, -ptTotal.y );
658
659                     if( RectInRegion( hRgn, &r ) )
660                     {
661                         OffsetRgn( hRgn, -ptOffset.x, -ptOffset.y );
662                         RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
663                         prevOrigin.x = r.left + ptTotal.x;
664                         prevOrigin.y = r.top + ptTotal.y;
665                         ptTotal.x += ptOffset.x;
666                         ptTotal.y += ptOffset.y;
667                     }
668                 }
669             }
670             OffsetRgn( hRgn, ptTotal.x, ptTotal.y );
671             bChildren = 0;
672         }
673     }
674
675     /* handle hRgn == 1 (alias for entire window) and/or internal paint recursion */
676
677     if( bChildren )
678     {
679         WND* wnd;
680         for( wnd = wndPtr->child; wnd; wnd = wnd->next )
681              if( wnd->dwStyle & WS_VISIBLE )
682                  RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
683     }
684
685 OUT:
686
687     /* Set/clear internal paint flag */
688
689     if (flags & RDW_INTERNALPAINT)
690     {
691         if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
692             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
693         wndPtr->flags |= WIN_INTERNAL_PAINT;
694     }
695     else if (flags & RDW_NOINTERNALPAINT)
696     {
697         if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
698             QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
699         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
700     }
701 }
702
703 /***********************************************************************
704  *           RDW_Paint [RedrawWindow() helper]
705  *
706  * Walks the window tree and paints/erases windows that have
707  * nonzero update regions according to redraw flags. hrgn is a scratch
708  * region passed down during recursion. Must not be 1.
709  *
710  */
711 static HRGN RDW_Paint( WND* wndPtr, HRGN hrgn, UINT flags, UINT ex )
712 {
713 /* NOTE: wndPtr is locked by caller.
714  * 
715  * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
716  * SendMessage() calls. This is a comment inside DefWindowProc() source
717  * from 16-bit SDK:
718  *
719  *   This message avoids lots of inter-app message traffic
720  *   by switching to the other task and continuing the
721  *   recursion there.
722  *
723  * wParam         = flags
724  * LOWORD(lParam) = hrgnClip
725  * HIWORD(lParam) = hwndSkip  (not used; always NULL)
726  *
727  */
728     HDC  hDC;
729     HWND hWnd = wndPtr->hwndSelf;
730     BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassWord(wndPtr->hwndSelf, GCW_HICON)); 
731
732       /* Erase/update the window itself ... */
733
734     TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags );
735
736     /*
737      * Check if this window should delay it's processing of WM_NCPAINT.
738      * See WIN_HaveToDelayNCPAINT for a description of the mechanism
739      */
740     if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr, 0) )
741         ex |= RDW_EX_DELAY_NCPAINT;
742
743     if (flags & RDW_UPDATENOW)
744     {
745         if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
746             SendMessage16( hWnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
747     }
748     else if ((flags & RDW_ERASENOW) || (ex & RDW_EX_TOPFRAME))
749     {
750         UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
751         HRGN hrgnRet;
752
753         hrgnRet = WIN_UpdateNCRgn(wndPtr, 
754                                   hrgn, 
755                                   UNC_REGION | UNC_CHECK | 
756                                   ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
757                                   ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) ); 
758
759         if( hrgnRet )
760         {
761             if( hrgnRet > 1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */
762             if( wndPtr->flags & WIN_NEEDS_ERASEBKGND )
763             {
764                 if( bIcon ) dcx |= DCX_WINDOW;
765                 else 
766                 if( hrgnRet )
767                     OffsetRgn( hrgnRet, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
768                                         wndPtr->rectWindow.top  - wndPtr->rectClient.top);
769                 else
770                     dcx &= ~DCX_INTERSECTRGN;
771                 if (( hDC = GetDCEx( hWnd, hrgnRet, dcx )) )
772                 {
773                     if (SendMessage16( hWnd, (bIcon) ? WM_ICONERASEBKGND
774                                        : WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
775                     wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
776                     ReleaseDC( hWnd, hDC );
777                 }
778             }
779         }
780     }
781
782     if( !IsWindow(hWnd) ) return hrgn;
783     ex &= ~RDW_EX_TOPFRAME;
784
785       /* ... and its child windows */
786
787     if( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
788         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) )
789     {
790         WND** list, **ppWnd;
791
792         if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
793         {
794             wndPtr = NULL;
795             for (ppWnd = list; *ppWnd; ppWnd++)
796             {
797                 WIN_UpdateWndPtr(&wndPtr,*ppWnd);
798                 if (!IsWindow(wndPtr->hwndSelf)) continue;
799                     if ( (wndPtr->dwStyle & WS_VISIBLE) &&
800                          (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) )
801                         hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
802             }
803             WIN_ReleaseWndPtr(wndPtr);
804             WIN_ReleaseWinArray(list);
805         }
806     }
807
808     return hrgn;
809 }
810
811 /***********************************************************************
812  *           PAINT_RedrawWindow
813  *
814  */
815 BOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
816                            HRGN hrgnUpdate, UINT flags, UINT ex )
817 {
818     HRGN hRgn = 0;
819     RECT r, r2;
820     POINT pt;
821     WND* wndPtr;
822
823     if (!hwnd) hwnd = GetDesktopWindow();
824     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
825
826     /* check if the window or its parents are visible/not minimized */
827
828     if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
829     {
830         WIN_ReleaseWndPtr(wndPtr);
831         return TRUE; 
832     }
833
834     if (TRACE_ON(win))
835     {
836         if( hrgnUpdate )
837         {
838             GetRgnBox( hrgnUpdate, &r );
839             TRACE_(win)( "%04x (%04x) NULL %04x box (%i,%i-%i,%i) flags=%04x, exflags=%04x\n", 
840                   hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags, ex);
841         }
842         else
843         {
844             if( rectUpdate )
845                 r = *rectUpdate;
846             else
847                 SetRectEmpty( &r );
848             TRACE_(win)( "%04x (%04x) %s %d,%d-%d,%d %04x flags=%04x, exflags=%04x\n",
849                         hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, 
850                         r.top, r.right, r.bottom, hrgnUpdate, flags, ex );
851         }
852     }
853
854     /* prepare an update region in window coordinates */
855
856     if( flags & RDW_FRAME )
857         r = wndPtr->rectWindow;
858     else
859         r = wndPtr->rectClient;
860
861     if( ex & RDW_EX_XYWINDOW )
862     {
863         pt.x = pt.y = 0;
864         OffsetRect( &r, -wndPtr->rectWindow.left, -wndPtr->rectWindow.top );
865     }
866     else
867     {
868         pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
869         pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
870         OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top );
871     }
872
873     if (flags & RDW_INVALIDATE)  /* ------------------------- Invalidate */
874     {
875         /* If the window doesn't have hrgnUpdate we leave hRgn zero
876          * and put a new region straight into wndPtr->hrgnUpdate
877          * so that RDW_UpdateRgns() won't have to do any extra work.
878          */
879
880         if( hrgnUpdate )
881         {
882             if( wndPtr->hrgnUpdate )
883                 hRgn = REGION_CropRgn( 0, hrgnUpdate, NULL, &pt );
884             else 
885                 wndPtr->hrgnUpdate = REGION_CropRgn( 0, hrgnUpdate, &r, &pt ); 
886         }
887         else if( rectUpdate )
888         {
889             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
890             OffsetRect( &r2, pt.x, pt.y );
891
892 rect2i:
893             if( wndPtr->hrgnUpdate == 0 )
894                 wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 );
895             else
896                 hRgn = CreateRectRgnIndirect( &r2 );
897         }
898         else /* entire window or client depending on RDW_FRAME */
899         {
900             if( flags & RDW_FRAME )
901             {
902                 if( wndPtr->hrgnUpdate )
903                     DeleteObject( wndPtr->hrgnUpdate );
904                 wndPtr->hrgnUpdate = 1;
905             }
906             else
907             {
908                 GETCLIENTRECTW( wndPtr, r2 );
909                 goto rect2i;
910             }
911         }
912     }
913     else if (flags & RDW_VALIDATE)  /* ------------------------- Validate */
914     {
915         /* In this we cannot leave with zero hRgn */
916         if( hrgnUpdate )
917         {
918             hRgn = REGION_CropRgn( hRgn, hrgnUpdate,  &r, &pt );
919             GetRgnBox( hRgn, &r2 );
920             if( IsRectEmpty( &r2 ) ) goto END;
921         }
922         else if( rectUpdate )
923         {
924             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
925                 OffsetRect( &r2, pt.x, pt.y );
926 rect2v:
927             hRgn = CreateRectRgnIndirect( &r2 );
928         }
929         else /* entire window or client depending on RDW_FRAME */
930         {
931             if( flags & RDW_FRAME ) 
932                 hRgn = 1;
933             else
934             {
935                 GETCLIENTRECTW( wndPtr, r2 );
936                 goto rect2v;
937             }
938         }
939     }
940
941     /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
942
943     RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE );
944
945     /* Erase/update windows, from now on hRgn is a scratch region */
946
947     hRgn = RDW_Paint( wndPtr, (hRgn == 1) ? 0 : hRgn, flags, ex );
948
949 END:
950     if( hRgn > 1 && (hRgn != hrgnUpdate) )
951         DeleteObject(hRgn );
952     WIN_ReleaseWndPtr(wndPtr);
953     return TRUE;
954 }
955
956
957 /***********************************************************************
958  *           RedrawWindow32    (USER32.426)
959  */
960 BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate,
961                               HRGN hrgnUpdate, UINT flags )
962 {
963     return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 );
964 }
965
966
967 /***********************************************************************
968  *           RedrawWindow16    (USER.290)
969  */
970 BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
971                               HRGN16 hrgnUpdate, UINT16 flags )
972 {
973     if (rectUpdate)
974     {
975         RECT r;
976         CONV_RECT16TO32( rectUpdate, &r );
977         return (BOOL16)RedrawWindow( (HWND)hwnd, &r, hrgnUpdate, flags );
978     }
979     return (BOOL16)PAINT_RedrawWindow( (HWND)hwnd, NULL, 
980                                        (HRGN)hrgnUpdate, flags, 0 );
981 }
982
983
984 /***********************************************************************
985  *           UpdateWindow16   (USER.124)
986  */
987 void WINAPI UpdateWindow16( HWND16 hwnd )
988 {
989     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
990 }
991
992 /***********************************************************************
993  *           UpdateWindow32   (USER32.567)
994  */
995 void WINAPI UpdateWindow( HWND hwnd )
996 {
997     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
998 }
999
1000 /***********************************************************************
1001  *           InvalidateRgn16   (USER.126)
1002  */
1003 void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
1004 {
1005     PAINT_RedrawWindow((HWND)hwnd, NULL, (HRGN)hrgn, 
1006                        RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1007 }
1008
1009
1010 /***********************************************************************
1011  *           InvalidateRgn32   (USER32.329)
1012  */
1013 BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
1014 {
1015     return PAINT_RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1016 }
1017
1018
1019 /***********************************************************************
1020  *           InvalidateRect16   (USER.125)
1021  */
1022 void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
1023 {
1024     RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
1025 }
1026
1027
1028 /***********************************************************************
1029  *           InvalidateRect32   (USER32.328)
1030  */
1031 BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase )
1032 {
1033     return PAINT_RedrawWindow( hwnd, rect, 0, 
1034                                RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1035 }
1036
1037
1038 /***********************************************************************
1039  *           ValidateRgn16   (USER.128)
1040  */
1041 void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
1042 {
1043     PAINT_RedrawWindow( (HWND)hwnd, NULL, (HRGN)hrgn, 
1044                         RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1045 }
1046
1047
1048 /***********************************************************************
1049  *           ValidateRgn32   (USER32.572)
1050  */
1051 void WINAPI ValidateRgn( HWND hwnd, HRGN hrgn )
1052 {
1053     PAINT_RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1054 }
1055
1056
1057 /***********************************************************************
1058  *           ValidateRect16   (USER.127)
1059  */
1060 void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
1061 {
1062     RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
1063 }
1064
1065
1066 /***********************************************************************
1067  *           ValidateRect32   (USER32.571)
1068  */
1069 void WINAPI ValidateRect( HWND hwnd, const RECT *rect )
1070 {
1071     PAINT_RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1072 }
1073
1074
1075 /***********************************************************************
1076  *           GetUpdateRect16   (USER.190)
1077  */
1078 BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
1079 {
1080     RECT r;
1081     BOOL16 ret;
1082
1083     if (!rect) return GetUpdateRect( hwnd, NULL, erase );
1084     ret = GetUpdateRect( hwnd, &r, erase );
1085     CONV_RECT32TO16( &r, rect );
1086     return ret;
1087 }
1088
1089
1090 /***********************************************************************
1091  *           GetUpdateRect32   (USER32.297)
1092  */
1093 BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
1094 {
1095     BOOL retvalue;
1096     WND * wndPtr = WIN_FindWndPtr( hwnd );
1097     if (!wndPtr) return FALSE;
1098
1099     if (rect)
1100     {
1101         if (wndPtr->hrgnUpdate > 1)
1102         {
1103             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1104             if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR)
1105             {
1106                 retvalue = FALSE;
1107                 goto END;
1108             }
1109             GetRgnBox( hrgn, rect );
1110             DeleteObject( hrgn );
1111             if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_OWNDC)
1112             {
1113                 if (GetMapMode(wndPtr->dce->hDC) != MM_TEXT)
1114                 {
1115                     DPtoLP (wndPtr->dce->hDC, (LPPOINT)rect,  2);
1116                 }
1117             }
1118         }
1119         else
1120         if( wndPtr->hrgnUpdate == 1 )
1121         {
1122             GetClientRect( hwnd, rect );
1123             if (erase) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_ERASENOW | RDW_NOCHILDREN );
1124         }
1125         else 
1126             SetRectEmpty( rect );
1127     }
1128     retvalue = (wndPtr->hrgnUpdate >= 1);
1129 END:
1130     WIN_ReleaseWndPtr(wndPtr);
1131     return retvalue;
1132 }
1133
1134
1135 /***********************************************************************
1136  *           GetUpdateRgn16   (USER.237)
1137  */
1138 INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
1139 {
1140     return GetUpdateRgn( hwnd, hrgn, erase );
1141 }
1142
1143
1144 /***********************************************************************
1145  *           GetUpdateRgn    (USER32.298)
1146  */
1147 INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
1148 {
1149     INT retval;
1150     WND * wndPtr = WIN_FindWndPtr( hwnd );
1151     if (!wndPtr) return ERROR;
1152
1153     if (wndPtr->hrgnUpdate == 0)
1154     {
1155         SetRectRgn( hrgn, 0, 0, 0, 0 );
1156         retval = NULLREGION;
1157         goto END;
1158     }
1159     else
1160     if (wndPtr->hrgnUpdate == 1)
1161     {
1162         SetRectRgn( hrgn, 0, 0, wndPtr->rectClient.right - wndPtr->rectClient.left,
1163                                 wndPtr->rectClient.bottom - wndPtr->rectClient.top );
1164         retval = SIMPLEREGION;
1165     }
1166     else
1167     {
1168         retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
1169         OffsetRgn( hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left,
1170                          wndPtr->rectWindow.top - wndPtr->rectClient.top );
1171     }
1172     if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
1173 END:
1174     WIN_ReleaseWndPtr(wndPtr);
1175     return retval;
1176 }
1177
1178
1179 /***********************************************************************
1180  *           ExcludeUpdateRgn16   (USER.238)
1181  */
1182 INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
1183 {
1184     return ExcludeUpdateRgn( hdc, hwnd );
1185 }
1186
1187
1188 /***********************************************************************
1189  *           ExcludeUpdateRgn32   (USER32.195)
1190  */
1191 INT WINAPI ExcludeUpdateRgn( HDC hdc, HWND hwnd )
1192 {
1193     RECT rect;
1194     WND * wndPtr;
1195
1196     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
1197
1198     if (wndPtr->hrgnUpdate)
1199     {
1200         INT ret;
1201         HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left,
1202                                       wndPtr->rectWindow.top - wndPtr->rectClient.top,
1203                                       wndPtr->rectWindow.right - wndPtr->rectClient.left,
1204                                       wndPtr->rectWindow.bottom - wndPtr->rectClient.top);
1205         if( wndPtr->hrgnUpdate > 1 )
1206         {
1207             CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
1208             OffsetRgn(hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
1209                             wndPtr->rectWindow.top - wndPtr->rectClient.top );
1210         }
1211
1212         /* do ugly coordinate translations in dce.c */
1213
1214         ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
1215         DeleteObject( hrgn );
1216         WIN_ReleaseWndPtr(wndPtr);
1217         return ret;
1218     } 
1219     WIN_ReleaseWndPtr(wndPtr);
1220     return GetClipBox( hdc, &rect );
1221 }
1222
1223