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