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