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