1 /* $XConsortium: mivaltree.c,v 5.33 94/04/17 20:27:58 dpw Exp $ */
4 * Functions for recalculating window clip lists. Main function
8 Copyright (c) 1987, 1988, 1989 X Consortium
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Except as contained in this notice, the name of the X Consortium shall not be
28 used in advertising or otherwise to promote the sale, use or other dealings
29 in this Software without prior written authorization from the X Consortium.
32 * Copyright 1987, 1988, 1989 by
33 * Digital Equipment Corporation, Maynard, Massachusetts,
37 * Permission to use, copy, modify, and distribute this software and its
38 * documentation for any purpose and without fee is hereby granted,
39 * provided that the above copyright notice appear in all copies and that
40 * both that copyright notice and this permission notice appear in
41 * supporting documentation, and that the name of Digital not be
42 * used in advertising or publicity pertaining to distribution of the
43 * software without specific, written prior permission.
45 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
46 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
47 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
48 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
49 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
50 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 ******************************************************************/
56 * Aug '86: Susan Angebranndt -- original code
57 * July '87: Adam de Boor -- substantially modified and commented
58 * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible.
59 * In particular, much improved code for window mapping and
61 * Bob Scheifler -- avoid miComputeClips for unmapped windows,
66 #include "scrnintstr.h"
68 #include "windowstr.h"
70 #include "regionstr.h"
71 #include "mivalidate.h"
75 * Compute the visibility of a shaped window
77 miShapedWindowIn (pScreen, universe, bounding, rect, x, y)
79 RegionPtr universe, bounding;
84 register BoxPtr boundBox;
87 register int t, x1, y1, x2, y2;
89 nbox = REGION_NUM_RECTS (bounding);
90 boundBox = REGION_RECTS (bounding);
91 someIn = someOut = FALSE;
98 if ((t = boundBox->x1 + x) < x1)
101 if ((t = boundBox->y1 + y) < y1)
104 if ((t = boundBox->x2 + x) > x2)
107 if ((t = boundBox->y2 + y) > y2)
114 switch (RECT_IN_REGION(pScreen, universe, &box))
137 #define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
139 (w)->backgroundState == ParentRelative)
142 *-----------------------------------------------------------------------
144 * Recompute the clipList, borderClip, exposed and borderExposed
145 * regions for pParent and its children. Only viewable windows are
146 * taken into account.
152 * clipList, borderClip, exposed and borderExposed are altered.
153 * A VisibilityNotify event may be generated on the parent window.
155 *-----------------------------------------------------------------------
159 miComputeClips (pParent, pScreen, universe, kind, exposed)
160 register WindowPtr pParent;
161 register ScreenPtr pScreen;
162 register RegionPtr universe;
164 RegionPtr exposed; /* for intermediate calculations */
168 RegionRec childUniverse;
169 register WindowPtr pChild;
172 RegionRec childUnion;
174 RegionPtr borderVisible;
178 * Figure out the new visibility of this window.
179 * The extent of the universe should be the same as the extent of
180 * the borderSize region. If the window is unobscured, this rectangle
181 * will be completely inside the universe (the universe will cover it
182 * completely). If the window is completely obscured, none of the
183 * universe will cover the rectangle.
186 borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
187 borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
188 dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
192 dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
197 oldVis = pParent->visibility;
198 switch (RECT_IN_REGION( pScreen, universe, &borderSize))
201 newVis = VisibilityUnobscured;
204 newVis = VisibilityPartiallyObscured;
209 if ((pBounding = wBoundingShape (pParent)))
211 switch (miShapedWindowIn (pScreen, universe, pBounding,
214 pParent->drawable.y))
217 newVis = VisibilityUnobscured;
220 newVis = VisibilityFullyObscured;
228 newVis = VisibilityFullyObscured;
231 pParent->visibility = newVis;
232 if (oldVis != newVis &&
233 ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
234 SendVisibilityNotify(pParent);
236 dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
237 dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
240 * avoid computations when dealing with simple operations
249 if ((oldVis == newVis) &&
250 ((oldVis == VisibilityFullyObscured) ||
251 (oldVis == VisibilityUnobscured)))
256 if (pChild->viewable)
258 if (pChild->visibility != VisibilityFullyObscured)
260 REGION_TRANSLATE( pScreen, &pChild->borderClip,
262 REGION_TRANSLATE( pScreen, &pChild->clipList,
264 pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
265 if (pScreen->ClipNotify)
266 (* pScreen->ClipNotify) (pChild, dx, dy);
272 &pChild->valdata->after.borderExposed,
274 if (HasParentRelativeBorder(pChild))
276 REGION_SUBTRACT(pScreen,
277 &pChild->valdata->after.borderExposed,
281 REGION_INIT( pScreen, &pChild->valdata->after.exposed,
284 if (pChild->firstChild)
286 pChild = pChild->firstChild;
290 while (!pChild->nextSib && (pChild != pParent))
291 pChild = pChild->parent;
292 if (pChild == pParent)
294 pChild = pChild->nextSib;
301 * To calculate exposures correctly, we have to translate the old
302 * borderClip and clipList regions to the window's new location so there
303 * is a correspondence between pieces of the new and old clipping regions.
308 * We translate the old clipList because that will be exposed or copied
309 * if gravity is right.
311 REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
312 REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
317 borderVisible = pParent->valdata->before.borderVisible;
318 resized = pParent->valdata->before.resized;
319 REGION_INIT( pScreen, &pParent->valdata->after.borderExposed, NullBox, 0);
320 REGION_INIT( pScreen, &pParent->valdata->after.exposed, NullBox, 0);
323 * Since the borderClip must not be clipped by the children, we do
324 * the border exposure first...
326 * 'universe' is the window's borderClip. To figure the exposures, remove
327 * the area that used to be exposed from the new.
328 * This leaves a region of pieces that weren't exposed before.
331 if (HasBorder (pParent))
336 * when the border changes shape, the old visible portions
337 * of the border will be saved by DIX in borderVisible --
338 * use that region and destroy it
340 REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
341 REGION_DESTROY( pScreen, borderVisible);
345 REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
347 if (HasParentRelativeBorder(pParent) && (dx || dy))
348 REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
352 REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
353 exposed, &pParent->winSize);
355 REGION_COPY( pScreen, &pParent->borderClip, universe);
358 * To get the right clipList for the parent, and to make doubly sure
359 * that no child overlaps the parent's border, we remove the parent's
360 * border from the universe before proceeding.
363 REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
366 REGION_COPY( pScreen, &pParent->borderClip, universe);
368 if ((pChild = pParent->firstChild) && pParent->mapped)
370 REGION_INIT(pScreen, &childUniverse, NullBox, 0);
371 REGION_INIT(pScreen, &childUnion, NullBox, 0);
372 if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
373 ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
374 (pChild->drawable.x < pParent->lastChild->drawable.x)))
376 for (; pChild; pChild = pChild->nextSib)
378 if (pChild->viewable)
379 REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
384 for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
386 if (pChild->viewable)
387 REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
390 REGION_VALIDATE( pScreen, &childUnion, &overlap);
392 for (pChild = pParent->firstChild;
394 pChild = pChild->nextSib)
396 if (pChild->viewable) {
398 * If the child is viewable, we want to remove its extents
399 * from the current universe, but we only re-clip it if
402 if (pChild->valdata) {
404 * Figure out the new universe from the child's
405 * perspective and recurse.
407 REGION_INTERSECT( pScreen, &childUniverse,
409 &pChild->borderSize);
410 miComputeClips (pChild, pScreen, &childUniverse, kind,
414 * Once the child has been processed, we remove its extents
415 * from the current universe, thus denying its space to any
419 REGION_SUBTRACT( pScreen, universe, universe,
420 &pChild->borderSize);
424 REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
425 REGION_UNINIT( pScreen, &childUnion);
426 REGION_UNINIT( pScreen, &childUniverse);
427 } /* if any children */
430 * 'universe' now contains the new clipList for the parent window.
432 * To figure the exposure of the window we subtract the old clip from the
433 * new, just as for the border.
436 if (oldVis == VisibilityFullyObscured ||
437 oldVis == VisibilityNotViewable)
439 REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
441 else if (newVis != VisibilityFullyObscured &&
442 newVis != VisibilityNotViewable)
444 REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
445 universe, &pParent->clipList);
449 * One last thing: backing storage. We have to try to save what parts of
450 * the window are about to be obscured. We can just subtract the universe
451 * from the old clipList and get the areas that were in the old but aren't
452 * in the new and, hence, are about to be obscured.
454 if (pParent->backStorage && !resized)
456 REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe);
457 (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy);
460 /* HACK ALERT - copying contents of regions, instead of regions */
464 tmp = pParent->clipList;
465 pParent->clipList = *universe;
470 REGION_COPY( pScreen, &pParent->clipList, universe);
473 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
475 if (pScreen->ClipNotify)
476 (* pScreen->ClipNotify) (pParent, dx, dy);
480 miTreeObscured(pParent)
481 register WindowPtr pParent;
483 register WindowPtr pChild;
489 if (pChild->viewable)
491 oldVis = pChild->visibility;
492 if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
493 ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
494 SendVisibilityNotify(pChild);
495 if (pChild->firstChild)
497 pChild = pChild->firstChild;
501 while (!pChild->nextSib && (pChild != pParent))
502 pChild = pChild->parent;
503 if (pChild == pParent)
505 pChild = pChild->nextSib;
510 *-----------------------------------------------------------------------
512 * Recomputes the clip list for pParent and all its inferiors.
518 * The clipList, borderClip, exposed, and borderExposed regions for
519 * each marked window are altered.
522 * This routine assumes that all affected windows have been marked
523 * (valdata created) and their winSize and borderSize regions
524 * adjusted to correspond to their new positions. The borderClip and
525 * clipList regions should not have been touched.
527 * The top-most level is treated differently from all lower levels
528 * because pParent is unchanged. For the top level, we merge the
529 * regions taken up by the marked children back into the clipList
530 * for pParent, thus forming a region from which the marked children
531 * can claim their areas. For lower levels, where the old clipList
532 * and borderClip are invalid, we can't do this and have to do the
533 * extra operations done in miComputeClips, but this is much faster
534 * e.g. when only one child has moved...
536 *-----------------------------------------------------------------------
540 miValidateTree (pParent, pChild, kind)
541 WindowPtr pParent; /* Parent to validate */
542 WindowPtr pChild; /* First child of pParent that was
544 VTKind kind; /* What kind of configuration caused call */
546 RegionRec totalClip; /* Total clipping region available to
547 * the marked children. pParent's clipList
548 * merged with the borderClips of all
549 * the marked children. */
550 RegionRec childClip; /* The new borderClip for the current
552 RegionRec childUnion; /* the space covered by borderSize for
553 * all marked children */
554 RegionRec exposed; /* For intermediate calculations */
555 register ScreenPtr pScreen;
556 register WindowPtr pWin;
561 pScreen = pParent->drawable.pScreen;
562 if (pChild == NullWindow)
563 pChild = pParent->firstChild;
565 REGION_INIT(pScreen, &childClip, NullBox, 0);
566 REGION_INIT(pScreen, &exposed, NullBox, 0);
569 * compute the area of the parent window occupied
570 * by the marked children + the parent itself. This
571 * is the area which can be divied up among the marked
572 * children in their new configuration.
574 REGION_INIT(pScreen, &totalClip, NullBox, 0);
576 if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
577 ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
578 (pChild->drawable.x < pParent->lastChild->drawable.x)))
581 for (pWin = pChild; pWin; pWin = pWin->nextSib)
585 REGION_APPEND( pScreen, &totalClip, &pWin->borderClip);
594 pWin = pParent->lastChild;
599 REGION_APPEND( pScreen, &totalClip, &pWin->borderClip);
605 pWin = pWin->prevSib;
608 REGION_VALIDATE( pScreen, &totalClip, &overlap);
611 * Now go through the children of the root and figure their new
612 * borderClips from the totalClip, passing that off to miComputeClips
613 * to handle recursively. Once that's done, we remove the child
614 * from the totalClip to clip any siblings below it.
620 REGION_UNION( pScreen, &totalClip, &totalClip, &pParent->clipList);
624 * precompute childUnion to discover whether any of them
625 * overlap. This seems redundant, but performance studies
626 * have demonstrated that the cost of this loop is
627 * lower than the cost of multiple Subtracts in the
630 REGION_INIT(pScreen, &childUnion, NullBox, 0);
633 for (pWin = pChild; pWin; pWin = pWin->nextSib)
634 if (pWin->valdata && pWin->viewable)
635 REGION_APPEND( pScreen, &childUnion,
640 pWin = pParent->lastChild;
643 if (pWin->valdata && pWin->viewable)
644 REGION_APPEND( pScreen, &childUnion,
648 pWin = pWin->prevSib;
651 REGION_VALIDATE(pScreen, &childUnion, &overlap);
653 REGION_UNINIT(pScreen, &childUnion);
659 pWin = pWin->nextSib)
661 if (pWin->viewable) {
663 REGION_INTERSECT( pScreen, &childClip,
666 miComputeClips (pWin, pScreen, &childClip, kind, &exposed);
669 REGION_SUBTRACT( pScreen, &totalClip,
673 } else if (pWin->visibility == VisibilityNotViewable) {
674 miTreeObscured(pWin);
678 REGION_EMPTY( pScreen, &pWin->clipList);
679 if (pScreen->ClipNotify)
680 (* pScreen->ClipNotify) (pWin, 0, 0);
681 REGION_EMPTY( pScreen, &pWin->borderClip);
682 pWin->valdata = (ValidatePtr)NULL;
687 REGION_UNINIT( pScreen, &childClip);
690 REGION_SUBTRACT(pScreen, &totalClip, &totalClip, &childUnion);
691 REGION_UNINIT(pScreen, &childUnion);
694 REGION_INIT( pScreen, &pParent->valdata->after.exposed, NullBox, 0);
695 REGION_INIT( pScreen, &pParent->valdata->after.borderExposed, NullBox, 0);
698 * each case below is responsible for updating the
699 * clipList and serial number for the parent window
707 * totalClip contains the new clipList for the parent. Figure out
708 * exposures and obscures as per miComputeClips and reset the parent's
711 REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
712 &totalClip, &pParent->clipList);
715 if (pParent->backStorage) {
716 REGION_SUBTRACT( pScreen, &exposed, &pParent->clipList, &totalClip);
717 (* pScreen->SaveDoomedAreas)(pParent, &exposed, 0, 0);
720 REGION_COPY( pScreen, &pParent->clipList, &totalClip);
721 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
725 REGION_UNINIT( pScreen, &totalClip);
726 REGION_UNINIT( pScreen, &exposed);
727 if (pScreen->ClipNotify)
728 (*pScreen->ClipNotify) (pParent, 0, 0);