1/*********************************************************** 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 44 45******************************************************************/ 46/***************************************************************** 47 48Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 49 50Permission is hereby granted, free of charge, to any person obtaining a copy 51of this software and associated documentation files (the "Software"), to deal 52in the Software without restriction, including without limitation the rights 53to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54copies of the Software. 55 56The above copyright notice and this permission notice shall be included in 57all copies or substantial portions of the Software. 58 59THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 60IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 61FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 62DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 63BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 64WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 65IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 66 67Except as contained in this notice, the name of Digital Equipment Corporation 68shall not be used in advertising or otherwise to promote the sale, use or other 69dealings in this Software without prior written authorization from Digital 70Equipment Corporation. 71 72******************************************************************/ 73 74#ifdef HAVE_DIX_CONFIG_H 75#include <dix-config.h> 76#endif 77 78#include <X11/X.h> 79#include <X11/Xproto.h> 80#include <X11/Xprotostr.h> 81 82#include "misc.h" 83#include "regionstr.h" 84#include "scrnintstr.h" 85#include "gcstruct.h" 86#include "windowstr.h" 87#include "pixmap.h" 88#include "input.h" 89 90#include "dixstruct.h" 91#include "mi.h" 92#include <X11/Xmd.h> 93 94#include "globals.h" 95 96#ifdef PANORAMIX 97#include "panoramiX.h" 98#include "panoramiXsrv.h" 99#endif 100 101/* 102 machine-independent graphics exposure code. any device that uses 103the region package can call this. 104*/ 105 106#ifndef RECTLIMIT 107#define RECTLIMIT 25 /* pick a number, any number > 8 */ 108#endif 109 110/* miHandleExposures 111 generate a region for exposures for areas that were copied from obscured or 112non-existent areas to non-obscured areas of the destination. Paint the 113background for the region, if the destination is a window. 114 115*/ 116 117RegionPtr 118miHandleExposures(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, 119 GCPtr pGC, int srcx, int srcy, int width, int height, 120 int dstx, int dsty) 121{ 122 RegionPtr prgnSrcClip; /* drawable-relative source clip */ 123 RegionRec rgnSrcRec; 124 RegionPtr prgnDstClip; /* drawable-relative dest clip */ 125 RegionRec rgnDstRec; 126 BoxRec srcBox; /* unclipped source */ 127 RegionRec rgnExposed; /* exposed region, calculated source- 128 relative, made dst relative to 129 intersect with visible parts of 130 dest and send events to client, 131 and then screen relative to paint 132 the window background 133 */ 134 WindowPtr pSrcWin; 135 BoxRec expBox = { 0, }; 136 Bool extents; 137 138 /* avoid work if we can */ 139 if (!pGC->graphicsExposures && pDstDrawable->type == DRAWABLE_PIXMAP) 140 return NULL; 141 142 srcBox.x1 = srcx; 143 srcBox.y1 = srcy; 144 srcBox.x2 = srcx + width; 145 srcBox.y2 = srcy + height; 146 147 if (pSrcDrawable->type != DRAWABLE_PIXMAP) { 148 BoxRec TsrcBox; 149 150 TsrcBox.x1 = srcx + pSrcDrawable->x; 151 TsrcBox.y1 = srcy + pSrcDrawable->y; 152 TsrcBox.x2 = TsrcBox.x1 + width; 153 TsrcBox.y2 = TsrcBox.y1 + height; 154 pSrcWin = (WindowPtr) pSrcDrawable; 155 if (pGC->subWindowMode == IncludeInferiors) { 156 prgnSrcClip = NotClippedByChildren(pSrcWin); 157 if ((RegionContainsRect(prgnSrcClip, &TsrcBox)) == rgnIN) { 158 RegionDestroy(prgnSrcClip); 159 return NULL; 160 } 161 } 162 else { 163 if ((RegionContainsRect(&pSrcWin->clipList, &TsrcBox)) == rgnIN) 164 return NULL; 165 prgnSrcClip = &rgnSrcRec; 166 RegionNull(prgnSrcClip); 167 RegionCopy(prgnSrcClip, &pSrcWin->clipList); 168 } 169 RegionTranslate(prgnSrcClip, -pSrcDrawable->x, -pSrcDrawable->y); 170 } 171 else { 172 BoxRec box; 173 174 if ((srcBox.x1 >= 0) && (srcBox.y1 >= 0) && 175 (srcBox.x2 <= pSrcDrawable->width) && 176 (srcBox.y2 <= pSrcDrawable->height)) 177 return NULL; 178 179 box.x1 = 0; 180 box.y1 = 0; 181 box.x2 = pSrcDrawable->width; 182 box.y2 = pSrcDrawable->height; 183 prgnSrcClip = &rgnSrcRec; 184 RegionInit(prgnSrcClip, &box, 1); 185 pSrcWin = NULL; 186 } 187 188 if (pDstDrawable == pSrcDrawable) { 189 prgnDstClip = prgnSrcClip; 190 } 191 else if (pDstDrawable->type != DRAWABLE_PIXMAP) { 192 if (pGC->subWindowMode == IncludeInferiors) { 193 prgnDstClip = NotClippedByChildren((WindowPtr) pDstDrawable); 194 } 195 else { 196 prgnDstClip = &rgnDstRec; 197 RegionNull(prgnDstClip); 198 RegionCopy(prgnDstClip, &((WindowPtr) pDstDrawable)->clipList); 199 } 200 RegionTranslate(prgnDstClip, -pDstDrawable->x, -pDstDrawable->y); 201 } 202 else { 203 BoxRec box; 204 205 box.x1 = 0; 206 box.y1 = 0; 207 box.x2 = pDstDrawable->width; 208 box.y2 = pDstDrawable->height; 209 prgnDstClip = &rgnDstRec; 210 RegionInit(prgnDstClip, &box, 1); 211 } 212 213 /* drawable-relative source region */ 214 RegionInit(&rgnExposed, &srcBox, 1); 215 216 /* now get the hidden parts of the source box */ 217 RegionSubtract(&rgnExposed, &rgnExposed, prgnSrcClip); 218 219 /* move them over the destination */ 220 RegionTranslate(&rgnExposed, dstx - srcx, dsty - srcy); 221 222 /* intersect with visible areas of dest */ 223 RegionIntersect(&rgnExposed, &rgnExposed, prgnDstClip); 224 225 /* intersect with client clip region. */ 226 if (pGC->clientClip) 227 RegionIntersect(&rgnExposed, &rgnExposed, pGC->clientClip); 228 229 /* 230 * If we have LOTS of rectangles, we decide to take the extents 231 * and force an exposure on that. This should require much less 232 * work overall, on both client and server. This is cheating, but 233 * isn't prohibited by the protocol ("spontaneous combustion" :-) 234 * for windows. 235 */ 236 extents = pGC->graphicsExposures && 237 (RegionNumRects(&rgnExposed) > RECTLIMIT) && 238 (pDstDrawable->type != DRAWABLE_PIXMAP); 239 if (pSrcWin) { 240 RegionPtr region; 241 242 if (!(region = wClipShape(pSrcWin))) 243 region = wBoundingShape(pSrcWin); 244 /* 245 * If you try to CopyArea the extents of a shaped window, compacting the 246 * exposed region will undo all our work! 247 */ 248 if (extents && pSrcWin && region && 249 (RegionContainsRect(region, &srcBox) != rgnIN)) 250 extents = FALSE; 251 } 252 if (extents) { 253 expBox = *RegionExtents(&rgnExposed); 254 RegionReset(&rgnExposed, &expBox); 255 } 256 if ((pDstDrawable->type != DRAWABLE_PIXMAP) && 257 (((WindowPtr) pDstDrawable)->backgroundState != None)) { 258 WindowPtr pWin = (WindowPtr) pDstDrawable; 259 260 /* make the exposed area screen-relative */ 261 RegionTranslate(&rgnExposed, pDstDrawable->x, pDstDrawable->y); 262 263 if (extents) { 264 /* PaintWindow doesn't clip, so we have to */ 265 RegionIntersect(&rgnExposed, &rgnExposed, &pWin->clipList); 266 } 267 pDstDrawable->pScreen->PaintWindow((WindowPtr) pDstDrawable, 268 &rgnExposed, PW_BACKGROUND); 269 270 if (extents) { 271 RegionReset(&rgnExposed, &expBox); 272 } 273 else 274 RegionTranslate(&rgnExposed, -pDstDrawable->x, -pDstDrawable->y); 275 } 276 if (prgnDstClip == &rgnDstRec) { 277 RegionUninit(prgnDstClip); 278 } 279 else if (prgnDstClip != prgnSrcClip) { 280 RegionDestroy(prgnDstClip); 281 } 282 283 if (prgnSrcClip == &rgnSrcRec) { 284 RegionUninit(prgnSrcClip); 285 } 286 else { 287 RegionDestroy(prgnSrcClip); 288 } 289 290 if (pGC->graphicsExposures) { 291 /* don't look */ 292 RegionPtr exposed = RegionCreate(NullBox, 0); 293 294 *exposed = rgnExposed; 295 return exposed; 296 } 297 else { 298 RegionUninit(&rgnExposed); 299 return NULL; 300 } 301} 302 303void 304miSendExposures(WindowPtr pWin, RegionPtr pRgn, int dx, int dy) 305{ 306 BoxPtr pBox; 307 int numRects; 308 xEvent *pEvent, *pe; 309 int i; 310 311 pBox = RegionRects(pRgn); 312 numRects = RegionNumRects(pRgn); 313 if (!(pEvent = calloc(1, numRects * sizeof(xEvent)))) 314 return; 315 316 for (i = numRects, pe = pEvent; --i >= 0; pe++, pBox++) { 317 pe->u.u.type = Expose; 318 pe->u.expose.window = pWin->drawable.id; 319 pe->u.expose.x = pBox->x1 - dx; 320 pe->u.expose.y = pBox->y1 - dy; 321 pe->u.expose.width = pBox->x2 - pBox->x1; 322 pe->u.expose.height = pBox->y2 - pBox->y1; 323 pe->u.expose.count = i; 324 } 325 326#ifdef PANORAMIX 327 if (!noPanoramiXExtension) { 328 int scrnum = pWin->drawable.pScreen->myNum; 329 int x = 0, y = 0; 330 XID realWin = 0; 331 332 if (!pWin->parent) { 333 x = screenInfo.screens[scrnum]->x; 334 y = screenInfo.screens[scrnum]->y; 335 pWin = screenInfo.screens[0]->root; 336 realWin = pWin->drawable.id; 337 } 338 else if (scrnum) { 339 PanoramiXRes *win; 340 341 win = PanoramiXFindIDByScrnum(XRT_WINDOW, 342 pWin->drawable.id, scrnum); 343 if (!win) { 344 free(pEvent); 345 return; 346 } 347 realWin = win->info[0].id; 348 dixLookupWindow(&pWin, realWin, serverClient, DixSendAccess); 349 } 350 if (x || y || scrnum) 351 for (i = 0; i < numRects; i++) { 352 pEvent[i].u.expose.window = realWin; 353 pEvent[i].u.expose.x += x; 354 pEvent[i].u.expose.y += y; 355 } 356 } 357#endif 358 359 DeliverEvents(pWin, pEvent, numRects, NullWindow); 360 361 free(pEvent); 362} 363 364void 365miWindowExposures(WindowPtr pWin, RegionPtr prgn) 366{ 367 RegionPtr exposures = prgn; 368 369 if (prgn && !RegionNil(prgn)) { 370 RegionRec expRec; 371 int clientInterested = 372 (pWin->eventMask | wOtherEventMasks(pWin)) & ExposureMask; 373 if (clientInterested && (RegionNumRects(prgn) > RECTLIMIT)) { 374 /* 375 * If we have LOTS of rectangles, we decide to take the extents 376 * and force an exposure on that. This should require much less 377 * work overall, on both client and server. This is cheating, but 378 * isn't prohibited by the protocol ("spontaneous combustion" :-). 379 */ 380 BoxRec box = *RegionExtents(prgn); 381 exposures = &expRec; 382 RegionInit(exposures, &box, 1); 383 RegionReset(prgn, &box); 384 /* miPaintWindow doesn't clip, so we have to */ 385 RegionIntersect(prgn, prgn, &pWin->clipList); 386 } 387 pWin->drawable.pScreen->PaintWindow(pWin, prgn, PW_BACKGROUND); 388 if (clientInterested) 389 miSendExposures(pWin, exposures, 390 pWin->drawable.x, pWin->drawable.y); 391 if (exposures == &expRec) 392 RegionUninit(exposures); 393 RegionEmpty(prgn); 394 } 395} 396 397void 398miPaintWindow(WindowPtr pWin, RegionPtr prgn, int what) 399{ 400 ScreenPtr pScreen = pWin->drawable.pScreen; 401 ChangeGCVal gcval[6]; 402 BITS32 gcmask; 403 GCPtr pGC; 404 int i; 405 BoxPtr pbox; 406 xRectangle *prect; 407 int numRects, regionnumrects; 408 409 /* 410 * Distance from screen to destination drawable, use this 411 * to adjust rendering coordinates which come in in screen space 412 */ 413 int draw_x_off, draw_y_off; 414 415 /* 416 * Tile offset for drawing; these need to align the tile 417 * to the appropriate window origin 418 */ 419 int tile_x_off, tile_y_off; 420 PixUnion fill; 421 Bool solid = TRUE; 422 DrawablePtr drawable = &pWin->drawable; 423 424 if (what == PW_BACKGROUND) { 425 while (pWin->backgroundState == ParentRelative) 426 pWin = pWin->parent; 427 428 draw_x_off = drawable->x; 429 draw_y_off = drawable->y; 430 431 tile_x_off = pWin->drawable.x - draw_x_off; 432 tile_y_off = pWin->drawable.y - draw_y_off; 433 fill = pWin->background; 434#ifdef COMPOSITE 435 if (pWin->inhibitBGPaint) 436 return; 437#endif 438 switch (pWin->backgroundState) { 439 case None: 440 return; 441 case BackgroundPixmap: 442 solid = FALSE; 443 break; 444 } 445 } 446 else { 447 PixmapPtr pixmap; 448 449 fill = pWin->border; 450 solid = pWin->borderIsPixel; 451 452 /* servers without pixmaps draw their own borders */ 453 if (!pScreen->GetWindowPixmap) 454 return; 455 pixmap = (*pScreen->GetWindowPixmap) ((WindowPtr) drawable); 456 drawable = &pixmap->drawable; 457 458 while (pWin->backgroundState == ParentRelative) 459 pWin = pWin->parent; 460 461 tile_x_off = pWin->drawable.x; 462 tile_y_off = pWin->drawable.y; 463 464#ifdef COMPOSITE 465 draw_x_off = pixmap->screen_x; 466 draw_y_off = pixmap->screen_y; 467 tile_x_off -= draw_x_off; 468 tile_y_off -= draw_y_off; 469#else 470 draw_x_off = 0; 471 draw_y_off = 0; 472#endif 473 } 474 475 gcval[0].val = GXcopy; 476 gcmask = GCFunction; 477 478#ifdef ROOTLESS_SAFEALPHA 479/* Bit mask for alpha channel with a particular number of bits per 480 * pixel. Note that we only care for 32bpp data. Mac OS X uses planar 481 * alpha for 16bpp. 482 */ 483#define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0) 484#endif 485 486 if (solid) { 487#ifdef ROOTLESS_SAFEALPHA 488 gcval[1].val = 489 fill.pixel | RootlessAlphaMask(pWin->drawable.bitsPerPixel); 490#else 491 gcval[1].val = fill.pixel; 492#endif 493 gcval[2].val = FillSolid; 494 gcmask |= GCForeground | GCFillStyle; 495 } 496 else { 497 int c = 1; 498 499#ifdef ROOTLESS_SAFEALPHA 500 gcval[c++].val = 501 ((CARD32) -1) & ~RootlessAlphaMask(pWin->drawable.bitsPerPixel); 502 gcmask |= GCPlaneMask; 503#endif 504 gcval[c++].val = FillTiled; 505 gcval[c++].ptr = (void *) fill.pixmap; 506 gcval[c++].val = tile_x_off; 507 gcval[c++].val = tile_y_off; 508 gcmask |= GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin; 509 } 510 511 regionnumrects = RegionNumRects(prgn); 512 if (regionnumrects == 0) 513 return; 514 prect = xallocarray(regionnumrects, sizeof(xRectangle)); 515 if (!prect) 516 return; 517 518 pGC = GetScratchGC(drawable->depth, drawable->pScreen); 519 if (!pGC) { 520 free(prect); 521 return; 522 } 523 524 ChangeGC(NullClient, pGC, gcmask, gcval); 525 ValidateGC(drawable, pGC); 526 527 numRects = RegionNumRects(prgn); 528 pbox = RegionRects(prgn); 529 for (i = numRects; --i >= 0; pbox++, prect++) { 530 prect->x = pbox->x1 - draw_x_off; 531 prect->y = pbox->y1 - draw_y_off; 532 prect->width = pbox->x2 - pbox->x1; 533 prect->height = pbox->y2 - pbox->y1; 534 } 535 prect -= numRects; 536 (*pGC->ops->PolyFillRect) (drawable, pGC, numRects, prect); 537 free(prect); 538 539 FreeScratchGC(pGC); 540} 541 542/* MICLEARDRAWABLE -- sets the entire drawable to the background color of 543 * the GC. Useful when we have a scratch drawable and need to initialize 544 * it. */ 545void 546miClearDrawable(DrawablePtr pDraw, GCPtr pGC) 547{ 548 ChangeGCVal fg, bg; 549 xRectangle rect; 550 551 fg.val = pGC->fgPixel; 552 bg.val = pGC->bgPixel; 553 rect.x = 0; 554 rect.y = 0; 555 rect.width = pDraw->width; 556 rect.height = pDraw->height; 557 ChangeGC(NullClient, pGC, GCForeground, &bg); 558 ValidateGC(pDraw, pGC); 559 (*pGC->ops->PolyFillRect) (pDraw, pGC, 1, &rect); 560 ChangeGC(NullClient, pGC, GCForeground, &fg); 561 ValidateGC(pDraw, pGC); 562} 563