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