painting.c 49.9 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 <string.h>
9 10 11
#include "windef.h"
#include "wingdi.h"
#include "wine/winuser16.h"
12
#include "wine/unicode.h"
13
#include "server.h"
14
#include "region.h"
15
#include "user.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
16
#include "win.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
17
#include "queue.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
18
#include "dce.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
19
#include "heap.h"
20
#include "debugtools.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
21

22 23
DEFAULT_DEBUG_CHANNEL(win);
DECLARE_DEBUG_CHANNEL(nonclient);
24

25 26 27 28 29 30 31
/* 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

32 33 34 35 36 37 38 39 40 41 42
  /* PAINT_RedrawWindow() control flags */
#define RDW_EX_DELAY_NCPAINT    0x0020

  /* WIN_UpdateNCRgn() flags */
#define UNC_CHECK		0x0001
#define UNC_ENTIRE		0x0002
#define UNC_REGION		0x0004
#define UNC_UPDATE		0x0008
#define UNC_DELAY_NCPAINT       0x0010
#define UNC_IN_BEGINPAINT       0x0020

43 44 45
  /* Last COLOR id */
#define COLOR_MAX   COLOR_GRADIENTINACTIVECAPTION

Alexandre Julliard's avatar
Alexandre Julliard committed
46 47 48
  /* Last CTLCOLOR id */
#define CTLCOLOR_MAX   CTLCOLOR_STATIC

49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/***********************************************************************
 *           add_paint_count
 *
 * Add an increment (normally 1 or -1) to the current paint count of a window.
 */
static void add_paint_count( HWND hwnd, int incr )
{
    SERVER_START_REQ( inc_queue_paint_count )
    {
        req->id   = (void *)GetWindowThreadProcessId( hwnd, NULL );
        req->incr = incr;
        SERVER_CALL();
    }
    SERVER_END_REQ;
}


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 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
/***********************************************************************
 *           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
145
/***********************************************************************
146
 *           WIN_UpdateNCRgn
Alexandre Julliard's avatar
Alexandre Julliard committed
147
 *
148 149 150 151 152 153 154 155 156 157
 *  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
158
 */
159
static HRGN WIN_UpdateNCRgn(WND* wnd, HRGN hRgn, UINT uncFlags )
Alexandre Julliard's avatar
Alexandre Julliard committed
160
{
161 162 163
    RECT  r;
    HRGN  hClip = 0;
    HRGN  hrgnRet = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
164

165 166
    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
167

168
    /* desktop window doesn't have a nonclient area */
Alexandre Julliard's avatar
Alexandre Julliard committed
169 170 171
    if(wnd == WIN_GetDesktop()) 
    {
        wnd->flags &= ~WIN_NEEDS_NCPAINT;
172 173 174 175 176 177
	if( wnd->hrgnUpdate > 1 )
	    hrgnRet = REGION_CropRgn( hRgn, wnd->hrgnUpdate, NULL, NULL );
	else 
	{
	    hrgnRet = wnd->hrgnUpdate;
	}
178
        WIN_ReleaseDesktop();
179
        return hrgnRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
180
    }
181
    WIN_ReleaseDesktop();
Alexandre Julliard's avatar
Alexandre Julliard committed
182

183
    if ((wnd->hwndSelf == GetForegroundWindow()) &&
184
        !(wnd->flags & WIN_NCACTIVATED) )
Alexandre Julliard's avatar
Alexandre Julliard committed
185
    {
186
	wnd->flags |= WIN_NCACTIVATED;
187
	uncFlags |= UNC_ENTIRE; 
188
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
189

190 191 192 193 194
    /*
     * If the window's non-client area needs to be painted, 
     */
    if ( ( wnd->flags & WIN_NEEDS_NCPAINT ) &&
	 !WIN_HaveToDelayNCPAINT(wnd, uncFlags) )
195
    {
196
	    RECT r2, r3;
Alexandre Julliard's avatar
Alexandre Julliard committed
197

198 199
	    wnd->flags &= ~WIN_NEEDS_NCPAINT;  
	    GETCLIENTRECTW( wnd, r );
Alexandre Julliard's avatar
Alexandre Julliard committed
200

201 202 203 204 205
	    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
206

207 208 209 210 211 212 213
		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
214

215 216 217 218
		    hClip = wnd->hrgnUpdate;
		    wnd->hrgnUpdate = REGION_CropRgn( hRgn, hClip, &r, NULL );
		    if( uncFlags & UNC_REGION ) hrgnRet = hClip;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
219

220
		if( uncFlags & UNC_CHECK )
221
		{
222 223 224 225 226 227 228 229 230
		    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))
231
			    add_paint_count( wnd->hwndSelf, -1 );
232 233 234

			wnd->flags &= ~WIN_NEEDS_ERASEBKGND;
		    }
235
		}
236 237 238 239 240 241 242 243 244

		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;
245
	    }
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
    }
    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;
261
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263
    }

264 265 266 267 268
    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);
    }
269

