]> diplodocus.org Git - xorg-xinput/commitdiff
Merge branch 'master' into xi2
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 20 May 2009 02:10:44 +0000 (12:10 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 20 May 2009 02:10:44 +0000 (12:10 +1000)
configure.ac
src/Makefile.am
src/hierarchy.c
src/list.c
src/property.c
src/setcp.c
src/test_xi2.c [new file with mode: 0644]
src/xinput.c
src/xinput.h

index e973c224f07bc236aa852275f50f9f8a0080d75c..84bdcc68cc497bb9e366c0dd31478b9881710834 100644 (file)
@@ -20,11 +20,12 @@ XORG_CWARNFLAGS
 # Checks for pkg-config packages
 PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.2] [inputproto >= 1.5])
 
-LIBS="$XINPUT_LIBS $LIBS"
-AC_CHECK_FUNC(XSetClientPointer,AC_DEFINE(HAVE_XI2,1,[XInput Version 2 Enabled]))
-AM_CONDITIONAL(HAVE_XI2, [test "x$ac_cv_func_XSetClientPointer" = "xyes"] )
+# XI2 support
+PKG_CHECK_MODULES(XI2, [xi >= 1.2.99] [inputproto >= 1.9.99.9],
+                  HAVE_XI2="yes"; AC_DEFINE(HAVE_XI2, 1, [XI2 available]),
+                  HAVE_XI2="no");
+AM_CONDITIONAL(HAVE_XI2, [ test "$HAVE_XI2" = "yes" ])
 
-XINPUT_CFLAGS="$CWARNFLAGS $XINPUT_CFLAGS"
 AC_SUBST(XINPUT_CFLAGS)
 AC_SUBST(XINPUT_LIBS)
 AC_SUBST(HAVE_XI2)
index 1efddb888b263ff048b09dca267572e87e43990f..a6dedb7662604e086ee5b0062f085b5d7a4224c0 100644 (file)
@@ -26,8 +26,8 @@ xinput_LDADD = $(XINPUT_LIBS)
 
 
 if HAVE_XI2
-    xinput2_files = hierarchy.c setcp.c
-endif # HAVE_XI2
+xinput2_files = hierarchy.c setcp.c test_xi2.c
+endif
 
 xinput_SOURCES = \
     buttonmap.c \
