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