rootlessValTree.c revision 05b261ec
1/*
2 * Calculate window clip lists for rootless mode
3 *
4 * This file is very closely based on mivaltree.c.
5 */
6
7/*
8 * mivaltree.c --
9 *	Functions for recalculating window clip lists. Main function
10 *	is miValidateTree.
11 *
12
13Copyright 1987, 1988, 1989, 1998  The Open Group
14
15All Rights Reserved.
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
23OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
24AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27Except as contained in this notice, the name of The Open Group shall not be
28used in advertising or otherwise to promote the sale, use or other dealings
29in this Software without prior written authorization from The Open Group.
30
31 *
32 * Copyright 1987, 1988, 1989 by
33 * Digital Equipment Corporation, Maynard, Massachusetts,
34 *
35 *                         All Rights Reserved
36 *
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.
44 *
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
51 * SOFTWARE.
52 *
53 ******************************************************************/
54
55/* The panoramix components contained the following notice */
56/*****************************************************************
57
58Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
59
60Permission is hereby granted, free of charge, to any person obtaining a copy
61of this software and associated documentation files (the "Software"), to deal
62in the Software without restriction, including without limitation the rights
63to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64copies of the Software.
65
66The above copyright notice and this permission notice shall be included in
67all copies or substantial portions of the Software.
68
69THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
72DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
73BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
74WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
75IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76
77Except as contained in this notice, the name of Digital Equipment Corporation
78shall not be used in advertising or otherwise to promote the sale, use or other
79dealings in this Software without prior written authorization from Digital
80Equipment Corporation.
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 <stddef.h> /* For NULL */
97#include    <X11/X.h>
98#include    "scrnintstr.h"
99#include    "validate.h"
100#include    "windowstr.h"
101#include    "mi.h"
102#include    "regionstr.h"
103#include    "mivalidate.h"
104
105#include    "globals.h"
106
107#ifdef SHAPE
108/*
109 * Compute the visibility of a shaped window
110 */
111int
112RootlessShapedWindowIn (pScreen, universe, bounding, rect, x, y)
113    ScreenPtr	pScreen;
114    RegionPtr	universe, bounding;
115    BoxPtr	rect;
116    register int x, y;
117{
118    BoxRec  box;
119    register BoxPtr  boundBox;
120    int	    nbox;
121    Bool    someIn, someOut;
122    register int t, x1, y1, x2, y2;
123
124    nbox = REGION_NUM_RECTS (bounding);
125    boundBox = REGION_RECTS (bounding);
126    someIn = someOut = FALSE;
127    x1 = rect->x1;
128    y1 = rect->y1;
129    x2 = rect->x2;
130    y2 = rect->y2;
131    while (nbox--)
132    {
133	if ((t = boundBox->x1 + x) < x1)
134	    t = x1;
135	box.x1 = t;
136	if ((t = boundBox->y1 + y) < y1)
137	    t = y1;
138	box.y1 = t;
139	if ((t = boundBox->x2 + x) > x2)
140	    t = x2;
141	box.x2 = t;
142	if ((t = boundBox->y2 + y) > y2)
143	    t = y2;
144	box.y2 = t;
145	if (box.x1 > box.x2)
146	    box.x2 = box.x1;
147	if (box.y1 > box.y2)
148	    box.y2 = box.y1;
149	switch (RECT_IN_REGION(pScreen, universe, &box))
150	{
151	case rgnIN:
152	    if (someOut)
153		return rgnPART;
154	    someIn = TRUE;
155	    break;
156	case rgnOUT:
157	    if (someIn)
158		return rgnPART;
159	    someOut = TRUE;
160	    break;
161	default:
162	    return rgnPART;
163	}
164	boundBox++;
165    }
166    if (someIn)
167	return rgnIN;
168    return rgnOUT;
169}
170#endif
171
172#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
173				    HasBorder(w) && \
174				    (w)->backgroundState == ParentRelative)
175
176
177/*
178 *-----------------------------------------------------------------------
179 * RootlessComputeClips --
180 *	Recompute the clipList, borderClip, exposed and borderExposed
181 *	regions for pParent and its children. Only viewable windows are
182 *	taken into account.
183 *
184 * Results:
185 *	None.
186 *
187 * Side Effects:
188 *	clipList, borderClip, exposed and borderExposed are altered.
189 *	A VisibilityNotify event may be generated on the parent window.
190 *
191 *-----------------------------------------------------------------------
192 */
193static void
194RootlessComputeClips (pParent, pScreen, universe, kind, exposed)
195    register WindowPtr	pParent;
196    register ScreenPtr	pScreen;
197    register RegionPtr	universe;
198    VTKind		kind;
199    RegionPtr		exposed; /* for intermediate calculations */
200{
201    int			dx,
202			dy;
203    RegionRec		childUniverse;
204    register WindowPtr	pChild;
205    int     	  	oldVis, newVis;
206    BoxRec		borderSize;
207    RegionRec		childUnion;
208    Bool		overlap;
209    RegionPtr		borderVisible;
210    Bool		resized;
211    /*
212     * Figure out the new visibility of this window.
213     * The extent of the universe should be the same as the extent of
214     * the borderSize region. If the window is unobscured, this rectangle
215     * will be completely inside the universe (the universe will cover it
216     * completely). If the window is completely obscured, none of the
217     * universe will cover the rectangle.
218     */
219    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
220    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
221    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
222    if (dx > 32767)
223	dx = 32767;
224    borderSize.x2 = dx;
225    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
226    if (dy > 32767)
227	dy = 32767;
228    borderSize.y2 = dy;
229
230    oldVis = pParent->visibility;
231    switch (RECT_IN_REGION( pScreen, universe, &borderSize))
232    {
233    case rgnIN:
234	    newVis = VisibilityUnobscured;
235	    break;
236	case rgnPART:
237	    newVis = VisibilityPartiallyObscured;
238#ifdef SHAPE
239	    {
240		RegionPtr   pBounding;
241
242		if ((pBounding = wBoundingShape (pParent)))
243		{
244		    switch (RootlessShapedWindowIn (pScreen, universe,
245						    pBounding, &borderSize,
246						    pParent->drawable.x,
247						    pParent->drawable.y))
248		    {
249		    case rgnIN:
250			newVis = VisibilityUnobscured;
251			break;
252		    case rgnOUT:
253			newVis = VisibilityFullyObscured;
254			break;
255		    }
256		}
257	    }
258#endif
259	    break;
260	default:
261	    newVis = VisibilityFullyObscured;
262	    break;
263    }
264
265    pParent->visibility = newVis;
266    if (oldVis != newVis &&
267	((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
268	SendVisibilityNotify(pParent);
269
270    dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
271    dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
272
273    /*
274     * avoid computations when dealing with simple operations
275     */
276
277    switch (kind) {
278    case VTMap:
279    case VTStack:
280    case VTUnmap:
281	break;
282    case VTMove:
283	if ((oldVis == newVis) &&
284	    ((oldVis == VisibilityFullyObscured) ||
285	     (oldVis == VisibilityUnobscured)))
286	{
287	    pChild = pParent;
288	    while (1)
289	    {
290		if (pChild->viewable)
291		{
292		    if (pChild->visibility != VisibilityFullyObscured)
293		    {
294			REGION_TRANSLATE( pScreen, &pChild->borderClip,
295						      dx, dy);
296			REGION_TRANSLATE( pScreen, &pChild->clipList,
297						      dx, dy);
298			pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
299			if (pScreen->ClipNotify)
300			    (* pScreen->ClipNotify) (pChild, dx, dy);
301
302		    }
303		    if (pChild->valdata)
304		    {
305			REGION_NULL(pScreen,
306				    &pChild->valdata->after.borderExposed);
307			if (HasParentRelativeBorder(pChild))
308			  {
309			    REGION_SUBTRACT(pScreen,
310					 &pChild->valdata->after.borderExposed,
311					 &pChild->borderClip,
312					 &pChild->winSize);
313			}
314			REGION_NULL(pScreen, &pChild->valdata->after.exposed);
315		    }
316		    if (pChild->firstChild)
317		    {
318			pChild = pChild->firstChild;
319			continue;
320		    }
321		}
322		while (!pChild->nextSib && (pChild != pParent))
323		    pChild = pChild->parent;
324		if (pChild == pParent)
325		    break;
326		pChild = pChild->nextSib;
327	    }
328	    return;
329	}
330	/* fall through */
331    default:
332    	/*
333     	 * To calculate exposures correctly, we have to translate the old
334     	 * borderClip and clipList regions to the window's new location so there
335     	 * is a correspondence between pieces of the new and old clipping regions.
336     	 */
337    	if (dx || dy)
338    	{
339	    /*
340	     * We translate the old clipList because that will be exposed or copied
341	     * if gravity is right.
342	     */
343	    REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy);
344	    REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy);
345    	}
346	break;
347    case VTBroken:
348	REGION_EMPTY (pScreen, &pParent->borderClip);
349	REGION_EMPTY (pScreen, &pParent->clipList);
350	break;
351    }
352
353    borderVisible = pParent->valdata->before.borderVisible;
354    resized = pParent->valdata->before.resized;
355    REGION_NULL(pScreen, &pParent->valdata->after.borderExposed);
356    REGION_NULL(pScreen, &pParent->valdata->after.exposed);
357
358    /*
359     * Since the borderClip must not be clipped by the children, we do
360     * the border exposure first...
361     *
362     * 'universe' is the window's borderClip. To figure the exposures, remove
363     * the area that used to be exposed from the new.
364     * This leaves a region of pieces that weren't exposed before.
365     */
366
367    if (HasBorder (pParent))
368    {
369    	if (borderVisible)
370    	{
371	    /*
372	     * when the border changes shape, the old visible portions
373	     * of the border will be saved by DIX in borderVisible --
374	     * use that region and destroy it
375	     */
376	    REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
377	    REGION_DESTROY( pScreen, borderVisible);
378    	}
379    	else
380    	{
381	    REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip);
382    	}
383	if (HasParentRelativeBorder(pParent) && (dx || dy)) {
384	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
385				  universe,
386				  &pParent->winSize);
387	} else {
388	    REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed,
389			       exposed, &pParent->winSize);
390	}
391
392    	REGION_COPY( pScreen, &pParent->borderClip, universe);
393
394    	/*
395     	 * To get the right clipList for the parent, and to make doubly sure
396     	 * that no child overlaps the parent's border, we remove the parent's
397     	 * border from the universe before proceeding.
398     	 */
399
400    	REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
401    }
402    else
403    	REGION_COPY( pScreen, &pParent->borderClip, universe);
404
405    if ((pChild = pParent->firstChild) && pParent->mapped)
406    {
407	REGION_NULL(pScreen, &childUniverse);
408	REGION_NULL(pScreen, &childUnion);
409	if ((pChild->drawable.y < pParent->lastChild->drawable.y) ||
410	    ((pChild->drawable.y == pParent->lastChild->drawable.y) &&
411	     (pChild->drawable.x < pParent->lastChild->drawable.x)))
412	{
413	    for (; pChild; pChild = pChild->nextSib)
414	    {
415		if (pChild->viewable)
416		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
417	    }
418	}
419	else
420	{
421	    for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
422	    {
423		if (pChild->viewable)
424		    REGION_APPEND( pScreen, &childUnion, &pChild->borderSize);
425	    }
426	}
427	REGION_VALIDATE( pScreen, &childUnion, &overlap);
428
429	for (pChild = pParent->firstChild;
430	     pChild;
431	     pChild = pChild->nextSib)
432 	{
433	    if (pChild->viewable) {
434		/*
435		 * If the child is viewable, we want to remove its extents
436		 * from the current universe, but we only re-clip it if
437		 * it's been marked.
438		 */
439		if (pChild->valdata) {
440		    /*
441		     * Figure out the new universe from the child's
442		     * perspective and recurse.
443		     */
444		    REGION_INTERSECT( pScreen, &childUniverse,
445					    universe,
446					    &pChild->borderSize);
447		    RootlessComputeClips (pChild, pScreen, &childUniverse,
448					  kind, exposed);
449		}
450		/*
451		 * Once the child has been processed, we remove its extents
452		 * from the current universe, thus denying its space to any
453		 * other sibling.
454		 */
455		if (overlap)
456		    REGION_SUBTRACT( pScreen, universe, universe,
457					  &pChild->borderSize);
458	    }
459	}
460	if (!overlap)
461	    REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
462	REGION_UNINIT( pScreen, &childUnion);
463	REGION_UNINIT( pScreen, &childUniverse);
464    } /* if any children */
465
466    /*
467     * 'universe' now contains the new clipList for the parent window.
468     *
469     * To figure the exposure of the window we subtract the old clip from the
470     * new, just as for the border.
471     */
472
473    if (oldVis == VisibilityFullyObscured ||
474	oldVis == VisibilityNotViewable)
475    {
476	REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe);
477    }
478    else if (newVis != VisibilityFullyObscured &&
479	     newVis != VisibilityNotViewable)
480    {
481    	REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed,
482			       universe, &pParent->clipList);
483    }
484
485    /*
486     * One last thing: backing storage. We have to try to save what parts of
487     * the window are about to be obscured. We can just subtract the universe
488     * from the old clipList and get the areas that were in the old but aren't
489     * in the new and, hence, are about to be obscured.
490     */
491    if (pParent->backStorage && !resized)
492    {
493	REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe);
494	(* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy);
495    }
496
497    /* HACK ALERT - copying contents of regions, instead of regions */
498    {
499	RegionRec   tmp;
500
501	tmp = pParent->clipList;
502	pParent->clipList = *universe;
503	*universe = tmp;
504    }
505
506#ifdef NOTDEF
507    REGION_COPY( pScreen, &pParent->clipList, universe);
508#endif
509
510    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
511
512    if (pScreen->ClipNotify)
513	(* pScreen->ClipNotify) (pParent, dx, dy);
514}
515
516static void
517RootlessTreeObscured(pParent)
518    register WindowPtr pParent;
519{
520    register WindowPtr pChild;
521    register int    oldVis;
522
523    pChild = pParent;
524    while (1)
525    {
526	if (pChild->viewable)
527	{
528	    oldVis = pChild->visibility;
529	    if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
530		((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
531		SendVisibilityNotify(pChild);
532	    if (pChild->firstChild)
533	    {
534		pChild = pChild->firstChild;
535		continue;
536	    }
537	}
538	while (!pChild->nextSib && (pChild != pParent))
539	    pChild = pChild->parent;
540	if (pChild == pParent)
541	    break;
542	pChild = pChild->nextSib;
543    }
544}
545
546/*
547 *-----------------------------------------------------------------------
548 * RootlessMiValidateTree --
549 *	Recomputes the clip list for pParent and all its inferiors.
550 *
551 * Results:
552 *	Always returns 1.
553 *
554 * Side Effects:
555 *	The clipList, borderClip, exposed, and borderExposed regions for
556 *	each marked window are altered.
557 *
558 * Notes:
559 *	This routine assumes that all affected windows have been marked
560 *	(valdata created) and their winSize and borderSize regions
561 *	adjusted to correspond to their new positions. The borderClip and
562 *	clipList regions should not have been touched.
563 *
564 *	The top-most level is treated differently from all lower levels
565 *	because pParent is unchanged. For the top level, we merge the
566 *	regions taken up by the marked children back into the clipList
567 *	for pParent, thus forming a region from which the marked children
568 *	can claim their areas. For lower levels, where the old clipList
569 *	and borderClip are invalid, we can't do this and have to do the
570 *	extra operations done in miComputeClips, but this is much faster
571 *	e.g. when only one child has moved...
572 *
573 *-----------------------------------------------------------------------
574 */
575/*
576   Quartz version: used for validate from root in rootless mode.
577   We need to make sure top-level windows don't clip each other,
578   and that top-level windows aren't clipped to the root window.
579*/
580/*ARGSUSED*/
581// fixme this is ugly
582// Xprint/ValTree.c doesn't work, but maybe that method can?
583int
584RootlessMiValidateTree (pRoot, pChild, kind)
585    WindowPtr	  	pRoot;      /* Parent to validate */
586    WindowPtr	  	pChild;     /* First child of pRoot that was
587				     * affected */
588    VTKind    	  	kind;       /* What kind of configuration caused call */
589{
590    RegionRec	  	childClip;  /* The new borderClip for the current
591				     * child */
592    RegionRec		exposed;    /* For intermediate calculations */
593    register ScreenPtr	pScreen;
594    register WindowPtr	pWin;
595
596    pScreen = pRoot->drawable.pScreen;
597    if (pChild == NullWindow)
598	pChild = pRoot->firstChild;
599
600    REGION_NULL(pScreen, &childClip);
601    REGION_NULL(pScreen, &exposed);
602
603    if (REGION_BROKEN (pScreen, &pRoot->clipList) &&
604	!REGION_BROKEN (pScreen, &pRoot->borderClip))
605    {
606        // fixme this might not work, but hopefully doesn't happen anyway.
607        kind = VTBroken;
608        REGION_EMPTY (pScreen, &pRoot->clipList);
609        ErrorF("ValidateTree: BUSTED!\n");
610    }
611
612    /*
613     * Recursively compute the clips for all children of the root.
614     * They don't clip against each other or the root itself, so
615     * childClip is always reset to that child's size.
616     */
617
618    for (pWin = pChild;
619	 pWin != NullWindow;
620	 pWin = pWin->nextSib)
621    {
622        if (pWin->viewable) {
623            if (pWin->valdata) {
624                REGION_COPY( pScreen, &childClip, &pWin->borderSize);
625                RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed);
626            } else if (pWin->visibility == VisibilityNotViewable) {
627                RootlessTreeObscured(pWin);
628            }
629        } else {
630            if (pWin->valdata) {
631                REGION_EMPTY( pScreen, &pWin->clipList);
632                if (pScreen->ClipNotify)
633                    (* pScreen->ClipNotify) (pWin, 0, 0);
634                REGION_EMPTY( pScreen, &pWin->borderClip);
635                pWin->valdata = (ValidatePtr)NULL;
636            }
637        }
638    }
639
640    REGION_UNINIT(pScreen, &childClip);
641
642    /* The root is never clipped by its children, so nothing on the root
643       is ever exposed by moving or mapping its children. */
644    REGION_NULL(pScreen, &pRoot->valdata->after.exposed);
645    REGION_NULL(pScreen, &pRoot->valdata->after.borderExposed);
646
647    return 1;
648}
649