]> diplodocus.org Git - xorg-xinput/blob - src/property.c
14e43085dce29e1dc23f90079e9df7f03ce9162d
[xorg-xinput] / src / property.c
1 /*
2 * Copyright © 2007 Peter Hutterer
3 * Copyright © 2009 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <X11/Xatom.h>
30 #include <X11/extensions/XIproto.h>
31
32 #include "xinput.h"
33
34 static Atom parse_atom(Display *dpy, char *name) {
35 Bool is_atom = True;
36 int i;
37
38 for (i = 0; name[i] != '\0'; i++) {
39 if (!isdigit(name[i])) {
40 is_atom = False;
41 break;
42 }
43 }
44
45 if (is_atom)
46 return atoi(name);
47 else
48 return XInternAtom(dpy, name, False);
49 }
50
51 static void
52 print_property(Display *dpy, XDevice* dev, Atom property)
53 {
54 Atom act_type;
55 char *name;
56 int act_format;
57 unsigned long nitems, bytes_after;
58 unsigned char *data, *ptr;
59 int j, done = False, size = 0;
60
61 name = XGetAtomName(dpy, property);
62 printf("\t%s (%ld):\t", name, property);
63
64 if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
65 AnyPropertyType, &act_type, &act_format,
66 &nitems, &bytes_after, &data) == Success)
67 {
68 Atom float_atom = XInternAtom(dpy, "FLOAT", True);
69
70 ptr = data;
71
72 if (nitems == 0)
73 printf("<no items>");
74
75 switch(act_format)
76 {
77 case 8: size = sizeof(char); break;
78 case 16: size = sizeof(short); break;
79 case 32: size = sizeof(long); break;
80 }
81
82 for (j = 0; j < nitems; j++)
83 {
84 switch(act_type)
85 {
86 case XA_INTEGER:
87 switch(act_format)
88 {
89 case 8:
90 printf("%d", *((char*)ptr));
91 break;
92 case 16:
93 printf("%d", *((short*)ptr));
94 break;
95 case 32:
96 printf("%ld", *((long*)ptr));
97 break;
98 }
99 break;
100 case XA_CARDINAL:
101 switch(act_format)
102 {
103 case 8:
104 printf("%u", *((unsigned char*)ptr));
105 break;
106 case 16:
107 printf("%u", *((unsigned short*)ptr));
108 break;
109 case 32:
110 printf("%lu", *((unsigned long*)ptr));
111 break;
112 }
113 break;
114 case XA_STRING:
115 if (act_format != 8)
116 {
117 printf("Unknown string format.\n");
118 done = True;
119 break;
120 }
121 printf("\"%s\"", ptr);
122 j += strlen((char*)ptr); /* The loop's j++ jumps over the
123 terminating 0 */
124 ptr += strlen((char*)ptr); /* ptr += size below jumps over
125 the terminating 0 */
126 break;
127 case XA_ATOM:
128 {
129 Atom a = *(Atom*)ptr;
130 printf("\"%s\" (%d)",
131 (a) ? XGetAtomName(dpy, a) : "None",
132 (int)a);
133 break;
134 }
135 default:
136 if (float_atom != None && act_type == float_atom)
137 {
138 printf("%f", *((float*)ptr));
139 break;
140 }
141
142 printf("\t... of unknown type '%s'\n",
143 XGetAtomName(dpy, act_type));
144 done = True;
145 break;
146 }
147
148 ptr += size;
149
150 if (done == True)
151 break;
152 if (j < nitems - 1)
153 printf(", ");
154 }
155 printf("\n");
156 XFree(data);
157 } else
158 printf("\tFetch failure\n");
159
160 }
161
162 static int
163 list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc)
164 {
165 XDeviceInfo *info;
166 XDevice *dev;
167 int i;
168 int nprops;
169 Atom *props;
170
171 if (argc == 0)
172 {
173 fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
174 return EXIT_FAILURE;
175 }
176
177 for (i = 0; i < argc; i++)
178 {
179 info = find_device_info(dpy, argv[i], False);
180 if (!info)
181 {
182 fprintf(stderr, "unable to find device '%s'\n", argv[i]);
183 continue;
184 }
185
186 dev = XOpenDevice(dpy, info->id);
187 if (!dev)
188 {
189 fprintf(stderr, "unable to open device '%s'\n", info->name);
190 continue;
191 }
192
193 props = XListDeviceProperties(dpy, dev, &nprops);
194 if (!nprops)
195 {
196 printf("Device '%s' does not report any properties.\n", info->name);
197 continue;
198 }
199
200 printf("Device '%s':\n", info->name);
201 while(nprops--)
202 {
203 print_property(dpy, dev, props[nprops]);
204 }
205
206 XFree(props);
207 XCloseDevice(dpy, dev);
208 }
209 return EXIT_SUCCESS;
210 }
211
212
213 int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
214 {
215 XDevice *dev;
216 XDeviceInfo *info;
217 XEvent ev;
218 XDevicePropertyNotifyEvent *dpev;
219 char *name;
220 int type_prop;
221 XEventClass cls_prop;
222
223 if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
224 return EXIT_FAILURE;
225
226 info = find_device_info(dpy, argv[0], False);
227 if (!info)
228 {
229 fprintf(stderr, "unable to find device '%s'\n", argv[0]);
230 return EXIT_FAILURE;
231 }
232
233 dev = XOpenDevice(dpy, info->id);
234 if (!dev)
235 {
236 fprintf(stderr, "unable to open device '%s'\n", info->name);
237 return EXIT_FAILURE;
238 }
239
240 DevicePropertyNotify(dev, type_prop, cls_prop);
241 XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
242
243 while(1)
244 {
245 XNextEvent(dpy, &ev);
246
247 dpev = (XDevicePropertyNotifyEvent*)&ev;
248 if (dpev->type != type_prop)
249 continue;
250
251 name = XGetAtomName(dpy, dpev->atom);
252 printf("Property '%s' changed.\n", name);
253 print_property(dpy, dev, dpev->atom);
254 }
255
256 XCloseDevice(dpy, dev);
257 }
258
259 static int
260 delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc)
261 {
262 XDevice *dev;
263 XDeviceInfo *info;
264 char *name;
265 Atom prop;
266
267 info = find_device_info(dpy, argv[0], False);
268 if (!info)
269 {
270 fprintf(stderr, "unable to find device '%s'\n", argv[0]);
271 return EXIT_FAILURE;
272 }
273
274 dev = XOpenDevice(dpy, info->id);
275 if (!dev)
276 {
277 fprintf(stderr, "unable to open device '%s'\n", info->name);
278 return EXIT_FAILURE;
279 }
280
281 name = argv[1];
282
283 prop = parse_atom(dpy, name);
284
285 XDeleteDeviceProperty(dpy, dev, prop);
286
287 XCloseDevice(dpy, dev);
288 return EXIT_SUCCESS;
289 }
290
291 static int
292 do_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
293 {
294 XDeviceInfo *info;
295 XDevice *dev;
296 Atom prop;
297 Atom old_type;
298 char *name;
299 int i;
300 Atom float_atom;
301 int old_format, nelements = 0;
302 unsigned long act_nitems, bytes_after;
303 char *endptr;
304 union {
305 unsigned char *c;
306 short *s;
307 long *l;
308 Atom *a;
309 } data;
310
311 if (argc < 3)
312 {
313 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
314 return EXIT_FAILURE;
315 }
316
317 info = find_device_info(dpy, argv[0], False);
318 if (!info)
319 {
320 fprintf(stderr, "unable to find device '%s'\n", argv[0]);
321 return EXIT_FAILURE;
322 }
323
324 dev = XOpenDevice(dpy, info->id);
325 if (!dev)
326 {
327 fprintf(stderr, "unable to open device '%s'\n", argv[0]);
328 return EXIT_FAILURE;
329 }
330
331 name = argv[1];
332
333 prop = parse_atom(dpy, name);
334
335 if (prop == None) {
336 fprintf(stderr, "invalid property '%s'\n", name);
337 return EXIT_FAILURE;
338 }
339
340 float_atom = XInternAtom(dpy, "FLOAT", False);
341
342 nelements = argc - 2;
343 if (type == None || format == 0) {
344 if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType,
345 &old_type, &old_format, &act_nitems,
346 &bytes_after, &data.c) != Success) {
347 fprintf(stderr, "failed to get property type and format for '%s'\n",
348 name);
349 return EXIT_FAILURE;
350 } else {
351 if (type == None)
352 type = old_type;
353 if (format == 0)
354 format = old_format;
355 }
356
357 XFree(data.c);
358 }
359
360 if (type == None) {
361 fprintf(stderr, "property '%s' doesn't exist, you need to specify "
362 "its type and format\n", name);
363 return EXIT_FAILURE;
364 }
365
366 data.c = calloc(nelements, sizeof(long));
367
368 for (i = 0; i < nelements; i++)
369 {
370 if (type == XA_INTEGER || type == XA_CARDINAL) {
371 switch (format)
372 {
373 case 8:
374 data.c[i] = atoi(argv[2 + i]);
375 break;
376 case 16:
377 data.s[i] = atoi(argv[2 + i]);
378 break;
379 case 32:
380 data.l[i] = atoi(argv[2 + i]);
381 break;
382 default:
383 fprintf(stderr, "unexpected size for property '%s'", name);
384 return EXIT_FAILURE;
385 }
386 } else if (type == float_atom) {
387 if (format != 32) {
388 fprintf(stderr, "unexpected format %d for property '%s'\n",
389 format, name);
390 return EXIT_FAILURE;
391 }
392 *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
393 if (endptr == argv[2 + i]) {
394 fprintf(stderr, "argument '%s' could not be parsed\n", argv[2 + i]);
395 return EXIT_FAILURE;
396 }
397 } else if (type == XA_ATOM) {
398 if (format != 32) {
399 fprintf(stderr, "unexpected format %d for property '%s'\n",
400 format, name);
401 return EXIT_FAILURE;
402 }
403 data.a[i] = parse_atom(dpy, argv[2 + i]);
404 } else {
405 fprintf(stderr, "unexpected type for property '%s'\n", name);
406 return EXIT_FAILURE;
407 }
408 }
409
410 XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace,
411 data.c, nelements);
412 free(data.c);
413 XCloseDevice(dpy, dev);
414 return EXIT_SUCCESS;
415 }
416
417 #if HAVE_XI2
418 static void
419 print_property_xi2(Display *dpy, int deviceid, Atom property)
420 {
421 Atom act_type;
422 char *name;
423 int act_format;
424 unsigned long nitems, bytes_after;
425 unsigned char *data, *ptr;
426 int j, done = False;
427
428 name = XGetAtomName(dpy, property);
429 printf("\t%s (%ld):\t", name, property);
430
431 if (XIGetProperty(dpy, deviceid, property, 0, 1000, False,
432 AnyPropertyType, &act_type, &act_format,
433 &nitems, &bytes_after, &data) == Success)
434 {
435 Atom float_atom = XInternAtom(dpy, "FLOAT", True);
436
437 ptr = data;
438
439 if (nitems == 0)
440 printf("<no items>");
441
442 for (j = 0; j < nitems; j++)
443 {
444 switch(act_type)
445 {
446 case XA_INTEGER:
447 switch(act_format)
448 {
449 case 8:
450 printf("%d", *((int8_t*)ptr));
451 break;
452 case 16:
453 printf("%d", *((int16_t*)ptr));
454 break;
455 case 32:
456 printf("%d", *((int32_t*)ptr));
457 break;
458 }
459 break;
460 case XA_CARDINAL:
461 switch(act_format)
462 {
463 case 8:
464 printf("%u", *((uint8_t*)ptr));
465 break;
466 case 16:
467 printf("%u", *((uint16_t*)ptr));
468 break;
469 case 32:
470 printf("%u", *((uint32_t*)ptr));
471 break;
472 }
473 break;
474 case XA_STRING:
475 if (act_format != 8)
476 {
477 printf("Unknown string format.\n");
478 done = True;
479 break;
480 }
481 printf("\"%s\"", ptr);
482 j += strlen((char*)ptr); /* The loop's j++ jumps over the
483 terminating 0 */
484 ptr += strlen((char*)ptr); /* ptr += size below jumps over
485 the terminating 0 */
486 break;
487 case XA_ATOM:
488 {
489 Atom a = *(uint32_t*)ptr;
490 printf("\"%s\" (%ld)",
491 (a) ? XGetAtomName(dpy, a) : "None",
492 a);
493 break;
494 }
495 break;
496 default:
497 if (float_atom != None && act_type == float_atom)
498 {
499 printf("%f", *((float*)ptr));
500 break;
501 }
502
503 printf("\t... of unknown type %s\n",
504 XGetAtomName(dpy, act_type));
505 done = True;
506 break;
507 }
508
509 ptr += act_format/8;
510
511 if (done == True)
512 break;
513 if (j < nitems - 1)
514 printf(", ");
515 }
516 printf("\n");
517 XFree(data);
518 } else
519 printf("\tFetch failure\n");
520
521 }
522
523 static int
524 list_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc)
525 {
526 XIDeviceInfo *info;
527 int i;
528 int nprops;
529 Atom *props;
530
531 if (argc == 0)
532 {
533 fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
534 return EXIT_FAILURE;
535 }
536
537 for (i = 0; i < argc; i++)
538 {
539 info = xi2_find_device_info(dpy, argv[i]);
540 if (!info)
541 {
542 fprintf(stderr, "unable to find device %s\n", argv[i]);
543 continue;
544 }
545
546 props = XIListProperties(dpy, info->deviceid, &nprops);
547 if (!nprops)
548 {
549 printf("Device '%s' does not report any properties.\n", info->name);
550 continue;
551 }
552
553 printf("Device '%s':\n", info->name);
554 while(nprops--)
555 {
556 print_property_xi2(dpy, info->deviceid, props[nprops]);
557 }
558
559 XFree(props);
560 }
561 return EXIT_SUCCESS;
562 }
563
564 static int
565 delete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc)
566 {
567 XIDeviceInfo *info;
568 char *name;
569 Atom prop;
570
571 info = xi2_find_device_info(dpy, argv[0]);
572 if (!info)
573 {
574 fprintf(stderr, "unable to find device %s\n", argv[0]);
575 return EXIT_FAILURE;
576 }
577
578 name = argv[1];
579
580 prop = parse_atom(dpy, name);
581
582 XIDeleteProperty(dpy, info->deviceid, prop);
583
584 return EXIT_SUCCESS;
585 }
586
587 static int
588 do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
589 {
590 XIDeviceInfo *info;
591 Atom prop;
592 Atom old_type;
593 char *name;
594 int i;
595 Atom float_atom;
596 int old_format, nelements = 0;
597 unsigned long act_nitems, bytes_after;
598 char *endptr;
599 union {
600 unsigned char *c;
601 int16_t *s;
602 int32_t *l;
603 } data;
604
605 if (argc < 3)
606 {
607 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
608 return EXIT_FAILURE;
609 }
610
611 info = xi2_find_device_info(dpy, argv[0]);
612 if (!info)
613 {
614 fprintf(stderr, "unable to find device %s\n", argv[0]);
615 return EXIT_FAILURE;
616 }
617
618 name = argv[1];
619
620 prop = parse_atom(dpy, name);
621
622 if (prop == None) {
623 fprintf(stderr, "invalid property '%s'\n", name);
624 return EXIT_FAILURE;
625 }
626
627 float_atom = XInternAtom(dpy, "FLOAT", False);
628
629 nelements = argc - 2;
630 if (type == None || format == 0) {
631 if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False,
632 AnyPropertyType, &old_type, &old_format, &act_nitems,
633 &bytes_after, &data.c) != Success) {
634 fprintf(stderr, "failed to get property type and format for '%s'\n",
635 name);
636 return EXIT_FAILURE;
637 } else {
638 if (type == None)
639 type = old_type;
640 if (format == 0)
641 format = old_format;
642 }
643
644 XFree(data.c);
645 }
646
647 if (type == None) {
648 fprintf(stderr, "property '%s' doesn't exist, you need to specify "
649 "its type and format\n", name);
650 return EXIT_FAILURE;
651 }
652
653 data.c = calloc(nelements, sizeof(int32_t));
654
655 for (i = 0; i < nelements; i++)
656 {
657 if (type == XA_INTEGER || type == XA_CARDINAL) {
658 switch (format)
659 {
660 case 8:
661 data.c[i] = atoi(argv[2 + i]);
662 break;
663 case 16:
664 data.s[i] = atoi(argv[2 + i]);
665 break;
666 case 32:
667 data.l[i] = atoi(argv[2 + i]);
668 break;
669 default:
670 fprintf(stderr, "unexpected size for property %s", name);
671 return EXIT_FAILURE;
672 }
673 } else if (type == float_atom) {
674 if (format != 32) {
675 fprintf(stderr, "unexpected format %d for property '%s'\n",
676 format, name);
677 return EXIT_FAILURE;
678 }
679 *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
680 if (endptr == argv[2 + i]) {
681 fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
682 return EXIT_FAILURE;
683 }
684 } else if (type == XA_ATOM) {
685 if (format != 32) {
686 fprintf(stderr, "unexpected format %d for property '%s'\n",
687 format, name);
688 return EXIT_FAILURE;
689 }
690 data.l[i] = parse_atom(dpy, argv[2 + i]);
691 } else {
692 fprintf(stderr, "unexpected type for property '%s'\n", name);
693 return EXIT_FAILURE;
694 }
695 }
696
697 XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace,
698 data.c, nelements);
699 free(data.c);
700 return EXIT_SUCCESS;
701 }
702 #endif
703
704 int list_props(Display *display, int argc, char *argv[], char *name,
705 char *desc)
706 {
707 #ifdef HAVE_XI2
708 if (xinput_version(display) == XI_2_Major)
709 return list_props_xi2(display, argc, argv, name, desc);
710 #endif
711 return list_props_xi1(display, argc, argv, name, desc);
712
713 }
714
715 int delete_prop(Display *display, int argc, char *argv[], char *name,
716 char *desc)
717 {
718 #ifdef HAVE_XI2
719 if (xinput_version(display) == XI_2_Major)
720 return delete_prop_xi2(display, argc, argv, name, desc);
721 #endif
722 return delete_prop_xi1(display, argc, argv, name, desc);
723
724 }
725
726 static int
727 do_set_prop(Display *display, Atom type, int format, int argc, char *argv[], char *name, char *desc)
728 {
729 #ifdef HAVE_XI2
730 if (xinput_version(display) == XI_2_Major)
731 return do_set_prop_xi2(display, type, format, argc, argv, name, desc);
732 #endif
733 return do_set_prop_xi1(display, type, format, argc, argv, name, desc);
734 }
735
736 int
737 set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
738 {
739 return do_set_prop(dpy, XA_ATOM, 32, argc, argv, n, desc);
740 }
741
742 int
743 set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
744 {
745 int i;
746 int format;
747
748 if (argc < 3)
749 {
750 fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
751 return EXIT_FAILURE;
752 }
753
754 format = atoi(argv[2]);
755 if (format != 8 && format != 16 && format != 32)
756 {
757 fprintf(stderr, "Invalid format %d\n", format);
758 return EXIT_FAILURE;
759 }
760
761 for (i = 3; i < argc; i++)
762 argv[i - 1] = argv[i];
763
764 return do_set_prop(dpy, XA_INTEGER, format, argc - 1, argv, n, desc);
765 }
766
767 int
768 set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
769 {
770 Atom float_atom = XInternAtom(dpy, "FLOAT", False);
771
772 if (sizeof(float) != 4)
773 {
774 fprintf(stderr, "sane FP required\n");
775 return EXIT_FAILURE;
776 }
777
778 return do_set_prop(dpy, float_atom, 32, argc, argv, n, desc);
779 }
780
781 int set_prop(Display *display, int argc, char *argv[], char *name,
782 char *desc)
783 {
784 Atom type = None;
785 int format = 0;
786 int i = 0, j;
787
788 while (i < argc) {
789 char *option = strchr(argv[i], '=');
790 /* skip non-option arguments */
791 if (strncmp(argv[i], "--", 2) || !option) {
792 i++;
793 continue;
794 }
795
796 if (!strncmp(argv[i], "--type=", strlen("--type="))) {
797 if (!strcmp(option + 1, "int")) {
798 type = XA_INTEGER;
799 } else if (!strcmp(option + 1, "float")) {
800 type = XInternAtom(display, "FLOAT", False);
801 format = 32;
802 } else if (!strcmp(option + 1, "atom")) {
803 type = XA_ATOM;
804 format = 32;
805 } else {
806 fprintf(stderr, "unknown property type %s\n", option + 1);
807 return EXIT_FAILURE;
808 }
809 } else if (!strncmp(argv[i], "--format=", strlen("--format="))) {
810 format = atoi(option + 1);
811 if (format != 8 && format != 16 && format != 32) {
812 fprintf(stderr, "invalid property format '%s'\n", option + 1);
813 return EXIT_FAILURE;
814 }
815 } else {
816 fprintf(stderr, "invalid option '%s'\n", argv[i]);
817 return EXIT_FAILURE;
818 }
819
820 for (j = i; j + 1 < argc; j++)
821 argv[j] = argv[j + 1];
822 argc--;
823 }
824
825 return do_set_prop(display, type, format, argc, argv, name, desc);
826 }
827
828 int disable(Display *display, int argc, char *argv[], char *name, char *desc)
829 {
830 char *new_argv[3] = { argv[0], "Device Enabled", "0" };
831 return set_prop(display, 3, new_argv, name, desc);
832 }
833
834 int enable(Display *display, int argc, char *argv[], char *name, char *desc)
835 {
836 char *new_argv[3] = { argv[0], "Device Enabled", "1" };
837 return set_prop(display, 3, new_argv, name, desc);
838 }