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 /* HACK ALERT - copying contents of regions, instead of regions */ 475 { 476 RegionRec tmp; 477 478 tmp = pParent->clipList; 479 pParent->clipList = *universe; 480 *universe = tmp; 481 } 482 483#ifdef NOTDEF 484 RegionCopy(&pParent->clipList, universe); 485#endif 486 487 pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; 488 489 if (pScreen->ClipNotify) 490 (* pScreen->ClipNotify) (pParent, dx, dy); 491} 492 493static void 494RootlessTreeObscured(WindowPtr pParent) 495{ 496 register WindowPtr pChild; 497 register int oldVis; 498 499 pChild = pParent; 500 while (1) 501 { 502 if (pChild->viewable) 503 { 504 oldVis = pChild->visibility; 505 if (oldVis != (pChild->visibility = VisibilityFullyObscured) && 506 ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) 507 SendVisibilityNotify(pChild); 508 if (pChild->firstChild) 509 { 510 pChild = pChild->firstChild; 511 continue; 512 } 513 } 514 while (!pChild->nextSib && (pChild != pParent)) 515 pChild = pChild->parent; 516 if (pChild == pParent) 517 break; 518 pChild = pChild->nextSib; 519 } 520} 521 522/* 523 *----------------------------------------------------------------------- 524 * RootlessMiValidateTree -- 525 * Recomputes the clip list for pParent and all its inferiors. 526 * 527 * Results: 528 * Always returns 1. 529 * 530 * Side Effects: 531 * The clipList, borderClip, exposed, and borderExposed regions for 532 * each marked window are altered. 533 * 534 * Notes: 535 * This routine assumes that all affected windows have been marked 536 * (valdata created) and their winSize and borderSize regions 537 * adjusted to correspond to their new positions. The borderClip and 538 * clipList regions should not have been touched. 539 * 540 * The top-most level is treated differently from all lower levels 541 * because pParent is unchanged. For the top level, we merge the 542 * regions taken up by the marked children back into the clipList 543 * for pParent, thus forming a region from which the marked children 544 * can claim their areas. For lower levels, where the old clipList 545 * and borderClip are invalid, we can't do this and have to do the 546 * extra operations done in miComputeClips, but this is much faster 547 * e.g. when only one child has moved... 548 * 549 *----------------------------------------------------------------------- 550 */ 551/* 552 Quartz version: used for validate from root in rootless mode. 553 We need to make sure top-level windows don't clip each other, 554 and that top-level windows aren't clipped to the root window. 555*/ 556/*ARGSUSED*/ 557// fixme this is ugly 558// Xprint/ValTree.c doesn't work, but maybe that method can? 559int 560RootlessMiValidateTree (WindowPtr pRoot, /* Parent to validate */ 561 WindowPtr pChild, /* First child of pRoot that was 562 * affected */ 563 VTKind kind /* What kind of configuration caused call */) 564{ 565 RegionRec childClip; /* The new borderClip for the current 566 * child */ 567 RegionRec exposed; /* For intermediate calculations */ 568 register ScreenPtr pScreen; 569 register WindowPtr pWin; 570 571 pScreen = pRoot->drawable.pScreen; 572 if (pChild == NullWindow) 573 pChild = pRoot->firstChild; 574 575 RegionNull(&childClip); 576 RegionNull(&exposed); 577 578 if (RegionBroken(&pRoot->clipList) && 579 !RegionBroken(&pRoot->borderClip)) 580 { 581 // fixme this might not work, but hopefully doesn't happen anyway. 582 kind = VTBroken; 583 RegionEmpty(&pRoot->clipList); 584 ErrorF("ValidateTree: BUSTED!\n"); 585 } 586 587 /* 588 * Recursively compute the clips for all children of the root. 589 * They don't clip against each other or the root itself, so 590 * childClip is always reset to that child's size. 591 */ 592 593 for (pWin = pChild; 594 pWin != NullWindow; 595 pWin = pWin->nextSib) 596 { 597 if (pWin->viewable) { 598 if (pWin->valdata) { 599 RegionCopy(&childClip, &pWin->borderSize); 600 RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed); 601 } else if (pWin->visibility == VisibilityNotViewable) { 602 RootlessTreeObscured(pWin); 603 } 604 } else { 605 if (pWin->valdata) { 606 RegionEmpty(&pWin->clipList); 607 if (pScreen->ClipNotify) 608 (* pScreen->ClipNotify) (pWin, 0, 0); 609 RegionEmpty(&pWin->borderClip); 610 pWin->valdata = NULL; 611 } 612 } 613 } 614 615 RegionUninit(&childClip); 616 617 /* The root is never clipped by its children, so nothing on the root 618 is ever exposed by moving or mapping its children. */ 619 RegionNull(&pRoot->valdata->after.exposed); 620 RegionNull(&pRoot->valdata->after.borderExposed); 621 622 return 1; 623} 624