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