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