2 * Calculate window clip lists for rootless mode
4 * This file is very closely based on mivaltree.c.
9 * Functions for recalculating window clip lists. Main function
13 Copyright 1987, 1988, 1989, 1998 The Open Group
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 OPEN GROUP 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 Open Group 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 Open Group.
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 ******************************************************************/
55 /* The panoramix components contained the following notice */
56 /*****************************************************************
58 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
60 Permission is hereby granted, free of charge, to any person obtaining a copy
61 of this software and associated documentation files (the "Software"), to deal
62 in the Software without restriction, including without limitation the rights
63 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64 copies of the Software.
66 The above copyright notice and this permission notice shall be included in
67 all copies or substantial portions of the Software.
69 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
72 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
73 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
74 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
75 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
77 Except as contained in this notice, the name of Digital Equipment Corporation
78 shall not be used in advertising or otherwise to promote the sale, use or other
79 dealings in this Software without prior written authorization from Digital
80 Equipment Corporation.
82 ******************************************************************/
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
89 * Bob Scheifler -- avoid miComputeClips for unmapped windows,
92 #ifdef HAVE_DIX_CONFIG_H
93 #include <dix-config.h>
96 #include <stddef.h> /* For NULL */
98 #include "scrnintstr.h"
100 #include "windowstr.h"
102 #include "regionstr.h"
103 #include "mivalidate.h"
107 int RootlessMiValidateTree(WindowPtr pRoot
, WindowPtr pChild
, VTKind kind
);
110 * Compute the visibility of a shaped window
113 RootlessShapedWindowIn(RegionPtr universe
,
114 RegionPtr bounding
, BoxPtr rect
, int x
, int y
)
117 register BoxPtr boundBox
;
119 Bool someIn
, someOut
;
120 register int t
, x1
, y1
, x2
, y2
;
122 nbox
= RegionNumRects(bounding
);
123 boundBox
= RegionRects(bounding
);
124 someIn
= someOut
= FALSE
;
130 if ((t
= boundBox
->x1
+ x
) < x1
)
133 if ((t
= boundBox
->y1
+ y
) < y1
)
136 if ((t
= boundBox
->x2
+ x
) > x2
)
139 if ((t
= boundBox
->y2
+ y
) > y2
)
146 switch (RegionContainsRect(universe
, &box
)) {
167 #define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
169 (w)->backgroundState == ParentRelative)
172 *-----------------------------------------------------------------------
173 * RootlessComputeClips --
174 * Recompute the clipList, borderClip, exposed and borderExposed
175 * regions for pParent and its children. Only viewable windows are
176 * taken into account.
182 * clipList, borderClip, exposed and borderExposed are altered.
183 * A VisibilityNotify event may be generated on the parent window.
185 *-----------------------------------------------------------------------
188 RootlessComputeClips(WindowPtr pParent
, ScreenPtr pScreen
,
189 RegionPtr universe
, VTKind kind
, RegionPtr exposed
)
192 RegionRec childUniverse
;
193 register WindowPtr pChild
;
196 RegionRec childUnion
;
198 RegionPtr borderVisible
;
201 * Figure out the new visibility of this window.
202 * The extent of the universe should be the same as the extent of
203 * the borderSize region. If the window is unobscured, this rectangle
204 * will be completely inside the universe (the universe will cover it
205 * completely). If the window is completely obscured, none of the
206 * universe will cover the rectangle.
208 borderSize
.x1
= pParent
->drawable
.x
- wBorderWidth(pParent
);
209 borderSize
.y1
= pParent
->drawable
.y
- wBorderWidth(pParent
);
210 dx
= (int) pParent
->drawable
.x
+ (int) pParent
->drawable
.width
+
211 wBorderWidth(pParent
);
215 dy
= (int) pParent
->drawable
.y
+ (int) pParent
->drawable
.height
+
216 wBorderWidth(pParent
);
221 oldVis
= pParent
->visibility
;
222 switch (RegionContainsRect(universe
, &borderSize
)) {
224 newVis
= VisibilityUnobscured
;
227 newVis
= VisibilityPartiallyObscured
;
231 if ((pBounding
= wBoundingShape(pParent
))) {
232 switch (RootlessShapedWindowIn(universe
,
233 pBounding
, &borderSize
,
235 pParent
->drawable
.y
)) {
237 newVis
= VisibilityUnobscured
;
240 newVis
= VisibilityFullyObscured
;
247 newVis
= VisibilityFullyObscured
;
251 pParent
->visibility
= newVis
;
252 if (oldVis
!= newVis
&&
254 eventMask
| wOtherEventMasks(pParent
)) & VisibilityChangeMask
))
255 SendVisibilityNotify(pParent
);
257 dx
= pParent
->drawable
.x
- pParent
->valdata
->before
.oldAbsCorner
.x
;
258 dy
= pParent
->drawable
.y
- pParent
->valdata
->before
.oldAbsCorner
.y
;
261 * avoid computations when dealing with simple operations
270 if ((oldVis
== newVis
) &&
271 ((oldVis
== VisibilityFullyObscured
) ||
272 (oldVis
== VisibilityUnobscured
))) {
275 if (pChild
->viewable
) {
276 if (pChild
->visibility
!= VisibilityFullyObscured
) {
277 RegionTranslate(&pChild
->borderClip
, dx
, dy
);
278 RegionTranslate(&pChild
->clipList
, dx
, dy
);
279 pChild
->drawable
.serialNumber
= NEXT_SERIAL_NUMBER
;
280 if (pScreen
->ClipNotify
)
281 (*pScreen
->ClipNotify
) (pChild
, dx
, dy
);
284 if (pChild
->valdata
) {
285 RegionNull(&pChild
->valdata
->after
.borderExposed
);
286 if (HasParentRelativeBorder(pChild
)) {
287 RegionSubtract(&pChild
->valdata
->after
.
288 borderExposed
, &pChild
->borderClip
,
291 RegionNull(&pChild
->valdata
->after
.exposed
);
293 if (pChild
->firstChild
) {
294 pChild
= pChild
->firstChild
;
298 while (!pChild
->nextSib
&& (pChild
!= pParent
))
299 pChild
= pChild
->parent
;
300 if (pChild
== pParent
)
302 pChild
= pChild
->nextSib
;
309 * To calculate exposures correctly, we have to translate the old
310 * borderClip and clipList regions to the window's new location so there
311 * is a correspondence between pieces of the new and old clipping regions.
315 * We translate the old clipList because that will be exposed or copied
316 * if gravity is right.
318 RegionTranslate(&pParent
->borderClip
, dx
, dy
);
319 RegionTranslate(&pParent
->clipList
, dx
, dy
);
323 RegionEmpty(&pParent
->borderClip
);
324 RegionEmpty(&pParent
->clipList
);
328 borderVisible
= pParent
->valdata
->before
.borderVisible
;
329 RegionNull(&pParent
->valdata
->after
.borderExposed
);
330 RegionNull(&pParent
->valdata
->after
.exposed
);
333 * Since the borderClip must not be clipped by the children, we do
334 * the border exposure first...
336 * 'universe' is the window's borderClip. To figure the exposures, remove
337 * the area that used to be exposed from the new.
338 * This leaves a region of pieces that weren't exposed before.
341 if (HasBorder(pParent
)) {
344 * when the border changes shape, the old visible portions
345 * of the border will be saved by DIX in borderVisible --
346 * use that region and destroy it
348 RegionSubtract(exposed
, universe
, borderVisible
);
349 RegionDestroy(borderVisible
);
352 RegionSubtract(exposed
, universe
, &pParent
->borderClip
);
354 if (HasParentRelativeBorder(pParent
) && (dx
|| dy
)) {
355 RegionSubtract(&pParent
->valdata
->after
.borderExposed
,
356 universe
, &pParent
->winSize
);
359 RegionSubtract(&pParent
->valdata
->after
.borderExposed
,
360 exposed
, &pParent
->winSize
);
363 RegionCopy(&pParent
->borderClip
, universe
);
366 * To get the right clipList for the parent, and to make doubly sure
367 * that no child overlaps the parent's border, we remove the parent's
368 * border from the universe before proceeding.
371 RegionIntersect(universe
, universe
, &pParent
->winSize
);
374 RegionCopy(&pParent
->borderClip
, universe
);
376 if ((pChild
= pParent
->firstChild
) && pParent
->mapped
) {
377 RegionNull(&childUniverse
);
378 RegionNull(&childUnion
);
379 if ((pChild
->drawable
.y
< pParent
->lastChild
->drawable
.y
) ||
380 ((pChild
->drawable
.y
== pParent
->lastChild
->drawable
.y
) &&
381 (pChild
->drawable
.x
< pParent
->lastChild
->drawable
.x
))) {
382 for (; pChild
; pChild
= pChild
->nextSib
) {
383 if (pChild
->viewable
)
384 RegionAppend(&childUnion
, &pChild
->borderSize
);
388 for (pChild
= pParent
->lastChild
; pChild
; pChild
= pChild
->prevSib
) {
389 if (pChild
->viewable
)
390 RegionAppend(&childUnion
, &pChild
->borderSize
);
393 RegionValidate(&childUnion
, &overlap
);
395 for (pChild
= pParent
->firstChild
; pChild
; 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 RegionIntersect(&childUniverse
,
408 universe
, &pChild
->borderSize
);
409 RootlessComputeClips(pChild
, pScreen
, &childUniverse
,
413 * Once the child has been processed, we remove its extents
414 * from the current universe, thus denying its space to any
418 RegionSubtract(universe
, universe
, &pChild
->borderSize
);
422 RegionSubtract(universe
, universe
, &childUnion
);
423 RegionUninit(&childUnion
);
424 RegionUninit(&childUniverse
);
425 } /* if any children */
428 * 'universe' now contains the new clipList for the parent window.
430 * To figure the exposure of the window we subtract the old clip from the
431 * new, just as for the border.
434 if (oldVis
== VisibilityFullyObscured
|| oldVis
== VisibilityNotViewable
) {
435 RegionCopy(&pParent
->valdata
->after
.exposed
, universe
);
437 else if (newVis
!= VisibilityFullyObscured
&&
438 newVis
!= VisibilityNotViewable
) {
439 RegionSubtract(&pParent
->valdata
->after
.exposed
,
440 universe
, &pParent
->clipList
);
443 /* HACK ALERT - copying contents of regions, instead of regions */
447 tmp
= pParent
->clipList
;
448 pParent
->clipList
= *universe
;
453 RegionCopy(&pParent
->clipList
, universe
);
456 pParent
->drawable
.serialNumber
= NEXT_SERIAL_NUMBER
;
458 if (pScreen
->ClipNotify
)
459 (*pScreen
->ClipNotify
) (pParent
, dx
, dy
);
463 RootlessTreeObscured(WindowPtr pParent
)
465 register WindowPtr pChild
;
470 if (pChild
->viewable
) {
471 oldVis
= pChild
->visibility
;
472 if (oldVis
!= (pChild
->visibility
= VisibilityFullyObscured
) &&
474 eventMask
| wOtherEventMasks(pChild
)) & VisibilityChangeMask
))
475 SendVisibilityNotify(pChild
);
476 if (pChild
->firstChild
) {
477 pChild
= pChild
->firstChild
;
481 while (!pChild
->nextSib
&& (pChild
!= pParent
))
482 pChild
= pChild
->parent
;
483 if (pChild
== pParent
)
485 pChild
= pChild
->nextSib
;
490 *-----------------------------------------------------------------------
491 * RootlessMiValidateTree --
492 * Recomputes the clip list for pParent and all its inferiors.
498 * The clipList, borderClip, exposed, and borderExposed regions for
499 * each marked window are altered.
502 * This routine assumes that all affected windows have been marked
503 * (valdata created) and their winSize and borderSize regions
504 * adjusted to correspond to their new positions. The borderClip and
505 * clipList regions should not have been touched.
507 * The top-most level is treated differently from all lower levels
508 * because pParent is unchanged. For the top level, we merge the
509 * regions taken up by the marked children back into the clipList
510 * for pParent, thus forming a region from which the marked children
511 * can claim their areas. For lower levels, where the old clipList
512 * and borderClip are invalid, we can't do this and have to do the
513 * extra operations done in miComputeClips, but this is much faster
514 * e.g. when only one child has moved...
516 *-----------------------------------------------------------------------
519 Quartz version: used for validate from root in rootless mode.
520 We need to make sure top-level windows don't clip each other,
521 and that top-level windows aren't clipped to the root window.
524 // fixme this is ugly
525 // Xprint/ValTree.c doesn't work, but maybe that method can?
527 RootlessMiValidateTree(WindowPtr pRoot
, /* Parent to validate */
528 WindowPtr pChild
, /* First child of pRoot that was
530 VTKind kind
/* What kind of configuration caused call */
533 RegionRec childClip
; /* The new borderClip for the current
535 RegionRec exposed
; /* For intermediate calculations */
536 register ScreenPtr pScreen
;
537 register WindowPtr pWin
;
539 pScreen
= pRoot
->drawable
.pScreen
;
540 if (pChild
== NullWindow
)
541 pChild
= pRoot
->firstChild
;
543 RegionNull(&childClip
);
544 RegionNull(&exposed
);
546 if (RegionBroken(&pRoot
->clipList
) && !RegionBroken(&pRoot
->borderClip
)) {
547 // fixme this might not work, but hopefully doesn't happen anyway.
549 RegionEmpty(&pRoot
->clipList
);
550 ErrorF("ValidateTree: BUSTED!\n");
554 * Recursively compute the clips for all children of the root.
555 * They don't clip against each other or the root itself, so
556 * childClip is always reset to that child's size.
559 for (pWin
= pChild
; pWin
!= NullWindow
; pWin
= pWin
->nextSib
) {
560 if (pWin
->viewable
) {
562 RegionCopy(&childClip
, &pWin
->borderSize
);
563 RootlessComputeClips(pWin
, pScreen
, &childClip
, kind
, &exposed
);
565 else if (pWin
->visibility
== VisibilityNotViewable
) {
566 RootlessTreeObscured(pWin
);
571 RegionEmpty(&pWin
->clipList
);
572 if (pScreen
->ClipNotify
)
573 (*pScreen
->ClipNotify
) (pWin
, 0, 0);
574 RegionEmpty(&pWin
->borderClip
);
575 pWin
->valdata
= NULL
;
580 RegionUninit(&childClip
);
582 /* The root is never clipped by its children, so nothing on the root
583 is ever exposed by moving or mapping its children. */
584 RegionNull(&pRoot
->valdata
->after
.exposed
);
585 RegionNull(&pRoot
->valdata
->after
.borderExposed
);