Prevent multiple definitions caused by MSVCRT headers.
[wine.git] / windows / dce.c
blob3fd9b4397aa0e1cb3a54c736079801e17803e535
1 /*
2 * USER DCE functions
4 * Copyright 1993 Alexandre Julliard
5 * 1996,1997 Alex Korobka
8 * Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs
9 * have to be updated dynamically.
11 * Internal DCX flags:
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
20 #include <assert.h>
21 #include "dce.h"
22 #include "win.h"
23 #include "gdi.h"
24 #include "region.h"
25 #include "user.h"
26 #include "debugtools.h"
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "wine/winbase16.h"
30 #include "wine/winuser16.h"
32 DEFAULT_DEBUG_CHANNEL(dc);
34 #define NB_DCE 5 /* Number of DCEs created at startup */
36 static DCE *firstDCE = 0;
37 static HDC defaultDCstate = 0;
39 static void DCE_DeleteClipRgn( DCE* );
40 static INT DCE_ReleaseDC( DCE* );
43 /***********************************************************************
44 * DCE_DumpCache
46 static void DCE_DumpCache(void)
48 DCE *dce;
50 WIN_LockWnds();
51 dce = firstDCE;
53 DPRINTF("DCE:\n");
54 while( dce )
56 DPRINTF("\t[0x%08x] hWnd 0x%04x, dcx %08x, %s %s\n",
57 (unsigned)dce, dce->hwndCurrent, (unsigned)dce->DCXflags,
58 (dce->DCXflags & DCX_CACHE) ? "Cache" : "Owned",
59 (dce->DCXflags & DCX_DCEBUSY) ? "InUse" : "" );
60 dce = dce->next;
63 WIN_UnlockWnds();
66 /***********************************************************************
67 * DCE_AllocDCE
69 * Allocate a new DCE.
71 DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
73 FARPROC16 hookProc;
74 DCE * dce;
75 WND* wnd;
77 if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(DCE) ))) return NULL;
78 if (!(dce->hDC = CreateDCA( "DISPLAY", NULL, NULL, NULL )))
80 HeapFree( GetProcessHeap(), 0, dce );
81 return 0;
84 wnd = WIN_FindWndPtr(hWnd);
86 /* store DCE handle in DC hook data field */
88 hookProc = GetProcAddress16( GetModuleHandle16("USER"), (LPCSTR)362 );
89 SetDCHook( dce->hDC, hookProc, (DWORD)dce );
91 dce->hwndCurrent = hWnd;
92 dce->hClipRgn = 0;
93 dce->next = firstDCE;
94 firstDCE = dce;
96 if( type != DCE_CACHE_DC ) /* owned or class DC */
98 dce->DCXflags = DCX_DCEBUSY;
99 if( hWnd )
101 if( wnd->dwStyle & WS_CLIPCHILDREN ) dce->DCXflags |= DCX_CLIPCHILDREN;
102 if( wnd->dwStyle & WS_CLIPSIBLINGS ) dce->DCXflags |= DCX_CLIPSIBLINGS;
104 SetHookFlags16(dce->hDC,DCHF_INVALIDATEVISRGN);
106 else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY;
108 WIN_ReleaseWndPtr(wnd);
110 return dce;
114 /***********************************************************************
115 * DCE_FreeDCE
117 DCE* DCE_FreeDCE( DCE *dce )
119 DCE **ppDCE;
121 if (!dce) return NULL;
123 WIN_LockWnds();
125 ppDCE = &firstDCE;
127 while (*ppDCE && (*ppDCE != dce)) ppDCE = &(*ppDCE)->next;
128 if (*ppDCE == dce) *ppDCE = dce->next;
130 SetDCHook(dce->hDC, NULL, 0L);
132 DeleteDC( dce->hDC );
133 if( dce->hClipRgn && !(dce->DCXflags & DCX_KEEPCLIPRGN) )
134 DeleteObject(dce->hClipRgn);
135 HeapFree( GetProcessHeap(), 0, dce );
137 WIN_UnlockWnds();
139 return *ppDCE;
142 /***********************************************************************
143 * DCE_FreeWindowDCE
145 * Remove owned DCE and reset unreleased cache DCEs.
147 void DCE_FreeWindowDCE( WND* pWnd )
149 DCE *pDCE;
151 WIN_LockWnds();
152 pDCE = firstDCE;
154 while( pDCE )
156 if( pDCE->hwndCurrent == pWnd->hwndSelf )
158 if( pDCE == pWnd->dce ) /* owned or Class DCE*/
160 if (pWnd->clsStyle & CS_OWNDC) /* owned DCE*/
162 pDCE = DCE_FreeDCE( pDCE );
163 pWnd->dce = NULL;
164 continue;
166 else if( pDCE->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN) ) /* Class DCE*/
168 DCE_DeleteClipRgn( pDCE );
169 pDCE->hwndCurrent = 0;
172 else
174 if( pDCE->DCXflags & DCX_DCEBUSY ) /* shared cache DCE */
176 /* FIXME: AFAICS we are doing the right thing here so
177 * this should be a WARN. But this is best left as an ERR
178 * because the 'application error' is likely to come from
179 * another part of Wine (i.e. it's our fault after all).
180 * We should change this to WARN when Wine is more stable
181 * (for 1.0?).
183 ERR("[%04x] GetDC() without ReleaseDC()!\n",
184 pWnd->hwndSelf);
185 DCE_ReleaseDC( pDCE );
188 pDCE->DCXflags &= DCX_CACHE;
189 pDCE->DCXflags |= DCX_DCEEMPTY;
190 pDCE->hwndCurrent = 0;
193 pDCE = pDCE->next;
196 WIN_UnlockWnds();
200 /***********************************************************************
201 * DCE_DeleteClipRgn
203 static void DCE_DeleteClipRgn( DCE* dce )
205 dce->DCXflags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
207 if( dce->DCXflags & DCX_KEEPCLIPRGN )
208 dce->DCXflags &= ~DCX_KEEPCLIPRGN;
209 else
210 if( dce->hClipRgn > 1 )
211 DeleteObject( dce->hClipRgn );
213 dce->hClipRgn = 0;
215 TRACE("\trestoring VisRgn\n");
217 RestoreVisRgn16(dce->hDC);
221 /***********************************************************************
222 * DCE_ReleaseDC
224 static INT DCE_ReleaseDC( DCE* dce )
226 if ((dce->DCXflags & (DCX_DCEEMPTY | DCX_DCEBUSY)) != DCX_DCEBUSY) return 0;
228 /* restore previous visible region */
230 if ((dce->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
231 (dce->DCXflags & (DCX_CACHE | DCX_WINDOWPAINT)) )
232 DCE_DeleteClipRgn( dce );
234 if (dce->DCXflags & DCX_CACHE)
236 SetDCState16( dce->hDC, defaultDCstate );
237 dce->DCXflags &= ~DCX_DCEBUSY;
238 if (dce->DCXflags & DCX_DCEDIRTY)
240 /* don't keep around invalidated entries
241 * because SetDCState() disables hVisRgn updates
242 * by removing dirty bit. */
244 dce->hwndCurrent = 0;
245 dce->DCXflags &= DCX_CACHE;
246 dce->DCXflags |= DCX_DCEEMPTY;
249 return 1;
253 /***********************************************************************
254 * DCE_InvalidateDCE
256 * It is called from SetWindowPos() and EVENT_MapNotify - we have to
257 * mark as dirty all busy DCEs for windows that have pWnd->parent as
258 * an ancestor and whose client rect intersects with specified update
259 * rectangle. In addition, pWnd->parent DCEs may need to be updated if
260 * DCX_CLIPCHILDREN flag is set. */
261 BOOL DCE_InvalidateDCE(WND* pWnd, const RECT* pRectUpdate)
263 WND* wndScope = WIN_LockWndPtr(pWnd->parent);
264 WND *pDesktop = WIN_GetDesktop();
265 BOOL bRet = FALSE;
267 if( wndScope )
269 DCE *dce;
271 TRACE("scope hwnd = %04x, (%i,%i - %i,%i)\n",
272 wndScope->hwndSelf, pRectUpdate->left,pRectUpdate->top,
273 pRectUpdate->right,pRectUpdate->bottom);
274 if(TRACE_ON(dc))
275 DCE_DumpCache();
277 /* walk all DCEs and fixup non-empty entries */
279 for (dce = firstDCE; (dce); dce = dce->next)
281 if( !(dce->DCXflags & DCX_DCEEMPTY) )
283 WND* wndCurrent = WIN_FindWndPtr(dce->hwndCurrent);
285 if( wndCurrent )
287 WND* wnd = NULL;
288 INT xoffset = 0, yoffset = 0;
290 if( (wndCurrent == wndScope) && !(dce->DCXflags & DCX_CLIPCHILDREN) )
292 /* child window positions don't bother us */
293 WIN_ReleaseWndPtr(wndCurrent);
294 continue;
297 if (wndCurrent == pDesktop && !(wndCurrent->flags & WIN_NATIVE))
299 /* don't bother with fake desktop */
300 WIN_ReleaseWndPtr(wndCurrent);
301 continue;
304 /* check if DCE window is within the z-order scope */
306 for( wnd = WIN_LockWndPtr(wndCurrent); wnd; WIN_UpdateWndPtr(&wnd,wnd->parent))
308 if( wnd == wndScope )
310 RECT wndRect;
312 wndRect = wndCurrent->rectWindow;
314 OffsetRect( &wndRect, xoffset - wndCurrent->rectClient.left,
315 yoffset - wndCurrent->rectClient.top);
317 if (pWnd == wndCurrent ||
318 IntersectRect( &wndRect, &wndRect, pRectUpdate ))
320 if( !(dce->DCXflags & DCX_DCEBUSY) )
322 /* Don't bother with visible regions of unused DCEs */
324 TRACE("\tpurged %08x dce [%04x]\n",
325 (unsigned)dce, wndCurrent->hwndSelf);
327 dce->hwndCurrent = 0;
328 dce->DCXflags &= DCX_CACHE;
329 dce->DCXflags |= DCX_DCEEMPTY;
331 else
333 /* Set dirty bits in the hDC and DCE structs */
335 TRACE("\tfixed up %08x dce [%04x]\n",
336 (unsigned)dce, wndCurrent->hwndSelf);
338 dce->DCXflags |= DCX_DCEDIRTY;
339 SetHookFlags16(dce->hDC, DCHF_INVALIDATEVISRGN);
340 bRet = TRUE;
343 WIN_ReleaseWndPtr(wnd);
344 break;
346 xoffset += wnd->rectClient.left;
347 yoffset += wnd->rectClient.top;
350 WIN_ReleaseWndPtr(wndCurrent);
352 } /* dce list */
353 WIN_ReleaseWndPtr(wndScope);
355 WIN_ReleaseDesktop();
356 return bRet;
359 /***********************************************************************
360 * DCE_Init
362 void DCE_Init(void)
364 int i;
365 DCE * dce;
367 for (i = 0; i < NB_DCE; i++)
369 if (!(dce = DCE_AllocDCE( 0, DCE_CACHE_DC ))) return;
370 if (!defaultDCstate) defaultDCstate = GetDCState16( dce->hDC );
375 /***********************************************************************
376 * DCE_GetVisRect
378 * Calculate the visible rectangle of a window (i.e. the client or
379 * window area clipped by the client area of all ancestors) in the
380 * corresponding coordinates. Return FALSE if the visible region is empty.
382 static BOOL DCE_GetVisRect( WND *wndPtr, BOOL clientArea, RECT *lprect )
384 *lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
386 if (wndPtr->dwStyle & WS_VISIBLE)
388 INT xoffset = lprect->left;
389 INT yoffset = lprect->top;
391 while( !(wndPtr->flags & WIN_NATIVE) &&
392 ( wndPtr = WIN_LockWndPtr(wndPtr->parent)) )
394 if ( (wndPtr->dwStyle & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE )
396 WIN_ReleaseWndPtr(wndPtr);
397 goto fail;
400 xoffset += wndPtr->rectClient.left;
401 yoffset += wndPtr->rectClient.top;
402 OffsetRect( lprect, wndPtr->rectClient.left,
403 wndPtr->rectClient.top );
405 if( (wndPtr->rectClient.left >= wndPtr->rectClient.right) ||
406 (wndPtr->rectClient.top >= wndPtr->rectClient.bottom) ||
407 (lprect->left >= wndPtr->rectClient.right) ||
408 (lprect->right <= wndPtr->rectClient.left) ||
409 (lprect->top >= wndPtr->rectClient.bottom) ||
410 (lprect->bottom <= wndPtr->rectClient.top) )
412 WIN_ReleaseWndPtr(wndPtr);
413 goto fail;
416 lprect->left = max( lprect->left, wndPtr->rectClient.left );
417 lprect->right = min( lprect->right, wndPtr->rectClient.right );
418 lprect->top = max( lprect->top, wndPtr->rectClient.top );
419 lprect->bottom = min( lprect->bottom, wndPtr->rectClient.bottom );
421 WIN_ReleaseWndPtr(wndPtr);
423 OffsetRect( lprect, -xoffset, -yoffset );
424 return TRUE;
427 fail:
428 SetRectEmpty( lprect );
429 return FALSE;
433 /***********************************************************************
434 * DCE_AddClipRects
436 * Go through the linked list of windows from pWndStart to pWndEnd,
437 * adding to the clip region the intersection of the target rectangle
438 * with an offset window rectangle.
440 static BOOL DCE_AddClipRects( WND *pWndStart, WND *pWndEnd,
441 HRGN hrgnClip, LPRECT lpRect, int x, int y )
443 RECT rect;
445 if( pWndStart->pDriver->pIsSelfClipping( pWndStart ) )
446 return TRUE; /* The driver itself will do the clipping */
448 for (WIN_LockWndPtr(pWndStart); (pWndStart && (pWndStart != pWndEnd)); WIN_UpdateWndPtr(&pWndStart,pWndStart->next))
450 if( !(pWndStart->dwStyle & WS_VISIBLE) ) continue;
452 rect.left = pWndStart->rectWindow.left + x;
453 rect.top = pWndStart->rectWindow.top + y;
454 rect.right = pWndStart->rectWindow.right + x;
455 rect.bottom = pWndStart->rectWindow.bottom + y;
457 if( IntersectRect( &rect, &rect, lpRect ))
459 if(!REGION_UnionRectWithRgn( hrgnClip, &rect )) break;
462 WIN_ReleaseWndPtr(pWndStart);
463 return (pWndStart == pWndEnd);
467 /***********************************************************************
468 * DCE_GetVisRgn
470 * Return the visible region of a window, i.e. the client or window area
471 * clipped by the client area of all ancestors, and then optionally
472 * by siblings and children.
474 HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
476 HRGN hrgnVis = 0;
477 RECT rect;
478 WND *wndPtr = WIN_FindWndPtr( hwnd );
479 WND *childWnd = WIN_FindWndPtr( hwndChild );
481 /* Get visible rectangle and create a region with it. */
483 if (wndPtr && DCE_GetVisRect(wndPtr, !(flags & DCX_WINDOW), &rect))
485 if((hrgnVis = CreateRectRgnIndirect( &rect )))
487 HRGN hrgnClip = CreateRectRgn( 0, 0, 0, 0 );
488 INT xoffset, yoffset;
490 if( hrgnClip )
492 /* Compute obscured region for the visible rectangle by
493 * clipping children, siblings, and ancestors. Note that
494 * DCE_GetVisRect() returns a rectangle either in client
495 * or in window coordinates (for DCX_WINDOW request). */
497 if( (flags & DCX_CLIPCHILDREN) && wndPtr->child )
499 if( flags & DCX_WINDOW )
501 /* adjust offsets since child window rectangles are
502 * in client coordinates */
504 xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
505 yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
507 else
508 xoffset = yoffset = 0;
510 DCE_AddClipRects( wndPtr->child, NULL, hrgnClip,
511 &rect, xoffset, yoffset );
514 /* We may need to clip children of child window, if a window with PARENTDC
515 * class style and CLIPCHILDREN window style (like in Free Agent 16
516 * preference dialogs) gets here, we take the region for the parent window
517 * but apparently still need to clip the children of the child window... */
519 if( (cflags & DCX_CLIPCHILDREN) && childWnd && childWnd->child )
521 if( flags & DCX_WINDOW )
523 /* adjust offsets since child window rectangles are
524 * in client coordinates */
526 xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
527 yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
529 else
530 xoffset = yoffset = 0;
532 /* client coordinates of child window */
533 xoffset += childWnd->rectClient.left;
534 yoffset += childWnd->rectClient.top;
536 DCE_AddClipRects( childWnd->child, NULL, hrgnClip,
537 &rect, xoffset, yoffset );
540 /* sibling window rectangles are in client
541 * coordinates of the parent window */
543 if (flags & DCX_WINDOW)
545 xoffset = -wndPtr->rectWindow.left;
546 yoffset = -wndPtr->rectWindow.top;
548 else
550 xoffset = -wndPtr->rectClient.left;
551 yoffset = -wndPtr->rectClient.top;
554 if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
555 DCE_AddClipRects( wndPtr->parent->child,
556 wndPtr, hrgnClip, &rect, xoffset, yoffset );
558 /* Clip siblings of all ancestors that have the
559 * WS_CLIPSIBLINGS style
562 while (wndPtr->parent)
564 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
565 xoffset -= wndPtr->rectClient.left;
566 yoffset -= wndPtr->rectClient.top;
567 if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
569 DCE_AddClipRects( wndPtr->parent->child, wndPtr,
570 hrgnClip, &rect, xoffset, yoffset );
574 /* Now once we've got a jumbo clip region we have
575 * to substract it from the visible rectangle.
578 CombineRgn( hrgnVis, hrgnVis, hrgnClip, RGN_DIFF );
579 DeleteObject( hrgnClip );
581 else
583 DeleteObject( hrgnVis );
584 hrgnVis = 0;
588 else
589 hrgnVis = CreateRectRgn(0, 0, 0, 0); /* empty */
590 WIN_ReleaseWndPtr(wndPtr);
591 WIN_ReleaseWndPtr(childWnd);
592 return hrgnVis;
595 /***********************************************************************
596 * DCE_OffsetVisRgn
598 * Change region from DC-origin relative coordinates to screen coords.
601 static void DCE_OffsetVisRgn( HDC hDC, HRGN hVisRgn )
603 DC *dc;
604 if (!(dc = DC_GetDCPtr( hDC ))) return;
606 OffsetRgn( hVisRgn, dc->DCOrgX, dc->DCOrgY );
608 GDI_ReleaseObj( hDC );
611 /***********************************************************************
612 * DCE_ExcludeRgn
614 * Translate given region from the wnd client to the DC coordinates
615 * and add it to the clipping region.
617 INT DCE_ExcludeRgn( HDC hDC, WND* wnd, HRGN hRgn )
619 POINT pt = {0, 0};
620 DCE *dce = firstDCE;
622 while (dce && (dce->hDC != hDC)) dce = dce->next;
623 if( dce )
625 MapWindowPoints( wnd->hwndSelf, dce->hwndCurrent, &pt, 1);
626 if( dce->DCXflags & DCX_WINDOW )
628 wnd = WIN_FindWndPtr(dce->hwndCurrent);
629 pt.x += wnd->rectClient.left - wnd->rectWindow.left;
630 pt.y += wnd->rectClient.top - wnd->rectWindow.top;
631 WIN_ReleaseWndPtr(wnd);
634 else return ERROR;
635 OffsetRgn(hRgn, pt.x, pt.y);
637 return ExtSelectClipRgn( hDC, hRgn, RGN_DIFF );
641 /***********************************************************************
642 * GetDCEx (USER.359)
644 HDC16 WINAPI GetDCEx16( HWND16 hwnd, HRGN16 hrgnClip, DWORD flags )
646 return (HDC16)GetDCEx( hwnd, hrgnClip, flags );
650 /***********************************************************************
651 * GetDCEx (USER32.@)
653 * Unimplemented flags: DCX_LOCKWINDOWUPDATE
655 * FIXME: Full support for hrgnClip == 1 (alias for entire window).
657 HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
659 HRGN hrgnVisible = 0;
660 HDC hdc = 0;
661 DCE * dce;
662 DC * dc;
663 WND * wndPtr;
664 DWORD dcxFlags = 0;
665 BOOL bUpdateVisRgn = TRUE;
666 BOOL bUpdateClipOrigin = FALSE;
668 TRACE("hwnd %04x, hrgnClip %04x, flags %08x\n",
669 hwnd, hrgnClip, (unsigned)flags);
671 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
673 /* fixup flags */
675 if (!wndPtr->dce) flags |= DCX_CACHE;
677 if (flags & DCX_USESTYLE)
679 flags &= ~( DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
681 if( wndPtr->dwStyle & WS_CLIPSIBLINGS )
682 flags |= DCX_CLIPSIBLINGS;
684 if ( !(flags & DCX_WINDOW) )
686 if (wndPtr->clsStyle & CS_PARENTDC) flags |= DCX_PARENTCLIP;
688 if (wndPtr->dwStyle & WS_CLIPCHILDREN &&
689 !(wndPtr->dwStyle & WS_MINIMIZE) ) flags |= DCX_CLIPCHILDREN;
691 else flags |= DCX_CACHE;
694 if( flags & DCX_NOCLIPCHILDREN )
696 flags |= DCX_CACHE;
697 flags &= ~(DCX_PARENTCLIP | DCX_CLIPCHILDREN);
700 if (flags & DCX_WINDOW)
701 flags = (flags & ~DCX_CLIPCHILDREN) | DCX_CACHE;
703 if (!(wndPtr->dwStyle & WS_CHILD) || !wndPtr->parent )
704 flags &= ~DCX_PARENTCLIP;
705 else if( flags & DCX_PARENTCLIP )
707 flags |= DCX_CACHE;
708 if( !(flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) )
709 if( (wndPtr->dwStyle & WS_VISIBLE) && (wndPtr->parent->dwStyle & WS_VISIBLE) )
711 flags &= ~DCX_CLIPCHILDREN;
712 if( wndPtr->parent->dwStyle & WS_CLIPSIBLINGS )
713 flags |= DCX_CLIPSIBLINGS;
717 /* find a suitable DCE */
719 dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
720 DCX_CACHE | DCX_WINDOW);
722 if (flags & DCX_CACHE)
724 DCE* dceEmpty;
725 DCE* dceUnused;
727 dceEmpty = dceUnused = NULL;
729 /* Strategy: First, we attempt to find a non-empty but unused DCE with
730 * compatible flags. Next, we look for an empty entry. If the cache is
731 * full we have to purge one of the unused entries.
734 for (dce = firstDCE; (dce); dce = dce->next)
736 if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE )
738 dceUnused = dce;
740 if (dce->DCXflags & DCX_DCEEMPTY)
741 dceEmpty = dce;
742 else
743 if ((dce->hwndCurrent == hwnd) &&
744 ((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
745 DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
747 TRACE("\tfound valid %08x dce [%04x], flags %08x\n",
748 (unsigned)dce, hwnd, (unsigned)dcxFlags );
749 bUpdateVisRgn = FALSE;
750 bUpdateClipOrigin = TRUE;
751 break;
756 if (!dce) dce = (dceEmpty) ? dceEmpty : dceUnused;
758 /* if there's no dce empty or unused, allocate a new one */
759 if (!dce)
761 dce = DCE_AllocDCE( 0, DCE_CACHE_DC );
764 else
766 dce = wndPtr->dce;
767 if( dce->hwndCurrent == hwnd )
769 TRACE("\tskipping hVisRgn update\n");
770 bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
772 /* Abey - 16Jul99. to take care of the nested GetDC. first one
773 with DCX_EXCLUDERGN or DCX_INTERSECTRGN flags and the next
774 one with or without these flags. */
776 if(dce->DCXflags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
778 /* This is likely to be a nested BeginPaint().
779 or a BeginPaint() followed by a GetDC()*/
781 if( dce->hClipRgn != hrgnClip )
783 FIXME("new hrgnClip[%04x] smashes the previous[%04x]\n",
784 hrgnClip, dce->hClipRgn );
785 DCE_DeleteClipRgn( dce );
787 else
788 RestoreVisRgn16(dce->hDC);
792 if (!dce)
794 hdc = 0;
795 goto END;
798 dce->hwndCurrent = hwnd;
799 dce->hClipRgn = 0;
800 dce->DCXflags = dcxFlags | (flags & DCX_WINDOWPAINT) | DCX_DCEBUSY;
801 hdc = dce->hDC;
803 if (!(dc = DC_GetDCPtr( hdc )))
805 hdc = 0;
806 goto END;
808 bUpdateVisRgn = bUpdateVisRgn || (dc->flags & DC_DIRTY);
810 /* recompute visible region */
811 wndPtr->pDriver->pSetDrawable( wndPtr, hdc, flags, bUpdateClipOrigin );
812 dc->flags &= ~DC_DIRTY;
813 GDI_ReleaseObj( hdc );
815 if( bUpdateVisRgn )
817 TRACE("updating visrgn for %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd);
819 if (flags & DCX_PARENTCLIP)
821 WND *parentPtr = WIN_LockWndPtr(wndPtr->parent);
823 if( wndPtr->dwStyle & WS_VISIBLE && !(parentPtr->dwStyle & WS_MINIMIZE) )
825 if( parentPtr->dwStyle & WS_CLIPSIBLINGS )
826 dcxFlags = DCX_CLIPSIBLINGS | (flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
827 else
828 dcxFlags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
830 hrgnVisible = DCE_GetVisRgn( parentPtr->hwndSelf, dcxFlags,
831 wndPtr->hwndSelf, flags );
832 if( flags & DCX_WINDOW )
833 OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left,
834 -wndPtr->rectWindow.top );
835 else
836 OffsetRgn( hrgnVisible, -wndPtr->rectClient.left,
837 -wndPtr->rectClient.top );
838 DCE_OffsetVisRgn( hdc, hrgnVisible );
840 else
841 hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
842 WIN_ReleaseWndPtr(parentPtr);
844 else
845 if ((hwnd == GetDesktopWindow()) && !USER_Driver.pIsSingleWindow())
846 hrgnVisible = CreateRectRgn( 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) );
847 else
849 hrgnVisible = DCE_GetVisRgn( hwnd, flags, 0, 0 );
850 DCE_OffsetVisRgn( hdc, hrgnVisible );
853 dce->DCXflags &= ~DCX_DCEDIRTY;
854 SelectVisRgn16( hdc, hrgnVisible );
856 else
857 TRACE("no visrgn update %08x dce, hwnd [%04x]\n", (unsigned)dce, hwnd);
859 /* apply additional region operation (if any) */
861 if( flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) )
863 if( !hrgnVisible ) hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
865 dce->DCXflags |= flags & (DCX_KEEPCLIPRGN | DCX_INTERSECTRGN | DCX_EXCLUDERGN);
866 dce->hClipRgn = hrgnClip;
868 TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgnClip);
870 SaveVisRgn16( hdc );
871 CombineRgn( hrgnVisible, hrgnClip, 0, RGN_COPY );
872 DCE_OffsetVisRgn( hdc, hrgnVisible );
873 CombineRgn( hrgnVisible, InquireVisRgn16( hdc ), hrgnVisible,
874 (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
875 SelectVisRgn16( hdc, hrgnVisible );
878 if( hrgnVisible ) DeleteObject( hrgnVisible );
880 TRACE("(%04x,%04x,0x%lx): returning %04x\n",
881 hwnd, hrgnClip, flags, hdc);
882 END:
883 WIN_ReleaseWndPtr(wndPtr);
884 return hdc;
888 /***********************************************************************
889 * GetDC (USER.66)
891 HDC16 WINAPI GetDC16( HWND16 hwnd )
893 return (HDC16)GetDC( hwnd );
897 /***********************************************************************
898 * GetDC (USER32.@)
899 * RETURNS
900 * :Handle to DC
901 * NULL: Failure
903 HDC WINAPI GetDC(
904 HWND hwnd /* [in] handle of window */
906 if (!hwnd)
907 return GetDCEx( GetDesktopWindow(), 0, DCX_CACHE | DCX_WINDOW );
908 return GetDCEx( hwnd, 0, DCX_USESTYLE );
912 /***********************************************************************
913 * GetWindowDC (USER.67)
915 HDC16 WINAPI GetWindowDC16( HWND16 hwnd )
917 if (!hwnd) hwnd = GetDesktopWindow16();
918 return GetDCEx16( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
922 /***********************************************************************
923 * GetWindowDC (USER32.@)
925 HDC WINAPI GetWindowDC( HWND hwnd )
927 if (!hwnd) hwnd = GetDesktopWindow();
928 return GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
932 /***********************************************************************
933 * ReleaseDC (USER.68)
935 INT16 WINAPI ReleaseDC16( HWND16 hwnd, HDC16 hdc )
937 return (INT16)ReleaseDC( hwnd, hdc );
941 /***********************************************************************
942 * ReleaseDC (USER32.@)
944 * RETURNS
945 * 1: Success
946 * 0: Failure
948 INT WINAPI ReleaseDC(
949 HWND hwnd /* [in] Handle of window - ignored */,
950 HDC hdc /* [in] Handle of device context */
952 DCE * dce;
953 INT nRet = 0;
955 WIN_LockWnds();
956 dce = firstDCE;
958 TRACE("%04x %04x\n", hwnd, hdc );
960 while (dce && (dce->hDC != hdc)) dce = dce->next;
962 if ( dce )
963 if ( dce->DCXflags & DCX_DCEBUSY )
964 nRet = DCE_ReleaseDC( dce );
966 WIN_UnlockWnds();
968 return nRet;
971 /***********************************************************************
972 * DCHook (USER.362)
974 * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
976 BOOL16 WINAPI DCHook16( HDC16 hDC, WORD code, DWORD data, LPARAM lParam )
978 BOOL retv = TRUE;
979 HRGN hVisRgn;
980 DCE *dce = (DCE *)data;
981 WND *wndPtr;
983 TRACE("hDC = %04x, %i\n", hDC, code);
985 if (!dce) return 0;
986 assert(dce->hDC == hDC);
988 /* Grab the windows lock before doing anything else */
989 WIN_LockWnds();
991 switch( code )
993 case DCHC_INVALIDVISRGN:
995 /* GDI code calls this when it detects that the
996 * DC is dirty (usually after SetHookFlags()). This
997 * means that we have to recompute the visible region.
1000 if( dce->DCXflags & DCX_DCEBUSY )
1003 /* Update stale DC in DCX */
1004 wndPtr = WIN_FindWndPtr( dce->hwndCurrent);
1005 if (wndPtr) wndPtr->pDriver->pSetDrawable( wndPtr, dce->hDC, dce->DCXflags, TRUE);
1007 SetHookFlags16(hDC, DCHF_VALIDATEVISRGN);
1008 hVisRgn = DCE_GetVisRgn(dce->hwndCurrent, dce->DCXflags, 0, 0);
1010 TRACE("\tapplying saved clipRgn\n");
1012 /* clip this region with saved clipping region */
1014 if ( (dce->DCXflags & DCX_INTERSECTRGN && dce->hClipRgn != 1) ||
1015 ( dce->DCXflags & DCX_EXCLUDERGN && dce->hClipRgn) )
1018 if( (!dce->hClipRgn && dce->DCXflags & DCX_INTERSECTRGN) ||
1019 (dce->hClipRgn == 1 && dce->DCXflags & DCX_EXCLUDERGN) )
1020 SetRectRgn(hVisRgn,0,0,0,0);
1021 else
1022 CombineRgn(hVisRgn, hVisRgn, dce->hClipRgn,
1023 (dce->DCXflags & DCX_EXCLUDERGN)? RGN_DIFF:RGN_AND);
1025 dce->DCXflags &= ~DCX_DCEDIRTY;
1026 DCE_OffsetVisRgn( hDC, hVisRgn );
1027 SelectVisRgn16(hDC, hVisRgn);
1028 DeleteObject( hVisRgn );
1029 WIN_ReleaseWndPtr( wndPtr ); /* Release WIN_FindWndPtr lock */
1031 else /* non-fatal but shouldn't happen */
1032 WARN("DC is not in use!\n");
1033 break;
1035 case DCHC_DELETEDC:
1037 * Windows will not let you delete a DC that is busy
1038 * (between GetDC and ReleaseDC)
1041 if ( dce->DCXflags & DCX_DCEBUSY )
1043 WARN("Application trying to delete a busy DC\n");
1044 retv = FALSE;
1046 break;
1048 default:
1049 FIXME("unknown code\n");
1052 WIN_UnlockWnds(); /* Release the wnd lock */
1053 return retv;
1057 /**********************************************************************
1058 * WindowFromDC (USER.117)
1060 HWND16 WINAPI WindowFromDC16( HDC16 hDC )
1062 return (HWND16)WindowFromDC( hDC );
1066 /**********************************************************************
1067 * WindowFromDC (USER32.@)
1069 HWND WINAPI WindowFromDC( HDC hDC )
1071 DCE *dce;
1072 HWND hwnd;
1074 WIN_LockWnds();
1075 dce = firstDCE;
1077 while (dce && (dce->hDC != hDC)) dce = dce->next;
1079 hwnd = dce ? dce->hwndCurrent : 0;
1080 WIN_UnlockWnds();
1082 return hwnd;
1086 /***********************************************************************
1087 * LockWindowUpdate (USER.294)
1089 BOOL16 WINAPI LockWindowUpdate16( HWND16 hwnd )
1091 return LockWindowUpdate( hwnd );
1095 /***********************************************************************
1096 * LockWindowUpdate (USER32.@)
1098 BOOL WINAPI LockWindowUpdate( HWND hwnd )
1100 FIXME("DCX_LOCKWINDOWUPDATE is unimplemented\n");
1101 return TRUE;