Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * mivaltree.c -- | |
3 | * Functions for recalculating window clip lists. Main function | |
4 | * is miValidateTree. | |
5 | * | |
6 | ||
7 | Copyright 1987, 1988, 1989, 1998 The Open Group | |
8 | ||
9 | Permission to use, copy, modify, distribute, and sell this software and its | |
10 | documentation for any purpose is hereby granted without fee, provided that | |
11 | the above copyright notice appear in all copies and that both that | |
12 | copyright notice and this permission notice appear in supporting | |
13 | documentation. | |
14 | ||
15 | The above copyright notice and this permission notice shall be included in | |
16 | all copies or substantial portions of the Software. | |
17 | ||
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
21 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |
22 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
24 | ||
25 | Except as contained in this notice, the name of The Open Group shall not be | |
26 | used in advertising or otherwise to promote the sale, use or other dealings | |
27 | in this Software without prior written authorization from The Open Group. | |
28 | ||
29 | * | |
30 | * Copyright 1987, 1988, 1989 by | |
31 | * Digital Equipment Corporation, Maynard, Massachusetts, | |
32 | * | |
33 | * All Rights Reserved | |
34 | * | |
35 | * Permission to use, copy, modify, and distribute this software and its | |
36 | * documentation for any purpose and without fee is hereby granted, | |
37 | * provided that the above copyright notice appear in all copies and that | |
38 | * both that copyright notice and this permission notice appear in | |
39 | * supporting documentation, and that the name of Digital not be | |
40 | * used in advertising or publicity pertaining to distribution of the | |
41 | * software without specific, written prior permission. | |
42 | * | |
43 | * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
44 | * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
45 | * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
46 | * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
47 | * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
48 | * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
49 | * SOFTWARE. | |
50 | * | |
51 | ******************************************************************/ | |
52 | ||
53 | /* The panoramix components contained the following notice */ | |
54 | /***************************************************************** | |
55 | ||
56 | Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. | |
57 | ||
58 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
59 | of this software and associated documentation files (the "Software"), to deal | |
60 | in the Software without restriction, including without limitation the rights | |
61 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
62 | copies of the Software. | |
63 | ||
64 | The above copyright notice and this permission notice shall be included in | |
65 | all copies or substantial portions of the Software. | |
66 | ||
67 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
68 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
69 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
70 | DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, | |
71 | BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, | |
72 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |
73 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
74 | ||
75 | Except as contained in this notice, the name of Digital Equipment Corporation | |
76 | shall not be used in advertising or otherwise to promote the sale, use or other | |
77 | dealings in this Software without prior written authorization from Digital | |
78 | Equipment Corporation. | |
79 | ||
80 | ******************************************************************/ | |
81 | ||
82 | /* | |
83 | * Aug '86: Susan Angebranndt -- original code | |
84 | * July '87: Adam de Boor -- substantially modified and commented | |
85 | * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible. | |
86 | * In particular, much improved code for window mapping and | |
87 | * circulating. | |
88 | * Bob Scheifler -- avoid miComputeClips for unmapped windows, | |
89 | * valdata changes | |
90 | */ | |
91 | #ifdef HAVE_DIX_CONFIG_H | |
92 | #include <dix-config.h> | |
93 | #endif | |
94 | ||
95 | #include <X11/X.h> | |
96 | #include "scrnintstr.h" | |
97 | #include "validate.h" | |
98 | #include "windowstr.h" | |
99 | #include "mi.h" | |
100 | #include "regionstr.h" | |
101 | #include "mivalidate.h" | |
102 | ||
103 | #include "globals.h" | |
104 | ||
105 | /* | |
106 | * Compute the visibility of a shaped window | |
107 | */ | |
108 | int | |
109 | miShapedWindowIn(RegionPtr universe, RegionPtr bounding, | |
110 | BoxPtr rect, int x, int y) | |
111 | { | |
112 | BoxRec box; | |
113 | BoxPtr boundBox; | |
114 | int nbox; | |
115 | Bool someIn, someOut; | |
116 | int t, x1, y1, x2, y2; | |
117 | ||
118 | nbox = RegionNumRects(bounding); | |
119 | boundBox = RegionRects(bounding); | |
120 | someIn = someOut = FALSE; | |
121 | x1 = rect->x1; | |
122 | y1 = rect->y1; | |
123 | x2 = rect->x2; | |
124 | y2 = rect->y2; | |
125 | while (nbox--) { | |
126 | if ((t = boundBox->x1 + x) < x1) | |
127 | t = x1; | |
128 | box.x1 = t; | |
129 | if ((t = boundBox->y1 + y) < y1) | |
130 | t = y1; | |
131 | box.y1 = t; | |
132 | if ((t = boundBox->x2 + x) > x2) | |
133 | t = x2; | |
134 | box.x2 = t; | |
135 | if ((t = boundBox->y2 + y) > y2) | |
136 | t = y2; | |
137 | box.y2 = t; | |
138 | if (box.x1 > box.x2) | |
139 | box.x2 = box.x1; | |
140 | if (box.y1 > box.y2) | |
141 | box.y2 = box.y1; | |
142 | switch (RegionContainsRect(universe, &box)) { | |
143 | case rgnIN: | |
144 | if (someOut) | |
145 | return rgnPART; | |
146 | someIn = TRUE; | |
147 | break; | |
148 | case rgnOUT: | |
149 | if (someIn) | |
150 | return rgnPART; | |
151 | someOut = TRUE; | |
152 | break; | |
153 | default: | |
154 | return rgnPART; | |
155 | } | |
156 | boundBox++; | |
157 | } | |
158 | if (someIn) | |
159 | return rgnIN; | |
160 | return rgnOUT; | |
161 | } | |
162 | ||
163 | static GetRedirectBorderClipProcPtr miGetRedirectBorderClipProc; | |
164 | static SetRedirectBorderClipProcPtr miSetRedirectBorderClipProc; | |
165 | ||
166 | void | |
167 | miRegisterRedirectBorderClipProc(SetRedirectBorderClipProcPtr setBorderClip, | |
168 | GetRedirectBorderClipProcPtr getBorderClip) | |
169 | { | |
170 | miSetRedirectBorderClipProc = setBorderClip; | |
171 | miGetRedirectBorderClipProc = getBorderClip; | |
172 | } | |
173 | ||
174 | /* | |
175 | * Manual redirected windows are treated as transparent; they do not obscure | |
176 | * siblings or parent windows | |
177 | */ | |
178 | ||
179 | #ifdef COMPOSITE | |
180 | #define TreatAsTransparent(w) ((w)->redirectDraw == RedirectDrawManual) | |
181 | #else | |
182 | #define TreatAsTransparent(w) FALSE | |
183 | #endif | |
184 | ||
185 | #define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ | |
186 | HasBorder(w) && \ | |
187 | (w)->backgroundState == ParentRelative) | |
188 | ||
189 | /* | |
190 | *----------------------------------------------------------------------- | |
191 | * miComputeClips -- | |
192 | * Recompute the clipList, borderClip, exposed and borderExposed | |
193 | * regions for pParent and its children. Only viewable windows are | |
194 | * taken into account. | |
195 | * | |
196 | * Results: | |
197 | * None. | |
198 | * | |
199 | * Side Effects: | |
200 | * clipList, borderClip, exposed and borderExposed are altered. | |
201 | * A VisibilityNotify event may be generated on the parent window. | |
202 | * | |
203 | *----------------------------------------------------------------------- | |
204 | */ | |
205 | static void | |
206 | miComputeClips(WindowPtr pParent, | |
207 | ScreenPtr pScreen, | |
208 | RegionPtr universe, VTKind kind, RegionPtr exposed) | |
209 | { /* for intermediate calculations */ | |
210 | int dx, dy; | |
211 | RegionRec childUniverse; | |
212 | WindowPtr pChild; | |
213 | int oldVis, newVis; | |
214 | BoxRec borderSize; | |
215 | RegionRec childUnion; | |
216 | Bool overlap; | |
217 | RegionPtr borderVisible; | |
218 | ||
219 | /* | |
220 | * Figure out the new visibility of this window. | |
221 | * The extent of the universe should be the same as the extent of | |
222 | * the borderSize region. If the window is unobscured, this rectangle | |
223 | * will be completely inside the universe (the universe will cover it | |
224 | * completely). If the window is completely obscured, none of the | |
225 | * universe will cover the rectangle. | |
226 | */ | |
227 | borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); | |
228 | borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); | |
229 | dx = (int) pParent->drawable.x + (int) pParent->drawable.width + | |
230 | wBorderWidth(pParent); | |
231 | if (dx > 32767) | |
232 | dx = 32767; | |
233 | borderSize.x2 = dx; | |
234 | dy = (int) pParent->drawable.y + (int) pParent->drawable.height + | |
235 | wBorderWidth(pParent); | |
236 | if (dy > 32767) | |
237 | dy = 32767; | |
238 | borderSize.y2 = dy; | |
239 | ||
240 | #ifdef COMPOSITE | |
241 | /* | |
242 | * In redirected drawing case, reset universe to borderSize | |
243 | */ | |
244 | if (pParent->redirectDraw != RedirectDrawNone) { | |
245 | if (miSetRedirectBorderClipProc) { | |
246 | if (TreatAsTransparent(pParent)) | |
247 | RegionEmpty(universe); | |
248 | (*miSetRedirectBorderClipProc) (pParent, universe); | |
249 | } | |
250 | RegionCopy(universe, &pParent->borderSize); | |
251 | } | |
252 | #endif | |
253 | ||
254 | oldVis = pParent->visibility; | |
255 | switch (RegionContainsRect(universe, &borderSize)) { | |
256 | case rgnIN: | |
257 | newVis = VisibilityUnobscured; | |
258 | break; | |
259 | case rgnPART: | |
260 | newVis = VisibilityPartiallyObscured; | |
261 | { | |
262 | RegionPtr pBounding; | |
263 | ||
264 | if ((pBounding = wBoundingShape(pParent))) { | |
265 | switch (miShapedWindowIn(universe, pBounding, | |
266 | &borderSize, | |
267 | pParent->drawable.x, | |
268 | pParent->drawable.y)) { | |
269 | case rgnIN: | |
270 | newVis = VisibilityUnobscured; | |
271 | break; | |
272 | case rgnOUT: | |
273 | newVis = VisibilityFullyObscured; | |
274 | break; | |
275 | } | |
276 | } | |
277 | } | |
278 | break; | |
279 | default: | |
280 | newVis = VisibilityFullyObscured; | |
281 | break; | |
282 | } | |
283 | pParent->visibility = newVis; | |
284 | if (oldVis != newVis && | |
285 | ((pParent-> | |
286 | eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) | |
287 | SendVisibilityNotify(pParent); | |
288 | ||
289 | dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; | |
290 | dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; | |
291 | ||
292 | /* | |
293 | * avoid computations when dealing with simple operations | |
294 | */ | |
295 | ||
296 | switch (kind) { | |
297 | case VTMap: | |
298 | case VTStack: | |
299 | case VTUnmap: | |
300 | break; | |
301 | case VTMove: | |
302 | if ((oldVis == newVis) && | |
303 | ((oldVis == VisibilityFullyObscured) || | |
304 | (oldVis == VisibilityUnobscured))) { | |
305 | pChild = pParent; | |
306 | while (1) { | |
307 | if (pChild->viewable) { | |
308 | if (pChild->visibility != VisibilityFullyObscured) { | |
309 | RegionTranslate(&pChild->borderClip, dx, dy); | |
310 | RegionTranslate(&pChild->clipList, dx, dy); | |
311 | pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; | |
312 | if (pScreen->ClipNotify) | |
313 | (*pScreen->ClipNotify) (pChild, dx, dy); | |
314 | ||
315 | } | |
316 | if (pChild->valdata) { | |
317 | RegionNull(&pChild->valdata->after.borderExposed); | |
318 | if (HasParentRelativeBorder(pChild)) { | |
319 | RegionSubtract(&pChild->valdata->after. | |
320 | borderExposed, &pChild->borderClip, | |
321 | &pChild->winSize); | |
322 | } | |
323 | RegionNull(&pChild->valdata->after.exposed); | |
324 | } | |
325 | if (pChild->firstChild) { | |
326 | pChild = pChild->firstChild; | |
327 | continue; | |
328 | } | |
329 | } | |
330 | while (!pChild->nextSib && (pChild != pParent)) | |
331 | pChild = pChild->parent; | |
332 | if (pChild == pParent) | |
333 | break; | |
334 | pChild = pChild->nextSib; | |
335 | } | |
336 | return; | |
337 | } | |
338 | /* fall through */ | |
339 | default: | |
340 | /* | |
341 | * To calculate exposures correctly, we have to translate the old | |
342 | * borderClip and clipList regions to the window's new location so there | |
343 | * is a correspondence between pieces of the new and old clipping regions. | |
344 | */ | |
345 | if (dx || dy) { | |
346 | /* | |
347 | * We translate the old clipList because that will be exposed or copied | |
348 | * if gravity is right. | |
349 | */ | |
350 | RegionTranslate(&pParent->borderClip, dx, dy); | |
351 | RegionTranslate(&pParent->clipList, dx, dy); | |
352 | } | |
353 | break; | |
354 | case VTBroken: | |
355 | RegionEmpty(&pParent->borderClip); | |
356 | RegionEmpty(&pParent->clipList); | |
357 | break; | |
358 | } | |
359 | ||
360 | borderVisible = pParent->valdata->before.borderVisible; | |
361 | RegionNull(&pParent->valdata->after.borderExposed); | |
362 | RegionNull(&pParent->valdata->after.exposed); | |
363 | ||
364 | /* | |
365 | * Since the borderClip must not be clipped by the children, we do | |
366 | * the border exposure first... | |
367 | * | |
368 | * 'universe' is the window's borderClip. To figure the exposures, remove | |
369 | * the area that used to be exposed from the new. | |
370 | * This leaves a region of pieces that weren't exposed before. | |
371 | */ | |
372 | ||
373 | if (HasBorder(pParent)) { | |
374 | if (borderVisible) { | |
375 | /* | |
376 | * when the border changes shape, the old visible portions | |
377 | * of the border will be saved by DIX in borderVisible -- | |
378 | * use that region and destroy it | |
379 | */ | |
380 | RegionSubtract(exposed, universe, borderVisible); | |
381 | RegionDestroy(borderVisible); | |
382 | } | |
383 | else { | |
384 | RegionSubtract(exposed, universe, &pParent->borderClip); | |
385 | } | |
386 | if (HasParentRelativeBorder(pParent) && (dx || dy)) | |
387 | RegionSubtract(&pParent->valdata->after.borderExposed, | |
388 | universe, &pParent->winSize); | |
389 | else | |
390 | RegionSubtract(&pParent->valdata->after.borderExposed, | |
391 | exposed, &pParent->winSize); | |
392 | ||
393 | RegionCopy(&pParent->borderClip, universe); | |
394 | ||
395 | /* | |
396 | * To get the right clipList for the parent, and to make doubly sure | |
397 | * that no child overlaps the parent's border, we remove the parent's | |
398 | * border from the universe before proceeding. | |
399 | */ | |
400 | ||
401 | RegionIntersect(universe, universe, &pParent->winSize); | |
402 | } | |
403 | else | |
404 | RegionCopy(&pParent->borderClip, universe); | |
405 | ||
406 | if ((pChild = pParent->firstChild) && pParent->mapped) { | |
407 | RegionNull(&childUniverse); | |
408 | RegionNull(&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 | for (; pChild; pChild = pChild->nextSib) { | |
413 | if (pChild->viewable && !TreatAsTransparent(pChild)) | |
414 | RegionAppend(&childUnion, &pChild->borderSize); | |
415 | } | |
416 | } | |
417 | else { | |
418 | for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) { | |
419 | if (pChild->viewable && !TreatAsTransparent(pChild)) | |
420 | RegionAppend(&childUnion, &pChild->borderSize); | |
421 | } | |
422 | } | |
423 | RegionValidate(&childUnion, &overlap); | |
424 | ||
425 | for (pChild = pParent->firstChild; pChild; pChild = pChild->nextSib) { | |
426 | if (pChild->viewable) { | |
427 | /* | |
428 | * If the child is viewable, we want to remove its extents | |
429 | * from the current universe, but we only re-clip it if | |
430 | * it's been marked. | |
431 | */ | |
432 | if (pChild->valdata) { | |
433 | /* | |
434 | * Figure out the new universe from the child's | |
435 | * perspective and recurse. | |
436 | */ | |
437 | RegionIntersect(&childUniverse, | |
438 | universe, &pChild->borderSize); | |
439 | miComputeClips(pChild, pScreen, &childUniverse, kind, | |
440 | exposed); | |
441 | } | |
442 | /* | |
443 | * Once the child has been processed, we remove its extents | |
444 | * from the current universe, thus denying its space to any | |
445 | * other sibling. | |
446 | */ | |
447 | if (overlap && !TreatAsTransparent(pChild)) | |
448 | RegionSubtract(universe, universe, &pChild->borderSize); | |
449 | } | |
450 | } | |
451 | if (!overlap) | |
452 | RegionSubtract(universe, universe, &childUnion); | |
453 | RegionUninit(&childUnion); | |
454 | RegionUninit(&childUniverse); | |
455 | } /* if any children */ | |
456 | ||
457 | /* | |
458 | * 'universe' now contains the new clipList for the parent window. | |
459 | * | |
460 | * To figure the exposure of the window we subtract the old clip from the | |
461 | * new, just as for the border. | |
462 | */ | |
463 | ||
464 | if (oldVis == VisibilityFullyObscured || oldVis == VisibilityNotViewable) { | |
465 | RegionCopy(&pParent->valdata->after.exposed, universe); | |
466 | } | |
467 | else if (newVis != VisibilityFullyObscured && | |
468 | newVis != VisibilityNotViewable) { | |
469 | RegionSubtract(&pParent->valdata->after.exposed, | |
470 | universe, &pParent->clipList); | |
471 | } | |
472 | ||
473 | /* HACK ALERT - copying contents of regions, instead of regions */ | |
474 | { | |
475 | RegionRec tmp; | |
476 | ||
477 | tmp = pParent->clipList; | |
478 | pParent->clipList = *universe; | |
479 | *universe = tmp; | |
480 | } | |
481 | ||
482 | #ifdef NOTDEF | |
483 | RegionCopy(&pParent->clipList, universe); | |
484 | #endif | |
485 | ||
486 | pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; | |
487 | ||
488 | if (pScreen->ClipNotify) | |
489 | (*pScreen->ClipNotify) (pParent, dx, dy); | |
490 | } | |
491 | ||
492 | static void | |
493 | miTreeObscured(WindowPtr pParent) | |
494 | { | |
495 | WindowPtr pChild; | |
496 | int oldVis; | |
497 | ||
498 | pChild = pParent; | |
499 | while (1) { | |
500 | if (pChild->viewable) { | |
501 | oldVis = pChild->visibility; | |
502 | if (oldVis != (pChild->visibility = VisibilityFullyObscured) && | |
503 | ((pChild-> | |
504 | eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) | |
505 | SendVisibilityNotify(pChild); | |
506 | if (pChild->firstChild) { | |
507 | pChild = pChild->firstChild; | |
508 | continue; | |
509 | } | |
510 | } | |
511 | while (!pChild->nextSib && (pChild != pParent)) | |
512 | pChild = pChild->parent; | |
513 | if (pChild == pParent) | |
514 | break; | |
515 | pChild = pChild->nextSib; | |
516 | } | |
517 | } | |
518 | ||
519 | /* | |
520 | *----------------------------------------------------------------------- | |
521 | * miValidateTree -- | |
522 | * Recomputes the clip list for pParent and all its inferiors. | |
523 | * | |
524 | * Results: | |
525 | * Always returns 1. | |
526 | * | |
527 | * Side Effects: | |
528 | * The clipList, borderClip, exposed, and borderExposed regions for | |
529 | * each marked window are altered. | |
530 | * | |
531 | * Notes: | |
532 | * This routine assumes that all affected windows have been marked | |
533 | * (valdata created) and their winSize and borderSize regions | |
534 | * adjusted to correspond to their new positions. The borderClip and | |
535 | * clipList regions should not have been touched. | |
536 | * | |
537 | * The top-most level is treated differently from all lower levels | |
538 | * because pParent is unchanged. For the top level, we merge the | |
539 | * regions taken up by the marked children back into the clipList | |
540 | * for pParent, thus forming a region from which the marked children | |
541 | * can claim their areas. For lower levels, where the old clipList | |
542 | * and borderClip are invalid, we can't do this and have to do the | |
543 | * extra operations done in miComputeClips, but this is much faster | |
544 | * e.g. when only one child has moved... | |
545 | * | |
546 | *----------------------------------------------------------------------- | |
547 | */ | |
548 | /*ARGSUSED*/ int | |
549 | miValidateTree(WindowPtr pParent, /* Parent to validate */ | |
550 | WindowPtr pChild, /* First child of pParent that was | |
551 | * affected */ | |
552 | VTKind kind /* What kind of configuration caused call */ | |
553 | ) | |
554 | { | |
555 | RegionRec totalClip; /* Total clipping region available to | |
556 | * the marked children. pParent's clipList | |
557 | * merged with the borderClips of all | |
558 | * the marked children. */ | |
559 | RegionRec childClip; /* The new borderClip for the current | |
560 | * child */ | |
561 | RegionRec childUnion; /* the space covered by borderSize for | |
562 | * all marked children */ | |
563 | RegionRec exposed; /* For intermediate calculations */ | |
564 | ScreenPtr pScreen; | |
565 | WindowPtr pWin; | |
566 | Bool overlap; | |
567 | int viewvals; | |
568 | Bool forward; | |
569 | ||
570 | pScreen = pParent->drawable.pScreen; | |
571 | if (pChild == NullWindow) | |
572 | pChild = pParent->firstChild; | |
573 | ||
574 | RegionNull(&childClip); | |
575 | RegionNull(&exposed); | |
576 | ||
577 | /* | |
578 | * compute the area of the parent window occupied | |
579 | * by the marked children + the parent itself. This | |
580 | * is the area which can be divied up among the marked | |
581 | * children in their new configuration. | |
582 | */ | |
583 | RegionNull(&totalClip); | |
584 | viewvals = 0; | |
585 | if (RegionBroken(&pParent->clipList) && !RegionBroken(&pParent->borderClip)) { | |
586 | kind = VTBroken; | |
587 | /* | |
588 | * When rebuilding clip lists after out of memory, | |
589 | * assume everything is busted. | |
590 | */ | |
591 | forward = TRUE; | |
592 | RegionCopy(&totalClip, &pParent->borderClip); | |
593 | RegionIntersect(&totalClip, &totalClip, &pParent->winSize); | |
594 | ||
595 | for (pWin = pParent->firstChild; pWin != pChild; pWin = pWin->nextSib) { | |
596 | if (pWin->viewable && !TreatAsTransparent(pWin)) | |
597 | RegionSubtract(&totalClip, &totalClip, &pWin->borderSize); | |
598 | } | |
599 | for (pWin = pChild; pWin; pWin = pWin->nextSib) | |
600 | if (pWin->valdata && pWin->viewable) | |
601 | viewvals++; | |
602 | ||
603 | RegionEmpty(&pParent->clipList); | |
604 | } | |
605 | else { | |
606 | if ((pChild->drawable.y < pParent->lastChild->drawable.y) || | |
607 | ((pChild->drawable.y == pParent->lastChild->drawable.y) && | |
608 | (pChild->drawable.x < pParent->lastChild->drawable.x))) { | |
609 | forward = TRUE; | |
610 | for (pWin = pChild; pWin; pWin = pWin->nextSib) { | |
611 | if (pWin->valdata) { | |
612 | RegionPtr pBorderClip = &pWin->borderClip; | |
613 | ||
614 | #ifdef COMPOSITE | |
615 | if (pWin->redirectDraw != RedirectDrawNone && | |
616 | miGetRedirectBorderClipProc) | |
617 | pBorderClip = (*miGetRedirectBorderClipProc) (pWin); | |
618 | #endif | |
619 | RegionAppend(&totalClip, pBorderClip); | |
620 | if (pWin->viewable) | |
621 | viewvals++; | |
622 | } | |
623 | } | |
624 | } | |
625 | else { | |
626 | forward = FALSE; | |
627 | pWin = pParent->lastChild; | |
628 | while (1) { | |
629 | if (pWin->valdata) { | |
630 | RegionPtr pBorderClip = &pWin->borderClip; | |
631 | ||
632 | #ifdef COMPOSITE | |
633 | if (pWin->redirectDraw != RedirectDrawNone && | |
634 | miGetRedirectBorderClipProc) | |
635 | pBorderClip = (*miGetRedirectBorderClipProc) (pWin); | |
636 | #endif | |
637 | RegionAppend(&totalClip, pBorderClip); | |
638 | if (pWin->viewable) | |
639 | viewvals++; | |
640 | } | |
641 | if (pWin == pChild) | |
642 | break; | |
643 | pWin = pWin->prevSib; | |
644 | } | |
645 | } | |
646 | RegionValidate(&totalClip, &overlap); | |
647 | } | |
648 | ||
649 | /* | |
650 | * Now go through the children of the root and figure their new | |
651 | * borderClips from the totalClip, passing that off to miComputeClips | |
652 | * to handle recursively. Once that's done, we remove the child | |
653 | * from the totalClip to clip any siblings below it. | |
654 | */ | |
655 | ||
656 | overlap = TRUE; | |
657 | if (kind != VTStack) { | |
658 | RegionUnion(&totalClip, &totalClip, &pParent->clipList); | |
659 | if (viewvals > 1) { | |
660 | /* | |
661 | * precompute childUnion to discover whether any of them | |
662 | * overlap. This seems redundant, but performance studies | |
663 | * have demonstrated that the cost of this loop is | |
664 | * lower than the cost of multiple Subtracts in the | |
665 | * loop below. | |
666 | */ | |
667 | RegionNull(&childUnion); | |
668 | if (forward) { | |
669 | for (pWin = pChild; pWin; pWin = pWin->nextSib) | |
670 | if (pWin->valdata && pWin->viewable && | |
671 | !TreatAsTransparent(pWin)) | |
672 | RegionAppend(&childUnion, &pWin->borderSize); | |
673 | } | |
674 | else { | |
675 | pWin = pParent->lastChild; | |
676 | while (1) { | |
677 | if (pWin->valdata && pWin->viewable && | |
678 | !TreatAsTransparent(pWin)) | |
679 | RegionAppend(&childUnion, &pWin->borderSize); | |
680 | if (pWin == pChild) | |
681 | break; | |
682 | pWin = pWin->prevSib; | |
683 | } | |
684 | } | |
685 | RegionValidate(&childUnion, &overlap); | |
686 | if (overlap) | |
687 | RegionUninit(&childUnion); | |
688 | } | |
689 | } | |
690 | ||
691 | for (pWin = pChild; pWin != NullWindow; pWin = pWin->nextSib) { | |
692 | if (pWin->viewable) { | |
693 | if (pWin->valdata) { | |
694 | RegionIntersect(&childClip, &totalClip, &pWin->borderSize); | |
695 | miComputeClips(pWin, pScreen, &childClip, kind, &exposed); | |
696 | if (overlap && !TreatAsTransparent(pWin)) { | |
697 | RegionSubtract(&totalClip, &totalClip, &pWin->borderSize); | |
698 | } | |
699 | } | |
700 | else if (pWin->visibility == VisibilityNotViewable) { | |
701 | miTreeObscured(pWin); | |
702 | } | |
703 | } | |
704 | else { | |
705 | if (pWin->valdata) { | |
706 | RegionEmpty(&pWin->clipList); | |
707 | if (pScreen->ClipNotify) | |
708 | (*pScreen->ClipNotify) (pWin, 0, 0); | |
709 | RegionEmpty(&pWin->borderClip); | |
710 | pWin->valdata = NULL; | |
711 | } | |
712 | } | |
713 | } | |
714 | ||
715 | RegionUninit(&childClip); | |
716 | if (!overlap) { | |
717 | RegionSubtract(&totalClip, &totalClip, &childUnion); | |
718 | RegionUninit(&childUnion); | |
719 | } | |
720 | ||
721 | RegionNull(&pParent->valdata->after.exposed); | |
722 | RegionNull(&pParent->valdata->after.borderExposed); | |
723 | ||
724 | /* | |
725 | * each case below is responsible for updating the | |
726 | * clipList and serial number for the parent window | |
727 | */ | |
728 | ||
729 | switch (kind) { | |
730 | case VTStack: | |
731 | break; | |
732 | default: | |
733 | /* | |
734 | * totalClip contains the new clipList for the parent. Figure out | |
735 | * exposures and obscures as per miComputeClips and reset the parent's | |
736 | * clipList. | |
737 | */ | |
738 | RegionSubtract(&pParent->valdata->after.exposed, | |
739 | &totalClip, &pParent->clipList); | |
740 | /* fall through */ | |
741 | case VTMap: | |
742 | RegionCopy(&pParent->clipList, &totalClip); | |
743 | pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; | |
744 | break; | |
745 | } | |
746 | ||
747 | RegionUninit(&totalClip); | |
748 | RegionUninit(&exposed); | |
749 | if (pScreen->ClipNotify) | |
750 | (*pScreen->ClipNotify) (pParent, 0, 0); | |
751 | return 1; | |
752 | } |