X-Git-Url: https://diplodocus.org/git/xorg-xinput/blobdiff_plain/49ef8a40f96c0383a8a42a78fda3a990ac934e59..09b075863708e43b9c1202dd052f36d5f865f571:/src/property.c?ds=sidebyside diff --git a/src/property.c b/src/property.c index e591013..6cd8e7a 100644 --- a/src/property.c +++ b/src/property.c @@ -34,6 +34,23 @@ #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) { @@ -42,7 +59,7 @@ print_property(Display *dpy, XDevice* dev, Atom property) int act_format; unsigned long nitems, bytes_after; unsigned char *data, *ptr; - int j, done = False; + int j, done = False, size; name = XGetAtomName(dpy, property); printf("\t%s (%ld):\t", name, property); @@ -51,10 +68,20 @@ print_property(Display *dpy, XDevice* dev, Atom property) AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { - int float_atom = XInternAtom(dpy, "FLOAT", False); + Atom float_atom = XInternAtom(dpy, "FLOAT", True); ptr = data; + if (nitems == 0) + printf(""); + + 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) @@ -63,23 +90,37 @@ print_property(Display *dpy, XDevice* dev, Atom property) switch(act_format) { case 8: - printf("%d", *((int8_t*)ptr)); + printf("%d", *((char*)ptr)); break; case 16: - printf("%d", *((int16_t*)ptr)); + printf("%d", *((short*)ptr)); break; case 32: - printf("%d", *((int32_t*)ptr)); + printf("%ld", *((long*)ptr)); break; } break; case XA_STRING: + if (act_format != 8) + { + printf("Unknown string format.\n"); + done = True; + break; + } printf("\"%s\"", ptr); - done = True; + 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: - printf("\"%s\"", XGetAtomName(dpy, *(Atom*)ptr)); - break; + { + Atom a = *(Atom*)ptr; + printf("\"%s\" (%d)", + (a) ? XGetAtomName(dpy, a) : "None", + (int)a); + break; + } default: if (float_atom != None && act_type == float_atom) { @@ -93,12 +134,12 @@ print_property(Display *dpy, XDevice* dev, Atom property) break; } - ptr += act_format/8; + ptr += size; - if (j < nitems - 1) - printf(", "); if (done == True) break; + if (j < nitems - 1) + printf(", "); } printf("\n"); XFree(data); @@ -107,7 +148,8 @@ print_property(Display *dpy, XDevice* dev, Atom property) } -int list_props(Display *dpy, int argc, char** argv, char* name, char *desc) +static int +list_props_xi1(Display *dpy, int argc, char** argv, char* name, char *desc) { XDeviceInfo *info; XDevice *dev; @@ -156,23 +198,19 @@ int list_props(Display *dpy, int argc, char** argv, char* name, char *desc) return EXIT_SUCCESS; } -int -set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc) + +int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc) { - XDeviceInfo *info; XDevice *dev; - Atom prop; + XDeviceInfo *info; + XEvent ev; + XDevicePropertyNotifyEvent *dpev; char *name; - int i; - Bool is_atom = True; - char *data; - int format, nelements = 0; + int type_prop; + XEventClass cls_prop; - if (argc < 3) - { - fprintf(stderr, "Usage: xinput %s %s\n", n, desc); + if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS) return EXIT_FAILURE; - } info = find_device_info(dpy, argv[0], False); if (!info) @@ -184,71 +222,82 @@ set_int_prop(Display *dpy, int argc, char** argv, char* n, char *desc) dev = XOpenDevice(dpy, info->id); if (!dev) { - fprintf(stderr, "unable to open device %s\n", argv[0]); + fprintf(stderr, "unable to open device '%s'\n", info->name); return EXIT_FAILURE; } - name = argv[1]; + DevicePropertyNotify(dev, type_prop, cls_prop); + XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1); - for(i = 0; i < strlen(name); i++) { - if (!isdigit(name[i])) { - is_atom = False; - break; - } + 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); } - if (!is_atom) - prop = XInternAtom(dpy, name, False); - else - prop = atoi(name); + XCloseDevice(dpy, dev); +} - nelements = argc - 3; - format = atoi(argv[2]); - if (format != 8 && format != 16 && format != 32) +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, "Invalid format %d\n", format); + fprintf(stderr, "unable to find device %s\n", argv[0]); return EXIT_FAILURE; } - data = calloc(nelements, format/8); - for (i = 0; i < nelements; i++) + dev = XOpenDevice(dpy, info->id); + if (!dev) { - switch(format) - { - case 8: - *(((int8_t*)data) + i) = atoi(argv[3 + i]); - break; - case 16: - *(((int16_t*)data) + i) = atoi(argv[3 + i]); - break; - case 32: - *(((int32_t*)data) + i) = atoi(argv[3 + i]); - break; - } + fprintf(stderr, "unable to open device '%s'\n", info->name); + return EXIT_FAILURE; } - XChangeDeviceProperty(dpy, dev, prop, XA_INTEGER, format, PropModeReplace, - (unsigned char*)data, nelements); + name = argv[1]; + + prop = parse_atom(dpy, name); + + XDeleteDeviceProperty(dpy, dev, prop); - free(data); XCloseDevice(dpy, dev); return EXIT_SUCCESS; } -int -set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc) +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, float_atom; - char *name; - int i; - Bool is_atom = True; - float *data; - int nelements = 0; - char* endptr; + 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 < 2) + if (argc < 3) { fprintf(stderr, "Usage: xinput %s %s\n", n, desc); return EXIT_FAILURE; @@ -270,153 +319,263 @@ set_float_prop(Display *dpy, int argc, char** argv, char* n, char *desc) name = argv[1]; - for(i = 0; i < strlen(name); i++) { - if (!isdigit(name[i])) { - is_atom = False; - break; - } + prop = parse_atom(dpy, name); + + if (prop == None) { + fprintf(stderr, "invalid property %s\n", name); + return EXIT_FAILURE; } - if (!is_atom) - prop = XInternAtom(dpy, name, False); - else - prop = atoi(name); + 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; + } - float_atom = XInternAtom(dpy, "FLOAT", False); - - if (float_atom == (Atom)0) - { - fprintf(stderr, "no FLOAT atom present in server\n"); - return EXIT_FAILURE; + XFree(data.c); } - if (sizeof(float) != 4) - { - fprintf(stderr, "sane FP required\n"); - return EXIT_FAILURE; + if (type == None) { + fprintf(stderr, "property %s doesn't exist, you need to specify " + "its type and format\n", name); + return EXIT_FAILURE; } - data = calloc(nelements, 4); + data.c = calloc(nelements, sizeof(long)); + for (i = 0; i < nelements; i++) { - *(data + 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; - } + if (type == XA_INTEGER) { + 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, float_atom, 32, PropModeReplace, - (unsigned char*)data, nelements); - - free(data); + XChangeDeviceProperty(dpy, dev, prop, type, format, PropModeReplace, + data.c, nelements); + free(data.c); XCloseDevice(dpy, dev); return EXIT_SUCCESS; } - -int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc) +#if HAVE_XI2 +static void +print_property_xi2(Display *dpy, int deviceid, Atom property) { - XDevice *dev; - XDeviceInfo *info; - XEvent ev; - XDevicePropertyNotifyEvent *dpev; - char *name; - int type_prop; - XEventClass cls_prop; + Atom act_type; + char *name; + int act_format; + unsigned long nitems, bytes_after; + unsigned char *data, *ptr; + int j, done = False; - if (list_props(dpy, argc, argv, n, desc) != EXIT_SUCCESS) - return EXIT_FAILURE; + name = XGetAtomName(dpy, property); + printf("\t%s (%ld):\t", name, property); - info = find_device_info(dpy, argv[0], False); - if (!info) + if (XIGetProperty(dpy, deviceid, property, 0, 1000, False, + AnyPropertyType, &act_type, &act_format, + &nitems, &bytes_after, &data) == Success) { - fprintf(stderr, "unable to find device %s\n", argv[0]); - return EXIT_FAILURE; - } + Atom float_atom = XInternAtom(dpy, "FLOAT", True); - dev = XOpenDevice(dpy, info->id); - if (!dev) + ptr = data; + + if (nitems == 0) + printf(""); + + 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_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; + } + 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, "unable to open device '%s'\n", info->name); + fprintf(stderr, "Usage: xinput %s %s\n", name, desc); return EXIT_FAILURE; } - DevicePropertyNotify(dev, type_prop, cls_prop); - XSelectExtensionEvent(dpy, DefaultRootWindow(dpy), &cls_prop, 1); - - while(1) + for (i = 0; i < argc; i++) { - XNextEvent(dpy, &ev); + info = xi2_find_device_info(dpy, argv[i]); + if (!info) + { + fprintf(stderr, "unable to find device %s\n", argv[i]); + continue; + } - dpev = (XDevicePropertyNotifyEvent*)&ev; - if (dpev->type != type_prop) + props = XIListProperties(dpy, info->deviceid, &nprops); + if (!nprops) + { + printf("Device '%s' does not report any properties.\n", info->name); continue; + } - name = XGetAtomName(dpy, dpev->atom); - printf("Property '%s' changed.\n", name); - print_property(dpy, dev, dpev->atom); - } + printf("Device '%s':\n", info->name); + while(nprops--) + { + print_property_xi2(dpy, info->deviceid, props[nprops]); + } - XCloseDevice(dpy, dev); + XFree(props); + } + return EXIT_SUCCESS; } -int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc) +static int +delete_prop_xi2(Display *dpy, int argc, char** argv, char* n, char *desc) { - XDevice *dev; - XDeviceInfo *info; + XIDeviceInfo *info; char *name; - int i; - Bool is_atom = True; Atom prop; - info = find_device_info(dpy, argv[0], False); + info = xi2_find_device_info(dpy, argv[0]); 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]; - for(i = 0; i < strlen(name); i++) { - if (!isdigit(name[i])) { - is_atom = False; - break; - } - } - - if (!is_atom) - prop = XInternAtom(dpy, name, False); - else - prop = atoi(name); + prop = parse_atom(dpy, name); - XDeleteDeviceProperty(dpy, dev, prop); + XIDeleteProperty(dpy, info->deviceid, prop); - XCloseDevice(dpy, dev); return EXIT_SUCCESS; } -int -set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc) +static int +do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc) { - XDeviceInfo *info; - XDevice *dev; - Atom prop; - char *name; - int i, j; - Bool is_atom = True; - Atom *data; - int nelements = 0; + 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) { @@ -424,62 +583,219 @@ set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc) return EXIT_FAILURE; } - info = find_device_info(dpy, argv[0], False); + info = xi2_find_device_info(dpy, argv[0]); 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]); + name = argv[1]; + + prop = parse_atom(dpy, name); + + if (prop == None) { + fprintf(stderr, "invalid property %s\n", name); return EXIT_FAILURE; } - name = argv[1]; + float_atom = XInternAtom(dpy, "FLOAT", False); - for(i = 0; i < strlen(name); i++) { - if (!isdigit(name[i])) { - is_atom = False; - break; - } + 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 (!is_atom) - prop = XInternAtom(dpy, name, False); - else - prop = atoi(name); + 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)); - nelements = argc - 2; - data = calloc(nelements, sizeof(Atom)); for (i = 0; i < nelements; i++) { - is_atom = True; - name = argv[2 + i]; - for(j = 0; j < strlen(name); j++) { - if (!isdigit(name[j])) { - is_atom = False; - break; + if (type == XA_INTEGER) { + 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; } + } - if (!is_atom) - data[i] = XInternAtom(dpy, name, False); - else - { - data[i] = atoi(name); - XFree(XGetAtomName(dpy, data[i])); - } + 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; } - XChangeDeviceProperty(dpy, dev, prop, XA_ATOM, 32, PropModeReplace, - (unsigned char*)data, nelements); + format = atoi(argv[2]); + if (format != 8 && format != 16 && format != 32) + { + fprintf(stderr, "Invalid format %d\n", format); + return EXIT_FAILURE; + } - free(data); - XCloseDevice(dpy, dev); - return EXIT_SUCCESS; + 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); +}