rootlessValTree.c revision 9ace9065
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
107int RootlessMiValidateTree (WindowPtr pRoot, WindowPtr pChild, VTKind kind);
108
109/*
110 * Compute the visibility of a shaped window
111 */
112static int
113RootlessShapedWindowIn (RegionPtr universe,
114			RegionPtr bounding, BoxPtr rect, int x, int y)
115{
116    BoxRec  box;
117    register BoxPtr  boundBox;
118    int	    nbox;
119    Bool    someIn, someOut;
120    register int t, x1, y1, x2, y2;
121
122    nbox = RegionNumRects (bounding);
123    boundBox = RegionRects (bounding);
124    someIn = someOut = FALSE;
125    x1 = rect->x1;
126    y1 = rect->y1;
127    x2 = rect->x2;
128    y2 = rect->y2;
129    while (nbox--)
130    {
131	if ((t = boundBox->x1 + x) < x1)
132	    t = x1;
133	box.x1 = t;
134	if ((t = boundBox->y1 + y) < y1)
135	    t = y1;
136	box.y1 = t;
137	if ((t = boundBox->x2 + x) > x2)
138	    t = x2;
139	box.x2 = t;
140	if ((t = boundBox->y2 + y) > y2)
141	    t = y2;
142	box.y2 = t;
143	if (box.x1 > box.x2)
144	    box.x2 = box.x1;
145	if (box.y1 > box.y2)
146	    box.y2 = box.y1;
147	switch (RegionContainsRect(universe, &box))
148	{
149	case rgnIN:
150	    if (someOut)
151		return rgnPART;
152	    someIn = TRUE;
153	    break;
154	case rgnOUT:
155	    if (someIn)
156		return rgnPART;
157	    someOut = TRUE;
158	    break;
159	default:
160	    return rgnPART;
161	}
162	boundBox++;
163    }
164    if (someIn)
165	return rgnIN;
166    return rgnOUT;
167}
168
169#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
170				    HasBorder(w) && \
171				    (w)->backgroundState == ParentRelative)
172
173
174/*
175 *-----------------------------------------------------------------------
176 * RootlessComputeClips --
177 *	Recompute the clipList, borderClip, exposed and borderExposed
178 *	regions for pParent and its children. Only viewable windows are
179 *	taken into account.
180 *
181 * Results:
182 *	None.
183 *
184 * Side Effects:
185 *	clipList, borderClip, exposed and borderExposed are altered.
186 *	A VisibilityNotify event may be generated on the parent window.
187 *
188 *-----------------------------------------------------------------------
189 */
190static void
191RootlessComputeClips (WindowPtr pParent, ScreenPtr pScreen,
192		      RegionPtr universe, VTKind kind, RegionPtr exposed)
193{
194    int			dx,
195			dy;
196    RegionRec		childUniverse;
197    register WindowPtr	pChild;
198    int     	  	oldVis, newVis;
199    BoxRec		borderSize;
200    RegionRec		childUnion;
201    Bool		overlap;
202    RegionPtr		borderVisible;
203    Bool		resized;
204    /*
205     * Figure out the new visibility of this window.
206     * The extent of the universe should be the same as the extent of
207     * the borderSize region. If the window is unobscured, this rectangle
208     * will be completely inside the universe (the universe will cover it
209     * completely). If the window is completely obscured, none of the
210     * universe will cover the rectangle.
211     */
212    borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
213    borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
214    dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent);
215    if (dx > 32767)
216	dx = 32767;
217    borderSize.x2 = dx;
218    dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent);
219    if (dy > 32767)
220	dy = 32767;
221    borderSize.y2 = dy;
222
223    oldVis = pParent->visibility;
224    switch (RegionContainsRect(universe, &borderSize))
225    {
226    case rgnIN:
227	    newVis = VisibilityUnobscured;
228	    break;
229	case rgnPART:
230	    newVis = VisibilityPartiallyObscured;
231	    {
232		RegionPtr   pBounding;
233
234		if ((pBounding = wBoundingShape (pParent)))
235		{
236		    switch (RootlessShapedWindowIn (universe,
237						    pBounding, &borderSize,
238						    pParent->drawable.x,
239						    pParent->drawable.y))
240		    {
241		    case rgnIN:
242			newVis = VisibilityUnobscured;
243			break;
244		    case rgnOUT:
245			newVis = VisibilityFullyObscured;
246			break;
247		    }
248		}
249	    }
250	    break;
251	default:
252	    newVis = VisibilityFullyObscured;
253	    break;
254    }
255
256    pParent->visibility = newVis;
257    if (oldVis != newVis &&
258	((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
259	SendVisibilityNotify(pParent);
260
261    dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
262    dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
263
264    /*
265     * avoid computations when dealing with simple operations
266     */
267
268    switch (kind) {
269    case VTMap:
270    case VTStack:
271    case VTUnmap:
272	break;
273    case VTMove:
274	if ((oldVis == newVis) &&
275	    ((oldVis == VisibilityFullyObscured) ||
276	     (oldVis == VisibilityUnobscured)))
277	{
278	    pChild = pParent;
279	    while (1)
280	    {
281		if (pChild->viewable)
282		{
283		    if (pChild->visibility != VisibilityFullyObscured)
284		    {
285			RegionTranslate(&pChild->borderClip,
286						      dx, dy);
287			RegionTranslate(&pChild->clipList,
288						      dx, dy);
289			pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
290			if (pScreen->ClipNotify)
291			    (* pScreen->ClipNotify) (pChild, dx, dy);
292
293		    }
294		    if (pChild->valdata)
295		    {
296			RegionNull(&pChild->valdata->after.borderExposed);
297			if (HasParentRelativeBorder(pChild))
298			  {
299			    RegionSubtract(&pChild->valdata->after.borderExposed,
300					   &pChild->borderClip,
301					   &pChild->winSize);
302			}
303			RegionNull(&pChild->valdata->after.exposed);
304		    }
305		    if (pChild->firstChild)
306		    {
307			pChild = pChild->firstChild;
308			continue;
309		    }
310		}
311		while (!pChild->nextSib && (pChild != pParent))
312		    pChild = pChild->parent;
313		if (pChild == pParent)
314		    break;
315		pChild = pChild->nextSib;
316	    }
317	    return;
318	}
319	/* fall through */
320    default:
321    	/*
322     	 * To calculate exposures correctly, we have to translate the old
323     	 * borderClip and clipList regions to the window's new location so there
324     	 * is a correspondence between pieces of the new and old clipping regions.
325     	 */
326    	if (dx || dy)
327    	{
328	    /*
329	     * We translate the old clipList because that will be exposed or copied
330	     * if gravity is right.
331	     */
332	    RegionTranslate(&pParent->borderClip, dx, dy);
333	    RegionTranslate(&pParent->clipList, dx, dy);
334    	}
335	break;
336    case VTBroken:
337	RegionEmpty(&pParent->borderClip);
338	RegionEmpty(&pParent->clipList);
339	break;
340    }
341
342    borderVisible = pParent->valdata->before.borderVisible;
343    resized = pParent->valdata->before.resized;
344    RegionNull(&pParent->valdata->after.borderExposed);
345    RegionNull(&pParent->valdata->after.exposed);
346
347    /*
348     * Since the borderClip must not be clipped by the children, we do
349     * the border exposure first...
350     *
351     * 'universe' is the window's borderClip. To figure the exposures, remove
352     * the area that used to be exposed from the new.
353     * This leaves a region of pieces that weren't exposed before.
354     */
355
356    if (HasBorder (pParent))
357    {
358    	if (borderVisible)
359    	{
360	    /*
361	     * when the border changes shape, the old visible portions
362	     * of the border will be saved by DIX in borderVisible --
363	     * use that region and destroy it
364	     */
365	    RegionSubtract(exposed, universe, borderVisible);
366	    RegionDestroy(borderVisible);
367    	}
368    	else
369    	{
370	    RegionSubtract(exposed, universe, &pParent->borderClip);
371    	}
372	if (HasParentRelativeBorder(pParent) && (dx || dy)) {
373	    RegionSubtract(&pParent->valdata->after.borderExposed,
374				  universe,
375				  &pParent->winSize);
376	} else {
377	    RegionSubtract(&pParent->valdata->after.borderExposed,
378			       exposed, &pParent->winSize);
379	}
380
381	RegionCopy(&pParent->borderClip, universe);
382
383    	/*
384     	 * To get the right clipList for the parent, and to make doubly sure
385     	 * that no child overlaps the parent's border, we remove the parent's
386     	 * border from the universe before proceeding.
387     	 */
388
389	RegionIntersect(universe, universe, &pParent->winSize);
390    }
391    else
392	RegionCopy(&pParent->borderClip, universe);
393
394    if ((pChild = pParent->firstChild) && pParent->mapped)
395    {
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	{
402	    for (; pChild; pChild = pChild->nextSib)
403	    {
404		if (pChild->viewable)
405		    RegionAppend(&childUnion, &pChild->borderSize);
406	    }
407	}
408	else
409	{
410	    for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib)
411	    {
412		if (pChild->viewable)
413		    RegionAppend(&childUnion, &pChild->borderSize);
414	    }
415	}
416	RegionValidate(&childUnion, &overlap);
417
418	for (pChild = pParent->firstChild;
419	     pChild;
420	     pChild = pChild->nextSib)
421 	{
422	    if (pChild->viewable) {
423		/*
424		 * If the child is viewable, we want to remove its extents
425		 * from the current universe, but we only re-clip it if
426		 * it's been marked.
427		 */
428		if (pChild->valdata) {
429		    /*
430		     * Figure out the new universe from the child's
431		     * perspective and recurse.
432		     */
433		    RegionIntersect(&childUniverse,
434					    universe,
435					    &pChild->borderSize);
436		    RootlessComputeClips (pChild, pScreen, &childUniverse,
437					  kind, exposed);
438		}
439		/*
440		 * Once the child has been processed, we remove its extents
441		 * from the current universe, thus denying its space to any
442		 * other sibling.
443		 */
444		if (overlap)
445		    RegionSubtract(universe, universe,
446					  &pChild->borderSize);
447	    }
448	}
449	if (!overlap)
450	    RegionSubtract(universe, universe, &childUnion);
451	RegionUninit(&childUnion);
452	RegionUninit(&childUniverse);
453    } /* if any children */
454
455    /*
456     * 'universe' now contains the new clipList for the parent window.
457     *
458     * To figure the exposure of the window we subtract the old clip from the
459     * new, just as for the border.
460     */
461
462    if (oldVis == VisibilityFullyObscured ||
463	oldVis == VisibilityNotViewable)
464    {
465	RegionCopy(&pParent->valdata->after.exposed, universe);
466    }
467    else if (newVis != VisibilityFullyObscured &&
468	     newVis != VisibilityNotViewable)
469    {
470	RegionSubtract(&pParent->valdata->after.exposed,
471			       universe, &pParent->clipList);
472    }
473
474    /* HACK ALERT - copying contents of regions, instead of regions */
475    {
476	RegionRec   tmp;
477
478	tmp = pParent->clipList;
479	pParent->clipList = *universe;
480	*universe = tmp;
481    }
482
483#ifdef NOTDEF
484    RegionCopy(&pParent->clipList, universe);
485#endif
486
487    pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
488
489    if (pScreen->ClipNotify)
490	(* pScreen->ClipNotify) (pParent, dx, dy);
491}
492
493static void
494RootlessTreeObscured(WindowPtr pParent)
495{
496    register WindowPtr pChild;
497    register int    oldVis;
498
499    pChild = pParent;
500    while (1)
501    {
502	if (pChild->viewable)
503	{
504	    oldVis = pChild->visibility;
505	    if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
506		((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
507		SendVisibilityNotify(pChild);
508	    if (pChild->firstChild)
509	    {
510		pChild = pChild->firstChild;
511		continue;
512	    }
513	}
514	while (!pChild->nextSib && (pChild != pParent))
515	    pChild = pChild->parent;
516	if (pChild == pParent)
517	    break;
518	pChild = pChild->nextSib;
519    }
520}
521
522/*
523 *-----------------------------------------------------------------------
524 * RootlessMiValidateTree --
525 *	Recomputes the clip list for pParent and all its inferiors.
526 *
527 * Results:
528 *	Always returns 1.
529 *
530 * Side Effects:
531 *	The clipList, borderClip, exposed, and borderExposed regions for
532 *	each marked window are altered.
533 *
534 * Notes:
535 *	This routine assumes that all affected windows have been marked
536 *	(valdata created) and their winSize and borderSize regions
537 *	adjusted to correspond to their new positions. The borderClip and
538 *	clipList regions should not have been touched.
539 *
540 *	The top-most level is treated differently from all lower levels
541 *	because pParent is unchanged. For the top level, we merge the
542 *	regions taken up by the marked children back into the clipList
543 *	for pParent, thus forming a region from which the marked children
544 *	can claim their areas. For lower levels, where the old clipList
545 *	and borderClip are invalid, we can't do this and have to do the
546 *	extra operations done in miComputeClips, but this is much faster
547 *	e.g. when only one child has moved...
548 *
549 *-----------------------------------------------------------------------
550 */
551/*
552   Quartz version: used for validate from root in rootless mode.
553   We need to make sure top-level windows don't clip each other,
554   and that top-level windows aren't clipped to the root window.
555*/
556/*ARGSUSED*/
557// fixme this is ugly
558// Xprint/ValTree.c doesn't work, but maybe that method can?
559int
560RootlessMiValidateTree (WindowPtr pRoot, /* Parent to validate */
561			WindowPtr pChild, /* First child of pRoot that was
562					   * affected */
563			VTKind kind /* What kind of configuration caused call */)
564{
565    RegionRec	  	childClip;  /* The new borderClip for the current
566				     * child */
567    RegionRec		exposed;    /* For intermediate calculations */
568    register ScreenPtr	pScreen;
569    register WindowPtr	pWin;
570
571    pScreen = pRoot->drawable.pScreen;
572    if (pChild == NullWindow)
573	pChild = pRoot->firstChild;
574
575    RegionNull(&childClip);
576    RegionNull(&exposed);
577
578    if (RegionBroken(&pRoot->clipList) &&
579	!RegionBroken(&pRoot->borderClip))
580    {
581        // fixme this might not work, but hopefully doesn't happen anyway.
582        kind = VTBroken;
583        RegionEmpty(&pRoot->clipList);
584        ErrorF("ValidateTree: BUSTED!\n");
585    }
586
587    /*
588     * Recursively compute the clips for all children of the root.
589     * They don't clip against each other or the root itself, so
590     * childClip is always reset to that child's size.
591     */
592
593    for (pWin = pChild;
594	 pWin != NullWindow;
595	 pWin = pWin->nextSib)
596    {
597        if (pWin->viewable) {
598            if (pWin->valdata) {
599                RegionCopy(&childClip, &pWin->borderSize);
600                RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed);
601            } else if (pWin->visibility == VisibilityNotViewable) {
602                RootlessTreeObscured(pWin);
603            }
604        } else {
605            if (pWin->valdata) {
606                RegionEmpty(&pWin->clipList);
607                if (pScreen->ClipNotify)
608                    (* pScreen->ClipNotify) (pWin, 0, 0);
609                RegionEmpty(&pWin->borderClip);
610                pWin->valdata = NULL;
611            }
612        }
613    }
614
615    RegionUninit(&childClip);
616
617    /* The root is never clipped by its children, so nothing on the root
618       is ever exposed by moving or mapping its children. */
619    RegionNull(&pRoot->valdata->after.exposed);
620    RegionNull(&pRoot->valdata->after.borderExposed);
621
622    return 1;
623}
624