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