Edit

IABSD.fr/xenocara/app/xinput/src/property.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2012-06-11 19:26:23
    Hash : 4b78f29c
    Message : Update to xinput 1.6.0

  • app/xinput/src/property.c
  • /*
     * Copyright © 2007 Peter Hutterer
     * Copyright © 2009 Red Hat, Inc.
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice (including the next
     * paragraph) shall be included in all copies or substantial portions of the
     * Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     * DEALINGS IN THE SOFTWARE.
     */
    
    #include <ctype.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <X11/Xatom.h>
    #include <X11/extensions/XIproto.h>
    
    #include "xinput.h"
    
    static Atom parse_atom(Display *dpy, char *name) {
        Bool is_atom = True;
        int i;
    
        for (i = 0; name[i] != '\0'; i++) {
            if (!isdigit(name[i])) {
                is_atom = False;
                break;
            }
        }
    
        if (is_atom)
            return atoi(name);
        else
            return XInternAtom(dpy, name, False);
    }
    
    static void
    print_property(Display *dpy, XDevice* dev, Atom property)
    {
        Atom                act_type;
        char                *name;
        int                 act_format;
        unsigned long       nitems, bytes_after;
        unsigned char       *data, *ptr;
        int                 j, done = False, size = 0;
    
        name = XGetAtomName(dpy, property);
        printf("\t%s (%ld):\t", name, property);
    
        if (XGetDeviceProperty(dpy, dev, property, 0, 1000, False,
                               AnyPropertyType, &act_type, &act_format,
                               &nitems, &bytes_after, &data) == Success)
        {
            Atom float_atom = XInternAtom(dpy, "FLOAT", True);
    
            ptr = data;
    
            if (nitems == 0)
                printf("<no items>");
    
            switch(act_format)
            {
                case 8: size = sizeof(char); break;
                case 16: size = sizeof(short); break;
                case 32: size = sizeof(long); break;
            }
    
            for (j = 0; j < nitems; j++)
            {
                switch(act_type)
                {
                    case XA_INTEGER:
                        switch(act_format)
                        {
                            case 8:
                                printf("%d", *((char*)ptr));
                                break;
                            case 16:
                                printf("%d", *((short*)ptr));
                                break;
                            case 32:
                                printf("%ld", *((long*)ptr));
                                break;
                        }
                        break;
                    case XA_CARDINAL:
                        switch(act_format)
                        {
                            case 8:
                                printf("%u", *((unsigned char*)ptr));
                                break;
                            case 16:
                                printf("%u", *((unsigned short*)ptr));
                                break;
                            case 32:
                                printf("%lu", *((unsigned long*)ptr));
                                break;
                        }
                        break;
                    case XA_STRING:
                        if (act_format != 8)
                        {
                            printf("Unknown string format.\n");
                            done = True;
                            break;
                        }
                        printf("\"%s\"", ptr);
                        j += strlen((char*)ptr); /* The loop's j++ jumps over the
                                                    terminating 0 */
                        ptr += strlen((char*)ptr); /* ptr += size below jumps over
                                                      the terminating 0 */
                        break;
                    case XA_ATOM:
                        {
                            Atom a = *(Atom*)ptr;
                            printf("\"%s\" (%d)",
                                    (a) ? XGetAtomName(dpy, a) : "None",
                                    (int)a);
                            break;
                        }
                    default:
                        if (float_atom != None && act_type == float_atom)
                        {
                            printf("%f", *((float*)ptr));
                            break;
                        }
    
                        printf("\t... of unknown type '%s'\n",
                                XGetAtomName(dpy, act_type));
                        done = True;
                        break;
                }
    
                ptr += size;
    
                if (done == True)
                    break;
                if (j < nitems - 1)
                    printf(", ");
            }
            printf("\n");
            XFree(data);
        } else
            printf("\tFetch failure\n");
    
    }
    
    static int
    list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc)
    {
        XDeviceInfo *info;
        XDevice     *dev;
        int          i;
        int         nprops;
        Atom        *props;
    
        if (argc == 0)
        {
            fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
            return EXIT_FAILURE;
        }
    
        for (i = 0; i < argc; i++)
        {
            info = find_device_info(dpy, argv[i], False);
            if (!info)
            {
                fprintf(stderr, "unable to find device '%s'\n", argv[i]);
                continue;
            }
    
            dev = XOpenDevice(dpy, info->id);
            if (!dev)
            {
                fprintf(stderr, "unable to open device '%s'\n", info->name);
                continue;
            }
    
            props = XListDeviceProperties(dpy, dev, &nprops);
            if (!nprops)
            {
                printf("Device '%s' does not report any properties.\n", info->name);
                continue;
            }
    
            printf("Device '%s':\n", info->name);
            while(nprops--)
            {
                print_property(dpy, dev, props[nprops]);
            }
    
            XFree(props);
            XCloseDevice(dpy, dev);
        }
        return EXIT_SUCCESS;
    }
    
    
    int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        XDevice     *dev;
        XDeviceInfo *info;
        XEvent      ev;
        XDevicePropertyNotifyEvent *dpev;
        char        *name;
        int         type_prop;
        XEventClass cls_prop;
    
        if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS)
            return EXIT_FAILURE;
    
        info = find_device_info(dpy, argv[0], False);
        if (!info)
        {
            fprintf(stderr, "unable to find device '%s'\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        dev = XOpenDevice(dpy, info->id);
        if (!dev)
        {
            fprintf(stderr, "unable to open device '%s'\n", info->name);
            return EXIT_FAILURE;
        }
    
        DevicePropertyNotify(dev, type_prop, cls_prop);
        XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1);
    
        while(1)
        {
            XNextEvent(dpy, &ev);
    
            dpev = (XDevicePropertyNotifyEvent*)&ev;
            if (dpev->type != type_prop)
                continue;
    
            name = XGetAtomName(dpy, dpev->atom);
            printf("Property '%s' changed.\n", name);
            print_property(dpy, dev, dpev->atom);
        }
    
        XCloseDevice(dpy, dev);
    }
    
    static int
    delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        XDevice     *dev;
        XDeviceInfo *info;
        char        *name;
        Atom        prop;
    
        info = find_device_info(dpy, argv[0], False);
        if (!info)
        {
            fprintf(stderr, "unable to find device '%s'\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        dev = XOpenDevice(dpy, info->id);
        if (!dev)
        {
            fprintf(stderr, "unable to open device '%s'\n", info->name);
            return EXIT_FAILURE;
        }
    
        name = argv[1];
    
        prop = parse_atom(dpy, name);
    
        XDeleteDeviceProperty(dpy, dev, prop);
    
        XCloseDevice(dpy, dev);
        return EXIT_SUCCESS;
    }
    
    static int
    do_set_prop_xi1(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
    {
        XDeviceInfo  *info;
        XDevice      *dev;
        Atom          prop;
        Atom          old_type;
        char         *name;
        int           i;
        Atom          float_atom;
        int           old_format, nelements = 0;
        unsigned long act_nitems, bytes_after;
        char         *endptr;
        union {
            unsigned char *c;
            short *s;
            long *l;
            Atom *a;
        } data;
    
        if (argc < 3)
        {
            fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
            return EXIT_FAILURE;
        }
    
        info = find_device_info(dpy, argv[0], False);
        if (!info)
        {
            fprintf(stderr, "unable to find device '%s'\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        dev = XOpenDevice(dpy, info->id);
        if (!dev)
        {
            fprintf(stderr, "unable to open device '%s'\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        name = argv[1];
    
        prop = parse_atom(dpy, name);
    
        if (prop == None) {
            fprintf(stderr, "invalid property '%s'\n", name);
            return EXIT_FAILURE;
        }
    
        float_atom = XInternAtom(dpy, "FLOAT", False);
    
        nelements = argc - 2;
        if (type == None || format == 0) {
            if (XGetDeviceProperty(dpy, dev, prop, 0, 0, False, AnyPropertyType,
                                   &old_type, &old_format, &act_nitems,
                                   &bytes_after, &data.c) != Success) {
                fprintf(stderr, "failed to get property type and format for '%s'\n",
                        name);
                return EXIT_FAILURE;
            } else {
                if (type == None)
                    type = old_type;
                if (format == 0)
                    format = old_format;
            }
    
            XFree(data.c);
        }
    
        if (type == None) {
            fprintf(stderr, "property '%s' doesn't exist, you need to specify "
                    "its type and format\n", name);
            return EXIT_FAILURE;
        }
    
        data.c = calloc(nelements, sizeof(long));
    
        for (i = 0; i < nelements; i++)
        {
            if (type == XA_INTEGER || type == XA_CARDINAL) {
                switch (format)
                {
                    case 8:
                        data.c[i] = atoi(argv[2 + i]);
                        break;
                    case 16:
                        data.s[i] = atoi(argv[2 + i]);
                        break;
                    case 32:
                        data.l[i] = atoi(argv[2 + i]);
                        break;
                    default:
                        fprintf(stderr, "unexpected size for property '%s'", name);
                        return EXIT_FAILURE;
                }
            } else if (type == float_atom) {
                if (format != 32) {
                    fprintf(stderr, "unexpected format %d for property '%s'\n",
                            format, name);
                    return EXIT_FAILURE;
                }
                *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
                if (endptr == argv[2 + i]) {
                    fprintf(stderr, "argument '%s' could not be parsed\n", argv[2 + i]);
                    return EXIT_FAILURE;
                }
            } else if (type == XA_ATOM) {
                if (format != 32) {
                    fprintf(stderr, "unexpected format %d for property '%s'\n",
                            format, name);
                    return EXIT_FAILURE;
                }
                data.a[i] = parse_atom(dpy, argv[2 + i]);
            } else {
                fprintf(stderr, "unexpected type for property '%s'\n", name);
                return EXIT_FAILURE;
            }
        }
    
        XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace,
                              data.c, nelements);
        free(data.c);
        XCloseDevice(dpy, dev);
        return EXIT_SUCCESS;
    }
    
    #if HAVE_XI2
    static void
    print_property_xi2(Display *dpy, int deviceid, Atom property)
    {
        Atom                act_type;
        char                *name;
        int                 act_format;
        unsigned long       nitems, bytes_after;
        unsigned char       *data, *ptr;
        int                 j, done = False;
    
        name = XGetAtomName(dpy, property);
        printf("\t%s (%ld):\t", name, property);
    
        if (XIGetProperty(dpy, deviceid, property, 0, 1000, False,
                               AnyPropertyType, &act_type, &act_format,
                               &nitems, &bytes_after, &data) == Success)
        {
            Atom float_atom = XInternAtom(dpy, "FLOAT", True);
    
            ptr = data;
    
            if (nitems == 0)
                printf("<no items>");
    
            for (j = 0; j < nitems; j++)
            {
                switch(act_type)
                {
                    case XA_INTEGER:
                        switch(act_format)
                        {
                            case 8:
                                printf("%d", *((int8_t*)ptr));
                                break;
                            case 16:
                                printf("%d", *((int16_t*)ptr));
                                break;
                            case 32:
                                printf("%d", *((int32_t*)ptr));
                                break;
                        }
                        break;
                    case XA_CARDINAL:
                        switch(act_format)
                        {
                            case 8:
                                printf("%u", *((uint8_t*)ptr));
                                break;
                            case 16:
                                printf("%u", *((uint16_t*)ptr));
                                break;
                            case 32:
                                printf("%u", *((uint32_t*)ptr));
                                break;
                        }
                        break;
                    case XA_STRING:
                        if (act_format != 8)
                        {
                            printf("Unknown string format.\n");
                            done = True;
                            break;
                        }
                        printf("\"%s\"", ptr);
                        j += strlen((char*)ptr); /* The loop's j++ jumps over the
                                                    terminating 0 */
                        ptr += strlen((char*)ptr); /* ptr += size below jumps over
                                                      the terminating 0 */
                        break;
                    case XA_ATOM:
                        {
                            Atom a = *(uint32_t*)ptr;
                            printf("\"%s\" (%ld)",
                                    (a) ? XGetAtomName(dpy, a) : "None",
                                    a);
                            break;
                        }
                        break;
                    default:
                        if (float_atom != None && act_type == float_atom)
                        {
                            printf("%f", *((float*)ptr));
                            break;
                        }
    
                        printf("\t... of unknown type %s\n",
                                XGetAtomName(dpy, act_type));
                        done = True;
                        break;
                }
    
                ptr += act_format/8;
    
                if (done == True)
                    break;
                if (j < nitems - 1)
                    printf(", ");
            }
            printf("\n");
            XFree(data);
        } else
            printf("\tFetch failure\n");
    
    }
    
    static int
    list_props_xi2(Display *dpy, int argc, char** argv, char* name, char *desc)
    {
        XIDeviceInfo *info;
        int         i;
        int         nprops;
        Atom        *props;
    
        if (argc == 0)
        {
            fprintf(stderr, "Usage: xinput %s %s\n", name, desc);
            return EXIT_FAILURE;
        }
    
        for (i = 0; i < argc; i++)
        {
            info = xi2_find_device_info(dpy, argv[i]);
            if (!info)
            {
                fprintf(stderr, "unable to find device %s\n", argv[i]);
                continue;
            }
    
            props = XIListProperties(dpy, info->deviceid, &nprops);
            if (!nprops)
            {
                printf("Device '%s' does not report any properties.\n", info->name);
                continue;
            }
    
            printf("Device '%s':\n", info->name);
            while(nprops--)
            {
                print_property_xi2(dpy, info->deviceid, props[nprops]);
            }
    
            XFree(props);
        }
        return EXIT_SUCCESS;
    }
    
    static int
    delete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        XIDeviceInfo *info;
        char        *name;
        Atom        prop;
    
        info = xi2_find_device_info(dpy, argv[0]);
        if (!info)
        {
            fprintf(stderr, "unable to find device %s\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        name = argv[1];
    
        prop = parse_atom(dpy, name);
    
        XIDeleteProperty(dpy, info->deviceid, prop);
    
        return EXIT_SUCCESS;
    }
    
    static int
    do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
    {
        XIDeviceInfo *info;
        Atom          prop;
        Atom          old_type;
        char         *name;
        int           i;
        Atom          float_atom;
        int           old_format, nelements = 0;
        unsigned long act_nitems, bytes_after;
        char         *endptr;
        union {
            unsigned char *c;
            int16_t *s;
            int32_t *l;
        } data;
    
        if (argc < 3)
        {
            fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
            return EXIT_FAILURE;
        }
    
        info = xi2_find_device_info(dpy, argv[0]);
        if (!info)
        {
            fprintf(stderr, "unable to find device %s\n", argv[0]);
            return EXIT_FAILURE;
        }
    
        name = argv[1];
    
        prop = parse_atom(dpy, name);
    
        if (prop == None) {
            fprintf(stderr, "invalid property '%s'\n", name);
            return EXIT_FAILURE;
        }
    
        float_atom = XInternAtom(dpy, "FLOAT", False);
    
        nelements = argc - 2;
        if (type == None || format == 0) {
            if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False,
                              AnyPropertyType, &old_type, &old_format, &act_nitems,
                              &bytes_after, &data.c) != Success) {
                fprintf(stderr, "failed to get property type and format for '%s'\n",
                        name);
                return EXIT_FAILURE;
            } else {
                if (type == None)
                    type = old_type;
                if (format == 0)
                    format = old_format;
            }
    
            XFree(data.c);
        }
    
        if (type == None) {
            fprintf(stderr, "property '%s' doesn't exist, you need to specify "
                    "its type and format\n", name);
            return EXIT_FAILURE;
        }
    
        data.c = calloc(nelements, sizeof(int32_t));
    
        for (i = 0; i < nelements; i++)
        {
            if (type == XA_INTEGER || type == XA_CARDINAL) {
                switch (format)
                {
                    case 8:
                        data.c[i] = atoi(argv[2 + i]);
                        break;
                    case 16:
                        data.s[i] = atoi(argv[2 + i]);
                        break;
                    case 32:
                        data.l[i] = atoi(argv[2 + i]);
                        break;
                    default:
                        fprintf(stderr, "unexpected size for property %s", name);
                        return EXIT_FAILURE;
                }
            } else if (type == float_atom) {
                if (format != 32) {
                    fprintf(stderr, "unexpected format %d for property '%s'\n",
                            format, name);
                    return EXIT_FAILURE;
                }
                *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
                if (endptr == argv[2 + i]) {
                    fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
                    return EXIT_FAILURE;
                }
            } else if (type == XA_ATOM) {
                if (format != 32) {
                    fprintf(stderr, "unexpected format %d for property '%s'\n",
                            format, name);
                    return EXIT_FAILURE;
                }
                data.l[i] = parse_atom(dpy, argv[2 + i]);
            } else {
                fprintf(stderr, "unexpected type for property '%s'\n", name);
                return EXIT_FAILURE;
            }
        }
    
        XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace,
                              data.c, nelements);
        free(data.c);
        return EXIT_SUCCESS;
    }
    #endif
    
    int list_props(Display *display, int argc, char *argv[], char *name,
                   char *desc)
    {
    #ifdef HAVE_XI2
        if (xinput_version(display) == XI_2_Major)
            return list_props_xi2(display, argc, argv, name, desc);
    #endif
        return list_props_xi1(display, argc, argv, name, desc);
    
    }
    
    int delete_prop(Display *display, int argc, char *argv[], char *name,
                    char *desc)
    {
    #ifdef HAVE_XI2
        if (xinput_version(display) == XI_2_Major)
            return delete_prop_xi2(display, argc, argv, name, desc);
    #endif
        return delete_prop_xi1(display, argc, argv, name, desc);
    
    }
    
    static int
    do_set_prop(Display *display, Atom type, int format, int argc, char *argv[], char *name, char *desc)
    {
    #ifdef HAVE_XI2
        if (xinput_version(display) == XI_2_Major)
            return do_set_prop_xi2(display, type, format, argc, argv, name, desc);
    #endif
        return do_set_prop_xi1(display, type, format, argc, argv, name, desc);
    }
    
    int
    set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        return do_set_prop(dpy, XA_ATOM, 32, argc, argv, n, desc);
    }
    
    int
    set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        int          i;
        int          format;
    
        if (argc < 3)
        {
            fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
            return EXIT_FAILURE;
        }
    
        format    = atoi(argv[2]);
        if (format != 8 && format != 16 && format != 32)
        {
            fprintf(stderr, "Invalid format %d\n", format);
            return EXIT_FAILURE;
        }
    
        for (i = 3; i < argc; i++)
            argv[i - 1] = argv[i];
    
        return do_set_prop(dpy, XA_INTEGER, format, argc - 1, argv, n, desc);
    }
    
    int
    set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
    {
        Atom float_atom = XInternAtom(dpy, "FLOAT", False);
    
        if (sizeof(float) != 4)
        {
    	fprintf(stderr, "sane FP required\n");
    	return EXIT_FAILURE;
        }
    
        return do_set_prop(dpy, float_atom, 32, argc, argv, n, desc);
    }
    
    int set_prop(Display *display, int argc, char *argv[], char *name,
                 char *desc)
    {
        Atom type = None;
        int format = 0;
        int i = 0, j;
    
        while (i < argc) {
            char *option = strchr(argv[i], '=');
            /* skip non-option arguments */
            if (strncmp(argv[i], "--", 2) || !option) {
                i++;
                continue;
            }
    
            if (!strncmp(argv[i], "--type=", strlen("--type="))) {
                if (!strcmp(option + 1, "int")) {
                    type = XA_INTEGER;
                } else if (!strcmp(option + 1, "float")) {
                    type = XInternAtom(display, "FLOAT", False);
                    format = 32;
                } else if (!strcmp(option + 1, "atom")) {
                    type = XA_ATOM;
                    format = 32;
                } else {
                    fprintf(stderr, "unknown property type %s\n", option + 1);
                    return EXIT_FAILURE;
                }
            } else if (!strncmp(argv[i], "--format=", strlen("--format="))) {
                format = atoi(option + 1);
                if (format != 8 && format != 16 && format != 32) {
                    fprintf(stderr, "invalid property format '%s'\n", option + 1);
                    return EXIT_FAILURE;
                }
            } else {
                fprintf(stderr, "invalid option '%s'\n", argv[i]);
                return EXIT_FAILURE;
            }
    
            for (j = i; j + 1 < argc; j++)
                argv[j] = argv[j + 1];
            argc--;
        }
    
        return do_set_prop(display, type, format, argc, argv, name, desc);
    }
    
    int disable(Display *display, int argc, char *argv[], char *name, char *desc)
    {
        char *new_argv[3] = { argv[0], "Device Enabled", "0" };
        return set_prop(display, 3, new_argv, name, desc);
    }
    
    int enable(Display *display, int argc, char *argv[], char *name, char *desc)
    {
        char *new_argv[3] = { argv[0], "Device Enabled", "1" };
        return set_prop(display, 3, new_argv, name, desc);
    }