Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | 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, pointer, int); | |
134 | static void XineramaDestroyClip(GCPtr); | |
135 | static void XineramaCopyClip(GCPtr, GCPtr); | |
136 | ||
137 | static 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 | |
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((pointer) pScreenPriv); | |
164 | ||
165 | return (*pScreen->CloseScreen) (pScreen); | |
166 | } | |
167 | ||
168 | static Bool | |
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 | |
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 | |
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 | |
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 | |
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 | |
297 | XineramaChangeClip(GCPtr pGC, int type, pointer 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 | |
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 | |
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 | |
321 | XineramaDeleteResource(pointer 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 | |
333 | XineramaFindIDByScrnum(pointer resource, XID id, pointer 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 * | |
342 | PanoramiXFindIDByScrnum(RESTYPE type, XID id, int screen) | |
343 | { | |
344 | PanoramiXSearchData data; | |
345 | pointer 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 | |
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 | |
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 | |
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 | |
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 | |
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 | pointer tmp; | |
695 | ||
696 | tmp = (pointer) 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 | |
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 | |
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 = realloc(PanoramiXDepths, | |
751 | PanoramiXNumDepths * sizeof(DepthRec)); | |
752 | PanoramiXDepths[j].depth = pDepth->depth; | |
753 | PanoramiXDepths[j].numVids = 0; | |
754 | /* XXX suboptimal, should grow these dynamically */ | |
755 | if (pDepth->numVids) | |
756 | PanoramiXDepths[j].vids = malloc(sizeof(VisualID) * pDepth->numVids); | |
757 | else | |
758 | PanoramiXDepths[j].vids = NULL; | |
759 | } | |
760 | ||
761 | static void | |
762 | PanoramiXMaybeAddVisual(VisualPtr pVisual) | |
763 | { | |
764 | ScreenPtr pScreen; | |
765 | int j, k; | |
766 | Bool found = FALSE; | |
767 | ||
768 | FOR_NSCREENS_FORWARD_SKIP(j) { | |
769 | pScreen = screenInfo.screens[j]; | |
770 | found = FALSE; | |
771 | ||
772 | for (k = 0; k < pScreen->numVisuals; k++) { | |
773 | VisualPtr candidate = &pScreen->visuals[k]; | |
774 | ||
775 | if ((*XineramaVisualsEqualPtr) (pVisual, pScreen, candidate) | |
776 | #ifdef GLXPROXY | |
777 | && glxMatchVisual(screenInfo.screens[0], pVisual, pScreen) | |
778 | #endif | |
779 | ) { | |
780 | found = TRUE; | |
781 | break; | |
782 | } | |
783 | } | |
784 | ||
785 | if (!found) | |
786 | return; | |
787 | } | |
788 | ||
789 | /* found a matching visual on all screens, add it to the subset list */ | |
790 | j = PanoramiXNumVisuals; | |
791 | PanoramiXNumVisuals++; | |
792 | PanoramiXVisuals = realloc(PanoramiXVisuals, | |
793 | PanoramiXNumVisuals * sizeof(VisualRec)); | |
794 | ||
795 | memcpy(&PanoramiXVisuals[j], pVisual, sizeof(VisualRec)); | |
796 | ||
797 | for (k = 0; k < PanoramiXNumDepths; k++) { | |
798 | if (PanoramiXDepths[k].depth == pVisual->nplanes) { | |
799 | PanoramiXDepths[k].vids[PanoramiXDepths[k].numVids] = pVisual->vid; | |
800 | PanoramiXDepths[k].numVids++; | |
801 | break; | |
802 | } | |
803 | } | |
804 | } | |
805 | ||
806 | extern void | |
807 | PanoramiXConsolidate(void) | |
808 | { | |
809 | int i; | |
810 | PanoramiXRes *root, *defmap, *saver; | |
811 | ScreenPtr pScreen = screenInfo.screens[0]; | |
812 | DepthPtr pDepth = pScreen->allowedDepths; | |
813 | VisualPtr pVisual = pScreen->visuals; | |
814 | ||
815 | PanoramiXNumDepths = 0; | |
816 | PanoramiXNumVisuals = 0; | |
817 | ||
818 | for (i = 0; i < pScreen->numDepths; i++) | |
819 | PanoramiXMaybeAddDepth(pDepth++); | |
820 | ||
821 | for (i = 0; i < pScreen->numVisuals; i++) | |
822 | PanoramiXMaybeAddVisual(pVisual++); | |
823 | ||
824 | root = malloc(sizeof(PanoramiXRes)); | |
825 | root->type = XRT_WINDOW; | |
826 | defmap = malloc(sizeof(PanoramiXRes)); | |
827 | defmap->type = XRT_COLORMAP; | |
828 | saver = malloc(sizeof(PanoramiXRes)); | |
829 | saver->type = XRT_WINDOW; | |
830 | ||
831 | FOR_NSCREENS(i) { | |
832 | ScreenPtr scr = screenInfo.screens[i]; | |
833 | ||
834 | root->info[i].id = scr->root->drawable.id; | |
835 | root->u.win.class = InputOutput; | |
836 | root->u.win.root = TRUE; | |
837 | saver->info[i].id = scr->screensaver.wid; | |
838 | saver->u.win.class = InputOutput; | |
839 | saver->u.win.root = TRUE; | |
840 | defmap->info[i].id = scr->defColormap; | |
841 | } | |
842 | ||
843 | AddResource(root->info[0].id, XRT_WINDOW, root); | |
844 | AddResource(saver->info[0].id, XRT_WINDOW, saver); | |
845 | AddResource(defmap->info[0].id, XRT_COLORMAP, defmap); | |
846 | } | |
847 | ||
848 | VisualID | |
849 | PanoramiXTranslateVisualID(int screen, VisualID orig) | |
850 | { | |
851 | ScreenPtr pOtherScreen = screenInfo.screens[screen]; | |
852 | VisualPtr pVisual = NULL; | |
853 | int i; | |
854 | ||
855 | for (i = 0; i < PanoramiXNumVisuals; i++) { | |
856 | if (orig == PanoramiXVisuals[i].vid) { | |
857 | pVisual = &PanoramiXVisuals[i]; | |
858 | break; | |
859 | } | |
860 | } | |
861 | ||
862 | if (!pVisual) | |
863 | return 0; | |
864 | ||
865 | /* if screen is 0, orig is already the correct visual ID */ | |
866 | if (screen == 0) | |
867 | return orig; | |
868 | ||
869 | /* found the original, now translate it relative to the backend screen */ | |
870 | for (i = 0; i < pOtherScreen->numVisuals; i++) { | |
871 | VisualPtr pOtherVisual = &pOtherScreen->visuals[i]; | |
872 | ||
873 | if ((*XineramaVisualsEqualPtr) (pVisual, pOtherScreen, pOtherVisual)) | |
874 | return pOtherVisual->vid; | |
875 | } | |
876 | ||
877 | return 0; | |
878 | } | |
879 | ||
880 | /* | |
881 | * PanoramiXResetProc() | |
882 | * Exit, deallocating as needed. | |
883 | */ | |
884 | ||
885 | static void | |
886 | PanoramiXResetProc(ExtensionEntry * extEntry) | |
887 | { | |
888 | int i; | |
889 | ||
890 | PanoramiXRenderReset(); | |
891 | PanoramiXFixesReset(); | |
892 | PanoramiXDamageReset(); | |
893 | #ifdef COMPOSITE | |
894 | PanoramiXCompositeReset (); | |
895 | #endif | |
896 | screenInfo.numScreens = PanoramiXNumScreens; | |
897 | for (i = 256; i--;) | |
898 | ProcVector[i] = SavedProcVector[i]; | |
899 | } | |
900 | ||
901 | int | |
902 | ProcPanoramiXQueryVersion(ClientPtr client) | |
903 | { | |
904 | /* REQUEST(xPanoramiXQueryVersionReq); */ | |
905 | xPanoramiXQueryVersionReply rep = { | |
906 | .type = X_Reply, | |
907 | .sequenceNumber = client->sequence, | |
908 | .length = 0, | |
909 | .majorVersion = SERVER_PANORAMIX_MAJOR_VERSION, | |
910 | .minorVersion = SERVER_PANORAMIX_MINOR_VERSION | |
911 | }; | |
912 | ||
913 | REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); | |
914 | if (client->swapped) { | |
915 | swaps(&rep.sequenceNumber); | |
916 | swapl(&rep.length); | |
917 | swaps(&rep.majorVersion); | |
918 | swaps(&rep.minorVersion); | |
919 | } | |
920 | WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), &rep); | |
921 | return Success; | |
922 | } | |
923 | ||
924 | int | |
925 | ProcPanoramiXGetState(ClientPtr client) | |
926 | { | |
927 | REQUEST(xPanoramiXGetStateReq); | |
928 | WindowPtr pWin; | |
929 | xPanoramiXGetStateReply rep; | |
930 | int rc; | |
931 | ||
932 | REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); | |
933 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
934 | if (rc != Success) | |
935 | return rc; | |
936 | ||
937 | rep = (xPanoramiXGetStateReply) { | |
938 | .type = X_Reply, | |
939 | .state = !noPanoramiXExtension, | |
940 | .sequenceNumber = client->sequence, | |
941 | .length = 0, | |
942 | .window = stuff->window | |
943 | }; | |
944 | if (client->swapped) { | |
945 | swaps(&rep.sequenceNumber); | |
946 | swapl(&rep.length); | |
947 | swapl(&rep.window); | |
948 | } | |
949 | WriteToClient(client, sizeof(xPanoramiXGetStateReply), &rep); | |
950 | return Success; | |
951 | ||
952 | } | |
953 | ||
954 | int | |
955 | ProcPanoramiXGetScreenCount(ClientPtr client) | |
956 | { | |
957 | REQUEST(xPanoramiXGetScreenCountReq); | |
958 | WindowPtr pWin; | |
959 | xPanoramiXGetScreenCountReply rep; | |
960 | int rc; | |
961 | ||
962 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); | |
963 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
964 | if (rc != Success) | |
965 | return rc; | |
966 | ||
967 | rep = (xPanoramiXGetScreenCountReply) { | |
968 | .type = X_Reply, | |
969 | .ScreenCount = PanoramiXNumScreens, | |
970 | .sequenceNumber = client->sequence, | |
971 | .length = 0, | |
972 | .window = stuff->window | |
973 | }; | |
974 | if (client->swapped) { | |
975 | swaps(&rep.sequenceNumber); | |
976 | swapl(&rep.length); | |
977 | swapl(&rep.window); | |
978 | } | |
979 | WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), &rep); | |
980 | return Success; | |
981 | } | |
982 | ||
983 | int | |
984 | ProcPanoramiXGetScreenSize(ClientPtr client) | |
985 | { | |
986 | REQUEST(xPanoramiXGetScreenSizeReq); | |
987 | WindowPtr pWin; | |
988 | xPanoramiXGetScreenSizeReply rep; | |
989 | int rc; | |
990 | ||
991 | if (stuff->screen >= PanoramiXNumScreens) | |
992 | return BadMatch; | |
993 | ||
994 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | } |