painting.c 35.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Window painting functions
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1993, 1994, 1995 Alexandre Julliard
5
 *			 1999 Alex Korobka
Alexandre Julliard's avatar
Alexandre Julliard committed
6 7
 */

8
#include "region.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
9
#include "win.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
10
#include "queue.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
11
#include "dce.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
12
#include "heap.h"
13
#include "debugtools.h"
14
#include "wine/winuser16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
15

16 17 18
DECLARE_DEBUG_CHANNEL(nonclient)
DECLARE_DEBUG_CHANNEL(win)

19 20 21 22 23 24 25
/* client rect in window coordinates */

#define GETCLIENTRECTW( wnd, r )	(r).left = (wnd)->rectClient.left - (wnd)->rectWindow.left; \
					(r).top = (wnd)->rectClient.top - (wnd)->rectWindow.top; \
					(r).right = (wnd)->rectClient.right - (wnd)->rectWindow.left; \
					(r).bottom = (wnd)->rectClient.bottom - (wnd)->rectWindow.top

Alexandre Julliard's avatar
Alexandre Julliard committed
26 27 28
  /* Last CTLCOLOR id */
#define CTLCOLOR_MAX   CTLCOLOR_STATIC

29

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/***********************************************************************
 *           WIN_HaveToDelayNCPAINT
 *
 * Currently, in the Wine painting mechanism, the WM_NCPAINT message
 * is generated as soon as a region intersecting the non-client area 
 * of a window is invalidated.
 *
 * This technique will work fine for all windows whose parents
 * have the WS_CLIPCHILDREN style. When the parents have that style,
 * they are not going to override the contents of their children.
 * However, when the parent doesn't have that style, Windows relies
 * on a "painter's algorithm" to display the contents of the windows.
 * That is, windows are painted from back to front. This includes the
 * non-client area.
 *
 * This method looks at the current state of a window to determine
 * if the sending of the WM_NCPAINT message should be delayed until 
 * the BeginPaint call.
 *
 * PARAMS:
 *   wndPtr   - A Locked window pointer to the window we're
 *              examining.
 *   uncFlags - This is the flag passed to the WIN_UpdateNCRgn
 *              function. This is a shortcut for the cases when
 *              we already know when to avoid scanning all the
 *              parents of a window. If you already know that this
 *              window's NCPAINT should be delayed, set the 
 *              UNC_DELAY_NCPAINT flag for this parameter. 
 *
 *              This shortcut behavior is implemented in the
 *              RDW_Paint() method.
 * 
 */