index 869c3fd8e41ea39781877aebff43d701716c1c2c..77960d5311b9f9540a95c80a63df7fd3361b7afa 100644 (file)
@@ -40,7 +40,7 @@
 int
 create_master(Display* dpy, int argc, char** argv, char* name, char *desc)
 {
-    XCreateMasterInfo c;
+    XICreateMasterInfo c;
 
     if (argc == 0)
     {
@@ -48,12 +48,12 @@ create_master(Display* dpy, int argc, char** argv, char* name, char *desc)
         return EXIT_FAILURE;
     }
 
-    c.type = CH_CreateMasterDevice;
+    c.type = XICreateMaster;
     c.name = argv[0];
     c.sendCore = (argc >= 2) ? atoi(argv[1]) : 1;
     c.enable = (argc >= 3) ? atoi(argv[2]) : 1;
 
-    return XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1);
+    return XIChangeHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1);
 }
 
 /**
@@ -64,9 +64,8 @@ create_master(Display* dpy, int argc, char** argv, char* name, char *desc)
 int
 remove_master(Display* dpy, int argc, char** argv, char *name, char *desc)
 {
-    XDeviceInfo *info;
-    XRemoveMasterInfo r;
-    XDevice* master = NULL, *ptr = NULL, *keybd = NULL;
+    XIRemoveMasterInfo r;
+    XIDeviceInfo *info;
     int ret;
 
     if (argc == 0)
@@ -75,45 +74,33 @@ remove_master(Display* dpy, int argc, char** argv, char *name, 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;
     }
 
-    master = XOpenDevice(dpy, info->id);
-    if (!master)
-        Error(BadValue, "Unable to open device %s.\n", argv[0]);
-
-    r.type = CH_RemoveMasterDevice;
-    r.device = master;
+    r.type = XIRemoveMaster;
+    r.device = info->deviceid;
     if (argc >= 2)
     {
         if (!strcmp(argv[1], "Floating"))
-            r.returnMode = Floating;
+            r.returnMode = XIFloating;
         else if (!strcmp(argv[1], "AttachToMaster"))
-            r.returnMode = AttachToMaster;
+            r.returnMode = XIAttachToMaster;
         else
             Error(BadValue, "Invalid returnMode.\n");
     } else
-        r.returnMode = Floating;
+        r.returnMode = XIFloating;
 
-    if (r.returnMode == AttachToMaster)
+    if (r.returnMode == XIAttachToMaster)
     {
-        ptr = XOpenDevice(dpy, atoi(argv[2]));
-        keybd = XOpenDevice(dpy, atoi(argv[3]));
-        if (!ptr || !keybd)
-            Error(BadValue, "Invalid fallback master.\n");
-        r.returnPointer = ptr;
-        r.returnKeyboard = keybd;
+        r.returnPointer = atoi(argv[2]);
+        r.returnKeyboard = atoi(argv[3]);
     }
 
-    ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&r, 1);
-    if (ptr)
-        XCloseDevice(dpy, ptr);
-    if (keybd)
-        XCloseDevice(dpy, keybd);
+    ret = XIChangeHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&r, 1);
     return ret;
 }
 
@@ -123,9 +110,8 @@ remove_master(Display* dpy, int argc, char** argv, char *name, char *desc)
 int
 change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc)
 {
-    XDeviceInfo *info_sd, *info_md;
-    XChangeAttachmentInfo c;
-    XDevice *slave, *master;
+    XIDeviceInfo *sd_info, *md_info;
+    XIAttachSlaveInfo c;
     int ret;
 
     if (argc < 2)
@@ -134,36 +120,24 @@ change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc)
         return EXIT_FAILURE;
     }
 
-    info_sd = find_device_info(dpy, argv[0], True);
-    info_md = find_device_info(dpy, argv[1], False);
+    sd_info = xi2_find_device_info(dpy, argv[0]);
+    md_info= xi2_find_device_info(dpy, argv[1]);
 
-    if (!info_sd) {
+    if (!sd_info) {
        fprintf(stderr, "unable to find device %s\n", argv[0]);
        return EXIT_FAILURE;
     }
 
-    if (!info_md) {
+    if (!md_info) {
        fprintf(stderr, "unable to find device %s\n", argv[1]);
        return EXIT_FAILURE;
     }
 
-    slave = XOpenDevice(dpy, info_sd->id);
-    master = XOpenDevice(dpy, info_md->id);
-
-    if (!slave)
-        Error(BadValue, "Invalid slave device given %d\n", atoi(argv[0]));
-
-    if (!master)
-        Error(BadValue, "Invalid master device given %d\n", atoi(argv[1]));
+    c.type = XIAttachSlave;
+    c.device = sd_info->deviceid;
+    c.newMaster = md_info->deviceid;
 
-    c.type = CH_ChangeAttachment;
-    c.changeMode = AttachToMaster;
-    c.device = slave;
-    c.newMaster = master;
-
-    ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1);
-    XCloseDevice(dpy, slave);
-    XCloseDevice(dpy, master);
+    ret = XIChangeHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1);
     return ret;
 }
 
@@ -173,9 +147,8 @@ change_attachment(Display* dpy, int argc, char** argv, char *name, char* desc)
 int
 float_device(Display* dpy, int argc, char** argv, char* name, char* desc)
 {
-    XDeviceInfo *info;
-    XChangeAttachmentInfo c;
-    XDevice *slave;
+    XIDeviceInfo *info;
+    XIDetachSlaveInfo c;
     int ret;
 
     if (argc < 1)
@@ -184,24 +157,17 @@ float_device(Display* dpy, int argc, char** argv, char* name, char* desc)
         return EXIT_FAILURE;
     }
 
-    info = find_device_info(dpy, argv[0], True);
+    info = xi2_find_device_info(dpy, argv[0]);
 
     if (!info) {
        fprintf(stderr, "unable to find device %s\n", argv[0]);
        return EXIT_FAILURE;
     }
 
-    slave = XOpenDevice(dpy, info->id);
-
-    if (!slave)
-        return BadValue;
-
-    c.type = CH_ChangeAttachment;
-    c.changeMode = Floating;
-    c.device = slave;
+    c.type = XIDetachSlave;
+    c.device = info->deviceid;
 
-    ret = XChangeDeviceHierarchy(dpy, (XAnyHierarchyChangeInfo*)&c, 1);
-    XCloseDevice(dpy, slave);
+    ret = XIChangeHierarchy(dpy, (XIAnyHierarchyChangeInfo*)&c, 1);
     return ret;
 }
 
index bd71a5cccc70aa77c39ceea4866779a600154fce..09eaa0a95b7df1ff248b674075d36ec7ce93020d 100644 (file)
@@ -34,9 +34,6 @@ print_info(Display* dpy, XDeviceInfo  *info, Bool shortformat)
     XButtonInfoPtr     b;
     XValuatorInfoPtr   v;
     XAxisInfoPtr       a;
-#if HAVE_XI2
-    XAttachInfoPtr      att;
-#endif
 
     printf("\"%s\"\tid=%ld\t[", info->name, info->id);
 
@@ -98,12 +95,6 @@ print_info(Display* dpy, XDeviceInfo *info, Bool shortformat)
                    printf ("\t\tResolution is %d\n", a->resolution);
                }
                break;
-#if HAVE_XI2
-            case AttachClass:
-                att = (XAttachInfoPtr)any;
-                printf("\tAttached to %d\n", att->attached);
-                break;
-#endif
            default:
                printf ("unknown class\n");
            }
@@ -112,12 +103,11 @@ print_info(Display* dpy, XDeviceInfo      *info, Bool shortformat)
     }
 }
 
-int
-list(Display   *display,
-     int       argc,
-     char      *argv[],
-     char      *name,
-     char      *desc)
+static int list_xi1(Display     *display,
+                    int                argc,
+                    char        *argv[],
+                    char        *name,
+                    char        *desc)
 {
     XDeviceInfo                *info;
     int                        loop;
@@ -129,44 +119,12 @@ list(Display      *display,
 
     if (argc == 0 || shortformat || daemon) {
        int             num_devices;
-        XEvent  ev;
-
-#if HAVE_XI2
-        if (daemon)
-        {
-            XiSelectEvent(display, DefaultRootWindow(display), NULL,
-                          XI_DeviceHierarchyChangedMask |
-                          XI_DeviceClassesChangedMask);
-        }
-#endif
 
         do {
             info = XListInputDevices(display, &num_devices);
             for(loop=0; loop<num_devices; loop++) {
                 print_info(display, info+loop, shortformat);
             }
-
-#if HAVE_XI2
-            /* just wait for the next generic event to come along */
-            while (daemon && !XNextEvent(display, &ev))
-            {
-                if (ev.type == GenericEvent)
-                {
-                    XGenericEvent* gev = (XGenericEvent*)&ev;
-                    /* we just assume that extension is IReqCode, pretty save
-                       since we don't register for other events. */
-                    if (gev->evtype == XI_DeviceHierarchyChangedNotify)
-                    {
-                        printf("Hierarchy change.\n");
-                    } else if (gev->evtype == XI_DeviceClassesChangedNotify)
-                    {
-                        printf("Device classes changed.\n");
-                        free(((XDeviceClassesChangedEvent*)&ev)->inputclassinfo);
-                    }
-                    break;
-                }
-            }
-#endif
         } while(daemon);
     } else {
        int     ret = EXIT_SUCCESS;
@@ -186,4 +144,160 @@ list(Display      *display,
     return EXIT_SUCCESS;
 }
 
+#ifdef HAVE_XI2
+/* also used from test_xi2.c */
+void
+print_classes_xi2(Display* display, XIAnyClassInfo **classes,
+                  int num_classes)
+{
+    int i;
+
+    printf("\tReporting %d classes:\n", num_classes);
+    for (i = 0; i < num_classes; i++)
+    {
+        switch(classes[i]->type)
+        {
+            case ButtonClass:
+                {
+                    XIButtonClassInfo *b = (XIButtonClassInfo*)classes[i];
+                    printf("\t\tButtons supported: %d\n", b->num_buttons);
+
+                }
+                break;
+            case KeyClass:
+                {
+                    XIKeyClassInfo *k = (XIKeyClassInfo*)classes[i];
+                    printf("\t\tKeycodes supported: %d\n", k->num_keycodes);
+                }
+                break;
+            case ValuatorClass:
+                {
+                    XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i];
+                    printf("\t\tDetail for Valuator %d:\n", v->number);
+                    printf("\t\t  Name: %s\n", XGetAtomName(display, v->name));
+                    printf("\t\t  Range: %f - %f\n", v->min, v->max);
+                    printf("\t\t  Resolution: %d units/m\n", v->resolution);
+                    printf("\t\t  Mode: %s\n", v->mode == Absolute ? "absolute" :
+                            "relative");
+                }
+                break;
+        }
+    }
+
+    printf("\n");
+}
+
+static void
+print_info_xi2(Display* display, XIDeviceInfo *dev, Bool shortformat)
+{
+    printf("%-40s\tid=%d\t[", dev->name, dev->deviceid);
+    switch(dev->use)
+    {
+        case XIMasterPointer:
+            printf("master pointer  (%d)]\n", dev->attachment);
+            break;
+        case XIMasterKeyboard:
+            printf("master keyboard (%d)]\n", dev->attachment);
+            break;
+        case XISlavePointer:
+            printf("slave  pointer  (%d)]\n", dev->attachment);
+            break;
+        case XISlaveKeyboard:
+            printf("slave  keyboard (%d)]\n", dev->attachment);
+            break;
+        case XIFloatingSlave:
+            printf("floating slave]\n");
+            break;
+    }
+
+    if (shortformat)
+        return;
+
+    if (!dev->enabled)
+        printf("\tThis device is disabled\n");
+
+    print_classes_xi2(display, dev->classes, dev->num_classes);
+}
+
+
+int
+list_xi2(Display       *display,
+         int   argc,
+         char  *argv[],
+         char  *name,
+         char  *desc)
+{
+    int major = XI_2_Major,
+        minor = XI_2_Minor;
+    int ndevices;
+    int i, j, shortformat;
+    XIDeviceInfo *info, *dev;
+
+    shortformat = (argc == 1 && strcmp(argv[0], "--short") == 0);
+
+    if (XIQueryVersion(display, &major, &minor) != Success ||
+        (major * 1000 + minor) < (XI_2_Major * 1000 + XI_2_Minor))
+    {
+        fprintf(stderr, "XI2 not supported.\n");
+        return EXIT_FAILURE;
+    }
+
+    info = XIQueryDevice(display, XIAllDevices, &ndevices);
+    dev = info;
+
+    for(i = 0; i < ndevices; i++)
+    {
+        dev = &info[i];
+        if (dev->use == XIMasterPointer || dev->use == XIMasterKeyboard)
+        {
+            if (dev->use == XIMasterPointer)
+                printf("⎡ ");
+            else
+                printf("⎣ ");
+
+            print_info_xi2(display, dev, shortformat);
+            for (j = 0; j < ndevices; j++)
+            {
+                XIDeviceInfo* sd = &info[j];
+
+                if ((sd->use == XISlavePointer || sd->use == XISlaveKeyboard) &&
+                     (sd->attachment == dev->deviceid))
+                {
+                    printf("%s   ↳ ", dev->use == XIMasterPointer ? "⎜" : " ");
+                    print_info_xi2(display, sd, shortformat);
+                }
+            }
+        }
+    }
+
+    for (i = 0; i < ndevices; i++)
+    {
+        dev = &info[i];
+        if (dev->use == XIFloatingSlave)
+        {
+            printf("∼ ");
+            print_info_xi2(display, dev, shortformat);
+        }
+    }
+
+
+    XIFreeDeviceInfo(info);
+    return EXIT_SUCCESS;
+}
+#endif
+
+int
+list(Display   *display,
+     int       argc,
+     char      *argv[],
+     char      *name,
+     char      *desc)
+{
+#ifdef HAVE_XI2
+    if (xinput_version(display) == XI_2_Major)
+        return list_xi2(display, argc, argv, name, desc);
+#endif
+    return list_xi1(display, argc, argv, name, desc);
+}
+
 /* end of list.c */
