Stub for GetUserObjectSecurity.
[wine] / windows / dce.c
1 /*
2  * USER DCE functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *           1996,1997 Alex Korobka
6  *
7  *
8  * Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs 
9  * have to be updated dynamically. 
10  * 
11  * Internal DCX flags:
12  *
13  * DCX_DCEEMPTY    - dce is uninitialized
14  * DCX_DCEBUSY     - dce is in use
15  * DCX_DCEDIRTY    - ReleaseDC() should wipe instead of caching
16  * DCX_KEEPCLIPRGN - ReleaseDC() should not delete the clipping region
17  * DCX_WINDOWPAINT - BeginPaint() is in effect
18  */
19
20 #include "options.h"
21 #include "dce.h"
22 #include "class.h"
23 #include "win.h"
24 #include "gdi.h"
25 #include "region.h"
26 #include "heap.h"
27 #include "sysmetrics.h"
28 #include "debug.h"
29 #include "wine/winuser16.h"
30
31 #define NB_DCE    5  /* Number of DCEs created at startup */
32
33 static DCE *firstDCE = 0;
34 static HDC32 defaultDCstate = 0;
35
36 static void DCE_DeleteClipRgn( DCE* );
37 static INT32 DCE_ReleaseDC( DCE* );
38
39
40 /***********************************************************************
41  *           DCE_DumpCache
42  */
43 static void DCE_DumpCache(void)
44 {
45     DCE* dce = firstDCE;
46     
47     DUMP("DCE:\n");
48     while( dce )
49     {
50         DUMP("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
51              (unsigned)dce, dce->hwndCurrent, (unsigned)dce->DCXflags, 
52              (dce->DCXflags & DCX_CACHE) ? "Cache" : "Owned", 
53              (dce->DCXflags & DCX_DCEBUSY) ? "InUse" : "" );
54         dce = dce->next;
55     }
56 }
57
58 /***********************************************************************
59  *           DCE_AllocDCE
60  *
61  * Allocate a new DCE.
62  */
63 DCE *DCE_AllocDCE( HWND32 hWnd, DCE_TYPE type )
64 {
65     DCE * dce;
66     if (!(dce = HeapAlloc( SystemHeap, 0, sizeof(DCE) ))) return NULL;
67     if (!(dce->hDC = CreateDC16( "DISPLAY", NULL, NULL, NULL )))
68     {
69         HeapFree( SystemHeap, 0, dce );
70         return 0;
71     }
72
73     /* store DCE handle in DC hook data field */
74
75     SetDCHook( dce->hDC, (FARPROC16)DCHook, (DWORD)dce );
76
77     dce->hwndCurrent = hWnd;
78     dce->hClipRgn    = 0;
79     dce->next        = firstDCE;
80     firstDCE = dce;
81
82     if( type != DCE_CACHE_DC ) /* owned or class DC */
83     {
84         dce->DCXflags = DCX_DCEBUSY;
85         if( hWnd )
86         {
87             WND* wnd = WIN_FindWndPtr(hWnd);
88         
89             if( wnd->dwStyle & WS_CLIPCHILDREN ) dce->DCXflags |= DCX_CLIPCHILDREN;
90             if( wnd->dwStyle & WS_CLIPSIBLINGS ) dce->DCXflags |= DCX_CLIPSIBLINGS;
91         }
92         SetHookFlags(dce->hDC,DCHF_INVALIDATEVISRGN);
93     }
94     else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY;
95
96     return dce;
97 }
98
99
100 /***********************************************************************
101  *           DCE_FreeDCE
102  */
103 DCE* DCE_FreeDCE( DCE *dce )
104 {
105     DCE **ppDCE = &firstDCE;
106
107     if (!dce) return NULL;
108     while (*ppDCE && (*ppDCE != dce)) ppDCE = &(*ppDCE)->next;
109     if (*ppDCE == dce) *ppDCE = dce->next;
110
111     SetDCHook(dce->hDC, NULL, 0L);
112
113     DeleteDC32( dce->hDC );
114     if( dce->hClipRgn && !(dce->DCXflags & DCX_KEEPCLIPRGN) )
115         DeleteObject32(dce->hClipRgn);
116     HeapFree( SystemHeap, 0, dce );
117     return *ppDCE;
118 }
119
120 /***********************************************************************
121  *           DCE_FreeWindowDCE
122  *
123  * Remove owned DCE and reset unreleased cache DCEs.
124  */
125 void DCE_FreeWindowDCE( WND* pWnd )
126 {
127     DCE *pDCE = firstDCE;
128
129     while( pDCE )
130     {
131         if( pDCE->hwndCurrent == pWnd->hwndSelf )
132         {
133             if( pDCE == pWnd->dce ) /* owned DCE */
134             {
135                 pDCE = DCE_FreeDCE( pDCE );
136                 pWnd->dce = NULL;
137                 continue;
138             }
139             else
140             {
141                 if(!(pDCE->DCXflags & DCX_CACHE) ) /* class DCE */
142                 {
143                     if( pDCE->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN) )
144                         DCE_DeleteClipRgn( pDCE );
145                 }
146                 else if( pDCE->DCXflags & DCX_DCEBUSY ) /* shared cache DCE */
147                 {
148                     ERR(dc,"[%04x] GetDC() without ReleaseDC()!\n", 
149                         pWnd->hwndSelf);
150                     DCE_ReleaseDC( pDCE );
151                 }
152
153                 pDCE->DCXflags &= DCX_CACHE;
154                 pDCE->DCXflags |= DCX_DCEEMPTY;
155                 pDCE->hwndCurrent = 0;
156             }
157         }
158         pDCE = pDCE->next;
159     }
160 }
161
162
163 /***********************************************************************
164  *   DCE_DeleteClipRgn
165  */
166 static void DCE_DeleteClipRgn( DCE* dce )
167 {
168     dce->DCXflags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
169
170     if( dce->DCXflags & DCX_KEEPCLIPRGN )
171         dce->DCXflags &= ~DCX_KEEPCLIPRGN;
172     else
173         if( dce->hClipRgn > 1 )
174             DeleteObject32( dce->hClipRgn );
175
176     dce->hClipRgn = 0;
177
178     TRACE(dc,"\trestoring VisRgn\n");
179
180     RestoreVisRgn(dce->hDC);
181 }
182
183
184 /***********************************************************************
185  *   DCE_ReleaseDC
186  */
187 static INT32 DCE_ReleaseDC( DCE* dce )
188 {
189     if ((dce->DCXflags & (DCX_DCEEMPTY | DCX_DCEBUSY)) != DCX_DCEBUSY) return 0;
190
191     /* restore previous visible region */
192
193     if ((dce->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
194         (dce->DCXflags & (DCX_CACHE | DCX_WINDOWPAINT)) )
195         DCE_DeleteClipRgn( dce );
196
197     if (dce->DCXflags & DCX_CACHE)
198     {
199         SetDCState( dce->hDC, defaultDCstate );
200         dce->DCXflags &= ~DCX_DCEBUSY;
201         if (dce->DCXflags & DCX_DCEDIRTY)
202         {
203             /* don't keep around invalidated entries 
204              * because SetDCState() disables hVisRgn updates
205              * by removing dirty bit. */
206
207             dce->hwndCurrent = 0;
208             dce->DCXflags &= DCX_CACHE;
209             dce->DCXflags |= DCX_DCEEMPTY;
210         }
211     }
212     return 1;
213 }
214
215
216 /***********************************************************************
217  *   DCE_InvalidateDCE
218  *
219  * It is called from SetWindowPos() - we have to mark as dirty all busy
220  * DCE's for windows that have pWnd->parent as an ansector and whose client 
221  * rect intersects with specified update rectangle. 
222  */
223 BOOL32 DCE_InvalidateDCE(WND* pWnd, const RECT32* pRectUpdate)
224 {
225     WND* wndScope = pWnd->parent;
226     BOOL32 bRet = FALSE;
227
228     if( wndScope )
229     {
230         DCE *dce;
231
232         TRACE(dc,"scope hwnd = %04x, (%i,%i - %i,%i)\n",
233                      wndScope->hwndSelf, pRectUpdate->left,pRectUpdate->top,
234                      pRectUpdate->right,pRectUpdate->bottom);
235         if(TRACE_ON(dc)) 
236           DCE_DumpCache();
237
238         /* walk all DCEs and fixup non-empty entries */
239
240         for (dce = firstDCE; (dce); dce = dce->next)
241         {
242             if( !(dce->DCXflags & DCX_DCEEMPTY) )
243             {
244                 WND* wndCurrent = WIN_FindWndPtr(dce->hwndCurrent);
245
246                 if( wndCurrent && wndCurrent != WIN_GetDesktop() )
247                 {
248                     WND* wnd = wndCurrent;
249                     INT32 xoffset = 0, yoffset = 0;
250
251                     if( (wndCurrent == wndScope) && !(dce->DCXflags & DCX_CLIPCHILDREN) ) continue;
252
253                     /* check if DCE window is within the z-order scope */
254
255                     for( wnd = wndCurrent; wnd; wnd = wnd->parent )
256                     {
257                         if( wnd == wndScope )
258                         {
259                             RECT32 wndRect;
260
261                             wndRect = wndCurrent->rectWindow;
262
263                             OffsetRect32( &wndRect, xoffset - wndCurrent->rectClient.left, 
264                                                     yoffset - wndCurrent->rectClient.top);
265
266                             if (pWnd == wndCurrent ||
267                                 IntersectRect32( &wndRect, &wndRect, pRectUpdate ))
268                             { 
269                                 if( !(dce->DCXflags & DCX_DCEBUSY) )
270                                 {
271                                     /* Don't bother with visible regions of unused DCEs */
272
273                                     TRACE(dc,"\tpurged %08x dce [%04x]\n", 
274                                                 (unsigned)dce, wndCurrent->hwndSelf);
275
276                                     dce->hwndCurrent = 0;
277                                     dce->DCXflags &= DCX_CACHE;
278                                     dce->DCXflags |= DCX_DCEEMPTY;
279                                 }
280                                 else
281                                 {
282                                     /* Set dirty bits in the hDC and DCE structs */
283
284                                     TRACE(dc,"\tfixed up %08x dce [%04x]\n", 
285                                                 (unsigned)dce, wndCurrent->hwndSelf);
286
287                                     dce->DCXflags |= DCX_DCEDIRTY;
288                                     SetHookFlags(dce->hDC, DCHF_INVALIDATEVISRGN);
289                                     bRet = TRUE;
290                                 }
291                             }
292                             break;
293                         }
294                         xoffset += wnd->rectClient.left;
295                         yoffset += wnd->rectClient.top;
296                     }
297                 }
298             }
299         } /* dce list */
300     }
301     return bRet;
302 }
303
304 /***********************************************************************
305  *           DCE_Init
306  */
307 void DCE_Init(void)
308 {
309     int i;
310     DCE * dce;
311         
312     for (i = 0; i < NB_DCE; i++)
313     {
314         if (!(dce = DCE_AllocDCE( 0, DCE_CACHE_DC ))) return;
315         if (!defaultDCstate) defaultDCstate = GetDCState( dce->hDC );
316     }
317 }
318
319
320 /***********************************************************************
321  *           DCE_GetVisRect
322  *
323  * Calculate the visible rectangle of a window (i.e. the client or
324  * window area clipped by the client area of all ancestors) in the
325  * corresponding coordinates. Return FALSE if the visible region is empty.
326  */
327 static BOOL32 DCE_GetVisRect( WND *wndPtr, BOOL32 clientArea, RECT32 *lprect )
328 {
329     *lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
330
331     if (wndPtr->dwStyle & WS_VISIBLE)
332     {
333         INT32 xoffset = lprect->left;
334         INT32 yoffset = lprect->top;
335
336         while (wndPtr->dwStyle & WS_CHILD)
337         {
338             wndPtr = wndPtr->parent;
339
340             if ( (wndPtr->dwStyle & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE )
341                 goto fail;
342
343             xoffset += wndPtr->rectClient.left;
344             yoffset += wndPtr->rectClient.top;
345             OffsetRect32( lprect, wndPtr->rectClient.left,
346                                   wndPtr->rectClient.top );
347
348             if( (wndPtr->rectClient.left >= wndPtr->rectClient.right) ||
349                 (wndPtr->rectClient.top >= wndPtr->rectClient.bottom) ||
350                 (lprect->left >= wndPtr->rectClient.right) ||
351                 (lprect->right <= wndPtr->rectClient.left) ||
352                 (lprect->top >= wndPtr->rectClient.bottom) ||
353                 (lprect->bottom <= wndPtr->rectClient.top) )
354                 goto fail;
355
356             lprect->left = MAX( lprect->left, wndPtr->rectClient.left );
357             lprect->right = MIN( lprect->right, wndPtr->rectClient.right );
358             lprect->top = MAX( lprect->top, wndPtr->rectClient.top );
359             lprect->bottom = MIN( lprect->bottom, wndPtr->rectClient.bottom );
360         }
361         OffsetRect32( lprect, -xoffset, -yoffset );
362         return TRUE;
363     }
364
365 fail:
366     SetRectEmpty32( lprect );
367     return FALSE;
368 }
369
370
371 /***********************************************************************
372  *           DCE_AddClipRects
373  *
374  * Go through the linked list of windows from pWndStart to pWndEnd,
375  * adding to the clip region the intersection of the target rectangle
376  * with an offset window rectangle.
377  */
378 static BOOL32 DCE_AddClipRects( WND *pWndStart, WND *pWndEnd, 
379                                 HRGN32 hrgnClip, LPRECT32 lpRect, int x, int y )
380 {
381     RECT32 rect;
382
383     if( pWndStart->pDriver->pIsSelfClipping( pWndStart ) )
384         return TRUE; /* The driver itself will do the clipping */
385
386     for (; pWndStart != pWndEnd; pWndStart = pWndStart->next)
387     {
388         if( !(pWndStart->dwStyle & WS_VISIBLE) ) continue;
389             
390         rect.left = pWndStart->rectWindow.left + x;
391         rect.top = pWndStart->rectWindow.top + y;
392         rect.right = pWndStart->rectWindow.right + x;
393         rect.bottom = pWndStart->rectWindow.bottom + y;
394
395         if( IntersectRect32( &rect, &rect, lpRect ))
396             if(!REGION_UnionRectWithRgn( hrgnClip, &rect ))
397                 break;
398     }
399     return (pWndStart == pWndEnd);
400 }
401
402
403 /***********************************************************************
404  *           DCE_GetVisRgn
405  *
406  * Return the visible region of a window, i.e. the client or window area
407  * clipped by the client area of all ancestors, and then optionally
408  * by siblings and children.
409  */
410 HRGN32 DCE_GetVisRgn( HWND32 hwnd, WORD flags )
411 {
412     HRGN32 hrgnVis = 0;
413     RECT32 rect;
414     WND *wndPtr = WIN_FindWndPtr( hwnd );
415
416     /* Get visible rectangle and create a region with it. */
417
418     if (wndPtr && DCE_GetVisRect(wndPtr, !(flags & DCX_WINDOW), &rect))
419     {
420         if((hrgnVis = CreateRectRgnIndirect32( &rect )))
421         {
422             HRGN32 hrgnClip = CreateRectRgn32( 0, 0, 0, 0 );
423             INT32 xoffset, yoffset;
424
425             if( hrgnClip )
426             {
427                 /* Compute obscured region for the visible rectangle by 
428                  * clipping children, siblings, and ancestors. Note that
429                  * DCE_GetVisRect() returns a rectangle either in client
430                  * or in window coordinates (for DCX_WINDOW request). */
431
432                 if( (flags & DCX_CLIPCHILDREN) && wndPtr->child )
433                 {
434                     if( flags & DCX_WINDOW )
435                     {
436                         /* adjust offsets since child window rectangles are 
437                          * in client coordinates */
438
439                         xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
440                         yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
441                     }
442                     else 
443                         xoffset = yoffset = 0;
444
445                     DCE_AddClipRects( wndPtr->child, NULL, hrgnClip, 
446                                       &rect, xoffset, yoffset );
447                 }
448
449                 /* sibling window rectangles are in client 
450                  * coordinates of the parent window */
451
452                 if (flags & DCX_WINDOW)
453                 {
454                     xoffset = -wndPtr->rectWindow.left;
455                     yoffset = -wndPtr->rectWindow.top;
456                 }
457                 else
458                 {
459                     xoffset = -wndPtr->rectClient.left;
460                     yoffset = -wndPtr->rectClient.top;
461                 }
462
463                 if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
464                     DCE_AddClipRects( wndPtr->parent->child,
465                                       wndPtr, hrgnClip, &rect, xoffset, yoffset );
466
467                 /* Clip siblings of all ancestors that have the
468                  * WS_CLIPSIBLINGS style
469                  */
470
471                 while (wndPtr->dwStyle & WS_CHILD)
472                 {
473                     wndPtr = wndPtr->parent;
474                     xoffset -= wndPtr->rectClient.left;
475                     yoffset -= wndPtr->rectClient.top;
476                     if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
477                     {
478                         DCE_AddClipRects( wndPtr->parent->child, wndPtr,
479                                           hrgnClip, &rect, xoffset, yoffset );
480                     }
481                 }
482
483                 /* Now once we've got a jumbo clip region we have
484                  * to substract it from the visible rectangle.
485                  */
486
487                 CombineRgn32( hrgnVis, hrgnVis, hrgnClip, RGN_DIFF );
488                 DeleteObject32( hrgnClip );
489             }
490             else
491             {
492                 DeleteObject32( hrgnVis );
493                 hrgnVis = 0;
494             }
495         }
496     }
497     else
498         hrgnVis = CreateRectRgn32(0, 0, 0, 0); /* empty */
499     return hrgnVis;
500 }
501
502 /***********************************************************************
503  *           DCE_OffsetVisRgn
504  *
505  * Change region from DC-origin relative coordinates to screen coords.
506  */
507
508 static void DCE_OffsetVisRgn( HDC32 hDC, HRGN32 hVisRgn )
509 {
510     DC *dc;
511     if (!(dc = (DC *) GDI_GetObjPtr( hDC, DC_MAGIC ))) return;
512
513     OffsetRgn32( hVisRgn, dc->w.DCOrgX, dc->w.DCOrgY );
514
515     GDI_HEAP_UNLOCK( hDC );
516 }
517
518 /***********************************************************************
519  *           DCE_ExcludeRgn
520  * 
521  *  Translate given region from the wnd client to the DC coordinates
522  *  and add it to the clipping region.
523  */
524 INT16 DCE_ExcludeRgn( HDC32 hDC, WND* wnd, HRGN32 hRgn )
525 {
526   POINT32  pt = {0, 0};
527   DCE     *dce = firstDCE;
528
529   while (dce && (dce->hDC != hDC)) dce = dce->next;
530   if( dce )
531   {
532       MapWindowPoints32( wnd->hwndSelf, dce->hwndCurrent, &pt, 1);
533       if( dce->DCXflags & DCX_WINDOW )
534       { 
535           wnd = WIN_FindWndPtr(dce->hwndCurrent);
536           pt.x += wnd->rectClient.left - wnd->rectWindow.left;
537           pt.y += wnd->rectClient.top - wnd->rectWindow.top;
538       }
539   }
540   else return ERROR;
541   OffsetRgn32(hRgn, pt.x, pt.y);
542
543   return ExtSelectClipRgn( hDC, hRgn, RGN_DIFF );
544 }
545
546 /***********************************************************************
547  *           GetDCEx16    (USER.359)
548  */
549 HDC16 WINAPI GetDCEx16( HWND16 hwnd, HRGN16 hrgnClip, DWORD flags )
550 {
551     return (HDC16)GetDCEx32( hwnd, hrgnClip, flags );
552 }
553
554
555 /***********************************************************************
556  *           GetDCEx32    (USER32.231)
557  *
558  * Unimplemented flags: DCX_LOCKWINDOWUPDATE
559  *
560  * FIXME: Full support for hrgnClip == 1 (alias for entire window).
561  */
562 HDC32 WINAPI GetDCEx32( HWND32 hwnd, HRGN32 hrgnClip, DWORD flags )
563 {
564     HRGN32      hrgnVisible = 0;
565     HDC32       hdc = 0;
566     DCE *       dce;
567     DC *        dc;
568     WND *       wndPtr;
569     DWORD       dcxFlags = 0;
570     BOOL32      bUpdateVisRgn = TRUE;
571     BOOL32      bUpdateClipOrigin = FALSE;
572
573     TRACE(dc,"hwnd %04x, hrgnClip %04x, flags %08x\n", 
574                                 hwnd, hrgnClip, (unsigned)flags);
575     
576     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
577
578     /* fixup flags */
579
580     if (!(wndPtr->class->style & (CS_OWNDC | CS_CLASSDC))) flags |= DCX_CACHE;
581
582     if (flags & DCX_USESTYLE)
583     {
584         flags &= ~( DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
585
586         if( wndPtr->dwStyle & WS_CLIPSIBLINGS )
587             flags |= DCX_CLIPSIBLINGS;
588
589         if ( !(flags & DCX_WINDOW) )
590         {
591             if (wndPtr->class->style & CS_PARENTDC) flags |= DCX_PARENTCLIP;
592
593             if (wndPtr->dwStyle & WS_CLIPCHILDREN &&
594                      !(wndPtr->dwStyle & WS_MINIMIZE) ) flags |= DCX_CLIPCHILDREN;
595         }
596         else flags |= DCX_CACHE;
597     }
598
599     if( flags & DCX_NOCLIPCHILDREN )
600     {
601         flags |= DCX_CACHE;
602         flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
603     }
604
605     if (flags & DCX_WINDOW) 
606         flags = (flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
607
608     if (!(wndPtr->dwStyle & WS_CHILD) || !wndPtr->parent ) 
609         flags &= ~DCX_PARENTCLIP;
610     else if( flags & DCX_PARENTCLIP )
611     {
612         flags |= DCX_CACHE;
613         if( !(flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) )
614             if( (wndPtr->dwStyle & WS_VISIBLE) && (wndPtr->parent->dwStyle & WS_VISIBLE) )
615             {
616                 flags &= ~DCX_CLIPCHILDREN;
617                 if( wndPtr->parent->dwStyle & WS_CLIPSIBLINGS )
618                     flags |= DCX_CLIPSIBLINGS;
619             }
620     }
621
622     /* find a suitable DCE */
623
624     dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | 
625                         DCX_CACHE | DCX_WINDOW);
626
627     if (flags & DCX_CACHE)
628     {
629         DCE*    dceEmpty;
630         DCE*    dceUnused;
631
632         dceEmpty = dceUnused = NULL;
633
634         /* Strategy: First, we attempt to find a non-empty but unused DCE with
635          * compatible flags. Next, we look for an empty entry. If the cache is
636          * full we have to purge one of the unused entries.
637          */
638
639         for (dce = firstDCE; (dce); dce = dce->next)
640         {
641             if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE )
642             {
643                 dceUnused = dce;
644
645                 if (dce->DCXflags & DCX_DCEEMPTY)
646                     dceEmpty = dce;
647                 else
648                 if ((dce->hwndCurrent == hwnd) &&
649                    ((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
650                                       DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
651                 {
652                     TRACE(dc,"\tfound valid %08x dce [%04x], flags %08x\n", 
653                                         (unsigned)dce, hwnd, (unsigned)dcxFlags );
654                     bUpdateVisRgn = FALSE; 
655                     bUpdateClipOrigin = TRUE;
656                     break;
657                 }
658             }
659         }
660         if (!dce) dce = (dceEmpty) ? dceEmpty : dceUnused;
661     }
662     else 
663     {
664         dce = (wndPtr->class->style & CS_OWNDC) ? wndPtr->dce : wndPtr->class->dce;
665         if( dce->hwndCurrent == hwnd )
666         {
667             TRACE(dc,"\tskipping hVisRgn update\n");
668             bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
669
670             if( (dce->DCXflags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) &&
671                 (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN)) )
672             {
673                 /* This is likely to be a nested BeginPaint(). */
674
675                 if( dce->hClipRgn != hrgnClip )
676                 {
677                     FIXME(dc,"new hrgnClip[%04x] smashes the previous[%04x]\n",
678                           hrgnClip, dce->hClipRgn );
679                     DCE_DeleteClipRgn( dce );
680                 }
681                 else 
682                     RestoreVisRgn(dce->hDC);
683             }
684         }
685     }
686     if (!dce) return 0;
687
688     dce->hwndCurrent = hwnd;
689     dce->hClipRgn = 0;
690     dce->DCXflags = dcxFlags | (flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
691     hdc = dce->hDC;
692     
693     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
694     bUpdateVisRgn = bUpdateVisRgn || (dc->w.flags & DC_DIRTY);
695
696     /* recompute visible region */
697
698     wndPtr->pDriver->pSetDrawable( wndPtr, dc, flags, bUpdateClipOrigin );
699     if( bUpdateVisRgn )
700     {
701         TRACE(dc,"updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd);
702
703         if (flags & DCX_PARENTCLIP)
704         {
705             WND *parentPtr = wndPtr->parent;
706
707             if( wndPtr->dwStyle & WS_VISIBLE && !(parentPtr->dwStyle & WS_MINIMIZE) )
708             {
709                 if( parentPtr->dwStyle & WS_CLIPSIBLINGS ) 
710                     dcxFlags = DCX_CLIPSIBLINGS | (flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
711                 else
712                     dcxFlags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
713
714                 hrgnVisible = DCE_GetVisRgn( parentPtr->hwndSelf, dcxFlags );
715                 if( flags & DCX_WINDOW )
716                     OffsetRgn32( hrgnVisible, -wndPtr->rectWindow.left,
717                                               -wndPtr->rectWindow.top );
718                 else
719                     OffsetRgn32( hrgnVisible, -wndPtr->rectClient.left,
720                                               -wndPtr->rectClient.top );
721                 DCE_OffsetVisRgn( hdc, hrgnVisible );
722             }
723             else
724                 hrgnVisible = CreateRectRgn32( 0, 0, 0, 0 );
725         }
726         else 
727             if ((hwnd == GetDesktopWindow32()) &&
728                 (rootWindow == DefaultRootWindow(display)))
729                  hrgnVisible = CreateRectRgn32( 0, 0, SYSMETRICS_CXSCREEN,
730                                                       SYSMETRICS_CYSCREEN );
731             else 
732             {
733                 hrgnVisible = DCE_GetVisRgn( hwnd, flags );
734                 DCE_OffsetVisRgn( hdc, hrgnVisible );
735             }
736
737         dc->w.flags &= ~DC_DIRTY;
738         dce->DCXflags &= ~DCX_DCEDIRTY;
739         SelectVisRgn( hdc, hrgnVisible );
740     }
741     else
742         TRACE(dc,"no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd);
743
744     /* apply additional region operation (if any) */
745
746     if( flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) )
747     {
748         if( !hrgnVisible ) hrgnVisible = CreateRectRgn32( 0, 0, 0, 0 );
749
750         dce->DCXflags |= flags & (DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_EXCLUDERGN);
751         dce->hClipRgn = hrgnClip;
752
753         TRACE(dc, "\tsaved VisRgn, clipRgn = %04x\n", hrgnClip);
754
755         SaveVisRgn( hdc );
756         CombineRgn32( hrgnVisible, hrgnClip, 0, RGN_COPY );
757         DCE_OffsetVisRgn( hdc, hrgnVisible );
758         CombineRgn32( hrgnVisible, InquireVisRgn( hdc ), hrgnVisible,
759                       (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
760         SelectVisRgn( hdc, hrgnVisible );
761     }
762
763     if( hrgnVisible ) DeleteObject32( hrgnVisible );
764
765     TRACE(dc, "(%04x,%04x,0x%lx): returning %04x\n", 
766                hwnd, hrgnClip, flags, hdc);
767     return hdc;
768 }
769
770
771 /***********************************************************************
772  *           GetDC16    (USER.66)
773  */
774 HDC16 WINAPI GetDC16( HWND16 hwnd )
775 {
776     return (HDC16)GetDC32( hwnd );
777 }
778
779
780 /***********************************************************************
781  *           GetDC32    (USER32.230)
782  * RETURNS
783  *      :Handle to DC
784  *      NULL: Failure
785  */
786 HDC32 WINAPI GetDC32(
787              HWND32 hwnd /* handle of window */
788 ) {
789     if (!hwnd)
790         return GetDCEx32( GetDesktopWindow32(), 0, DCX_CACHE | DCX_WINDOW );
791     return GetDCEx32( hwnd, 0, DCX_USESTYLE );
792 }
793
794
795 /***********************************************************************
796  *           GetWindowDC16    (USER.67)
797  */
798 HDC16 WINAPI GetWindowDC16( HWND16 hwnd )
799 {
800     if (!hwnd) hwnd = GetDesktopWindow16();
801     return GetDCEx16( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
802 }
803
804
805 /***********************************************************************
806  *           GetWindowDC32    (USER32.304)
807  */
808 HDC32 WINAPI GetWindowDC32( HWND32 hwnd )
809 {
810     if (!hwnd) hwnd = GetDesktopWindow32();
811     return GetDCEx32( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
812 }
813
814
815 /***********************************************************************
816  *           ReleaseDC16    (USER.68)
817  */
818 INT16 WINAPI ReleaseDC16( HWND16 hwnd, HDC16 hdc )
819 {
820     return (INT16)ReleaseDC32( hwnd, hdc );
821 }
822
823
824 /***********************************************************************
825  *           ReleaseDC32    (USER32.440)
826  *
827  * RETURNS
828  *      1: Success
829  *      0: Failure
830  */
831 INT32 WINAPI ReleaseDC32( 
832              HWND32 hwnd /* Handle of window - ignored */, 
833              HDC32 hdc   /* Handle of device context */
834 ) {
835     DCE * dce = firstDCE;
836     
837     TRACE(dc, "%04x %04x\n", hwnd, hdc );
838         
839     while (dce && (dce->hDC != hdc)) dce = dce->next;
840
841     if ( dce ) 
842         if ( dce->DCXflags & DCX_DCEBUSY )
843              return DCE_ReleaseDC( dce );
844     return 0;
845 }
846
847 /***********************************************************************
848  *           DCHook    (USER.362)
849  *
850  * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..  
851  */
852 BOOL16 WINAPI DCHook( HDC16 hDC, WORD code, DWORD data, LPARAM lParam )
853 {
854     HRGN32 hVisRgn;
855     DCE *dce = firstDCE;;
856
857     TRACE(dc,"hDC = %04x, %i\n", hDC, code);
858
859     while (dce && (dce->hDC != hDC)) dce = dce->next;
860     if (!dce) return 0;
861
862     switch( code )
863     {
864       case DCHC_INVALIDVISRGN:
865
866            /* GDI code calls this when it detects that the
867             * DC is dirty (usually after SetHookFlags()). This
868             * means that we have to recompute the visible region.
869             */
870
871            if( dce->DCXflags & DCX_DCEBUSY )
872            {
873                SetHookFlags(hDC, DCHF_VALIDATEVISRGN);
874                hVisRgn = DCE_GetVisRgn(dce->hwndCurrent, dce->DCXflags);
875
876                TRACE(dc,"\tapplying saved clipRgn\n");
877   
878                /* clip this region with saved clipping region */
879
880                if ( (dce->DCXflags & DCX_INTERSECTRGN && dce->hClipRgn != 1) ||
881                   (  dce->DCXflags & DCX_EXCLUDERGN && dce->hClipRgn) )
882                {
883
884                     if( (!dce->hClipRgn && dce->DCXflags & DCX_INTERSECTRGN) ||
885                          (dce->hClipRgn == 1 && dce->DCXflags & DCX_EXCLUDERGN) )            
886                          SetRectRgn32(hVisRgn,0,0,0,0);
887                     else
888                          CombineRgn32(hVisRgn, hVisRgn, dce->hClipRgn, 
889                                       (dce->DCXflags & DCX_EXCLUDERGN)? RGN_DIFF:RGN_AND);
890                }
891                dce->DCXflags &= ~DCX_DCEDIRTY;
892                DCE_OffsetVisRgn( hDC, hVisRgn );
893                SelectVisRgn(hDC, hVisRgn);
894                DeleteObject32( hVisRgn );
895            }
896            else /* non-fatal but shouldn't happen */
897              WARN(dc, "DC is not in use!\n");
898            break;
899
900       case DCHC_DELETEDC: /* FIXME: ?? */
901            break;
902
903       default:
904            FIXME(dc,"unknown code\n");
905     }
906   return 0;
907 }
908
909
910 /**********************************************************************
911  *          WindowFromDC16   (USER.117)
912  */
913 HWND16 WINAPI WindowFromDC16( HDC16 hDC )
914 {
915     return (HWND16)WindowFromDC32( hDC );
916 }
917
918
919 /**********************************************************************
920  *          WindowFromDC32   (USER32.581)
921  */
922 HWND32 WINAPI WindowFromDC32( HDC32 hDC )
923 {
924     DCE *dce = firstDCE;
925     while (dce && (dce->hDC != hDC)) dce = dce->next;
926     return dce ? dce->hwndCurrent : 0;
927 }
928
929
930 /***********************************************************************
931  *           LockWindowUpdate16   (USER.294)
932  */
933 BOOL16 WINAPI LockWindowUpdate16( HWND16 hwnd )
934 {
935     return LockWindowUpdate32( hwnd );
936 }
937
938
939 /***********************************************************************
940  *           LockWindowUpdate32   (USER32.378)
941  */
942 BOOL32 WINAPI LockWindowUpdate32( HWND32 hwnd )
943 {
944     /* FIXME? DCX_LOCKWINDOWUPDATE is unimplemented */
945     return TRUE;
946 }