rootlessValTree.c revision 6747b715
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 { 131 if ((t = boundBox->x1 + x) < x1) 132 t = x1; 133 box.x1 = t; 134 if ((t = boundBox->y1 + y) < y1) 135 t = y1; 136 box.y1 = t; 137 if ((t = boundBox->x2 + x) > x2) 138 t = x2; 139 box.x2 = t; 140 if ((t = boundBox->y2 + y) > y2) 141 t = y2; 142 box.y2 = t; 143 if (box.x1 > box.x2) 144 box.x2 = box.x1; 145 if (box.y1 > box.y2) 146 box.y2 = box.y1; 147 switch (RegionContainsRect(universe, &box)) 148 { 149 case rgnIN: 150 if (someOut) 151 return rgnPART; 152 someIn = TRUE; 153 break; 154 case rgnOUT: 155 if (someIn) 156 return rgnPART; 157 someOut = TRUE; 158 break; 159 default: 160 return rgnPART; 161 } 162 boundBox++; 163 } 164 if (someIn) 165 return rgnIN; 166 return rgnOUT; 167} 168 169#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ 170 HasBorder(w) && \ 171 (w)->backgroundState == ParentRelative) 172 173 174/* 175 *----------------------------------------------------------------------- 176 * RootlessComputeClips -- 177 * Recompute the clipList, borderClip, exposed and borderExposed 178 * regions for pParent and its children. Only viewable windows are 179 * taken into account. 180 * 181 * Results: 182 * None. 183 * 184 * Side Effects: 185 * clipList, borderClip, exposed and borderExposed are altered. 186 * A VisibilityNotify event may be generated on the parent window. 187 * 188 *----------------------------------------------------------------------- 189 */ 190static void 191RootlessComputeClips (WindowPtr pParent, ScreenPtr pScreen, 192 RegionPtr universe, VTKind kind, RegionPtr exposed) 193{ 194 int dx, 195 dy; 196 RegionRec childUniverse; 197 register WindowPtr pChild; 198 int oldVis, newVis; 199 BoxRec borderSize; 200 RegionRec childUnion; 201 Bool overlap; 202 RegionPtr borderVisible; 203 Bool resized; 204 /* 205 * Figure out the new visibility of this window. 206 * The extent of the universe should be the same as the extent of 207 * the borderSize region. If the window is unobscured, this rectangle 208 * will be completely inside the universe (the universe will cover it 209 * completely). If the window is completely obscured, none of the 210 * universe will cover the rectangle. 211 */ 212 borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); 213 borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); 214 dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent); 215 if (dx > 32767) 216 dx = 32767; 217 borderSize.x2 = dx; 218 dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent); 219 if (dy > 32767) 220 dy = 32767; 221 borderSize.y2 = dy; 222 223 oldVis = pParent->visibility; 224 switch (RegionContainsRect(universe, &borderSize)) 225 { 226 case rgnIN: 227 newVis = VisibilityUnobscured; 228 break; 229 case rgnPART: 230 newVis = VisibilityPartiallyObscured; 231 { 232 RegionPtr pBounding; 233 234 if ((pBounding = wBoundingShape (pParent))) 235 { 236 switch (RootlessShapedWindowIn (universe, 237 pBounding, &borderSize, 238 pParent->drawable.x, 239 pParent->drawable.y)) 240 { 241 case rgnIN: 242 newVis = VisibilityUnobscured; 243 break; 244 case rgnOUT: 245 newVis = VisibilityFullyObscured; 246 break; 247 } 248 } 249 } 250 break; 251 default: 252 newVis = VisibilityFullyObscured; 253 break; 254 } 255 256 pParent->visibility = newVis; 257 if (oldVis != newVis && 258 ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) 259 SendVisibilityNotify(pParent); 260 261 dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; 262 dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; 263 264 /* 265 * avoid computations when dealing with simple operations 266 */ 267 268 switch (kind) { 269 case VTMap: 270 case VTStack: 271 case VTUnmap: 272 break; 273 case VTMove: 274 if ((oldVis == newVis) && 275 ((oldVis == VisibilityFullyObscured) || 276 (oldVis == VisibilityUnobscured))) 277 { 278 pChild = pParent; 279 while (1) 280 { 281 if (pChild->viewable) 282 { 283 if (pChild->visibility != VisibilityFullyObscured) 284 { 285 RegionTranslate(&pChild->borderClip, 286 dx, dy); 287 RegionTranslate(&pChild->clipList, 288 dx, dy); 289 pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; 290 if (pScreen->ClipNotify) 291 (* pScreen->ClipNotify) (pChild, dx, dy); 292 293 } 294 if (pChild->valdata) 295 { 296 RegionNull(&pChild->valdata->after.borderExposed); 297 if (HasParentRelativeBorder(pChild)) 298 { 299 RegionSubtract(&pChild->valdata->after.borderExposed, 300 &pChild->borderClip, 301 &pChild->winSize); 302 } 303 RegionNull(&pChild->valdata->after.exposed); 304 } 305 if (pChild->firstChild) 306 { 307 pChild = pChild->firstChild; 308 continue; 309 } 310 } 311 while (!pChild->nextSib && (pChild != pParent)) 312 pChild = pChild->parent; 313 if (pChild == pParent) 314 break; 315 pChild = pChild->nextSib; 316 } 317 return; 318 } 319 /* fall through */ 320 default: 321 /* 322 * To calculate exposures correctly, we have to translate the old 323 * borderClip and clipList regions to the window's new location so there 324 * is a correspondence between pieces of the new and old clipping regions. 325 */ 326 if (dx || dy) 327 { 328 /* 329 * We translate the old clipList because that will be exposed or copied 330 * if gravity is right. 331 */ 332 RegionTranslate(&pParent->borderClip, dx, dy); 333 RegionTranslate(&pParent->clipList, dx, dy); 334 } 335 break; 336 case VTBroken: 337 RegionEmpty(&pParent->borderClip); 338 RegionEmpty(&pParent->clipList); 339 break; 340 } 341 342 borderVisible = pParent->valdata->before.borderVisible; 343 resized = pParent->valdata->before.resized; 344 RegionNull(&pParent->valdata->after.borderExposed); 345 RegionNull(&pParent->valdata->after.exposed); 346 347 /* 348 * Since the borderClip must not be clipped by the children, we do 349 * the border exposure first... 350 * 351 * 'universe' is the window's borderClip. To figure the exposures, remove 352 * the area that used to be exposed from the new. 353 * This leaves a region of pieces that weren't exposed before. 354 */ 355 356 if (HasBorder (pParent)) 357 { 358 if (borderVisible) 359 { 360 /* 361 * when the border changes shape, the old visible portions 362 * of the border will be saved by DIX in borderVisible -- 363 * use that region and destroy it 364 */ 365 RegionSubtract(exposed, universe, borderVisible); 366 RegionDestroy(borderVisible); 367 } 368 else 369 { 370 RegionSubtract(exposed, universe, &pParent->borderClip); 371 } 372 if (HasParentRelativeBorder(pParent) && (dx || dy)) { 373 RegionSubtract(&pParent->valdata->after.borderExposed, 374 universe, 375 &pParent->winSize); 376 } else { 377 RegionSubtract(&pParent->valdata->after.borderExposed, 378 exposed, &pParent->winSize); 379 } 380 381 RegionCopy(&pParent->borderClip, universe); 382 383 /* 384 * To get the right clipList for the parent, and to make doubly sure 385 * that no child overlaps the parent's border, we remove the parent's 386 * border from the universe before proceeding. 387 */ 388 389 RegionIntersect(universe, universe, &pParent->winSize); 390 } 391 else 392 RegionCopy(&pParent->borderClip, universe); 393 394 if ((pChild = pParent->firstChild) && pParent->mapped) 395 { 396 RegionNull(&childUniverse); 397 RegionNull(&childUnion); 398 if ((pChild->drawable.y < pParent->lastChild->drawable.y) || 399 ((pChild->drawable.y == pParent->lastChild->drawable.y) && 400 (pChild->drawable.x < pParent->lastChild->drawable.x))) 401 { 402 for (; pChild; pChild = pChild->nextSib) 403 { 404 if (pChild->viewable) 405 RegionAppend(&childUnion, &pChild->borderSize); 406 } 407 } 408 else 409 { 410 for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) 411 { 412 if (pChild->viewable) 413 RegionAppend(&childUnion, &pChild->borderSize); 414 } 415 } 416 RegionValidate(&childUnion, &overlap); 417 418 for (pChild = pParent->firstChild; 419 pChild; 420 pChild = pChild->nextSib) 421 { 422 if (pChild->viewable) { 423 /* 424 * If the child is viewable, we want to remove its extents 425 * from the current universe, but we only re-clip it if 426 * it's been marked. 427 */ 428 if (pChild->valdata) { 429 /* 430 * Figure out the new universe from the child's 431 * perspective and recurse. 432 */ 433 RegionIntersect(&childUniverse, 434 universe, 435 &pChild->borderSize); 436 RootlessComputeClips (pChild, pScreen, &childUniverse, 437 kind, exposed); 438 } 439 /* 440 * Once the child has been processed, we remove its extents 441 * from the current universe, thus denying its space to any 442 * other sibling. 443 */ 444 if (overlap) 445 RegionSubtract(universe, universe, 446 &pChild->borderSize); 447 } 448 } 449 if (!overlap) 450 RegionSubtract(universe, universe, &childUnion); 451 RegionUninit(&childUnion); 452 RegionUninit(&childUniverse); 453 } /* if any children */ 454 455 /* 456 * 'universe' now contains the new clipList for the parent window. 457 * 458 * To figure the exposure of the window we subtract the old clip from the 459 * new, just as for the border. 460 */ 461 462 if (oldVis == VisibilityFullyObscured || 463 oldVis == VisibilityNotViewable) 464 { 465 RegionCopy(&pParent->valdata->after.exposed, universe); 466 } 467 else if (newVis != VisibilityFullyObscured && 468 newVis != VisibilityNotViewable) 469 { 470 RegionSubtract(&pParent->valdata->after.exposed, 471 universe, &pParent->clipList); 472 } 473 474 /* 475 * One last thing: backing storage. We have to try to save what parts of 476 * the window are about to be obscured. We can just subtract the universe 477 * from the old clipList and get the areas that were in the old but aren't 478 * in the new and, hence, are about to be obscured. 479 */ 480 if (pParent->backStorage && !resized) 481 { 482 RegionSubtract(exposed, &pParent->clipList, universe); 483 (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy); 484 } 485 486 /* HACK ALERT - copying contents of regions, instead of regions */ 487 { 488 RegionRec tmp; 489 490 tmp = pParent->clipList; 491 pParent->clipList = *universe; 492 *universe = tmp; 493 } 494 495#ifdef NOTDEF 496 RegionCopy(&pParent->clipList, universe); 497#endif 498 499 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; 500 501 if (pScreen->ClipNotify) 502 (* pScreen->ClipNotify) (pParent, dx, dy); 503} 504 505static void 506RootlessTreeObscured(WindowPtr pParent) 507{ 508 register WindowPtr pChild; 509 register int oldVis; 510 511 pChild = pParent; 512 while (1) 513 { 514 if (pChild->viewable) 515 { 516 oldVis = pChild->visibility; 517 if (oldVis != (pChild->visibility = VisibilityFullyObscured) && 518 ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) 519 SendVisibilityNotify(pChild); 520 if (pChild->firstChild) 521 { 522 pChild = pChild->firstChild; 523 continue; 524 } 525 } 526 while (!pChild->nextSib && (pChild != pParent)) 527 pChild = pChild->parent; 528 if (pChild == pParent) 529 break; 530 pChild = pChild->nextSib; 531 } 532} 533 534/* 535 *----------------------------------------------------------------------- 536 * RootlessMiValidateTree -- 537 * Recomputes the clip list for pParent and all its inferiors. 538 * 539 * Results: 540 * Always returns 1. 541 * 542 * Side Effects: 543 * The clipList, borderClip, exposed, and borderExposed regions for 544 * each marked window are altered. 545 * 546 * Notes: 547 * This routine assumes that all affected windows have been marked 548 * (valdata created) and their winSize and borderSize regions 549 * adjusted to correspond to their new positions. The borderClip and 550 * clipList regions should not have been touched. 551 * 552 * The top-most level is treated differently from all lower levels 553 * because pParent is unchanged. For the top level, we merge the 554 * regions taken up by the marked children back into the clipList 555 * for pParent, thus forming a region from which the marked children 556 * can claim their areas. For lower levels, where the old clipList 557 * and borderClip are invalid, we can't do this and have to do the 558 * extra operations done in miComputeClips, but this is much faster 559 * e.g. when only one child has moved... 560 * 561 *----------------------------------------------------------------------- 562 */ 563/* 564 Quartz version: used for validate from root in rootless mode. 565 We need to make sure top-level windows don't clip each other, 566 and that top-level windows aren't clipped to the root window. 567*/ 568/*ARGSUSED*/ 569// fixme this is ugly 570// Xprint/ValTree.c doesn't work, but maybe that method can? 571int 572RootlessMiValidateTree (WindowPtr pRoot, /* Parent to validate */ 573 WindowPtr pChild, /* First child of pRoot that was 574 * affected */ 575 VTKind kind /* What kind of configuration caused call */) 576{ 577 RegionRec childClip; /* The new borderClip for the current 578 * child */ 579 RegionRec exposed; /* For intermediate calculations */ 580 register ScreenPtr pScreen; 581 register WindowPtr pWin; 582 583 pScreen = pRoot->drawable.pScreen; 584 if (pChild == NullWindow) 585 pChild = pRoot->firstChild; 586 587 RegionNull(&childClip); 588 RegionNull(&exposed); 589 590 if (RegionBroken(&pRoot->clipList) && 591 !RegionBroken(&pRoot->borderClip)) 592 { 593 // fixme this might not work, but hopefully doesn't happen anyway. 594 kind = VTBroken; 595 RegionEmpty(&pRoot->clipList); 596 ErrorF("ValidateTree: BUSTED!\n"); 597 } 598 599 /* 600 * Recursively compute the clips for all children of the root. 601 * They don't clip against each other or the root itself, so 602 * childClip is always reset to that child's size. 603 */ 604 605 for (pWin = pChild; 606 pWin != NullWindow; 607 pWin = pWin->nextSib) 608 { 609 if (pWin->viewable) { 610 if (pWin->valdata) { 611 RegionCopy(&childClip, &pWin->borderSize); 612 RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed); 613 } else if (pWin->visibility == VisibilityNotViewable) { 614 RootlessTreeObscured(pWin); 615 } 616 } else { 617 if (pWin->valdata) { 618 RegionEmpty(&pWin->clipList); 619 if (pScreen->ClipNotify) 620 (* pScreen->ClipNotify) (pWin, 0, 0); 621 RegionEmpty(&pWin->borderClip); 622 pWin->valdata = NULL; 623 } 624 } 625 } 626 627 RegionUninit(&childClip); 628 629 /* The root is never clipped by its children, so nothing on the root 630 is ever exposed by moving or mapping its children. */ 631 RegionNull(&pRoot->valdata->after.exposed); 632 RegionNull(&pRoot->valdata->after.borderExposed); 633 634 return 1; 635} 636