index 86c160867abef70229c8cd2bab6ae9f9692aad86..49ba4f03f27b1fd480e6feaa18d01e210107d692 100644 (file)
@@ -133,10 +133,10 @@ print_property(Display *dpy, XDevice* dev, Atom property)
 
             ptr += size;
 
-            if (j < nitems - 1)
-                printf(", ");
             if (done == True)
                 break;
+            if (j < nitems - 1)
+                printf(", ");
         }
         printf("\n");
         XFree(data);
@@ -145,7 +145,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;
@@ -379,7 +380,8 @@ int watch_props(Display *dpy, int argc, char** argv, char* n, char *desc)
     XCloseDevice(dpy, dev);
 }
 
-int delete_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
+static int
+delete_prop_xi1(Display *dpy, int argc, char** argv, char* n, char *desc)
 {
     XDevice     *dev;
     XDeviceInfo *info;
@@ -476,8 +478,8 @@ set_atom_prop(Display *dpy, int argc, char** argv, char* n, char *desc)
     return EXIT_SUCCESS;
 }
 
-int
-set_prop(Display *dpy, int argc, char **argv, char *n, char *desc)
+static int
+set_prop_xi1(Display *dpy, int argc, char **argv, char *n, char *desc)
 {
     XDeviceInfo  *info;
     XDevice      *dev;
@@ -592,3 +594,290 @@ set_prop(Display *dpy, int argc, char **argv, char *n, char *desc)
     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;
+
+        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:
+                    printf("\"%s\"", XGetAtomName(dpy, *(Atom*)ptr));
+                    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
+set_prop_xi2(Display *dpy, int argc, char **argv, char *n, char *desc)
+{
+    XIDeviceInfo *info;
+    Atom          prop;
+    Atom          type;
+    char         *name;
+    int           i;
+    Atom          float_atom;
+    int           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 (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False, AnyPropertyType,
+                      &type, &format, &act_nitems, &bytes_after, &data.c)
+            != Success) {
+        fprintf(stderr, "failed to get property type and format for %s\n", name);
+        return EXIT_FAILURE;
+    }
+
+    XFree(data.c);
+
+    if (type == None) {
+        fprintf(stderr, "property %s doesn't exist\n", name);
+        return EXIT_FAILURE;
+    }
+
+    data.c = calloc(nelements, sizeof(int32_t));
+
+    for (i = 0; i < nelements; i++)
+    {
+        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;
+        }
+    }
+
+    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);
+
+}
+
+int set_prop(Display *display, int argc, char *argv[], char *name,
+             char *desc)
+{
+#ifdef HAVE_XI2
+    if (xinput_version(display) == XI_2_Major)
+        return set_prop_xi2(display, argc, argv, name, desc);
+#endif
+    return set_prop_xi1(display, argc, argv, name, desc);
+}
index e44bb00fabeb1d13bfbc253ec1e4ce72e100d932..7a2864479cf7b195bc785226d70f56b6656391f3 100644 (file)
@@ -32,9 +32,8 @@
 int
 set_clientpointer(Display* dpy, int argc, char** argv, char* name, char *desc)
 {
-    XDeviceInfo* info;
+    XIDeviceInfo *info;
     XID window;
-    XDevice* dev = NULL;
     char* id;
     char* dummy;
 
@@ -50,19 +49,13 @@ set_clientpointer(Display* dpy, int argc, char** argv, char* name, char *desc)
 
     window = strtol(argv[0], &dummy, (*id == 'x') ? 16 : 10);
 
-    info = find_device_info(dpy, argv[1], False);
+    info = xi2_find_device_info(dpy, argv[1]);
 
     if (!info) {
        fprintf(stderr, "unable to find device %s\n", argv[1]);
        return EXIT_FAILURE;
     }
 
-    dev = XOpenDevice(dpy, info->id);
-
-    if (!dev)
-    {
-        fprintf(stderr, "Cannot open device %s.\n", argv[1]);
-    } else
-        XSetClientPointer(dpy, window, dev);
+    XISetClientPointer(dpy, window, info->deviceid);
     return 0;
 }
