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