mivaltree.c revision 4642e01f
1/*
2 * mivaltree.c --
3 *	Functions for recalculating window clip lists. Main function
4 *	is miValidateTree.
5 *
6
7Copyright 1987, 1988, 1989, 1998  The Open Group
8
9Permission to use, copy, modify, distribute, and sell this software and its
10documentation for any purpose is hereby granted without fee, provided that
11the above copyright notice appear in all copies and that both that
12copyright notice and this permission notice appear in supporting
13documentation.
14
15The above copyright notice and this permission notice shall be included in
16all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
21OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of The Open Group shall not be
26used in advertising or otherwise to promote the sale, use or other dealings
27in this Software without prior written authorization from The Open Group.
28
29 *
30 * Copyright 1987, 1988, 1989 by
31 * Digital Equipment Corporation, Maynard, Massachusetts,
32 *
33 *                         All Rights Reserved
34 *
35 * Permission to use, copy, modify, and distribute this software and its
36 * documentation for any purpose and without fee is hereby granted,
37 * provided that the above copyright notice appear in all copies and that
38 * both that copyright notice and this permission notice appear in
39 * supporting documentation, and that the name of Digital not be
40 * used in advertising or publicity pertaining to distribution of the
41 * software without specific, written prior permission.
42 *
43 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
44 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
45 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
47 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
48 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49 * SOFTWARE.
50 *
51 ******************************************************************/
52
53/* The panoramix components contained the following notice */
54/*****************************************************************
55
56Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
57
58Permission is hereby granted, free of charge, to any person obtaining a copy
59of this software and associated documentation files (the "Software"), to deal
60in the Software without restriction, including without limitation the rights
61to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
62copies of the Software.
63
64The above copyright notice and this permission notice shall be included in
65all copies or substantial portions of the Software.
66
67THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
70DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
71BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
72WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
73IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
74
75Except as contained in this notice, the name of Digital Equipment Corporation
76shall not be used in advertising or otherwise to promote the sale, use or other
77dealings in this Software without prior written authorization from Digital
78Equipment Corporation.
79
80******************************************************************/
81
82
83 /*
84  * Aug '86: Susan Angebranndt -- original code
85  * July '87: Adam de Boor -- substantially modified and commented
86  * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible.
87  *             In particular, much improved code for window mapping and
88  *             circulating.
89  *		Bob Scheifler -- avoid miComputeClips for unmapped windows,
90  *				 valdata changes
91  */
92#ifdef HAVE_DIX_CONFIG_H
93#include <dix-config.h>
94#endif
95
96#include    <X11/X.h>
97#include    "scrnintstr.h"
98#include    "validate.h"
99#include    "windowstr.h"
100#include    "mi.h"
101#include    "regionstr.h"
102#include    "mivalidate.h"
103
104#include    "globals.h"
105
106/*
107 * Compute the visibility of a shaped window
108 */
109int
110miShapedWindowIn (ScreenPtr pScreen, RegionPtr universe, RegionPtr bounding,
111                  BoxPtr rect, int x, int y)
112{
113    BoxRec  	box;
114    BoxPtr	boundBox;
115    int		nbox;
116    Bool	someIn, someOut;
117    int 	t, x1, y1, x2, y2;
118
119    nbox = REGION_NUM_RECTS (bounding);
120    boundBox = REGION_RECTS (bounding);
121    someIn = someOut = FALSE;
122    x1 = rect->x1;
123    y1 = rect->y1;
124    x2 = rect->x2;
125    y2 = rect->y2;
126    while (nbox--)
127    {
128	if ((t = boundBox->x1 + x) < x1)
129	    t = x1;
130	box.x1 = t;
131	if ((t = boundBox->y1 + y) < y1)
132	    t = y1;
133	box.y1 = t;
134	if ((t = boundBox->x2 + x) > x2)
135	    t = x2;
136	box.x2 = t;
137	if ((t = boundBox->y2 + y) > y2)
138	    t = y2;
139	box.y2 = t;
140	if (box.x1 > box.x2)
141	    box.x2 = box.x1;
142	if (box.y1 > box.y2)
143	    box.y2 = box.y1;
144	switch (RECT_IN_REGION(pScreen, universe, &box))
145	{
146	case rgnIN:
147	    if (someOut)
148		return rgnPART;
149	    someIn = TRUE;
150	    break;
151	case rgnOUT:
152	    if (someIn)
153		return rgnPART;
154	    someOut = TRUE;
155	    break;
156	default:
157	    return rgnPART;
158	}
159	boundBox++;
160    }
161    if (someIn)
162	return rgnIN;
163    return rgnOUT;
164}
165
166static GetRedirectBorderClipProcPtr	miGetRedirectBorderClipProc;
167static SetRedirectBorderClipProcPtr	miSetRedirectBorderClipProc;
168
169void
170miRegisterRedirectBorderClipProc (SetRedirectBorderClipProcPtr setBorderClip,
171				  GetRedirectBorderClipProcPtr getBorderClip)
172{
173    miSetRedirectBorderClipProc = setBorderClip;
174    miGetRedirectBorderClipProc = getBorderClip;
175}
176
177/*
178 * Manual redirected windows are treated as transparent; they do not obscure
179 * siblings or parent windows
180 */
181
182#ifdef COMPOSITE
183#define TreatAsTransparent(w)	((w)->redirectDraw == RedirectDrawManual)
184#else
185#define TreatAsTransparent(w)	FALSE
186#endif
187
188#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
189				    HasBorder(w) && \
190				    (w)->backgroundState == ParentRelative)
191
192
193/*
194 *-----------------------------------------------------------------------
195 * miComputeClips --
196 *	Recompute the clipList, borderClip, exposed and borderExposed
197 *	regions for pParent and its children. Only viewable windows are
198 *	taken into account.
199 *
200 * Results:
201 *	None.
202 *
203 * Side Effects:
204 *	clipList, borderClip, exposed and borderExposed are altered.
205 *	A VisibilityNotify event may be generated on the parent window.
206 *
207 *-----------------------------------------------------------------------
208 */
209static void
210miComputeClips (
211    WindowPtr	pParent,
212    ScreenPtr	pScreen,
213    RegionPtr	universe,
214    VTKind		kind,
215    RegionPtr		exposed ) /* for intermediate calculations */
216{
217    int			dx,
218			dy;
219    RegionRec		childUniverse;
220    WindowPtr		pChild;
221    int     	  	oldVis, newVis;
222    BoxRec		borderSize;
223    RegionRec		childUnion;
224    Bool		overlap;
225    RegionPtr		borderVisible;
226    Bool		resized;
227    /*
228     * Figure out the new visibility of this window.
229     * The extent of the universe should be the same as the extent of
230     * the borderSize region. If the window is unobscured, this rectangle
231     * will be completely inside the universe (the universe will cover it
232     * completely). If the window is completely obscured, none of the
233     * universe will cover the rectangle.
234     */
235    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
236    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
237    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
238    if (dx > 32767)
239	dx = 32767;
240    borderSize.x2 = dx;
241    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
242    if (dy > 32767)
243	dy = 32767;
244    borderSize.y2 = dy;
245
246#ifdef COMPOSITE
247    /*
248     * In redirected drawing case, reset universe to borderSize
249     */
250    if (pParent->redirectDraw != RedirectDrawNone)
251    {
252	if (miSetRedirectBorderClipProc)
253	{
254	    if (TreatAsTransparent (pParent))
255		REGION_EMPTY (pScreen, universe);
256	    (*miSetRedirectBorderClipProc) (pParent, universe);
257	}
258	REGION_COPY(pScreen, universe, &pParent->borderSize);
259    }
260#endif
261
262    oldVis = pParent->visibility;
263    switch (RECT_IN_REGION( pScreen, universe, &borderSize))
264    {
265	case rgnIN:
266	    newVis = VisibilityUnobscured;
267	    break;
268	case rgnPART:
269	    newVis = VisibilityPartiallyObscured;
270	    {
271		RegionPtr   pBounding;
272
273		if ((pBounding = wBoundingShape (pParent)))
274		{
275		    switch (miShapedWindowIn (pScreen, universe, pBounding,
276					      &borderSize,
277					      pParent->drawable.x,
278 					      pParent->drawable.y))
279		    {
280		    case rgnIN:
281			newVis = VisibilityUnobscured;
282			break;
283		    case rgnOUT:
284			newVis = VisibilityFullyObscured;
285			break;
286		    }
287		}
288	    }
289	    break;
290	default:
291	    newVis = VisibilityFullyObscured;
292	    break;
293    }
294    pParent->visibility = newVis;
295    if (oldVis != newVis &&
296	((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
297	SendVisibilityNotify(pParent);
298
299    dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
300    dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
301
302    /*
303     * avoid computations when dealing with simple operations
304     */
305
306    switch (kind) {
307    case VTMap:
308    case VTStack:
309    case VTUnmap:
310	break;
311    case VTMove:
312	if ((oldVis == newVis) &&
313	    ((oldVis == VisibilityFullyObscured) ||
314	     (oldVis == VisibilityUnobscured)))
315	{
316	    pChild = pParent;
317	    while (1)
318	    {
319		if (pChild->viewable)
320		{
321		    if (pChild->visibility != VisibilityFullyObscured)
322		    {
323			REGION_TRANSLATE( pScreen, &pChild->borderClip,
324						      dx, dy);
325			REGION_TRANSLATE( pScreen, &pChild->clipList,
326						      dx, dy);
327			pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
328			if (pScreen->ClipNotify)
329			    (* pScreen->ClipNotify) (pChild, dx, dy);
330
331		    }
332		    if (pChild->valdata)
333		    {
334			REGION_NULL(pScreen,
335				    &pChild->valdata->after.borderExposed);
336			if (HasParentRelativeBorder(pChild))
337			{
338			    REGION_SUBTRACT(pScreen,
339					 &pChild->valdata->after.borderExposed,
340					 &pChild->borderClip,
341					 &pChild->winSize);
342			}
343			REGION_NULL(pScreen, &pChild->valdata->after.exposed);
344		    }
345		    if (pChild->firstChild)
346		    {
347			pChild = pChild->firstChild;
348			continue;
349		    }
350		}
351		while (!pChild->nextSib && (pChild != pParent))
352		    pChild = pChild->parent;
353		if (pChild == pParent)
354		    break;
355		pChild = pChild->nextSib;
356	    }
357	    return;
358	}
359	/* fall through */
360    default:
361    	/*
362     	 * To calculate exposures correctly, we have to translate the old
363     	 * borderClip and clipList regions to the window's new location so there
364     	 * is a correspondence between pieces of the new and old clipping regions.
365     	 */
366    	if (dx || dy)
367    	{
368	    /*
369	     * We translate the old clipList because that will be exposed or copied
370	     * if gravity is right.
371	     */
372	    REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
373	    REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
374    	}
375	break;
376    case VTBroken:
377	REGION_EMPTY (pScreen, &pParent->borderClip);
378	REGION_EMPTY (pScreen, &pParent->clipList);
379	break;
380    }
381
382    borderVisible = pParent->valdata->before.borderVisible;
383    resized = pParent->valdata->before.resized;
384    REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
385    REGION_NULL(pScreen, &pParent->valdata->after.exposed);
386
387    /*
388     * Since the borderClip must not be clipped by the children, we do
389     * the border exposure first...
390     *
391     * 'universe' is the window's borderClip. To figure the exposures, remove
392     * the area that used to be exposed from the new.
393     * This leaves a region of pieces that weren't exposed before.
394     */
395
396    if (HasBorder (pParent))
397    {
398    	if (borderVisible)
399    	{
400	    /*
401	     * when the border changes shape, the old visible portions
402	     * of the border will be saved by DIX in borderVisible --
403	     * use that region and destroy it
404	     */
405	    REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
406	    REGION_DESTROY( pScreen, borderVisible);
407    	}
408    	else
409    	{
410	    REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
411    	}
412	if (HasParentRelativeBorder(pParent) && (dx || dy))
413	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
414				  universe,
415				  &pParent->winSize);
416	else
417	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
418			       exposed, &pParent->winSize);
419
420    	REGION_COPY( pScreen, &pParent->borderClip, universe);
421
422    	/*
423     	 * To get the right clipList for the parent, and to make doubly sure
424     	 * that no child overlaps the parent's border, we remove the parent's
425     	 * border from the universe before proceeding.
426     	 */
427
428    	REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
429    }
430    else
431    	REGION_COPY( pScreen, &pParent->borderClip, universe);
432
433    if ((pChild = pParent->firstChild) && pParent->mapped)
434    {
435	REGION_NULL(pScreen, &childUniverse);
436	REGION_NULL(pScreen, &childUnion);
437	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
438	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
439	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
440	{
441	    for (; pChild; pChild = pChild->nextSib)
442	    {
443		if (pChild->viewable && !TreatAsTransparent(pChild))
444		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
445	    }
446	}
447	else
448	{
449	    for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
450	    {
451		if (pChild->viewable && !TreatAsTransparent(pChild))
452		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
453	    }
454	}
455	REGION_VALIDATE( pScreen, &childUnion, &overlap);
456
457	for (pChild = pParent->firstChild;
458	     pChild;
459	     pChild = pChild->nextSib)
460 	{
461	    if (pChild->viewable) {
462		/*
463		 * If the child is viewable, we want to remove its extents
464		 * from the current universe, but we only re-clip it if
465		 * it's been marked.
466		 */
467		if (pChild->valdata) {
468		    /*
469		     * Figure out the new universe from the child's
470		     * perspective and recurse.
471		     */
472		    REGION_INTERSECT( pScreen, &childUniverse,
473					    universe,
474					    &pChild->borderSize);
475		    miComputeClips (pChild, pScreen, &childUniverse, kind,
476				    exposed);
477		}
478		/*
479		 * Once the child has been processed, we remove its extents
480		 * from the current universe, thus denying its space to any
481		 * other sibling.
482		 */
483		if (overlap && !TreatAsTransparent (pChild))
484		    REGION_SUBTRACT( pScreen, universe, universe,
485					  &pChild->borderSize);
486	    }
487	}
488	if (!overlap)
489	    REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
490	REGION_UNINIT( pScreen, &childUnion);
491	REGION_UNINIT( pScreen, &childUniverse);
492    } /* if any children */
493
494    /*
495     * 'universe' now contains the new clipList for the parent window.
496     *
497     * To figure the exposure of the window we subtract the old clip from the
498     * new, just as for the border.
499     */
500
501    if (oldVis == VisibilityFullyObscured ||
502	oldVis == VisibilityNotViewable)
503    {
504	REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
505    }
506    else if (newVis != VisibilityFullyObscured &&
507	     newVis != VisibilityNotViewable)
508    {
509    	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
510			       universe, &pParent->clipList);
511    }
512
513    /* HACK ALERT - copying contents of regions, instead of regions */
514    {
515	RegionRec   tmp;
516
517	tmp = pParent->clipList;
518	pParent->clipList = *universe;
519	*universe = tmp;
520    }
521
522#ifdef NOTDEF
523    REGION_COPY( pScreen, &pParent->clipList, universe);
524#endif
525
526    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
527
528    if (pScreen->ClipNotify)
529	(* pScreen->ClipNotify) (pParent, dx, dy);
530}
531
532static void
533miTreeObscured(
534    WindowPtr pParent )
535{
536    WindowPtr 	pChild;
537    int    	oldVis;
538
539    pChild = pParent;
540    while (1)
541    {
542	if (pChild->viewable)
543	{
544	    oldVis = pChild->visibility;
545	    if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
546		((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
547		SendVisibilityNotify(pChild);
548	    if (pChild->firstChild)
549	    {
550		pChild = pChild->firstChild;
551		continue;
552	    }
553	}
554	while (!pChild->nextSib && (pChild != pParent))
555	    pChild = pChild->parent;
556	if (pChild == pParent)
557	    break;
558	pChild = pChild->nextSib;
559    }
560}
561
562/*
563 *-----------------------------------------------------------------------
564 * miValidateTree --
565 *	Recomputes the clip list for pParent and all its inferiors.
566 *
567 * Results:
568 *	Always returns 1.
569 *
570 * Side Effects:
571 *	The clipList, borderClip, exposed, and borderExposed regions for
572 *	each marked window are altered.
573 *
574 * Notes:
575 *	This routine assumes that all affected windows have been marked
576 *	(valdata created) and their winSize and borderSize regions
577 *	adjusted to correspond to their new positions. The borderClip and
578 *	clipList regions should not have been touched.
579 *
580 *	The top-most level is treated differently from all lower levels
581 *	because pParent is unchanged. For the top level, we merge the
582 *	regions taken up by the marked children back into the clipList
583 *	for pParent, thus forming a region from which the marked children
584 *	can claim their areas. For lower levels, where the old clipList
585 *	and borderClip are invalid, we can't do this and have to do the
586 *	extra operations done in miComputeClips, but this is much faster
587 *	e.g. when only one child has moved...
588 *
589 *-----------------------------------------------------------------------
590 */
591/*ARGSUSED*/
592int
593miValidateTree (
594    WindowPtr		pParent,    /* Parent to validate */
595    WindowPtr		pChild,     /* First child of pParent that was
596				     * affected */
597    VTKind		kind        /* What kind of configuration caused call */
598    )
599{
600    RegionRec	  	totalClip;  /* Total clipping region available to
601				     * the marked children. pParent's clipList
602				     * merged with the borderClips of all
603				     * the marked children. */
604    RegionRec	  	childClip;  /* The new borderClip for the current
605				     * child */
606    RegionRec		childUnion; /* the space covered by borderSize for
607				     * all marked children */
608    RegionRec		exposed;    /* For intermediate calculations */
609    ScreenPtr		pScreen;
610    WindowPtr		pWin;
611    Bool		overlap;
612    int			viewvals;
613    Bool		forward;
614
615    pScreen = pParent->drawable.pScreen;
616    if (pChild == NullWindow)
617	pChild = pParent->firstChild;
618
619    REGION_NULL(pScreen, &childClip);
620    REGION_NULL(pScreen, &exposed);
621
622    /*
623     * compute the area of the parent window occupied
624     * by the marked children + the parent itself.  This
625     * is the area which can be divied up among the marked
626     * children in their new configuration.
627     */
628    REGION_NULL(pScreen, &totalClip);
629    viewvals = 0;
630    if (REGION_BROKEN (pScreen, &pParent->clipList) &&
631	!REGION_BROKEN (pScreen, &pParent->borderClip))
632    {
633	kind = VTBroken;
634	/*
635	 * When rebuilding clip lists after out of memory,
636	 * assume everything is busted.
637	 */
638	forward = TRUE;
639	REGION_COPY (pScreen, &totalClip, &pParent->borderClip);
640	REGION_INTERSECT (pScreen, &totalClip, &totalClip, &pParent->winSize);
641
642	for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib)
643	{
644	    if (pWin->viewable && !TreatAsTransparent (pWin))
645		REGION_SUBTRACT (pScreen, &totalClip, &totalClip, &pWin->borderSize);
646	}
647	for (pWin = pChild; pWin; pWin = pWin->nextSib)
648	    if (pWin->valdata && pWin->viewable)
649		viewvals++;
650
651	REGION_EMPTY (pScreen, &pParent->clipList);
652    }
653    else
654    {
655	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
656	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
657	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
658	{
659	    forward = TRUE;
660	    for (pWin = pChild; pWin; pWin = pWin->nextSib)
661	    {
662		if (pWin->valdata)
663		{
664		    RegionPtr	pBorderClip = &pWin->borderClip;
665#ifdef COMPOSITE
666		    if (pWin->redirectDraw != RedirectDrawNone && miGetRedirectBorderClipProc)
667			pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
668#endif
669		    REGION_APPEND( pScreen, &totalClip, pBorderClip );
670		    if (pWin->viewable)
671			viewvals++;
672		}
673	    }
674	}
675	else
676	{
677	    forward = FALSE;
678	    pWin = pParent->lastChild;
679	    while (1)
680	    {
681		if (pWin->valdata)
682		{
683		    RegionPtr	pBorderClip = &pWin->borderClip;
684#ifdef COMPOSITE
685		    if (pWin->redirectDraw != RedirectDrawNone && miGetRedirectBorderClipProc)
686			pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
687#endif
688		    REGION_APPEND( pScreen, &totalClip, pBorderClip );
689		    if (pWin->viewable)
690			viewvals++;
691		}
692		if (pWin == pChild)
693		    break;
694		pWin = pWin->prevSib;
695	    }
696	}
697	REGION_VALIDATE( pScreen, &totalClip, &overlap);
698    }
699
700    /*
701     * Now go through the children of the root and figure their new
702     * borderClips from the totalClip, passing that off to miComputeClips
703     * to handle recursively. Once that's done, we remove the child
704     * from the totalClip to clip any siblings below it.
705     */
706
707    overlap = TRUE;
708    if (kind != VTStack)
709    {
710	REGION_UNION( pScreen, &totalClip, &totalClip, &pParent->clipList);
711	if (viewvals > 1)
712	{
713	    /*
714	     * precompute childUnion to discover whether any of them
715	     * overlap.  This seems redundant, but performance studies
716	     * have demonstrated that the cost of this loop is
717	     * lower than the cost of multiple Subtracts in the
718	     * loop below.
719	     */
720	    REGION_NULL(pScreen, &childUnion);
721	    if (forward)
722	    {
723		for (pWin = pChild; pWin; pWin = pWin->nextSib)
724		    if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin))
725			REGION_APPEND( pScreen, &childUnion,
726						   &pWin->borderSize);
727	    }
728	    else
729	    {
730		pWin = pParent->lastChild;
731		while (1)
732		{
733		    if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin))
734			REGION_APPEND( pScreen, &childUnion,
735						   &pWin->borderSize);
736		    if (pWin == pChild)
737			break;
738		    pWin = pWin->prevSib;
739		}
740	    }
741	    REGION_VALIDATE(pScreen, &childUnion, &overlap);
742	    if (overlap)
743		REGION_UNINIT(pScreen, &childUnion);
744	}
745    }
746
747    for (pWin = pChild;
748	 pWin != NullWindow;
749	 pWin = pWin->nextSib)
750    {
751	if (pWin->viewable) {
752	    if (pWin->valdata) {
753		REGION_INTERSECT( pScreen, &childClip,
754					&totalClip,
755 					&pWin->borderSize);
756		miComputeClips (pWin, pScreen, &childClip, kind, &exposed);
757		if (overlap && !TreatAsTransparent (pWin))
758		{
759		    REGION_SUBTRACT( pScreen, &totalClip,
760				       	   &totalClip,
761				       	   &pWin->borderSize);
762		}
763	    } else if (pWin->visibility == VisibilityNotViewable) {
764		miTreeObscured(pWin);
765	    }
766	} else {
767	    if (pWin->valdata) {
768		REGION_EMPTY( pScreen, &pWin->clipList);
769		if (pScreen->ClipNotify)
770		    (* pScreen->ClipNotify) (pWin, 0, 0);
771		REGION_EMPTY( pScreen, &pWin->borderClip);
772		pWin->valdata = (ValidatePtr)NULL;
773	    }
774	}
775    }
776
777    REGION_UNINIT( pScreen, &childClip);
778    if (!overlap)
779    {
780	REGION_SUBTRACT(pScreen, &totalClip, &totalClip, &childUnion);
781	REGION_UNINIT(pScreen, &childUnion);
782    }
783
784    REGION_NULL(pScreen, &pParent->valdata->after.exposed);
785    REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
786
787    /*
788     * each case below is responsible for updating the
789     * clipList and serial number for the parent window
790     */
791
792    switch (kind) {
793    case VTStack:
794	break;
795    default:
796	/*
797	 * totalClip contains the new clipList for the parent. Figure out
798	 * exposures and obscures as per miComputeClips and reset the parent's
799	 * clipList.
800	 */
801	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
802			       &totalClip, &pParent->clipList);
803	/* fall through */
804    case VTMap:
805	REGION_COPY( pScreen, &pParent->clipList, &totalClip);
806	pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
807	break;
808    }
809
810    REGION_UNINIT( pScreen, &totalClip);
811    REGION_UNINIT( pScreen, &exposed);
812    if (pScreen->ClipNotify)
813	(*pScreen->ClipNotify) (pParent, 0, 0);
814    return (1);
815}
816