diff --git a/src/test_xi2.c b/src/test_xi2.c
new file mode 100644 (file)
index 0000000..b03b762
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * 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 "xinput.h"
+#include <string.h>
+
+extern void print_classes_xi2(Display*, XIAnyClassInfo **classes,
+                              int num_classes);
+
+#define BitIsOn(ptr, bit) (((unsigned char *) (ptr))[(bit)>>3] & (1 << ((bit) & 7)))
+#define SetBit(ptr, bit)  (((unsigned char *) (ptr))[(bit)>>3] |= (1 << ((bit) & 7)))
+
+static Window create_win(Display *dpy)
+{
+    Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200,
+            200, 0, 0, WhitePixel(dpy, 0));
+    Window subwindow = XCreateSimpleWindow(dpy, win, 50, 50, 50, 50, 0, 0,
+            BlackPixel(dpy, 0));
+
+    XSelectInput(dpy, win, ExposureMask);
+    XMapWindow(dpy, subwindow);
+    XMapWindow(dpy, win);
+    XFlush(dpy);
+    return win;
+}
+
+static void print_deviceevent(XIDeviceEvent* event)
+{
+    double *val;
+    int i;
+
+    printf("    device: %d (%d)\n", event->deviceid, event->sourceid);
+    printf("    detail: %d\n", event->detail);
+
+    printf("    root: %.2f/%.2f\n", event->root_x, event->root_y);
+    printf("    event: %.2f/%.2f\n", event->event_x, event->event_x);
+
+    printf("    buttons:");
+    for (i = 0; i < event->buttons->mask_len * 8; i++)
+        if (BitIsOn(event->buttons->mask, i))
+            printf(" %d", i);
+    printf("\n");
+
+    printf("    modifiers: locked 0x%x latched 0x%x base 0x%x\n",
+            event->mods->locked, event->mods->latched,
+            event->mods->base);
+    printf("    group: locked 0x%x latched 0x%x base 0x%x\n",
+            event->group->locked, event->group->latched,
+            event->group->base);
+    printf("    valuators:");
+
+    val = event->valuators->values;
+    for (i = 0; i < event->valuators->mask_len * 8; i++)
+        if (BitIsOn(event->valuators->mask, i))
+            printf(" %.2f", *val++);
+    printf("\n");
+
+    printf("    windows: root 0x%lx event 0x%lx child 0x%ld\n",
+            event->root, event->event, event->child);
+}
+
+static void print_devicechangedevent(Display *dpy, XIDeviceChangedEvent *event)
+{
+    printf("    device: %d (%d)\n", event->deviceid, event->sourceid);
+    printf("    reason: %s\n", (event->reason == XISlaveSwitch) ? "SlaveSwitch" :
+                                "DeviceChanged");
+    print_classes_xi2(dpy, event->classes, event->num_classes);
+}
+
+static void print_hierarchychangedevent(XIHierarchyEvent *event)
+{
+    int i;
+    printf("    Changes happened: %s %s %s %s %s %s %s %s\n",
+            (event->flags & XIMasterAdded) ? "[new master]" : "",
+            (event->flags & XIMasterRemoved) ? "[master removed]" : "",
+            (event->flags & XISlaveAdded) ? "[new slave]" : "",
+            (event->flags & XISlaveRemoved) ? "[slave removed]" : "",
+            (event->flags & XISlaveAttached) ? "[slave attached]" : "",
+            (event->flags & XISlaveDetached) ? "[slave detached]" : "",
+            (event->flags & XIDeviceEnabled) ? "[device enabled]" : "",
+            (event->flags & XIDeviceDisabled) ? "[device disabled]" : "");
+
+    for (i = 0; i < event->num_devices; i++)
+    {
+        char *use;
+        switch(event->info[i].use)
+        {
+            case XIMasterPointer: use = "master pointer";
+            case XIMasterKeyboard: use = "master keyboard"; break;
+            case XISlavePointer: use = "slave pointer";
+            case XISlaveKeyboard: use = "slave keyboard"; break;
+            case XIFloatingSlave: use = "floating slave"; break;
+                break;
+        }
+
+        printf("    device %d [%s (%d)] is %s\n",
+                event->info[i].deviceid,
+                use,
+                event->info[i].attachment,
+                (event->info[i].enabled) ? "enabled" : "disabled");
+        if (event->info[i].flags)
+        {
+            printf("    changes: %s %s %s %s %s %s %s %s\n",
+                    (event->info[i].flags & XIMasterAdded) ? "[new master]" : "",
+                    (event->info[i].flags & XIMasterRemoved) ? "[master removed]" : "",
+                    (event->info[i].flags & XISlaveAdded) ? "[new slave]" : "",
+                    (event->info[i].flags & XISlaveRemoved) ? "[slave removed]" : "",
+                    (event->info[i].flags & XISlaveAttached) ? "[slave attached]" : "",
+                    (event->info[i].flags & XISlaveDetached) ? "[slave detached]" : "",
+                    (event->info[i].flags & XIDeviceEnabled) ? "[device enabled]" : "",
+                    (event->info[i].flags & XIDeviceDisabled) ? "[device disabled]" : "");
+        }
+    }
+}
+
+static void print_rawevent(XIRawEvent *event)
+{
+    int i;
+    double *val, *raw_val;
+
+    printf("    device: %d\n", event->deviceid);
+    printf("    detail: %d\n", event->detail);
+    printf("    valuators:\n");
+
+    val = event->valuators->values;
+    raw_val = event->raw_values;
+    for (i = 0; i < event->valuators->mask_len * 8; i++)
+        if (BitIsOn(event->valuators->mask, i))
+            printf("         %2d: %.2f (%.2f)\n", i, *val++, *raw_val++);
+    printf("\n");
+}
+
+static void print_enterleave(XILeaveEvent* event)
+{
+    char *mode, *detail;
+    int i;
+
+    printf("    windows: root 0x%lx event 0x%lx child 0x%ld\n",
+            event->root, event->event, event->child);
+    switch(event->mode)
+    {
+        case NotifyNormal:       mode = "NotifyNormal"; break;
+        case NotifyGrab:         mode = "NotifyGrab"; break;
+        case NotifyUngrab:       mode = "NotifyUngrab"; break;
+        case NotifyWhileGrabbed: mode = "NotifyWhileGrabbed"; break;
+    }
+    switch (event->detail)
+    {
+        case NotifyAncestor: detail = "NotifyAncestor"; break;
+        case NotifyVirtual: detail = "NotifyVirtual"; break;
+        case NotifyInferior: detail = "NotifyInferior"; break;
+        case NotifyNonlinear: detail = "NotifyNonlinear"; break;
+        case NotifyNonlinearVirtual: detail = "NotifyNonlinearVirtual"; break;
+        case NotifyPointer: detail = "NotifyPointer"; break;
+        case NotifyPointerRoot: detail = "NotifyPointerRoot"; break;
+        case NotifyDetailNone: detail = "NotifyDetailNone"; break;
+    }
+    printf("    mode: %s (detail %s)\n", mode, detail);
+    printf("    flags: %s %s\n", event->focus ? "[focus]" : "",
+                                 event->same_screen ? "[same screen]" : "");
+    printf("    buttons:");
+    for (i = 0; i < event->buttons->mask_len * 8; i++)
+        if (BitIsOn(event->buttons->mask, i))
+            printf(" %d", i);
+    printf("\n");
+
+    printf("    modifiers: locked 0x%x latched 0x%x base 0x%x\n",
+            event->mods->locked, event->mods->latched,
+            event->mods->base);
+    printf("    group: locked 0x%x latched 0x%x base 0x%x\n",
+            event->group->locked, event->group->latched,
+            event->group->base);
+
+    printf("    root x/y:  %.2f / %.2f\n", event->root_x, event->root_y);
+    printf("    event x/y: %.2f / %.2f\n", event->event_x, event->event_y);
+
+}
+
+static void print_propertyevent(Display *display, XIPropertyEvent* event)
+{
+    char *changed;
+
+    if (event->what == XIPropertyDeleted)
+        changed = "deleted";
+    else if (event->what == XIPropertyCreated)
+        changed = "created";
+    else
+        changed = "modified";
+
+    printf("     property: %ld '%s'\n", event->property, XGetAtomName(display, event->property));
+    printf("     changed: %s\n", changed);
+
+}
+void
+test_sync_grab(Display *display, Window win)
+{
+    int loop = 3;
+    int rc;
+    XIEventMask mask;
+
+    /* Select for motion events */
+    mask.deviceid = XIAllDevices;
+    mask.mask_len = 2;
+    mask.mask = calloc(2, sizeof(char));
+    SetBit(mask.mask, XI_ButtonPress);
+
+    if ((rc = XIGrabDevice(display, 2,  win, CurrentTime, None, GrabModeSync,
+                           GrabModeAsync, False, &mask)) != GrabSuccess)
+    {
+        fprintf(stderr, "Grab failed with %d\n", rc);
+        return;
+    }
+    free(mask.mask);
+
+    XSync(display, True);
+    XIAllowEvents(display, 2, SyncPointer, CurrentTime);
+    XFlush(display);
+
+    printf("Holding sync grab for %d button presses.\n", loop);
+
+    while(loop--)
+    {
+        XIEvent ev;
+
+        XNextEvent(display, (XEvent*)&ev);
+        if (ev.type == GenericEvent)
+        {
+            XIDeviceEvent *event = (XIDeviceEvent*)&ev;
+            print_deviceevent(event);
+            XIAllowEvents(display, 2, SyncPointer, CurrentTime);
+            XIFreeEventData(&ev);
+        }
+    }
+
+    XIUngrabDevice(display, 2, CurrentTime);
+    printf("Done\n");
+}
+
+int
+test_xi2(Display       *display,
+         int   argc,
+         char  *argv[],
+         char  *name,
+         char  *desc)
+{
+    XIEventMask mask;
+    Window win;
+
+    list(display, argc, argv, name, desc);
+    win = create_win(display);
+
+    XSync(display, False);
+
+    /* Select for motion events */
+    mask.deviceid = XIAllDevices;
+    mask.mask_len = 2;
+    mask.mask = calloc(mask.mask_len, sizeof(char));
+    SetBit(mask.mask, XI_ButtonPress);
+    SetBit(mask.mask, XI_ButtonRelease);
+    SetBit(mask.mask, XI_KeyPress);
+    SetBit(mask.mask, XI_KeyRelease);
+    SetBit(mask.mask, XI_Motion);
+    SetBit(mask.mask, XI_DeviceChanged);
+    SetBit(mask.mask, XI_Enter);
+    SetBit(mask.mask, XI_Leave);
+    SetBit(mask.mask, XI_FocusIn);
+    SetBit(mask.mask, XI_FocusOut);
+    SetBit(mask.mask, XI_HierarchyChanged);
+    SetBit(mask.mask, XI_PropertyEvent);
+    XISelectEvents(display, win, &mask, 1);
+    XSync(display, False);
+
+    {
+        int modifiers[] = {0, 0x10, 0x1, 0x11};
+        int nmods = sizeof(modifiers)/sizeof(modifiers[0]);
+
+        mask.deviceid = 2;
+        memset(mask.mask, 0, 2);
+        SetBit(mask.mask, XI_KeyPress);
+        SetBit(mask.mask, XI_KeyRelease);
+        SetBit(mask.mask, XI_ButtonPress);
+        SetBit(mask.mask, XI_Motion);
+        XIGrabButton(display, 2, 1, win, None, GrabModeAsync, GrabModeAsync,
+                False, &mask, nmods, modifiers);
+        XIGrabKeysym(display, 3, 0x71, win, GrabModeAsync, GrabModeAsync,
+                False, &mask, nmods, modifiers);
+        XIUngrabButton(display, 3, 1, win, nmods - 2, &modifiers[2]);
+        XIUngrabKeysym(display, 3, 0x71, win, nmods - 2, &modifiers[2]);
+    }
+
+    mask.deviceid = XIAllMasterDevices;
+    memset(mask.mask, 0, 2);
+    SetBit(mask.mask, XI_RawEvent);
+    XISelectEvents(display, DefaultRootWindow(display), &mask, 1);
+
+    free(mask.mask);
+
+    {
+        XEvent event;
+        XMaskEvent(display, ExposureMask, &event);
+        XSelectInput(display, win, 0);
+    }
+
+    /*
+    test_sync_grab(display, win);
+    */
+
+    while(1)
+    {
+        XIEvent ev;
+        XNextEvent(display, (XEvent*)&ev);
+        if (ev.type == GenericEvent)
+        {
+            XIDeviceEvent *event = (XIDeviceEvent*)&ev;
+
+            printf("EVENT type %d\n", event->evtype);
+            switch (event->evtype)
+            {
+                case XI_DeviceChanged:
+                    print_devicechangedevent(display,
+                                             (XIDeviceChangedEvent*)event);
+                    break;
+                case XI_HierarchyChanged:
+                    print_hierarchychangedevent((XIHierarchyEvent*)event);
+                    break;
+                case XI_RawEvent:
+                    print_rawevent((XIRawEvent*)event);
+                    break;
+                case XI_Enter:
+                case XI_Leave:
+                case XI_FocusIn:
+                case XI_FocusOut:
+                    print_enterleave((XILeaveEvent*)event);
+                    break;
+                case XI_PropertyEvent:
+                    print_propertyevent(display, (XIPropertyEvent*)event);
+                    break;
+                default:
+                    print_deviceevent(event);
+                    break;
+            }
+        }
+
+        XIFreeEventData(&ev);
+    }
+
+    XDestroyWindow(display, win);
+
+    return EXIT_SUCCESS;
+}
index 2a9df6ab053abe933b9dc2543f3e337120aa5f6d..007fe2cd1248336e5d577678ada99966d7be1d33 100644 (file)
@@ -102,6 +102,10 @@ static entry drivers[] =
       "<window> <device>",
       set_clientpointer
     },
