reactos/win32ss/user/ntuser/vis.c

178 lines
5.3 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Visibility computations
* FILE: win32ss/user/ntuser/vis.c
* PROGRAMMER: Ge van Geldorp (ge@gse.nl)
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserWinpos);
PREGION FASTCALL
VIS_ComputeVisibleRegion(
PWND Wnd,
BOOLEAN ClientArea,
BOOLEAN ClipChildren,
BOOLEAN ClipSiblings)
{
PREGION VisRgn, ClipRgn;
PWND PreviousWindow, CurrentWindow, CurrentSibling;
if (!Wnd || !(Wnd->style & WS_VISIBLE))
{
return NULL;
}
VisRgn = NULL;
if (ClientArea)
{
VisRgn = IntSysCreateRectpRgnIndirect(&Wnd->rcClient);
}
else
{
VisRgn = IntSysCreateRectpRgnIndirect(&Wnd->rcWindow);
}
/*
* Walk through all parent windows and for each clip the visble region
* to the parent's client area and exclude all siblings that are over
* our window.
*/
PreviousWindow = Wnd;
CurrentWindow = Wnd->spwndParent;
while (CurrentWindow)
{
if (!VerifyWnd(CurrentWindow))
{
ERR("ATM the Current Window or Parent is dead! %p\n",CurrentWindow);
if (VisRgn)
REGION_Delete(VisRgn);
return NULL;
}
if (!(CurrentWindow->style & WS_VISIBLE))
{
if (VisRgn)
REGION_Delete(VisRgn);
return NULL;
}
ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentWindow->rcClient);
IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_AND);
REGION_Delete(ClipRgn);
if ((PreviousWindow->style & WS_CLIPSIBLINGS) ||
(PreviousWindow == Wnd && ClipSiblings))
{
CurrentSibling = CurrentWindow->spwndChild;
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
while ( CurrentSibling != NULL &&
CurrentSibling != PreviousWindow )
{
if ((CurrentSibling->style & WS_VISIBLE) &&
!(CurrentSibling->ExStyle & WS_EX_TRANSPARENT))
{
ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentSibling->rcWindow);
/* Combine it with the window region if available */
if (CurrentSibling->hrgnClip && !(CurrentSibling->style & WS_MINIMIZE))
{
PREGION SiblingClipRgn = REGION_LockRgn(CurrentSibling->hrgnClip);
if (SiblingClipRgn)
{
REGION_bOffsetRgn(ClipRgn, -CurrentSibling->rcWindow.left, -CurrentSibling->rcWindow.top);
IntGdiCombineRgn(ClipRgn, ClipRgn, SiblingClipRgn, RGN_AND);
REGION_bOffsetRgn(ClipRgn, CurrentSibling->rcWindow.left, CurrentSibling->rcWindow.top);
REGION_UnlockRgn(SiblingClipRgn);
}
}
IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
REGION_Delete(ClipRgn);
}
CurrentSibling = CurrentSibling->spwndNext;
}
}
PreviousWindow = CurrentWindow;
CurrentWindow = CurrentWindow->spwndParent;
}
if (ClipChildren)
{
CurrentWindow = Wnd->spwndChild;
while (CurrentWindow)
{
if ((CurrentWindow->style & WS_VISIBLE) &&
!(CurrentWindow->ExStyle & WS_EX_TRANSPARENT))
{
ClipRgn = IntSysCreateRectpRgnIndirect(&CurrentWindow->rcWindow);
/* Combine it with the window region if available */
if (CurrentWindow->hrgnClip && !(CurrentWindow->style & WS_MINIMIZE))
{
PREGION CurrentRgnClip = REGION_LockRgn(CurrentWindow->hrgnClip);
if (CurrentRgnClip)
{
REGION_bOffsetRgn(ClipRgn, -CurrentWindow->rcWindow.left, -CurrentWindow->rcWindow.top);
IntGdiCombineRgn(ClipRgn, ClipRgn, CurrentRgnClip, RGN_AND);
REGION_bOffsetRgn(ClipRgn, CurrentWindow->rcWindow.left, CurrentWindow->rcWindow.top);
REGION_UnlockRgn(CurrentRgnClip);
}
}
IntGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
REGION_Delete(ClipRgn);
}
CurrentWindow = CurrentWindow->spwndNext;
}
}
if (Wnd->hrgnClip && !(Wnd->style & WS_MINIMIZE))
{
PREGION WndRgnClip = REGION_LockRgn(Wnd->hrgnClip);
if (WndRgnClip)
{
REGION_bOffsetRgn(VisRgn, -Wnd->rcWindow.left, -Wnd->rcWindow.top);
IntGdiCombineRgn(VisRgn, VisRgn, WndRgnClip, RGN_AND);
REGION_bOffsetRgn(VisRgn, Wnd->rcWindow.left, Wnd->rcWindow.top);
REGION_UnlockRgn(WndRgnClip);
}
}
return VisRgn;
}
VOID FASTCALL
co_VIS_WindowLayoutChanged(
PWND Wnd,
PREGION NewlyExposed)
{
PWND Parent;
USER_REFERENCE_ENTRY Ref;
ASSERT_REFS_CO(Wnd);
Parent = Wnd->spwndParent;
if(Parent)
{
PREGION TempRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
if (!TempRgn)
return;
IntGdiCombineRgn(TempRgn, NewlyExposed, NULL, RGN_COPY);
REGION_bOffsetRgn(TempRgn,
Wnd->rcWindow.left - Parent->rcClient.left,
Wnd->rcWindow.top - Parent->rcClient.top);
UserRefObjectCo(Parent, &Ref);
co_UserRedrawWindow(Parent, NULL, TempRgn,
RDW_FRAME | RDW_ERASE | RDW_INVALIDATE |
RDW_ALLCHILDREN);
UserDerefObjectCo(Parent);
REGION_Delete(TempRgn);
}
}
/* EOF */