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