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