dce.c 19.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * USER DCE functions
 *
 * Copyright 1993 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *	     1996,1997 Alex Korobka
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 *
22 23 24
 * Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs
 * have to be updated dynamically.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
 * Internal DCX flags:
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
27 28
 * DCX_DCEEMPTY    - dce is uninitialized
 * DCX_DCEBUSY     - dce is in use
Alexandre Julliard's avatar
Alexandre Julliard committed
29 30 31
 * DCX_DCEDIRTY    - ReleaseDC() should wipe instead of caching
 * DCX_KEEPCLIPRGN - ReleaseDC() should not delete the clipping region
 * DCX_WINDOWPAINT - BeginPaint() is in effect
Alexandre Julliard's avatar
Alexandre Julliard committed
32
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
35 36
#include "dce.h"
#include "win.h"
37
#include "user.h"
38
#include "wine/debug.h"
39 40
#include "windef.h"
#include "wingdi.h"
41
#include "wownt32.h"
42
#include "wine/winbase16.h"
43
#include "wine/winuser16.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
44

45
WINE_DEFAULT_DEBUG_CHANNEL(dc);
46

47
static DCE *firstDCE;
48
static HDC16 defaultDCstate;
Alexandre Julliard's avatar
Alexandre Julliard committed
49

Alexandre Julliard's avatar
Alexandre Julliard committed
50
static void DCE_DeleteClipRgn( DCE* );
51
static INT DCE_ReleaseDC( DCE* );
Alexandre Julliard's avatar
Alexandre Julliard committed
52 53 54 55 56


/***********************************************************************
 *           DCE_DumpCache
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
57
static void DCE_DumpCache(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
58
{
59
    DCE *dce;
60

61
    USER_Lock();
62
    dce = firstDCE;
63

64
    DPRINTF("DCE:\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66
    while( dce )
    {
67
	DPRINTF("\t[0x%08x] hWnd %p, dcx %08x, %s %s\n",
68 69
	     (unsigned)dce, dce->hwndCurrent, (unsigned)dce->DCXflags,
	     (dce->DCXflags & DCX_CACHE) ? "Cache" : "Owned",
Alexandre Julliard's avatar
Alexandre Julliard committed
70
	     (dce->DCXflags & DCX_DCEBUSY) ? "InUse" : "" );
Alexandre Julliard's avatar
Alexandre Julliard committed
71 72
	dce = dce->next;
    }
73

74
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
75 76
}

Alexandre Julliard's avatar
Alexandre Julliard committed
77 78
/***********************************************************************
 *           DCE_AllocDCE
Alexandre Julliard's avatar
Alexandre Julliard committed
79
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
80 81
 * Allocate a new DCE.
 */
82
DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
Alexandre Julliard's avatar
Alexandre Julliard committed
83 84
{
    DCE * dce;
85

86
    if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(DCE) ))) return NULL;
87
    if (!(dce->hDC = CreateDCA( "DISPLAY", NULL, NULL, NULL )))
Alexandre Julliard's avatar
Alexandre Julliard committed
88
    {
89
        HeapFree( GetProcessHeap(), 0, dce );
Alexandre Julliard's avatar
Alexandre Julliard committed
90 91
	return 0;
    }
92
    if (!defaultDCstate) defaultDCstate = GetDCState16( HDC_16(dce->hDC) );
Alexandre Julliard's avatar
Alexandre Julliard committed
93 94 95

    /* store DCE handle in DC hook data field */

96
    SetDCHook( dce->hDC, DCHook16, (DWORD)dce );
Alexandre Julliard's avatar
Alexandre Julliard committed
97

