2 * Calculate window clip lists for rootless mode
4 * This file is very closely based on mivaltree.c.
6 /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessValTree.c,v 1.2 2002/06/18 19:43:04 torrey Exp $ */
10 * Functions for recalculating window clip lists. Main function
14 Copyright 1987, 1988, 1989, 1998 The Open Group
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 Except as contained in this notice, the name of The Open Group shall not be
29 used in advertising or otherwise to promote the sale, use or other dealings
30 in this Software without prior written authorization from The Open Group.
33 * Copyright 1987, 1988, 1989 by
34 * Digital Equipment Corporation, Maynard, Massachusetts,
38 * Permission to use, copy, modify, and distribute this software and its
39 * documentation for any purpose and without fee is hereby granted,
40 * provided that the above copyright notice appear in all copies and that
41 * both that copyright notice and this permission notice appear in
42 * supporting documentation, and that the name of Digital not be
43 * used in advertising or publicity pertaining to distribution of the
44 * software without specific, written prior permission.
46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54 ******************************************************************/
56 /* The panoramix components contained the following notice */
57 /****************************************************************
59 * Copyright (c) Digital Equipment Corporation, 1991, 1997 *
61 * All Rights Reserved. Unpublished rights reserved under *
62 * the copyright laws of the United States. *
64 * The software contained on this media is proprietary to *
65 * and embodies the confidential technology of Digital *
66 * Equipment Corporation. Possession, use, duplication or *
67 * dissemination of the software and media is authorized only *
68 * pursuant to a valid written license from Digital Equipment *
71 * RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure *
72 * by the U.S. Government is subject to restrictions as set *
73 * forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, *
74 * or in FAR 52.227-19, as applicable. *
76 *****************************************************************/
79 * Aug '86: Susan Angebranndt -- original code
80 * July '87: Adam de Boor -- substantially modified and commented
81 * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible.
82 * In particular, much improved code for window mapping and
84 * Bob Scheifler -- avoid miComputeClips for unmapped windows,
88 #include "scrnintstr.h"
90 #include "windowstr.h"
92 #include "regionstr.h"
93 #include "mivalidate.h"
99 * Compute the visibility of a shaped window
102 RootlessShapedWindowIn (pScreen, universe, bounding, rect, x, y)
104 RegionPtr universe, bounding;
109 register BoxPtr boundBox;
111 Bool someIn, someOut;
112 register int t, x1, y1, x2, y2;
114 nbox = REGION_NUM_RECTS (bounding);
115 boundBox = REGION_RECTS (bounding);
116 someIn = someOut = FALSE;
123 if ((t = boundBox->x1 + x) < x1)
126 if ((t = boundBox->y1 + y) < y1)
129 if ((t = boundBox->x2 + x) > x2)
132 if ((t = boundBox->y2 + y) > y2)
139 switch (RECT_IN_REGION(pScreen, universe, &box))
162 #define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
164 (w)->backgroundState == ParentRelative)
168 *-----------------------------------------------------------------------
169 * RootlessComputeClips --
170 * Recompute the clipList, borderClip, exposed and borderExposed
171 * regions for pParent and its children. Only viewable windows are
172 * taken into account.
178 * clipList, borderClip, exposed and borderExposed are altered.
179 * A VisibilityNotify event may be generated on the parent window.
181 *-----------------------------------------------------------------------
184 RootlessComputeClips (pParent, pScreen, universe, kind, exposed)
185 register WindowPtr pParent;
186 register ScreenPtr pScreen;
187 register RegionPtr universe;
189 RegionPtr exposed; /* for intermediate calculations */
193 RegionRec childUniverse;
194 register WindowPtr pChild;
197 RegionRec childUnion;
199 RegionPtr borderVisible;
202 * Figure out the new visibility of this window.
203 * The extent of the universe should be the same as the extent of
204 * the borderSize region. If the window is unobscured, this rectangle
205 * will be completely inside the universe (the universe will cover it
206 * completely). If the window is completely obscured, none of the
207 * universe will cover the rectangle.
209 borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
210 borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
211 dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
215 dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
220 oldVis = pParent->visibility;
221 switch (RECT_IN_REGION( pScreen, universe, &borderSize))
224 newVis = VisibilityUnobscured;
227 newVis = VisibilityPartiallyObscured;
232 if ((pBounding = wBoundingShape (pParent)))
234 switch (RootlessShapedWindowIn (pScreen, universe,
235 pBounding, &borderSize,
237 pParent->drawable.y))
240 newVis = VisibilityUnobscured;
243 newVis = VisibilityFullyObscured;
251 newVis = VisibilityFullyObscured;
255 pParent->visibility = newVis;
256 if (oldVis != newVis &&
257 ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
258 SendVisibilityNotify(pParent);
260 dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
261 dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
264 * avoid computations when dealing with simple operations
273 if ((oldVis == newVis) &&
274 ((oldVis == VisibilityFullyObscured) ||
275 (oldVis == VisibilityUnobscured)))
280 if (pChild->viewable)
282 if (pChild->visibility != VisibilityFullyObscured)
284 REGION_TRANSLATE( pScreen, &pChild->borderClip,
286 REGION_TRANSLATE( pScreen, &pChild->clipList,
288 pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
289 if (pScreen->ClipNotify)
290 (* pScreen->ClipNotify) (pChild, dx, dy);
296 &pChild->valdata->after.borderExposed,
298 if (HasParentRelativeBorder(pChild))
300 REGION_SUBTRACT(pScreen,
301 &pChild->valdata->after.borderExposed,
305 REGION_INIT( pScreen, &pChild->valdata->after.exposed,
308 if (pChild->firstChild)
310 pChild = pChild->firstChild;
314 while (!pChild->nextSib && (pChild != pParent))
315 pChild = pChild->parent;
316 if (pChild == pParent)
318 pChild = pChild->nextSib;
325 * To calculate exposures correctly, we have to translate the old
326 * borderClip and clipList regions to the window's new location so there
327 * is a correspondence between pieces of the new and old clipping regions.
332 * We translate the old clipList because that will be exposed or copied
333 * if gravity is right.
335 REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
336 REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
340 REGION_EMPTY (pScreen, &pParent->borderClip);
341 REGION_EMPTY (pScreen, &pParent->clipList);
345 borderVisible = pParent->valdata->before.borderVisible;
346 resized = pParent->valdata->before.resized;
347 REGION_INIT( pScreen, &pParent->valdata->after.borderExposed, NullBox, 0);
348 REGION_INIT( pScreen, &pParent->valdata->after.exposed, NullBox, 0);
351 * Since the borderClip must not be clipped by the children, we do
352 * the border exposure first...
354 * 'universe' is the window's borderClip. To figure the exposures, remove
355 * the area that used to be exposed from the new.
356 * This leaves a region of pieces that weren't exposed before.
359 if (HasBorder (pParent))
364 * when the border changes shape, the old visible portions
365 * of the border will be saved by DIX in borderVisible --
366 * use that region and destroy it
368 REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
369 REGION_DESTROY( pScreen, borderVisible);
373 REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
375 if (HasParentRelativeBorder(pParent) && (dx || dy)) {
376 REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
380 REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
381 exposed, &pParent->winSize);
384 REGION_COPY( pScreen, &pParent->borderClip, universe);
387 * To get the right clipList for the parent, and to make doubly sure
388 * that no child overlaps the parent's border, we remove the parent's
389 * border from the universe before proceeding.
392 REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
395 REGION_COPY( pScreen, &pParent->borderClip, universe);
397 if ((pChild = pParent->firstChild) && pParent->mapped)
399 REGION_INIT(pScreen, &childUniverse, NullBox, 0);
400 REGION_INIT(pScreen, &childUnion, NullBox, 0);
401 if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
402 ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
403 (pChild->drawable.x < pParent->lastChild->drawable.x)))
405 for (; pChild; pChild = pChild->nextSib)
407 if (pChild->viewable)
408 REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
413 for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
415 if (pChild->viewable)
416 REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
419 REGION_VALIDATE( pScreen, &childUnion, &overlap);
421 for (pChild = pParent->firstChild;
423 pChild = pChild->nextSib)
425 if (pChild->viewable) {
427 * If the child is viewable, we want to remove its extents
428 * from the current universe, but we only re-clip it if
431 if (pChild->valdata) {
433 * Figure out the new universe from the child's
434 * perspective and recurse.
436 REGION_INTERSECT( pScreen, &childUniverse,
438 &pChild->borderSize);
439 RootlessComputeClips (pChild, pScreen, &childUniverse,
443 * Once the child has been processed, we remove its extents
444 * from the current universe, thus denying its space to any
448 REGION_SUBTRACT( pScreen, universe, universe,
449 &pChild->borderSize);
453 REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
454 REGION_UNINIT( pScreen, &childUnion);
455 REGION_UNINIT( pScreen, &childUniverse);
456 } /* if any children */
459 * 'universe' now contains the new clipList for the parent window.
461 * To figure the exposure of the window we subtract the old clip from the
462 * new, just as for the border.
465 if (oldVis == VisibilityFullyObscured ||
466 oldVis == VisibilityNotViewable)
468 REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
470 else if (newVis != VisibilityFullyObscured &&
471 newVis != VisibilityNotViewable)
473 REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
474 universe, &pParent->clipList);
478 * One last thing: backing storage. We have to try to save what parts of
479 * the window are about to be obscured. We can just subtract the universe
480 * from the old clipList and get the areas that were in the old but aren't
481 * in the new and, hence, are about to be obscured.
483 if (pParent->backStorage && !resized)
485 REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe);
486 (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy);
489 /* HACK ALERT - copying contents of regions, instead of regions */
493 tmp = pParent->clipList;
494 pParent->clipList = *universe;
499 REGION_COPY( pScreen, &pParent->clipList, universe);
502 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
504 if (pScreen->ClipNotify)
505 (* pScreen->ClipNotify) (pParent, dx, dy);
509 RootlessTreeObscured(pParent)
510 register WindowPtr pParent;
512 register WindowPtr pChild;
518 if (pChild->viewable)
520 oldVis = pChild->visibility;
521 if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
522 ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
523 SendVisibilityNotify(pChild);
524 if (pChild->firstChild)
526 pChild = pChild->firstChild;
530 while (!pChild->nextSib && (pChild != pParent))
531 pChild = pChild->parent;
532 if (pChild == pParent)
534 pChild = pChild->nextSib;
539 *-----------------------------------------------------------------------
540 * RootlessMiValidateTree --
541 * Recomputes the clip list for pParent and all its inferiors.
547 * The clipList, borderClip, exposed, and borderExposed regions for
548 * each marked window are altered.
551 * This routine assumes that all affected windows have been marked
552 * (valdata created) and their winSize and borderSize regions
553 * adjusted to correspond to their new positions. The borderClip and
554 * clipList regions should not have been touched.
556 * The top-most level is treated differently from all lower levels
557 * because pParent is unchanged. For the top level, we merge the
558 * regions taken up by the marked children back into the clipList
559 * for pParent, thus forming a region from which the marked children
560 * can claim their areas. For lower levels, where the old clipList
561 * and borderClip are invalid, we can't do this and have to do the
562 * extra operations done in miComputeClips, but this is much faster
563 * e.g. when only one child has moved...
565 *-----------------------------------------------------------------------
568 Quartz version: used for validate from root in rootless mode.
569 We need to make sure top-level windows don't clip each other,
570 and that top-level windows aren't clipped to the root window.
573 // fixme this is ugly
574 // Xprint/ValTree.c doesn't work, but maybe that method can?
576 RootlessMiValidateTree (pRoot, pChild, kind)
577 WindowPtr pRoot; /* Parent to validate */
578 WindowPtr pChild; /* First child of pRoot that was
580 VTKind kind; /* What kind of configuration caused call */
582 RegionRec childClip; /* The new borderClip for the current
584 RegionRec exposed; /* For intermediate calculations */
585 register ScreenPtr pScreen;
586 register WindowPtr pWin;
588 pScreen = pRoot->drawable.pScreen;
589 if (pChild == NullWindow)
590 pChild = pRoot->firstChild;
592 REGION_INIT(pScreen, &childClip, NullBox, 0);
593 REGION_INIT(pScreen, &exposed, NullBox, 0);
595 if (REGION_BROKEN (pScreen, &pRoot->clipList) &&
596 !REGION_BROKEN (pScreen, &pRoot->borderClip))
598 // fixme this might not work, but hopefully doesn't happen anyway.
600 REGION_EMPTY (pScreen, &pRoot->clipList);
601 ErrorF("ValidateTree: BUSTED!\n");
605 * Recursively compute the clips for all children of the root.
606 * They don't clip against each other or the root itself, so
607 * childClip is always reset to that child's size.
612 pWin = pWin->nextSib)
614 if (pWin->viewable) {
616 REGION_COPY( pScreen, &childClip, &pWin->borderSize);
617 RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed);
618 } else if (pWin->visibility == VisibilityNotViewable) {
619 RootlessTreeObscured(pWin);
623 REGION_EMPTY( pScreen, &pWin->clipList);
624 if (pScreen->ClipNotify)
625 (* pScreen->ClipNotify) (pWin, 0, 0);
626 REGION_EMPTY( pScreen, &pWin->borderClip);
627 pWin->valdata = (ValidatePtr)NULL;
632 REGION_UNINIT( pScreen, &childClip);
634 /* The root is never clipped by its children, so nothing on the root
635 is ever exposed by moving or mapping its children. */
636 REGION_INIT( pScreen, &pRoot->valdata->after.exposed, NullBox, 0);
637 REGION_INIT( pScreen, &pRoot->valdata->after.borderExposed, NullBox, 0);