1 /*
2  * Copyright 2002-2004 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
33 
34 /** \file
35  * This file implements the server-side part of the DMX protocol. A
36  * vector of fucntions is provided at extension initialization time, so
37  * most all of the useful functions in this file are declared static and
38  * do not appear in the doxygen documentation.
39  *
40  * Much of the low-level work is done by functions in \a dmxextension.c
41  *
42  * Please see the Client-to-Server DMX Extension to the X Protocol
43  * document for details about the protocol.  */
44 
45 #ifdef HAVE_DMX_CONFIG_H
46 #include <dmx-config.h>
47 #endif
48 
49 #include <X11/X.h>
50 #include <X11/Xproto.h>
51 #include "misc.h"
52 #include "os.h"
53 #include "dixstruct.h"
54 #include "extnsionst.h"
55 #include "extinit.h"
56 #include "opaque.h"
57 
58 #include "dmx.h"
59 #include "dmxextension.h"
60 #include <X11/extensions/dmxproto.h>
61 #include <X11/extensions/dmx.h>
62 #include "protocol-versions.h"
63 
64 #ifdef PANORAMIX
65 #include "panoramiXsrv.h"
66 #endif
67 
68 static unsigned char DMXCode;
69 
70 static int
_DMXXineramaActive(void)71 _DMXXineramaActive(void)
72 {
73 #ifdef PANORAMIX
74     return !noPanoramiXExtension;
75 #else
76     return 0;
77 #endif
78 }
79 
80 static void
dmxSetScreenAttribute(int bit,DMXScreenAttributesPtr attr,CARD32 value)81 dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, CARD32 value)
82 {
83     switch (1 << bit) {
84     case DMXScreenWindowWidth:
85         attr->screenWindowWidth = value;
86         break;
87     case DMXScreenWindowHeight:
88         attr->screenWindowHeight = value;
89         break;
90     case DMXScreenWindowXoffset:
91         attr->screenWindowXoffset = value;
92         break;
93     case DMXScreenWindowYoffset:
94         attr->screenWindowYoffset = value;
95         break;
96     case DMXRootWindowWidth:
97         attr->rootWindowWidth = value;
98         break;
99     case DMXRootWindowHeight:
100         attr->rootWindowHeight = value;
101         break;
102     case DMXRootWindowXoffset:
103         attr->rootWindowXoffset = value;
104         break;
105     case DMXRootWindowYoffset:
106         attr->rootWindowYoffset = value;
107         break;
108     case DMXRootWindowXorigin:
109         attr->rootWindowXorigin = value;
110         break;
111     case DMXRootWindowYorigin:
112         attr->rootWindowYorigin = value;
113         break;
114     }
115 }
116 
117 static int
dmxFetchScreenAttributes(unsigned int mask,DMXScreenAttributesPtr attr,CARD32 * value_list)118 dmxFetchScreenAttributes(unsigned int mask,
119                          DMXScreenAttributesPtr attr, CARD32 *value_list)
120 {
121     int i;
122     CARD32 *value = value_list;
123     int count = 0;
124 
125     for (i = 0; i < 32; i++) {
126         if (mask & (1 << i)) {
127             dmxSetScreenAttribute(i, attr, *value);
128             ++value;
129             ++count;
130         }
131     }
132     return count;
133 }
134 
135 static void
dmxSetDesktopAttribute(int bit,DMXDesktopAttributesPtr attr,CARD32 value)136 dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, CARD32 value)
137 {
138     switch (1 << bit) {
139     case DMXDesktopWidth:
140         attr->width = value;
141         break;
142     case DMXDesktopHeight:
143         attr->height = value;
144         break;
145     case DMXDesktopShiftX:
146         attr->shiftX = value;
147         break;
148     case DMXDesktopShiftY:
149         attr->shiftY = value;
150         break;
151     }
152 }
153 
154 static int
dmxFetchDesktopAttributes(unsigned int mask,DMXDesktopAttributesPtr attr,CARD32 * value_list)155 dmxFetchDesktopAttributes(unsigned int mask,
156                           DMXDesktopAttributesPtr attr, CARD32 *value_list)
157 {
158     int i;
159     CARD32 *value = value_list;
160     int count = 0;
161 
162     for (i = 0; i < 32; i++) {
163         if (mask & (1 << i)) {
164             dmxSetDesktopAttribute(i, attr, *value);
165             ++value;
166             ++count;
167         }
168     }
169     return count;
170 }
171 
172 static void
dmxSetInputAttribute(int bit,DMXInputAttributesPtr attr,CARD32 value)173 dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, CARD32 value)
174 {
175     switch (1 << bit) {
176     case DMXInputType:
177         attr->inputType = value;
178         break;
179     case DMXInputPhysicalScreen:
180         attr->physicalScreen = value;
181         break;
182     case DMXInputSendsCore:
183         attr->sendsCore = ! !value;
184         break;
185     }
186 }
187 
188 static int
dmxFetchInputAttributes(unsigned int mask,DMXInputAttributesPtr attr,CARD32 * value_list)189 dmxFetchInputAttributes(unsigned int mask,
190                         DMXInputAttributesPtr attr, CARD32 *value_list)
191 {
192     int i;
193     CARD32 *value = value_list;
194     int count = 0;
195 
196     for (i = 0; i < 32; i++) {
197         if (mask & (1 << i)) {
198             dmxSetInputAttribute(i, attr, *value);
199             ++value;
200             ++count;
201         }
202     }
203     return count;
204 }
205 
206 static int
ProcDMXQueryVersion(ClientPtr client)207 ProcDMXQueryVersion(ClientPtr client)
208 {
209     xDMXQueryVersionReply rep = {
210         .type = X_Reply,
211         .sequenceNumber = client->sequence,
212         .length = 0,
213         .majorVersion = SERVER_DMX_MAJOR_VERSION,
214         .minorVersion = SERVER_DMX_MINOR_VERSION,
215         .patchVersion = SERVER_DMX_PATCH_VERSION
216     };
217 
218     REQUEST_SIZE_MATCH(xDMXQueryVersionReq);
219 
220     if (client->swapped) {
221         swaps(&rep.sequenceNumber);
222         swapl(&rep.length);
223         swapl(&rep.majorVersion);
224         swapl(&rep.minorVersion);
225         swapl(&rep.patchVersion);
226     }
227     WriteToClient(client, sizeof(xDMXQueryVersionReply), &rep);
228     return Success;
229 }
230 
231 static int
ProcDMXSync(ClientPtr client)232 ProcDMXSync(ClientPtr client)
233 {
234     xDMXSyncReply rep;
235 
236     REQUEST_SIZE_MATCH(xDMXSyncReq);
237 
238     dmxFlushPendingSyncs();
239 
240     rep = (xDMXSyncReply) {
241         .type = X_Reply,
242         .sequenceNumber = client->sequence,
243         .length = 0,
244         .status = 0
245     };
246     if (client->swapped) {
247         swaps(&rep.sequenceNumber);
248         swapl(&rep.length);
249         swapl(&rep.status);
250     }
251     WriteToClient(client, sizeof(xDMXSyncReply), &rep);
252     return Success;
253 }
254 
255 static int
ProcDMXForceWindowCreation(ClientPtr client)256 ProcDMXForceWindowCreation(ClientPtr client)
257 {
258     xDMXForceWindowCreationReply rep;
259 
260     REQUEST(xDMXForceWindowCreationReq);
261     WindowPtr pWin;
262 
263     REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq);
264 
265 #ifdef PANORAMIX
266     if (!noPanoramiXExtension) {
267         PanoramiXRes *win;
268         int i;
269 
270         if (Success != dixLookupResourceByType((void **) &win,
271                                                stuff->window, XRT_WINDOW,
272                                                client, DixReadAccess))
273             return -1;          /* BadWindow */
274 
275         FOR_NSCREENS(i) {
276             if (Success != dixLookupWindow(&pWin, win->info[i].id, client,
277                                            DixReadAccess))
278                 return -1;      /* BadWindow */
279 
280             dmxForceWindowCreation(pWin);
281         }
282         goto doreply;
283     }
284 #endif
285 
286     if (Success != dixLookupWindow(&pWin, stuff->window, client, DixReadAccess))
287         return -1;              /* BadWindow */
288 
289     dmxForceWindowCreation(pWin);
290  doreply:
291     dmxFlushPendingSyncs();
292     rep = (xDMXForceWindowCreationReply) {
293         .type = X_Reply,
294         .sequenceNumber = client->sequence,
295         .length = 0,
296         .status = 0
297     };
298     if (client->swapped) {
299         swaps(&rep.sequenceNumber);
300         swapl(&rep.length);
301         swapl(&rep.status);
302     }
303     WriteToClient(client, sizeof(xDMXForceWindowCreationReply), &rep);
304     return Success;
305 }
306 
307 static int
ProcDMXGetScreenCount(ClientPtr client)308 ProcDMXGetScreenCount(ClientPtr client)
309 {
310     xDMXGetScreenCountReply rep;
311 
312     REQUEST_SIZE_MATCH(xDMXGetScreenCountReq);
313 
314     rep = (xDMXGetScreenCountReply) {
315         .type = X_Reply,
316         .sequenceNumber = client->sequence,
317         .length = 0,
318         .screenCount = dmxGetNumScreens()
319     };
320     if (client->swapped) {
321         swaps(&rep.sequenceNumber);
322         swapl(&rep.length);
323         swapl(&rep.screenCount);
324     }
325     WriteToClient(client, sizeof(xDMXGetScreenCountReply), &rep);
326     return Success;
327 }
328 
329 static int
ProcDMXGetScreenAttributes(ClientPtr client)330 ProcDMXGetScreenAttributes(ClientPtr client)
331 {
332     REQUEST(xDMXGetScreenAttributesReq);
333     xDMXGetScreenAttributesReply rep;
334     int length;
335     int paddedLength;
336     DMXScreenAttributesRec attr;
337 
338     REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq);
339 
340     if (stuff->physicalScreen < 0
341         || stuff->physicalScreen >= dmxGetNumScreens())
342         return BadValue;
343 
344     if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr))
345         return BadValue;
346 
347     length = attr.displayName ? strlen(attr.displayName) : 0;
348     paddedLength = pad_to_int32(length);
349 
350     rep = (xDMXGetScreenAttributesReply) {
351         .type = X_Reply,
352         .sequenceNumber = client->sequence,
353         .length =
354             bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) -
355                             sizeof(xGenericReply))
356                            + paddedLength),
357         .displayNameLength = length,
358         .logicalScreen = attr.logicalScreen,
359         .screenWindowWidth = attr.screenWindowWidth,
360         .screenWindowHeight = attr.screenWindowHeight,
361         .screenWindowXoffset = attr.screenWindowXoffset,
362         .screenWindowYoffset = attr.screenWindowYoffset,
363         .rootWindowWidth = attr.rootWindowWidth,
364         .rootWindowHeight = attr.rootWindowHeight,
365         .rootWindowXoffset = attr.rootWindowXoffset,
366         .rootWindowYoffset = attr.rootWindowYoffset,
367         .rootWindowXorigin = attr.rootWindowXorigin,
368         .rootWindowYorigin = attr.rootWindowYorigin
369     };
370 
371     if (client->swapped) {
372         swaps(&rep.sequenceNumber);
373         swapl(&rep.length);
374         swapl(&rep.displayNameLength);
375         swapl(&rep.logicalScreen);
376         swaps(&rep.screenWindowWidth);
377         swaps(&rep.screenWindowHeight);
378         swaps(&rep.screenWindowXoffset);
379         swaps(&rep.screenWindowYoffset);
380         swaps(&rep.rootWindowWidth);
381         swaps(&rep.rootWindowHeight);
382         swaps(&rep.rootWindowXoffset);
383         swaps(&rep.rootWindowYoffset);
384         swaps(&rep.rootWindowXorigin);
385         swaps(&rep.rootWindowYorigin);
386     }
387     WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), &rep);
388     if (length)
389         WriteToClient(client, length, attr.displayName);
390     return Success;
391 }
392 
393 static int
ProcDMXChangeScreensAttributes(ClientPtr client)394 ProcDMXChangeScreensAttributes(ClientPtr client)
395 {
396     REQUEST(xDMXChangeScreensAttributesReq);
397     xDMXChangeScreensAttributesReply rep;
398     int status = DMX_BAD_XINERAMA;
399     unsigned int mask = 0;
400     unsigned int i;
401     CARD32 *screen_list;
402     CARD32 *mask_list;
403     CARD32 *value_list;
404     DMXScreenAttributesPtr attribs;
405     int errorScreen = 0;
406     unsigned int len;
407     int ones = 0;
408 
409     REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq);
410     len =
411         client->req_len -
412         bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq));
413     if (len < stuff->screenCount + stuff->maskCount)
414         return BadLength;
415 
416     screen_list = (CARD32 *) (stuff + 1);
417     mask_list = &screen_list[stuff->screenCount];
418     value_list = &mask_list[stuff->maskCount];
419 
420     for (i = 0; i < stuff->maskCount; i++)
421         ones += Ones(mask_list[i]);
422     if (len != stuff->screenCount + stuff->maskCount + ones)
423         return BadLength;
424 
425     if (!_DMXXineramaActive())
426         goto noxinerama;
427 
428     if (!(attribs = xallocarray(stuff->screenCount, sizeof(*attribs))))
429         return BadAlloc;
430 
431     for (i = 0; i < stuff->screenCount; i++) {
432         int count;
433 
434         if (i < stuff->maskCount)
435             mask = mask_list[i];
436         dmxGetScreenAttributes(screen_list[i], &attribs[i]);
437         count = dmxFetchScreenAttributes(mask, &attribs[i], value_list);
438         value_list += count;
439     }
440 
441 #ifdef PANORAMIX
442     status = dmxConfigureScreenWindows(stuff->screenCount,
443                                        screen_list, attribs, &errorScreen);
444 #endif
445 
446     free(attribs);
447 
448     if (status == BadValue)
449         return status;
450 
451  noxinerama:
452     rep = (xDMXChangeScreensAttributesReply) {
453         .type = X_Reply,
454         .sequenceNumber = client->sequence,
455         .length = 0,
456         .status = status,
457         .errorScreen = errorScreen
458     };
459     if (client->swapped) {
460         swaps(&rep.sequenceNumber);
461         swapl(&rep.length);
462         swapl(&rep.status);
463         swapl(&rep.errorScreen);
464     }
465     WriteToClient(client, sizeof(xDMXChangeScreensAttributesReply), &rep);
466     return Success;
467 }
468 
469 static int
ProcDMXAddScreen(ClientPtr client)470 ProcDMXAddScreen(ClientPtr client)
471 {
472     REQUEST(xDMXAddScreenReq);
473     xDMXAddScreenReply rep;
474     int status = 0;
475     CARD32 *value_list;
476     DMXScreenAttributesRec attr;
477     int count;
478     char *name;
479     int len;
480     int paddedLength;
481 
482     REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq);
483     paddedLength = pad_to_int32(stuff->displayNameLength);
484     len = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq));
485     if (len != Ones(stuff->valueMask) + paddedLength / 4)
486         return BadLength;
487 
488     memset(&attr, 0, sizeof(attr));
489     dmxGetScreenAttributes(stuff->physicalScreen, &attr);
490     value_list = (CARD32 *) (stuff + 1);
491     count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list);
492 
493     if (!(name = malloc(stuff->displayNameLength + 1 + 4)))
494         return BadAlloc;
495     memcpy(name, &value_list[count], stuff->displayNameLength);
496     name[stuff->displayNameLength] = '\0';
497     attr.displayName = name;
498 
499     status = dmxAttachScreen(stuff->physicalScreen, &attr);
500 
501     free(name);
502 
503     rep = (xDMXAddScreenReply) {
504         .type = X_Reply,
505         .sequenceNumber = client->sequence,
506         .length = 0,
507         .status = status,
508         .physicalScreen = stuff->physicalScreen
509     };
510     if (client->swapped) {
511         swaps(&rep.sequenceNumber);
512         swapl(&rep.length);
513         swapl(&rep.status);
514         swapl(&rep.physicalScreen);
515     }
516     WriteToClient(client, sizeof(xDMXAddScreenReply), &rep);
517     return Success;
518 }
519 
520 static int
ProcDMXRemoveScreen(ClientPtr client)521 ProcDMXRemoveScreen(ClientPtr client)
522 {
523     REQUEST(xDMXRemoveScreenReq);
524     xDMXRemoveScreenReply rep;
525     int status = 0;
526 
527     REQUEST_SIZE_MATCH(xDMXRemoveScreenReq);
528 
529     status = dmxDetachScreen(stuff->physicalScreen);
530 
531     rep = (xDMXRemoveScreenReply) {
532         .type = X_Reply,
533         .sequenceNumber = client->sequence,
534         .length = 0,
535         .status = status
536     };
537     if (client->swapped) {
538         swaps(&rep.sequenceNumber);
539         swapl(&rep.length);
540         swapl(&rep.status);
541     }
542     WriteToClient(client, sizeof(xDMXRemoveScreenReply), &rep);
543     return Success;
544 }
545 
546 #ifdef PANORAMIX
547 static int
dmxPopulatePanoramiX(ClientPtr client,Window window,CARD32 * screens,CARD32 * windows,xRectangle * pos,xRectangle * vis)548 dmxPopulatePanoramiX(ClientPtr client, Window window,
549                      CARD32 *screens, CARD32 *windows,
550                      xRectangle *pos, xRectangle *vis)
551 {
552     WindowPtr pWin;
553     PanoramiXRes *win;
554     int i;
555     int count = 0;
556     DMXWindowAttributesRec attr;
557 
558     if (Success != dixLookupResourceByType((void **) &win,
559                                            window, XRT_WINDOW,
560                                            client, DixReadAccess))
561         return -1;              /* BadWindow */
562 
563     FOR_NSCREENS(i) {
564         if (Success != dixLookupWindow(&pWin, win->info[i].id, client,
565                                        DixReadAccess))
566             return -1;          /* BadWindow */
567         if (dmxGetWindowAttributes(pWin, &attr)) {
568             screens[count] = attr.screen;
569             windows[count] = attr.window;
570             pos[count] = attr.pos;
571             vis[count] = attr.vis;
572             ++count;            /* Only count existing windows */
573         }
574     }
575     return count;
576 }
577 #endif
578 
579 static int
dmxPopulate(ClientPtr client,Window window,CARD32 * screens,CARD32 * windows,xRectangle * pos,xRectangle * vis)580 dmxPopulate(ClientPtr client, Window window, CARD32 *screens,
581             CARD32 *windows, xRectangle *pos, xRectangle *vis)
582 {
583     WindowPtr pWin;
584     DMXWindowAttributesRec attr;
585 
586 #ifdef PANORAMIX
587     if (!noPanoramiXExtension)
588         return dmxPopulatePanoramiX(client, window, screens, windows, pos, vis);
589 #endif
590 
591     if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess))
592         return -1;              /* BadWindow */
593 
594     dmxGetWindowAttributes(pWin, &attr);
595     *screens = attr.screen;
596     *windows = attr.window;
597     *pos = attr.pos;
598     *vis = attr.vis;
599     return 1;
600 }
601 
602 static int
dmxMaxNumScreens(void)603 dmxMaxNumScreens(void)
604 {
605 #ifdef PANORAMIX
606     if (!noPanoramiXExtension)
607         return PanoramiXNumScreens;
608 #endif
609     return 1;
610 }
611 
612 static int
ProcDMXGetWindowAttributes(ClientPtr client)613 ProcDMXGetWindowAttributes(ClientPtr client)
614 {
615     REQUEST(xDMXGetWindowAttributesReq);
616     xDMXGetWindowAttributesReply rep;
617     int i;
618     CARD32 *screens;
619     CARD32 *windows;
620     xRectangle *pos, *vis;
621     int count = dmxMaxNumScreens();
622 
623     REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq);
624 
625     if (!(screens = xallocarray(count, sizeof(*screens))))
626         return BadAlloc;
627     if (!(windows = xallocarray(count, sizeof(*windows)))) {
628         free(screens);
629         return BadAlloc;
630     }
631     if (!(pos = xallocarray(count, sizeof(*pos)))) {
632         free(windows);
633         free(screens);
634         return BadAlloc;
635     }
636     if (!(vis = xallocarray(count, sizeof(*vis)))) {
637         free(pos);
638         free(windows);
639         free(screens);
640         return BadAlloc;
641     }
642 
643     if ((count = dmxPopulate(client, stuff->window, screens, windows,
644                              pos, vis)) < 0) {
645         free(vis);
646         free(pos);
647         free(windows);
648         free(screens);
649         return BadWindow;
650     }
651 
652     rep = (xDMXGetWindowAttributesReply) {
653         .type = X_Reply,
654         .sequenceNumber = client->sequence,
655         .length = count * 6,
656         .screenCount = count
657     };
658     if (client->swapped) {
659         swaps(&rep.sequenceNumber);
660         swapl(&rep.length);
661         swapl(&rep.screenCount);
662         for (i = 0; i < count; i++) {
663             swapl(&screens[i]);
664             swapl(&windows[i]);
665 
666             swaps(&pos[i].x);
667             swaps(&pos[i].y);
668             swaps(&pos[i].width);
669             swaps(&pos[i].height);
670 
671             swaps(&vis[i].x);
672             swaps(&vis[i].y);
673             swaps(&vis[i].width);
674             swaps(&vis[i].height);
675         }
676     }
677 
678     dmxFlushPendingSyncs();
679 
680     WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), &rep);
681     if (count) {
682         WriteToClient(client, count * sizeof(*screens), screens);
683         WriteToClient(client, count * sizeof(*windows), windows);
684         WriteToClient(client, count * sizeof(*pos), pos);
685         WriteToClient(client, count * sizeof(*vis), vis);
686     }
687 
688     free(vis);
689     free(pos);
690     free(windows);
691     free(screens);
692 
693     return Success;
694 }
695 
696 static int
ProcDMXGetDesktopAttributes(ClientPtr client)697 ProcDMXGetDesktopAttributes(ClientPtr client)
698 {
699     xDMXGetDesktopAttributesReply rep;
700     DMXDesktopAttributesRec attr;
701 
702     REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq);
703 
704     dmxGetDesktopAttributes(&attr);
705 
706     rep = (xDMXGetDesktopAttributesReply) {
707         .type = X_Reply,
708         .sequenceNumber = client->sequence,
709         .length = 0,
710         .width = attr.width,
711         .height = attr.height,
712         .shiftX = attr.shiftX,
713         .shiftY = attr.shiftY
714     };
715 
716     if (client->swapped) {
717         swaps(&rep.sequenceNumber);
718         swapl(&rep.length);
719         swaps(&rep.width);
720         swaps(&rep.height);
721         swaps(&rep.shiftX);
722         swaps(&rep.shiftY);
723     }
724     WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), &rep);
725     return Success;
726 }
727 
728 static int
ProcDMXChangeDesktopAttributes(ClientPtr client)729 ProcDMXChangeDesktopAttributes(ClientPtr client)
730 {
731     REQUEST(xDMXChangeDesktopAttributesReq);
732     xDMXChangeDesktopAttributesReply rep;
733     int status = DMX_BAD_XINERAMA;
734     CARD32 *value_list;
735     DMXDesktopAttributesRec attr;
736     int len;
737 
738     REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq);
739     len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2);
740     if (len != Ones(stuff->valueMask))
741         return BadLength;
742 
743     if (!_DMXXineramaActive())
744         goto noxinerama;
745 
746     value_list = (CARD32 *) (stuff + 1);
747 
748     dmxGetDesktopAttributes(&attr);
749     dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list);
750 
751 #ifdef PANORAMIX
752     status = dmxConfigureDesktop(&attr);
753 #endif
754     if (status == BadValue)
755         return status;
756 
757  noxinerama:
758     rep = (xDMXChangeDesktopAttributesReply) {
759         .type = X_Reply,
760         .sequenceNumber = client->sequence,
761         .length = 0,
762         .status = status
763     };
764     if (client->swapped) {
765         swaps(&rep.sequenceNumber);
766         swapl(&rep.length);
767         swapl(&rep.status);
768     }
769     WriteToClient(client, sizeof(xDMXChangeDesktopAttributesReply), &rep);
770     return Success;
771 }
772 
773 static int
ProcDMXGetInputCount(ClientPtr client)774 ProcDMXGetInputCount(ClientPtr client)
775 {
776     xDMXGetInputCountReply rep;
777 
778     REQUEST_SIZE_MATCH(xDMXGetInputCountReq);
779 
780     rep = (xDMXGetInputCountReply) {
781         .type = X_Reply,
782         .sequenceNumber = client->sequence,
783         .length = 0,
784         .inputCount = dmxGetInputCount()
785     };
786     if (client->swapped) {
787         swaps(&rep.sequenceNumber);
788         swapl(&rep.length);
789         swapl(&rep.inputCount);
790     }
791     WriteToClient(client, sizeof(xDMXGetInputCountReply), &rep);
792     return Success;
793 }
794 
795 static int
ProcDMXGetInputAttributes(ClientPtr client)796 ProcDMXGetInputAttributes(ClientPtr client)
797 {
798     REQUEST(xDMXGetInputAttributesReq);
799     xDMXGetInputAttributesReply rep;
800     int length;
801     int paddedLength;
802     DMXInputAttributesRec attr;
803 
804     REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq);
805 
806     if (dmxGetInputAttributes(stuff->deviceId, &attr))
807         return BadValue;
808 
809     length = attr.name ? strlen(attr.name) : 0;
810     paddedLength = pad_to_int32(length);
811 
812     rep = (xDMXGetInputAttributesReply) {
813         .type = X_Reply,
814         .sequenceNumber = client->sequence,
815         .length = bytes_to_int32(paddedLength),
816 
817         .inputType = attr.inputType,
818         .physicalScreen = attr.physicalScreen,
819         .physicalId = attr.physicalId,
820         .nameLength = length,
821         .isCore = attr.isCore,
822         .sendsCore = attr.sendsCore,
823         .detached = attr.detached
824     };
825 
826     if (client->swapped) {
827         swaps(&rep.sequenceNumber);
828         swapl(&rep.length);
829         swapl(&rep.inputType);
830         swapl(&rep.physicalScreen);
831         swapl(&rep.physicalId);
832         swapl(&rep.nameLength);
833     }
834     WriteToClient(client, sizeof(xDMXGetInputAttributesReply), &rep);
835     if (length)
836         WriteToClient(client, length, attr.name);
837     return Success;
838 }
839 
840 static int
ProcDMXAddInput(ClientPtr client)841 ProcDMXAddInput(ClientPtr client)
842 {
843     REQUEST(xDMXAddInputReq);
844     xDMXAddInputReply rep;
845     int status = 0;
846     CARD32 *value_list;
847     DMXInputAttributesRec attr;
848     int count;
849     char *name;
850     int len;
851     int paddedLength;
852     int id = -1;
853 
854     REQUEST_AT_LEAST_SIZE(xDMXAddInputReq);
855     paddedLength = pad_to_int32(stuff->displayNameLength);
856     len = client->req_len - (sizeof(xDMXAddInputReq) >> 2);
857     if (len != Ones(stuff->valueMask) + paddedLength / 4)
858         return BadLength;
859 
860     memset(&attr, 0, sizeof(attr));
861     value_list = (CARD32 *) (stuff + 1);
862     count = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list);
863 
864     if (!(name = malloc(stuff->displayNameLength + 1 + 4)))
865         return BadAlloc;
866     memcpy(name, &value_list[count], stuff->displayNameLength);
867     name[stuff->displayNameLength] = '\0';
868     attr.name = name;
869 
870     status = dmxAddInput(&attr, &id);
871 
872     free(name);
873 
874     if (status)
875         return status;
876 
877     rep = (xDMXAddInputReply) {
878         .type = X_Reply,
879         .sequenceNumber = client->sequence,
880         .length = 0,
881         .status = status,
882         .physicalId = id
883     };
884     if (client->swapped) {
885         swaps(&rep.sequenceNumber);
886         swapl(&rep.length);
887         swapl(&rep.status);
888         swapl(&rep.physicalId);
889     }
890     WriteToClient(client, sizeof(xDMXAddInputReply), &rep);
891     return Success;
892 }
893 
894 static int
ProcDMXRemoveInput(ClientPtr client)895 ProcDMXRemoveInput(ClientPtr client)
896 {
897     REQUEST(xDMXRemoveInputReq);
898     xDMXRemoveInputReply rep;
899     int status = 0;
900 
901     REQUEST_SIZE_MATCH(xDMXRemoveInputReq);
902 
903     status = dmxRemoveInput(stuff->physicalId);
904 
905     if (status)
906         return status;
907 
908     rep = (xDMXRemoveInputReply) {
909         .type = X_Reply,
910         .sequenceNumber = client->sequence,
911         .length = 0,
912         .status = status
913     };
914     if (client->swapped) {
915         swaps(&rep.sequenceNumber);
916         swapl(&rep.length);
917         swapl(&rep.status);
918     }
919     WriteToClient(client, sizeof(xDMXRemoveInputReply), &rep);
920     return Success;
921 }
922 
923 static int
ProcDMXDispatch(ClientPtr client)924 ProcDMXDispatch(ClientPtr client)
925 {
926     REQUEST(xReq);
927 
928     switch (stuff->data) {
929     case X_DMXQueryVersion:
930         return ProcDMXQueryVersion(client);
931     case X_DMXSync:
932         return ProcDMXSync(client);
933     case X_DMXForceWindowCreation:
934         return ProcDMXForceWindowCreation(client);
935     case X_DMXGetScreenCount:
936         return ProcDMXGetScreenCount(client);
937     case X_DMXGetScreenAttributes:
938         return ProcDMXGetScreenAttributes(client);
939     case X_DMXChangeScreensAttributes:
940         return ProcDMXChangeScreensAttributes(client);
941     case X_DMXAddScreen:
942         return ProcDMXAddScreen(client);
943     case X_DMXRemoveScreen:
944         return ProcDMXRemoveScreen(client);
945     case X_DMXGetWindowAttributes:
946         return ProcDMXGetWindowAttributes(client);
947     case X_DMXGetDesktopAttributes:
948         return ProcDMXGetDesktopAttributes(client);
949     case X_DMXChangeDesktopAttributes:
950         return ProcDMXChangeDesktopAttributes(client);
951     case X_DMXGetInputCount:
952         return ProcDMXGetInputCount(client);
953     case X_DMXGetInputAttributes:
954         return ProcDMXGetInputAttributes(client);
955     case X_DMXAddInput:
956         return ProcDMXAddInput(client);
957     case X_DMXRemoveInput:
958         return ProcDMXRemoveInput(client);
959 
960     case X_DMXGetScreenInformationDEPRECATED:
961     case X_DMXForceWindowCreationDEPRECATED:
962     case X_DMXReconfigureScreenDEPRECATED:
963         return BadImplementation;
964 
965     default:
966         return BadRequest;
967     }
968 }
969 
970 static int _X_COLD
SProcDMXQueryVersion(ClientPtr client)971 SProcDMXQueryVersion(ClientPtr client)
972 {
973     REQUEST(xDMXQueryVersionReq);
974 
975     swaps(&stuff->length);
976     REQUEST_SIZE_MATCH(xDMXQueryVersionReq);
977     return ProcDMXQueryVersion(client);
978 }
979 
980 static int _X_COLD
SProcDMXSync(ClientPtr client)981 SProcDMXSync(ClientPtr client)
982 {
983     REQUEST(xDMXSyncReq);
984 
985     swaps(&stuff->length);
986     REQUEST_SIZE_MATCH(xDMXSyncReq);
987     return ProcDMXSync(client);
988 }
989 
990 static int _X_COLD
SProcDMXForceWindowCreation(ClientPtr client)991 SProcDMXForceWindowCreation(ClientPtr client)
992 {
993     REQUEST(xDMXForceWindowCreationReq);
994 
995     swaps(&stuff->length);
996     REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq);
997     swapl(&stuff->window);
998     return ProcDMXForceWindowCreation(client);
999 }
1000 
1001 static int _X_COLD
SProcDMXGetScreenCount(ClientPtr client)1002 SProcDMXGetScreenCount(ClientPtr client)
1003 {
1004     REQUEST(xDMXGetScreenCountReq);
1005 
1006     swaps(&stuff->length);
1007     REQUEST_SIZE_MATCH(xDMXGetScreenCountReq);
1008     return ProcDMXGetScreenCount(client);
1009 }
1010 
1011 static int _X_COLD
SProcDMXGetScreenAttributes(ClientPtr client)1012 SProcDMXGetScreenAttributes(ClientPtr client)
1013 {
1014     REQUEST(xDMXGetScreenAttributesReq);
1015 
1016     swaps(&stuff->length);
1017     REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq);
1018     swapl(&stuff->physicalScreen);
1019     return ProcDMXGetScreenAttributes(client);
1020 }
1021 
1022 static int _X_COLD
SProcDMXChangeScreensAttributes(ClientPtr client)1023 SProcDMXChangeScreensAttributes(ClientPtr client)
1024 {
1025     REQUEST(xDMXChangeScreensAttributesReq);
1026 
1027     swaps(&stuff->length);
1028     REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq);
1029     swapl(&stuff->screenCount);
1030     swapl(&stuff->maskCount);
1031     SwapRestL(stuff);
1032     return ProcDMXGetScreenAttributes(client);
1033 }
1034 
1035 static int _X_COLD
SProcDMXAddScreen(ClientPtr client)1036 SProcDMXAddScreen(ClientPtr client)
1037 {
1038     int paddedLength;
1039 
1040     REQUEST(xDMXAddScreenReq);
1041 
1042     swaps(&stuff->length);
1043     REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq);
1044     swapl(&stuff->displayNameLength);
1045     swapl(&stuff->valueMask);
1046     paddedLength = pad_to_int32(stuff->displayNameLength);
1047     SwapLongs((CARD32 *) (stuff + 1), LengthRestL(stuff) - paddedLength / 4);
1048     return ProcDMXAddScreen(client);
1049 }
1050 
1051 static int _X_COLD
SProcDMXRemoveScreen(ClientPtr client)1052 SProcDMXRemoveScreen(ClientPtr client)
1053 {
1054     REQUEST(xDMXRemoveScreenReq);
1055 
1056     swaps(&stuff->length);
1057     REQUEST_SIZE_MATCH(xDMXRemoveScreenReq);
1058     swapl(&stuff->physicalScreen);
1059     return ProcDMXRemoveScreen(client);
1060 }
1061 
1062 static int _X_COLD
SProcDMXGetWindowAttributes(ClientPtr client)1063 SProcDMXGetWindowAttributes(ClientPtr client)
1064 {
1065     REQUEST(xDMXGetWindowAttributesReq);
1066 
1067     swaps(&stuff->length);
1068     REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq);
1069     swapl(&stuff->window);
1070     return ProcDMXGetWindowAttributes(client);
1071 }
1072 
1073 static int _X_COLD
SProcDMXGetDesktopAttributes(ClientPtr client)1074 SProcDMXGetDesktopAttributes(ClientPtr client)
1075 {
1076     REQUEST(xDMXGetDesktopAttributesReq);
1077 
1078     swaps(&stuff->length);
1079     REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq);
1080     return ProcDMXGetDesktopAttributes(client);
1081 }
1082 
1083 static int _X_COLD
SProcDMXChangeDesktopAttributes(ClientPtr client)1084 SProcDMXChangeDesktopAttributes(ClientPtr client)
1085 {
1086     REQUEST(xDMXChangeDesktopAttributesReq);
1087 
1088     swaps(&stuff->length);
1089     REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq);
1090     swapl(&stuff->valueMask);
1091     SwapRestL(stuff);
1092     return ProcDMXChangeDesktopAttributes(client);
1093 }
1094 
1095 static int _X_COLD
SProcDMXGetInputCount(ClientPtr client)1096 SProcDMXGetInputCount(ClientPtr client)
1097 {
1098     REQUEST(xDMXGetInputCountReq);
1099 
1100     swaps(&stuff->length);
1101     REQUEST_SIZE_MATCH(xDMXGetInputCountReq);
1102     return ProcDMXGetInputCount(client);
1103 }
1104 
1105 static int _X_COLD
SProcDMXGetInputAttributes(ClientPtr client)1106 SProcDMXGetInputAttributes(ClientPtr client)
1107 {
1108     REQUEST(xDMXGetInputAttributesReq);
1109 
1110     swaps(&stuff->length);
1111     REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq);
1112     swapl(&stuff->deviceId);
1113     return ProcDMXGetInputAttributes(client);
1114 }
1115 
1116 static int _X_COLD
SProcDMXAddInput(ClientPtr client)1117 SProcDMXAddInput(ClientPtr client)
1118 {
1119     int paddedLength;
1120 
1121     REQUEST(xDMXAddInputReq);
1122 
1123     swaps(&stuff->length);
1124     REQUEST_AT_LEAST_SIZE(xDMXAddInputReq);
1125     swapl(&stuff->displayNameLength);
1126     swapl(&stuff->valueMask);
1127     paddedLength = pad_to_int32(stuff->displayNameLength);
1128     SwapLongs((CARD32 *) (stuff + 1), LengthRestL(stuff) - paddedLength / 4);
1129     return ProcDMXAddInput(client);
1130 }
1131 
1132 static int _X_COLD
SProcDMXRemoveInput(ClientPtr client)1133 SProcDMXRemoveInput(ClientPtr client)
1134 {
1135     REQUEST(xDMXRemoveInputReq);
1136 
1137     swaps(&stuff->length);
1138     REQUEST_SIZE_MATCH(xDMXRemoveInputReq);
1139     swapl(&stuff->physicalId);
1140     return ProcDMXRemoveInput(client);
1141 }
1142 
1143 static int _X_COLD
SProcDMXDispatch(ClientPtr client)1144 SProcDMXDispatch(ClientPtr client)
1145 {
1146     REQUEST(xReq);
1147 
1148     switch (stuff->data) {
1149     case X_DMXQueryVersion:
1150         return SProcDMXQueryVersion(client);
1151     case X_DMXSync:
1152         return SProcDMXSync(client);
1153     case X_DMXForceWindowCreation:
1154         return SProcDMXForceWindowCreation(client);
1155     case X_DMXGetScreenCount:
1156         return SProcDMXGetScreenCount(client);
1157     case X_DMXGetScreenAttributes:
1158         return SProcDMXGetScreenAttributes(client);
1159     case X_DMXChangeScreensAttributes:
1160         return SProcDMXChangeScreensAttributes(client);
1161     case X_DMXAddScreen:
1162         return SProcDMXAddScreen(client);
1163     case X_DMXRemoveScreen:
1164         return SProcDMXRemoveScreen(client);
1165     case X_DMXGetWindowAttributes:
1166         return SProcDMXGetWindowAttributes(client);
1167     case X_DMXGetDesktopAttributes:
1168         return SProcDMXGetDesktopAttributes(client);
1169     case X_DMXChangeDesktopAttributes:
1170         return SProcDMXChangeDesktopAttributes(client);
1171     case X_DMXGetInputCount:
1172         return SProcDMXGetInputCount(client);
1173     case X_DMXGetInputAttributes:
1174         return SProcDMXGetInputAttributes(client);
1175     case X_DMXAddInput:
1176         return SProcDMXAddInput(client);
1177     case X_DMXRemoveInput:
1178         return SProcDMXRemoveInput(client);
1179 
1180     case X_DMXGetScreenInformationDEPRECATED:
1181     case X_DMXForceWindowCreationDEPRECATED:
1182     case X_DMXReconfigureScreenDEPRECATED:
1183         return BadImplementation;
1184 
1185     default:
1186         return BadRequest;
1187     }
1188 }
1189 
1190 /** Initialize the extension. */
1191 void
DMXExtensionInit(void)1192 DMXExtensionInit(void)
1193 {
1194     ExtensionEntry *extEntry;
1195 
1196     if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0,
1197                                  ProcDMXDispatch, SProcDMXDispatch,
1198                                  NULL, StandardMinorOpcode)))
1199         DMXCode = extEntry->base;
1200 }
1201