270 271
    if( hClip ) /* NOTE: WM_NCPAINT allows wParam to be 1 */
    {
272 273 274 275 276
        if ( hClip == hrgnRet && hrgnRet > 1 ) {
	    hClip = CreateRectRgn( 0, 0, 0, 0 );
	    CombineRgn( hClip, hrgnRet, 0, RGN_COPY );
	}

277
	SendMessageA( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
278 279
	if( (hClip > 1) && (hClip != hRgn) && (hClip != hrgnRet) )
	    DeleteObject( hClip );
280 281 282 283 284 285 286 287 288
	/*
         * 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;
        }
289
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
290

291 292 293
    TRACE_(nonclient)("returning %04x (hClip = %04x, hrgnUpdate = %04x)\n", hrgnRet, hClip, wnd->hrgnUpdate );

    return hrgnRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
294 295
}

Alexandre Julliard's avatar
Alexandre Julliard committed
296 297

/***********************************************************************
298
 *		BeginPaint (USER.39)
Alexandre Julliard's avatar
Alexandre Julliard committed
299
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
300
HDC16 WINAPI BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps ) 
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
{
    PAINTSTRUCT ps;

    BeginPaint( hwnd, &ps );
    lps->hdc            = ps.hdc;
    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;
}


/***********************************************************************
318
 *		BeginPaint (USER32.@)
319 320
 */
HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
321
{
322 323
    BOOL bIcon;
    HRGN hrgnUpdate;
324
    RECT clipRect, clientRect;
Alexandre Julliard's avatar
Alexandre Julliard committed
325
    WND *wndPtr = WIN_FindWndPtr( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
326 327
    if (!wndPtr) return 0;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
330
    wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
Alexandre Julliard's avatar
Alexandre Julliard committed
331

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

335 336 337 338 339 340 341 342 343 344
    /*
     * 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;
    }

345
    if( ((hrgnUpdate = wndPtr->hrgnUpdate) != 0) || (wndPtr->flags & WIN_INTERNAL_PAINT))
346
        add_paint_count( hwnd, -1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
347 348

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

351
    HideCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
352

353
    TRACE("hrgnUpdate = %04x, \n", hrgnUpdate);
Alexandre Julliard's avatar
Alexandre Julliard committed
354

355
    if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_PARENTDC)
Alexandre Julliard's avatar
Alexandre Julliard committed
356
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
357
        /* Don't clip the output to the update region for CS_PARENTDC window */
358
	if( hrgnUpdate ) 
359
	    DeleteObject(hrgnUpdate);
360
        lps->hdc = GetDCEx( hwnd, 0, DCX_WINDOWPAINT | DCX_USESTYLE |
Alexandre Julliard's avatar
Alexandre Julliard committed
361
                              (bIcon ? DCX_WINDOW : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
362
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
363
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
364
    {
365
	if( hrgnUpdate ) /* convert to client coordinates */
366 367
	    OffsetRgn( hrgnUpdate, wndPtr->rectWindow.left - wndPtr->rectClient.left,
			           wndPtr->rectWindow.top - wndPtr->rectClient.top );
368
        lps->hdc = GetDCEx(hwnd, hrgnUpdate, DCX_INTERSECTRGN | 
369 370
                             DCX_WINDOWPAINT | DCX_USESTYLE | (bIcon ? DCX_WINDOW : 0) );
	/* ReleaseDC() in EndPaint() will delete the region */
Alexandre Julliard's avatar
Alexandre Julliard committed
371
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
372

373
    TRACE("hdc = %04x\n", lps->hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
374

Alexandre Julliard's avatar
Alexandre Julliard committed
375 376
    if (!lps->hdc)
    {
377
        WARN("GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
378
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
379 380
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
381

382 383 384 385 386
    /* 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  */
    
387
    GetClientRect( hwnd, &clientRect );
388

389 390
    GetClipBox( lps->hdc, &clipRect );
    LPtoDP(lps->hdc, (LPPOINT)&clipRect, 2);      /* GetClipBox returns LP */
391

392
    IntersectRect(&lps->rcPaint, &clientRect, &clipRect);
393
    DPtoLP(lps->hdc, (LPPOINT)&lps->rcPaint, 2);  /* we must return LP */
Alexandre Julliard's avatar
Alexandre Julliard committed
394

395
    TRACE("box = (%i,%i - %i,%i)\n", lps->rcPaint.left, lps->rcPaint.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397
		    lps->rcPaint.right, lps->rcPaint.bottom );

Alexandre Julliard's avatar
Alexandre Julliard committed
398 399 400
    if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
    {
        wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
401 402
        lps->fErase = !SendMessageA(hwnd, (bIcon) ? WM_ICONERASEBKGND : WM_ERASEBKGND,
                                    (WPARAM16)lps->hdc, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
403 404
    }
    else lps->fErase = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
405

406
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
407 408 409 410
    return lps->hdc;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
411
/***********************************************************************
412
 *		EndPaint (USER.40)
Alexandre Julliard's avatar
Alexandre Julliard committed
413
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
414
BOOL16 WINAPI EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
415
{
Alexandre Julliard's avatar
Alexandre Julliard committed
416
    ReleaseDC16( hwnd, lps->hdc );
417
    ShowCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
418
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
419 420 421
}


Alexandre Julliard's avatar
Alexandre Julliard committed
422
/***********************************************************************
423
 *		EndPaint (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
424
 */
425
BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
Alexandre Julliard's avatar
Alexandre Julliard committed
426
{
427 428
    ReleaseDC( hwnd, lps->hdc );
    ShowCaret( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
429 430 431 432
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
433
/***********************************************************************
434
 *		FillWindow (USER.324)
Alexandre Julliard's avatar
Alexandre Julliard committed
435
 */
436
void WINAPI FillWindow16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
Alexandre Julliard's avatar
Alexandre Julliard committed
437
{
438 439 440 441 442 443
    RECT rect;
    RECT16 rc16;
    GetClientRect( hwnd, &rect );
    DPtoLP( hdc, (LPPOINT)&rect, 2 );
    CONV_RECT32TO16( &rect, &rc16 );
    PaintRect16( hwndParent, hwnd, hdc, hbrush, &rc16 );
Alexandre Julliard's avatar
Alexandre Julliard committed
444 445 446
}


Alexandre Julliard's avatar
Alexandre Julliard committed
447 448 449
/***********************************************************************
 *	     PAINT_GetControlBrush
 */
450
static HBRUSH16 PAINT_GetControlBrush( HWND hParent, HWND hWnd, HDC16 hDC, UINT16 ctlType )
Alexandre Julliard's avatar
Alexandre Julliard committed
451
{
452 453 454
    HBRUSH16 bkgBrush = (HBRUSH16)SendMessageA( hParent, WM_CTLCOLORMSGBOX + ctlType, 
							     (WPARAM)hDC, (LPARAM)hWnd );
    if( !IsGDIObject16(bkgBrush) )
Alexandre Julliard's avatar
Alexandre Julliard committed
455 456 457 458 459
	bkgBrush = DEFWND_ControlColor( hDC, ctlType );
    return bkgBrush;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
460
/***********************************************************************
461
 *		PaintRect (USER.325)
Alexandre Julliard's avatar
Alexandre Julliard committed
462
 */
463
void WINAPI PaintRect16( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
Alexandre Julliard's avatar
Alexandre Julliard committed
464
                       HBRUSH16 hbrush, const RECT16 *rect)
Alexandre Julliard's avatar
Alexandre Julliard committed
465
{
Alexandre Julliard's avatar
Alexandre Julliard committed
466
    if( hbrush <= CTLCOLOR_MAX ) 
467
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
468 469 470 471
	if( hwndParent )
	    hbrush = PAINT_GetControlBrush( hwndParent, hwnd, hdc, (UINT16)hbrush );
	else 
	    return;
472
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
473 474
    if( hbrush ) 
	FillRect16( hdc, rect, hbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
475
}
Alexandre Julliard's avatar
Alexandre Julliard committed
476 477


Alexandre Julliard's avatar
Alexandre Julliard committed
478
/***********************************************************************
479
 *		GetControlBrush (USER.326)
Alexandre Julliard's avatar
Alexandre Julliard committed
480
 */
481
HBRUSH16 WINAPI GetControlBrush16( HWND16 hwnd, HDC16 hdc, UINT16 ctlType )
Alexandre Julliard's avatar
Alexandre Julliard committed
482
{
Alexandre Julliard's avatar
Alexandre Julliard committed
483
    WND* wndPtr = WIN_FindWndPtr( hwnd );
484
    HBRUSH16 retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
485 486 487 488

    if((ctlType <= CTLCOLOR_MAX) && wndPtr )
    {
	WND* parent;
489 490
	if( wndPtr->dwStyle & WS_POPUP ) parent = WIN_LockWndPtr(wndPtr->owner);
	else parent = WIN_LockWndPtr(wndPtr->parent);
Alexandre Julliard's avatar
Alexandre Julliard committed
491
	if( !parent ) parent = wndPtr;
492 493 494 495 496 497 498 499
	retvalue = (HBRUSH16)PAINT_GetControlBrush( parent->hwndSelf, hwnd, hdc, ctlType );
        WIN_ReleaseWndPtr(parent);
        goto END;
    }
    retvalue = (HBRUSH16)0;
END:
    WIN_ReleaseWndPtr(wndPtr);
    return retvalue;
500 501
}

502 503 504 505

/***********************************************************************
 * 		RDW_ValidateParent [RDW_UpdateRgns() helper] 
 *
506
 *  Validate the portions of parents that are covered by a validated child
507 508
 *  wndPtr = child
 */
509
static void RDW_ValidateParent(WND *wndChild)
510 511 512
{
    WND *wndParent = WIN_LockWndPtr(wndChild->parent);
    WND *wndDesktop = WIN_GetDesktop();
513 514 515 516 517 518 519 520 521 522 523 524 525 526
    HRGN hrg;

    if (wndChild->hrgnUpdate == 1 ) {
        RECT r;
        r.left = 0;
        r.top = 0;
        r.right = wndChild->rectWindow.right - wndChild->rectWindow.left;
        r.bottom = wndChild->rectWindow.bottom - wndChild->rectWindow.top;
        hrg = CreateRectRgnIndirect( &r );
    } else
        hrg = wndChild->hrgnUpdate;

    while ((wndParent) && (wndParent != wndDesktop) ) {
        if (!(wndParent->dwStyle & WS_CLIPCHILDREN))
527
        {
528
            if (wndParent->hrgnUpdate != 0)
529
            {
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
                POINT ptOffset;
                RECT rect, rectParent;
                if( wndParent->hrgnUpdate == 1 )
                {
                   RECT r;

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

                   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 );
551 552
            }
        }
553
        WIN_UpdateWndPtr(&wndParent, wndParent->parent);    
554
    }
555
    if (hrg != wndChild->hrgnUpdate) DeleteObject( hrg );
556 557 558
    WIN_ReleaseWndPtr(wndParent);
    WIN_ReleaseDesktop();
}
559 560 561 562 563 564 565 566 567 568

/***********************************************************************
 * 		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).
 */
569
static void RDW_UpdateRgns( WND* wndPtr, HRGN hRgn, UINT flags, BOOL firstRecursLevel )
570 571 572 573 574 575 576 577 578
{
    /* 
     * 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
579 580 581 582 583 584
    RECT r;

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

586
    TRACE("\thwnd %04x [%04x] -> hrgn [%04x], flags [%04x]\n", wndPtr->hwndSelf, wndPtr->hrgnUpdate, hRgn, flags );
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

    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;
608
			        goto end;
609 610 611 612
			    }
			}
			break;
		case 1:	/* already an entire window */
Patrik Stridvall's avatar
Patrik Stridvall committed
613
		        break;
614 615 616 617 618 619 620 621 622 623 624 625
	    }
	}
	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) )
626
            add_paint_count( wndPtr->hwndSelf, 1 );
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642

	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 )
643 644 645 646
                {
                    DeleteObject( wndPtr->hrgnUpdate );
                    wndPtr->hrgnUpdate = 0;
                }
647 648 649
	    }
	    else /* validate everything */
	    {
650
		if( wndPtr->hrgnUpdate > 1 ) DeleteObject( wndPtr->hrgnUpdate );
651 652 653 654 655 656 657
		wndPtr->hrgnUpdate = 0;
	    }

	    if( !wndPtr->hrgnUpdate )
	    {
		wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
		if( !(wndPtr->flags & WIN_INTERNAL_PAINT) )
658
                    add_paint_count( wndPtr->hwndSelf, -1 );
659 660 661 662 663
	    }
	}

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

Alexandre Julliard's avatar
Alexandre Julliard committed
665
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
666

667 668 669
    if ((firstRecursLevel) && (wndPtr->hrgnUpdate != 0) && (flags & RDW_UPDATENOW))
        RDW_ValidateParent(wndPtr); /* validate parent covered by region */

670 671 672 673 674 675 676 677 678
    /* 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
679 680 681 682
            POINT ptClient;

            ptClient.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
            ptClient.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701

            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 );
702
                        RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
			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 )
722
		 RDW_UpdateRgns( wnd, hRgn, flags, FALSE );
723 724
    }

725
end:
726 727 728 729 730 731

    /* Set/clear internal paint flag */

    if (flags & RDW_INTERNALPAINT)
    {
        if ( !wndPtr->hrgnUpdate && !(wndPtr->flags & WIN_INTERNAL_PAINT))
732
            add_paint_count( wndPtr->hwndSelf, 1 );
733 734 735 736 737
        wndPtr->flags |= WIN_INTERNAL_PAINT;
    }
    else if (flags & RDW_NOINTERNALPAINT)
    {
        if ( !wndPtr->hrgnUpdate && (wndPtr->flags & WIN_INTERNAL_PAINT))
738
            add_paint_count( wndPtr->hwndSelf, -1 );
739 740 741
        wndPtr->flags &= ~WIN_INTERNAL_PAINT;
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
742

Alexandre Julliard's avatar
Alexandre Julliard committed
743
/***********************************************************************
744
 *           RDW_Paint [RedrawWindow() helper]
Alexandre Julliard's avatar
Alexandre Julliard committed
745
 *
746 747 748 749 750 751 752 753 754
 * 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
755
 * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask
756
 * SendMessage() calls. This is a comment inside DefWindowProc() source
Alexandre Julliard's avatar
Alexandre Julliard committed
757 758
 * from 16-bit SDK:
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
759 760 761
 *   This message avoids lots of inter-app message traffic
 *   by switching to the other task and continuing the
 *   recursion there.
762
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
763 764 765
 * wParam         = flags
 * LOWORD(lParam) = hrgnClip
 * HIWORD(lParam) = hwndSkip  (not used; always NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
766
 *
767 768 769
 */
    HDC  hDC;
    HWND hWnd = wndPtr->hwndSelf;
770
    BOOL bIcon = ((wndPtr->dwStyle & WS_MINIMIZE) && GetClassWord(wndPtr->hwndSelf, GCW_HICON)); 
771 772 773

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

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

776 777 778 779 780 781 782
    /*
     * 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;

783 784 785 786 787
    if (flags & RDW_UPDATENOW)
    {
        if (wndPtr->hrgnUpdate) /* wm_painticon wparam is 1 */
            SendMessage16( hWnd, (bIcon) ? WM_PAINTICON : WM_PAINT, bIcon, 0 );
    }
788
    else if (flags & RDW_ERASENOW)
789
    {
790
	UINT dcx = DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT | DCX_CACHE;
791 792 793 794 795 796 797
	HRGN hrgnRet;

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

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
        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;

      /* ... 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 )) )
	{
832
            wndPtr = NULL;
833 834 835 836 837 838
	    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)) )
839
		        hrgn = RDW_Paint( wndPtr, hrgn, flags, ex );
840
	    }
841
            WIN_ReleaseWndPtr(wndPtr);
842 843 844 845 846 847 848
	    WIN_ReleaseWinArray(list);
	}
    }

    return hrgn;
}

849

850
/***********************************************************************
851
 *		RedrawWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
852
 */
853 854
BOOL WINAPI RedrawWindow( HWND hwnd, const RECT *rectUpdate,
                              HRGN hrgnUpdate, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
855
{
856
    HRGN hRgn = 0;
857 858
    RECT r, r2;
    POINT pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
859
    WND* wndPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
860

861
    if (!hwnd) hwnd = GetDesktopWindow();
Alexandre Julliard's avatar
Alexandre Julliard committed
862
    if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
863 864 865

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

Alexandre Julliard's avatar
Alexandre Julliard committed
866
    if (!WIN_IsWindowDrawable( wndPtr, !(flags & RDW_FRAME) ) )
867 868
    {
        WIN_ReleaseWndPtr(wndPtr);
869
        return TRUE; 
870
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
871

872
    if (TRACE_ON(win))
Alexandre Julliard's avatar
Alexandre Julliard committed
873
    {
874 875 876
	if( hrgnUpdate )
	{
	    GetRgnBox( hrgnUpdate, &r );
877 878
            TRACE( "%04x (%04x) NULL %04x box (%i,%i-%i,%i) flags=%04x\n",
	          hwnd, wndPtr->hrgnUpdate, hrgnUpdate, r.left, r.top, r.right, r.bottom, flags );
879 880 881 882 883 884 885
	}
	else
	{
	    if( rectUpdate )
		r = *rectUpdate;
	    else
		SetRectEmpty( &r );
886
	    TRACE( "%04x (%04x) %s %d,%d-%d,%d %04x flags=%04x\n",
887
			hwnd, wndPtr->hrgnUpdate, rectUpdate ? "rect" : "NULL", r.left, 
888
			r.top, r.right, r.bottom, hrgnUpdate, flags );
889
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
890
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
891

892 893
    /* prepare an update region in window coordinates */

894 895 896 897
    if( flags & RDW_FRAME )
	r = wndPtr->rectWindow;
    else
	r = wndPtr->rectClient;
898

899 900 901
    pt.x = wndPtr->rectClient.left - wndPtr->rectWindow.left;
    pt.y = wndPtr->rectClient.top - wndPtr->rectWindow.top;
    OffsetRect( &r, -wndPtr->rectClient.left, -wndPtr->rectClient.top );
902 903

    if (flags & RDW_INVALIDATE)  /* ------------------------- Invalidate */
Alexandre Julliard's avatar
Alexandre Julliard committed
904
    {
905 906 907
	/* 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.
908
	 */
Alexandre Julliard's avatar
Alexandre Julliard committed
909

910 911
	if( hrgnUpdate )
	{
912 913 914 915
	    if( wndPtr->hrgnUpdate )
	        hRgn = REGION_CropRgn( 0, hrgnUpdate, NULL, &pt );
	    else 
		wndPtr->hrgnUpdate = REGION_CropRgn( 0, hrgnUpdate, &r, &pt ); 
916 917 918
	}
	else if( rectUpdate )
	{
919 920
	    if( !IntersectRect( &r2, &r, rectUpdate ) ) goto END;
	    OffsetRect( &r2, pt.x, pt.y );
921

922
rect2i:
923 924 925
	    if( wndPtr->hrgnUpdate == 0 )
		wndPtr->hrgnUpdate = CreateRectRgnIndirect( &r2 );
	    else
926
		hRgn = CreateRectRgnIndirect( &r2 );
927 928 929 930 931 932 933 934 935
	}
	else /* entire window or client depending on RDW_FRAME */
	{
	    if( flags & RDW_FRAME )
	    {
		if( wndPtr->hrgnUpdate )
		    DeleteObject( wndPtr->hrgnUpdate );
		wndPtr->hrgnUpdate = 1;
	    }
936 937 938
	    else
	    {
		GETCLIENTRECTW( wndPtr, r2 );
939
		goto rect2i;
940
	    }
941
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
942
    }
943
    else if (flags & RDW_VALIDATE)  /* ------------------------- Validate */
Alexandre Julliard's avatar
Alexandre Julliard committed
944
    {
945 946 947 948 949 950 951 952 953 954 955 956 957 958
	/* 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 );
	    hRgn = CreateRectRgnIndirect( &r2 );
	}
	else /* entire window or client depending on RDW_FRAME */
Alexandre Julliard's avatar
Alexandre Julliard committed
959
        {
960 961
	    if( flags & RDW_FRAME ) 
		hRgn = 1;
962 963
	    else
	    {
964
		GETCLIENTRECTW( wndPtr, r2 );
965
                hRgn = CreateRectRgnIndirect( &r2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
966 967
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
968 969
    }

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

972
    RDW_UpdateRgns( wndPtr, hRgn, flags, TRUE );
973

974
    /* Erase/update windows, from now on hRgn is a scratch region */
975

976
    hRgn = RDW_Paint( wndPtr, (hRgn == 1) ? 0 : hRgn, flags, 0 );
977 978

END:
979 980
    if( hRgn > 1 && (hRgn != hrgnUpdate) )
	DeleteObject(hRgn );
981
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
982 983 984 985 986
    return TRUE;
}


/***********************************************************************
987
 *		RedrawWindow (USER.290)
Alexandre Julliard's avatar
Alexandre Julliard committed
988
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
989 990
BOOL16 WINAPI RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
                              HRGN16 hrgnUpdate, UINT16 flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
991
{
Alexandre Julliard's avatar
Alexandre Julliard committed
992 993
    if (rectUpdate)
    {
994
        RECT r;
Alexandre Julliard's avatar
Alexandre Julliard committed
995
        CONV_RECT16TO32( rectUpdate, &r );
996
        return (BOOL16)RedrawWindow( (HWND)hwnd, &r, hrgnUpdate, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
997
    }
998
    return RedrawWindow( hwnd, NULL, hrgnUpdate, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
999 1000 1001 1002
}


/***********************************************************************
1003
 *		UpdateWindow (USER.124)
Alexandre Julliard's avatar
Alexandre Julliard committed
1004
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1005
void WINAPI UpdateWindow16( HWND16 hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1006
{
1007
    RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1008 1009 1010
}

/***********************************************************************
1011
 *		UpdateWindow (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1012
 */
1013
void WINAPI UpdateWindow( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1014
{
1015
    RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1016 1017 1018
}

/***********************************************************************
1019
 *		InvalidateRgn (USER.126)
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1021
void WINAPI InvalidateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1022
{
1023
    RedrawWindow((HWND)hwnd, NULL, (HRGN)hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1024 1025 1026 1027
}


/***********************************************************************
1028
 *		InvalidateRgn (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1029
 */
1030
BOOL WINAPI InvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1031
{
1032
    return RedrawWindow(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1033 1034 1035 1036
}


/***********************************************************************
1037
 *		InvalidateRect (USER.125)
Alexandre Julliard's avatar
Alexandre Julliard committed
1038
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1039
void WINAPI InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1040
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1041
    RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1042 1043 1044 1045
}


/***********************************************************************
1046
 *		InvalidateRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
 */
1048
BOOL WINAPI InvalidateRect( HWND hwnd, const RECT *rect, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
{
1050
    return RedrawWindow( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1051 1052 1053 1054
}


/***********************************************************************
1055
 *		ValidateRgn (USER.128)
Alexandre Julliard's avatar
Alexandre Julliard committed
1056
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1057
void WINAPI ValidateRgn16( HWND16 hwnd, HRGN16 hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
1058
{
1059
    RedrawWindow( (HWND)hwnd, NULL, (HRGN)hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1060 1061 1062 1063
}


/***********************************************************************
1064
 *		ValidateRgn (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1065
 */
1066
void WINAPI ValidateRgn( HWND hwnd, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
1067
{
1068
    RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1069 1070 1071 1072
}


/***********************************************************************
1073
 *		ValidateRect (USER.127)
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1075
void WINAPI ValidateRect16( HWND16 hwnd, const RECT16 *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079 1080 1081
{
    RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
}


/***********************************************************************
1082
 *		ValidateRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1083
 */
1084
void WINAPI ValidateRect( HWND hwnd, const RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1085
{
1086
    RedrawWindow( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1087 1088 1089 1090
}


/***********************************************************************
1091
 *		GetUpdateRect (USER.190)
Alexandre Julliard's avatar
Alexandre Julliard committed
1092
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1093
BOOL16 WINAPI GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1094
{
1095
    RECT r;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096 1097
    BOOL16 ret;

1098 1099
    if (!rect) return GetUpdateRect( hwnd, NULL, erase );
    ret = GetUpdateRect( hwnd, &r, erase );
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101
    CONV_RECT32TO16( &r, rect );
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1102 1103 1104 1105
}


/***********************************************************************
1106
 *		GetUpdateRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1107
 */
1108
BOOL WINAPI GetUpdateRect( HWND hwnd, LPRECT rect, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1109
{
1110
    BOOL retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1111 1112 1113 1114 1115
    WND * wndPtr = WIN_FindWndPtr( hwnd );
    if (!wndPtr) return FALSE;

    if (rect)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1116
	if (wndPtr->hrgnUpdate > 1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1117
	{
1118
	    HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
1119 1120 1121 1122 1123
            if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR)
            {
                retvalue = FALSE;
                goto END;
            }
1124 1125
	    GetRgnBox( hrgn, rect );
	    DeleteObject( hrgn );
1126
	    if (GetClassLongA(wndPtr->hwndSelf, GCL_STYLE) & CS_OWNDC)
1127
	    {
1128
		if (GetMapMode(wndPtr->dce->hDC) != MM_TEXT)
1129
		{
1130
		    DPtoLP (wndPtr->dce->hDC, (LPPOINT)rect,  2);
1131 1132
		}
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1133
	}
1134 1135 1136 1137 1138 1139 1140 1141
	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
1142
    }
1143
    retvalue = (wndPtr->hrgnUpdate >= 1);
1144 1145 1146
END:
    WIN_ReleaseWndPtr(wndPtr);
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148 1149 1150
}


/***********************************************************************
1151
 *		GetUpdateRgn (USER.237)
Alexandre Julliard's avatar
Alexandre Julliard committed
1152
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1153
INT16 WINAPI GetUpdateRgn16( HWND16 hwnd, HRGN16 hrgn, BOOL16 erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1154
{
1155
    return GetUpdateRgn( hwnd, hrgn, erase );
Alexandre Julliard's avatar
Alexandre Julliard committed
1156 1157 1158 1159
}


/***********************************************************************
1160
 *		GetUpdateRgn (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1161
 */
1162
INT WINAPI GetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
Alexandre Julliard's avatar
Alexandre Julliard committed
1163
{
1164
    INT retval;
Alexandre Julliard's avatar
Alexandre Julliard committed
1165 1166 1167
    WND * wndPtr = WIN_FindWndPtr( hwnd );
    if (!wndPtr) return ERROR;

1168
    if (wndPtr->hrgnUpdate == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1169
    {
1170
        SetRectRgn( hrgn, 0, 0, 0, 0 );
1171 1172
        retval = NULLREGION;
        goto END;
Alexandre Julliard's avatar
Alexandre Julliard committed
1173
    }
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
    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 );
    }
1187
    if (erase) RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
1188 1189
END:
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1190 1191 1192 1193 1194
    return retval;
}


/***********************************************************************
1195
 *		ExcludeUpdateRgn (USER.238)
Alexandre Julliard's avatar
Alexandre Julliard committed
1196
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
INT16 WINAPI ExcludeUpdateRgn16( HDC16 hdc, HWND16 hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1198
{
1199
    return ExcludeUpdateRgn( hdc, hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1200 1201 1202 1203
}


/***********************************************************************
1204
 *		ExcludeUpdateRgn (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1205
 */
1206
INT WINAPI ExcludeUpdateRgn( HDC hdc, HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
1207
{
1208
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1209 1210 1211
    WND * wndPtr;

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

    if (wndPtr->hrgnUpdate)
Alexandre Julliard's avatar
Alexandre Julliard committed
1214
    {
1215 1216
	INT ret;
	HRGN hrgn = CreateRectRgn(wndPtr->rectWindow.left - wndPtr->rectClient.left,
Alexandre Julliard's avatar
Alexandre Julliard committed
1217
				      wndPtr->rectWindow.top - wndPtr->rectClient.top,
1218 1219
				      wndPtr->rectWindow.right - wndPtr->rectClient.left,
				      wndPtr->rectWindow.bottom - wndPtr->rectClient.top);
Alexandre Julliard's avatar
Alexandre Julliard committed
1220
	if( wndPtr->hrgnUpdate > 1 )
1221
	{
1222
	    CombineRgn(hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY);
1223 1224 1225
	    OffsetRgn(hrgn, wndPtr->rectWindow.left - wndPtr->rectClient.left, 
			    wndPtr->rectWindow.top - wndPtr->rectClient.top );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1226 1227 1228 1229

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

	ret = DCE_ExcludeRgn( hdc, wndPtr, hrgn );
1230
	DeleteObject( hrgn );
1231
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1232 1233
	return ret;
    } 
1234
    WIN_ReleaseWndPtr(wndPtr);
1235
    return GetClipBox( hdc, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1236
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1237 1238


1239 1240

/***********************************************************************
1241
 *		FillRect (USER.81)
1242 1243 1244 1245
 * NOTE
 *   The Win16 variant doesn't support special color brushes like
 *   the Win32 one, despite the fact that Win16, as well as Win32,
 *   supports special background brushes for a window class.
1246 1247 1248
 */
INT16 WINAPI FillRect16( HDC16 hdc, const RECT16 *rect, HBRUSH16 hbrush )
{
1249
    HBRUSH prevBrush;
1250 1251 1252 1253 1254

    /* coordinates are logical so we cannot fast-check 'rect',
     * it will be done later in the PatBlt().
     */

1255
    if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1256 1257
    PatBlt( hdc, rect->left, rect->top,
              rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1258
    SelectObject( hdc, prevBrush );
1259 1260 1261 1262 1263
    return 1;
}


/***********************************************************************
1264
 *		FillRect (USER32.@)
1265 1266 1267 1268 1269
 */
INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
{
    HBRUSH prevBrush;

1270 1271 1272 1273
    if (hbrush <= (HBRUSH) (COLOR_MAX + 1)) {
	hbrush = GetSysColorBrush( (INT) hbrush - 1 );
    }

1274 1275 1276 1277 1278 1279 1280 1281 1282
    if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
    PatBlt( hdc, rect->left, rect->top,
              rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
    SelectObject( hdc, prevBrush );
    return 1;
}


/***********************************************************************
1283
 *		InvertRect (USER.82)
1284 1285 1286 1287 1288 1289 1290 1291 1292
 */
void WINAPI InvertRect16( HDC16 hdc, const RECT16 *rect )
{
    PatBlt( hdc, rect->left, rect->top,
              rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
}


/***********************************************************************
1293
 *		InvertRect (USER32.@)
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
 */
BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
{
    return PatBlt( hdc, rect->left, rect->top,
		     rect->right - rect->left, rect->bottom - rect->top, 
		     DSTINVERT );
}


/***********************************************************************
1304
 *		FrameRect (USER32.@)
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
 */
INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
{
    HBRUSH prevBrush;
    RECT r = *rect;

    if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
    if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
    
    PatBlt( hdc, r.left, r.top, 1,
	      r.bottom - r.top, PATCOPY );
    PatBlt( hdc, r.right - 1, r.top, 1,
	      r.bottom - r.top, PATCOPY );
    PatBlt( hdc, r.left, r.top,
	      r.right - r.left, 1, PATCOPY );
    PatBlt( hdc, r.left, r.bottom - 1,
	      r.right - r.left, 1, PATCOPY );

    SelectObject( hdc, prevBrush );
    return TRUE;
}


/***********************************************************************
1329
 *		FrameRect (USER.83)
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
 */
INT16 WINAPI FrameRect16( HDC16 hdc, const RECT16 *rect16, HBRUSH16 hbrush )
{
    RECT rect;
    CONV_RECT16TO32( rect16, &rect );
    return FrameRect( hdc, &rect, hbrush );
}


/***********************************************************************
1340
 *		DrawFocusRect (USER.466)
1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
 */
void WINAPI DrawFocusRect16( HDC16 hdc, const RECT16* rc )
{
    RECT rect32;
    CONV_RECT16TO32( rc, &rect32 );
    DrawFocusRect( hdc, &rect32 );
}


/***********************************************************************
1351
 *		DrawFocusRect (USER32.@)
1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
 *
 * FIXME: PatBlt(PATINVERT) with background brush.
 */
BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
{
    HBRUSH hOldBrush;
    HPEN hOldPen, hNewPen;
    INT oldDrawMode, oldBkMode;

    hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1362
    hNewPen = CreatePen(PS_ALTERNATE, 1, GetSysColor(COLOR_WINDOWTEXT));
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
    hOldPen = SelectObject(hdc, hNewPen);
    oldDrawMode = SetROP2(hdc, R2_XORPEN);
    oldBkMode = SetBkMode(hdc, TRANSPARENT);

    Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);

    SetBkMode(hdc, oldBkMode);
    SetROP2(hdc, oldDrawMode);
    SelectObject(hdc, hOldPen);
    DeleteObject(hNewPen);
    SelectObject(hdc, hOldBrush);

    return TRUE;
}

/**********************************************************************
1379
 *		DrawAnimatedRects (USER.448)
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
 */
BOOL16 WINAPI DrawAnimatedRects16( HWND16 hwnd, INT16 idAni,
                                   const RECT16* lprcFrom,
                                   const RECT16* lprcTo )
{
    RECT rcFrom32, rcTo32;

    rcFrom32.left	= (INT)lprcFrom->left;
    rcFrom32.top	= (INT)lprcFrom->top;
    rcFrom32.right	= (INT)lprcFrom->right;
    rcFrom32.bottom	= (INT)lprcFrom->bottom;

    rcTo32.left		= (INT)lprcTo->left;
    rcTo32.top		= (INT)lprcTo->top;
    rcTo32.right	= (INT)lprcTo->right;
    rcTo32.bottom	= (INT)lprcTo->bottom;

    return DrawAnimatedRects((HWND)hwnd, (INT)idAni, &rcFrom32, &rcTo32);
}


/**********************************************************************
1402
 *		DrawAnimatedRects (USER32.@)
1403
 */
1404
BOOL WINAPI DrawAnimatedRects( HWND hwnd, INT idAni,
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
                                   const RECT* lprcFrom,
                                   const RECT* lprcTo )
{
    FIXME_(win)("(0x%x,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
    return TRUE;
}


/**********************************************************************
 *          PAINTING_DrawStateJam
 *
 * Jams in the requested type in the dc
 */
static BOOL PAINTING_DrawStateJam(HDC hdc, UINT opcode,
                                    DRAWSTATEPROC func, LPARAM lp, WPARAM wp, 
                                    LPRECT rc, UINT dtflags,
                                    BOOL unicode, BOOL _32bit)
{
    HDC memdc;
    HBITMAP hbmsave;
    BOOL retval;
    INT cx = rc->right - rc->left;
    INT cy = rc->bottom - rc->top;
    
    switch(opcode)
    {
    case DST_TEXT:
    case DST_PREFIXTEXT:
        if(unicode)
            return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
        else if(_32bit)
            return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
        else
1438
            return DrawTextA(hdc, MapSL(lp), (INT)wp, rc, dtflags);
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457

    case DST_ICON:
        return DrawIcon(hdc, rc->left, rc->top, (HICON)lp);

    case DST_BITMAP:
        memdc = CreateCompatibleDC(hdc);
        if(!memdc) return FALSE;
        hbmsave = (HBITMAP)SelectObject(memdc, (HBITMAP)lp);
        if(!hbmsave) 
        {
            DeleteDC(memdc);
            return FALSE;
        }
        retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
        SelectObject(memdc, hbmsave);
        DeleteDC(memdc);
        return retval;
            
    case DST_COMPLEX:
1458 1459 1460 1461 1462
        if(func) {
	    BOOL bRet;
	    /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */

	    OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1463
            if(_32bit)
1464
                bRet = func(hdc, lp, wp, cx, cy);
1465
            else
1466 1467 1468 1469 1470
                bRet = (BOOL)((DRAWSTATEPROC16)func)((HDC16)hdc, (LPARAM)lp, (WPARAM16)wp, (INT16)cx, (INT16)cy);
	    /* Restore origin */
	    OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
	    return bRet;
	} else
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
            return FALSE;
    }
    return FALSE;
}

/**********************************************************************
 *      PAINTING_DrawState()
 */
static BOOL PAINTING_DrawState(HDC hdc, HBRUSH hbr, 
                                   DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
                                   INT x, INT y, INT cx, INT cy, 
                                   UINT flags, BOOL unicode, BOOL _32bit)
{
    HBITMAP hbm, hbmsave;
    HFONT hfsave;
1486
    HBRUSH hbsave, hbrtmp = 0;
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
    HDC memdc;
    RECT rc;
    UINT dtflags = DT_NOCLIP;
    COLORREF fg, bg;
    UINT opcode = flags & 0xf;
    INT len = wp;
    BOOL retval, tmp;

    if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
    {
        if(unicode)
1498
            len = strlenW((LPWSTR)lp);
1499
        else if(_32bit)
1500
            len = strlen((LPSTR)lp);
1501
        else
1502
            len = strlen(MapSL(lp));
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520
    }

    /* Find out what size the image has if not given by caller */
    if(!cx || !cy)
    {
        SIZE s;
        CURSORICONINFO *ici;
	BITMAP bm;

        switch(opcode)
        {
        case DST_TEXT:
        case DST_PREFIXTEXT:
            if(unicode)
                retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
            else if(_32bit)
                retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
            else
1521
                retval = GetTextExtentPoint32A(hdc, MapSL(lp), len, &s);
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
            if(!retval) return FALSE;
            break;
            
        case DST_ICON:
            ici = (CURSORICONINFO *)GlobalLock16((HGLOBAL16)lp);
            if(!ici) return FALSE;
            s.cx = ici->nWidth;
            s.cy = ici->nHeight;
            GlobalUnlock16((HGLOBAL16)lp);
            break;            

        case DST_BITMAP:
	    if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm))
	        return FALSE;
            s.cx = bm.bmWidth;
            s.cy = bm.bmHeight;
            break;
            
        case DST_COMPLEX: /* cx and cy must be set in this mode */
            return FALSE;
	}
	            
        if(!cx) cx = s.cx;
        if(!cy) cy = s.cy;
    }

    rc.left   = x;
    rc.top    = y;
    rc.right  = x + cx;
    rc.bottom = y + cy;

    if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
        dtflags |= DT_RIGHT;
    if(opcode == DST_TEXT)
        dtflags |= DT_NOPREFIX;

    /* For DSS_NORMAL we just jam in the image and return */
    if((flags & 0x7ff0) == DSS_NORMAL)
    {
        return PAINTING_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode, _32bit);
    }

    /* For all other states we need to convert the image to B/W in a local bitmap */
    /* before it is displayed */
    fg = SetTextColor(hdc, RGB(0, 0, 0));
    bg = SetBkColor(hdc, RGB(255, 255, 255));
    hbm = (HBITMAP)NULL; hbmsave = (HBITMAP)NULL;
    memdc = (HDC)NULL; hbsave = (HBRUSH)NULL;
    retval = FALSE; /* assume failure */
    
    /* From here on we must use "goto cleanup" when something goes wrong */
    hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
    if(!hbm) goto cleanup;
    memdc   = CreateCompatibleDC(hdc);
    if(!memdc) goto cleanup;
    hbmsave = (HBITMAP)SelectObject(memdc, hbm);
    if(!hbmsave) goto cleanup;
    rc.left = rc.top = 0;
    rc.right = cx;
    rc.bottom = cy;
    if(!FillRect(memdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
    SetBkColor(memdc, RGB(255, 255, 255));
    SetTextColor(memdc, RGB(0, 0, 0));
    hfsave  = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1586 1587 1588 1589 1590

    /* DST_COMPLEX may draw text as well,
     * so we must be sure that correct font is selected
     */
    if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1591 1592 1593 1594
    tmp = PAINTING_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode, _32bit);
    if(hfsave) SelectObject(memdc, hfsave);
    if(!tmp) goto cleanup;
    
1595 1596
    /* This state cause the image to be dithered */
    if(flags & DSS_UNION)
1597 1598 1599 1600
    {
        hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
        if(!hbsave) goto cleanup;
        tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1601
        SelectObject(memdc, hbsave);
1602 1603 1604
        if(!tmp) goto cleanup;
    }

1605 1606 1607 1608 1609 1610 1611
    if (flags & DSS_DISABLED)
       hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
    else if (flags & DSS_DEFAULT)
       hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));

    /* Draw light or dark shadow */
    if (flags & (DSS_DISABLED|DSS_DEFAULT))
1612
    {
1613 1614 1615 1616 1617 1618 1619
       if(!hbrtmp) goto cleanup;
       hbsave = (HBRUSH)SelectObject(hdc, hbrtmp);
       if(!hbsave) goto cleanup;
       if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
       SelectObject(hdc, hbsave);
       DeleteObject(hbrtmp);
       hbrtmp = 0;
1620 1621
    }

1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
    if (flags & DSS_DISABLED)
    {
       hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
       if(!hbrtmp) goto cleanup;
    }
    else if (!hbr)
    {
       hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);
    }

    hbsave = (HBRUSH)SelectObject(hdc, hbr);
    
    if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
    
1636 1637 1638 1639 1640 1641 1642 1643
    retval = TRUE; /* We succeeded */
    
cleanup:    
    SetTextColor(hdc, fg);
    SetBkColor(hdc, bg);

    if(hbsave)  SelectObject(hdc, hbsave);
    if(hbmsave) SelectObject(memdc, hbmsave);
1644
    if(hbrtmp)  DeleteObject(hbrtmp);
1645 1646 1647 1648 1649 1650 1651
    if(hbm)     DeleteObject(hbm);
    if(memdc)   DeleteDC(memdc);

    return retval;
}

/**********************************************************************
1652
 *		DrawStateA (USER32.@)
1653 1654 1655 1656 1657 1658 1659 1660 1661
 */
BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
                   DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
                   INT x, INT y, INT cx, INT cy, UINT flags)
{
    return PAINTING_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE, TRUE);
}

/**********************************************************************
1662
 *		DrawStateW (USER32.@)
1663 1664 1665 1666 1667 1668 1669 1670 1671
 */
BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
                   DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
                   INT x, INT y, INT cx, INT cy, UINT flags)
{
    return PAINTING_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE, TRUE);
}

/**********************************************************************
1672
 *		DrawState (USER.449)
1673 1674 1675 1676 1677 1678 1679 1680 1681
 */
BOOL16 WINAPI DrawState16(HDC16 hdc, HBRUSH16 hbr,
                   DRAWSTATEPROC16 func, LPARAM ldata, WPARAM16 wdata,
                   INT16 x, INT16 y, INT16 cx, INT16 cy, UINT16 flags)
{
    return PAINTING_DrawState(hdc, hbr, (DRAWSTATEPROC)func, ldata, wdata, x, y, cx, cy, flags, FALSE, FALSE);
}


1682
/***********************************************************************
1683
 *		SelectPalette (USER.282)
1684 1685 1686 1687
 */
HPALETTE16 WINAPI SelectPalette16( HDC16 hDC, HPALETTE16 hPal,
                                   BOOL16 bForceBackground )
{
1688 1689
    WORD wBkgPalette = 1;

1690
    if (!bForceBackground && (hPal != GetStockObject(DEFAULT_PALETTE)))
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
    {
        HWND hwnd = WindowFromDC( hDC );
        if (hwnd)
        {
            HWND hForeground = GetForegroundWindow();
            /* set primary palette if it's related to current active */
            if (hForeground == hwnd || IsChild(hForeground,hwnd)) wBkgPalette = 0;
        }
    }
    return GDISelectPalette16( hDC, hPal, wBkgPalette);
1701 1702 1703 1704
}


/***********************************************************************
1705
 *		RealizePalette (USER.283)
1706 1707 1708
 */
UINT16 WINAPI RealizePalette16( HDC16 hDC )
{
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
    UINT16 realized = GDIRealizePalette16( hDC );

    /* do not send anything if no colors were changed */
    if (realized && IsDCCurrentPalette16( hDC ))
    {
        /* send palette change notification */
        HWND hWnd = WindowFromDC( hDC );
        if (hWnd) SendMessageA( HWND_BROADCAST, WM_PALETTECHANGED, hWnd, 0L);
    }
    return realized;
}


/***********************************************************************
1723
 *		UserRealizePalette (USER32.@)
1724 1725 1726 1727
 */
UINT WINAPI UserRealizePalette( HDC hDC )
{
    return RealizePalette16( hDC );
1728
}