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