Make use of the DEFAULT_DEBUG_CHANNEL where appropriate.
[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 #include "cache.h"
16
17 DEFAULT_DEBUG_CHANNEL(win)
18 DECLARE_DEBUG_CHANNEL(nonclient)
19
20 /* client rect in window coordinates */
21
22 #define GETCLIENTRECTW( wnd, r )        (r).left = (wnd)->rectClient.left - (wnd)->rectWindow.left; \
23                                         (r).top = (wnd)->rectClient.top - (wnd)->rectWindow.top; \
24                                         (r).right = (wnd)->rectClient.right - (wnd)->rectWindow.left; \
25                                         (r).bottom = (wnd)->rectClient.bottom - (wnd)->rectWindow.top
26
27   /* Last CTLCOLOR id */
28 #define CTLCOLOR_MAX   CTLCOLOR_STATIC
29
30
31 /***********************************************************************
32  *           WIN_HaveToDelayNCPAINT
33  *
34  * Currently, in the Wine painting mechanism, the WM_NCPAINT message
35  * is generated as soon as a region intersecting the non-client area 
36  * of a window is invalidated.
37  *
38  * This technique will work fine for all windows whose parents
39  * have the WS_CLIPCHILDREN style. When the parents have that style,
40  * they are not going to override the contents of their children.
41  * However, when the parent doesn't have that style, Windows relies
42  * on a "painter's algorithm" to display the contents of the windows.
43  * That is, windows are painted from back to front. This includes the
44  * non-client area.
45  *
46  * This method looks at the current state of a window to determine
47  * if the sending of the WM_NCPAINT message should be delayed until 
48  * the BeginPaint call.
49  *
50  * PARAMS:
51  *   wndPtr   - A Locked window pointer to the window we're
52  *              examining.
53  *   uncFlags - This is the flag passed to the WIN_UpdateNCRgn
54  *              function. This is a shortcut for the cases when
55  *              we already know when to avoid scanning all the
56  *              parents of a window. If you already know that this
57  *              window's NCPAINT should be delayed, set the 
58  *              UNC_DELAY_NCPAINT flag for this parameter. 
59  *
60  *              This shortcut behavior is implemented in the
61  *              RDW_Paint() method.
62  * 
63  */
64 static BOOL WIN_HaveToDelayNCPAINT(
65   WND* wndPtr, 
66   UINT uncFlags)
67 {
68   WND* parentWnd = NULL;
69
70   /*
71    * Test the shortcut first. (duh)
72    */
73   if (uncFlags & UNC_DELAY_NCPAINT)
74     return TRUE;
75
76   /*
77    * The UNC_IN_BEGINPAINT flag is set in the BeginPaint
78    * method only. This is another shortcut to avoid going
79    * up the parent's chain of the window to finally
80    * figure-out that none of them has an invalid region.
81    */
82   if (uncFlags & UNC_IN_BEGINPAINT)
83     return FALSE;
84
85   /*
86    * Scan all the parents of this window to find a window
87    * that doesn't have the WS_CLIPCHILDREN style and that
88    * has an invalid region. 
89    */
90   parentWnd = WIN_LockWndPtr(wndPtr->parent);
91
92   while (parentWnd!=NULL)
93   {
94     if ( ((parentWnd->dwStyle & WS_CLIPCHILDREN) == 0) &&
95          (parentWnd->hrgnUpdate != 0) )
96     {
97       WIN_ReleaseWndPtr(parentWnd);
98       return TRUE;
99     }
100
101     WIN_UpdateWndPtr(&parentWnd, parentWnd->parent);    
102   }
103
104   WIN_ReleaseWndPtr(parentWnd);
105
106   return FALSE;
107 }
108
109 /***********************************************************************
110  *           WIN_UpdateNCRgn
111  *
112  *  Things to do:
113  *      Send WM_NCPAINT if required (when nonclient is invalid or UNC_ENTIRE flag is set)
114  *      Crop hrgnUpdate to a client rect, especially if it 1.
115  *      If UNC_REGION is set return update region for the client rect.
116  *
117  *  NOTE: UNC_REGION is mainly for the RDW_Paint() chunk that sends WM_ERASEBKGND message.
118  *        The trick is that when the returned region handle may be different from hRgn.
119  *        In this case the old hRgn must be considered gone. BUT, if the returned value
120  *        is 1 then the hRgn is preserved and RDW_Paint() will have to get 
121  *        a DC without extra clipping region.
122  */
123 HRGN WIN_UpdateNCRgn(WND* wnd, HRGN hRgn, UINT uncFlags )
124 {
125     RECT  r;
126     HRGN  hClip = 0;
127     HRGN  hrgnRet = 0;
128
129     TRACE_(nonclient)("hwnd %04x [%04x] hrgn %04x, unc %04x, ncf %i\n", 
130                       wnd->hwndSelf, wnd->hrgnUpdate, hRgn, uncFlags, wnd->flags & WIN_NEEDS_NCPAINT);
131
132     /* desktop window doesn't have a nonclient area */
133     if(wnd == WIN_GetDesktop()) 
134     {
135         wnd->flags &= ~WIN_NEEDS_NCPAINT;
136         if( wnd->hrgnUpdate > 1 )
137             hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
138         else 
139         {
140             hrgnRet = wnd->hrgnUpdate;
141         }
142         WIN_ReleaseDesktop();
143         return hrgnRet;
144     }
145     WIN_ReleaseDesktop();
146
147     if ((wnd->hwndSelf == GetForegroundWindow()) &&
148         !(wnd->flags & WIN_NCACTIVATED) )
149     {
150         wnd->flags |= WIN_NCACTIVATED;
151         uncFlags |= UNC_ENTIRE; 
152     }
153
154     /*
155      * If the window's non-client area needs to be painted, 
156      */
157     if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) &&
158          !WIN_HaveToDelayNCPAINT(wnd, uncFlags) )
159     {
160             RECT r2, r3;
161
162             wnd->flags &= ~WIN_NEEDS_NCPAINT;  
163             GETCLIENTRECTW( wnd, r );
164
165             TRACE_(nonclient)( "\tclient box (%i,%i-%i,%i), hrgnUpdate %04x\n", 
166                                 r.left, r.top, r.right, r.bottom, wnd->hrgnUpdate );
167             if( wnd->hrgnUpdate > 1 )
168             {
169                 /* Check if update rgn overlaps with nonclient area */
170
171                 GetRgnBox( wnd->hrgnUpdate, &r2 );
172                 UnionRect( &r3, &r2, &r );
173                 if( r3.left != r.left || r3.top != r.top || 
174                     r3.right != r.right || r3.bottom != r.bottom ) /* it does */
175                 {
176                     /* crop hrgnUpdate, save old one in hClip - the only
177                      * case that places a valid region handle in hClip */
178
179                     hClip = wnd->hrgnUpdate;
180                     wnd->hrgnUpdate = REGION_CropRgn( hRgn, hClip, &r, NULL );
181                     if( uncFlags & UNC_REGION ) hrgnRet = hClip;
182                 }
183
184                 if( uncFlags & UNC_CHECK )
185                 {
186                     GetRgnBox( wnd->hrgnUpdate, &r3 );
187                     if( IsRectEmpty( &r3 ) )
188                     {
189                         /* delete the update region since all invalid 
190                          * parts were in the nonclient area */
191
192                         DeleteObject( wnd->hrgnUpdate );
193                         wnd->hrgnUpdate = 0;
194                         if(!(wnd->flags & WIN_INTERNAL_PAINT))
195                             QUEUE_DecPaintCount( wnd->hmemTaskQ );
196
197                         wnd->flags &= ~WIN_NEEDS_ERASEBKGND;
198                     }
199                 }
200
201                 if(!hClip && wnd->hrgnUpdate ) goto copyrgn;
202             }
203             else 
204             if( wnd->hrgnUpdate == 1 )/* entire window */
205             {
206                 if( uncFlags & UNC_UPDATE ) wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
207                 if( uncFlags & UNC_REGION ) hrgnRet = 1;
208                 uncFlags |= UNC_ENTIRE;
209             }
210     }
211     else /* no WM_NCPAINT unless forced */
212     {
213         if( wnd->hrgnUpdate >  1 )
214         {
215 copyrgn:
216             if( uncFlags & UNC_REGION )
217                 hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
218         }
219         else
220         if( wnd->hrgnUpdate == 1 && (uncFlags & UNC_UPDATE) )
221         {
222             GETCLIENTRECTW( wnd, r ); 
223             wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
224             if( uncFlags & UNC_REGION ) hrgnRet = 1;
225         }
226     }
227
228     if(!hClip && (uncFlags & UNC_ENTIRE) )
229     {
230         /* still don't do anything if there is no nonclient area */
231         hClip = (memcmp( &wnd->rectWindow, &wnd->rectClient, sizeof(RECT) ) != 0);
232     }
233
234     if( hClip ) /* NOTE: WM_NCPAINT allows wParam to be 1 */
235     {
236         if ( hClip == hrgnRet && hrgnRet > 1 ) {
237             hClip = CreateRectRgn( 0, 0, 0, 0 );
238             CombineRgn( hClip, hrgnRet, 0, RGN_COPY );
239         }
240
241         SendMessageA( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
242         if( (hClip > 1) && (hClip != hRgn) && (hClip != hrgnRet) )
243             DeleteObject( hClip );
244         /*
245          * Since all Window locks are suspended while processing the WM_NCPAINT
246          * we want to make sure the window still exists before continuing.
247          */
248         if (!IsWindow(wnd->hwndSelf))
249         {
250           DeleteObject(hrgnRet);
251           hrgnRet=0;
252         }
253     }
254
255     TRACE_(nonclient)("returning %04x (hClip = %04x, hrgnUpdate = %04x)\n", hrgnRet, hClip, wnd->hrgnUpdate );
256
257     return hrgnRet;
258 }
259
260
261 /***********************************************************************
262  *           BeginPaint16    (USER.39)
263  */
264 HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) 
265 {
266     BOOL bIcon;
267     HRGN hrgnUpdate;
268     RECT16 clipRect, clientRect;
269     WND *wndPtr = WIN_FindWndPtr( hwnd );
270     if (!wndPtr) return 0;
271
272     bIcon = (wndPtr->dwStyle & WS_MINIMIZE && GetClassWord(wndPtr->hwndSelf, GCW_HICON));
273
274     wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
275
276     /* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */
277     WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
278
279     /*
280      * Make sure the window is still a window. All window locks are suspended
281      * when the WM_NCPAINT is sent.
282      */
283     if (!IsWindow(wndPtr->hwndSelf))
284     {
285         WIN_ReleaseWndPtr(wndPtr);
286         return 0;
287     }
288
289     if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT))
290         QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
291
292     wndPtr->hrgnUpdate = 0;
293     wndPtr->flags &= ~WIN_INTERNAL_PAINT;
294
295     HideCaret( hwnd );
296
297     TRACE("hrgnUpdate = %04x, \n", hrgnUpdate);
298
299     if (GetClassWord16(wndPtr->hwndSelf, GCW_STYLE) & CS_PARENTDC)
300     {
301         /* Don't clip the output to the update region for CS_PARENTDC window */
302         if( hrgnUpdate ) 
303             DeleteObject(hrgnUpdate);
304         lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
305                               (bIcon ? DCX_WINDOW : 0) );
306     }
307     else
308     {
309         if( hrgnUpdate ) /* convert to client coordinates */
310             OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left,
311                                    wndPtr->rectWindow.top - wndPtr->rectClient.top );
312         lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
313                              DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) );
314         /* ReleaseDC() in EndPaint() will delete the region */
315     }
316
317     TRACE("hdc = %04x\n", lps->hdc);
318
319     if (!lps->hdc)
320     {
321         WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
322         WIN_ReleaseWndPtr(wndPtr);
323         return 0;
324     }
325
326     /* It is possible that the clip box is bigger than the window itself,
327        if CS_PARENTDC flag is set. Windows never return a paint rect bigger
328        than the window itself, so we need to intersect the cliprect with
329        the window  */
330     
331     GetClipBox16( lps->hdc, &clipRect );
332     GetClientRect16( hwnd, &clientRect );
333
334     /* The rect obtained by GetClipBox is in logical, so make the client in logical to*/
335     DPtoLP16(lps->hdc, (LPPOINT16) &clientRect, 2);    
336
337     IntersectRect16(&lps->rcPaint, &clientRect, &clipRect);
338
339     TRACE("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
340                     lps->rcPaint.right, lps->rcPaint.bottom );
341
342     if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
343     {
344         wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
345         lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
346                                                    : WM_ERASEBKGND,
347                                      (WPARAM16)lps->hdc, 0 );
348     }
349     else lps->fErase = TRUE;
350
351     WIN_ReleaseWndPtr(wndPtr);
352     return lps->hdc;
353 }
354
355
356 /***********************************************************************
357  *           BeginPaint32    (USER32.10)
358  */
359 HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
360 {
361     PAINTSTRUCT16 ps;
362
363     BeginPaint16( hwnd, &ps );
364     lps->hdc            = (HDC)ps.hdc;
365     lps->fErase         = ps.fErase;
366     lps->rcPaint.top    = ps.rcPaint.top;
367     lps->rcPaint.left   = ps.rcPaint.left;
368     lps->rcPaint.right  = ps.rcPaint.right;
369     lps->rcPaint.bottom = ps.rcPaint.bottom;
370     lps->fRestore       = ps.fRestore;
371     lps->fIncUpdate     = ps.fIncUpdate;
372     return lps->hdc;
373 }
374
375
376 /***********************************************************************
377  *           EndPaint16    (USER.40)
378  */
379 BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
380 {
381     ReleaseDC16( hwnd, lps->hdc );
382     ShowCaret( hwnd );
383     return TRUE;
384 }
385
386
387 /***********************************************************************
388  *           EndPaint32    (USER32.176)
389  */
390 BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
391 {
392     ReleaseDC( hwnd, lps->hdc );
393     ShowCaret( hwnd );
394     return TRUE;
395 }
396
397
398 /***********************************************************************
399  *           FillWindow    (USER.324)
400  */
401 void WINAPI FillWindow16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
402 {
403     RECT16 rect;
404     GetClientRect16( hwnd, &rect );
405     DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
406     PaintRect16( hwndParent, hwnd, hdc, hbrush, &rect );
407 }
408
409
410 /***********************************************************************
411  *           PAINT_GetControlBrush
412  */
413 static HBRUSH16 PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC16 hDC, UINT16 ctlType )
414 {
415     HBRUSH16 bkgBrush = (HBRUSH16)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
416                                                              (WPARAM)hDC, (LPARAM)hWnd );
417     if( !IsGDIObject16(bkgBrush) )
418         bkgBrush = DEFWND_ControlColor( hDC, ctlType );
419     return bkgBrush;
420 }
421
422
423 /***********************************************************************
424  *           PaintRect    (USER.325)
425  */
426 void WINAPI PaintRect16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
427                        HBRUSH16 hbrush, const RECT16 *rect)
428 {
429     if( hbrush <= CTLCOLOR_MAX ) 
430     {
431         if( hwndParent )
432             hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
433         else 
434             return;
435     }
436     if( hbrush ) 
437         FillRect16( hdc, rect, hbrush );
438 }
439
440
441 /***********************************************************************
442  *           GetControlBrush    (USER.326)
443  */
444 HBRUSH16 WINAPI GetControlBrush16( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
445 {
446     WND* wndPtr = WIN_FindWndPtr( hwnd );
447     HBRUSH16 retvalue;
448
449     if((ctlType <= CTLCOLOR_MAX) && wndPtr )
450     {
451         WND* parent;
452         if( wndPtr->dwStyle & WS_POPUP ) parent = WIN_LockWndPtr(wndPtr->owner);
453         else parent = WIN_LockWndPtr(wndPtr->parent);
454         if( !parent ) parent = wndPtr;
455         retvalue = (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
456         WIN_ReleaseWndPtr(parent);
457         goto END;
458     }
459     retvalue = (HBRUSH16)0;
460 END:
461     WIN_ReleaseWndPtr(wndPtr);
462     return retvalue;
463 }
464
465
466 /***********************************************************************
467  *              RDW_ValidateParent [RDW_UpdateRgns() helper] 
468  *
469  *  Validate the portions of parent that are covered by a validated child
470  *  wndPtr = child
471  */
472 void  RDW_ValidateParent(WND *wndChild)  
473 {
474     WND *wndParent = WIN_LockWndPtr(wndChild->parent);
475     WND *wndDesktop = WIN_GetDesktop();
476
477     if ((wndParent) && (wndParent != wndDesktop) && !(wndParent->dwStyle & WS_CLIPCHILDREN))
478     {
479         HRGN hrg;
480         if (wndChild->hrgnUpdate == 1 )
481         {
482             RECT r;
483
484             r.left = 0;
485             r.top = 0;
486             r.right = wndChild->rectWindow.right - wndChild->rectWindow.left;
487             r.bottom = wndChild->rectWindow.bottom - wndChild->rectWindow.top;
488
489             hrg = CreateRectRgnIndirect( &r );
490         }
491         else
492            hrg = wndChild->hrgnUpdate;
493         if (wndParent->hrgnUpdate != 0)
494         {
495             POINT ptOffset;
496             RECT rect, rectParent;
497             if( wndParent->hrgnUpdate == 1 )
498             {
499                RECT r;
500
501                r.left = 0;
502                r.top = 0;
503                r.right = wndParent->rectWindow.right - wndParent->rectWindow.left;
504                r.bottom = wndParent->rectWindow.bottom - wndParent->rectWindow.top;
505
506                wndParent->hrgnUpdate = CreateRectRgnIndirect( &r );
507             }
508             /* we must offset the child region by the offset of the child rect in the parent */
509             GetWindowRect(wndParent->hwndSelf, &rectParent);
510             GetWindowRect(wndChild->hwndSelf, &rect);
511             ptOffset.x = rect.left - rectParent.left;
512             ptOffset.y = rect.top - rectParent.top;
513             OffsetRgn( hrg, ptOffset.x, ptOffset.y );
514             CombineRgn( wndParent->hrgnUpdate, wndParent->hrgnUpdate, hrg, RGN_DIFF );
515             OffsetRgn( hrg, -ptOffset.x, -ptOffset.y );
516         }
517         if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg );
518     }
519     WIN_ReleaseWndPtr(wndParent);
520     WIN_ReleaseDesktop();
521 }
522
523 /***********************************************************************
524  *              RDW_UpdateRgns [RedrawWindow() helper] 
525  *
526  *  Walks the window tree and adds/removes parts of the hRgn to/from update
527  *  regions of windows that overlap it. Also, manages internal paint flags.
528  *
529  *  NOTE: Walks the window tree so the caller must lock it.
530  *        MUST preserve hRgn (can modify but then has to restore).
531  */
532 static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel )
533 {
534     /* 
535      * Called only when one of the following is set:
536      * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
537      */
538
539     BOOL bHadOne =  wndPtr->hrgnUpdate && hRgn;
540     BOOL bChildren =  ( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
541                         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) );
542     RECT r;
543
544     r.left = 0;
545     r.top = 0;
546     r.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
547     r.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
548
549     TRACE("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags );
550
551     if( flags & RDW_INVALIDATE )
552     {
553         if( hRgn > 1 )
554         {
555             switch( wndPtr->hrgnUpdate )
556             {
557                 default:
558                         CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_OR );
559                         /* fall through */
560                 case 0:
561                         wndPtr->hrgnUpdate = REGION_CropRgn( wndPtr->hrgnUpdate, 
562                                                              wndPtr->hrgnUpdate ? wndPtr->hrgnUpdate : hRgn, 
563                                                              &r, NULL );
564                         if( !bHadOne )
565                         {
566                             GetRgnBox( wndPtr->hrgnUpdate, &r );
567                             if( IsRectEmpty( &r ) )
568                             {
569                                 DeleteObject( wndPtr->hrgnUpdate );
570                                 wndPtr->hrgnUpdate = 0;
571                                 goto OUT;
572                             }
573                         }
574                         break;
575                 case 1: /* already an entire window */
576                         break;
577             }
578         }
579         else if( hRgn == 1 )
580         {
581             if( wndPtr->hrgnUpdate > 1 )
582                 DeleteObject( wndPtr->hrgnUpdate );
583             wndPtr->hrgnUpdate = 1;
584         }
585         else
586             hRgn = wndPtr->hrgnUpdate;  /* this is a trick that depends on code in PAINT_RedrawWindow() */
587
588         if( !bHadOne && !(wndPtr->flags & WIN_INTERNAL_PAINT) )
589             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
590
591         if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
592         if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
593         flags    |= RDW_FRAME;
594     }
595     else if( flags & RDW_VALIDATE )
596     {
597         if( wndPtr->hrgnUpdate )
598         {
599             if( hRgn > 1 )
600             {
601                 if( wndPtr->hrgnUpdate == 1 )
602                     wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r );
603
604                 if( CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_DIFF )
605                     == NULLREGION )
606                     goto EMPTY;
607             }
608             else /* validate everything */
609             {
610                 if( wndPtr->hrgnUpdate > 1 )
611                 {
612 EMPTY:
613                     DeleteObject( wndPtr->hrgnUpdate );
614                 }
615                 wndPtr->hrgnUpdate = 0;
616             }
617
618             if( !wndPtr->hrgnUpdate )
619             {
620                 wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
621                 if( !(wndPtr->flags & WIN_INTERNAL_PAINT) )
622                     QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
623             }
624         }
625
626         if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
627         if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
628
629     }
630
631     if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW))
632         RDW_ValidateParent(wndPtr); /* validate parent covered by region */
633
634     /* in/validate child windows that intersect with the region if it
635      * is a valid handle. */
636
637     if( flags & (RDW_INVALIDATE | RDW_VALIDATE) )
638     {
639         if( hRgn > 1 && bChildren )
640         {
641             WND* wnd = wndPtr->child;
642             POINT ptTotal, prevOrigin = {0,0};
643             POINT ptClient;
644
645             ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
646             ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
647
648             for( ptTotal.x = ptTotal.y = 0; wnd; wnd = wnd->next )
649             {
650                 if( wnd->dwStyle & WS_VISIBLE )
651                 {
652                     POINT ptOffset;
653
654                     r.left = wnd->rectWindow.left + ptClient.x;
655                     r.right = wnd->rectWindow.right + ptClient.x;
656                     r.top = wnd->rectWindow.top + ptClient.y;
657                     r.bottom = wnd->rectWindow.bottom + ptClient.y;
658
659                     ptOffset.x = r.left - prevOrigin.x; 
660                     ptOffset.y = r.top - prevOrigin.y;
661                     OffsetRect( &r, -ptTotal.x, -ptTotal.y );
662
663                     if( RectInRegion( hRgn, &r ) )
664                     {
665                         OffsetRgn( hRgn, -ptOffset.x, -ptOffset.y );
666                         RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
667                         prevOrigin.x = r.left + ptTotal.x;
668                         prevOrigin.y = r.top + ptTotal.y;
669                         ptTotal.x += ptOffset.x;
670                         ptTotal.y += ptOffset.y;
671                     }
672                 }
673             }
674             OffsetRgn( hRgn, ptTotal.x, ptTotal.y );
675             bChildren = 0;
676         }
677     }
678
679     /* handle hRgn == 1 (alias for entire window) and/or internal paint recursion */
680
681     if( bChildren )
682     {
683         WND* wnd;
684         for( wnd = wndPtr->child; wnd; wnd = wnd->next )
685              if( wnd->dwStyle & WS_VISIBLE )
686                  RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
687     }
688
689 OUT:
690
691     /* Set/clear internal paint flag */
692
693     if (flags & RDW_INTERNALPAINT)
694     {
695         if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
696             QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
697         wndPtr->flags |= WIN_INTERNAL_PAINT;
698     }
699     else if (flags & RDW_NOINTERNALPAINT)
700     {
701         if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
702             QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
703         wndPtr->flags &= ~WIN_INTERNAL_PAINT;
704     }
705 }
706
707 /***********************************************************************
708  *           RDW_Paint [RedrawWindow() helper]
709  *
710  * Walks the window tree and paints/erases windows that have
711  * nonzero update regions according to redraw flags. hrgn is a scratch
712  * region passed down during recursion. Must not be 1.
713  *
714  */
715 static HRGN RDW_Paint( WND* wndPtr, HRGN hrgn, UINT flags, UINT ex )
716 {
717 /* NOTE: wndPtr is locked by caller.
718  * 
719  * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
720  * SendMessage() calls. This is a comment inside DefWindowProc() source
721  * from 16-bit SDK:
722  *
723  *   This message avoids lots of inter-app message traffic
724  *   by switching to the other task and continuing the
725  *   recursion there.
726  *
727  * wParam         = flags
728  * LOWORD(lParam) = hrgnClip
729  * HIWORD(lParam) = hwndSkip  (not used; always NULL)
730  *
731  */
732     HDC  hDC;
733     HWND hWnd = wndPtr->hwndSelf;
734     BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassWord(wndPtr->hwndSelf, GCW_HICON)); 
735
736       /* Erase/update the window itself ... */
737
738     TRACE("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags );
739
740     /*
741      * Check if this window should delay it's processing of WM_NCPAINT.
742      * See WIN_HaveToDelayNCPAINT for a description of the mechanism
743      */
744     if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr, 0) )
745         ex |= RDW_EX_DELAY_NCPAINT;
746
747     if (flags & RDW_UPDATENOW)
748     {
749         if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
750             SendMessage16( hWnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
751     }
752     else if ((flags & RDW_ERASENOW) || (ex & RDW_EX_TOPFRAME))
753     {
754         UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
755         HRGN hrgnRet;
756
757         hrgnRet = WIN_UpdateNCRgn(wndPtr, 
758                                   hrgn, 
759                                   UNC_REGION | UNC_CHECK | 
760                                   ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
761                                   ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) ); 
762
763         if( hrgnRet )
764         {
765             if( hrgnRet > 1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */
766             if( wndPtr->flags & WIN_NEEDS_ERASEBKGND )
767             {
768                 if( bIcon ) dcx |= DCX_WINDOW;
769                 else 
770                 if( hrgnRet )
771                     OffsetRgn( hrgnRet, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
772                                         wndPtr->rectWindow.top  - wndPtr->rectClient.top);
773                 else
774                     dcx &= ~DCX_INTERSECTRGN;
775                 if (( hDC = GetDCEx( hWnd, hrgnRet, dcx )) )
776                 {
777                     if (SendMessage16( hWnd, (bIcon) ? WM_ICONERASEBKGND
778                                        : WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
779                     wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
780                     ReleaseDC( hWnd, hDC );
781                 }
782             }
783         }
784     }
785
786     if( !IsWindow(hWnd) ) return hrgn;
787     ex &= ~RDW_EX_TOPFRAME;
788
789       /* ... and its child windows */
790
791     if( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
792         && ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) )
793     {
794         WND** list, **ppWnd;
795
796         if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
797         {
798             wndPtr = NULL;
799             for (ppWnd = list; *ppWnd; ppWnd++)
800             {
801                 WIN_UpdateWndPtr(&wndPtr,*ppWnd);
802                 if (!IsWindow(wndPtr->hwndSelf)) continue;
803                     if ( (wndPtr->dwStyle & WS_VISIBLE) &&
804                          (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) )
805                         hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
806             }
807             WIN_ReleaseWndPtr(wndPtr);
808             WIN_ReleaseWinArray(list);
809         }
810     }
811
812     return hrgn;
813 }
814
815 /***********************************************************************
816  *           PAINT_RedrawWindow
817  *
818  */
819 BOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
820                            HRGN hrgnUpdate, UINT flags, UINT ex )
821 {
822     HRGN hRgn = 0;
823     RECT r, r2;
824     POINT pt;
825     WND* wndPtr;
826
827     if (!hwnd) hwnd = GetDesktopWindow();
828     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
829
830     /* check if the window or its parents are visible/not minimized */
831
832     if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
833     {
834         WIN_ReleaseWndPtr(wndPtr);
835         return TRUE; 
836     }
837
838     if (TRACE_ON(win))
839     {
840         if( hrgnUpdate )
841         {
842             GetRgnBox( hrgnUpdate, &r );
843             TRACE( "%04x (%04x) NULL %04x box (%i,%i-%i,%i) flags=%04x, exflags=%04x\n", 
844                   hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags, ex);
845         }
846         else
847         {
848             if( rectUpdate )
849                 r = *rectUpdate;
850             else
851                 SetRectEmpty( &r );
852             TRACE( "%04x (%04x) %s %d,%d-%d,%d %04x flags=%04x, exflags=%04x\n",
853                         hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, 
854                         r.top, r.right, r.bottom, hrgnUpdate, flags, ex );
855         }
856     }
857
858     /* prepare an update region in window coordinates */
859
860     if( flags & RDW_FRAME )
861         r = wndPtr->rectWindow;
862     else
863         r = wndPtr->rectClient;
864
865     if( ex & RDW_EX_XYWINDOW )
866     {
867         pt.x = pt.y = 0;
868         OffsetRect( &r, -wndPtr->rectWindow.left, -wndPtr->rectWindow.top );
869     }
870     else
871     {
872         pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
873         pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
874         OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top );
875     }
876
877     if (flags & RDW_INVALIDATE)  /* ------------------------- Invalidate */
878     {
879         /* If the window doesn't have hrgnUpdate we leave hRgn zero
880          * and put a new region straight into wndPtr->hrgnUpdate
881          * so that RDW_UpdateRgns() won't have to do any extra work.
882          */
883
884         if( hrgnUpdate )
885         {
886             if( wndPtr->hrgnUpdate )
887                 hRgn = REGION_CropRgn( 0, hrgnUpdate, NULL, &pt );
888             else 
889                 wndPtr->hrgnUpdate = REGION_CropRgn( 0, hrgnUpdate, &r, &pt ); 
890         }
891         else if( rectUpdate )
892         {
893             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
894             OffsetRect( &r2, pt.x, pt.y );
895
896 rect2i:
897             if( wndPtr->hrgnUpdate == 0 )
898                 wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 );
899             else
900                 hRgn = CreateRectRgnIndirect( &r2 );
901         }
902         else /* entire window or client depending on RDW_FRAME */
903         {
904             if( flags & RDW_FRAME )
905             {
906                 if( wndPtr->hrgnUpdate )
907                     DeleteObject( wndPtr->hrgnUpdate );
908                 wndPtr->hrgnUpdate = 1;
909             }
910             else
911             {
912                 GETCLIENTRECTW( wndPtr, r2 );
913                 goto rect2i;
914             }
915         }
916     }
917     else if (flags & RDW_VALIDATE)  /* ------------------------- Validate */
918     {
919         /* In this we cannot leave with zero hRgn */
920         if( hrgnUpdate )
921         {
922             hRgn = REGION_CropRgn( hRgn, hrgnUpdate,  &r, &pt );
923             GetRgnBox( hRgn, &r2 );
924             if( IsRectEmpty( &r2 ) ) goto END;
925         }
926         else if( rectUpdate )
927         {
928             if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
929                 OffsetRect( &r2, pt.x, pt.y );
930 rect2v:
931             hRgn = CreateRectRgnIndirect( &r2 );
932         }
933         else /* entire window or client depending on RDW_FRAME */
934         {
935             if( flags & RDW_FRAME ) 
936                 hRgn = 1;
937             else
938             {
939                 GETCLIENTRECTW( wndPtr, r2 );
940                 goto rect2v;
941             }
942         }
943     }
944
945     /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
946
947     RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE );
948
949     /* Erase/update windows, from now on hRgn is a scratch region */
950
951     hRgn = RDW_Paint( wndPtr, (hRgn == 1) ? 0 : hRgn, flags, ex );
952
953 END:
954     if( hRgn > 1 && (hRgn != hrgnUpdate) )
955         DeleteObject(hRgn );
956     WIN_ReleaseWndPtr(wndPtr);
957     return TRUE;
958 }
959
960
961 /***********************************************************************
962  *           RedrawWindow32    (USER32.426)
963  */
964 BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate,
965                               HRGN hrgnUpdate, UINT flags )
966 {
967     return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 );
968 }
969
970
971 /***********************************************************************
972  *           RedrawWindow16    (USER.290)
973  */
974 BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
975                               HRGN16 hrgnUpdate, UINT16 flags )
976 {
977     if (rectUpdate)
978     {
979         RECT r;
980         CONV_RECT16TO32( rectUpdate, &r );
981         return (BOOL16)RedrawWindow( (HWND)hwnd, &r, hrgnUpdate, flags );
982     }
983     return (BOOL16)PAINT_RedrawWindow( (HWND)hwnd, NULL, 
984                                        (HRGN)hrgnUpdate, flags, 0 );
985 }
986
987
988 /***********************************************************************
989  *           UpdateWindow16   (USER.124)
990  */
991 void WINAPI UpdateWindow16( HWND16 hwnd )
992 {
993     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
994 }
995
996 /***********************************************************************
997  *           UpdateWindow32   (USER32.567)
998  */
999 void WINAPI UpdateWindow( HWND hwnd )
1000 {
1001     PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
1002 }
1003
1004 /***********************************************************************
1005  *           InvalidateRgn16   (USER.126)
1006  */
1007 void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
1008 {
1009     PAINT_RedrawWindow((HWND)hwnd, NULL, (HRGN)hrgn, 
1010                        RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1011 }
1012
1013
1014 /***********************************************************************
1015  *           InvalidateRgn32   (USER32.329)
1016  */
1017 BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
1018 {
1019     return PAINT_RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1020 }
1021
1022
1023 /***********************************************************************
1024  *           InvalidateRect16   (USER.125)
1025  */
1026 void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
1027 {
1028     RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
1029 }
1030
1031
1032 /***********************************************************************
1033  *           InvalidateRect32   (USER32.328)
1034  */
1035 BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase )
1036 {
1037     return PAINT_RedrawWindow( hwnd, rect, 0, 
1038                                RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
1039 }
1040
1041
1042 /***********************************************************************
1043  *           ValidateRgn16   (USER.128)
1044  */
1045 void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
1046 {
1047     PAINT_RedrawWindow( (HWND)hwnd, NULL, (HRGN)hrgn, 
1048                         RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1049 }
1050
1051
1052 /***********************************************************************
1053  *           ValidateRgn32   (USER32.572)
1054  */
1055 void WINAPI ValidateRgn( HWND hwnd, HRGN hrgn )
1056 {
1057     PAINT_RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1058 }
1059
1060
1061 /***********************************************************************
1062  *           ValidateRect16   (USER.127)
1063  */
1064 void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
1065 {
1066     RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
1067 }
1068
1069
1070 /***********************************************************************
1071  *           ValidateRect32   (USER32.571)
1072  */
1073 void WINAPI ValidateRect( HWND hwnd, const RECT *rect )
1074 {
1075     PAINT_RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
1076 }
1077
1078
1079 /***********************************************************************
1080  *           GetUpdateRect16   (USER.190)
1081  */
1082 BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
1083 {
1084     RECT r;
1085     BOOL16 ret;
1086
1087     if (!rect) return GetUpdateRect( hwnd, NULL, erase );
1088     ret = GetUpdateRect( hwnd, &r, erase );
1089     CONV_RECT32TO16( &r, rect );
1090     return ret;
1091 }
1092
1093
1094 /***********************************************************************
1095  *           GetUpdateRect32   (USER32.297)
1096  */
1097 BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
1098 {
1099     BOOL retvalue;
1100     WND * wndPtr = WIN_FindWndPtr( hwnd );
1101     if (!wndPtr) return FALSE;
1102
1103     if (rect)
1104     {
1105         if (wndPtr->hrgnUpdate > 1)
1106         {
1107             HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1108             if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR)
1109             {
1110                 retvalue = FALSE;
1111                 goto END;
1112             }
1113             GetRgnBox( hrgn, rect );
1114             DeleteObject( hrgn );
1115             if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_OWNDC)
1116             {
1117                 if (GetMapMode(wndPtr->dce->hDC) != MM_TEXT)
1118                 {
1119                     DPtoLP (wndPtr->dce->hDC, (LPPOINT)rect,  2);
1120                 }
1121             }
1122         }
1123         else
1124         if( wndPtr->hrgnUpdate == 1 )
1125         {
1126             GetClientRect( hwnd, rect );
1127             if (erase) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_ERASENOW | RDW_NOCHILDREN );
1128         }
1129         else 
1130             SetRectEmpty( rect );
1131     }
1132     retvalue = (wndPtr->hrgnUpdate >= 1);
1133 END:
1134     WIN_ReleaseWndPtr(wndPtr);
1135     return retvalue;
1136 }
1137
1138
1139 /***********************************************************************
1140  *           GetUpdateRgn16   (USER.237)
1141  */
1142 INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
1143 {
1144     return GetUpdateRgn( hwnd, hrgn, erase );
1145 }
1146
1147
1148 /***********************************************************************
1149  *           GetUpdateRgn    (USER32.298)
1150  */
1151 INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
1152 {
1153     INT retval;
1154     WND * wndPtr = WIN_FindWndPtr( hwnd );
1155     if (!wndPtr) return ERROR;
1156
1157     if (wndPtr->hrgnUpdate == 0)
1158     {
1159         SetRectRgn( hrgn, 0, 0, 0, 0 );
1160         retval = NULLREGION;
1161         goto END;
1162     }
1163     else
1164     if (wndPtr->hrgnUpdate == 1)
1165     {
1166         SetRectRgn( hrgn, 0, 0, wndPtr->rectClient.right - wndPtr->rectClient.left,
1167                                 wndPtr->rectClient.bottom - wndPtr->rectClient.top );
1168         retval = SIMPLEREGION;
1169     }
1170     else
1171     {
1172         retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
1173         OffsetRgn( hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left,
1174                          wndPtr->rectWindow.top - wndPtr->rectClient.top );
1175     }
1176     if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
1177 END:
1178     WIN_ReleaseWndPtr(wndPtr);
1179     return retval;
1180 }
1181
1182
1183 /***********************************************************************
1184  *           ExcludeUpdateRgn16   (USER.238)
1185  */
1186 INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
1187 {
1188     return ExcludeUpdateRgn( hdc, hwnd );
1189 }
1190
1191
1192 /***********************************************************************
1193  *           ExcludeUpdateRgn32   (USER32.195)
1194  */
1195 INT WINAPI ExcludeUpdateRgn( HDC hdc, HWND hwnd )
1196 {
1197     RECT rect;
1198     WND * wndPtr;
1199
1200     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
1201
1202     if (wndPtr->hrgnUpdate)
1203     {
1204         INT ret;
1205         HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left,
1206                                       wndPtr->rectWindow.top - wndPtr->rectClient.top,
1207                                       wndPtr->rectWindow.right - wndPtr->rectClient.left,
1208                                       wndPtr->rectWindow.bottom - wndPtr->rectClient.top);
1209         if( wndPtr->hrgnUpdate > 1 )
1210         {
1211             CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
1212             OffsetRgn(hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
1213                             wndPtr->rectWindow.top - wndPtr->rectClient.top );
1214         }
1215
1216         /* do ugly coordinate translations in dce.c */
1217
1218         ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
1219         DeleteObject( hrgn );
1220         WIN_ReleaseWndPtr(wndPtr);
1221         return ret;
1222     } 
1223     WIN_ReleaseWndPtr(wndPtr);
1224     return GetClipBox( hdc, &rect );
1225 }
1226
1227
1228
1229 /***********************************************************************
1230  *           FillRect16    (USER.81)
1231  */
1232 INT16 WINAPI FillRect16( HDC16 hdc, const RECT16 *rect, HBRUSH16 hbrush )
1233 {
1234     HBRUSH16 prevBrush;
1235
1236     /* coordinates are logical so we cannot fast-check 'rect',
1237      * it will be done later in the PatBlt().
1238      */
1239
1240     if (!(prevBrush = SelectObject16( hdc, hbrush ))) return 0;
1241     PatBlt( hdc, rect->left, rect->top,
1242               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1243     SelectObject16( hdc, prevBrush );
1244     return 1;
1245 }
1246
1247
1248 /***********************************************************************
1249  *           FillRect    (USER32.197)
1250  */
1251 INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1252 {
1253     HBRUSH prevBrush;
1254
1255     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1256     PatBlt( hdc, rect->left, rect->top,
1257               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1258     SelectObject( hdc, prevBrush );
1259     return 1;
1260 }
1261
1262
1263 /***********************************************************************
1264  *           InvertRect16    (USER.82)
1265  */
1266 void WINAPI InvertRect16( HDC16 hdc, const RECT16 *rect )
1267 {
1268     PatBlt( hdc, rect->left, rect->top,
1269               rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
1270 }
1271
1272
1273 /***********************************************************************
1274  *           InvertRect    (USER32.330)
1275  */
1276 BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
1277 {
1278     return PatBlt( hdc, rect->left, rect->top,
1279                      rect->right - rect->left, rect->bottom - rect->top, 
1280                      DSTINVERT );
1281 }
1282
1283
1284 /***********************************************************************
1285  *           FrameRect    (USER32.203)
1286  */
1287 INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1288 {
1289     HBRUSH prevBrush;
1290     RECT r = *rect;
1291
1292     LPtoDP(hdc, (POINT *)&r, 2);
1293
1294     if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1295     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1296     
1297     PatBlt( hdc, r.left, r.top, 1,
1298               r.bottom - r.top, PATCOPY );
1299     PatBlt( hdc, r.right - 1, r.top, 1,
1300               r.bottom - r.top, PATCOPY );
1301     PatBlt( hdc, r.left, r.top,
1302               r.right - r.left, 1, PATCOPY );
1303     PatBlt( hdc, r.left, r.bottom - 1,
1304               r.right - r.left, 1, PATCOPY );
1305
1306     SelectObject( hdc, prevBrush );
1307     return TRUE;
1308 }
1309
1310
1311 /***********************************************************************
1312  *           FrameRect16    (USER.83)
1313  */
1314 INT16 WINAPI FrameRect16( HDC16 hdc, const RECT16 *rect16, HBRUSH16 hbrush )
1315 {
1316     RECT rect;
1317     CONV_RECT16TO32( rect16, &rect );
1318     return FrameRect( hdc, &rect, hbrush );
1319 }
1320
1321
1322 /***********************************************************************
1323  *           DrawFocusRect16    (USER.466)
1324  */
1325 void WINAPI DrawFocusRect16( HDC16 hdc, const RECT16* rc )
1326 {
1327     RECT rect32;
1328     CONV_RECT16TO32( rc, &rect32 );
1329     DrawFocusRect( hdc, &rect32 );
1330 }
1331
1332
1333 /***********************************************************************
1334  *           DrawFocusRect    (USER32.156)
1335  *
1336  * FIXME: PatBlt(PATINVERT) with background brush.
1337  */
1338 BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
1339 {
1340     HBRUSH hOldBrush;
1341     HPEN hOldPen, hNewPen;
1342     INT oldDrawMode, oldBkMode;
1343
1344     hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1345     hNewPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_WINDOWTEXT));
1346     hOldPen = SelectObject(hdc, hNewPen);
1347     oldDrawMode = SetROP2(hdc, R2_XORPEN);
1348     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1349
1350     Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);
1351
1352     SetBkMode(hdc, oldBkMode);
1353     SetROP2(hdc, oldDrawMode);
1354     SelectObject(hdc, hOldPen);
1355     DeleteObject(hNewPen);
1356     SelectObject(hdc, hOldBrush);
1357
1358     return TRUE;
1359 }
1360
1361 /**********************************************************************
1362  *          DrawAnimatedRects16  (USER.448)
1363  */
1364 BOOL16 WINAPI DrawAnimatedRects16( HWND16 hwnd, INT16 idAni,
1365                                    const RECT16* lprcFrom,
1366                                    const RECT16* lprcTo )
1367 {
1368     RECT rcFrom32, rcTo32;
1369
1370     rcFrom32.left       = (INT)lprcFrom->left;
1371     rcFrom32.top        = (INT)lprcFrom->top;
1372     rcFrom32.right      = (INT)lprcFrom->right;
1373     rcFrom32.bottom     = (INT)lprcFrom->bottom;
1374
1375     rcTo32.left         = (INT)lprcTo->left;
1376     rcTo32.top          = (INT)lprcTo->top;
1377     rcTo32.right        = (INT)lprcTo->right;
1378     rcTo32.bottom       = (INT)lprcTo->bottom;
1379
1380     return DrawAnimatedRects((HWND)hwnd, (INT)idAni, &rcFrom32, &rcTo32);
1381 }
1382
1383
1384 /**********************************************************************
1385  *          DrawAnimatedRects  (USER32.153)
1386  */
1387 BOOL WINAPI DrawAnimatedRects( HWND hwnd, int idAni,
1388                                    const RECT* lprcFrom,
1389                                    const RECT* lprcTo )
1390 {
1391     FIXME_(win)("(0x%x,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
1392     return TRUE;
1393 }
1394
1395
1396 /**********************************************************************
1397  *          PAINTING_DrawStateJam
1398  *
1399  * Jams in the requested type in the dc
1400  */
1401 static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
1402                                     DRAWSTATEPROC func, LPARAM lp, WPARAM wp, 
1403                                     LPRECT rc, UINT dtflags,
1404                                     BOOL unicode, BOOL _32bit)
1405 {
1406     HDC memdc;
1407     HBITMAP hbmsave;
1408     BOOL retval;
1409     INT cx = rc->right - rc->left;
1410     INT cy = rc->bottom - rc->top;
1411     
1412     switch(opcode)
1413     {
1414     case DST_TEXT:
1415     case DST_PREFIXTEXT:
1416         if(unicode)
1417             return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1418         else if(_32bit)
1419             return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1420         else
1421             return DrawTextA(hdc, (LPSTR)PTR_SEG_TO_LIN(lp), (INT)wp, rc, dtflags);
1422
1423     case DST_ICON:
1424         return DrawIcon(hdc, rc->left, rc->top, (HICON)lp);
1425
1426     case DST_BITMAP:
1427         memdc = CreateCompatibleDC(hdc);
1428         if(!memdc) return FALSE;
1429         hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
1430         if(!hbmsave) 
1431         {
1432             DeleteDC(memdc);
1433             return FALSE;
1434         }
1435         retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1436         SelectObject(memdc, hbmsave);
1437         DeleteDC(memdc);
1438         return retval;
1439             
1440     case DST_COMPLEX:
1441         if(func)
1442             if(_32bit)
1443                 return func(hdc, lp, wp, cx, cy);
1444             else
1445                 return (BOOL)((DRAWSTATEPROC16)func)((HDC16)hdc, (LPARAM)lp, (WPARAM16)wp, (INT16)cx, (INT16)cy);
1446         else
1447             return FALSE;
1448     }
1449     return FALSE;
1450 }
1451
1452 /**********************************************************************
1453  *      PAINTING_DrawState()
1454  */
1455 static BOOL PAINTING_DrawState(HDC hdc, HBRUSH hbr, 
1456                                    DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1457                                    INT x, INT y, INT cx, INT cy, 
1458                                    UINT flags, BOOL unicode, BOOL _32bit)
1459 {
1460     HBITMAP hbm, hbmsave;
1461     HFONT hfsave;
1462     HBRUSH hbsave;
1463     HDC memdc;
1464     RECT rc;
1465     UINT dtflags = DT_NOCLIP;
1466     COLORREF fg, bg;
1467     UINT opcode = flags & 0xf;
1468     INT len = wp;
1469     BOOL retval, tmp;
1470
1471     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1472     {
1473         if(unicode)
1474             len = lstrlenW((LPWSTR)lp);
1475         else if(_32bit)
1476             len = lstrlenA((LPSTR)lp);
1477         else
1478             len = lstrlenA((LPSTR)PTR_SEG_TO_LIN(lp));
1479     }
1480
1481     /* Find out what size the image has if not given by caller */
1482     if(!cx || !cy)
1483     {
1484         SIZE s;
1485         CURSORICONINFO *ici;
1486         BITMAP bm;
1487
1488         switch(opcode)
1489         {
1490         case DST_TEXT:
1491         case DST_PREFIXTEXT:
1492             if(unicode)
1493                 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1494             else if(_32bit)
1495                 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1496             else
1497                 retval = GetTextExtentPoint32A(hdc, PTR_SEG_TO_LIN(lp), len, &s);
1498             if(!retval) return FALSE;
1499             break;
1500             
1501         case DST_ICON:
1502             ici = (CURSORICONINFO *)GlobalLock16((HGLOBAL16)lp);
1503             if(!ici) return FALSE;
1504             s.cx = ici->nWidth;
1505             s.cy = ici->nHeight;
1506             GlobalUnlock16((HGLOBAL16)lp);
1507             break;            
1508
1509         case DST_BITMAP:
1510             if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm))
1511                 return FALSE;
1512             s.cx = bm.bmWidth;
1513             s.cy = bm.bmHeight;
1514             break;
1515             
1516         case DST_COMPLEX: /* cx and cy must be set in this mode */
1517             return FALSE;
1518         }
1519                     
1520         if(!cx) cx = s.cx;
1521         if(!cy) cy = s.cy;
1522     }
1523
1524     rc.left   = x;
1525     rc.top    = y;
1526     rc.right  = x + cx;
1527     rc.bottom = y + cy;
1528
1529     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1530         dtflags |= DT_RIGHT;
1531     if(opcode == DST_TEXT)
1532         dtflags |= DT_NOPREFIX;
1533
1534     /* For DSS_NORMAL we just jam in the image and return */
1535     if((flags & 0x7ff0) == DSS_NORMAL)
1536     {
1537         return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode, _32bit);
1538     }
1539
1540     /* For all other states we need to convert the image to B/W in a local bitmap */
1541     /* before it is displayed */
1542     fg = SetTextColor(hdc, RGB(0, 0, 0));
1543     bg = SetBkColor(hdc, RGB(255, 255, 255));
1544     hbm = (HBITMAP)NULL; hbmsave = (HBITMAP)NULL;
1545     memdc = (HDC)NULL; hbsave = (HBRUSH)NULL;
1546     retval = FALSE; /* assume failure */
1547     
1548     /* From here on we must use "goto cleanup" when something goes wrong */
1549     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1550     if(!hbm) goto cleanup;
1551     memdc   = CreateCompatibleDC(hdc);
1552     if(!memdc) goto cleanup;
1553     hbmsave = (HBITMAP)SelectObject(memdc, hbm);
1554     if(!hbmsave) goto cleanup;
1555     rc.left = rc.top = 0;
1556     rc.right = cx;
1557     rc.bottom = cy;
1558     if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
1559     SetBkColor(memdc, RGB(255, 255, 255));
1560     SetTextColor(memdc, RGB(0, 0, 0));
1561     hfsave  = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1562     if(!hfsave && (opcode == DST_TEXT || opcode == DST_PREFIXTEXT)) goto cleanup;
1563     tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode, _32bit);
1564     if(hfsave) SelectObject(memdc, hfsave);
1565     if(!tmp) goto cleanup;
1566     
1567     /* These states cause the image to be dithered */
1568     if(flags & (DSS_UNION|DSS_DISABLED))
1569     {
1570         hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
1571         if(!hbsave) goto cleanup;
1572         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1573         if(hbsave) SelectObject(memdc, hbsave);
1574         if(!tmp) goto cleanup;
1575     }
1576
1577     hbsave = (HBRUSH)SelectObject(hdc, hbr ? hbr : GetStockObject(WHITE_BRUSH));
1578     if(!hbsave) goto cleanup;
1579     
1580     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1581     
1582     /* DSS_DEFAULT makes the image boldface */
1583     if(flags & DSS_DEFAULT)
1584     {
1585         if(!BitBlt(hdc, x+1, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1586     }
1587
1588     retval = TRUE; /* We succeeded */
1589     
1590 cleanup:    
1591     SetTextColor(hdc, fg);
1592     SetBkColor(hdc, bg);
1593
1594     if(hbsave)  SelectObject(hdc, hbsave);
1595     if(hbmsave) SelectObject(memdc, hbmsave);
1596     if(hbm)     DeleteObject(hbm);
1597     if(memdc)   DeleteDC(memdc);
1598
1599     return retval;
1600 }
1601
1602 /**********************************************************************
1603  *      DrawStateA()   (USER32.162)
1604  */
1605 BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
1606                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1607                    INT x, INT y, INT cx, INT cy, UINT flags)
1608 {
1609     return PAINTING_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE, TRUE);
1610 }
1611
1612 /**********************************************************************
1613  *      DrawStateW()   (USER32.163)
1614  */
1615 BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
1616                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1617                    INT x, INT y, INT cx, INT cy, UINT flags)
1618 {
1619     return PAINTING_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE, TRUE);
1620 }
1621
1622 /**********************************************************************
1623  *      DrawState16()   (USER.449)
1624  */
1625 BOOL16 WINAPI DrawState16(HDC16 hdc, HBRUSH16 hbr,
1626                    DRAWSTATEPROC16 func, LPARAM ldata, WPARAM16 wdata,
1627                    INT16 x, INT16 y, INT16 cx, INT16 cy, UINT16 flags)
1628 {
1629     return PAINTING_DrawState(hdc, hbr, (DRAWSTATEPROC)func, ldata, wdata, x, y, cx, cy, flags, FALSE, FALSE);
1630 }
1631
1632