panoramiX.c revision 52397711
1/***************************************************************** 2Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 3Permission is hereby granted, free of charge, to any person obtaining a copy 4of this software and associated documentation files (the "Software"), to deal 5in the Software without restriction, including without limitation the rights 6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7copies of the Software. 8 9The above copyright notice and this permission notice shall be included in 10all copies or substantial portions of the Software. 11 12THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 15DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 16BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 17WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 18IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 20Except as contained in this notice, the name of Digital Equipment Corporation 21shall not be used in advertising or otherwise to promote the sale, use or other 22dealings in this Software without prior written authorization from Digital 23Equipment Corporation. 24******************************************************************/ 25 26#ifdef HAVE_DIX_CONFIG_H 27#include <dix-config.h> 28#endif 29 30#ifdef HAVE_DMX_CONFIG_H 31#include <dmx-config.h> 32#endif 33 34#define NEED_REPLIES 35#include <stdio.h> 36#include <X11/X.h> 37#include <X11/Xproto.h> 38#include <X11/Xarch.h> 39#include "misc.h" 40#include "cursor.h" 41#include "cursorstr.h" 42#include "extnsionst.h" 43#include "dixstruct.h" 44#include "gc.h" 45#include "gcstruct.h" 46#include "scrnintstr.h" 47#include "window.h" 48#include "windowstr.h" 49#include "pixmapstr.h" 50#include "panoramiX.h" 51#include <X11/extensions/panoramiXproto.h> 52#include "panoramiXsrv.h" 53#include "globals.h" 54#include "servermd.h" 55#include "resource.h" 56#ifdef RENDER 57#include "picturestr.h" 58#endif 59#include "modinit.h" 60 61#define SERVER_PANORAMIX_MAJOR_VERSION 1 62#define SERVER_PANORAMIX_MINOR_VERSION 1 63 64#ifdef GLXPROXY 65extern VisualPtr glxMatchVisual(ScreenPtr pScreen, 66 VisualPtr pVisual, 67 ScreenPtr pMatchScreen); 68#endif 69 70/* 71 * PanoramiX data declarations 72 */ 73 74int PanoramiXPixWidth = 0; 75int PanoramiXPixHeight = 0; 76_X_EXPORT int PanoramiXNumScreens = 0; 77 78_X_EXPORT PanoramiXData *panoramiXdataPtr = NULL; 79static RegionRec PanoramiXScreenRegion = {{0, 0, 0, 0}, NULL}; 80 81static int PanoramiXNumDepths; 82static DepthPtr PanoramiXDepths; 83static int PanoramiXNumVisuals; 84static VisualPtr PanoramiXVisuals; 85 86_X_EXPORT unsigned long XRC_DRAWABLE; 87_X_EXPORT unsigned long XRT_WINDOW; 88_X_EXPORT unsigned long XRT_PIXMAP; 89_X_EXPORT unsigned long XRT_GC; 90_X_EXPORT unsigned long XRT_COLORMAP; 91 92static Bool VisualsEqual(VisualPtr, ScreenPtr, VisualPtr); 93_X_EXPORT XineramaVisualsEqualProcPtr XineramaVisualsEqualPtr = &VisualsEqual; 94 95/* 96 * Function prototypes 97 */ 98 99static int panoramiXGeneration; 100static int ProcPanoramiXDispatch(ClientPtr client); 101 102static void PanoramiXResetProc(ExtensionEntry*); 103 104/* 105 * External references for functions and data variables 106 */ 107 108#include "panoramiXh.h" 109 110int (* SavedProcVector[256]) (ClientPtr client) = { NULL, }; 111 112static int PanoramiXGCKeyIndex; 113static DevPrivateKey PanoramiXGCKey = &PanoramiXGCKeyIndex; 114static int PanoramiXScreenKeyIndex; 115static DevPrivateKey PanoramiXScreenKey = &PanoramiXScreenKeyIndex; 116 117typedef struct { 118 DDXPointRec clipOrg; 119 DDXPointRec patOrg; 120 GCFuncs *wrapFuncs; 121} PanoramiXGCRec, *PanoramiXGCPtr; 122 123typedef struct { 124 CreateGCProcPtr CreateGC; 125 CloseScreenProcPtr CloseScreen; 126} PanoramiXScreenRec, *PanoramiXScreenPtr; 127 128RegionRec XineramaScreenRegions[MAXSCREENS]; 129 130static void XineramaValidateGC(GCPtr, unsigned long, DrawablePtr); 131static void XineramaChangeGC(GCPtr, unsigned long); 132static void XineramaCopyGC(GCPtr, unsigned long, GCPtr); 133static void XineramaDestroyGC(GCPtr); 134static void XineramaChangeClip(GCPtr, int, pointer, int); 135static void XineramaDestroyClip(GCPtr); 136static void XineramaCopyClip(GCPtr, GCPtr); 137 138static GCFuncs XineramaGCFuncs = { 139 XineramaValidateGC, XineramaChangeGC, XineramaCopyGC, XineramaDestroyGC, 140 XineramaChangeClip, XineramaDestroyClip, XineramaCopyClip 141}; 142 143#define Xinerama_GC_FUNC_PROLOGUE(pGC)\ 144 PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) \ 145 dixLookupPrivate(&(pGC)->devPrivates, PanoramiXGCKey); \ 146 (pGC)->funcs = pGCPriv->wrapFuncs; 147 148#define Xinerama_GC_FUNC_EPILOGUE(pGC)\ 149 pGCPriv->wrapFuncs = (pGC)->funcs;\ 150 (pGC)->funcs = &XineramaGCFuncs; 151 152 153static Bool 154XineramaCloseScreen (int i, ScreenPtr pScreen) 155{ 156 PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) 157 dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); 158 159 pScreen->CloseScreen = pScreenPriv->CloseScreen; 160 pScreen->CreateGC = pScreenPriv->CreateGC; 161 162 REGION_UNINIT(pScreen, &XineramaScreenRegions[pScreen->myNum]); 163 if (pScreen->myNum == 0) 164 REGION_UNINIT(pScreen, &PanoramiXScreenRegion); 165 166 xfree ((pointer) pScreenPriv); 167 168 return (*pScreen->CloseScreen) (i, pScreen); 169} 170 171static Bool 172XineramaCreateGC(GCPtr pGC) 173{ 174 ScreenPtr pScreen = pGC->pScreen; 175 PanoramiXScreenPtr pScreenPriv = (PanoramiXScreenPtr) 176 dixLookupPrivate(&pScreen->devPrivates, PanoramiXScreenKey); 177 Bool ret; 178 179 pScreen->CreateGC = pScreenPriv->CreateGC; 180 if((ret = (*pScreen->CreateGC)(pGC))) { 181 PanoramiXGCPtr pGCPriv = (PanoramiXGCPtr) 182 dixLookupPrivate(&pGC->devPrivates, PanoramiXGCKey); 183 184 pGCPriv->wrapFuncs = pGC->funcs; 185 pGC->funcs = &XineramaGCFuncs; 186 187 pGCPriv->clipOrg.x = pGC->clipOrg.x; 188 pGCPriv->clipOrg.y = pGC->clipOrg.y; 189 pGCPriv->patOrg.x = pGC->patOrg.x; 190 pGCPriv->patOrg.y = pGC->patOrg.y; 191 } 192 pScreen->CreateGC = XineramaCreateGC; 193 194 return ret; 195} 196 197static void 198XineramaValidateGC( 199 GCPtr pGC, 200 unsigned long changes, 201 DrawablePtr pDraw 202){ 203 Xinerama_GC_FUNC_PROLOGUE (pGC); 204 205 if((pDraw->type == DRAWABLE_WINDOW) && !(((WindowPtr)pDraw)->parent)) { 206 /* the root window */ 207 int x_off = panoramiXdataPtr[pGC->pScreen->myNum].x; 208 int y_off = panoramiXdataPtr[pGC->pScreen->myNum].y; 209 int new_val; 210 211 new_val = pGCPriv->clipOrg.x - x_off; 212 if(pGC->clipOrg.x != new_val) { 213 pGC->clipOrg.x = new_val; 214 changes |= GCClipXOrigin; 215 } 216 new_val = pGCPriv->clipOrg.y - y_off; 217 if(pGC->clipOrg.y != new_val) { 218 pGC->clipOrg.y = new_val; 219 changes |= GCClipYOrigin; 220 } 221 new_val = pGCPriv->patOrg.x - x_off; 222 if(pGC->patOrg.x != new_val) { 223 pGC->patOrg.x = new_val; 224 changes |= GCTileStipXOrigin; 225 } 226 new_val = pGCPriv->patOrg.y - y_off; 227 if(pGC->patOrg.y != new_val) { 228 pGC->patOrg.y = new_val; 229 changes |= GCTileStipYOrigin; 230 } 231 } else { 232 if(pGC->clipOrg.x != pGCPriv->clipOrg.x) { 233 pGC->clipOrg.x = pGCPriv->clipOrg.x; 234 changes |= GCClipXOrigin; 235 } 236 if(pGC->clipOrg.y != pGCPriv->clipOrg.y) { 237 pGC->clipOrg.y = pGCPriv->clipOrg.y; 238 changes |= GCClipYOrigin; 239 } 240 if(pGC->patOrg.x != pGCPriv->patOrg.x) { 241 pGC->patOrg.x = pGCPriv->patOrg.x; 242 changes |= GCTileStipXOrigin; 243 } 244 if(pGC->patOrg.y != pGCPriv->patOrg.y) { 245 pGC->patOrg.y = pGCPriv->patOrg.y; 246 changes |= GCTileStipYOrigin; 247 } 248 } 249 250 (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); 251 Xinerama_GC_FUNC_EPILOGUE (pGC); 252} 253 254static void 255XineramaDestroyGC(GCPtr pGC) 256{ 257 Xinerama_GC_FUNC_PROLOGUE (pGC); 258 (*pGC->funcs->DestroyGC)(pGC); 259 Xinerama_GC_FUNC_EPILOGUE (pGC); 260} 261 262static void 263XineramaChangeGC ( 264 GCPtr pGC, 265 unsigned long mask 266){ 267 Xinerama_GC_FUNC_PROLOGUE (pGC); 268 269 if(mask & GCTileStipXOrigin) 270 pGCPriv->patOrg.x = pGC->patOrg.x; 271 if(mask & GCTileStipYOrigin) 272 pGCPriv->patOrg.y = pGC->patOrg.y; 273 if(mask & GCClipXOrigin) 274 pGCPriv->clipOrg.x = pGC->clipOrg.x; 275 if(mask & GCClipYOrigin) 276 pGCPriv->clipOrg.y = pGC->clipOrg.y; 277 278 (*pGC->funcs->ChangeGC) (pGC, mask); 279 Xinerama_GC_FUNC_EPILOGUE (pGC); 280} 281 282static void 283XineramaCopyGC ( 284 GCPtr pGCSrc, 285 unsigned long mask, 286 GCPtr pGCDst 287){ 288 PanoramiXGCPtr pSrcPriv = (PanoramiXGCPtr) 289 dixLookupPrivate(&pGCSrc->devPrivates, PanoramiXGCKey); 290 Xinerama_GC_FUNC_PROLOGUE (pGCDst); 291 292 if(mask & GCTileStipXOrigin) 293 pGCPriv->patOrg.x = pSrcPriv->patOrg.x; 294 if(mask & GCTileStipYOrigin) 295 pGCPriv->patOrg.y = pSrcPriv->patOrg.y; 296 if(mask & GCClipXOrigin) 297 pGCPriv->clipOrg.x = pSrcPriv->clipOrg.x; 298 if(mask & GCClipYOrigin) 299 pGCPriv->clipOrg.y = pSrcPriv->clipOrg.y; 300 301 (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); 302 Xinerama_GC_FUNC_EPILOGUE (pGCDst); 303} 304 305static void 306XineramaChangeClip ( 307 GCPtr pGC, 308 int type, 309 pointer pvalue, 310 int nrects 311){ 312 Xinerama_GC_FUNC_PROLOGUE (pGC); 313 (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); 314 Xinerama_GC_FUNC_EPILOGUE (pGC); 315} 316 317static void 318XineramaCopyClip(GCPtr pgcDst, GCPtr pgcSrc) 319{ 320 Xinerama_GC_FUNC_PROLOGUE (pgcDst); 321 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); 322 Xinerama_GC_FUNC_EPILOGUE (pgcDst); 323} 324 325static void 326XineramaDestroyClip(GCPtr pGC) 327{ 328 Xinerama_GC_FUNC_PROLOGUE (pGC); 329 (* pGC->funcs->DestroyClip)(pGC); 330 Xinerama_GC_FUNC_EPILOGUE (pGC); 331} 332 333_X_EXPORT int 334XineramaDeleteResource(pointer data, XID id) 335{ 336 xfree(data); 337 return 1; 338} 339 340typedef struct { 341 int screen; 342 int id; 343} PanoramiXSearchData; 344 345static Bool 346XineramaFindIDByScrnum(pointer resource, XID id, pointer privdata) 347{ 348 PanoramiXRes *res = (PanoramiXRes*)resource; 349 PanoramiXSearchData *data = (PanoramiXSearchData*)privdata; 350 351 return (res->info[data->screen].id == data->id); 352} 353 354PanoramiXRes * 355PanoramiXFindIDByScrnum(RESTYPE type, XID id, int screen) 356{ 357 PanoramiXSearchData data; 358 359 if(!screen) 360 return LookupIDByType(id, type); 361 362 data.screen = screen; 363 data.id = id; 364 365 return LookupClientResourceComplex(clients[CLIENT_ID(id)], type, 366 XineramaFindIDByScrnum, &data); 367} 368 369typedef struct _connect_callback_list { 370 void (*func)(void); 371 struct _connect_callback_list *next; 372} XineramaConnectionCallbackList; 373 374static XineramaConnectionCallbackList *ConnectionCallbackList = NULL; 375 376_X_EXPORT Bool 377XineramaRegisterConnectionBlockCallback(void (*func)(void)) 378{ 379 XineramaConnectionCallbackList *newlist; 380 381 if(!(newlist = xalloc(sizeof(XineramaConnectionCallbackList)))) 382 return FALSE; 383 384 newlist->next = ConnectionCallbackList; 385 newlist->func = func; 386 ConnectionCallbackList = newlist; 387 388 return TRUE; 389} 390 391static void XineramaInitData(ScreenPtr pScreen) 392{ 393 int i, w, h; 394 395 REGION_NULL(pScreen, &PanoramiXScreenRegion) 396 for (i = 0; i < PanoramiXNumScreens; i++) { 397 BoxRec TheBox; 398 399 pScreen = screenInfo.screens[i]; 400 401 panoramiXdataPtr[i].x = dixScreenOrigins[i].x; 402 panoramiXdataPtr[i].y = dixScreenOrigins[i].y; 403 panoramiXdataPtr[i].width = pScreen->width; 404 panoramiXdataPtr[i].height = pScreen->height; 405 406 TheBox.x1 = panoramiXdataPtr[i].x; 407 TheBox.x2 = TheBox.x1 + panoramiXdataPtr[i].width; 408 TheBox.y1 = panoramiXdataPtr[i].y; 409 TheBox.y2 = TheBox.y1 + panoramiXdataPtr[i].height; 410 411 REGION_INIT(pScreen, &XineramaScreenRegions[i], &TheBox, 1); 412 REGION_UNION(pScreen, &PanoramiXScreenRegion, &PanoramiXScreenRegion, 413 &XineramaScreenRegions[i]); 414 } 415 416 PanoramiXPixWidth = panoramiXdataPtr[0].x + panoramiXdataPtr[0].width; 417 PanoramiXPixHeight = panoramiXdataPtr[0].y + panoramiXdataPtr[0].height; 418 419 for (i = 1; i < PanoramiXNumScreens; i++) { 420 w = panoramiXdataPtr[i].x + panoramiXdataPtr[i].width; 421 h = panoramiXdataPtr[i].y + panoramiXdataPtr[i].height; 422 423 if (PanoramiXPixWidth < w) 424 PanoramiXPixWidth = w; 425 if (PanoramiXPixHeight < h) 426 PanoramiXPixHeight = h; 427 } 428} 429 430void XineramaReinitData(ScreenPtr pScreen) 431{ 432 int i; 433 434 REGION_UNINIT(pScreen, &PanoramiXScreenRegion); 435 for (i = 0; i < PanoramiXNumScreens; i++) 436 REGION_UNINIT(pScreen, &XineramaScreenRegions[i]); 437 438 XineramaInitData(pScreen); 439} 440 441/* 442 * PanoramiXExtensionInit(): 443 * Called from InitExtensions in main(). 444 * Register PanoramiXeen Extension 445 * Initialize global variables. 446 */ 447 448void PanoramiXExtensionInit(int argc, char *argv[]) 449{ 450 int i; 451 Bool success = FALSE; 452 ExtensionEntry *extEntry; 453 ScreenPtr pScreen = screenInfo.screens[0]; 454 PanoramiXScreenPtr pScreenPriv; 455 456 if (noPanoramiXExtension) 457 return; 458 459 PanoramiXNumScreens = screenInfo.numScreens; 460 if (PanoramiXNumScreens == 1) { /* Only 1 screen */ 461 noPanoramiXExtension = TRUE; 462 return; 463 } 464 465 while (panoramiXGeneration != serverGeneration) { 466 extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, 467 ProcPanoramiXDispatch, 468 SProcPanoramiXDispatch, PanoramiXResetProc, 469 StandardMinorOpcode); 470 if (!extEntry) 471 break; 472 473 /* 474 * First make sure all the basic allocations succeed. If not, 475 * run in non-PanoramiXeen mode. 476 */ 477 478 panoramiXdataPtr = (PanoramiXData *) 479 xcalloc(PanoramiXNumScreens, sizeof(PanoramiXData)); 480 481 BREAK_IF(!panoramiXdataPtr); 482 483 if (!dixRequestPrivate(PanoramiXGCKey, sizeof(PanoramiXGCRec))) { 484 noPanoramiXExtension = TRUE; 485 return; 486 } 487 488 for (i = 0; i < PanoramiXNumScreens; i++) { 489 pScreen = screenInfo.screens[i]; 490 pScreenPriv = xalloc(sizeof(PanoramiXScreenRec)); 491 dixSetPrivate(&pScreen->devPrivates, PanoramiXScreenKey, 492 pScreenPriv); 493 if(!pScreenPriv) { 494 noPanoramiXExtension = TRUE; 495 return; 496 } 497 498 pScreenPriv->CreateGC = pScreen->CreateGC; 499 pScreenPriv->CloseScreen = pScreen->CloseScreen; 500 501 pScreen->CreateGC = XineramaCreateGC; 502 pScreen->CloseScreen = XineramaCloseScreen; 503 } 504 505 XRC_DRAWABLE = CreateNewResourceClass(); 506 XRT_WINDOW = CreateNewResourceType(XineramaDeleteResource) | 507 XRC_DRAWABLE; 508 XRT_PIXMAP = CreateNewResourceType(XineramaDeleteResource) | 509 XRC_DRAWABLE; 510 XRT_GC = CreateNewResourceType(XineramaDeleteResource); 511 XRT_COLORMAP = CreateNewResourceType(XineramaDeleteResource); 512 513 panoramiXGeneration = serverGeneration; 514 success = TRUE; 515 } 516 517 if (!success) { 518 noPanoramiXExtension = TRUE; 519 ErrorF(PANORAMIX_PROTOCOL_NAME " extension failed to initialize\n"); 520 return; 521 } 522 523 XineramaInitData(pScreen); 524 525 /* 526 * Put our processes into the ProcVector 527 */ 528 529 for (i = 256; i--; ) 530 SavedProcVector[i] = ProcVector[i]; 531 532 ProcVector[X_CreateWindow] = PanoramiXCreateWindow; 533 ProcVector[X_ChangeWindowAttributes] = PanoramiXChangeWindowAttributes; 534 ProcVector[X_DestroyWindow] = PanoramiXDestroyWindow; 535 ProcVector[X_DestroySubwindows] = PanoramiXDestroySubwindows; 536 ProcVector[X_ChangeSaveSet] = PanoramiXChangeSaveSet; 537 ProcVector[X_ReparentWindow] = PanoramiXReparentWindow; 538 ProcVector[X_MapWindow] = PanoramiXMapWindow; 539 ProcVector[X_MapSubwindows] = PanoramiXMapSubwindows; 540 ProcVector[X_UnmapWindow] = PanoramiXUnmapWindow; 541 ProcVector[X_UnmapSubwindows] = PanoramiXUnmapSubwindows; 542 ProcVector[X_ConfigureWindow] = PanoramiXConfigureWindow; 543 ProcVector[X_CirculateWindow] = PanoramiXCirculateWindow; 544 ProcVector[X_GetGeometry] = PanoramiXGetGeometry; 545 ProcVector[X_TranslateCoords] = PanoramiXTranslateCoords; 546 ProcVector[X_CreatePixmap] = PanoramiXCreatePixmap; 547 ProcVector[X_FreePixmap] = PanoramiXFreePixmap; 548 ProcVector[X_CreateGC] = PanoramiXCreateGC; 549 ProcVector[X_ChangeGC] = PanoramiXChangeGC; 550 ProcVector[X_CopyGC] = PanoramiXCopyGC; 551 ProcVector[X_SetDashes] = PanoramiXSetDashes; 552 ProcVector[X_SetClipRectangles] = PanoramiXSetClipRectangles; 553 ProcVector[X_FreeGC] = PanoramiXFreeGC; 554 ProcVector[X_ClearArea] = PanoramiXClearToBackground; 555 ProcVector[X_CopyArea] = PanoramiXCopyArea; 556 ProcVector[X_CopyPlane] = PanoramiXCopyPlane; 557 ProcVector[X_PolyPoint] = PanoramiXPolyPoint; 558 ProcVector[X_PolyLine] = PanoramiXPolyLine; 559 ProcVector[X_PolySegment] = PanoramiXPolySegment; 560 ProcVector[X_PolyRectangle] = PanoramiXPolyRectangle; 561 ProcVector[X_PolyArc] = PanoramiXPolyArc; 562 ProcVector[X_FillPoly] = PanoramiXFillPoly; 563 ProcVector[X_PolyFillRectangle] = PanoramiXPolyFillRectangle; 564 ProcVector[X_PolyFillArc] = PanoramiXPolyFillArc; 565 ProcVector[X_PutImage] = PanoramiXPutImage; 566 ProcVector[X_GetImage] = PanoramiXGetImage; 567 ProcVector[X_PolyText8] = PanoramiXPolyText8; 568 ProcVector[X_PolyText16] = PanoramiXPolyText16; 569 ProcVector[X_ImageText8] = PanoramiXImageText8; 570 ProcVector[X_ImageText16] = PanoramiXImageText16; 571 ProcVector[X_CreateColormap] = PanoramiXCreateColormap; 572 ProcVector[X_FreeColormap] = PanoramiXFreeColormap; 573 ProcVector[X_CopyColormapAndFree] = PanoramiXCopyColormapAndFree; 574 ProcVector[X_InstallColormap] = PanoramiXInstallColormap; 575 ProcVector[X_UninstallColormap] = PanoramiXUninstallColormap; 576 ProcVector[X_AllocColor] = PanoramiXAllocColor; 577 ProcVector[X_AllocNamedColor] = PanoramiXAllocNamedColor; 578 ProcVector[X_AllocColorCells] = PanoramiXAllocColorCells; 579 ProcVector[X_AllocColorPlanes] = PanoramiXAllocColorPlanes; 580 ProcVector[X_FreeColors] = PanoramiXFreeColors; 581 ProcVector[X_StoreColors] = PanoramiXStoreColors; 582 ProcVector[X_StoreNamedColor] = PanoramiXStoreNamedColor; 583 584#ifdef RENDER 585 PanoramiXRenderInit (); 586#endif 587} 588 589extern Bool CreateConnectionBlock(void); 590 591Bool PanoramiXCreateConnectionBlock(void) 592{ 593 int i, j, length; 594 Bool disableBackingStore = FALSE; 595 int old_width, old_height; 596 float width_mult, height_mult; 597 xWindowRoot *root; 598 xVisualType *visual; 599 xDepth *depth; 600 VisualPtr pVisual; 601 ScreenPtr pScreen; 602 603 /* 604 * Do normal CreateConnectionBlock but faking it for only one screen 605 */ 606 607 if(!PanoramiXNumDepths) { 608 ErrorF("Xinerama error: No common visuals\n"); 609 return FALSE; 610 } 611 612 for(i = 1; i < screenInfo.numScreens; i++) { 613 pScreen = screenInfo.screens[i]; 614 if(pScreen->rootDepth != screenInfo.screens[0]->rootDepth) { 615 ErrorF("Xinerama error: Root window depths differ\n"); 616 return FALSE; 617 } 618 if(pScreen->backingStoreSupport != screenInfo.screens[0]->backingStoreSupport) 619 disableBackingStore = TRUE; 620 } 621 622 if (disableBackingStore) { 623 for (i = 0; i < screenInfo.numScreens; i++) { 624 pScreen = screenInfo.screens[i]; 625 pScreen->backingStoreSupport = NotUseful; 626 } 627 } 628 629 i = screenInfo.numScreens; 630 screenInfo.numScreens = 1; 631 if (!CreateConnectionBlock()) { 632 screenInfo.numScreens = i; 633 return FALSE; 634 } 635 636 screenInfo.numScreens = i; 637 638 root = (xWindowRoot *) (ConnectionInfo + connBlockScreenStart); 639 length = connBlockScreenStart + sizeof(xWindowRoot); 640 641 /* overwrite the connection block */ 642 root->nDepths = PanoramiXNumDepths; 643 644 for (i = 0; i < PanoramiXNumDepths; i++) { 645 depth = (xDepth *) (ConnectionInfo + length); 646 depth->depth = PanoramiXDepths[i].depth; 647 depth->nVisuals = PanoramiXDepths[i].numVids; 648 length += sizeof(xDepth); 649 visual = (xVisualType *)(ConnectionInfo + length); 650 651 for (j = 0; j < depth->nVisuals; j++, visual++) { 652 visual->visualID = PanoramiXDepths[i].vids[j]; 653 654 for (pVisual = PanoramiXVisuals; 655 pVisual->vid != visual->visualID; 656 pVisual++) 657 ; 658 659 visual->class = pVisual->class; 660 visual->bitsPerRGB = pVisual->bitsPerRGBValue; 661 visual->colormapEntries = pVisual->ColormapEntries; 662 visual->redMask = pVisual->redMask; 663 visual->greenMask = pVisual->greenMask; 664 visual->blueMask = pVisual->blueMask; 665 } 666 667 length += (depth->nVisuals * sizeof(xVisualType)); 668 } 669 670 connSetupPrefix.length = length >> 2; 671 672 for (i = 0; i < PanoramiXNumDepths; i++) 673 xfree(PanoramiXDepths[i].vids); 674 xfree(PanoramiXDepths); 675 PanoramiXDepths = NULL; 676 677 /* 678 * OK, change some dimensions so it looks as if it were one big screen 679 */ 680 681 old_width = root->pixWidth; 682 old_height = root->pixHeight; 683 684 root->pixWidth = PanoramiXPixWidth; 685 root->pixHeight = PanoramiXPixHeight; 686 width_mult = (1.0 * root->pixWidth) / old_width; 687 height_mult = (1.0 * root->pixHeight) / old_height; 688 root->mmWidth *= width_mult; 689 root->mmHeight *= height_mult; 690 691 while(ConnectionCallbackList) { 692 pointer tmp; 693 694 tmp = (pointer)ConnectionCallbackList; 695 (*ConnectionCallbackList->func)(); 696 ConnectionCallbackList = ConnectionCallbackList->next; 697 xfree(tmp); 698 } 699 700 return TRUE; 701} 702 703/* 704 * This isn't just memcmp(), bitsPerRGBValue is skipped. markv made that 705 * change way back before xf86 4.0, but the comment for _why_ is a bit 706 * opaque, so I'm not going to question it for now. 707 * 708 * This is probably better done as a screen hook so DBE/EVI/GLX can add 709 * their own tests, and adding privates to VisualRec so they don't have to 710 * do their own back-mapping. 711 */ 712static Bool 713VisualsEqual(VisualPtr a, ScreenPtr pScreenB, VisualPtr b) 714{ 715 return ((a->class == b->class) && 716 (a->ColormapEntries == b->ColormapEntries) && 717 (a->nplanes == b->nplanes) && 718 (a->redMask == b->redMask) && 719 (a->greenMask == b->greenMask) && 720 (a->blueMask == b->blueMask) && 721 (a->offsetRed == b->offsetRed) && 722 (a->offsetGreen == b->offsetGreen) && 723 (a->offsetBlue == b->offsetBlue)); 724} 725 726static void 727PanoramiXMaybeAddDepth(DepthPtr pDepth) 728{ 729 ScreenPtr pScreen; 730 int j, k; 731 Bool found = FALSE; 732 733 for (j = 1; j < PanoramiXNumScreens; j++) { 734 pScreen = screenInfo.screens[j]; 735 for (k = 0; k < pScreen->numDepths; k++) { 736 if (pScreen->allowedDepths[k].depth == pDepth->depth) { 737 found = TRUE; 738 break; 739 } 740 } 741 } 742 743 if (!found) 744 return; 745 746 j = PanoramiXNumDepths; 747 PanoramiXNumDepths++; 748 PanoramiXDepths = xrealloc(PanoramiXDepths, 749 PanoramiXNumDepths * sizeof(DepthRec)); 750 PanoramiXDepths[j].depth = pDepth->depth; 751 PanoramiXDepths[j].numVids = 0; 752 /* XXX suboptimal, should grow these dynamically */ 753 if(pDepth->numVids) 754 PanoramiXDepths[j].vids = xalloc(sizeof(VisualID) * pDepth->numVids); 755 else 756 PanoramiXDepths[j].vids = NULL; 757} 758 759static void 760PanoramiXMaybeAddVisual(VisualPtr pVisual) 761{ 762 ScreenPtr pScreen; 763 int j, k; 764 Bool found = FALSE; 765 766 for (j = 1; j < PanoramiXNumScreens; j++) { 767 pScreen = screenInfo.screens[j]; 768 found = FALSE; 769 770 for (k = 0; k < pScreen->numVisuals; k++) { 771 VisualPtr candidate = &pScreen->visuals[k]; 772 773 if ((*XineramaVisualsEqualPtr)(pVisual, pScreen, candidate) 774#ifdef GLXPROXY 775 && glxMatchVisual(screenInfo.screens[0], pVisual, pScreen) 776#endif 777 ) { 778 found = TRUE; 779 break; 780 } 781 } 782 783 if (!found) 784 return; 785 } 786 787 /* found a matching visual on all screens, add it to the subset list */ 788 j = PanoramiXNumVisuals; 789 PanoramiXNumVisuals++; 790 PanoramiXVisuals = xrealloc(PanoramiXVisuals, 791 PanoramiXNumVisuals * sizeof(VisualRec)); 792 793 memcpy(&PanoramiXVisuals[j], pVisual, sizeof(VisualRec)); 794 795 for (k = 0; k < PanoramiXNumDepths; k++) { 796 if (PanoramiXDepths[k].depth == pVisual->nplanes) { 797 PanoramiXDepths[k].vids[PanoramiXDepths[k].numVids] = pVisual->vid; 798 PanoramiXDepths[k].numVids++; 799 break; 800 } 801 } 802} 803 804extern void 805PanoramiXConsolidate(void) 806{ 807 int i; 808 PanoramiXRes *root, *defmap, *saver; 809 ScreenPtr pScreen = screenInfo.screens[0]; 810 DepthPtr pDepth = pScreen->allowedDepths; 811 VisualPtr pVisual = pScreen->visuals; 812 813 PanoramiXNumDepths = 0; 814 PanoramiXNumVisuals = 0; 815 816 for (i = 0; i < pScreen->numDepths; i++) 817 PanoramiXMaybeAddDepth(pDepth++); 818 819 for (i = 0; i < pScreen->numVisuals; i++) 820 PanoramiXMaybeAddVisual(pVisual++); 821 822 root = xalloc(sizeof(PanoramiXRes)); 823 root->type = XRT_WINDOW; 824 defmap = xalloc(sizeof(PanoramiXRes)); 825 defmap->type = XRT_COLORMAP; 826 saver = xalloc(sizeof(PanoramiXRes)); 827 saver->type = XRT_WINDOW; 828 829 for (i = 0; i < PanoramiXNumScreens; i++) { 830 root->info[i].id = WindowTable[i]->drawable.id; 831 root->u.win.class = InputOutput; 832 root->u.win.root = TRUE; 833 saver->info[i].id = savedScreenInfo[i].wid; 834 saver->u.win.class = InputOutput; 835 saver->u.win.root = TRUE; 836 defmap->info[i].id = (screenInfo.screens[i])->defColormap; 837 } 838 839 AddResource(root->info[0].id, XRT_WINDOW, root); 840 AddResource(saver->info[0].id, XRT_WINDOW, saver); 841 AddResource(defmap->info[0].id, XRT_COLORMAP, defmap); 842} 843 844_X_EXPORT VisualID 845PanoramiXTranslateVisualID(int screen, VisualID orig) 846{ 847 ScreenPtr pOtherScreen = screenInfo.screens[screen]; 848 VisualPtr pVisual = NULL; 849 int i; 850 851 for (i = 0; i < PanoramiXNumVisuals; i++) { 852 if (orig == PanoramiXVisuals[i].vid) { 853 pVisual = &PanoramiXVisuals[i]; 854 break; 855 } 856 } 857 858 if (!pVisual) 859 return 0; 860 861 /* if screen is 0, orig is already the correct visual ID */ 862 if (screen == 0) 863 return orig; 864 865 /* found the original, now translate it relative to the backend screen */ 866 for (i = 0; i < pOtherScreen->numVisuals; i++) { 867 VisualPtr pOtherVisual = &pOtherScreen->visuals[i]; 868 869 if ((*XineramaVisualsEqualPtr)(pVisual, pOtherScreen, pOtherVisual)) 870 return pOtherVisual->vid; 871 } 872 873 return 0; 874} 875 876 877/* 878 * PanoramiXResetProc() 879 * Exit, deallocating as needed. 880 */ 881 882static void PanoramiXResetProc(ExtensionEntry* extEntry) 883{ 884 int i; 885 886#ifdef RENDER 887 PanoramiXRenderReset (); 888#endif 889 screenInfo.numScreens = PanoramiXNumScreens; 890 for (i = 256; i--; ) 891 ProcVector[i] = SavedProcVector[i]; 892 893 Xfree(panoramiXdataPtr); 894} 895 896 897int 898ProcPanoramiXQueryVersion (ClientPtr client) 899{ 900 /* REQUEST(xPanoramiXQueryVersionReq); */ 901 xPanoramiXQueryVersionReply rep; 902 register int n; 903 904 REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); 905 rep.type = X_Reply; 906 rep.length = 0; 907 rep.sequenceNumber = client->sequence; 908 rep.majorVersion = SERVER_PANORAMIX_MAJOR_VERSION; 909 rep.minorVersion = SERVER_PANORAMIX_MINOR_VERSION; 910 if (client->swapped) { 911 swaps(&rep.sequenceNumber, n); 912 swapl(&rep.length, n); 913 swaps(&rep.majorVersion, n); 914 swaps(&rep.minorVersion, n); 915 } 916 WriteToClient(client, sizeof (xPanoramiXQueryVersionReply), (char *)&rep); 917 return (client->noClientException); 918} 919 920int 921ProcPanoramiXGetState(ClientPtr client) 922{ 923 REQUEST(xPanoramiXGetStateReq); 924 WindowPtr pWin; 925 xPanoramiXGetStateReply rep; 926 int n, rc; 927 928 REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); 929 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 930 if (rc != Success) 931 return rc; 932 933 rep.type = X_Reply; 934 rep.length = 0; 935 rep.sequenceNumber = client->sequence; 936 rep.state = !noPanoramiXExtension; 937 rep.window = stuff->window; 938 if (client->swapped) { 939 swaps (&rep.sequenceNumber, n); 940 swapl (&rep.length, n); 941 swapl (&rep.window, n); 942 } 943 WriteToClient (client, sizeof (xPanoramiXGetStateReply), (char *) &rep); 944 return client->noClientException; 945 946} 947 948int 949ProcPanoramiXGetScreenCount(ClientPtr client) 950{ 951 REQUEST(xPanoramiXGetScreenCountReq); 952 WindowPtr pWin; 953 xPanoramiXGetScreenCountReply rep; 954 int n, rc; 955 956 REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); 957 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 958 if (rc != Success) 959 return rc; 960 961 rep.type = X_Reply; 962 rep.length = 0; 963 rep.sequenceNumber = client->sequence; 964 rep.ScreenCount = PanoramiXNumScreens; 965 rep.window = stuff->window; 966 if (client->swapped) { 967 swaps (&rep.sequenceNumber, n); 968 swapl (&rep.length, n); 969 swapl (&rep.window, n); 970 } 971 WriteToClient (client, sizeof (xPanoramiXGetScreenCountReply), (char *) &rep); 972 return client->noClientException; 973} 974 975int 976ProcPanoramiXGetScreenSize(ClientPtr client) 977{ 978 REQUEST(xPanoramiXGetScreenSizeReq); 979 WindowPtr pWin; 980 xPanoramiXGetScreenSizeReply rep; 981 int n, rc; 982 983 if (stuff->screen >= PanoramiXNumScreens) 984 return BadMatch; 985 986 REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); 987 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 988 if (rc != Success) 989 return rc; 990 991 rep.type = X_Reply; 992 rep.length = 0; 993 rep.sequenceNumber = client->sequence; 994 /* screen dimensions */ 995 rep.width = panoramiXdataPtr[stuff->screen].width; 996 rep.height = panoramiXdataPtr[stuff->screen].height; 997 rep.window = stuff->window; 998 rep.screen = stuff->screen; 999 if (client->swapped) { 1000 swaps (&rep.sequenceNumber, n); 1001 swapl (&rep.length, n); 1002 swapl (&rep.width, n); 1003 swapl (&rep.height, n); 1004 swapl (&rep.window, n); 1005 swapl (&rep.screen, n); 1006 } 1007 WriteToClient (client, sizeof (xPanoramiXGetScreenSizeReply), (char *) &rep); 1008 return client->noClientException; 1009} 1010 1011 1012int 1013ProcXineramaIsActive(ClientPtr client) 1014{ 1015 /* REQUEST(xXineramaIsActiveReq); */ 1016 xXineramaIsActiveReply rep; 1017 1018 REQUEST_SIZE_MATCH(xXineramaIsActiveReq); 1019 1020 rep.type = X_Reply; 1021 rep.length = 0; 1022 rep.sequenceNumber = client->sequence; 1023#if 1 1024 { 1025 /* The following hack fools clients into thinking that Xinerama 1026 * is disabled even though it is not. */ 1027 rep.state = !noPanoramiXExtension && !PanoramiXExtensionDisabledHack; 1028 } 1029#else 1030 rep.state = !noPanoramiXExtension; 1031#endif 1032 if (client->swapped) { 1033 int n; 1034 swaps (&rep.sequenceNumber, n); 1035 swapl (&rep.length, n); 1036 swapl (&rep.state, n); 1037 } 1038 WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); 1039 return client->noClientException; 1040} 1041 1042 1043int 1044ProcXineramaQueryScreens(ClientPtr client) 1045{ 1046 /* REQUEST(xXineramaQueryScreensReq); */ 1047 xXineramaQueryScreensReply rep; 1048 1049 REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); 1050 1051 rep.type = X_Reply; 1052 rep.sequenceNumber = client->sequence; 1053 rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens; 1054 rep.length = rep.number * sz_XineramaScreenInfo >> 2; 1055 if (client->swapped) { 1056 int n; 1057 swaps (&rep.sequenceNumber, n); 1058 swapl (&rep.length, n); 1059 swapl (&rep.number, n); 1060 } 1061 WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); 1062 1063 if(!noPanoramiXExtension) { 1064 xXineramaScreenInfo scratch; 1065 int i; 1066 1067 for(i = 0; i < PanoramiXNumScreens; i++) { 1068 scratch.x_org = panoramiXdataPtr[i].x; 1069 scratch.y_org = panoramiXdataPtr[i].y; 1070 scratch.width = panoramiXdataPtr[i].width; 1071 scratch.height = panoramiXdataPtr[i].height; 1072 1073 if(client->swapped) { 1074 int n; 1075 swaps (&scratch.x_org, n); 1076 swaps (&scratch.y_org, n); 1077 swaps (&scratch.width, n); 1078 swaps (&scratch.height, n); 1079 } 1080 WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); 1081 } 1082 } 1083 1084 return client->noClientException; 1085} 1086 1087 1088static int 1089ProcPanoramiXDispatch (ClientPtr client) 1090{ REQUEST(xReq); 1091 switch (stuff->data) 1092 { 1093 case X_PanoramiXQueryVersion: 1094 return ProcPanoramiXQueryVersion(client); 1095 case X_PanoramiXGetState: 1096 return ProcPanoramiXGetState(client); 1097 case X_PanoramiXGetScreenCount: 1098 return ProcPanoramiXGetScreenCount(client); 1099 case X_PanoramiXGetScreenSize: 1100 return ProcPanoramiXGetScreenSize(client); 1101 case X_XineramaIsActive: 1102 return ProcXineramaIsActive(client); 1103 case X_XineramaQueryScreens: 1104 return ProcXineramaQueryScreens(client); 1105 } 1106 return BadRequest; 1107} 1108 1109 1110#if X_BYTE_ORDER == X_LITTLE_ENDIAN 1111#define SHIFT_L(v,s) (v) << (s) 1112#define SHIFT_R(v,s) (v) >> (s) 1113#else 1114#define SHIFT_L(v,s) (v) >> (s) 1115#define SHIFT_R(v,s) (v) << (s) 1116#endif 1117 1118static void 1119CopyBits(char *dst, int shiftL, char *src, int bytes) 1120{ 1121 /* Just get it to work. Worry about speed later */ 1122 int shiftR = 8 - shiftL; 1123 1124 while(bytes--) { 1125 *dst |= SHIFT_L(*src, shiftL); 1126 *(dst + 1) |= SHIFT_R(*src, shiftR); 1127 dst++; src++; 1128 } 1129} 1130 1131 1132/* Caution. This doesn't support 2 and 4 bpp formats. We expect 1133 1 bpp and planar data to be already cleared when presented 1134 to this function */ 1135 1136void 1137XineramaGetImageData( 1138 DrawablePtr *pDrawables, 1139 int left, 1140 int top, 1141 int width, 1142 int height, 1143 unsigned int format, 1144 unsigned long planemask, 1145 char *data, 1146 int pitch, 1147 Bool isRoot 1148){ 1149 RegionRec SrcRegion, GrabRegion; 1150 BoxRec SrcBox, *pbox; 1151 int x, y, w, h, i, j, nbox, size, sizeNeeded, ScratchPitch, inOut, depth; 1152 DrawablePtr pDraw = pDrawables[0]; 1153 char *ScratchMem = NULL; 1154 1155 size = 0; 1156 1157 /* find box in logical screen space */ 1158 SrcBox.x1 = left; 1159 SrcBox.y1 = top; 1160 if(!isRoot) { 1161 SrcBox.x1 += pDraw->x + panoramiXdataPtr[0].x; 1162 SrcBox.y1 += pDraw->y + panoramiXdataPtr[0].y; 1163 } 1164 SrcBox.x2 = SrcBox.x1 + width; 1165 SrcBox.y2 = SrcBox.y1 + height; 1166 1167 REGION_INIT(pScreen, &SrcRegion, &SrcBox, 1); 1168 REGION_NULL(pScreen, &GrabRegion); 1169 1170 depth = (format == XYPixmap) ? 1 : pDraw->depth; 1171 1172 for(i = 0; i < PanoramiXNumScreens; i++) { 1173 pDraw = pDrawables[i]; 1174 1175 inOut = RECT_IN_REGION(pScreen,&XineramaScreenRegions[i],&SrcBox); 1176 1177 if(inOut == rgnIN) { 1178 (*pDraw->pScreen->GetImage)(pDraw, 1179 SrcBox.x1 - pDraw->x - panoramiXdataPtr[i].x, 1180 SrcBox.y1 - pDraw->y - panoramiXdataPtr[i].y, 1181 width, height, format, planemask, data); 1182 break; 1183 } else if (inOut == rgnOUT) 1184 continue; 1185 1186 REGION_INTERSECT(pScreen, &GrabRegion, &SrcRegion, 1187 &XineramaScreenRegions[i]); 1188 1189 nbox = REGION_NUM_RECTS(&GrabRegion); 1190 1191 if(nbox) { 1192 pbox = REGION_RECTS(&GrabRegion); 1193 1194 while(nbox--) { 1195 w = pbox->x2 - pbox->x1; 1196 h = pbox->y2 - pbox->y1; 1197 ScratchPitch = PixmapBytePad(w, depth); 1198 sizeNeeded = ScratchPitch * h; 1199 1200 if(sizeNeeded > size) { 1201 char *tmpdata = ScratchMem; 1202 ScratchMem = xrealloc(ScratchMem, sizeNeeded); 1203 if(ScratchMem) 1204 size = sizeNeeded; 1205 else { 1206 ScratchMem = tmpdata; 1207 break; 1208 } 1209 } 1210 1211 x = pbox->x1 - pDraw->x - panoramiXdataPtr[i].x; 1212 y = pbox->y1 - pDraw->y - panoramiXdataPtr[i].y; 1213 1214 (*pDraw->pScreen->GetImage)(pDraw, x, y, w, h, 1215 format, planemask, ScratchMem); 1216 1217 /* copy the memory over */ 1218 1219 if(depth == 1) { 1220 int k, shift, leftover, index, index2; 1221 1222 x = pbox->x1 - SrcBox.x1; 1223 y = pbox->y1 - SrcBox.y1; 1224 shift = x & 7; 1225 x >>= 3; 1226 leftover = w & 7; 1227 w >>= 3; 1228 1229 /* clean up the edge */ 1230 if(leftover) { 1231 int mask = (1 << leftover) - 1; 1232 for(j = h, k = w; j--; k += ScratchPitch) 1233 ScratchMem[k] &= mask; 1234 } 1235 1236 for(j = 0, index = (pitch * y) + x, index2 = 0; j < h; 1237 j++, index += pitch, index2 += ScratchPitch) 1238 { 1239 if(w) { 1240 if(!shift) 1241 memcpy(data + index, ScratchMem + index2, w); 1242 else 1243 CopyBits(data + index, shift, 1244 ScratchMem + index2, w); 1245 } 1246 1247 if(leftover) { 1248 data[index + w] |= 1249 SHIFT_L(ScratchMem[index2 + w], shift); 1250 if((shift + leftover) > 8) 1251 data[index + w + 1] |= 1252 SHIFT_R(ScratchMem[index2 + w],(8 - shift)); 1253 } 1254 } 1255 } else { 1256 j = BitsPerPixel(depth) >> 3; 1257 x = (pbox->x1 - SrcBox.x1) * j; 1258 y = pbox->y1 - SrcBox.y1; 1259 w *= j; 1260 1261 for(j = 0; j < h; j++) { 1262 memcpy(data + (pitch * (y + j)) + x, 1263 ScratchMem + (ScratchPitch * j), w); 1264 } 1265 } 1266 pbox++; 1267 } 1268 1269 REGION_SUBTRACT(pScreen, &SrcRegion, &SrcRegion, &GrabRegion); 1270 if(!REGION_NOTEMPTY(pScreen, &SrcRegion)) 1271 break; 1272 } 1273 1274 } 1275 1276 if(ScratchMem) 1277 xfree(ScratchMem); 1278 1279 REGION_UNINIT(pScreen, &SrcRegion); 1280 REGION_UNINIT(pScreen, &GrabRegion); 1281} 1282