98
    dce->hwndCurrent = WIN_GetFullHandle( hWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
99
    dce->hClipRgn    = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
100

Alexandre Julliard's avatar
Alexandre Julliard committed
101 102
    if( type != DCE_CACHE_DC ) /* owned or class DC */
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
103 104
	dce->DCXflags = DCX_DCEBUSY;
	if( hWnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
105
	{
106 107 108
            LONG style = GetWindowLongW( hWnd, GWL_STYLE );
            if (style & WS_CLIPCHILDREN) dce->DCXflags |= DCX_CLIPCHILDREN;
            if (style & WS_CLIPSIBLINGS) dce->DCXflags |= DCX_CLIPSIBLINGS;
Alexandre Julliard's avatar
Alexandre Julliard committed
109
	}
110
        SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
Alexandre Julliard's avatar
Alexandre Julliard committed
111 112
    }
    else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY;
113

114 115 116 117
    USER_Lock();
    dce->next = firstDCE;
    firstDCE = dce;
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
118
    return dce;
Alexandre Julliard's avatar
Alexandre Julliard committed
119 120 121 122 123 124
}


/***********************************************************************
 *           DCE_FreeDCE
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
125
DCE* DCE_FreeDCE( DCE *dce )
Alexandre Julliard's avatar
Alexandre Julliard committed
126
{
127
    DCE **ppDCE, *ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
128

Alexandre Julliard's avatar
Alexandre Julliard committed
129
    if (!dce) return NULL;
130

131
    USER_Lock();
132 133 134

    ppDCE = &firstDCE;

Alexandre Julliard's avatar
Alexandre Julliard committed
135 136
    while (*ppDCE && (*ppDCE != dce)) ppDCE = &(*ppDCE)->next;
    if (*ppDCE == dce) *ppDCE = dce->next;
137 138
    ret = *ppDCE;
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
139

Alexandre Julliard's avatar
Alexandre Julliard committed
140
    SetDCHook(dce->hDC, NULL, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
141

142
    DeleteDC( dce->hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
143
    if( dce->hClipRgn && !(dce->DCXflags & DCX_KEEPCLIPRGN) )
144
	DeleteObject(dce->hClipRgn);
145
    HeapFree( GetProcessHeap(), 0, dce );
146

147
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
148 149
}

Alexandre Julliard's avatar
Alexandre Julliard committed
150 151 152 153 154
/***********************************************************************
 *           DCE_FreeWindowDCE
 *
 * Remove owned DCE and reset unreleased cache DCEs.
 */
