Delay WM_NCPAINT message until the "painter's algorithm" kicks in.
[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         SendMessageA( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
236         if( (hClip > 1)&& (hClip != hRgn) && (hClip != hrgnRet) ) DeleteObject( hClip );
237         /*
238          * Since all Window locks are suspended while processing the WM_NCPAINT
239          * we want to make sure the window still exists before continuing.
240          */
241         if (!IsWindow(wnd->hwndSelf))
242         {
243           DeleteObject(hrgnRet);
244           hrgnRet=0;
245         }
246     }
247
248     TRACE_(nonclient)("returning %04x (hClip = %04x, hrgnUpdate = %04x)\n", hrgnRet, hClip, wnd->hrgnUpdate );
249
250     return hrgnRet;
251 }
252
253
254 /***********************************************************************
255  *           BeginPaint16    (USER.39)
256  */
257 HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) 
258 {
259     BOOL bIcon;
260     HRGN hrgnUpdate;
261     WND *wndPtr = WIN_FindWndPtr( hwnd );
262     if (!wndPtr) return 0;
263
264     bIcon = (wndPtr->dwStyle & WS_MINIMIZE && GetClassWord(wndPtr->hwndSelf, GCW_HICON));
265
266     wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
267
268     /* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */
269     WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
270
271     /*
272      * Make sure the window is still a window. All window locks are suspended
273      * when the WM_NCPAINT is sent.
274      */
275     if (!IsWindow(wndPtr->hwndSelf))
276     {
277         WIN_ReleaseWndPtr(wndPtr);
278         return 0;
279     }
280
281     if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT))
282         QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
283
284     wndPtr->hrgnUpdate = 0;
285     wndPtr->flags &= ~WIN_INTERNAL_PAINT;
286
287     HideCaret( hwnd );
288
289     TRACE_(win)("hrgnUpdate = %04x, \n", hrgnUpdate);
290
291     if (GetClassWord16(wndPtr->hwndSelf, GCW_STYLE) & CS_PARENTDC)
292     {
293         /* Don't clip the output to the update region for CS_PARENTDC window */
294         if( hrgnUpdate ) 
295             DeleteObject(hrgnUpdate);
296         lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
297                               (bIcon ? DCX_WINDOW : 0) );
298     }
299     else
300     {
301         if( hrgnUpdate ) /* convert to client coordinates */
302             OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left,
303                                    wndPtr->rectWindow.top - wndPtr->rectClient.top );
304         lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
305                              DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) );
306         /* ReleaseDC() in EndPaint() will delete the region */
307     }
308
309     TRACE_(win)("hdc = %04x\n", lps->hdc);
310
311     if (!lps->hdc)
312     {
313         WARN_(win)("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
314         WIN_ReleaseWndPtr(wndPtr);
315         return 0;
316     }
317
318     GetClipBox16( lps->hdc, &lps->rcPaint );
319
320     TRACE_(win)("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
321                     lps->rcPaint.right, lps->rcPaint.bottom );
322
323     if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
324     {
325         wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
326         lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
327                                                    : WM_ERASEBKGND,
328                                      (WPARAM16)lps->hdc, 0 );
329     }
330     else lps->fErase = TRUE;
331
332     WIN_ReleaseWndPtr(wndPtr);
333     return lps->hdc;
334 }
335
336
337 /***********************************************************************
338  *           BeginPaint32    (USER32.10)
339  */
340 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
341 {
342     PAINTSTRUCT16 ps;
343
344     BeginPaint16( hwnd, &ps );
345     lps->hdc            = (HDC)ps.hdc;
346     lps->fErase         = ps.fErase;
347     lps->rcPaint.top    = ps.rcPaint.top;
348     lps->rcPaint.left   = ps.rcPaint.left;
349     lps->rcPaint.right  = ps.rcPaint.right;
350     lps->rcPaint.bottom = ps.rcPaint.bottom;
351     lps->fRestore       = ps.fRestore;
352     lps->fIncUpdate     = ps.fIncUpdate;
353     return lps->hdc;
354 }
355
356
357 /***********************************************************************
358  *           EndPaint16    (USER.40)
359  */
360 BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
361 {
362     ReleaseDC16( hwnd, lps->hdc );
363     ShowCaret( hwnd );
364     return TRUE;
365 }
366
367
368 /***********************************************************************
369  *           EndPaint32    (USER32.176)
370  */
371 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
372 {
373     ReleaseDC( hwnd, lps->hdc );
374     ShowCaret( hwnd );
375     return TRUE;
376 }
377
378
379 /***********************************************************************
380  *           FillWindow    (USER.324)
381  */
382 void WINAPI FillWindow16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
383 {
384     RECT16 rect;
385     GetClientRect16( hwnd, &rect );
386     DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
387     PaintRect16( hwndParent, hwnd, hdc, hbrush, &rect );
388 }
389
390
391 /***********************************************************************
392  *           PAINT_GetControlBrush
393  */
394 static HBRUSH16 PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC16 hDC, UINT16 ctlType )
395 {
396     HBRUSH16 bkgBrush = (HBRUSH16)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
397                                                              (WPARAM)hDC, (LPARAM)hWnd );
398     if( !IsGDIObject16(bkgBrush) )
399         bkgBrush = DEFWND_ControlColor( hDC, ctlType );
400     return bkgBrush;
401 }
402
403
404 /***********************************************************************
405  *           PaintRect    (USER.325)
406  */
407 void WINAPI PaintRect16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
408                        HBRUSH16 hbrush, const RECT16 *rect)
409 {
410     if( hbrush <= CTLCOLOR_MAX ) 
411     {
412         if( hwndParent )
413             hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
414         else 
415             return;
416     }
417     if( hbrush ) 
418         FillRect16( hdc, rect, hbrush );
419 }
420
421
422 /***********************************************************************
423  *           GetControlBrush    (USER.326)
424  */
425 HBRUSH16 WINAPI GetControlBrush16( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
426 {
427     WND* wndPtr = WIN_FindWndPtr( hwnd );
428     HBRUSH16 retvalue;
429
430     if((ctlType <= CTLCOLOR_MAX) && wndPtr )
431     {
432         WND* parent;
433         if( wndPtr->dwStyle & WS_POPUP ) parent = WIN_LockWndPtr(wndPtr->owner);
434         else parent = WIN_LockWndPtr(wndPtr->parent);
435         if( !parent ) parent = wndPtr;
436         retvalue = (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
437         WIN_ReleaseWndPtr(parent);
438         goto END;
439     }
440     retvalue = (HBRUSH16)0;
441 END:
442     WIN_ReleaseWndPtr(wndPtr);
443     return retvalue;
444 }
445
446
447 /***********************************************************************
448  *              RDW_ValidateParent [RDW_UpdateRgns() helper] 
449  *
450  *  Validate the portions of parent that are covered by a validated child
451  *  wndPtr = child
452  */
453 void  RDW_ValidateParent(WND *wndChild)  
454 {
455     WND *wndParent = WIN_LockWndPtr(wndChild->parent);
456     WND *wndDesktop = WIN_GetDesktop();
457
458     if ((wndParent) && (wndParent != wndDesktop) && !(wndParent->dwStyle & WS_CLIPCHILDREN))
459     {
460         HRGN hrg;
461         if (wndChild->hrgnUpdate == 1 )
462         {
463             RECT r = {0, 0, wndChild->rectWindow.right - wndChild->rectWindow.left,
464                             wndChild->rectWindow.bottom - wndChild->rectWindow.top };
465             hrg = CreateRectRgnIndirect( &r );
466         }
467         else
468            hrg = wndChild->hrgnUpdate;
469         if (wndParent->hrgnUpdate != 0)
470         {
471             POINT ptOffset;
472             RECT rect, rectParent;
473             if( wndParent->hrgnUpdate == 1 )
474             {
475                RECT r = {0, 0, wndParent->rectWindow.right - wndParent->rectWindow.left,
476                             wndParent->rectWindow.bottom - wndParent->rectWindow.top };
477                wndParent->hrgnUpdate = CreateRectRgnIndirect( &r );
478             }
479             /* we must offset the child region by the offset of the child rect in the parent */
480             GetWindowRect(wndParent->hwndSelf, &rectParent);
481             GetWindowRect(wndChild->hwndSelf, &rect);
482             ptOffset.x = rect.left - rectParent.left;
483             ptOffset.y = rect.top - rectParent.top;
484             OffsetRgn( hrg, ptOffset.x, ptOffset.y );
485             CombineRgn( wndParent->hrgnUpdate, wndParent->hrgnUpdate, hrg, RGN_DIFF );
486             OffsetRgn( hrg, -ptOffset.x, -ptOffset.y );
487         }
488         if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg );
489     }
490     WIN_ReleaseWndPtr(wndParent);
491     WIN_ReleaseDesktop();
492 }
493
494 /***********************************************************************
495  *              RDW_UpdateRgns [RedrawWindow() helper] 
496  *
497  *  Walks the window tree and adds/removes parts of the hRgn to/from update
498  *  regions of windows that overlap it. Also, manages internal paint flags.
499  *
500  *  NOTE: Walks the window tree so the caller must lock it.
501  *        MUST preserve hRgn (can modify but then has to restore).
502  */
503 static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel )
504 {
505     /* 
506      * Called only when one of the following is set:
507      * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
508      */
509
510     BOOL bHadOne =  wndPtr->hrgnUpdate && hRgn;
511     BOOL bChildren =  ( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
512                         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) );
513     RECT r;
514
515     r.left = 0;
516     r.top = 0;
517     r.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
518     r.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
519
520     TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags );
521
522     if( flags & RDW_INVALIDATE )
523     {
524         if( hRgn > 1 )
525         {
526             switch( wndPtr->hrgnUpdate )
527             {
528                 default:
529                         CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_OR );
530                         /* fall through */
531                 case 0:
532                         wndPtr->hrgnUpdate = REGION_CropRgn( wndPtr->hrgnUpdate, 
533                                                              wndPtr->hrgnUpdate ? wndPtr->hrgnUpdate : hRgn, 
534                                                              &r, NULL );
535                         if( !bHadOne )
536                         {
537                             GetRgnBox( wndPtr->hrgnUpdate, &r );
538                             if( IsRectEmpty( &r ) )
539                             {
540                                 DeleteObject( wndPtr->hrgnUpdate );
541                                 wndPtr->hrgnUpdate = 0;
542                                 goto OUT;
543                             }
544                         }
545                         break;
546                 case 1: /* already an entire window */
547                         break;
548             }
549         }
550         else if( hRgn == 1 )
551         {
552             if( wndPtr->hrgnUpdate > 1 )
553                 DeleteObject( wndPtr->hrgnUpdate );
554             wndPtr->hrgnUpdate = 1;
555         }
556         else
557             hRgn = wndPtr->hrgnUpdate;  /* this is a trick that depends on code in PAINT_RedrawWindow() */
558
559         if( !bHadOne && !(wndPtr->flags & WIN_INTERNAL_PAINT) )
560             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
561
562         if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
563         if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
564         flags    |= RDW_FRAME;
565     }
566     else if( flags & RDW_VALIDATE )
567     {
568         if( wndPtr->hrgnUpdate )
569         {
570             if( hRgn > 1 )
571             {
572                 if( wndPtr->hrgnUpdate == 1 )
573                     wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r );
574
575                 if( CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_DIFF )
576                     == NULLREGION )
577                     goto EMPTY;
578             }
579             else /* validate everything */
580             {
581                 if( wndPtr->hrgnUpdate > 1 )
582                 {
583 EMPTY:
584                     DeleteObject( wndPtr->hrgnUpdate );
585                 }
586                 wndPtr->hrgnUpdate = 0;
587             }
588
589             if( !wndPtr->hrgnUpdate )
590             {
591                 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
592                 if( !(wndPtr->flags & WIN_INTERNAL_PAINT) )
593                     QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
594             }
595         }
596
597         if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
598         if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
599
600     }
601
602     if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW))
603         RDW_ValidateParent(wndPtr); /* validate parent covered by region */
604
605     /* in/validate child windows that intersect with the region if it
606      * is a valid handle. */
607
608     if( flags & (RDW_INVALIDATE | RDW_VALIDATE) )
609     {
610         if( hRgn > 1 && bChildren )
611         {
612             WND* wnd = wndPtr->child;
613             POINT ptTotal, prevOrigin = {0,0};
614             POINT ptClient;
615
616             ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
617             ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
618
619             for( ptTotal.x = ptTotal.y = 0; wnd; wnd = wnd->next )
620             {
621                 if( wnd->dwStyle & WS_VISIBLE )
622                 {
623                     POINT ptOffset;
624
625                     r.left = wnd->rectWindow.left + ptClient.x;
626                     r.right = wnd->rectWindow.right + ptClient.x;
627                     r.top = wnd->rectWindow.top + ptClient.y;
628                     r.bottom = wnd->rectWindow.bottom + ptClient.y;
629
630                     ptOffset.x = r.left - prevOrigin.x; 
631                     ptOffset.y = r.top - prevOrigin.y;
632                     OffsetRect( &r, -ptTotal.x, -ptTotal.y );
633
634                     if( RectInRegion( hRgn, &r ) )
635                     {
636                         OffsetRgn( hRgn, -ptOffset.x, -ptOffset.y );
637                         RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
638                         prevOrigin.x = r.left + ptTotal.x;
639                         prevOrigin.y = r.top + ptTotal.y;
640                         ptTotal.x += ptOffset.x;
641                         ptTotal.y += ptOffset.y;
642                     }
643                 }
644             }
645             OffsetRgn( hRgn, ptTotal.x, ptTotal.y );
646             bChildren = 0;
647         }
648     }
649
650     /* handle hRgn == 1 (alias for entire window) and/or internal paint recursion */
651
652     if( bChildren )
653     {
654         WND* wnd;
655         for( wnd = wndPtr->child; wnd; wnd = wnd->next )
656              if( wnd->dwStyle & WS_VISIBLE )
657                  RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
658     }
659
660 OUT:
661
662     /* Set/clear internal paint flag */
663
664     if (flags & RDW_INTERNALPAINT)
665     {
666         if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
667             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
668         wndPtr->flags |= WIN_INTERNAL_PAINT;
669     }
670     else if (flags & RDW_NOINTERNALPAINT)
671     {
672         if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
673             QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
674         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
675     }
676 }
677
678 /***********************************************************************
679  *           RDW_Paint [RedrawWindow() helper]
680  *
681  * Walks the window tree and paints/erases windows that have
682  * nonzero update regions according to redraw flags. hrgn is a scratch
683  * region passed down during recursion. Must not be 1.
684  *
685  */
686 static HRGN RDW_Paint( WND* wndPtr, HRGN hrgn, UINT flags, UINT ex )
687 {
688 /* NOTE: wndPtr is locked by caller.
689  * 
690  * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
691  * SendMessage() calls. This is a comment inside DefWindowProc() source
692  * from 16-bit SDK:
693  *
694  *   This message avoids lots of inter-app message traffic
695  *   by switching to the other task and continuing the
696  *   recursion there.
697  *
698  * wParam         = flags
699  * LOWORD(lParam) = hrgnClip
700  * HIWORD(lParam) = hwndSkip  (not used; always NULL)
701  *
702  */
703     HDC  hDC;
704     HWND hWnd = wndPtr->hwndSelf;
705     BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassWord(wndPtr->hwndSelf, GCW_HICON)); 
706
707       /* Erase/update the window itself ... */
708
709     TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags );
710
711     /*
712      * Check if this window should delay it's processing of WM_NCPAINT.
713      * See WIN_HaveToDelayNCPAINT for a description of the mechanism
714      */
715     if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr, 0) )
716         ex |= RDW_EX_DELAY_NCPAINT;
717
718     if (flags & RDW_UPDATENOW)
719     {
720         if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
721             SendMessage16( hWnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
722     }
723     else if ((flags & RDW_ERASENOW) || (ex & RDW_EX_TOPFRAME))
724     {
725         UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
726         HRGN hrgnRet;
727
728         hrgnRet = WIN_UpdateNCRgn(wndPtr, 
729                                   hrgn, 
730                                   UNC_REGION | UNC_CHECK | 
731                                   ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
732                                   ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) ); 
733
734         if( hrgnRet )
735         {
736             if( hrgnRet > 1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */
737             if( wndPtr->flags & WIN_NEEDS_ERASEBKGND )
738             {
739                 if( bIcon ) dcx |= DCX_WINDOW;
740                 else 
741                 if( hrgnRet )
742                     OffsetRgn( hrgnRet, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
743                                         wndPtr->rectWindow.top  - wndPtr->rectClient.top);
744                 else
745                     dcx &= ~DCX_INTERSECTRGN;
746                 if (( hDC = GetDCEx( hWnd, hrgnRet, dcx )) )
747                 {
748                     if (SendMessage16( hWnd, (bIcon) ? WM_ICONERASEBKGND
749                                        : WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
750                     wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
751                     ReleaseDC( hWnd, hDC );
752                 }
753             }
754         }
755     }
756
757     if( !IsWindow(hWnd) ) return hrgn;
758     ex &= ~RDW_EX_TOPFRAME;
759
760       /* ... and its child windows */
761
762     if( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
763         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) )
764     {
765         WND** list, **ppWnd;
766
767         if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
768         {
769             wndPtr = NULL;
770             for (ppWnd = list; *ppWnd; ppWnd++)
771             {
772                 WIN_UpdateWndPtr(&wndPtr,*ppWnd);
773                 if (!IsWindow(wndPtr->hwndSelf)) continue;
774                     if ( (wndPtr->dwStyle & WS_VISIBLE) &&
775                          (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) )
776                         hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
777             }
778             WIN_ReleaseWndPtr(wndPtr);
779             WIN_ReleaseWinArray(list);
780         }
781     }
782
783     return hrgn;
784 }
785
786 /***********************************************************************
787  *           PAINT_RedrawWindow
788  *
789  */
790 BOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
791                            HRGN hrgnUpdate, UINT flags, UINT ex )
792 {
793     HRGN hRgn = 0;
794     RECT r, r2;
795     POINT pt;
796     WND* wndPtr;
797
798     if (!hwnd) hwnd = GetDesktopWindow();
799     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
800
801     /* check if the window or its parents are visible/not minimized */
802
803     if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
804     {
805         WIN_ReleaseWndPtr(wndPtr);
806         return TRUE; 
807     }
808
809     if (TRACE_ON(win))
810     {
811         if( hrgnUpdate )
812         {
813             GetRgnBox( hrgnUpdate, &r );
814             TRACE_(win)( "%04x (%04x) NULL %04x box (%i,%i-%i,%i) flags=%04x, exflags=%04x\n", 
815                   hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags, ex);
816         }
817         else
818         {
819             if( rectUpdate )
820                 r = *rectUpdate;
821             else
822                 SetRectEmpty( &r );
823             TRACE_(win)( "%04x (%04x) %s %d,%d-%d,%d %04x flags=%04x, exflags=%04x\n",
824                         hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, 
825                         r.top, r.right, r.bottom, hrgnUpdate, flags, ex );
826         }
827     }
828
829     /* prepare an update region in window coordinates */
830
831     if( flags & RDW_FRAME )
832         r = wndPtr->rectWindow;
833     else
834         r = wndPtr->rectClient;
835
836     if( ex & RDW_EX_XYWINDOW )
837     {
838         pt.x = pt.y = 0;
839         OffsetRect( &r, -wndPtr->rectWindow.left, -wndPtr->rectWindow.top );
840     }
841     else
842     {
843         pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
844         pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
845         OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top );
846     }
847
848     if (flags & RDW_INVALIDATE)  /* ------------------------- Invalidate */
849     {
850         /* If the window doesn't have hrgnUpdate we leave hRgn zero
851          * and put a new region straight into wndPtr->hrgnUpdate
852          * so that RDW_UpdateRgns() won't have to do any extra work.
853          */
854
855         if( hrgnUpdate )
856         {
857             if( wndPtr->hrgnUpdate )
858                 hRgn = REGION_CropRgn( 0, hrgnUpdate, NULL, &pt );
859             else 
860                 wndPtr->hrgnUpdate = REGION_CropRgn( 0, hrgnUpdate, &r, &pt ); 
861         }
862         else if( rectUpdate )
863         {
864             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
865             OffsetRect( &r2, pt.x, pt.y );
866
867 rect2i:
868             if( wndPtr->hrgnUpdate == 0 )
869                 wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 );
870             else
871                 hRgn = CreateRectRgnIndirect( &r2 );
872         }
873         else /* entire window or client depending on RDW_FRAME */
874         {
875             if( flags & RDW_FRAME )
876             {
877                 if( wndPtr->hrgnUpdate )
878                     DeleteObject( wndPtr->hrgnUpdate );
879                 wndPtr->hrgnUpdate = 1;
880             }
881             else
882             {
883                 GETCLIENTRECTW( wndPtr, r2 );
884                 goto rect2i;
885             }
886         }
887     }
888     else if (flags & RDW_VALIDATE)  /* ------------------------- Validate */
889     {
890         /* In this we cannot leave with zero hRgn */
891         if( hrgnUpdate )
892         {
893             hRgn = REGION_CropRgn( hRgn, hrgnUpdate,  &r, &pt );
894             GetRgnBox( hRgn, &r2 );
895             if( IsRectEmpty( &r2 ) ) goto END;
896         }
897         else if( rectUpdate )
898         {
899             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
900                 OffsetRect( &r2, pt.x, pt.y );
901 rect2v:
902             hRgn = CreateRectRgnIndirect( &r2 );
903         }
904         else /* entire window or client depending on RDW_FRAME */
905         {
906             if( flags & RDW_FRAME ) 
907                 hRgn = 1;
908             else
909             {
910                 GETCLIENTRECTW( wndPtr, r2 );
911                 goto rect2v;
912             }
913         }
914     }
915
916     /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
917
918     RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE );
919
920     /* Erase/update windows, from now on hRgn is a scratch region */
921
922     hRgn = RDW_Paint( wndPtr, (hRgn == 1) ? 0 : hRgn, flags, ex );
923
924 END:
925     if( hRgn > 1 && (hRgn != hrgnUpdate) )
926         DeleteObject(hRgn );
927     WIN_ReleaseWndPtr(wndPtr);
928     return TRUE;
929 }
930
931
932 /***********************************************************************
933  *           RedrawWindow32    (USER32.426)
934  */
935 BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate,
936                               HRGN hrgnUpdate, UINT flags )
937 {
938     return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 );
939 }
940
941
942 /***********************************************************************
943  *           RedrawWindow16    (USER.290)
944  */
945 BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
946                               HRGN16 hrgnUpdate, UINT16 flags )
947 {
948     if (rectUpdate)
949     {
950         RECT r;
951         CONV_RECT16TO32( rectUpdate, &r );
952         return (BOOL16)RedrawWindow( (HWND)hwnd, &r, hrgnUpdate, flags );
953     }
954     return (BOOL16)PAINT_RedrawWindow( (HWND)hwnd, NULL, 
955                                        (HRGN)hrgnUpdate, flags, 0 );
956 }
957
958
959 /***********************************************************************
960  *           UpdateWindow16   (USER.124)
961  */
962 void WINAPI UpdateWindow16( HWND16 hwnd )
963 {
964     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
965 }
966
967 /***********************************************************************
968  *           UpdateWindow32   (USER32.567)
969  */
970 void WINAPI UpdateWindow( HWND hwnd )
971 {
972     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
973 }
974
975 /***********************************************************************
976  *           InvalidateRgn16   (USER.126)
977  */
978 void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
979 {
980     PAINT_RedrawWindow((HWND)hwnd, NULL, (HRGN)hrgn, 
981                        RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
982 }
983
984
985 /***********************************************************************
986  *           InvalidateRgn32   (USER32.329)
987  */
988 BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
989 {
990     return PAINT_RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
991 }
992
993
994 /***********************************************************************
995  *           InvalidateRect16   (USER.125)
996  */
997 void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
998 {
999     RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
1000 }
1001
1002
1003 /***********************************************************************
1004  *           InvalidateRect32   (USER32.328)
1005  */
1006 BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase )
1007 {
1008     return PAINT_RedrawWindow( hwnd, rect, 0, 
1009                                RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1010 }
1011
1012
1013 /***********************************************************************
1014  *           ValidateRgn16   (USER.128)
1015  */
1016 void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
1017 {
1018     PAINT_RedrawWindow( (HWND)hwnd, NULL, (HRGN)hrgn, 
1019                         RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1020 }
1021
1022
1023 /***********************************************************************
1024  *           ValidateRgn32   (USER32.572)
1025  */
1026 void WINAPI ValidateRgn( HWND hwnd, HRGN hrgn )
1027 {
1028     PAINT_RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1029 }
1030
1031
1032 /***********************************************************************
1033  *           ValidateRect16   (USER.127)
1034  */
1035 void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
1036 {
1037     RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
1038 }
1039
1040
1041 /***********************************************************************
1042  *           ValidateRect32   (USER32.571)
1043  */
1044 void WINAPI ValidateRect( HWND hwnd, const RECT *rect )
1045 {
1046     PAINT_RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1047 }
1048
1049
1050 /***********************************************************************
1051  *           GetUpdateRect16   (USER.190)
1052  */
1053 BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
1054 {
1055     RECT r;
1056     BOOL16 ret;
1057
1058     if (!rect) return GetUpdateRect( hwnd, NULL, erase );
1059     ret = GetUpdateRect( hwnd, &r, erase );
1060     CONV_RECT32TO16( &r, rect );
1061     return ret;
1062 }
1063
1064
1065 /***********************************************************************
1066  *           GetUpdateRect32   (USER32.297)
1067  */
1068 BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
1069 {
1070     BOOL retvalue;
1071     WND * wndPtr = WIN_FindWndPtr( hwnd );
1072     if (!wndPtr) return FALSE;
1073
1074     if (rect)
1075     {
1076         if (wndPtr->hrgnUpdate > 1)
1077         {
1078             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1079             if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR)
1080             {
1081                 retvalue = FALSE;
1082                 goto END;
1083             }
1084             GetRgnBox( hrgn, rect );
1085             DeleteObject( hrgn );
1086             if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_OWNDC)
1087             {
1088                 if (GetMapMode(wndPtr->dce->hDC) != MM_TEXT)
1089                 {
1090                     DPtoLP (wndPtr->dce->hDC, (LPPOINT)rect,  2);
1091                 }
1092             }
1093         }
1094         else
1095         if( wndPtr->hrgnUpdate == 1 )
1096         {
1097             GetClientRect( hwnd, rect );
1098             if (erase) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_ERASENOW | RDW_NOCHILDREN );
1099         }
1100         else 
1101             SetRectEmpty( rect );
1102     }
1103     retvalue = (wndPtr->hrgnUpdate >= 1);
1104 END:
1105     WIN_ReleaseWndPtr(wndPtr);
1106     return retvalue;
1107 }
1108
1109
1110 /***********************************************************************
1111  *           GetUpdateRgn16   (USER.237)
1112  */
1113 INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
1114 {
1115     return GetUpdateRgn( hwnd, hrgn, erase );
1116 }
1117
1118
1119 /***********************************************************************
1120  *           GetUpdateRgn    (USER32.298)
1121  */
1122 INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
1123 {
1124     INT retval;
1125     WND * wndPtr = WIN_FindWndPtr( hwnd );
1126     if (!wndPtr) return ERROR;
1127
1128     if (wndPtr->hrgnUpdate == 0)
1129     {
1130         SetRectRgn( hrgn, 0, 0, 0, 0 );
1131         retval = NULLREGION;
1132         goto END;
1133     }
1134     else
1135     if (wndPtr->hrgnUpdate == 1)
1136     {
1137         SetRectRgn( hrgn, 0, 0, wndPtr->rectClient.right - wndPtr->rectClient.left,
1138                                 wndPtr->rectClient.bottom - wndPtr->rectClient.top );
1139         retval = SIMPLEREGION;
1140     }
1141     else
1142     {
1143         retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
1144         OffsetRgn( hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left,
1145                          wndPtr->rectWindow.top - wndPtr->rectClient.top );
1146     }
1147     if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
1148 END:
1149     WIN_ReleaseWndPtr(wndPtr);
1150     return retval;
1151 }
1152
1153
1154 /***********************************************************************
1155  *           ExcludeUpdateRgn16   (USER.238)
1156  */
1157 INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
1158 {
1159     return ExcludeUpdateRgn( hdc, hwnd );
1160 }
1161
1162
1163 /***********************************************************************
1164  *           ExcludeUpdateRgn32   (USER32.195)
1165  */
1166 INT WINAPI ExcludeUpdateRgn( HDC hdc, HWND hwnd )
1167 {
1168     RECT rect;
1169     WND * wndPtr;
1170
1171     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
1172
1173     if (wndPtr->hrgnUpdate)
1174     {
1175         INT ret;
1176         HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left,
1177                                       wndPtr->rectWindow.top - wndPtr->rectClient.top,
1178                                       wndPtr->rectWindow.right - wndPtr->rectClient.left,
1179                                       wndPtr->rectWindow.bottom - wndPtr->rectClient.top);
1180         if( wndPtr->hrgnUpdate > 1 )
1181         {
1182             CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
1183             OffsetRgn(hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
1184                             wndPtr->rectWindow.top - wndPtr->rectClient.top );
1185         }
1186
1187         /* do ugly coordinate translations in dce.c */
1188
1189         ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
1190         DeleteObject( hrgn );
1191         WIN_ReleaseWndPtr(wndPtr);
1192         return ret;
1193     } 
1194     WIN_ReleaseWndPtr(wndPtr);
1195     return GetClipBox( hdc, &rect );
1196 }
1197
1198