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