static BOOL WIN_HaveToDelayNCPAINT(
  WND* wndPtr, 
  UINT uncFlags)
{
  WND* parentWnd = NULL;

  /*
   * Test the shortcut first. (duh)
   */
  if (uncFlags & UNC_DELAY_NCPAINT)
    return TRUE;

  /*
   * The UNC_IN_BEGINPAINT flag is set in the BeginPaint
   * method only. This is another shortcut to avoid going
   * up the parent's chain of the window to finally
   * figure-out that none of them has an invalid region.
   */
  if (uncFlags & UNC_IN_BEGINPAINT)
    return FALSE;

  /*
   * Scan all the parents of this window to find a window
   * that doesn't have the WS_CLIPCHILDREN style and that
   * has an invalid region. 
   */
  parentWnd = WIN_LockWndPtr(wndPtr->parent);

  while (parentWnd!=NULL)
  {
    if ( ((parentWnd->dwStyle & WS_CLIPCHILDREN) == 0) &&
	 (parentWnd->hrgnUpdate != 0) )
    {
      WIN_ReleaseWndPtr(parentWnd);
      return TRUE;
    }

    WIN_UpdateWndPtr(&parentWnd, parentWnd->parent);    
  }

  WIN_ReleaseWndPtr(parentWnd);

  return FALSE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
108
/***********************************************************************
109
 *           WIN_UpdateNCRgn
Alexandre Julliard's avatar
Alexandre Julliard committed
110
 *
111 112 113 114 115 116 117 118 119 120
 *  Things to do:
 *	Send WM_NCPAINT if required (when nonclient is invalid or UNC_ENTIRE flag is set)
 *	Crop hrgnUpdate to a client rect, especially if it 1.
 *	If UNC_REGION is set return update region for the client rect.
 *
 *  NOTE: UNC_REGION is mainly for the RDW_Paint() chunk that sends WM_ERASEBKGND message.
 *	  The trick is that when the returned region handle may be different from hRgn.
 *	  In this case the old hRgn must be considered gone. BUT, if the returned value
 *	  is 1 then the hRgn is preserved and RDW_Paint() will have to get 
 *	  a DC without extra clipping region.
Alexandre Julliard's avatar
Alexandre Julliard committed
121
 */
122
HRGN WIN_UpdateNCRgn(WND* wnd, HRGN hRgn, UINT uncFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
123
{
124 125 126
    RECT  r;
    HRGN  hClip = 0;
    HRGN  hrgnRet = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
127

128 129
    TRACE_(nonclient)("hwnd %04x [%04x] hrgn %04x, unc %04x, ncf %i\n", 
                      wnd->hwndSelf, wnd->hrgnUpdate, hRgn, uncFlags, wnd->flags & WIN_NEEDS_NCPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
130

131
    /* desktop window doesn't have a nonclient area */
Alexandre Julliard's avatar
Alexandre Julliard committed
132 133 134
    if(wnd == WIN_GetDesktop()) 
    {
        wnd->flags &= ~WIN_NEEDS_NCPAINT;
135 136 137 138 139 140
	if( wnd->hrgnUpdate > 1 )
	    hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
	else 
	{
	    hrgnRet = wnd->hrgnUpdate;
	}
141
        WIN_ReleaseDesktop();
142
        return hrgnRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
143
    }
144
    WIN_ReleaseDesktop();
Alexandre Julliard's avatar
Alexandre Julliard committed
145

146
    if ((wnd->hwndSelf == GetForegroundWindow()) &&
147
        !(wnd->flags & WIN_NCACTIVATED) )
Alexandre Julliard's avatar
Alexandre Julliard committed
148
    {
149
	wnd->flags |= WIN_NCACTIVATED;
150
	uncFlags |= UNC_ENTIRE; 
151
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
152

153 154 155 156 157
    /*
     * If the window's non-client area needs to be painted, 
     */
    if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) &&
	 !WIN_HaveToDelayNCPAINT(wnd, uncFlags) )
158
    {
159
	    RECT r2, r3;
Alexandre Julliard's avatar
Alexandre Julliard committed
160

161 162
	    wnd->flags &= ~WIN_NEEDS_NCPAINT;  
	    GETCLIENTRECTW( wnd, r );
Alexandre Julliard's avatar
Alexandre Julliard committed
163

164 165 166 167 168
	    TRACE_(nonclient)( "\tclient box (%i,%i-%i,%i), hrgnUpdate %04x\n", 
				r.left, r.top, r.right, r.bottom, wnd->hrgnUpdate );
	    if( wnd->hrgnUpdate > 1 )
	    {
		/* Check if update rgn overlaps with nonclient area */
Alexandre Julliard's avatar
Alexandre Julliard committed
169

170 171 172 173 174 175 176
		GetRgnBox( wnd->hrgnUpdate, &r2 );
		UnionRect( &r3, &r2, &r );
		if( r3.left != r.left || r3.top != r.top || 
		    r3.right != r.right || r3.bottom != r.bottom ) /* it does */
		{
		    /* crop hrgnUpdate, save old one in hClip - the only
		     * case that places a valid region handle in hClip */
Alexandre Julliard's avatar
Alexandre Julliard committed
177

178 179 180 181
		    hClip = wnd->hrgnUpdate;
		    wnd->hrgnUpdate = REGION_CropRgn( hRgn, hClip, &r, NULL );
		    if( uncFlags & UNC_REGION ) hrgnRet = hClip;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
182

183
		if( uncFlags & UNC_CHECK )
184
		{
185 186 187 188 189 190 191 192 193 194 195 196 197
		    GetRgnBox( wnd->hrgnUpdate, &r3 );
		    if( IsRectEmpty( &r3 ) )
		    {
			/* delete the update region since all invalid 
			 * parts were in the nonclient area */

			DeleteObject( wnd->hrgnUpdate );
			wnd->hrgnUpdate = 0;
			if(!(wnd->flags & WIN_INTERNAL_PAINT))
			    QUEUE_DecPaintCount( wnd->hmemTaskQ );

			wnd->flags &= ~WIN_NEEDS_ERASEBKGND;
		    }
198
		}
199 200 201 202 203 204 205 206 207

		if(!hClip && wnd->hrgnUpdate ) goto copyrgn;
	    }
	    else 
	    if( wnd->hrgnUpdate == 1 )/* entire window */
	    {
		if( uncFlags & UNC_UPDATE ) wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
		if( uncFlags & UNC_REGION ) hrgnRet = 1;
		uncFlags |= UNC_ENTIRE;
208
	    }
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    }
    else /* no WM_NCPAINT unless forced */
    {
	if( wnd->hrgnUpdate >  1 )
	{
copyrgn:
	    if( uncFlags & UNC_REGION )
		hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
	}
	else
	if( wnd->hrgnUpdate == 1 && (uncFlags & UNC_UPDATE) )
	{
	    GETCLIENTRECTW( wnd, r ); 
	    wnd->hrgnUpdate = CreateRectRgnIndirect( &r );
	    if( uncFlags & UNC_REGION ) hrgnRet = 1;
224
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
225 226
    }

227 228 229 230 231
    if(!hClip && (uncFlags & UNC_ENTIRE) )
    {
	/* still don't do anything if there is no nonclient area */
	hClip = (memcmp( &wnd->rectWindow, &wnd->rectClient, sizeof(RECT) ) != 0);
    }
232

233 234
    if( hClip ) /* NOTE: WM_NCPAINT allows wParam to be 1 */
    {
235 236 237 238 239
        if ( hClip == hrgnRet && hrgnRet > 1 ) {
	    hClip = CreateRectRgn( 0, 0, 0, 0 );
	    CombineRgn( hClip, hrgnRet, 0, RGN_COPY );
	}

240
	SendMessageA( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
241 242
	if( (hClip > 1) && (hClip != hRgn) && (hClip != hrgnRet) )
	    DeleteObject( hClip );
243 244 245 246 247 248 249 250 251
	/*
         * Since all Window locks are suspended while processing the WM_NCPAINT
         * we want to make sure the window still exists before continuing.
	 */
        if (!IsWindow(wnd->hwndSelf))
        {
	  DeleteObject(hrgnRet);
	  hrgnRet=0;
        }
252
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
253

254 255 256
    TRACE_(nonclient)("returning %04x (hClip = %04x, hrgnUpdate = %04x)\n", hrgnRet, hClip, wnd->hrgnUpdate );

    return hrgnRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
257 258
}

Alexandre Julliard's avatar
Alexandre Julliard committed
259 260

/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
261
 *           BeginPaint16    (USER.39)
Alexandre Julliard's avatar
Alexandre Julliard committed
262
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
263
HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) 
Alexandre Julliard's avatar
Alexandre Julliard committed
264
{
265 266
    BOOL bIcon;
    HRGN hrgnUpdate;
267
    RECT16 clipRect, clientRect;
Alexandre Julliard's avatar
Alexandre Julliard committed
268
    WND *wndPtr = WIN_FindWndPtr( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
269 270
    if (!wndPtr) return 0;

271
    bIcon = (wndPtr->dwStyle & WS_MINIMIZE && GetClassWord(wndPtr->hwndSelf, GCW_HICON));
Alexandre Julliard's avatar
Alexandre Julliard committed
272

Alexandre Julliard's avatar
Alexandre Julliard committed
273
    wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
Alexandre Julliard's avatar
Alexandre Julliard committed
274

275
    /* send WM_NCPAINT and make sure hrgnUpdate is a valid rgn handle */
276
    WIN_UpdateNCRgn( wndPtr, 0, UNC_UPDATE | UNC_IN_BEGINPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
277

278 279 280 281 282 283 284 285 286 287
    /*
     * Make sure the window is still a window. All window locks are suspended
     * when the WM_NCPAINT is sent.
     */
    if (!IsWindow(wndPtr->hwndSelf))
    {
        WIN_ReleaseWndPtr(wndPtr);
        return 0;
    }

288
    if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT))
Alexandre Julliard's avatar
Alexandre Julliard committed
289
        QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
Alexandre Julliard's avatar
Alexandre Julliard committed
290 291

    wndPtr->hrgnUpdate = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
292
    wndPtr->flags &= ~WIN_INTERNAL_PAINT;
Alexandre Julliard's avatar
Alexandre Julliard committed
293

294
    HideCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
295

296
    TRACE_(win)("hrgnUpdate = %04x, \n", hrgnUpdate);
Alexandre Julliard's avatar
Alexandre Julliard committed
297

298
    if (GetClassWord16(wndPtr->hwndSelf, GCW_STYLE) & CS_PARENTDC)
Alexandre Julliard's avatar
Alexandre Julliard committed
299
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
300
        /* Don't clip the output to the update region for CS_PARENTDC window */
301
	if( hrgnUpdate ) 
302
	    DeleteObject(hrgnUpdate);
Alexandre Julliard's avatar
Alexandre Julliard committed
303 304
        lps->hdc = GetDCEx16( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
                              (bIcon ? DCX_WINDOW : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
305
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
306
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
307
    {
308
	if( hrgnUpdate ) /* convert to client coordinates */
309 310
	    OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left,
			           wndPtr->rectWindow.top - wndPtr->rectClient.top );
Alexandre Julliard's avatar
Alexandre Julliard committed
311
        lps->hdc = GetDCEx16(hwnd, hrgnUpdate, DCX_INTERSECTRGN |
312 313
                             DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) );
	/* ReleaseDC() in EndPaint() will delete the region */
Alexandre Julliard's avatar
Alexandre Julliard committed
314
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
315

316
    TRACE_(win)("hdc = %04x\n", lps->hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
317

Alexandre Julliard's avatar
Alexandre Julliard committed
318 319
    if (!lps->hdc)
    {
320
        WARN_(win)("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
321
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
322 323
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
324

325 326 327 328 329 330 331
    /* It is possible that the clip box is bigger than the window itself,
       if CS_PARENTDC flag is set. Windows never return a paint rect bigger
       than the window itself, so we need to intersect the cliprect with
       the window  */
    
    GetClipBox16( lps->hdc, &clipRect );
    GetClientRect16( hwnd, &clientRect );
332 333 334 335

    /* The rect obtained by GetClipBox is in logical, so make the client in logical to*/
    DPtoLP16(lps->hdc, (LPPOINT16) &clientRect, 2);    

336
    IntersectRect16(&lps->rcPaint, &clientRect, &clipRect);
Alexandre Julliard's avatar
Alexandre Julliard committed
337

338
    TRACE_(win)("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
339 340
		    lps->rcPaint.right, lps->rcPaint.bottom );

Alexandre Julliard's avatar
Alexandre Julliard committed
341 342 343
    if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
    {
        wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345
        lps->fErase = !SendMessage16(hwnd, (bIcon) ? WM_ICONERASEBKGND
                                                   : WM_ERASEBKGND,
Alexandre Julliard's avatar
Alexandre Julliard committed
346
                                     (WPARAM16)lps->hdc, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
347 348
    }
    else lps->fErase = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
349

350
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
351 352 353 354 355
    return lps->hdc;
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
356
 *           BeginPaint32    (USER32.10)
Alexandre Julliard's avatar
Alexandre Julliard committed
357
 */
358
HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
359 360 361 362
{
    PAINTSTRUCT16 ps;

    BeginPaint16( hwnd, &ps );
363
    lps->hdc            = (HDC)ps.hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377
    lps->fErase         = ps.fErase;
    lps->rcPaint.top    = ps.rcPaint.top;
    lps->rcPaint.left   = ps.rcPaint.left;
    lps->rcPaint.right  = ps.rcPaint.right;
    lps->rcPaint.bottom = ps.rcPaint.bottom;
    lps->fRestore       = ps.fRestore;
    lps->fIncUpdate     = ps.fIncUpdate;
    return lps->hdc;
}


/***********************************************************************
 *           EndPaint16    (USER.40)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
378
BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
379
{
Alexandre Julliard's avatar
Alexandre Julliard committed
380
    ReleaseDC16( hwnd, lps->hdc );
381
    ShowCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
382
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
383 384 385
}


Alexandre Julliard's avatar
Alexandre Julliard committed
386
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
387
 *           EndPaint32    (USER32.176)
Alexandre Julliard's avatar
Alexandre Julliard committed
388
 */
389
BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
390
{
391 392
    ReleaseDC( hwnd, lps->hdc );
    ShowCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
393 394 395 396
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
397 398 399
/***********************************************************************
 *           FillWindow    (USER.324)
 */
400
void WINAPI FillWindow16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
401
{
Alexandre Julliard's avatar
Alexandre Julliard committed
402 403 404
    RECT16 rect;
    GetClientRect16( hwnd, &rect );
    DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
405
    PaintRect16( hwndParent, hwnd, hdc, hbrush, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407 408
}


Alexandre Julliard's avatar
Alexandre Julliard committed
409 410 411
/***********************************************************************
 *	     PAINT_GetControlBrush
 */
412
static HBRUSH16 PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC16 hDC, UINT16 ctlType )
Alexandre Julliard's avatar
Alexandre Julliard committed
413
{
414 415 416
    HBRUSH16 bkgBrush = (HBRUSH16)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
							     (WPARAM)hDC, (LPARAM)hWnd );
    if( !IsGDIObject16(bkgBrush) )
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419 420 421
	bkgBrush = DEFWND_ControlColor( hDC, ctlType );
    return bkgBrush;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
422 423 424
/***********************************************************************
 *           PaintRect    (USER.325)
 */
425
void WINAPI PaintRect16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
Alexandre Julliard's avatar
Alexandre Julliard committed
426
                       HBRUSH16 hbrush, const RECT16 *rect)
Alexandre Julliard's avatar
Alexandre Julliard committed
427
{
Alexandre Julliard's avatar
Alexandre Julliard committed
428
    if( hbrush <= CTLCOLOR_MAX ) 
429
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
430 431 432 433
	if( hwndParent )
	    hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
	else 
	    return;
434
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
435 436
    if( hbrush ) 
	FillRect16( hdc, rect, hbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
437
}
Alexandre Julliard's avatar
Alexandre Julliard committed
438 439


Alexandre Julliard's avatar
Alexandre Julliard committed
440 441 442
/***********************************************************************
 *           GetControlBrush    (USER.326)
 */
443
HBRUSH16 WINAPI GetControlBrush16( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
Alexandre Julliard's avatar
Alexandre Julliard committed
444
{
Alexandre Julliard's avatar
Alexandre Julliard committed
445
    WND* wndPtr = WIN_FindWndPtr( hwnd );
446
    HBRUSH16 retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
447 448 449 450

    if((ctlType <= CTLCOLOR_MAX) && wndPtr )
    {
	WND* parent;
451 452
	if( wndPtr->dwStyle & WS_POPUP ) parent = WIN_LockWndPtr(wndPtr->owner);
	else parent = WIN_LockWndPtr(wndPtr->parent);
Alexandre Julliard's avatar
Alexandre Julliard committed
453
	if( !parent ) parent = wndPtr;
454 455 456 457 458 459 460 461
	retvalue = (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
        WIN_ReleaseWndPtr(parent);
        goto END;
    }
    retvalue = (HBRUSH16)0;
END:
    WIN_ReleaseWndPtr(wndPtr);
    return retvalue;
462 463
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

/***********************************************************************
 * 		RDW_ValidateParent [RDW_UpdateRgns() helper] 
 *
 *  Validate the portions of parent that are covered by a validated child
 *  wndPtr = child
 */
void  RDW_ValidateParent(WND *wndChild)  
{
    WND *wndParent = WIN_LockWndPtr(wndChild->parent);
    WND *wndDesktop = WIN_GetDesktop();

    if ((wndParent) && (wndParent != wndDesktop) && !(wndParent->dwStyle & WS_CLIPCHILDREN))
    {
        HRGN hrg;
        if (wndChild->hrgnUpdate == 1 )
        {
481 482 483 484 485 486 487
            RECT r;

	    r.left = 0;
	    r.top = 0;
	    r.right = wndChild->rectWindow.right - wndChild->rectWindow.left;
	    r.bottom = wndChild->rectWindow.bottom - wndChild->rectWindow.top;

488 489 490 491 492 493 494 495 496 497
            hrg = CreateRectRgnIndirect( &r );
        }
        else
	   hrg = wndChild->hrgnUpdate;
        if (wndParent->hrgnUpdate != 0)
        {
            POINT ptOffset;
            RECT rect, rectParent;
            if( wndParent->hrgnUpdate == 1 )
            {
498 499 500 501 502 503 504
	       RECT r;

	       r.left = 0;
	       r.top = 0;
	       r.right = wndParent->rectWindow.right - wndParent->rectWindow.left;
	       r.bottom = wndParent->rectWindow.bottom - wndParent->rectWindow.top;

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
               wndParent->hrgnUpdate = CreateRectRgnIndirect( &r );
            }
            /* we must offset the child region by the offset of the child rect in the parent */
            GetWindowRect(wndParent->hwndSelf, &rectParent);
            GetWindowRect(wndChild->hwndSelf, &rect);
            ptOffset.x = rect.left - rectParent.left;
            ptOffset.y = rect.top - rectParent.top;
            OffsetRgn( hrg, ptOffset.x, ptOffset.y );
            CombineRgn( wndParent->hrgnUpdate, wndParent->hrgnUpdate, hrg, RGN_DIFF );
            OffsetRgn( hrg, -ptOffset.x, -ptOffset.y );
        }
        if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg );
    }
    WIN_ReleaseWndPtr(wndParent);
    WIN_ReleaseDesktop();
}
521 522 523 524 525 526 527 528 529 530

/***********************************************************************
 * 		RDW_UpdateRgns [RedrawWindow() helper] 
 *
 *  Walks the window tree and adds/removes parts of the hRgn to/from update
 *  regions of windows that overlap it. Also, manages internal paint flags.
 *
 *  NOTE: Walks the window tree so the caller must lock it.
 *	  MUST preserve hRgn (can modify but then has to restore).
 */
531
static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel )
532 533 534 535 536 537 538 539 540
{
    /* 
     * Called only when one of the following is set:
     * (RDW_INVALIDATE | RDW_VALIDATE | RDW_INTERNALPAINT | RDW_NOINTERNALPAINT)
     */

    BOOL bHadOne =  wndPtr->hrgnUpdate && hRgn;
    BOOL bChildren =  ( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
			&& ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) );
Patrik Stridvall's avatar
Patrik Stridvall committed
541 542 543 544 545 546
    RECT r;

    r.left = 0;
    r.top = 0;
    r.right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
    r.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574

    TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags );

    if( flags & RDW_INVALIDATE )
    {
	if( hRgn > 1 )
	{
	    switch( wndPtr->hrgnUpdate )
	    {
		default:
			CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_OR );
			/* fall through */
		case 0:
			wndPtr->hrgnUpdate = REGION_CropRgn( wndPtr->hrgnUpdate, 
							     wndPtr->hrgnUpdate ? wndPtr->hrgnUpdate : hRgn, 
							     &r, NULL );
			if( !bHadOne )
			{
			    GetRgnBox( wndPtr->hrgnUpdate, &r );
			    if( IsRectEmpty( &r ) )
			    {
				DeleteObject( wndPtr->hrgnUpdate );
				wndPtr->hrgnUpdate = 0;
			        goto OUT;
			    }
			}
			break;
		case 1:	/* already an entire window */
Patrik Stridvall's avatar
Patrik Stridvall committed
575
		        break;
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
	    }
	}
	else if( hRgn == 1 )
	{
	    if( wndPtr->hrgnUpdate > 1 )
		DeleteObject( wndPtr->hrgnUpdate );
	    wndPtr->hrgnUpdate = 1;
	}
	else
	    hRgn = wndPtr->hrgnUpdate;	/* this is a trick that depends on code in PAINT_RedrawWindow() */

	if( !bHadOne && !(wndPtr->flags & WIN_INTERNAL_PAINT) )
            QUEUE_IncPaintCount( wndPtr->hmemTaskQ );

	if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
	if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
	flags    |= RDW_FRAME;
    }
    else if( flags & RDW_VALIDATE )
    {
	if( wndPtr->hrgnUpdate )
	{
	    if( hRgn > 1 )
	    {
		if( wndPtr->hrgnUpdate == 1 )
		    wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r );

		if( CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hRgn, RGN_DIFF )
		    == NULLREGION )
		    goto EMPTY;
	    }
	    else /* validate everything */
	    {
		if( wndPtr->hrgnUpdate > 1 )
		{
EMPTY:
		    DeleteObject( wndPtr->hrgnUpdate );
		}
		wndPtr->hrgnUpdate = 0;
	    }

	    if( !wndPtr->hrgnUpdate )
	    {
		wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
		if( !(wndPtr->flags & WIN_INTERNAL_PAINT) )
		    QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
	    }
	}

	if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
	if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
627

Alexandre Julliard's avatar
Alexandre Julliard committed
628
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
629

630 631 632
    if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW))
        RDW_ValidateParent(wndPtr); /* validate parent covered by region */

633 634 635 636 637 638 639 640 641
    /* in/validate child windows that intersect with the region if it
     * is a valid handle. */

    if( flags & (RDW_INVALIDATE | RDW_VALIDATE) )
    {
	if( hRgn > 1 && bChildren )
	{
            WND* wnd = wndPtr->child;
	    POINT ptTotal, prevOrigin = {0,0};
Patrik Stridvall's avatar
Patrik Stridvall committed
642 643 644 645
            POINT ptClient;

            ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
            ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664

            for( ptTotal.x = ptTotal.y = 0; wnd; wnd = wnd->next )
            {
                if( wnd->dwStyle & WS_VISIBLE )
                {
		    POINT ptOffset;

                    r.left = wnd->rectWindow.left + ptClient.x;
                    r.right = wnd->rectWindow.right + ptClient.x;
                    r.top = wnd->rectWindow.top + ptClient.y;
                    r.bottom = wnd->rectWindow.bottom + ptClient.y;

		    ptOffset.x = r.left - prevOrigin.x; 
		    ptOffset.y = r.top - prevOrigin.y;
                    OffsetRect( &r, -ptTotal.x, -ptTotal.y );

                    if( RectInRegion( hRgn, &r ) )
                    {
                        OffsetRgn( hRgn, -ptOffset.x, -ptOffset.y );
665
                        RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
			prevOrigin.x = r.left + ptTotal.x;
			prevOrigin.y = r.top + ptTotal.y;
                        ptTotal.x += ptOffset.x;
                        ptTotal.y += ptOffset.y;
                    }
                }
            }
            OffsetRgn( hRgn, ptTotal.x, ptTotal.y );
	    bChildren = 0;
	}
    }

    /* handle hRgn == 1 (alias for entire window) and/or internal paint recursion */

    if( bChildren )
    {
	WND* wnd;
	for( wnd = wndPtr->child; wnd; wnd = wnd->next )
	     if( wnd->dwStyle & WS_VISIBLE )
685
		 RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
    }

OUT:

    /* Set/clear internal paint flag */

    if (flags & RDW_INTERNALPAINT)
    {
        if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
            QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
        wndPtr->flags |= WIN_INTERNAL_PAINT;
    }
    else if (flags & RDW_NOINTERNALPAINT)
    {
        if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
            QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
        wndPtr->flags &= ~WIN_INTERNAL_PAINT;
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
705

Alexandre Julliard's avatar
Alexandre Julliard committed
706
/***********************************************************************
707
 *           RDW_Paint [RedrawWindow() helper]
Alexandre Julliard's avatar
Alexandre Julliard committed
708
 *
709 710 711 712 713 714 715 716 717
 * Walks the window tree and paints/erases windows that have
 * nonzero update regions according to redraw flags. hrgn is a scratch
 * region passed down during recursion. Must not be 1.
 *
 */
static HRGN RDW_Paint( WND* wndPtr, HRGN hrgn, UINT flags, UINT ex )
{
/* NOTE: wndPtr is locked by caller.
 * 
Alexandre Julliard's avatar
Alexandre Julliard committed
718
 * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
719
 * SendMessage() calls. This is a comment inside DefWindowProc() source
Alexandre Julliard's avatar
Alexandre Julliard committed
720 721
 * from 16-bit SDK:
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
722 723 724
 *   This message avoids lots of inter-app message traffic
 *   by switching to the other task and continuing the
 *   recursion there.
725
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727 728
 * wParam         = flags
 * LOWORD(lParam) = hrgnClip
 * HIWORD(lParam) = hwndSkip  (not used; always NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
729
 *
730 731 732
 */
    HDC  hDC;
    HWND hWnd = wndPtr->hwndSelf;
733
    BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassWord(wndPtr->hwndSelf, GCW_HICON)); 
734 735 736 737 738

      /* Erase/update the window itself ... */

    TRACE_(win)("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", hWnd, wndPtr->hrgnUpdate, hrgn, flags );

739 740 741 742 743 744 745
    /*
     * Check if this window should delay it's processing of WM_NCPAINT.
     * See WIN_HaveToDelayNCPAINT for a description of the mechanism
     */
    if ((ex & RDW_EX_DELAY_NCPAINT) || WIN_HaveToDelayNCPAINT(wndPtr, 0) )
	ex |= RDW_EX_DELAY_NCPAINT;

746 747 748 749 750 751 752
    if (flags & RDW_UPDATENOW)
    {
        if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
            SendMessage16( hWnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
    }
    else if ((flags & RDW_ERASENOW) || (ex & RDW_EX_TOPFRAME))
    {
753
	UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
754 755 756 757 758 759 760 761
	HRGN hrgnRet;

	hrgnRet = WIN_UpdateNCRgn(wndPtr, 
				  hrgn, 
				  UNC_REGION | UNC_CHECK | 
				  ((ex & RDW_EX_TOPFRAME) ? UNC_ENTIRE : 0) |
				  ((ex & RDW_EX_DELAY_NCPAINT) ? UNC_DELAY_NCPAINT : 0) ); 

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
        if( hrgnRet )
	{
	    if( hrgnRet > 1 ) hrgn = hrgnRet; else hrgnRet = 0; /* entire client */
	    if( wndPtr->flags & WIN_NEEDS_ERASEBKGND )
	    {
		if( bIcon ) dcx |= DCX_WINDOW;
		else 
		if( hrgnRet )
		    OffsetRgn( hrgnRet, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
			                wndPtr->rectWindow.top  - wndPtr->rectClient.top);
		else
		    dcx &= ~DCX_INTERSECTRGN;
		if (( hDC = GetDCEx( hWnd, hrgnRet, dcx )) )
		{
		    if (SendMessage16( hWnd, (bIcon) ? WM_ICONERASEBKGND
                                       : WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
		    wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
		    ReleaseDC( hWnd, hDC );
		}
            }
        }
    }

    if( !IsWindow(hWnd) ) return hrgn;
    ex &= ~RDW_EX_TOPFRAME;

      /* ... and its child windows */

    if( wndPtr->child && !(flags & RDW_NOCHILDREN) && !(wndPtr->dwStyle & WS_MINIMIZE) 
	&& ((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)) )
    {
	WND** list, **ppWnd;

	if( (list = WIN_BuildWinArray( wndPtr, 0, NULL )) )
	{
797
            wndPtr = NULL;
798 799 800 801 802 803
	    for (ppWnd = list; *ppWnd; ppWnd++)
	    {
		WIN_UpdateWndPtr(&wndPtr,*ppWnd);
		if (!IsWindow(wndPtr->hwndSelf)) continue;
		    if ( (wndPtr->dwStyle & WS_VISIBLE) &&
			 (wndPtr->hrgnUpdate || (wndPtr->flags & WIN_INTERNAL_PAINT)) )
804
		        hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
805
	    }
806
            WIN_ReleaseWndPtr(wndPtr);
807 808 809 810 811 812 813 814 815 816
	    WIN_ReleaseWinArray(list);
	}
    }

    return hrgn;
}

/***********************************************************************
 *           PAINT_RedrawWindow
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
817
 */
818
BOOL PAINT_RedrawWindow( HWND hwnd, const RECT *rectUpdate,
819
                           HRGN hrgnUpdate, UINT flags, UINT ex )
Alexandre Julliard's avatar
Alexandre Julliard committed
820
{
821
    HRGN hRgn = 0;
822 823
    RECT r, r2;
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
824
    WND* wndPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
825

826
    if (!hwnd) hwnd = GetDesktopWindow();
Alexandre Julliard's avatar
Alexandre Julliard committed
827
    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
828 829 830

    /* check if the window or its parents are visible/not minimized */

Alexandre Julliard's avatar
Alexandre Julliard committed
831
    if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
832 833
    {
        WIN_ReleaseWndPtr(wndPtr);
834
        return TRUE; 
835
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
836

837
    if (TRACE_ON(win))
Alexandre Julliard's avatar
Alexandre Julliard committed
838
    {
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
	if( hrgnUpdate )
	{
	    GetRgnBox( hrgnUpdate, &r );
            TRACE_(win)( "%04x (%04x) NULL %04x box (%i,%i-%i,%i) flags=%04x, exflags=%04x\n", 
	          hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags, ex);
	}
	else
	{
	    if( rectUpdate )
		r = *rectUpdate;
	    else
		SetRectEmpty( &r );
	    TRACE_(win)( "%04x (%04x) %s %d,%d-%d,%d %04x flags=%04x, exflags=%04x\n",
			hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, 
			r.top, r.right, r.bottom, hrgnUpdate, flags, ex );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
855
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
856

857 858
    /* prepare an update region in window coordinates */

859 860 861 862
    if( flags & RDW_FRAME )
	r = wndPtr->rectWindow;
    else
	r = wndPtr->rectClient;
863

864
    if( ex & RDW_EX_XYWINDOW )
865 866
    {
	pt.x = pt.y = 0;
867
        OffsetRect( &r, -wndPtr->rectWindow.left, -wndPtr->rectWindow.top );
868
    }
869
    else
870 871 872
    {
	pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
	pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
873
	OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top );
874
    }
875 876

    if (flags & RDW_INVALIDATE)  /* ------------------------- Invalidate */
Alexandre Julliard's avatar
Alexandre Julliard committed
877
    {
878 879 880
	/* If the window doesn't have hrgnUpdate we leave hRgn zero
	 * and put a new region straight into wndPtr->hrgnUpdate
	 * so that RDW_UpdateRgns() won't have to do any extra work.
881
	 */
Alexandre Julliard's avatar
Alexandre Julliard committed
882

883 884
	if( hrgnUpdate )
	{
885 886 887 888
	    if( wndPtr->hrgnUpdate )
	        hRgn = REGION_CropRgn( 0, hrgnUpdate, NULL, &pt );
	    else 
		wndPtr->hrgnUpdate = REGION_CropRgn( 0, hrgnUpdate, &r, &pt ); 
889 890 891
	}
	else if( rectUpdate )
	{
892 893
	    if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
	    OffsetRect( &r2, pt.x, pt.y );
894

895
rect2i:
896 897 898
	    if( wndPtr->hrgnUpdate == 0 )
		wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 );
	    else
899
		hRgn = CreateRectRgnIndirect( &r2 );
900 901 902 903 904 905 906 907 908
	}
	else /* entire window or client depending on RDW_FRAME */
	{
	    if( flags & RDW_FRAME )
	    {
		if( wndPtr->hrgnUpdate )
		    DeleteObject( wndPtr->hrgnUpdate );
		wndPtr->hrgnUpdate = 1;
	    }
909 910 911
	    else
	    {
		GETCLIENTRECTW( wndPtr, r2 );
912
		goto rect2i;
913
	    }
914
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
915
    }
916
    else if (flags & RDW_VALIDATE)  /* ------------------------- Validate */
Alexandre Julliard's avatar
Alexandre Julliard committed
917
    {
918 919 920 921 922 923 924 925 926 927 928
	/* In this we cannot leave with zero hRgn */
	if( hrgnUpdate )
	{
	    hRgn = REGION_CropRgn( hRgn, hrgnUpdate,  &r, &pt );
	    GetRgnBox( hRgn, &r2 );
	    if( IsRectEmpty( &r2 ) ) goto END;
	}
	else if( rectUpdate )
	{
	    if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
		OffsetRect( &r2, pt.x, pt.y );
929
rect2v:
930 931 932
	    hRgn = CreateRectRgnIndirect( &r2 );
	}
	else /* entire window or client depending on RDW_FRAME */
Alexandre Julliard's avatar
Alexandre Julliard committed
933
        {
934 935
	    if( flags & RDW_FRAME ) 
		hRgn = 1;
936 937
	    else
	    {
938 939
		GETCLIENTRECTW( wndPtr, r2 );
		goto rect2v;
Alexandre Julliard's avatar
Alexandre Julliard committed
940 941
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
942 943
    }

944
    /* At this point hRgn is either an update region in window coordinates or 1 or 0 */
Alexandre Julliard's avatar
Alexandre Julliard committed
945

946
    RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE );
947

948
    /* Erase/update windows, from now on hRgn is a scratch region */
949

950
    hRgn = RDW_Paint( wndPtr, (hRgn == 1) ? 0 : hRgn, flags, ex );
951 952

END:
953 954
    if( hRgn > 1 && (hRgn != hrgnUpdate) )
	DeleteObject(hRgn );
955
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
956 957 958 959
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
960
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
961
 *           RedrawWindow32    (USER32.426)
Alexandre Julliard's avatar
Alexandre Julliard committed
962
 */
963 964
BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate,
                              HRGN hrgnUpdate, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
965
{
Alexandre Julliard's avatar
Alexandre Julliard committed
966
    return PAINT_RedrawWindow( hwnd, rectUpdate, hrgnUpdate, flags, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
967 968 969
}


Alexandre Julliard's avatar
Alexandre Julliard committed
970
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
971
 *           RedrawWindow16    (USER.290)
Alexandre Julliard's avatar
Alexandre Julliard committed
972
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
973 974
BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
                              HRGN16 hrgnUpdate, UINT16 flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
975
{
Alexandre Julliard's avatar
Alexandre Julliard committed
976 977
    if (rectUpdate)
    {
978
        RECT r;
Alexandre Julliard's avatar
Alexandre Julliard committed
979
        CONV_RECT16TO32( rectUpdate, &r );
980
        return (BOOL16)RedrawWindow( (HWND)hwnd, &r, hrgnUpdate, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
981
    }
982 983
    return (BOOL16)PAINT_RedrawWindow( (HWND)hwnd, NULL, 
				       (HRGN)hrgnUpdate, flags, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
984 985 986 987
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
988
 *           UpdateWindow16   (USER.124)
Alexandre Julliard's avatar
Alexandre Julliard committed
989
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
990
void WINAPI UpdateWindow16( HWND16 hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
991
{
Alexandre Julliard's avatar
Alexandre Julliard committed
992
    PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
993 994 995
}

/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
996
 *           UpdateWindow32   (USER32.567)
Alexandre Julliard's avatar
Alexandre Julliard committed
997
 */
998
void WINAPI UpdateWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
999
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1000
    PAINT_RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1001 1002 1003
}

/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1004
 *           InvalidateRgn16   (USER.126)
Alexandre Julliard's avatar
Alexandre Julliard committed
1005
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1006
void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1007
{
1008
    PAINT_RedrawWindow((HWND)hwnd, NULL, (HRGN)hrgn, 
Alexandre Julliard's avatar
Alexandre Julliard committed
1009
		       RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1010 1011 1012 1013
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1014
 *           InvalidateRgn32   (USER32.329)
Alexandre Julliard's avatar
Alexandre Julliard committed
1015
 */
1016
BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1017
{
1018
    return PAINT_RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1019 1020 1021 1022
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1023
 *           InvalidateRect16   (USER.125)
Alexandre Julliard's avatar
Alexandre Julliard committed
1024
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1025
void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1026
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1027
    RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1028 1029 1030 1031
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1032
 *           InvalidateRect32   (USER32.328)
Alexandre Julliard's avatar
Alexandre Julliard committed
1033
 */
1034
BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1035
{
1036 1037
    return PAINT_RedrawWindow( hwnd, rect, 0, 
			       RDW_INVALIDATE | (erase ? RDW_ERASE : 0), 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1038 1039 1040 1041
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1042 1043
 *           ValidateRgn16   (USER.128)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1044
void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
1045
{
1046
    PAINT_RedrawWindow( (HWND)hwnd, NULL, (HRGN)hrgn, 
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
			RDW_VALIDATE | RDW_NOCHILDREN, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049 1050 1051
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1052
 *           ValidateRgn32   (USER32.572)
Alexandre Julliard's avatar
Alexandre Julliard committed
1053
 */
1054
void WINAPI ValidateRgn( HWND hwnd, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
1055
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1056
    PAINT_RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1057 1058 1059 1060 1061 1062
}


/***********************************************************************
 *           ValidateRect16   (USER.127)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1063
void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1064 1065 1066 1067 1068 1069
{
    RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1070
 *           ValidateRect32   (USER32.571)
Alexandre Julliard's avatar
Alexandre Julliard committed
1071
 */
1072
void WINAPI ValidateRect( HWND hwnd, const RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1073
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
    PAINT_RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076 1077 1078 1079 1080
}


/***********************************************************************
 *           GetUpdateRect16   (USER.190)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1081
BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1082
{
1083
    RECT r;
Alexandre Julliard's avatar
Alexandre Julliard committed
1084 1085
    BOOL16 ret;

1086 1087
    if (!rect) return GetUpdateRect( hwnd, NULL, erase );
    ret = GetUpdateRect( hwnd, &r, erase );
Alexandre Julliard's avatar
Alexandre Julliard committed
1088 1089
    CONV_RECT32TO16( &r, rect );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091 1092 1093
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1094
 *           GetUpdateRect32   (USER32.297)
Alexandre Julliard's avatar
Alexandre Julliard committed
1095
 */
1096
BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1097
{
1098
    BOOL retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1099 1100 1101 1102 1103
    WND * wndPtr = WIN_FindWndPtr( hwnd );
    if (!wndPtr) return FALSE;

    if (rect)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
	if (wndPtr->hrgnUpdate > 1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1105
	{
1106
	    HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1107 1108 1109 1110 1111
            if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR)
            {
                retvalue = FALSE;
                goto END;
            }
1112 1113
	    GetRgnBox( hrgn, rect );
	    DeleteObject( hrgn );
1114
	    if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_OWNDC)
1115
	    {
1116
		if (GetMapMode(wndPtr->dce->hDC) != MM_TEXT)
1117
		{
1118
		    DPtoLP (wndPtr->dce->hDC, (LPPOINT)rect,  2);
1119 1120
		}
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1121
	}
1122 1123 1124 1125 1126 1127 1128 1129
	else
	if( wndPtr->hrgnUpdate == 1 )
	{
	    GetClientRect( hwnd, rect );
	    if (erase) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_ERASENOW | RDW_NOCHILDREN );
	}
	else 
	    SetRectEmpty( rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1130
    }
1131
    retvalue = (wndPtr->hrgnUpdate >= 1);
1132 1133 1134
END:
    WIN_ReleaseWndPtr(wndPtr);
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1135 1136 1137 1138
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1139 1140
 *           GetUpdateRgn16   (USER.237)
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1141
INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1142
{
1143
    return GetUpdateRgn( hwnd, hrgn, erase );
Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145 1146 1147
}


/***********************************************************************
1148
 *           GetUpdateRgn    (USER32.298)
Alexandre Julliard's avatar
Alexandre Julliard committed
1149
 */
1150
INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1151
{
1152
    INT retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
1153 1154 1155
    WND * wndPtr = WIN_FindWndPtr( hwnd );
    if (!wndPtr) return ERROR;

1156
    if (wndPtr->hrgnUpdate == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1157
    {
1158
        SetRectRgn( hrgn, 0, 0, 0, 0 );
1159 1160
        retval = NULLREGION;
        goto END;
Alexandre Julliard's avatar
Alexandre Julliard committed
1161
    }
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
    else
    if (wndPtr->hrgnUpdate == 1)
    {
	SetRectRgn( hrgn, 0, 0, wndPtr->rectClient.right - wndPtr->rectClient.left,
				wndPtr->rectClient.bottom - wndPtr->rectClient.top );
	retval = SIMPLEREGION;
    }
    else
    {
	retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
	OffsetRgn( hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left,
			 wndPtr->rectWindow.top - wndPtr->rectClient.top );
    }
1175
    if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
1176 1177
END:
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1178 1179 1180 1181 1182
    return retval;
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1183
 *           ExcludeUpdateRgn16   (USER.238)
Alexandre Julliard's avatar
Alexandre Julliard committed
1184
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1185
INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1186
{
1187
    return ExcludeUpdateRgn( hdc, hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1188 1189 1190 1191
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1192
 *           ExcludeUpdateRgn32   (USER32.195)
Alexandre Julliard's avatar
Alexandre Julliard committed
1193
 */
1194
INT WINAPI ExcludeUpdateRgn( HDC hdc, HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1195
{
1196
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1197 1198 1199
    WND * wndPtr;

    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1200 1201

    if (wndPtr->hrgnUpdate)
Alexandre Julliard's avatar
Alexandre Julliard committed
1202
    {
1203 1204
	INT ret;
	HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left,
Alexandre Julliard's avatar
Alexandre Julliard committed
1205
				      wndPtr->rectWindow.top - wndPtr->rectClient.top,
1206 1207
				      wndPtr->rectWindow.right - wndPtr->rectClient.left,
				      wndPtr->rectWindow.bottom - wndPtr->rectClient.top);
Alexandre Julliard's avatar
Alexandre Julliard committed
1208
	if( wndPtr->hrgnUpdate > 1 )
1209
	{
1210
	    CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
1211 1212 1213
	    OffsetRgn(hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
			    wndPtr->rectWindow.top - wndPtr->rectClient.top );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1214 1215 1216 1217

	/* do ugly coordinate translations in dce.c */

	ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
1218
	DeleteObject( hrgn );
1219
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1220 1221
	return ret;
    } 
1222
    WIN_ReleaseWndPtr(wndPtr);
1223
    return GetClipBox( hdc, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1224
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1225 1226