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  * Aug '86: Susan Angebranndt -- original code
84  * July '87: Adam de Boor -- substantially modified and commented
85  * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible.
86  *             In particular, much improved code for window mapping and
87  *             circulating.
88  *             Bob Scheifler -- avoid miComputeClips for unmapped windows,
89  *                              valdata changes
90  */
91#ifdef HAVE_DIX_CONFIG_H
92#include <dix-config.h>
93#endif
94
95#include    <X11/X.h>
96#include    "scrnintstr.h"
97#include    "validate.h"
98#include    "windowstr.h"
99#include    "mi.h"
100#include    "regionstr.h"
101#include    "mivalidate.h"
102#include    "globals.h"
103#ifdef COMPOSITE
104#include    "compint.h"
105#endif
106
107/*
108 * Compute the visibility of a shaped window
109 */
110int
111miShapedWindowIn(RegionPtr universe, RegionPtr bounding,
112                 BoxPtr rect, int x, int y)
113{
114    BoxRec box;
115    BoxPtr boundBox;
116    int nbox;
117    Bool someIn, someOut;
118    int t, x1, y1, x2, y2;
119
120    nbox = RegionNumRects(bounding);
121    boundBox = RegionRects(bounding);
122    someIn = someOut = FALSE;
123    x1 = rect->x1;
124    y1 = rect->y1;
125    x2 = rect->x2;
126    y2 = rect->y2;
127    while (nbox--) {
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        case rgnIN:
146            if (someOut)
147                return rgnPART;
148            someIn = TRUE;
149            break;
150        case rgnOUT:
151            if (someIn)
152                return rgnPART;
153            someOut = TRUE;
154            break;
155        default:
156            return rgnPART;
157        }
158        boundBox++;
159    }
160    if (someIn)
161        return rgnIN;
162    return rgnOUT;
163}
164
165/*
166 * Manual redirected windows are treated as transparent; they do not obscure
167 * siblings or parent windows
168 */
169
170#ifdef COMPOSITE
171#define TreatAsTransparent(w)	((w)->redirectDraw == RedirectDrawManual)
172#else
173#define TreatAsTransparent(w)	FALSE
174#endif
175
176#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
177				    HasBorder(w) && \
178				    (w)->backgroundState == ParentRelative)
179
180/*
181 *-----------------------------------------------------------------------
182 * miComputeClips --
183 *	Recompute the clipList, borderClip, exposed and borderExposed
184 *	regions for pParent and its children. Only viewable windows are
185 *	taken into account.
186 *
187 * Results:
188 *	None.
189 *
190 * Side Effects:
191 *	clipList, borderClip, exposed and borderExposed are altered.
192 *	A VisibilityNotify event may be generated on the parent window.
193 *
194 *-----------------------------------------------------------------------
195 */
196static void
197miComputeClips(WindowPtr pParent,
198               ScreenPtr pScreen,
199               RegionPtr universe, VTKind kind, RegionPtr exposed)
200{                               /* for intermediate calculations */
201    int dx, dy;
202    RegionRec childUniverse;
203    WindowPtr pChild;
204    int oldVis, newVis;
205    BoxRec borderSize;
206    RegionRec childUnion;
207    Bool overlap;
208    RegionPtr borderVisible;
209
210    /*
211     * Figure out the new visibility of this window.
212     * The extent of the universe should be the same as the extent of
213     * the borderSize region. If the window is unobscured, this rectangle
214     * will be completely inside the universe (the universe will cover it
215     * completely). If the window is completely obscured, none of the
216     * universe will cover the rectangle.
217     */
218    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
219    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
220    dx = (int) pParent->drawable.x + (int) pParent->drawable.width +
221        wBorderWidth(pParent);
222    if (dx > 32767)
223        dx = 32767;
224    borderSize.x2 = dx;
225    dy = (int) pParent->drawable.y + (int) pParent->drawable.height +
226        wBorderWidth(pParent);
227    if (dy > 32767)
228        dy = 32767;
229    borderSize.y2 = dy;
230
231#ifdef COMPOSITE
232    /*
233     * In redirected drawing case, reset universe to borderSize
234     */
235    if (pParent->redirectDraw != RedirectDrawNone) {
236        if (TreatAsTransparent(pParent))
237            RegionEmpty(universe);
238        compSetRedirectBorderClip (pParent, universe);
239        RegionCopy(universe, &pParent->borderSize);
240    }
241#endif
242
243    oldVis = pParent->visibility;
244    switch (RegionContainsRect(universe, &borderSize)) {
245    case rgnIN:
246        newVis = VisibilityUnobscured;
247        break;
248    case rgnPART:
249        newVis = VisibilityPartiallyObscured;
250        {
251            RegionPtr pBounding;
252
253            if ((pBounding = wBoundingShape(pParent))) {
254                switch (miShapedWindowIn(universe, pBounding,
255                                         &borderSize,
256                                         pParent->drawable.x,
257                                         pParent->drawable.y)) {
258                case rgnIN:
259                    newVis = VisibilityUnobscured;
260                    break;
261                case rgnOUT:
262                    newVis = VisibilityFullyObscured;
263                    break;
264                }
265            }
266        }
267        break;
268    default:
269        newVis = VisibilityFullyObscured;
270        break;
271    }
272    pParent->visibility = newVis;
273    if (oldVis != newVis &&
274        ((pParent->
275          eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
276        SendVisibilityNotify(pParent);
277
278    dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
279    dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
280
281    /*
282     * avoid computations when dealing with simple operations
283     */
284
285    switch (kind) {
286    case VTMap:
287    case VTStack:
288    case VTUnmap:
289        break;
290    case VTMove:
291        if ((oldVis == newVis) &&
292            ((oldVis == VisibilityFullyObscured) ||
293             (oldVis == VisibilityUnobscured))) {
294            pChild = pParent;
295            while (1) {
296                if (pChild->viewable) {
297                    if (pChild->visibility != VisibilityFullyObscured) {
298                        RegionTranslate(&pChild->borderClip, dx, dy);
299                        RegionTranslate(&pChild->clipList, dx, dy);
300                        pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
301                        if (pScreen->ClipNotify)
302                            (*pScreen->ClipNotify) (pChild, dx, dy);
303
304                    }
305                    if (pChild->valdata) {
306                        RegionNull(&pChild->valdata->after.borderExposed);
307                        if (HasParentRelativeBorder(pChild)) {
308                            RegionSubtract(&pChild->valdata->after.
309                                           borderExposed, &pChild->borderClip,
310                                           &pChild->winSize);
311                        }
312                        RegionNull(&pChild->valdata->after.exposed);
313                    }
314                    if (pChild->firstChild) {
315                        pChild = pChild->firstChild;
316                        continue;
317                    }
318                }
319                while (!pChild->nextSib && (pChild != pParent))
320                    pChild = pChild->parent;
321                if (pChild == pParent)
322                    break;
323                pChild = pChild->nextSib;
324            }
325            return;
326        }
327        /* fall through */
328    default:
329        /*
330         * To calculate exposures correctly, we have to translate the old
331         * borderClip and clipList regions to the window's new location so there
332         * is a correspondence between pieces of the new and old clipping regions.
333         */
334        if (dx || dy) {
335            /*
336             * We translate the old clipList because that will be exposed or copied
337             * if gravity is right.
338             */
339            RegionTranslate(&pParent->borderClip, dx, dy);
340            RegionTranslate(&pParent->clipList, dx, dy);
341        }
342        break;
343    case VTBroken:
344        RegionEmpty(&pParent->borderClip);
345        RegionEmpty(&pParent->clipList);
346        break;
347    }
348
349    borderVisible = pParent->valdata->before.borderVisible;
350    RegionNull(&pParent->valdata->after.borderExposed);
351    RegionNull(&pParent->valdata->after.exposed);
352
353    /*
354     * Since the borderClip must not be clipped by the children, we do
355     * the border exposure first...
356     *
357     * 'universe' is the window's borderClip. To figure the exposures, remove
358     * the area that used to be exposed from the new.
359     * This leaves a region of pieces that weren't exposed before.
360     */
361
362    if (HasBorder(pParent)) {
363        if (borderVisible) {
364            /*
365             * when the border changes shape, the old visible portions
366             * of the border will be saved by DIX in borderVisible --
367             * use that region and destroy it
368             */
369            RegionSubtract(exposed, universe, borderVisible);
370            RegionDestroy(borderVisible);
371        }
372        else {
373            RegionSubtract(exposed, universe, &pParent->borderClip);
374        }
375        if (HasParentRelativeBorder(pParent) && (dx || dy))
376            RegionSubtract(&pParent->valdata->after.borderExposed,
377                           universe, &pParent->winSize);
378        else
379            RegionSubtract(&pParent->valdata->after.borderExposed,
380                           exposed, &pParent->winSize);
381
382        RegionCopy(&pParent->borderClip, universe);
383
384        /*
385         * To get the right clipList for the parent, and to make doubly sure
386         * that no child overlaps the parent's border, we remove the parent's
387         * border from the universe before proceeding.
388         */
389
390        RegionIntersect(universe, universe, &pParent->winSize);
391    }
392    else
393        RegionCopy(&pParent->borderClip, universe);
394
395    if ((pChild = pParent->firstChild) && pParent->mapped) {
396        RegionNull(&childUniverse);
397        RegionNull(&childUnion);
398        if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
399            ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
400             (pChild->drawable.x < pParent->lastChild->drawable.x))) {
401            for (; pChild; pChild = pChild->nextSib) {
402                if (pChild->viewable && !TreatAsTransparent(pChild))
403                    RegionAppend(&childUnion, &pChild->borderSize);
404            }
405        }
406        else {
407            for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) {
408                if (pChild->viewable && !TreatAsTransparent(pChild))
409                    RegionAppend(&childUnion, &pChild->borderSize);
410            }
411        }
412        RegionValidate(&childUnion, &overlap);
413
414        for (pChild = pParent->firstChild; pChild; pChild = pChild->nextSib) {
415            if (pChild->viewable) {
416                /*
417                 * If the child is viewable, we want to remove its extents
418                 * from the current universe, but we only re-clip it if
419                 * it's been marked.
420                 */
421                if (pChild->valdata) {
422                    /*
423                     * Figure out the new universe from the child's
424                     * perspective and recurse.
425                     */
426                    RegionIntersect(&childUniverse,
427                                    universe, &pChild->borderSize);
428                    miComputeClips(pChild, pScreen, &childUniverse, kind,
429                                   exposed);
430                }
431                /*
432                 * Once the child has been processed, we remove its extents
433                 * from the current universe, thus denying its space to any
434                 * other sibling.
435                 */
436                if (overlap && !TreatAsTransparent(pChild))
437                    RegionSubtract(universe, universe, &pChild->borderSize);
438            }
439        }
440        if (!overlap)
441            RegionSubtract(universe, universe, &childUnion);
442        RegionUninit(&childUnion);
443        RegionUninit(&childUniverse);
444    }                           /* if any children */
445
446    /*
447     * 'universe' now contains the new clipList for the parent window.
448     *
449     * To figure the exposure of the window we subtract the old clip from the
450     * new, just as for the border.
451     */
452
453    if (oldVis == VisibilityFullyObscured || oldVis == VisibilityNotViewable) {
454        RegionCopy(&pParent->valdata->after.exposed, universe);
455    }
456    else if (newVis != VisibilityFullyObscured &&
457             newVis != VisibilityNotViewable) {
458        RegionSubtract(&pParent->valdata->after.exposed,
459                       universe, &pParent->clipList);
460    }
461
462    /* HACK ALERT - copying contents of regions, instead of regions */
463    {
464        RegionRec tmp;
465
466        tmp = pParent->clipList;
467        pParent->clipList = *universe;
468        *universe = tmp;
469    }
470
471#ifdef NOTDEF
472    RegionCopy(&pParent->clipList, universe);
473#endif
474
475    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
476
477    if (pScreen->ClipNotify)
478        (*pScreen->ClipNotify) (pParent, dx, dy);
479}
480
481static void
482miTreeObscured(WindowPtr pParent)
483{
484    WindowPtr pChild;
485    int oldVis;
486
487    pChild = pParent;
488    while (1) {
489        if (pChild->viewable) {
490            oldVis = pChild->visibility;
491            if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
492                ((pChild->
493                  eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
494                SendVisibilityNotify(pChild);
495            if (pChild->firstChild) {
496                pChild = pChild->firstChild;
497                continue;
498            }
499        }
500        while (!pChild->nextSib && (pChild != pParent))
501            pChild = pChild->parent;
502        if (pChild == pParent)
503            break;
504        pChild = pChild->nextSib;
505    }
506}
507
508static RegionPtr
509getBorderClip(WindowPtr pWin)
510{
511#ifdef COMPOSITE
512    if (pWin->redirectDraw != RedirectDrawNone)
513        return compGetRedirectBorderClip(pWin);
514    else
515#endif
516        return &pWin->borderClip;
517}
518
519/*
520 *-----------------------------------------------------------------------
521 * miValidateTree --
522 *	Recomputes the clip list for pParent and all its inferiors.
523 *
524 * Results:
525 *	Always returns 1.
526 *
527 * Side Effects:
528 *	The clipList, borderClip, exposed, and borderExposed regions for
529 *	each marked window are altered.
530 *
531 * Notes:
532 *	This routine assumes that all affected windows have been marked
533 *	(valdata created) and their winSize and borderSize regions
534 *	adjusted to correspond to their new positions. The borderClip and
535 *	clipList regions should not have been touched.
536 *
537 *	The top-most level is treated differently from all lower levels
538 *	because pParent is unchanged. For the top level, we merge the
539 *	regions taken up by the marked children back into the clipList
540 *	for pParent, thus forming a region from which the marked children
541 *	can claim their areas. For lower levels, where the old clipList
542 *	and borderClip are invalid, we can't do this and have to do the
543 *	extra operations done in miComputeClips, but this is much faster
544 *	e.g. when only one child has moved...
545 *
546 *-----------------------------------------------------------------------
547 */
548 /*ARGSUSED*/ int
549miValidateTree(WindowPtr pParent,       /* Parent to validate */
550               WindowPtr pChild,        /* First child of pParent that was
551                                         * affected */
552               VTKind kind      /* What kind of configuration caused call */
553    )
554{
555    RegionRec totalClip;        /* Total clipping region available to
556                                 * the marked children. pParent's clipList
557                                 * merged with the borderClips of all
558                                 * the marked children. */
559    RegionRec childClip;        /* The new borderClip for the current
560                                 * child */
561    RegionRec childUnion;       /* the space covered by borderSize for
562                                 * all marked children */
563    RegionRec exposed;          /* For intermediate calculations */
564    ScreenPtr pScreen;
565    WindowPtr pWin;
566    Bool overlap;
567    int viewvals;
568    Bool forward;
569
570    pScreen = pParent->drawable.pScreen;
571    if (pChild == NullWindow)
572        pChild = pParent->firstChild;
573
574    RegionNull(&childClip);
575    RegionNull(&exposed);
576
577    /*
578     * compute the area of the parent window occupied
579     * by the marked children + the parent itself.  This
580     * is the area which can be divied up among the marked
581     * children in their new configuration.
582     */
583    RegionNull(&totalClip);
584    viewvals = 0;
585    if (RegionBroken(&pParent->clipList) && !RegionBroken(&pParent->borderClip)) {
586        kind = VTBroken;
587        /*
588         * When rebuilding clip lists after out of memory,
589         * assume everything is busted.
590         */
591        forward = TRUE;
592        RegionCopy(&totalClip, &pParent->borderClip);
593        RegionIntersect(&totalClip, &totalClip, &pParent->winSize);
594
595        for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib) {
596            if (pWin->viewable && !TreatAsTransparent(pWin))
597                RegionSubtract(&totalClip, &totalClip, &pWin->borderSize);
598        }
599        for (pWin = pChild; pWin; pWin = pWin->nextSib)
600            if (pWin->valdata && pWin->viewable)
601                viewvals++;
602
603        RegionEmpty(&pParent->clipList);
604    }
605    else {
606        if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
607            ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
608             (pChild->drawable.x < pParent->lastChild->drawable.x))) {
609            forward = TRUE;
610            for (pWin = pChild; pWin; pWin = pWin->nextSib) {
611                if (pWin->valdata) {
612                    RegionAppend(&totalClip, getBorderClip(pWin));
613                    if (pWin->viewable)
614                        viewvals++;
615                }
616            }
617        }
618        else {
619            forward = FALSE;
620            pWin = pParent->lastChild;
621            while (1) {
622                if (pWin->valdata) {
623                    RegionAppend(&totalClip, getBorderClip(pWin));
624                    if (pWin->viewable)
625                        viewvals++;
626                }
627                if (pWin == pChild)
628                    break;
629                pWin = pWin->prevSib;
630            }
631        }
632        RegionValidate(&totalClip, &overlap);
633    }
634
635    /*
636     * Now go through the children of the root and figure their new
637     * borderClips from the totalClip, passing that off to miComputeClips
638     * to handle recursively. Once that's done, we remove the child
639     * from the totalClip to clip any siblings below it.
640     */
641
642    overlap = TRUE;
643    if (kind != VTStack) {
644        RegionUnion(&totalClip, &totalClip, &pParent->clipList);
645        if (viewvals > 1) {
646            /*
647             * precompute childUnion to discover whether any of them
648             * overlap.  This seems redundant, but performance studies
649             * have demonstrated that the cost of this loop is
650             * lower than the cost of multiple Subtracts in the
651             * loop below.
652             */
653            RegionNull(&childUnion);
654            if (forward) {
655                for (pWin = pChild; pWin; pWin = pWin->nextSib)
656                    if (pWin->valdata && pWin->viewable &&
657                        !TreatAsTransparent(pWin))
658                        RegionAppend(&childUnion, &pWin->borderSize);
659            }
660            else {
661                pWin = pParent->lastChild;
662                while (1) {
663                    if (pWin->valdata && pWin->viewable &&
664                        !TreatAsTransparent(pWin))
665                        RegionAppend(&childUnion, &pWin->borderSize);
666                    if (pWin == pChild)
667                        break;
668                    pWin = pWin->prevSib;
669                }
670            }
671            RegionValidate(&childUnion, &overlap);
672            if (overlap)
673                RegionUninit(&childUnion);
674        }
675    }
676
677    for (pWin = pChild; pWin != NullWindow; pWin = pWin->nextSib) {
678        if (pWin->viewable) {
679            if (pWin->valdata) {
680                RegionIntersect(&childClip, &totalClip, &pWin->borderSize);
681                miComputeClips(pWin, pScreen, &childClip, kind, &exposed);
682                if (overlap && !TreatAsTransparent(pWin)) {
683                    RegionSubtract(&totalClip, &totalClip, &pWin->borderSize);
684                }
685            }
686            else if (pWin->visibility == VisibilityNotViewable) {
687                miTreeObscured(pWin);
688            }
689        }
690        else {
691            if (pWin->valdata) {
692                RegionEmpty(&pWin->clipList);
693                if (pScreen->ClipNotify)
694                    (*pScreen->ClipNotify) (pWin, 0, 0);
695                RegionEmpty(&pWin->borderClip);
696                pWin->valdata = NULL;
697            }
698        }
699    }
700
701    RegionUninit(&childClip);
702    if (!overlap) {
703        RegionSubtract(&totalClip, &totalClip, &childUnion);
704        RegionUninit(&childUnion);
705    }
706
707    RegionNull(&pParent->valdata->after.exposed);
708    RegionNull(&pParent->valdata->after.borderExposed);
709
710    /*
711     * each case below is responsible for updating the
712     * clipList and serial number for the parent window
713     */
714
715    switch (kind) {
716    case VTStack:
717        break;
718    default:
719        /*
720         * totalClip contains the new clipList for the parent. Figure out
721         * exposures and obscures as per miComputeClips and reset the parent's
722         * clipList.
723         */
724        RegionSubtract(&pParent->valdata->after.exposed,
725                       &totalClip, &pParent->clipList);
726        /* fall through */
727    case VTMap:
728        RegionCopy(&pParent->clipList, &totalClip);
729        pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
730        break;
731    }
732
733    RegionUninit(&totalClip);
734    RegionUninit(&exposed);
735    if (pScreen->ClipNotify)
736        (*pScreen->ClipNotify) (pParent, 0, 0);
737    return 1;
738}
739