|
|
1.1 root 1: /*
2: * mivaltree.c --
3: * Functions for recalculating window clip lists. Main function
4: * is miValidateTree.
5: *
6: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
7: * and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
8: *
9: * All Rights Reserved
10: *
11: * Permission to use, copy, modify, and distribute this software and its
12: * documentation for any purpose and without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and that
14: * both that copyright notice and this permission notice appear in
15: * supporting documentation, and that the names of Digital or MIT not be
16: * used in advertising or publicity pertaining to distribution of the
17: * software without specific, written prior permission.
18: *
19: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25: * SOFTWARE.
26: *
27: ******************************************************************/
28:
29: /*
30: * Aug '86: Susan Angebranndt -- original code
31: * July '87: Adam de Boor -- substantially modified and commented
32: */
33:
34: #ifndef lint
35: static char rcsid[] =
36: "$Header: mivaltree.c,v 1.36 87/09/11 07:20:34 toddb Exp $ SPRITE (Berkeley)";
37: #endif lint
38:
39: #include "X.h"
40: #include "scrnintstr.h"
41: #include "windowstr.h"
42: #include "mi.h"
43: #include "region.h"
44:
45: static RegionPtr exposed = NullRegion;
46:
47: /*-
48: *-----------------------------------------------------------------------
49: * miComputeClips --
50: * Recompute the clipList, borderClip, exposed and borderExposed
51: * regions for pParent and its children. Only viewable windows are
52: * taken into account.
53: *
54: * Results:
55: * None.
56: *
57: * Side Effects:
58: * clipList, borderClip, exposed and borderExposed are altered.
59: * A VisibilityNotify event may be generated on the parent window.
60: *
61: *-----------------------------------------------------------------------
62: */
63: static void
64: miComputeClips (pParent, pScreen, universe)
65: register WindowPtr pParent;
66: register ScreenPtr pScreen;
67: register RegionPtr universe;
68: {
69: int dx,
70: dy;
71: RegionPtr childUniverse;
72: register WindowPtr pChild;
73: int oldVis;
74: BoxPtr borderSize;
75:
76:
77: childUniverse = (RegionPtr)NULL;
78:
79: /*
80: * Figure out the new visibility of this window.
81: * The extent of the universe should be the same as the extent of
82: * the borderSize region. If the window is unobscured, this rectangle
83: * will be completely inside the universe (the universe will cover it
84: * completely). If the window is completely obscured, none of the
85: * universe will cover the rectangle.
86: */
87: borderSize = (* pScreen->RegionExtents) (pParent->borderSize);
88:
89: oldVis = pParent->visibility;
90: switch ((* pScreen->RectIn) (universe, borderSize))
91: {
92: case rgnIN:
93: pParent->visibility = VisibilityUnobscured;
94: break;
95: case rgnPART:
96: pParent->visibility = VisibilityPartiallyObscured;
97: break;
98: default:
99: pParent->visibility = VisibilityFullyObscured;
100: break;
101: }
102: if (oldVis != pParent->visibility)
103: SendVisibilityNotify(pParent);
104:
105: /*
106: * To calculate exposures correctly, we have to translate the old
107: * borderClip and clipList regions to the window's new location so there
108: * is a correspondence between pieces of the new and old clipping regions.
109: */
110: dx = pParent->absCorner.x - pParent->oldAbsCorner.x;
111: dy = pParent->absCorner.y - pParent->oldAbsCorner.y;
112:
113: if (dx || dy)
114: {
115: /*
116: * If the window has moved, the border will *not* be copied, so we
117: * empty the old border clip to force exposure of the whole thing.
118: * We translate the old clipList because that will be exposed or copied
119: * if gravity is right.
120: */
121: (* pScreen->RegionEmpty) (pParent->borderClip);
122: (* pScreen->TranslateRegion) (pParent->clipList, dx, dy);
123: pParent->oldAbsCorner = pParent->absCorner;
124: }
125: else if (pParent->borderWidth)
126: {
127: /*
128: * If the window has shrunk, we have to be careful about figuring the
129: * exposure of the right and bottom borders -- they should be exposed
130: * if the window shrank on that side and they aren't being obscured
131: * by a sibling -- so we add those edges to the borderExposed region.
132: * This is all necessary because sometimes what was the internal window
133: * in the old borderClip will overlap the new border and cause the
134: * right and bottom edges of the new border not to appear in the
135: * borderExposed region and it's a royal pain to figure out what to
136: * remove from the old borderClip.
137: * XXX: Isn't there a nicer way to do this?
138: */
139: BoxPtr oldExtents;
140: BoxPtr newExtents;
141: BoxPtr windowExtents;
142:
143: oldExtents = (* pScreen->RegionExtents) (pParent->borderClip);
144: newExtents = (* pScreen->RegionExtents) (universe);
145: windowExtents = (* pScreen->RegionExtents) (pParent->borderSize);
146:
147: if ((* pScreen->RegionNotEmpty) (universe) &&
148: (* pScreen->RegionNotEmpty) (pParent->borderClip) &&
149: ((newExtents->x2 < oldExtents->x2) ||
150: (newExtents->y2 < oldExtents->y2)))
151: {
152: BoxRec borderBox;
153: RegionPtr borderRegion;
154:
155: borderRegion = (* pScreen->RegionCreate) (NULL, 1);
156:
157: if (newExtents->x2 < oldExtents->x2)
158: {
159: /*
160: * Add the right edge.
161: */
162: borderBox.x1 = windowExtents->x2 - pParent->borderWidth;
163: borderBox.y1 = windowExtents->y1;
164: borderBox.x2 = windowExtents->x2;
165: borderBox.y2 = windowExtents->y2;
166: (* pScreen->RegionReset) (borderRegion, &borderBox);
167: (* pScreen->Union) (pParent->borderExposed,
168: pParent->borderExposed,
169: borderRegion);
170: }
171: if (newExtents->y2 < oldExtents->y2)
172: {
173: /*
174: * Add the bottom edge.
175: */
176: borderBox.x1 = windowExtents->x1;
177: borderBox.y1 = windowExtents->y2 - pParent->borderWidth;
178: borderBox.x2 = windowExtents->x2;
179: borderBox.y2 = windowExtents->y2;
180: (* pScreen->RegionReset) (borderRegion, &borderBox);
181: (* pScreen->Union) (pParent->borderExposed,
182: pParent->borderExposed,
183: borderRegion);
184: }
185: (* pScreen->RegionDestroy) (borderRegion);
186:
187: /*
188: * To make sure we don't expose a border that's supposed to
189: * be clipped, clip the regions we just added to borderExposed...
190: */
191: (* pScreen->Intersect) (pParent->borderExposed, universe,
192: pParent->borderExposed);
193: }
194: }
195:
196: /*
197: * Since the borderClip must not be clipped by the children, we do
198: * the border exposure first...
199: *
200: * 'universe' is the window's borderClip. To figure the exposures, remove
201: * the area that used to be exposed (the old borderClip) from the new.
202: * This leaves a region of pieces that weren't exposed before. Border
203: * exposures accumulate until they're taken care of.
204: */
205: (* pScreen->Subtract) (exposed, universe, pParent->borderClip);
206: (* pScreen->Subtract) (exposed, exposed, pParent->winSize);
207:
208: (* pScreen->Union) (pParent->borderExposed, pParent->borderExposed,
209: exposed);
210:
211: (* pScreen->RegionCopy) (pParent->borderClip, universe);
212:
213: /*
214: * To get the right clipList for the parent, and to make doubly sure
215: * that no child overlaps the parent's border, we remove the parent's
216: * border from the universe before proceeding.
217: */
218: (* pScreen->Intersect) (universe, universe, pParent->winSize);
219:
220: for (pChild = pParent->firstChild; pChild; pChild = pChild->nextSib)
221: {
222: if (pChild->viewable)
223: {
224: /*
225: * If the child is viewable, we want to remove its extents from
226: * the current universe, but we only re-clip it if it's been
227: * marked.
228: */
229: if (pChild->marked)
230: {
231: /*
232: * Figure out the new universe from the child's perspective and
233: * recurse.
234: */
235: if (childUniverse == NullRegion)
236: {
237: childUniverse = (* pScreen->RegionCreate) (NULL, 1);
238: }
239: (* pScreen->Intersect) (childUniverse, universe,
240: pChild->borderSize);
241: miComputeClips (pChild, pScreen, childUniverse);
242: }
243: /*
244: * Once the child has been processed, we remove its extents from
245: * the current universe, thus denying its space to any other
246: * sibling.
247: */
248: (* pScreen->Subtract) (universe, universe, pChild->borderSize);
249: }
250: else
251: {
252: pChild->marked = 0;
253: if ((* pScreen->RegionNotEmpty) (pChild->borderClip))
254: {
255: /*
256: * If the child isn't viewable, it has no business taking up
257: * clipping space, so we nuke all its clipping regions. There
258: * was a problem with UnmapGravity where the clipList wouldn't
259: * get nuked, so drawing operations succeeded while the window
260: * was unmapped...
261: */
262: (* pScreen->RegionEmpty) (pChild->borderClip);
263: (* pScreen->RegionEmpty) (pChild->clipList);
264: (* pScreen->RegionEmpty) (pChild->exposed);
265: (* pScreen->RegionEmpty) (pChild->borderExposed);
266: pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
267: }
268: }
269: }
270:
271: /*
272: * 'universe' now contains the new clipList for the parent window.
273: *
274: * To figure the exposure of the window we subtract the old clip from the
275: * new, just as for the border. Again, exposures accumulate.
276: */
277: (* pScreen->Subtract) (exposed, universe, pParent->clipList);
278:
279: (* pScreen->Union) (pParent->exposed, pParent->exposed, exposed);
280:
281: /*
282: * One last thing: backing storage. We have to find out what parts of
283: * the window are about to be obscured. We can just subtract the universe
284: * from the old clipList and get the areas that were in the old but aren't
285: * in the new and, hence, are about to be obscured.
286: */
287: if (pParent->backStorage && (pParent->backingStore != NotUseful))
288: {
289: (* pScreen->Subtract) (exposed, pParent->clipList, universe);
290: (* pScreen->Union) (pParent->backStorage->obscured,
291: pParent->backStorage->obscured,
292: exposed);
293: }
294:
295: (* pScreen->RegionCopy) (pParent->clipList, universe);
296:
297: pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
298: pParent->marked = 0;
299:
300: if (childUniverse)
301: (* pScreen->RegionDestroy) (childUniverse);
302: }
303:
304: /*-
305: *-----------------------------------------------------------------------
306: * miValidateTree --
307: * Recomputes the clip list for pParent and all its inferiors.
308: *
309: * Results:
310: * Always returns 1.
311: *
312: * Side Effects:
313: * The clipList, borderClip, exposed, and borderExposed regions for
314: * each marked window are altered.
315: *
316: * Notes:
317: * This routine assumes that all affected windows have had their
318: * marked fields set true and their winSize and borderSize regions
319: * adjusted to correspond to their new positions. The borderClip and
320: * clipList regions should not have been touched.
321: *
322: * The top-most level is treated differently from all lower levels
323: * because pParent is unchanged. For the top level, we merge the
324: * regions taken up by the marked children back into the clipList
325: * for pParent, thus forming a region from which the marked children
326: * can claim their areas. For lower levels, where the old clipList
327: * and borderClip are invalid, we can't do this and have to do the
328: * extra operations done in miComputeClips, but this is much faster
329: * e.g. when only one child has moved...
330: *
331: *-----------------------------------------------------------------------
332: */
333: /*ARGSUSED*/
334: int
335: miValidateTree (pParent, pChild, top, anyMarked)
336: WindowPtr pParent; /* Parent to validate */
337: WindowPtr pChild; /* First child of pParent that was
338: * affected */
339: Bool top; /* TRUE if at top level. UNUSED */
340: Bool anyMarked; /* TRUE if any windows were marked. */
341: {
342: RegionPtr totalClip; /* Total clipping region available to
343: * the marked children. pParent's clipList
344: * merged with the borderClips of all
345: * the marked children. */
346: RegionPtr childClip; /* The new borderClip for the current
347: * child */
348: register ScreenPtr pScreen;
349: register WindowPtr pWin;
350:
351: if (!anyMarked)
352: {
353: return (1);
354: }
355: pScreen = pParent->drawable.pScreen;
356:
357: if (exposed == NullRegion)
358: {
359: exposed = (* pScreen->RegionCreate) (NULL, 1);
360: }
361:
362: totalClip = (* pScreen->RegionCreate) (NULL, 1);
363: childClip = (* pScreen->RegionCreate) (NULL, 1);
364:
365: /*
366: * Preserve the parent's old clipList to make calculating exposures
367: * easier.
368: */
369: (* pScreen->RegionCopy) (totalClip, pParent->clipList);
370:
371: if (pChild == NullWindow)
372: {
373: pChild = pParent->firstChild;
374: }
375:
376: /*
377: * First merge in the child windows at their old places.
378: */
379: for (pWin = pChild; pWin != NullWindow; pWin = pWin->nextSib)
380: {
381: if (pWin->marked)
382: {
383: (* pScreen->Union) (totalClip, totalClip, pWin->borderClip);
384: }
385: }
386:
387: /*
388: * Now go through the children of the root and figure their new
389: * borderClips from the totalClip, passing that off to miComputeClips
390: * to handle recursively. Once that's done, we remove the child
391: * from the totalClip to clip any siblings below it.
392: */
393: for (pWin = pChild; pWin != NullWindow; pWin = pWin->nextSib)
394: {
395: if (pWin->viewable)
396: {
397: if (pWin->marked)
398: {
399: (* pScreen->Intersect) (childClip, totalClip, pWin->borderSize);
400: miComputeClips (pWin, pScreen, childClip);
401: (* pScreen->Subtract) (totalClip, totalClip, pWin->borderSize);
402: }
403: }
404: else
405: {
406: /*
407: * Make sure the child is no longer marked (Windows being unmapped
408: * are marked but unviewable...)
409: */
410: pWin->marked = 0;
411: if ((* pScreen->RegionNotEmpty) (pWin->borderClip))
412: {
413: /*
414: * If the child isn't viewable, it has no business taking up
415: * clipping space, so we nuke all its clipping regions. There
416: * was a problem with UnmapGravity where the clipList wouldn't
417: * get nuked, so drawing operations succeeded while the window
418: * was unmapped...
419: */
420: (* pScreen->RegionEmpty) (pChild->borderClip);
421: (* pScreen->RegionEmpty) (pChild->clipList);
422: (* pScreen->RegionEmpty) (pChild->exposed);
423: (* pScreen->RegionEmpty) (pChild->borderExposed);
424: pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER;
425: }
426: }
427: }
428:
429: /*
430: * totalClip contains the new clipList for the parent. Figure out
431: * exposures and obscures as per miComputeClips and reset the parent's
432: * clipList.
433: */
434: (* pScreen->Subtract) (exposed, totalClip, pParent->clipList);
435: (* pScreen->Union) (pParent->exposed, pParent->exposed, exposed);
436:
437: if (pParent->backStorage && (pParent->backingStore != NotUseful))
438: {
439: (* pScreen->Subtract) (exposed, pParent->clipList, totalClip);
440: (* pScreen->Union) (pParent->backStorage->obscured,
441: pParent->backStorage->obscured,
442: exposed);
443: }
444:
445: (* pScreen->RegionCopy) (pParent->clipList, totalClip);
446: pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
447: pParent->marked = 0;
448:
449: (* pScreen->RegionDestroy) (childClip);
450:
451: WindowsRestructured();
452:
453: (* pScreen->RegionDestroy) (totalClip);
454:
455: return (1);
456: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.