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