panoramiX.c revision 48a68b89
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 REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); 994 995 if (stuff->screen >= PanoramiXNumScreens) 996 return BadMatch; 997 998 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 999 if (rc != Success) 1000 return rc; 1001 1002 rep.type = X_Reply; 1003 rep.length = 0; 1004 rep.sequenceNumber = client->sequence; 1005 /* screen dimensions */ 1006 rep.width = screenInfo.screens[stuff->screen]->width; 1007 rep.height = screenInfo.screens[stuff->screen]->height; 1008 rep.window = stuff->window; 1009 rep.screen = stuff->screen; 1010 if (client->swapped) { 1011 swaps (&rep.sequenceNumber, n); 1012 swapl (&rep.length, n); 1013 swapl (&rep.width, n); 1014 swapl (&rep.height, n); 1015 swapl (&rep.window, n); 1016 swapl (&rep.screen, n); 1017 } 1018 WriteToClient (client, sizeof (xPanoramiXGetScreenSizeReply), (char *) &rep); 1019 return Success; 1020} 1021 1022 1023int 1024ProcXineramaIsActive(ClientPtr client) 1025{ 1026 /* REQUEST(xXineramaIsActiveReq); */ 1027 xXineramaIsActiveReply rep; 1028 1029 REQUEST_SIZE_MATCH(xXineramaIsActiveReq); 1030 1031 rep.type = X_Reply; 1032 rep.length = 0; 1033 rep.sequenceNumber = client->sequence; 1034#if 1 1035 { 1036 /* The following hack fools clients into thinking that Xinerama 1037 * is disabled even though it is not. */ 1038 rep.state = !noPanoramiXExtension && !PanoramiXExtensionDisabledHack; 1039 } 1040#else 1041 rep.state = !noPanoramiXExtension; 1042#endif 1043 if (client->swapped) { 1044 int n; 1045 swaps (&rep.sequenceNumber, n); 1046 swapl (&rep.length, n); 1047 swapl (&rep.state, n); 1048 } 1049 WriteToClient (client, sizeof (xXineramaIsActiveReply), (char *) &rep); 1050 return Success; 1051} 1052 1053 1054int 1055ProcXineramaQueryScreens(ClientPtr client) 1056{ 1057 /* REQUEST(xXineramaQueryScreensReq); */ 1058 xXineramaQueryScreensReply rep; 1059 1060 REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); 1061 1062 rep.type = X_Reply; 1063 rep.sequenceNumber = client->sequence; 1064 rep.number = (noPanoramiXExtension) ? 0 : PanoramiXNumScreens; 1065 rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); 1066 if (client->swapped) { 1067 int n; 1068 swaps (&rep.sequenceNumber, n); 1069 swapl (&rep.length, n); 1070 swapl (&rep.number, n); 1071 } 1072 WriteToClient (client, sizeof (xXineramaQueryScreensReply), (char *) &rep); 1073 1074 if(!noPanoramiXExtension) { 1075 xXineramaScreenInfo scratch; 1076 int i; 1077 1078 for(i = 0; i < PanoramiXNumScreens; i++) { 1079 scratch.x_org = screenInfo.screens[i]->x; 1080 scratch.y_org = screenInfo.screens[i]->y; 1081 scratch.width = screenInfo.screens[i]->width; 1082 scratch.height = screenInfo.screens[i]->height; 1083 1084 if(client->swapped) { 1085 int n; 1086 swaps (&scratch.x_org, n); 1087 swaps (&scratch.y_org, n); 1088 swaps (&scratch.width, n); 1089 swaps (&scratch.height, n); 1090 } 1091 WriteToClient (client, sz_XineramaScreenInfo, (char *) &scratch); 1092 } 1093 } 1094 1095 return Success; 1096} 1097 1098 1099static int 1100ProcPanoramiXDispatch (ClientPtr client) 1101{ REQUEST(xReq); 1102 switch (stuff->data) 1103 { 1104 case X_PanoramiXQueryVersion: 1105 return ProcPanoramiXQueryVersion(client); 1106 case X_PanoramiXGetState: 1107 return ProcPanoramiXGetState(client); 1108 case X_PanoramiXGetScreenCount: 1109 return ProcPanoramiXGetScreenCount(client); 1110 case X_PanoramiXGetScreenSize: 1111 return ProcPanoramiXGetScreenSize(client); 1112 case X_XineramaIsActive: 1113 return ProcXineramaIsActive(client); 1114 case X_XineramaQueryScreens: 1115 return ProcXineramaQueryScreens(client); 1116 } 1117 return BadRequest; 1118} 1119 1120 1121#if X_BYTE_ORDER == X_LITTLE_ENDIAN 1122#define SHIFT_L(v,s) (v) << (s) 1123#define SHIFT_R(v,s) (v) >> (s) 1124#else 1125#define SHIFT_L(v,s) (v) >> (s) 1126#define SHIFT_R(v,s) (v) << (s) 1127#endif 1128 1129static void 1130CopyBits(char *dst, int shiftL, char *src, int bytes) 1131{ 1132 /* Just get it to work. Worry about speed later */ 1133 int shiftR = 8 - shiftL; 1134 1135 while(bytes--) { 1136 *dst |= SHIFT_L(*src, shiftL); 1137 *(dst + 1) |= SHIFT_R(*src, shiftR); 1138 dst++; src++; 1139 } 1140} 1141 1142 1143/* Caution. This doesn't support 2 and 4 bpp formats. We expect 1144 1 bpp and planar data to be already cleared when presented 1145 to this function */ 1146 1147void 1148XineramaGetImageData( 1149 DrawablePtr *pDrawables, 1150 int left, 1151 int top, 1152 int width, 1153 int height, 1154 unsigned int format, 1155 unsigned long planemask, 1156 char *data, 1157 int pitch, 1158 Bool isRoot 1159){ 1160 RegionRec SrcRegion, ScreenRegion, GrabRegion; 1161 BoxRec SrcBox, *pbox; 1162 int x, y, w, h, i, j, nbox, size, sizeNeeded, ScratchPitch, inOut, depth; 1163 DrawablePtr pDraw = pDrawables[0]; 1164 char *ScratchMem = NULL; 1165 1166 size = 0; 1167 1168 /* find box in logical screen space */ 1169 SrcBox.x1 = left; 1170 SrcBox.y1 = top; 1171 if(!isRoot) { 1172 SrcBox.x1 += pDraw->x + screenInfo.screens[0]->x; 1173 SrcBox.y1 += pDraw->y + screenInfo.screens[0]->y; 1174 } 1175 SrcBox.x2 = SrcBox.x1 + width; 1176 SrcBox.y2 = SrcBox.y1 + height; 1177 1178 RegionInit(&SrcRegion, &SrcBox, 1); 1179 RegionNull(&GrabRegion); 1180 1181 depth = (format == XYPixmap) ? 1 : pDraw->depth; 1182 1183 for(i = 0; i < PanoramiXNumScreens; i++) { 1184 BoxRec TheBox; 1185 ScreenPtr pScreen; 1186 pDraw = pDrawables[i]; 1187 pScreen = pDraw->pScreen; 1188 1189 TheBox.x1 = pScreen->x; 1190 TheBox.x2 = TheBox.x1 + pScreen->width; 1191 TheBox.y1 = pScreen->y; 1192 TheBox.y2 = TheBox.y1 + pScreen->height; 1193 1194 RegionInit(&ScreenRegion, &TheBox, 1); 1195 inOut = RegionContainsRect(&ScreenRegion, &SrcBox); 1196 if(inOut == rgnPART) 1197 RegionIntersect(&GrabRegion, &SrcRegion, &ScreenRegion); 1198 RegionUninit(&ScreenRegion); 1199 1200 if(inOut == rgnIN) { 1201 (*pScreen->GetImage)(pDraw, 1202 SrcBox.x1 - pDraw->x - screenInfo.screens[i]->x, 1203 SrcBox.y1 - pDraw->y - screenInfo.screens[i]->y, 1204 width, height, format, planemask, data); 1205 break; 1206 } else if (inOut == rgnOUT) 1207 continue; 1208 1209 nbox = RegionNumRects(&GrabRegion); 1210 1211 if(nbox) { 1212 pbox = RegionRects(&GrabRegion); 1213 1214 while(nbox--) { 1215 w = pbox->x2 - pbox->x1; 1216 h = pbox->y2 - pbox->y1; 1217 ScratchPitch = PixmapBytePad(w, depth); 1218 sizeNeeded = ScratchPitch * h; 1219 1220 if(sizeNeeded > size) { 1221 char *tmpdata = ScratchMem; 1222 ScratchMem = realloc(ScratchMem, sizeNeeded); 1223 if(ScratchMem) 1224 size = sizeNeeded; 1225 else { 1226 ScratchMem = tmpdata; 1227 break; 1228 } 1229 } 1230 1231 x = pbox->x1 - pDraw->x - screenInfo.screens[i]->x; 1232 y = pbox->y1 - pDraw->y - screenInfo.screens[i]->y; 1233 1234 (*pScreen->GetImage)(pDraw, x, y, w, h, 1235 format, planemask, ScratchMem); 1236 1237 /* copy the memory over */ 1238 1239 if(depth == 1) { 1240 int k, shift, leftover, index, index2; 1241 1242 x = pbox->x1 - SrcBox.x1; 1243 y = pbox->y1 - SrcBox.y1; 1244 shift = x & 7; 1245 x >>= 3; 1246 leftover = w & 7; 1247 w >>= 3; 1248 1249 /* clean up the edge */ 1250 if(leftover) { 1251 int mask = (1 << leftover) - 1; 1252 for(j = h, k = w; j--; k += ScratchPitch) 1253 ScratchMem[k] &= mask; 1254 } 1255 1256 for(j = 0, index = (pitch * y) + x, index2 = 0; j < h; 1257 j++, index += pitch, index2 += ScratchPitch) 1258 { 1259 if(w) { 1260 if(!shift) 1261 memcpy(data + index, ScratchMem + index2, w); 1262 else 1263 CopyBits(data + index, shift, 1264 ScratchMem + index2, w); 1265 } 1266 1267 if(leftover) { 1268 data[index + w] |= 1269 SHIFT_L(ScratchMem[index2 + w], shift); 1270 if((shift + leftover) > 8) 1271 data[index + w + 1] |= 1272 SHIFT_R(ScratchMem[index2 + w],(8 - shift)); 1273 } 1274 } 1275 } else { 1276 j = BitsPerPixel(depth) >> 3; 1277 x = (pbox->x1 - SrcBox.x1) * j; 1278 y = pbox->y1 - SrcBox.y1; 1279 w *= j; 1280 1281 for(j = 0; j < h; j++) { 1282 memcpy(data + (pitch * (y + j)) + x, 1283 ScratchMem + (ScratchPitch * j), w); 1284 } 1285 } 1286 pbox++; 1287 } 1288 1289 RegionSubtract(&SrcRegion, &SrcRegion, &GrabRegion); 1290 if(!RegionNotEmpty(&SrcRegion)) 1291 break; 1292 } 1293 1294 } 1295 1296 free(ScratchMem); 1297 1298 RegionUninit(&SrcRegion); 1299 RegionUninit(&GrabRegion); 1300} 1301