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 (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 = RegionNumRects (bounding);
120    boundBox = RegionRects (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 (RegionContainsRect(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		RegionEmpty(universe);
256	    (*miSetRedirectBorderClipProc) (pParent, universe);
257	}
258	RegionCopy(universe, &pParent->borderSize);
259    }
260#endif
261
262    oldVis = pParent->visibility;
263    switch (RegionContainsRect(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 (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			RegionTranslate(&pChild->borderClip,
324						      dx, dy);
325			RegionTranslate(&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			RegionNull(&pChild->valdata->after.borderExposed);
335			if (HasParentRelativeBorder(pChild))
336			{
337			    RegionSubtract(&pChild->valdata->after.borderExposed,
338					   &pChild->borderClip,
339					   &pChild->winSize);
340			}
341			RegionNull(&pChild->valdata->after.exposed);
342		    }
343		    if (pChild->firstChild)
344		    {
345			pChild = pChild->firstChild;
346			continue;
347		    }
348		}
349		while (!pChild->nextSib && (pChild != pParent))
350		    pChild = pChild->parent;
351		if (pChild == pParent)
352		    break;
353		pChild = pChild->nextSib;
354	    }
355	    return;
356	}
357	/* fall through */
358    default:
359    	/*
360     	 * To calculate exposures correctly, we have to translate the old
361     	 * borderClip and clipList regions to the window's new location so there
362     	 * is a correspondence between pieces of the new and old clipping regions.
363     	 */
364    	if (dx || dy)
365    	{
366	    /*
367	     * We translate the old clipList because that will be exposed or copied
368	     * if gravity is right.
369	     */
370	    RegionTranslate(&pParent->borderClip, dx, dy);
371	    RegionTranslate(&pParent->clipList, dx, dy);
372    	}
373	break;
374    case VTBroken:
375	RegionEmpty(&pParent->borderClip);
376	RegionEmpty(&pParent->clipList);
377	break;
378    }
379
380    borderVisible = pParent->valdata->before.borderVisible;
381    resized = pParent->valdata->before.resized;
382    RegionNull(&pParent->valdata->after.borderExposed);
383    RegionNull(&pParent->valdata->after.exposed);
384
385    /*
386     * Since the borderClip must not be clipped by the children, we do
387     * the border exposure first...
388     *
389     * 'universe' is the window's borderClip. To figure the exposures, remove
390     * the area that used to be exposed from the new.
391     * This leaves a region of pieces that weren't exposed before.
392     */
393
394    if (HasBorder (pParent))
395    {
396    	if (borderVisible)
397    	{
398	    /*
399	     * when the border changes shape, the old visible portions
400	     * of the border will be saved by DIX in borderVisible --
401	     * use that region and destroy it
402	     */
403	    RegionSubtract(exposed, universe, borderVisible);
404	    RegionDestroy(borderVisible);
405    	}
406    	else
407    	{
408	    RegionSubtract(exposed, universe, &pParent->borderClip);
409    	}
410	if (HasParentRelativeBorder(pParent) && (dx || dy))
411	    RegionSubtract(&pParent->valdata->after.borderExposed,
412				  universe,
413				  &pParent->winSize);
414	else
415	    RegionSubtract(&pParent->valdata->after.borderExposed,
416			       exposed, &pParent->winSize);
417
418	RegionCopy(&pParent->borderClip, universe);
419
420    	/*
421     	 * To get the right clipList for the parent, and to make doubly sure
422     	 * that no child overlaps the parent's border, we remove the parent's
423     	 * border from the universe before proceeding.
424     	 */
425
426	RegionIntersect(universe, universe, &pParent->winSize);
427    }
428    else
429	RegionCopy(&pParent->borderClip, universe);
430
431    if ((pChild = pParent->firstChild) && pParent->mapped)
432    {
433	RegionNull(&childUniverse);
434	RegionNull(&childUnion);
435	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
436	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
437	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
438	{
439	    for (; pChild; pChild = pChild->nextSib)
440	    {
441		if (pChild->viewable && !TreatAsTransparent(pChild))
442		    RegionAppend(&childUnion, &pChild->borderSize);
443	    }
444	}
445	else
446	{
447	    for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
448	    {
449		if (pChild->viewable && !TreatAsTransparent(pChild))
450		    RegionAppend(&childUnion, &pChild->borderSize);
451	    }
452	}
453	RegionValidate(&childUnion, &overlap);
454
455	for (pChild = pParent->firstChild;
456	     pChild;
457	     pChild = pChild->nextSib)
458 	{
459	    if (pChild->viewable) {
460		/*
461		 * If the child is viewable, we want to remove its extents
462		 * from the current universe, but we only re-clip it if
463		 * it's been marked.
464		 */
465		if (pChild->valdata) {
466		    /*
467		     * Figure out the new universe from the child's
468		     * perspective and recurse.
469		     */
470		    RegionIntersect(&childUniverse,
471					    universe,
472					    &pChild->borderSize);
473		    miComputeClips (pChild, pScreen, &childUniverse, kind,
474				    exposed);
475		}
476		/*
477		 * Once the child has been processed, we remove its extents
478		 * from the current universe, thus denying its space to any
479		 * other sibling.
480		 */
481		if (overlap && !TreatAsTransparent (pChild))
482		    RegionSubtract(universe, universe,
483					  &pChild->borderSize);
484	    }
485	}
486	if (!overlap)
487	    RegionSubtract(universe, universe, &childUnion);
488	RegionUninit(&childUnion);
489	RegionUninit(&childUniverse);
490    } /* if any children */
491
492    /*
493     * 'universe' now contains the new clipList for the parent window.
494     *
495     * To figure the exposure of the window we subtract the old clip from the
496     * new, just as for the border.
497     */
498
499    if (oldVis == VisibilityFullyObscured ||
500	oldVis == VisibilityNotViewable)
501    {
502	RegionCopy(&pParent->valdata->after.exposed, universe);
503    }
504    else if (newVis != VisibilityFullyObscured &&
505	     newVis != VisibilityNotViewable)
506    {
507	RegionSubtract(&pParent->valdata->after.exposed,
508			       universe, &pParent->clipList);
509    }
510
511    /* HACK ALERT - copying contents of regions, instead of regions */
512    {
513	RegionRec   tmp;
514
515	tmp = pParent->clipList;
516	pParent->clipList = *universe;
517	*universe = tmp;
518    }
519
520#ifdef NOTDEF
521    RegionCopy(&pParent->clipList, universe);
522#endif
523
524    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
525
526    if (pScreen->ClipNotify)
527	(* pScreen->ClipNotify) (pParent, dx, dy);
528}
529
530static void
531miTreeObscured(
532    WindowPtr pParent )
533{
534    WindowPtr 	pChild;
535    int    	oldVis;
536
537    pChild = pParent;
538    while (1)
539    {
540	if (pChild->viewable)
541	{
542	    oldVis = pChild->visibility;
543	    if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
544		((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
545		SendVisibilityNotify(pChild);
546	    if (pChild->firstChild)
547	    {
548		pChild = pChild->firstChild;
549		continue;
550	    }
551	}
552	while (!pChild->nextSib && (pChild != pParent))
553	    pChild = pChild->parent;
554	if (pChild == pParent)
555	    break;
556	pChild = pChild->nextSib;
557    }
558}
559
560/*
561 *-----------------------------------------------------------------------
562 * miValidateTree --
563 *	Recomputes the clip list for pParent and all its inferiors.
564 *
565 * Results:
566 *	Always returns 1.
567 *
568 * Side Effects:
569 *	The clipList, borderClip, exposed, and borderExposed regions for
570 *	each marked window are altered.
571 *
572 * Notes:
573 *	This routine assumes that all affected windows have been marked
574 *	(valdata created) and their winSize and borderSize regions
575 *	adjusted to correspond to their new positions. The borderClip and
576 *	clipList regions should not have been touched.
577 *
578 *	The top-most level is treated differently from all lower levels
579 *	because pParent is unchanged. For the top level, we merge the
580 *	regions taken up by the marked children back into the clipList
581 *	for pParent, thus forming a region from which the marked children
582 *	can claim their areas. For lower levels, where the old clipList
583 *	and borderClip are invalid, we can't do this and have to do the
584 *	extra operations done in miComputeClips, but this is much faster
585 *	e.g. when only one child has moved...
586 *
587 *-----------------------------------------------------------------------
588 */
589/*ARGSUSED*/
590int
591miValidateTree (
592    WindowPtr		pParent,    /* Parent to validate */
593    WindowPtr		pChild,     /* First child of pParent that was
594				     * affected */
595    VTKind		kind        /* What kind of configuration caused call */
596    )
597{
598    RegionRec	  	totalClip;  /* Total clipping region available to
599				     * the marked children. pParent's clipList
600				     * merged with the borderClips of all
601				     * the marked children. */
602    RegionRec	  	childClip;  /* The new borderClip for the current
603				     * child */
604    RegionRec		childUnion; /* the space covered by borderSize for
605				     * all marked children */
606    RegionRec		exposed;    /* For intermediate calculations */
607    ScreenPtr		pScreen;
608    WindowPtr		pWin;
609    Bool		overlap;
610    int			viewvals;
611    Bool		forward;
612
613    pScreen = pParent->drawable.pScreen;
614    if (pChild == NullWindow)
615	pChild = pParent->firstChild;
616
617    RegionNull(&childClip);
618    RegionNull(&exposed);
619
620    /*
621     * compute the area of the parent window occupied
622     * by the marked children + the parent itself.  This
623     * is the area which can be divied up among the marked
624     * children in their new configuration.
625     */
626    RegionNull(&totalClip);
627    viewvals = 0;
628    if (RegionBroken(&pParent->clipList) &&
629	!RegionBroken(&pParent->borderClip))
630    {
631	kind = VTBroken;
632	/*
633	 * When rebuilding clip lists after out of memory,
634	 * assume everything is busted.
635	 */
636	forward = TRUE;
637	RegionCopy(&totalClip, &pParent->borderClip);
638	RegionIntersect(&totalClip, &totalClip, &pParent->winSize);
639
640	for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib)
641	{
642	    if (pWin->viewable && !TreatAsTransparent (pWin))
643		RegionSubtract(&totalClip, &totalClip, &pWin->borderSize);
644	}
645	for (pWin = pChild; pWin; pWin = pWin->nextSib)
646	    if (pWin->valdata && pWin->viewable)
647		viewvals++;
648
649	RegionEmpty(&pParent->clipList);
650    }
651    else
652    {
653	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
654	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
655	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
656	{
657	    forward = TRUE;
658	    for (pWin = pChild; pWin; pWin = pWin->nextSib)
659	    {
660		if (pWin->valdata)
661		{
662		    RegionPtr	pBorderClip = &pWin->borderClip;
663#ifdef COMPOSITE
664		    if (pWin->redirectDraw != RedirectDrawNone && miGetRedirectBorderClipProc)
665			pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
666#endif
667		    RegionAppend(&totalClip, pBorderClip );
668		    if (pWin->viewable)
669			viewvals++;
670		}
671	    }
672	}
673	else
674	{
675	    forward = FALSE;
676	    pWin = pParent->lastChild;
677	    while (1)
678	    {
679		if (pWin->valdata)
680		{
681		    RegionPtr	pBorderClip = &pWin->borderClip;
682#ifdef COMPOSITE
683		    if (pWin->redirectDraw != RedirectDrawNone && miGetRedirectBorderClipProc)
684			pBorderClip = (*miGetRedirectBorderClipProc)(pWin);
685#endif
686		    RegionAppend(&totalClip, pBorderClip );
687		    if (pWin->viewable)
688			viewvals++;
689		}
690		if (pWin == pChild)
691		    break;
692		pWin = pWin->prevSib;
693	    }
694	}
695	RegionValidate(&totalClip, &overlap);
696    }
697
698    /*
699     * Now go through the children of the root and figure their new
700     * borderClips from the totalClip, passing that off to miComputeClips
701     * to handle recursively. Once that's done, we remove the child
702     * from the totalClip to clip any siblings below it.
703     */
704
705    overlap = TRUE;
706    if (kind != VTStack)
707    {
708	RegionUnion(&totalClip, &totalClip, &pParent->clipList);
709	if (viewvals > 1)
710	{
711	    /*
712	     * precompute childUnion to discover whether any of them
713	     * overlap.  This seems redundant, but performance studies
714	     * have demonstrated that the cost of this loop is
715	     * lower than the cost of multiple Subtracts in the
716	     * loop below.
717	     */
718	    RegionNull(&childUnion);
719	    if (forward)
720	    {
721		for (pWin = pChild; pWin; pWin = pWin->nextSib)
722		    if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin))
723			RegionAppend(&childUnion,
724						   &pWin->borderSize);
725	    }
726	    else
727	    {
728		pWin = pParent->lastChild;
729		while (1)
730		{
731		    if (pWin->valdata && pWin->viewable && !TreatAsTransparent (pWin))
732			RegionAppend(&childUnion,
733						   &pWin->borderSize);
734		    if (pWin == pChild)
735			break;
736		    pWin = pWin->prevSib;
737		}
738	    }
739	    RegionValidate(&childUnion, &overlap);
740	    if (overlap)
741		RegionUninit(&childUnion);
742	}
743    }
744
745    for (pWin = pChild;
746	 pWin != NullWindow;
747	 pWin = pWin->nextSib)
748    {
749	if (pWin->viewable) {
750	    if (pWin->valdata) {
751		RegionIntersect(&childClip,
752					&totalClip,
753 					&pWin->borderSize);
754		miComputeClips (pWin, pScreen, &childClip, kind, &exposed);
755		if (overlap && !TreatAsTransparent (pWin))
756		{
757		    RegionSubtract(&totalClip,
758				       	   &totalClip,
759				       	   &pWin->borderSize);
760		}
761	    } else if (pWin->visibility == VisibilityNotViewable) {
762		miTreeObscured(pWin);
763	    }
764	} else {
765	    if (pWin->valdata) {
766		RegionEmpty(&pWin->clipList);
767		if (pScreen->ClipNotify)
768		    (* pScreen->ClipNotify) (pWin, 0, 0);
769		RegionEmpty(&pWin->borderClip);
770		pWin->valdata = NULL;
771	    }
772	}
773    }
774
775    RegionUninit(&childClip);
776    if (!overlap)
777    {
778	RegionSubtract(&totalClip, &totalClip, &childUnion);
779	RegionUninit(&childUnion);
780    }
781
782    RegionNull(&pParent->valdata->after.exposed);
783    RegionNull(&pParent->valdata->after.borderExposed);
784
785    /*
786     * each case below is responsible for updating the
787     * clipList and serial number for the parent window
788     */
789
790    switch (kind) {
791    case VTStack:
792	break;
793    default:
794	/*
795	 * totalClip contains the new clipList for the parent. Figure out
796	 * exposures and obscures as per miComputeClips and reset the parent's
797	 * clipList.
798	 */
799	RegionSubtract(&pParent->valdata->after.exposed,
800			       &totalClip, &pParent->clipList);
801	/* fall through */
802    case VTMap:
803	RegionCopy(&pParent->clipList, &totalClip);
804	pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
805	break;
806    }
807
808    RegionUninit(&totalClip);
809    RegionUninit(&exposed);
810    if (pScreen->ClipNotify)
811	(*pScreen->ClipNotify) (pParent, 0, 0);
812    return 1;
813}
814