Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

miComputeClips()

miComputeClips() is called from miValidateTree() at section 7.1 as:

    for (pWin = pChild;
	 pWin != NullWindow;
	 pWin = pWin->nextSib)
    {
	if (pWin->viewable) {
	    if (pWin->valdata) {
		REGION_INTERSECT( pScreen, &childClip,
					&totalClip,
 					&pWin->borderSize);
		miComputeClips (pWin, pScreen, &childClip, kind, &exposed);

As we read from the source code comment what miComputeClips() is called to "Recompute the clipList, borderClip, exposed and borderExposed regions for pParent and its children".

Notice that the first argument of miComputeClips(), pParent, is each child of the initial window that miValidateTree() processes at section 7.1, which as seen in the previous code snippet it takes now the role of the 'parent' in order to determine its clipping areas as well the clipping areas of any child of this (if exists).

miComputeClips() as called from miValidateTree() is relatively simple. In other cases for instance when called with VTMove, as its fourth argument, instead of VTMap, it is more complicated and this is one reason that many of code lines marked with grey are omitted from the commentary.

The regions referred in the comment are used for instance when MapWindow() is called, to determine the areas to be redrawn when a window is mapped. miComputeClips() is a recursive function since it calls itself for each infererior widnow of the one that is passed as the first argument.

miComputeClips() is implemented as:

/*
 *-----------------------------------------------------------------------
 * miComputeClips --
 *	Recompute the clipList, borderClip, exposed and borderExposed
 *	regions for pParent and its children. Only viewable windows are
 *	taken into account.
 *
 * Results:
 *	None.
 *
 * Side Effects:
 *	clipList, borderClip, exposed and borderExposed are altered.
 *	A VisibilityNotify event may be generated on the parent window.
 *
 *-----------------------------------------------------------------------
 */
static void
miComputeClips (
    register WindowPtr	pParent,
    register ScreenPtr	pScreen,
    register RegionPtr	universe,
    VTKind		kind,
    RegionPtr		exposed ) /* for intermediate calculations */
{
    int			dx,
			dy;
    RegionRec		childUniverse;
    register WindowPtr	pChild;
    int     	  	oldVis, newVis;
    BoxRec		borderSize;
    RegionRec		childUnion;
    Bool		overlap;
    RegionPtr		borderVisible;
    Bool		resized;
    /*
     * Figure out the new visibility of this window.
     * The extent of the universe should be the same as the extent of
     * the borderSize region. If the window is unobscured, this rectangle
     * will be completely inside the universe (the universe will cover it
     * completely). If the window is completely obscured, none of the
     * universe will cover the rectangle.
     */
    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
    if (dx > 32767)
	dx = 32767;
    borderSize.x2 = dx;
    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
    if (dy > 32767)
	dy = 32767;
    borderSize.y2 = dy;

    oldVis = pParent->visibility;
    switch (RECT_IN_REGION( pScreen, universe, &borderSize)) 
    {
	case rgnIN:
	    newVis = VisibilityUnobscured;
	    break;
	case rgnPART:
	    newVis = VisibilityPartiallyObscured;

#ifdef SHAPE
	    {
		RegionPtr   pBounding;

		if ((pBounding = wBoundingShape (pParent)))
		{
		    switch (miShapedWindowIn (pScreen, universe, pBounding,
					      &borderSize,
					      pParent->drawable.x,
 					      pParent->drawable.y))
		    {
		    case rgnIN:
			newVis = VisibilityUnobscured;
			break;
		    case rgnOUT:
			newVis = VisibilityFullyObscured;
			break;
		    }
		}
	    }
#endif
	    break;
	default:
	    newVis = VisibilityFullyObscured;
	    break;
    }
    pParent->visibility = newVis;
    if (oldVis != newVis &&
	((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
	SendVisibilityNotify(pParent);

#ifdef COMPOSITE
    /*
     * In redirected drawing case, reset universe to borderSize
     */
    if (pParent->redirectDraw)
    {
	if (miSetRedirectBorderClipProc)
	    (*miSetRedirectBorderClipProc) (pParent, universe);
	REGION_COPY(pScreen, universe, &pParent->borderSize);
    }
#endif

    dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
    dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;

    /*
     * avoid computations when dealing with simple operations
     */

    switch (kind) {
    case VTMap:
    case VTStack:
    case VTUnmap:
	break;
    case VTMove:
	if ((oldVis == newVis) &&
	    ((oldVis == VisibilityFullyObscured) ||
	     (oldVis == VisibilityUnobscured)))
	{
	    pChild = pParent;
	    while (1)
	    {
		if (pChild->viewable)
		{
		    if (pChild->visibility != VisibilityFullyObscured)
		    {
			REGION_TRANSLATE( pScreen, &pChild->borderClip,
						      dx, dy);
			REGION_TRANSLATE( pScreen, &pChild->clipList,
						      dx, dy);
			pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
			if (pScreen->ClipNotify)
			    (* pScreen->ClipNotify) (pChild, dx, dy);

		    }
		    if (pChild->valdata)
		    {
			REGION_NULL(pScreen,
				    &pChild->valdata->after.borderExposed);
			if (HasParentRelativeBorder(pChild))
			{
			    REGION_SUBTRACT(pScreen,
					 &pChild->valdata->after.borderExposed,
					 &pChild->borderClip,
					 &pChild->winSize);
			}
			REGION_NULL(pScreen, &pChild->valdata->after.exposed);
		    }
		    if (pChild->firstChild)
		    {
			pChild = pChild->firstChild;
			continue;
		    }
		}
		while (!pChild->nextSib && (pChild != pParent))
		    pChild = pChild->parent;
		if (pChild == pParent)
		    break;
		pChild = pChild->nextSib;
	    }
	    return;
	}
	/* fall through */
    default:
    	/*
     	 * To calculate exposures correctly, we have to translate the old
     	 * borderClip and clipList regions to the window's new location so there
     	 * is a correspondence between pieces of the new and old clipping regions.
     	 */
    	if (dx || dy) 
    	{
	    /*
	     * We translate the old clipList because that will be exposed or copied
	     * if gravity is right.
	     */
	    REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
	    REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
    	} 
	break;
    case VTBroken:
	REGION_EMPTY (pScreen, &pParent->borderClip);
	REGION_EMPTY (pScreen, &pParent->clipList);
	break;
    }

    borderVisible = pParent->valdata->before.borderVisible;
    resized = pParent->valdata->before.resized;
    REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
    REGION_NULL(pScreen, &pParent->valdata->after.exposed);

    /*
     * Since the borderClip must not be clipped by the children, we do
     * the border exposure first...
     *
     * 'universe' is the window's borderClip. To figure the exposures, remove
     * the area that used to be exposed from the new.
     * This leaves a region of pieces that weren't exposed before.
     */

    if (HasBorder (pParent))
    {
    	if (borderVisible)
    	{
	    /*
	     * when the border changes shape, the old visible portions
	     * of the border will be saved by DIX in borderVisible --
	     * use that region and destroy it
	     */
	    REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
	    REGION_DESTROY( pScreen, borderVisible);
    	}
    	else
    	{
	    REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
    	}

	if (HasParentRelativeBorder(pParent) && (dx || dy))
	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
				  universe,
				  &pParent->winSize);
	else
	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
			       exposed, &pParent->winSize);

    	REGION_COPY( pScreen, &pParent->borderClip, universe);
    
    	/*
     	 * To get the right clipList for the parent, and to make doubly sure
     	 * that no child overlaps the parent's border, we remove the parent's
     	 * border from the universe before proceeding.
     	 */
    
    	REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
    }
    else
    	REGION_COPY( pScreen, &pParent->borderClip, universe);
    
    if ((pChild = pParent->firstChild) && pParent->mapped)
    {
	REGION_NULL(pScreen, &childUniverse);
	REGION_NULL(pScreen, &childUnion);
	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
	{
	    for (; pChild; pChild = pChild->nextSib)
	    {
		if (pChild->viewable)
		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
	    }
	}
	else
	{
	    for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
	    {
		if (pChild->viewable)
		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
	    }
	}
	REGION_VALIDATE( pScreen, &childUnion, &overlap);

	for (pChild = pParent->firstChild;
	     pChild;
	     pChild = pChild->nextSib)
 	{
	    if (pChild->viewable) {
		/*
		 * If the child is viewable, we want to remove its extents
		 * from the current universe, but we only re-clip it if
		 * it's been marked.
		 */
		if (pChild->valdata) {
		    /*
		     * Figure out the new universe from the child's
		     * perspective and recurse.
		     */
		    REGION_INTERSECT( pScreen, &childUniverse,
					    universe,
					    &pChild->borderSize);
		    miComputeClips (pChild, pScreen, &childUniverse, kind,
				    exposed);

		}
		/*
		 * Once the child has been processed, we remove its extents
		 * from the current universe, thus denying its space to any
		 * other sibling.
		 */
		if (overlap)
		    REGION_SUBTRACT( pScreen, universe, universe,
					  &pChild->borderSize);
	    }
	}
	if (!overlap)
	    REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
	REGION_UNINIT( pScreen, &childUnion);
	REGION_UNINIT( pScreen, &childUniverse);
    } /* if any children */

    /*
     * 'universe' now contains the new clipList for the parent window.
     *
     * To figure the exposure of the window we subtract the old clip from the
     * new, just as for the border.
     */

    if (oldVis == VisibilityFullyObscured ||
	oldVis == VisibilityNotViewable)
    {
	REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
    }
    else if (newVis != VisibilityFullyObscured &&
	     newVis != VisibilityNotViewable)
    {
    	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
			       universe, &pParent->clipList);
    }

wBorderWidth is defined as:

#define wBorderWidth(w)		((int) (w)->borderWidth)

drawable.x and drawable.y are the x and y coordinates of the upper-leftfrom corner in the screen of the window drawable (the content). With the following instruction they are incremented by the border width of the current window. borderSize.x1 and borderSize.y1 are now the coordination of the upper-left corner of the window. Similarly borderSize.x2 and borderSize.y2 become the coordinates of the lower-right corner of the window:

    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
    if (dx > 32767)
	dx = 32767;
    borderSize.x2 = dx;
    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
    if (dy > 32767)
	dy = 32767;
    borderSize.y2 = dy;

This info is passed to RECT_IN_REGION in order to find if borderSize is inside universe. In other words it examines the relationship between the whole parent window and the universe, which is the same window's borderClip (referred here as childClip). As seen in the first code snippet of the current section childClip is the intersection between totalClip and pWin->borderSize (see section 7.1). This is what the following miComputeClips() comment describes:

     * Figure out the new visibility of this window.
     * The extent of the universe should be the same as the extent of
     * the borderSize region. If the window is unobscured, this rectangle
     * will be completely inside the universe (the universe will cover it
     * completely). 

RECT_IN_REGION is an encapsulation of miRectIn()

#define RECT_IN_REGION(_pScreen, _pReg, prect) \
    (REGION_SCREEN(_pScreen), miRectIn(_pReg, prect))

miRectIn() returns rgnOUT, rgnIN, or rgnPART (defined in regionstr.h) for the three cases the miRectIn() comment refers:

 *   RectIn(region, rect)
 *   This routine takes a pointer to a region and a pointer to a box
 *   and determines if the box is outside/inside/partly inside the region.

The outcome of miRectIn() determines the new parent visibility (pParent->visibility). If the new visibility differs from the old the parent is notified via SendVisibilityNotify().

As we read in the next comment:

     * 'universe' is the window's borderClip. To figure the exposures, remove
     * the area that used to be exposed from the new.
     * This leaves a region of pieces that weren't exposed before.
'universe' is the current window's borderClip. It was resulted in section 7.1 as:

		REGION_INTERSECT( pScreen, &childClip,
					&totalClip,
 					&pWin->borderSize);

where totalClip is the borderClip of the parent's of the current window clipList merged with the borderClips of all the marked children.

REGION_SUBTRACT, which is resolved to miSubtract() is used as:

	    REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);

to find "region of pieces that weren't exposed before".

The instruction that follows:

	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
			       exposed, &pParent->winSize);
finds the pParent->valdata->after.borderExposed that is used by PaintWindowBorder() to paint the exposed border.

Notice that the previous calculations might result to empty exposed regions. The reason that those calculation take place here are for cases where windows are moved, unmapped, etc. miComputeClips() are NOT called only for window mapping, which is the case in the current flow of section 7.

For the previous calculations the instruction:

   	REGION_COPY( pScreen, &pParent->borderClip, universe);
updates the pParent->borderClip.

The following comment:

     	 * To get the right clipList for the parent, and to make doubly sure
     	 * that no child overlaps the parent's border, we remove the parent's
     	 * border from the universe before proceeding.
signals the start of the process which was similar with the one inside miValidateTree(), just before miComputeClips() was called. Here miComputeClips() will be called recursivelly by itself. At this point, where miComputeClips() handles each child of the original parent of miValidateTree() a recursive miComputeClips() call is necessary to make calculations of the clipping regions of each grandchild (and so on) of the original window:
					    &pChild->borderSize);
		    miComputeClips (pChild, pScreen, &childUniverse, kind,
				    exposed);

As we read in the following comment, the space the current child (grandchild of the original miValidateTree() window) occupies is removed from the 'universe' so that the next time miComputeClips() is called from miValidateTree(), at section 7.1, it finds less space available. In other words it is obscured by the previous sibling which is higher in the stacking order.
		 * Once the child has been processed, we remove its extents
		 * from the current universe, thus denying its space to any
		 * other sibling.

From Xlib programming manual we read on this:

Mapping and Visibility

A newly created window does not immediately appear on the screen. It is an abstract entity that cannot be drawn.

Mapping marks a window as eligible for display. If it is not obsured by siblings of ancestors, it may be visible, and only then can it be drawn to.

XMapWindow() maps a window in its current position in the stacking order, while XMApRaised() places the window at the top of the stacking order of its siblings before mapping it. For a new window never mapped before, these two calls are equivalent, since the initial stacking position of a new window is at top.

You must map a window before you have any chance of seeing it. But several factors are needed:
The window must be mapped with XMapWindow() or related routines.
All of the window's ancestors must be mapped.
The window must not be obscured by visible sibling windows or siblings of ancestors.
The fact of obscured window depends on the stacking order.
The stacking order can be manipulated with XCirculateSubwindows(), XConfigureWindow(), and XRestackWindows().
The request buffer must be flushed by a routine that gets events, with a call to XFlush(), or by a function that requests information from the server.
For complicated reasons, a client must wait for the first Expose event before assuming that its window is visible and drawing into it.

consequence of these rules : unmapping a window (with XUnmapWindow()) erases the window and all its descendants from the screen.

The window configuration and window attributes are maintained when a window is unmapped.

Graphic operations on a window that is not visible or that is unmapped have no effect.

Mapping is done with the XMapWindow() or XMapSubwindows() routines. Unmapping is done with the XUnmapWindow() or XunmapSubwindows() routines.

As the following comment describes:

     * 'universe' now contains the new clipList for the parent window.
     *
     * To figure the exposure of the window we subtract the old clip from the
     * new, just as for the border.
in order to calculate the valdata->after.exposed field as the difference of the two clipLists. The old one is the
&pParent->clipList and the new one is the universe after all child borderSize are subtracted.
    if (oldVis == VisibilityFullyObscured ||
	oldVis == VisibilityNotViewable)
    {
	REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
    }
    else if (newVis != VisibilityFullyObscured &&
	     newVis != VisibilityNotViewable)
    {
    	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
			       universe, &pParent->clipList);
In the current flow of section 7 a window that gets mapped has to be wholly painted. In that case all the universe (the window's borderClip) needs to get painted:
	REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
Recall the miValidateTree(), miComputeClips() are called also in other cases, e.g. when a window gets unmapped and then the following would be used:
    	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
			       universe, &pParent->clipList);

REFERENCES

Xlib function index - Much of the code of miComputeClips() includes conditions that should be considered in other Xlib functions other than XMapWindow(), for instance XUnmapWindow(), XMoveWindow(), etc. This manual includes a list of all Xlib functions.