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