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