155
void DCE_FreeWindowDCE( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
156
{
157
    DCE *pDCE;
158
    WND *pWnd = WIN_GetPtr( hwnd );
159 160

    pDCE = firstDCE;
Alexandre Julliard's avatar
Alexandre Julliard committed
161 162
    while( pDCE )
    {
163
	if( pDCE->hwndCurrent == hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
164
	{
165
	    if( pDCE == pWnd->dce ) /* owned or Class DCE*/
Alexandre Julliard's avatar
Alexandre Julliard committed
166
	    {
167
                if (pWnd->clsStyle & CS_OWNDC)	/* owned DCE*/
168 169 170 171 172 173 174
		{
                    pDCE = DCE_FreeDCE( pDCE );
                    pWnd->dce = NULL;
                    continue;
                }
		else if( pDCE->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN) )	/* Class DCE*/
		{
175 176
                    if (USER_Driver.pReleaseDC)
                        USER_Driver.pReleaseDC( pDCE->hwndCurrent, pDCE->hDC );
177 178 179
                    DCE_DeleteClipRgn( pDCE );
                    pDCE->hwndCurrent = 0;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
180 181 182
	    }
	    else
	    {
183
		if( pDCE->DCXflags & DCX_DCEBUSY ) /* shared cache DCE */
Alexandre Julliard's avatar
Alexandre Julliard committed
184
		{
185 186 187 188
                    /* FIXME: AFAICS we are doing the right thing here so
                     * this should be a WARN. But this is best left as an ERR
                     * because the 'application error' is likely to come from
                     * another part of Wine (i.e. it's our fault after all).
189 190 191
                     * We should change this to WARN when Wine is more stable
                     * (for 1.0?).
                     */
192
		    ERR("[%p] GetDC() without ReleaseDC()!\n",hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
193 194 195
		    DCE_ReleaseDC( pDCE );
		}

196 197
                if (pDCE->hwndCurrent && USER_Driver.pReleaseDC)
                    USER_Driver.pReleaseDC( pDCE->hwndCurrent, pDCE->hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
198 199 200 201 202 203 204
		pDCE->DCXflags &= DCX_CACHE;
		pDCE->DCXflags |= DCX_DCEEMPTY;
		pDCE->hwndCurrent = 0;
	    }
	}
	pDCE = pDCE->next;
    }
205
    WIN_ReleasePtr( pWnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
206 207 208 209 210
}


/***********************************************************************
 *   DCE_DeleteClipRgn
Alexandre Julliard's avatar
Alexandre Julliard committed
211
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
212
static void DCE_DeleteClipRgn( DCE* dce )
Alexandre Julliard's avatar
Alexandre Julliard committed
213
{
Alexandre Julliard's avatar
Alexandre Julliard committed
214 215 216 217 218
    dce->DCXflags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);

    if( dce->DCXflags & DCX_KEEPCLIPRGN )
	dce->DCXflags &= ~DCX_KEEPCLIPRGN;
    else
219
	if( dce->hClipRgn > (HRGN)1 )
220
	    DeleteObject( dce->hClipRgn );
Alexandre Julliard's avatar
Alexandre Julliard committed
221 222

    dce->hClipRgn = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
223

224 225
    /* make it dirty so that the vis rgn gets recomputed next time */
    dce->DCXflags |= DCX_DCEDIRTY;
226
    SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
Alexandre Julliard's avatar
Alexandre Julliard committed
227 228
}

Alexandre Julliard's avatar
Alexandre Julliard committed
229

Alexandre Julliard's avatar
Alexandre Julliard committed
230 231
/***********************************************************************
 *   DCE_ReleaseDC
Alexandre Julliard's avatar
Alexandre Julliard committed
232
 */
233
static INT DCE_ReleaseDC( DCE* dce )
Alexandre Julliard's avatar
Alexandre Julliard committed
234
{
Alexandre Julliard's avatar
Alexandre Julliard committed
235 236 237 238 239 240 241 242 243 244
    if ((dce->DCXflags & (DCX_DCEEMPTY | DCX_DCEBUSY)) != DCX_DCEBUSY) return 0;

    /* restore previous visible region */

    if ((dce->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
        (dce->DCXflags & (DCX_CACHE | DCX_WINDOWPAINT)) )
        DCE_DeleteClipRgn( dce );

    if (dce->DCXflags & DCX_CACHE)
    {
245
        /* make the DC clean so that SetDCState doesn't try to update the vis rgn */
246 247
        SetHookFlags16( HDC_16(dce->hDC), DCHF_VALIDATEVISRGN );
        SetDCState16( HDC_16(dce->hDC), defaultDCstate );
Alexandre Julliard's avatar
Alexandre Julliard committed
248 249 250
        dce->DCXflags &= ~DCX_DCEBUSY;
	if (dce->DCXflags & DCX_DCEDIRTY)
	{
251
	    /* don't keep around invalidated entries
Alexandre Julliard's avatar
Alexandre Julliard committed
252 253
	     * because SetDCState() disables hVisRgn updates
	     * by removing dirty bit. */
254 255
            if (dce->hwndCurrent && USER_Driver.pReleaseDC)
                USER_Driver.pReleaseDC( dce->hwndCurrent, dce->hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257 258 259
	    dce->hwndCurrent = 0;
	    dce->DCXflags &= DCX_CACHE;
	    dce->DCXflags |= DCX_DCEEMPTY;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
260 261
    }
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263
}

Alexandre Julliard's avatar
Alexandre Julliard committed
264

Alexandre Julliard's avatar
Alexandre Julliard committed
265 266
/***********************************************************************
 *   DCE_InvalidateDCE
Alexandre Julliard's avatar
Alexandre Julliard committed
267
 *
268 269
 * It is called from SetWindowPos() and EVENT_MapNotify - we have to
 * mark as dirty all busy DCEs for windows that have pWnd->parent as
Andreas Mohr's avatar
Andreas Mohr committed
270
 * an ancestor and whose client rect intersects with specified update
271 272
 * rectangle. In addition, pWnd->parent DCEs may need to be updated if
 * DCX_CLIPCHILDREN flag is set.  */
273
BOOL DCE_InvalidateDCE(HWND hwnd, const RECT* pRectUpdate)
Alexandre Julliard's avatar
Alexandre Julliard committed
274
{
275
    HWND hwndScope = GetAncestor( hwnd, GA_PARENT );
276
    BOOL bRet = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
277

278
    if( hwndScope )
Alexandre Julliard's avatar
Alexandre Julliard committed
279 280
    {
	DCE *dce;
Alexandre Julliard's avatar
Alexandre Julliard committed
281

282
        TRACE("scope hwnd = %p, (%ld,%ld - %ld,%ld)\n",
283 284
              hwndScope, pRectUpdate->left,pRectUpdate->top,
              pRectUpdate->right,pRectUpdate->bottom);
285
	if(TRACE_ON(dc))
Alexandre Julliard's avatar
Alexandre Julliard committed
286
	  DCE_DumpCache();
Alexandre Julliard's avatar
Alexandre Julliard committed
287

Alexandre Julliard's avatar
Alexandre Julliard committed
288
 	/* walk all DCEs and fixup non-empty entries */
Alexandre Julliard's avatar
Alexandre Julliard committed
289

Alexandre Julliard's avatar
Alexandre Julliard committed
290 291
	for (dce = firstDCE; (dce); dce = dce->next)
	{
292 293 294 295 296 297
            if (dce->DCXflags & DCX_DCEEMPTY) continue;
            if ((dce->hwndCurrent == hwndScope) && !(dce->DCXflags & DCX_CLIPCHILDREN))
                continue;  /* child window positions don't bother us */

            /* check if DCE window is within the z-order scope */

298
            if (hwndScope == dce->hwndCurrent || IsChild( hwndScope, dce->hwndCurrent ))
299
            {
300 301 302 303 304 305 306 307 308 309
                if (hwnd != dce->hwndCurrent)
                {
                    /* check if the window rectangle intersects this DCE window */
                    RECT rect;
                    GetWindowRect( dce->hwndCurrent, &rect );
                    MapWindowPoints( 0, hwndScope, (POINT *)&rect, 2 );
                    if (!IntersectRect( &rect, &rect, pRectUpdate )) continue;

                }
                if( !(dce->DCXflags & DCX_DCEBUSY) )
310
                {
311 312
                    /* Don't bother with visible regions of unused DCEs */

313
                    TRACE("\tpurged %p dce [%p]\n", dce, dce->hwndCurrent);
314 315
                    if (dce->hwndCurrent && USER_Driver.pReleaseDC)
                        USER_Driver.pReleaseDC( dce->hwndCurrent, dce->hDC );
316 317 318
                    dce->hwndCurrent = 0;
                    dce->DCXflags &= DCX_CACHE;
                    dce->DCXflags |= DCX_DCEEMPTY;
319 320 321
                }
                else
                {
322 323
                    /* Set dirty bits in the hDC and DCE structs */

324
                    TRACE("\tfixed up %p dce [%p]\n", dce, dce->hwndCurrent);
325
                    dce->DCXflags |= DCX_DCEDIRTY;
326
                    SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
327
                    bRet = TRUE;
328 329
                }
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
330 331 332
	} /* dce list */
    }
    return bRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
333
}
Alexandre Julliard's avatar
Alexandre Julliard committed
334

Alexandre Julliard's avatar
Alexandre Julliard committed
335

Alexandre Julliard's avatar
Alexandre Julliard committed
336 337
/***********************************************************************
 *           DCE_ExcludeRgn
338
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
339 340 341
 *  Translate given region from the wnd client to the DC coordinates
 *  and add it to the clipping region.
 */
342
INT DCE_ExcludeRgn( HDC hDC, HWND hwnd, HRGN hRgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
343
{
344
  POINT  pt = {0, 0};
Alexandre Julliard's avatar
Alexandre Julliard committed
345 346 347
  DCE     *dce = firstDCE;

  while (dce && (dce->hDC != hDC)) dce = dce->next;
348 349 350 351
  if (!dce) return ERROR;

  MapWindowPoints( hwnd, dce->hwndCurrent, &pt, 1);
  if( dce->DCXflags & DCX_WINDOW )
Alexandre Julliard's avatar
Alexandre Julliard committed
352
  {
353 354 355 356
      WND *wnd = WIN_FindWndPtr(dce->hwndCurrent);
      pt.x += wnd->rectClient.left - wnd->rectWindow.left;
      pt.y += wnd->rectClient.top - wnd->rectWindow.top;
      WIN_ReleaseWndPtr(wnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
357
  }
358
  OffsetRgn(hRgn, pt.x, pt.y);
359 360

  return ExtSelectClipRgn( hDC, hRgn, RGN_DIFF );
Alexandre Julliard's avatar
Alexandre Julliard committed
361
}
Alexandre Julliard's avatar
Alexandre Julliard committed
362

363

Alexandre Julliard's avatar
Alexandre Julliard committed
364
/***********************************************************************
365
 *		GetDCEx (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
366 367
 *
 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369
 *
 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
Alexandre Julliard's avatar
Alexandre Julliard committed
370
 */
371
HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
372
{
373
    HDC 	hdc = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
374 375
    DCE * 	dce;
    WND * 	wndPtr;
Alexandre Julliard's avatar
Alexandre Julliard committed
376
    DWORD 	dcxFlags = 0;
377 378
    BOOL	bUpdateVisRgn = TRUE;
    BOOL	bUpdateClipOrigin = FALSE;
379
    HWND parent, full;
Alexandre Julliard's avatar
Alexandre Julliard committed
380

381
    TRACE("hwnd %p, hrgnClip %p, flags %08lx\n", hwnd, hrgnClip, flags);
382

383 384 385 386 387 388 389
    if (flags & (DCX_LOCKWINDOWUPDATE)) {
       FIXME("not yet supported - see source\n");
       /* See the comment in LockWindowUpdate for more explanation. This flag is not implemented
        * by that patch, but we need LockWindowUpdate implemented correctly before this can be done.
        */
    }

390
    if (!hwnd) hwnd = GetDesktopWindow();
391
    if (!(full = WIN_IsCurrentProcess( hwnd )))
392
    {
393
        FIXME( "not supported yet on other process window %p\n", hwnd );
394 395 396 397
        return 0;
    }
    hwnd = full;
    if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
398

Alexandre Julliard's avatar
Alexandre Julliard committed
399 400
    /* fixup flags */

401
    if (flags & (DCX_WINDOW | DCX_PARENTCLIP)) flags |= DCX_CACHE;
Alexandre Julliard's avatar
Alexandre Julliard committed
402

Alexandre Julliard's avatar
Alexandre Julliard committed
403 404
    if (flags & DCX_USESTYLE)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
405 406 407 408 409 410
	flags &= ~( DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);

        if( wndPtr->dwStyle & WS_CLIPSIBLINGS )
            flags |= DCX_CLIPSIBLINGS;

	if ( !(flags & DCX_WINDOW) )
Alexandre Julliard's avatar
Alexandre Julliard committed
411
	{
412
            if (wndPtr->clsStyle & CS_PARENTDC) flags |= DCX_PARENTCLIP;
Alexandre Julliard's avatar
Alexandre Julliard committed
413 414 415

	    if (wndPtr->dwStyle & WS_CLIPCHILDREN &&
                     !(wndPtr->dwStyle & WS_MINIMIZE) ) flags |= DCX_CLIPCHILDREN;
416
            if (!wndPtr->dce) flags |= DCX_CACHE;
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418 419
	}
    }

420
    if (flags & DCX_WINDOW) flags &= ~DCX_CLIPCHILDREN;
Alexandre Julliard's avatar
Alexandre Julliard committed
421

422 423
    parent = GetAncestor( hwnd, GA_PARENT );
    if (!parent || (parent == GetDesktopWindow()))
424
        flags = (flags & ~DCX_PARENTCLIP) | DCX_CLIPSIBLINGS;
425 426 427 428 429

    /* it seems parent clip is ignored when clipping siblings or children */
    if (flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) flags &= ~DCX_PARENTCLIP;

    if( flags & DCX_PARENTCLIP )
Alexandre Julliard's avatar
Alexandre Julliard committed
430
    {
431 432
        LONG parent_style = GetWindowLongW( parent, GWL_STYLE );
        if( (wndPtr->dwStyle & WS_VISIBLE) && (parent_style & WS_VISIBLE) )
433 434
        {
            flags &= ~DCX_CLIPCHILDREN;
435
            if (parent_style & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
436
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
437
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
438

Alexandre Julliard's avatar
Alexandre Julliard committed
439 440
    /* find a suitable DCE */

441
    dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
Alexandre Julliard's avatar
Alexandre Julliard committed
442 443
		        DCX_CACHE | DCX_WINDOW);

Alexandre Julliard's avatar
Alexandre Julliard committed
444
    if (flags & DCX_CACHE)
Alexandre Julliard's avatar
Alexandre Julliard committed
445
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
446 447 448 449 450 451 452 453 454 455
	DCE*	dceEmpty;
	DCE*	dceUnused;

	dceEmpty = dceUnused = NULL;

	/* Strategy: First, we attempt to find a non-empty but unused DCE with
	 * compatible flags. Next, we look for an empty entry. If the cache is
	 * full we have to purge one of the unused entries.
	 */

Alexandre Julliard's avatar
Alexandre Julliard committed
456
	for (dce = firstDCE; (dce); dce = dce->next)
Alexandre Julliard's avatar
Alexandre Julliard committed
457
	{
Alexandre Julliard's avatar
Alexandre Julliard committed
458 459 460 461 462 463 464 465 466 467 468
	    if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE )
	    {
		dceUnused = dce;

		if (dce->DCXflags & DCX_DCEEMPTY)
		    dceEmpty = dce;
		else
		if ((dce->hwndCurrent == hwnd) &&
		   ((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
				      DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
		{
469 470
		    TRACE("\tfound valid %p dce [%p], flags %08lx\n",
                          dce, hwnd, dcxFlags );
471
		    bUpdateVisRgn = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
472 473 474 475
		    bUpdateClipOrigin = TRUE;
		    break;
		}
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
476
	}
477

Alexandre Julliard's avatar
Alexandre Julliard committed
478
	if (!dce) dce = (dceEmpty) ? dceEmpty : dceUnused;
479

480 481 482 483 484
        /* if there's no dce empty or unused, allocate a new one */
        if (!dce)
        {
            dce = DCE_AllocDCE( 0, DCE_CACHE_DC );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
485
    }
486
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
487
    {
488
        dce = wndPtr->dce;
489
        if (dce && dce->hwndCurrent == hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
490
	{
491
	    TRACE("\tskipping hVisRgn update\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
492
	    bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
Alexandre Julliard's avatar
Alexandre Julliard committed
493
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
494
    }
495 496 497 498 499
    if (!dce)
    {
        hdc = 0;
        goto END;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
500

501
    if (!(flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) hrgnClip = 0;
502 503 504 505 506 507 508 509

    if (((flags ^ dce->DCXflags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
        (dce->hClipRgn != hrgnClip))
    {
        /* if the extra clip region has changed, get rid of the old one */
        DCE_DeleteClipRgn( dce );
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
510
    dce->hwndCurrent = hwnd;
511 512 513 514 515 516
    dce->hClipRgn = hrgnClip;
    dce->DCXflags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
                             DCX_CACHE | DCX_WINDOW | DCX_WINDOWPAINT |
                             DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_EXCLUDERGN);
    dce->DCXflags |= DCX_DCEBUSY;
    dce->DCXflags &= ~DCX_DCEDIRTY;
Alexandre Julliard's avatar
Alexandre Julliard committed
517
    hdc = dce->hDC;
Alexandre Julliard's avatar
Alexandre Julliard committed
518

519
    if (bUpdateVisRgn) SetHookFlags16( HDC_16(hdc), DCHF_INVALIDATEVISRGN ); /* force update */
520

521
    if (!USER_Driver.pGetDC( hwnd, hdc, hrgnClip, flags )) hdc = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
522

523
    TRACE("(%p,%p,0x%lx): returning %p\n", hwnd, hrgnClip, flags, hdc);
524
END:
525
    WIN_ReleasePtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
526 527 528
    return hdc;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
529 530

/***********************************************************************
531
 *		GetDC (USER32.@)
Jon Griffiths's avatar
Jon Griffiths committed
532 533 534
 *
 * Get a device context.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
535
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
536 537
 *	Success: Handle to the device context
 *	Failure: NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
538
 */
539
HDC WINAPI GetDC(
Jon Griffiths's avatar
Jon Griffiths committed
540
	     HWND hwnd /* [in] handle of window - may be NULL */
Alexandre Julliard's avatar
Alexandre Julliard committed
541
) {
Alexandre Julliard's avatar
Alexandre Julliard committed
542
    if (!hwnd)
543
        return GetDCEx( 0, 0, DCX_CACHE | DCX_WINDOW );
544
    return GetDCEx( hwnd, 0, DCX_USESTYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
545 546 547
}


Alexandre Julliard's avatar
Alexandre Julliard committed
548
/***********************************************************************
549
 *		GetWindowDC (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
550
 */
551
HDC WINAPI GetWindowDC( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
552
{
553
    return GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
Alexandre Julliard's avatar
Alexandre Julliard committed
554 555 556
}


Alexandre Julliard's avatar
Alexandre Julliard committed
557
/***********************************************************************
558
 *		ReleaseDC (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
559
 *
Jon Griffiths's avatar
Jon Griffiths committed
560 561
 * Release a device context.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
562
 * RETURNS
Jon Griffiths's avatar
Jon Griffiths committed
563 564
 *	Success: Non-zero. Resources used by hdc are released.
 *	Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
565
 */
566
INT WINAPI ReleaseDC(
Jon Griffiths's avatar
Jon Griffiths committed
567
             HWND hwnd, /* [in] Handle of window - ignored */
568
             HDC hdc   /* [in] Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
569
) {
570 571 572
    DCE * dce;
    INT nRet = 0;

573
    USER_Lock();
574
    dce = firstDCE;
575

576
    TRACE("%p %p\n", hwnd, hdc );
577

Alexandre Julliard's avatar
Alexandre Julliard committed
578
    while (dce && (dce->hDC != hdc)) dce = dce->next;
Alexandre Julliard's avatar
Alexandre Julliard committed
579

580
    if ( dce )
Alexandre Julliard's avatar
Alexandre Julliard committed
581
	if ( dce->DCXflags & DCX_DCEBUSY )
582 583
            nRet = DCE_ReleaseDC( dce );

584
    USER_Unlock();
585 586

    return nRet;
Alexandre Julliard's avatar
Alexandre Julliard committed
587
}
Alexandre Julliard's avatar
Alexandre Julliard committed
588 589

/***********************************************************************
590
 *		DCHook (USER.362)
Alexandre Julliard's avatar
Alexandre Julliard committed
591
 *
592
 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
Alexandre Julliard's avatar
Alexandre Julliard committed
593
 */
594
BOOL16 WINAPI DCHook16( HDC16 hDC, WORD code, DWORD data, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
595
{
596 597
    BOOL retv = TRUE;
    DCE *dce = (DCE *)data;
598

599
    TRACE("hDC = %04x, %i\n", hDC, code);
Alexandre Julliard's avatar
Alexandre Julliard committed
600

601
    if (!dce) return 0;
602
    assert( HDC_16(dce->hDC) == hDC );
603

604
    /* Grab the windows lock before doing anything else  */
605
    USER_Lock();
Alexandre Julliard's avatar
Alexandre Julliard committed
606

Alexandre Julliard's avatar
Alexandre Julliard committed
607
    switch( code )
Alexandre Julliard's avatar
Alexandre Julliard committed
608 609
    {
      case DCHC_INVALIDVISRGN:
Alexandre Julliard's avatar
Alexandre Julliard committed
610 611 612 613
	   /* GDI code calls this when it detects that the
	    * DC is dirty (usually after SetHookFlags()). This
	    * means that we have to recompute the visible region.
	    */
Alexandre Julliard's avatar
Alexandre Julliard committed
614
           if( dce->DCXflags & DCX_DCEBUSY )
615 616 617
           {
               /* Dirty bit has been cleared by caller, set it again so that
                * pGetDC recomputes the visible region. */
618
               SetHookFlags16( hDC, DCHF_INVALIDATEVISRGN );
619
               USER_Driver.pGetDC( dce->hwndCurrent, dce->hDC, dce->hClipRgn, dce->DCXflags );
620
           }
Alexandre Julliard's avatar
Alexandre Julliard committed
621
           else /* non-fatal but shouldn't happen */
622
	     WARN("DC is not in use!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
623
	   break;
Alexandre Julliard's avatar
Alexandre Julliard committed
624

625 626 627 628 629 630 631 632
      case DCHC_DELETEDC:
           /*
            * Windows will not let you delete a DC that is busy
            * (between GetDC and ReleaseDC)
            */

           if ( dce->DCXflags & DCX_DCEBUSY )
           {
633
               WARN("Application trying to delete a busy DC\n");
634 635
               retv = FALSE;
           }
636
           else DCE_FreeDCE( dce );
Alexandre Julliard's avatar
Alexandre Julliard committed
637
	   break;
Alexandre Julliard's avatar
Alexandre Julliard committed
638 639

      default:
640
	   FIXME("unknown code\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
641
    }
642

643
  USER_Unlock();  /* Release the wnd lock */
644
  return retv;
Alexandre Julliard's avatar
Alexandre Julliard committed
645 646
}

Alexandre Julliard's avatar
Alexandre Julliard committed
647

Alexandre Julliard's avatar
Alexandre Julliard committed
648
/**********************************************************************
649
 *		WindowFromDC (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
650
 */
651
HWND WINAPI WindowFromDC( HDC hDC )
Alexandre Julliard's avatar
Alexandre Julliard committed
652
{
653 654 655
    DCE *dce;
    HWND hwnd;

656
    USER_Lock();
657
    dce = firstDCE;
658

Alexandre Julliard's avatar
Alexandre Julliard committed
659
    while (dce && (dce->hDC != hDC)) dce = dce->next;
660 661

    hwnd = dce ? dce->hwndCurrent : 0;
662
    USER_Unlock();
663

664
    return hwnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666 667
}


Alexandre Julliard's avatar
Alexandre Julliard committed
668
/***********************************************************************
669
 *		LockWindowUpdate (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
670
 */
671
BOOL WINAPI LockWindowUpdate( HWND hwnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
672
{
673 674
    static HWND lockedWnd;

675 676 677 678 679 680 681 682 683 684
    /* This function is fully implemented by the following patch:
     *
     * http://www.winehq.org/hypermail/wine-patches/2004/01/0142.html
     *
     * but in order to work properly, it needs the ability to invalidate
     * DCEs in other processes when the lock window is changed, which
     * isn't possible yet.
     * -mike
     */

685
    FIXME("(%p), partial stub!\n",hwnd);
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704

    USER_Lock();
    if (lockedWnd)
    {
        if (!hwnd)
        {
            /* Unlock lockedWnd */
            /* FIXME: Do something */
        }
        else
        {
            /* Attempted to lock a second window */
            /* Return FALSE and do nothing */
            USER_Unlock();
            return FALSE;
        }
    }
    lockedWnd = hwnd;
    USER_Unlock();
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706
    return TRUE;
}