property.c revision 0309d3b3
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
34static 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
51static void
52print_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
162static int
163list_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
213int 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
259static int
260delete_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
291static int
292do_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
418static void
419print_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
523static int
524list_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
564static int
565delete_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
587static int
588do_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
704int 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
715int 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
726static int
727do_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
736int
737set_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
742int
743set_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
767int
768set_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
781int 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
828int 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
834int 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}
839