+    { "test-xi2",
+      "<device>",
+      test_xi2,
+    },
 #endif
     { "list-props",
       "<device> [<device> ...]",
@@ -135,25 +139,23 @@ static entry drivers[] =
     }
 };
 
-static Bool
-is_xinput_present(Display      *display)
+int
+xinput_version(Display *display)
 {
     XExtensionVersion  *version;
-    Bool               present;
+    static int vers = -1;
+
+    if (vers != -1)
+        return vers;
 
-#if HAVE_XI2
-    version = XQueryInputVersion(display, XI_2_Major, XI_2_Minor);
-#else
     version = XGetExtensionVersion(display, INAME);
-#endif
 
     if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
-       present = version->present;
+       vers = version->major_version;
        XFree(version);
-       return present;
-    } else {
-       return False;
     }
+
+    return vers;
 }
 
 XDeviceInfo*
@@ -200,6 +202,41 @@ find_device_info(Display   *display,
     return found;
 }
 
+#ifdef HAVE_XI2
+XIDeviceInfo*
+xi2_find_device_info(Display *display, char *name)
+{
+    XIDeviceInfo *info;
+    int ndevices;
+    Bool is_id = True;
+    int i, id = -1;
+
+    for(i = 0; i < strlen(name); i++) {
+       if (!isdigit(name[i])) {
+           is_id = False;
+           break;
+       }
+    }
+
+    if (is_id) {
+       id = atoi(name);
+    }
+
+    info = XIQueryDevice(display, XIAllDevices, &ndevices);
+    for(i = 0; i < ndevices; i++)
+    {
+        if ((is_id && info[i].deviceid == id) ||
+                (!is_id && strcmp(info[i].name, name) == 0))
+        {
+            return &info[i];
+        }
+    }
+
+    XIFreeDeviceInfo(info);
+    return NULL;
+}
+#endif
+
 static void
 usage(void)
 {
@@ -236,7 +273,7 @@ main(int argc, char * argv[])
     func = argv[1];
     while((*func) == '-') func++;
 
-    if (!is_xinput_present(display)) {
+    if (!xinput_version(display)) {
        fprintf(stderr, "%s extension not available\n", INAME);
        return EXIT_FAILURE;
     }
index c4a6f8f96e57b1f1f55891c35f08e8dfc5b4af5b..fd468b01530d5c8695aeb79510b40e3479416215 100644 (file)
@@ -27,6 +27,9 @@
 
 #include <X11/Xlib.h>
 #include <X11/extensions/XInput.h>
+#ifdef HAVE_XI2
+#include <X11/extensions/XInput2.h>
+#endif
 #include <X11/Xutil.h>
 #include <stdio.h>
 #include <stdlib.h>
 #endif
 
 XDeviceInfo* find_device_info( Display *display, char *name, Bool only_extended);
+#if HAVE_XI2
+XIDeviceInfo* xi2_find_device_info(Display *display, char *name);
+int xinput_version(Display* display);
+#endif
 
 int get_feedbacks( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
 int set_ptr_feedback( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
@@ -68,4 +75,6 @@ int remove_master( Display* display, int argc, char *argv[], char *prog_name, ch
 int change_attachment( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
 int float_device( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
 int set_clientpointer( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
+int test_xi2( Display* display, int argc, char *argv[], char *prog_name, char *prog_desc);
+
 /* end of xinput.h */