Imported Upstream version 1.15.1
[deb_xorg-server.git] / miext / rootless / rootlessValTree.c
CommitLineData
a09e091a
JB
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 if ((t = boundBox->x1 + x) < x1)
131 t = x1;
132 box.x1 = t;
133 if ((t = boundBox->y1 + y) < y1)
134 t = y1;
135 box.y1 = t;
136 if ((t = boundBox->x2 + x) > x2)
137 t = x2;
138 box.x2 = t;
139 if ((t = boundBox->y2 + y) > y2)
140 t = y2;
141 box.y2 = t;
142 if (box.x1 > box.x2)
143 box.x2 = box.x1;
144 if (box.y1 > box.y2)
145 box.y2 = box.y1;
146 switch (RegionContainsRect(universe, &box)) {
147 case rgnIN:
148 if (someOut)
149 return rgnPART;
150 someIn = TRUE;
151 break;
152 case rgnOUT:
153 if (someIn)
154 return rgnPART;
155 someOut = TRUE;
156 break;
157 default:
158 return rgnPART;
159 }
160 boundBox++;
161 }
162 if (someIn)
163 return rgnIN;
164 return rgnOUT;
165}
166
167#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
168 HasBorder(w) && \
169 (w)->backgroundState == ParentRelative)
170
171/*
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.
177 *
178 * Results:
179 * None.
180 *
181 * Side Effects:
182 * clipList, borderClip, exposed and borderExposed are altered.
183 * A VisibilityNotify event may be generated on the parent window.
184 *
185 *-----------------------------------------------------------------------
186 */
187static void
188RootlessComputeClips(WindowPtr pParent, ScreenPtr pScreen,
189 RegionPtr universe, VTKind kind, RegionPtr exposed)
190{
191 int dx, dy;
192 RegionRec childUniverse;
193 register WindowPtr pChild;
194 int oldVis, newVis;
195 BoxRec borderSize;
196 RegionRec childUnion;
197 Bool overlap;
198 RegionPtr borderVisible;
199
200 /*
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.
207 */
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);
212 if (dx > 32767)
213 dx = 32767;
214 borderSize.x2 = dx;
215 dy = (int) pParent->drawable.y + (int) pParent->drawable.height +
216 wBorderWidth(pParent);
217 if (dy > 32767)
218 dy = 32767;
219 borderSize.y2 = dy;
220
221 oldVis = pParent->visibility;
222 switch (RegionContainsRect(universe, &borderSize)) {
223 case rgnIN:
224 newVis = VisibilityUnobscured;
225 break;
226 case rgnPART:
227 newVis = VisibilityPartiallyObscured;
228 {
229 RegionPtr pBounding;
230
231 if ((pBounding = wBoundingShape(pParent))) {
232 switch (RootlessShapedWindowIn(universe,
233 pBounding, &borderSize,
234 pParent->drawable.x,
235 pParent->drawable.y)) {
236 case rgnIN:
237 newVis = VisibilityUnobscured;
238 break;
239 case rgnOUT:
240 newVis = VisibilityFullyObscured;
241 break;
242 }
243 }
244 }
245 break;
246 default:
247 newVis = VisibilityFullyObscured;
248 break;
249 }
250
251 pParent->visibility = newVis;
252 if (oldVis != newVis &&
253 ((pParent->
254 eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask))
255 SendVisibilityNotify(pParent);
256
257 dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x;
258 dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y;
259
260 /*
261 * avoid computations when dealing with simple operations
262 */
263
264 switch (kind) {
265 case VTMap:
266 case VTStack:
267 case VTUnmap:
268 break;
269 case VTMove:
270 if ((oldVis == newVis) &&
271 ((oldVis == VisibilityFullyObscured) ||
272 (oldVis == VisibilityUnobscured))) {
273 pChild = pParent;
274 while (1) {
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);
282
283 }
284 if (pChild->valdata) {
285 RegionNull(&pChild->valdata->after.borderExposed);
286 if (HasParentRelativeBorder(pChild)) {
287 RegionSubtract(&pChild->valdata->after.
288 borderExposed, &pChild->borderClip,
289 &pChild->winSize);
290 }
291 RegionNull(&pChild->valdata->after.exposed);
292 }
293 if (pChild->firstChild) {
294 pChild = pChild->firstChild;
295 continue;
296 }
297 }
298 while (!pChild->nextSib && (pChild != pParent))
299 pChild = pChild->parent;
300 if (pChild == pParent)
301 break;
302 pChild = pChild->nextSib;
303 }
304 return;
305 }
306 /* fall through */
307 default:
308 /*
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.
312 */
313 if (dx || dy) {
314 /*
315 * We translate the old clipList because that will be exposed or copied
316 * if gravity is right.
317 */
318 RegionTranslate(&pParent->borderClip, dx, dy);
319 RegionTranslate(&pParent->clipList, dx, dy);
320 }
321 break;
322 case VTBroken:
323 RegionEmpty(&pParent->borderClip);
324 RegionEmpty(&pParent->clipList);
325 break;
326 }
327
328 borderVisible = pParent->valdata->before.borderVisible;
329 RegionNull(&pParent->valdata->after.borderExposed);
330 RegionNull(&pParent->valdata->after.exposed);
331
332 /*
333 * Since the borderClip must not be clipped by the children, we do
334 * the border exposure first...
335 *
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.
339 */
340
341 if (HasBorder(pParent)) {
342 if (borderVisible) {
343 /*
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
347 */
348 RegionSubtract(exposed, universe, borderVisible);
349 RegionDestroy(borderVisible);
350 }
351 else {
352 RegionSubtract(exposed, universe, &pParent->borderClip);
353 }
354 if (HasParentRelativeBorder(pParent) && (dx || dy)) {
355 RegionSubtract(&pParent->valdata->after.borderExposed,
356 universe, &pParent->winSize);
357 }
358 else {
359 RegionSubtract(&pParent->valdata->after.borderExposed,
360 exposed, &pParent->winSize);
361 }
362
363 RegionCopy(&pParent->borderClip, universe);
364
365 /*
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.
369 */
370
371 RegionIntersect(universe, universe, &pParent->winSize);
372 }
373 else
374 RegionCopy(&pParent->borderClip, universe);
375
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);
385 }
386 }
387 else {
388 for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) {
389 if (pChild->viewable)
390 RegionAppend(&childUnion, &pChild->borderSize);
391 }
392 }
393 RegionValidate(&childUnion, &overlap);
394
395 for (pChild = pParent->firstChild; pChild; pChild = pChild->nextSib) {
396 if (pChild->viewable) {
397 /*
398 * If the child is viewable, we want to remove its extents
399 * from the current universe, but we only re-clip it if
400 * it's been marked.
401 */
402 if (pChild->valdata) {
403 /*
404 * Figure out the new universe from the child's
405 * perspective and recurse.
406 */
407 RegionIntersect(&childUniverse,
408 universe, &pChild->borderSize);
409 RootlessComputeClips(pChild, pScreen, &childUniverse,
410 kind, exposed);
411 }
412 /*
413 * Once the child has been processed, we remove its extents
414 * from the current universe, thus denying its space to any
415 * other sibling.
416 */
417 if (overlap)
418 RegionSubtract(universe, universe, &pChild->borderSize);
419 }
420 }
421 if (!overlap)
422 RegionSubtract(universe, universe, &childUnion);
423 RegionUninit(&childUnion);
424 RegionUninit(&childUniverse);
425 } /* if any children */
426
427 /*
428 * 'universe' now contains the new clipList for the parent window.
429 *
430 * To figure the exposure of the window we subtract the old clip from the
431 * new, just as for the border.
432 */
433
434 if (oldVis == VisibilityFullyObscured || oldVis == VisibilityNotViewable) {
435 RegionCopy(&pParent->valdata->after.exposed, universe);
436 }
437 else if (newVis != VisibilityFullyObscured &&
438 newVis != VisibilityNotViewable) {
439 RegionSubtract(&pParent->valdata->after.exposed,
440 universe, &pParent->clipList);
441 }
442
443 /* HACK ALERT - copying contents of regions, instead of regions */
444 {
445 RegionRec tmp;
446
447 tmp = pParent->clipList;
448 pParent->clipList = *universe;
449 *universe = tmp;
450 }
451
452#ifdef NOTDEF
453 RegionCopy(&pParent->clipList, universe);
454#endif
455
456 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
457
458 if (pScreen->ClipNotify)
459 (*pScreen->ClipNotify) (pParent, dx, dy);
460}
461
462static void
463RootlessTreeObscured(WindowPtr pParent)
464{
465 register WindowPtr pChild;
466 register int oldVis;
467
468 pChild = pParent;
469 while (1) {
470 if (pChild->viewable) {
471 oldVis = pChild->visibility;
472 if (oldVis != (pChild->visibility = VisibilityFullyObscured) &&
473 ((pChild->
474 eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask))
475 SendVisibilityNotify(pChild);
476 if (pChild->firstChild) {
477 pChild = pChild->firstChild;
478 continue;
479 }
480 }
481 while (!pChild->nextSib && (pChild != pParent))
482 pChild = pChild->parent;
483 if (pChild == pParent)
484 break;
485 pChild = pChild->nextSib;
486 }
487}
488
489/*
490 *-----------------------------------------------------------------------
491 * RootlessMiValidateTree --
492 * Recomputes the clip list for pParent and all its inferiors.
493 *
494 * Results:
495 * Always returns 1.
496 *
497 * Side Effects:
498 * The clipList, borderClip, exposed, and borderExposed regions for
499 * each marked window are altered.
500 *
501 * Notes:
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.
506 *
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...
515 *
516 *-----------------------------------------------------------------------
517 */
518/*
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.
522*/
523 /*ARGSUSED*/
524// fixme this is ugly
525// Xprint/ValTree.c doesn't work, but maybe that method can?
526 int
527RootlessMiValidateTree(WindowPtr pRoot, /* Parent to validate */
528 WindowPtr pChild, /* First child of pRoot that was
529 * affected */
530 VTKind kind /* What kind of configuration caused call */
531 )
532{
533 RegionRec childClip; /* The new borderClip for the current
534 * child */
535 RegionRec exposed; /* For intermediate calculations */
536 register ScreenPtr pScreen;
537 register WindowPtr pWin;
538
539 pScreen = pRoot->drawable.pScreen;
540 if (pChild == NullWindow)
541 pChild = pRoot->firstChild;
542
543 RegionNull(&childClip);
544 RegionNull(&exposed);
545
546 if (RegionBroken(&pRoot->clipList) && !RegionBroken(&pRoot->borderClip)) {
547 // fixme this might not work, but hopefully doesn't happen anyway.
548 kind = VTBroken;
549 RegionEmpty(&pRoot->clipList);
550 ErrorF("ValidateTree: BUSTED!\n");
551 }
552
553 /*
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.
557 */
558
559 for (pWin = pChild; pWin != NullWindow; pWin = pWin->nextSib) {
560 if (pWin->viewable) {
561 if (pWin->valdata) {
562 RegionCopy(&childClip, &pWin->borderSize);
563 RootlessComputeClips(pWin, pScreen, &childClip, kind, &exposed);
564 }
565 else if (pWin->visibility == VisibilityNotViewable) {
566 RootlessTreeObscured(pWin);
567 }
568 }
569 else {
570 if (pWin->valdata) {
571 RegionEmpty(&pWin->clipList);
572 if (pScreen->ClipNotify)
573 (*pScreen->ClipNotify) (pWin, 0, 0);
574 RegionEmpty(&pWin->borderClip);
575 pWin->valdata = NULL;
576 }
577 }
578 }
579
580 RegionUninit(&childClip);
581
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);
586
587 return 1;
588}