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