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 /* THIS IS NOT AN X CONSORTIUM STANDARD */
35
36 /** \file
37 * This file implements the client-side part of the DMX protocol. It
38 * can be included in client applications by linking with the libdmx.a
39 * library. */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44 #include <X11/Xlibint.h>
45 #include <X11/extensions/Xext.h>
46 #define EXTENSION_PROC_ARGS void *
47 #include <X11/extensions/extutil.h>
48 #include <X11/extensions/dmxproto.h>
49 #include <X11/extensions/dmxext.h>
50 #include <limits.h>
51
52 static XExtensionInfo dmx_extension_info_data;
53 static XExtensionInfo *dmx_extension_info = &dmx_extension_info_data;
54 static const char *dmx_extension_name = DMX_EXTENSION_NAME;
55
56 #define DMXCheckExtension(dpy,i,val) \
57 XextCheckExtension(dpy, i, dmx_extension_name, val)
58 #define DMXSimpleCheckExtension(dpy,i) \
59 XextSimpleCheckExtension(dpy, i, dmx_extension_name)
60
61 /*****************************************************************************
62 * *
63 * private utility routines *
64 * *
65 *****************************************************************************/
66
67 static int close_display(Display *dpy, XExtCodes *extCodes);
68 static /* const */ XExtensionHooks dmx_extension_hooks = {
69 NULL, /* create_gc */
70 NULL, /* copy_gc */
71 NULL, /* flush_gc */
72 NULL, /* free_gc */
73 NULL, /* create_font */
74 NULL, /* free_font */
75 close_display, /* close_display */
76 NULL, /* wire_to_event */
77 NULL, /* event_to_wire */
78 NULL, /* error */
79 NULL, /* error_string */
80 };
81
82 static XEXT_GENERATE_FIND_DISPLAY(find_display, dmx_extension_info,
83 dmx_extension_name,
84 &dmx_extension_hooks,
85 0, NULL)
86
XEXT_GENERATE_CLOSE_DISPLAY(close_display,dmx_extension_info)87 static XEXT_GENERATE_CLOSE_DISPLAY(close_display, dmx_extension_info)
88
89
90 /*****************************************************************************
91 * *
92 * public DMX Extension routines *
93 * *
94 *****************************************************************************/
95
96 /** If the server has the DMX extension, the event and error bases will
97 * be placed in \a event_basep and \a error_basep, and True will be
98 * returned. Otherwise, False will be returned.
99 *
100 * Available in DMX Protocol Version 1.0 */
101 Bool DMXQueryExtension(Display *dpy, int *event_basep, int *error_basep)
102 {
103 XExtDisplayInfo *info = find_display(dpy);
104
105 if (XextHasExtension(info)) {
106 *event_basep = info->codes->first_event;
107 *error_basep = info->codes->first_error;
108 return True;
109 } else {
110 return False;
111 }
112 }
113
114 /** If the DMXQueryVersion protocol request returns version information
115 * from the server, \a majorVersion, \a minorVersion, and \a
116 * patchVersion are filled in with the appropriate information and True
117 * is returned. Otherwise, False will be returned.
118 *
119 * Available in DMX Protocol Version 1.0 */
DMXQueryVersion(Display * dpy,int * majorVersion,int * minorVersion,int * patchVersion)120 Bool DMXQueryVersion(Display *dpy,
121 int *majorVersion, int *minorVersion, int *patchVersion)
122 {
123 XExtDisplayInfo *info = find_display(dpy);
124 xDMXQueryVersionReply rep;
125 xDMXQueryVersionReq *req;
126
127 DMXCheckExtension(dpy, info, False);
128
129 LockDisplay(dpy);
130 GetReq(DMXQueryVersion, req);
131 req->reqType = info->codes->major_opcode;
132 req->dmxReqType = X_DMXQueryVersion;
133 if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
134 UnlockDisplay(dpy);
135 SyncHandle();
136 return False;
137 }
138 *majorVersion = rep.majorVersion;
139 *minorVersion = rep.minorVersion;
140 *patchVersion = rep.patchVersion;
141 UnlockDisplay(dpy);
142 SyncHandle();
143 return True;
144 }
145
146 /** Flush all pending dmxSync requests in DMX server.
147 *
148 * Available in DMX Protocol Version 1.5 */
DMXSync(Display * dpy)149 Bool DMXSync(Display *dpy)
150 {
151 XExtDisplayInfo *info = find_display(dpy);
152 xDMXSyncReply rep;
153 xDMXSyncReq *req;
154
155 DMXCheckExtension(dpy, info, False);
156
157 LockDisplay(dpy);
158 GetReq(DMXSync, req);
159 req->reqType = info->codes->major_opcode;
160 req->dmxReqType = X_DMXSync;
161 if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
162 UnlockDisplay(dpy);
163 SyncHandle();
164 return False;
165 }
166
167 UnlockDisplay(dpy);
168 SyncHandle();
169 return rep.status == Success ? True : False;
170 }
171
172 /** The creation of the specified \a window will be forced.
173 *
174 * Available in DMX Protocol Version 1.2
175 * Reply added in DMX Protocol Version 2.0 */
DMXForceWindowCreation(Display * dpy,Window window)176 Bool DMXForceWindowCreation(Display *dpy, Window window)
177 {
178 XExtDisplayInfo *info = find_display(dpy);
179 xDMXForceWindowCreationReq *req;
180 xDMXForceWindowCreationReply rep;
181
182 DMXCheckExtension(dpy, info, False);
183
184 LockDisplay(dpy);
185 GetReq(DMXForceWindowCreation, req);
186 req->reqType = info->codes->major_opcode;
187 req->dmxReqType = X_DMXForceWindowCreation;
188 req->window = window;
189 if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
190 UnlockDisplay(dpy);
191 SyncHandle();
192 return False;
193 }
194
195 UnlockDisplay(dpy);
196 SyncHandle();
197 return rep.status == Success ? True : False;
198 }
199
200 /** If the DMXGetScreenCount protocol request returns the screen count,
201 * the value will be placed in \a screen_count, and True will be
202 * returned. Otherwise, False will be returned.
203 *
204 * Available in DMX Protocol Version 1.0 */
DMXGetScreenCount(Display * dpy,int * screen_count)205 Bool DMXGetScreenCount(Display *dpy, int *screen_count)
206 {
207 XExtDisplayInfo *info = find_display(dpy);
208 xDMXGetScreenCountReply rep;
209 xDMXGetScreenCountReq *req;
210
211 DMXCheckExtension(dpy, info, False);
212
213 LockDisplay(dpy);
214 GetReq(DMXGetScreenCount, req);
215 req->reqType = info->codes->major_opcode;
216 req->dmxReqType = X_DMXGetScreenCount;
217 if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
218 UnlockDisplay(dpy);
219 SyncHandle();
220 return False;
221 }
222 *screen_count = rep.screenCount;
223 UnlockDisplay(dpy);
224 SyncHandle();
225 return True;
226 }
227
228 /** If the DMXGetScreenAttributes protocol request returns information
229 * for the specified \a physical_screen, information about the screen
230 * will be placed in \a attr, and True will be returned. Otherwise,
231 * False will be returned.
232 *
233 * Available in DMX Protocol Version 1.0; Modified in Version 2.0 */
DMXGetScreenAttributes(Display * dpy,int physical_screen,DMXScreenAttributes * attr)234 Bool DMXGetScreenAttributes(Display *dpy, int physical_screen,
235 DMXScreenAttributes *attr)
236 {
237 XExtDisplayInfo *info = find_display(dpy);
238 xDMXGetScreenAttributesReply rep;
239 xDMXGetScreenAttributesReq *req;
240 Bool ret = False;
241
242 DMXCheckExtension(dpy, info, False);
243
244 LockDisplay(dpy);
245 GetReq(DMXGetScreenAttributes, req);
246 req->reqType = info->codes->major_opcode;
247 req->dmxReqType = X_DMXGetScreenAttributes;
248 req->physicalScreen = physical_screen;
249 if (!_XReply(dpy, (xReply *)&rep,
250 (SIZEOF(xDMXGetScreenAttributesReply) - 32) >> 2, xFalse)) {
251 UnlockDisplay(dpy);
252 SyncHandle();
253 return False;
254 }
255
256 if (rep.displayNameLength < 1024)
257 attr->displayName = Xmalloc(rep.displayNameLength + 1 + 4 /* for pad */);
258 else
259 attr->displayName = NULL; /* name length is unbelievable, reject */
260 if (attr->displayName == NULL) {
261 _XEatDataWords(dpy, rep.length);
262 goto end;
263 }
264 _XReadPad(dpy, attr->displayName, rep.displayNameLength);
265 attr->displayName[rep.displayNameLength] = '\0';
266 attr->logicalScreen = rep.logicalScreen;
267
268 attr->screenWindowWidth = rep.screenWindowWidth;
269 attr->screenWindowHeight = rep.screenWindowHeight;
270 attr->screenWindowXoffset = rep.screenWindowXoffset;
271 attr->screenWindowYoffset = rep.screenWindowYoffset;
272
273 attr->rootWindowWidth = rep.rootWindowWidth;
274 attr->rootWindowHeight = rep.rootWindowHeight;
275 attr->rootWindowXoffset = rep.rootWindowXoffset;
276 attr->rootWindowYoffset = rep.rootWindowYoffset;
277 attr->rootWindowXorigin = rep.rootWindowXorigin;
278 attr->rootWindowYorigin = rep.rootWindowYorigin;
279
280 ret = True;
281
282 end:
283 UnlockDisplay(dpy);
284 SyncHandle();
285 return ret;
286 }
287
_DMXGetScreenAttribute(int bit,DMXScreenAttributes * attr)288 static CARD32 _DMXGetScreenAttribute(int bit, DMXScreenAttributes *attr)
289 {
290 switch (1 << bit) {
291 case DMXScreenWindowWidth: return attr->screenWindowWidth;
292 case DMXScreenWindowHeight: return attr->screenWindowHeight;
293 case DMXScreenWindowXoffset: return attr->screenWindowXoffset;
294 case DMXScreenWindowYoffset: return attr->screenWindowYoffset;
295 case DMXRootWindowWidth: return attr->rootWindowWidth;
296 case DMXRootWindowHeight: return attr->rootWindowHeight;
297 case DMXRootWindowXoffset: return attr->rootWindowXoffset;
298 case DMXRootWindowYoffset: return attr->rootWindowYoffset;
299 case DMXRootWindowXorigin: return attr->rootWindowXorigin;
300 case DMXRootWindowYorigin: return attr->rootWindowYorigin;
301 default: return 0;
302 }
303 }
304
_DMXDumpScreenAttributes(Display * dpy,unsigned long mask,DMXScreenAttributes * attr)305 static int _DMXDumpScreenAttributes(Display *dpy,
306 unsigned long mask,
307 DMXScreenAttributes *attr)
308 {
309 int i;
310 unsigned long value_list[32];
311 unsigned long *value = value_list;
312 int count = 0;
313
314 for (i = 0; i < 32; i++) {
315 if (mask & (1 << i)) {
316 *value++ = _DMXGetScreenAttribute(i, attr);
317 ++count;
318 }
319 }
320 Data32(dpy, value_list, count * sizeof(CARD32));
321 return count;
322 }
323
_DMXGetInputAttribute(int bit,DMXInputAttributes * attr)324 static CARD32 _DMXGetInputAttribute(int bit, DMXInputAttributes *attr)
325 {
326 switch (1 << bit) {
327 case DMXInputType:
328 switch (attr->inputType) {
329 case DMXLocalInputType: return 0;
330 case DMXConsoleInputType: return 1;
331 case DMXBackendInputType: return 2;
332 }
333 return attr->inputType;
334 case DMXInputPhysicalScreen: return attr->physicalScreen;
335 case DMXInputSendsCore: return attr->sendsCore;
336 default: return 0;
337 }
338 }
339
_DMXDumpInputAttributes(Display * dpy,unsigned long mask,DMXInputAttributes * attr)340 static int _DMXDumpInputAttributes(Display *dpy,
341 unsigned long mask,
342 DMXInputAttributes *attr)
343 {
344 int i;
345 unsigned long value_list[32];
346 unsigned long *value = value_list;
347 int count = 0;
348
349 for (i = 0; i < 32; i++) {
350 if (mask & (1 << i)) {
351 *value++ = _DMXGetInputAttribute(i, attr);
352 ++count;
353 }
354 }
355 Data32(dpy, value_list, count * sizeof(CARD32));
356 return count;
357 }
358
359 /** Change geometries and positions of the DMX screen and root windows
360 * on the back-end X server. */
DMXChangeScreensAttributes(Display * dpy,int screen_count,int * screens,int mask_count,unsigned int * masks,DMXScreenAttributes * attrs,int * error_screen)361 int DMXChangeScreensAttributes(Display *dpy,
362 int screen_count,
363 int *screens,
364 int mask_count,
365 unsigned int *masks,
366 DMXScreenAttributes *attrs, /* vector */
367 int *error_screen)
368 {
369 XExtDisplayInfo *info = find_display(dpy);
370 xDMXChangeScreensAttributesReply rep;
371 xDMXChangeScreensAttributesReq *req;
372 int i;
373 unsigned int mask = 0;
374 CARD32 *screen_list;
375 CARD32 *mask_list;
376
377 DMXCheckExtension(dpy, info, False);
378
379 if (screen_count < 1 || mask_count < 1) return DmxBadValue;
380
381 LockDisplay(dpy);
382 GetReq(DMXChangeScreensAttributes, req);
383 req->reqType = info->codes->major_opcode;
384 req->dmxReqType = X_DMXChangeScreensAttributes;
385 req->screenCount = screen_count;
386 req->maskCount = mask_count;
387 req->length += screen_count + mask_count;
388
389 screen_list = (CARD32 *)Xmalloc(sizeof(*screen_list) * screen_count);
390 for (i = 0; i < screen_count; i++) screen_list[i] = screens[i];
391 Data32(dpy, screen_list, screen_count * sizeof(CARD32));
392 Xfree(screen_list);
393
394 mask_list = (CARD32 *)Xmalloc(sizeof(*mask_list) * mask_count);
395 for (i = 0; i < mask_count; i++) mask_list[i] = masks[i];
396 Data32(dpy, mask_list, mask_count * sizeof(CARD32));
397 Xfree(mask_list);
398
399 for (i = 0; i < screen_count; i++) {
400 if (i < mask_count) mask = masks[i];
401 req->length += _DMXDumpScreenAttributes(dpy, mask, attrs + i);
402 }
403
404 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
405 UnlockDisplay(dpy);
406 SyncHandle();
407 return DmxBadReply;
408 }
409 if (error_screen) *error_screen = rep.errorScreen;
410 UnlockDisplay(dpy);
411 SyncHandle();
412 return rep.status;
413 }
414
415 /** Add a screen. */
DMXAddScreen(Display * dpy,const char * displayName,unsigned int mask,DMXScreenAttributes * attr,int * screen)416 Bool DMXAddScreen(Display *dpy, const char *displayName, unsigned int mask,
417 DMXScreenAttributes *attr, int *screen)
418 {
419 XExtDisplayInfo *info = find_display(dpy);
420 xDMXAddScreenReply rep;
421 xDMXAddScreenReq *req;
422 int length;
423 int paddedLength;
424
425 if (!screen)
426 return False;
427
428 DMXCheckExtension(dpy, info, False);
429
430 LockDisplay(dpy);
431 GetReq(DMXAddScreen, req);
432 length = displayName ? strlen(displayName) : 0;
433 paddedLength = (length + 3) & ~3;
434 req->reqType = info->codes->major_opcode;
435 req->dmxReqType = X_DMXAddScreen;
436 req->displayNameLength = length;
437 req->physicalScreen = *screen;
438 req->valueMask = mask;
439 req->length += paddedLength/4;
440 req->length += _DMXDumpScreenAttributes(dpy, mask, attr);
441
442 if (length) {
443 char *buffer = Xcalloc(paddedLength, 1);
444 memcpy(buffer, displayName, length);
445 Data32(dpy, buffer, paddedLength);
446 Xfree(buffer);
447 }
448
449 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
450 UnlockDisplay(dpy);
451 SyncHandle();
452 return False;
453 }
454 if (screen) *screen = rep.physicalScreen;
455 UnlockDisplay(dpy);
456 SyncHandle();
457 return rep.status == Success ? True : False;
458 }
459
460 /** Remove a screen. */
DMXRemoveScreen(Display * dpy,int screen)461 Bool DMXRemoveScreen(Display *dpy, int screen)
462 {
463 XExtDisplayInfo *info = find_display(dpy);
464 xDMXRemoveScreenReply rep;
465 xDMXRemoveScreenReq *req;
466
467 DMXCheckExtension(dpy, info, False);
468
469 LockDisplay(dpy);
470 GetReq(DMXRemoveScreen, req);
471 req->reqType = info->codes->major_opcode;
472 req->dmxReqType = X_DMXRemoveScreen;
473 req->physicalScreen = screen;
474
475 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
476 UnlockDisplay(dpy);
477 SyncHandle();
478 return False;
479 }
480 UnlockDisplay(dpy);
481 SyncHandle();
482 return rep.status == Success ? True : False;
483 }
484
485 /** If the DMXGetWindowAttributes protocol request returns information
486 * about the specified \a window, the number of screens for which
487 * information is available will be returned in \a screen_count and
488 * information about the first \a available_count of those screens will
489 * be placed in \a inf. Because this call transports a great deal of
490 * information over the wire, please call #DMXGetScreenCount first, and
491 * make sure \a inf is that large.
492 *
493 * Note that if the specified \a window has not yet been mapped when
494 * #DMXGetWindowAttributes is called, then a subsequent XMapWindow call
495 * might be buffered in xlib while requests directly to the back-end X
496 * servers are processed. This race condition can be solved by calling
497 * #DMXSync before talking directly to the back-end X servers.
498 *
499 * Available in DMX Protocol Version 1.0, but not working correctly
500 * until DMX Protocol Version 1.4 */
DMXGetWindowAttributes(Display * dpy,Window window,int * screen_count,int available_count,DMXWindowAttributes * inf)501 Bool DMXGetWindowAttributes(Display *dpy, Window window,
502 int *screen_count, int available_count,
503 DMXWindowAttributes *inf)
504 {
505 XExtDisplayInfo *info = find_display(dpy);
506 xDMXGetWindowAttributesReply rep;
507 xDMXGetWindowAttributesReq *req;
508 unsigned long current;
509 CARD32 *screens; /* Must match protocol size */
510 CARD32 *windows; /* Must match protocol size */
511 XRectangle *pos; /* Must match protocol size */
512 XRectangle *vis; /* Must match protocol size */
513 Bool ret = False;
514
515 DMXCheckExtension(dpy, info, False);
516
517 LockDisplay(dpy);
518 GetReq(DMXGetWindowAttributes, req);
519 req->reqType = info->codes->major_opcode;
520 req->dmxReqType = X_DMXGetWindowAttributes;
521 req->window = window;
522 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
523 UnlockDisplay(dpy);
524 SyncHandle();
525 return False;
526 }
527
528 /*
529 * rep.screenCount is a CARD32 so could be as large as 2^32
530 * The X11 protocol limits the total screen size to 64k x 64k,
531 * and no screen can be smaller than a pixel. While technically
532 * that means we could theoretically reach 2^32 screens, and that's
533 * not even taking overlap into account, 64k seems far larger than
534 * any reasonable configuration, so we limit to that to prevent both
535 * integer overflow in the size calculations, and bad X server
536 * responses causing massive memory allocation.
537 */
538 if (rep.screenCount < 65536) {
539 screens = Xmalloc(rep.screenCount * sizeof(*screens));
540 windows = Xmalloc(rep.screenCount * sizeof(*windows));
541 pos = Xmalloc(rep.screenCount * sizeof(*pos));
542 vis = Xmalloc(rep.screenCount * sizeof(*vis));
543 } else {
544 screens = windows = NULL;
545 pos = vis = NULL;
546 }
547
548 if (!screens || !windows || !pos || !vis) {
549 _XEatDataWords(dpy, rep.length);
550 goto end;
551 }
552
553 _XRead(dpy, (char *)screens, rep.screenCount * sizeof(*screens));
554 _XRead(dpy, (char *)windows, rep.screenCount * sizeof(*windows));
555 _XRead(dpy, (char *)pos, rep.screenCount * sizeof(*pos));
556 _XRead(dpy, (char *)vis, rep.screenCount * sizeof(*vis));
557
558 *screen_count = rep.screenCount;
559 for (current = 0;
560 current < rep.screenCount && current < (unsigned)available_count;
561 current++, inf++) {
562 inf->screen = screens[current];
563 inf->window = windows[current];
564 inf->pos = pos[current];
565 inf->vis = vis[current];
566 }
567 ret = True;
568
569 end:
570 Xfree(vis);
571 Xfree(pos);
572 Xfree(windows);
573 Xfree(screens);
574
575 UnlockDisplay(dpy);
576 SyncHandle();
577 return ret;
578 }
579
580 /** If the DMXGetDesktopAttributes protocol request returns information
581 * correctly, the information will be placed in \a attr, and True will
582 * be returned. Otherwise, False will be returned.
583 *
584 * Available in DMX Protocol Version 2.0 */
DMXGetDesktopAttributes(Display * dpy,DMXDesktopAttributes * attr)585 Bool DMXGetDesktopAttributes(Display *dpy, DMXDesktopAttributes *attr)
586 {
587 XExtDisplayInfo *info = find_display(dpy);
588 xDMXGetDesktopAttributesReply rep;
589 xDMXGetDesktopAttributesReq *req;
590
591 DMXCheckExtension(dpy, info, False);
592
593 LockDisplay(dpy);
594 GetReq(DMXGetDesktopAttributes, req);
595 req->reqType = info->codes->major_opcode;
596 req->dmxReqType = X_DMXGetDesktopAttributes;
597 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
598 UnlockDisplay(dpy);
599 SyncHandle();
600 return False;
601 }
602 attr->width = rep.width;
603 attr->height = rep.height;
604 attr->shiftX = rep.shiftX;
605 attr->shiftY = rep.shiftY;
606
607 UnlockDisplay(dpy);
608 SyncHandle();
609 return True;
610 }
611
_DMXGetDesktopAttribute(int bit,DMXDesktopAttributes * attr)612 static CARD32 _DMXGetDesktopAttribute(int bit, DMXDesktopAttributes *attr)
613 {
614 switch (1 << bit) {
615 case DMXDesktopWidth: return attr->width;
616 case DMXDesktopHeight: return attr->height;
617 case DMXDesktopShiftX: return attr->shiftX;
618 case DMXDesktopShiftY: return attr->shiftY;
619 default: return 0;
620 }
621 }
622
_DMXDumpDesktopAttributes(Display * dpy,unsigned long mask,DMXDesktopAttributes * attr)623 static int _DMXDumpDesktopAttributes(Display *dpy,
624 unsigned long mask,
625 DMXDesktopAttributes *attr)
626 {
627 int i;
628 unsigned long value_list[32];
629 unsigned long *value = value_list;
630 int count = 0;
631
632 for (i = 0; i < 32; i++) {
633 if (mask & (1 << i)) {
634 *value++ = _DMXGetDesktopAttribute(i, attr);
635 ++count;
636 }
637 }
638 Data32(dpy, value_list, count * sizeof(CARD32));
639 return count;
640 }
641
642 /** Change the global bounding box and origin offset.
643 *
644 * Available in DMX Protocol Version 2.0 */
DMXChangeDesktopAttributes(Display * dpy,unsigned int mask,DMXDesktopAttributes * attr)645 int DMXChangeDesktopAttributes(Display *dpy,
646 unsigned int mask,
647 DMXDesktopAttributes *attr)
648 {
649 XExtDisplayInfo *info = find_display(dpy);
650 xDMXChangeDesktopAttributesReply rep;
651 xDMXChangeDesktopAttributesReq *req;
652
653 DMXCheckExtension(dpy, info, False);
654
655 LockDisplay(dpy);
656 GetReq(DMXChangeDesktopAttributes, req);
657 req->reqType = info->codes->major_opcode;
658 req->dmxReqType = X_DMXChangeDesktopAttributes;
659 req->valueMask = mask;
660 req->length +=_DMXDumpDesktopAttributes(dpy, mask, attr);
661
662 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
663 UnlockDisplay(dpy);
664 SyncHandle();
665 return DmxBadReply;
666 }
667 UnlockDisplay(dpy);
668 SyncHandle();
669 return rep.status;
670 }
671
672 /** If the DMXGetInputCount protocol request returns the input count,
673 * the value will be placed in \a input_count, and True will be
674 * returned. Otherwise, False will be returned.
675 *
676 * Available in DMX Protocol Version 1.1 */
DMXGetInputCount(Display * dpy,int * input_count)677 Bool DMXGetInputCount(Display *dpy, int *input_count)
678 {
679 XExtDisplayInfo *info = find_display(dpy);
680 xDMXGetInputCountReply rep;
681 xDMXGetInputCountReq *req;
682
683 DMXCheckExtension(dpy, info, False);
684
685 LockDisplay(dpy);
686 GetReq(DMXGetInputCount, req);
687 req->reqType = info->codes->major_opcode;
688 req->dmxReqType = X_DMXGetInputCount;
689 if (!_XReply(dpy, (xReply *)&rep, 0, xTrue)) {
690 UnlockDisplay(dpy);
691 SyncHandle();
692 return False;
693 }
694 *input_count = rep.inputCount;
695 UnlockDisplay(dpy);
696 SyncHandle();
697 return True;
698 }
699
700 /** If the DMXGetInputAttributes protocol request returns information
701 * about the input device with the specified \a id, information about
702 * the input device will be placed in \a inf, and True will be returned.
703 * Otherwise, False will be returned.
704 *
705 * Available in DMX Protocol Version 1.1 */
DMXGetInputAttributes(Display * dpy,int id,DMXInputAttributes * inf)706 Bool DMXGetInputAttributes(Display *dpy, int id, DMXInputAttributes *inf)
707 {
708 XExtDisplayInfo *info = find_display(dpy);
709 xDMXGetInputAttributesReply rep;
710 xDMXGetInputAttributesReq *req;
711 char *buffer;
712 Bool ret = False;
713
714 DMXCheckExtension(dpy, info, False);
715
716 LockDisplay(dpy);
717 GetReq(DMXGetInputAttributes, req);
718 req->reqType = info->codes->major_opcode;
719 req->dmxReqType = X_DMXGetInputAttributes;
720 req->deviceId = id;
721 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
722 UnlockDisplay(dpy);
723 SyncHandle();
724 return False;
725 }
726
727 if (rep.nameLength < 1024)
728 buffer = Xmalloc(rep.nameLength + 1 + 4 /* for pad */);
729 else
730 buffer = NULL; /* name length is unbelievable, reject */
731
732 if (buffer == NULL) {
733 _XEatDataWords(dpy, rep.length);
734 goto end;
735 }
736
737 switch (rep.inputType) {
738 case 0: inf->inputType = DMXLocalInputType; break;
739 case 1: inf->inputType = DMXConsoleInputType; break;
740 case 2: inf->inputType = DMXBackendInputType; break;
741 }
742
743 inf->physicalScreen = rep.physicalScreen;
744 inf->physicalId = rep.physicalId;
745 inf->isCore = rep.isCore;
746 inf->sendsCore = rep.sendsCore;
747 inf->detached = rep.detached;
748 _XReadPad(dpy, buffer, rep.nameLength);
749 buffer[rep.nameLength] = '\0';
750 inf->name = buffer;
751 ret = True;
752 end:
753 UnlockDisplay(dpy);
754 SyncHandle();
755 return ret;
756 }
757
758 /** Add input. */
DMXAddInput(Display * dpy,unsigned int mask,DMXInputAttributes * attr,int * id)759 Bool DMXAddInput(Display *dpy, unsigned int mask, DMXInputAttributes *attr,
760 int *id)
761 {
762 XExtDisplayInfo *info = find_display(dpy);
763 xDMXAddInputReply rep;
764 xDMXAddInputReq *req;
765 int length;
766 int paddedLength;
767
768 DMXCheckExtension(dpy, info, False);
769
770 LockDisplay(dpy);
771 GetReq(DMXAddInput, req);
772 length = attr->name ? strlen(attr->name) : 0;
773 paddedLength = (length + 3) & ~3;
774 req->reqType = info->codes->major_opcode;
775 req->dmxReqType = X_DMXAddInput;
776 req->displayNameLength = length;
777 req->valueMask = mask;
778 req->length += paddedLength/4;
779 req->length += _DMXDumpInputAttributes(dpy, mask, attr);
780
781 if (length) {
782 char *buffer = Xcalloc(paddedLength, 1);
783 memcpy(buffer, attr->name, paddedLength);
784 Data32(dpy, buffer, paddedLength);
785 Xfree(buffer);
786 }
787
788 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
789 UnlockDisplay(dpy);
790 SyncHandle();
791 return False;
792 }
793 if (id) *id = rep.physicalId;
794 UnlockDisplay(dpy);
795 SyncHandle();
796 return rep.status == Success ? True : False;
797 }
798
799 /** Add backend input (a helper function that calls #DMXAddInput). */
DMXAddBackendInput(Display * dpy,int screen,int sendsCore,int * newId)800 Bool DMXAddBackendInput(Display *dpy, int screen, int sendsCore, int *newId)
801 {
802 DMXInputAttributes attr;
803 unsigned int mask = (DMXInputType
804 | DMXInputPhysicalScreen
805 | DMXInputSendsCore);
806
807 attr.inputType = DMXBackendInputType;
808 attr.physicalScreen = screen;
809 attr.sendsCore = sendsCore;
810 attr.name = NULL;
811 return DMXAddInput(dpy, mask, &attr, newId);
812 }
813
814 /** Add console input (a helper function that calls #DMXAddInput). */
DMXAddConsoleInput(Display * dpy,const char * name,int sendsCore,int * newId)815 Bool DMXAddConsoleInput(Display *dpy, const char *name, int sendsCore,
816 int *newId)
817 {
818 DMXInputAttributes attr;
819 unsigned int mask = (DMXInputType
820 | DMXInputSendsCore);
821
822 attr.inputType = DMXConsoleInputType;
823 attr.physicalScreen = 0;
824 attr.sendsCore = sendsCore;
825 attr.name = name;
826 return DMXAddInput(dpy, mask, &attr, newId);
827 }
828
829 /** Remove an input. */
DMXRemoveInput(Display * dpy,int id)830 Bool DMXRemoveInput(Display *dpy, int id)
831 {
832 XExtDisplayInfo *info = find_display(dpy);
833 xDMXRemoveInputReply rep;
834 xDMXRemoveInputReq *req;
835
836 DMXCheckExtension(dpy, info, False);
837
838 LockDisplay(dpy);
839 GetReq(DMXRemoveInput, req);
840 req->reqType = info->codes->major_opcode;
841 req->dmxReqType = X_DMXRemoveInput;
842 req->physicalId = id;
843
844 if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
845 UnlockDisplay(dpy);
846 SyncHandle();
847 return False;
848 }
849 UnlockDisplay(dpy);
850 SyncHandle();
851 return rep.status == Success ? True : False;
852 }
853