Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2009 Red Hat, Inc.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  *
     23  */
     24 
     25 #if HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <limits.h>
     30 #include <stdint.h>
     31 #include <X11/Xlibint.h>
     32 #include <X11/extensions/XI2proto.h>
     33 #include <X11/extensions/XInput2.h>
     34 #include <X11/extensions/extutil.h>
     35 #include "XIint.h"
     36 
     37 extern int copy_classes(XIDeviceInfo* to, xXIAnyInfo* from, int *nclasses);
     38 extern int size_classes(xXIAnyInfo* from, int nclasses);
     39 
     40 XIDeviceInfo*
     41 XIQueryDevice(Display *dpy, int deviceid, int *ndevices_return)
     42 {
     43     XIDeviceInfo        *info = NULL;
     44     xXIQueryDeviceReq   *req;
     45     xXIQueryDeviceReply reply;
     46     char                *ptr;
     47     char                *end;
     48     int                 i;
     49     char                *buf = NULL;
     50 
     51     XExtDisplayInfo *extinfo = XInput_find_display(dpy);
     52 
     53     LockDisplay(dpy);
     54     if (_XiCheckExtInit(dpy, XInput_2_0, extinfo) == -1)
     55         goto error_unlocked;
     56 
     57     GetReq(XIQueryDevice, req);
     58     req->reqType  = extinfo->codes->major_opcode;
     59     req->ReqType  = X_XIQueryDevice;
     60     req->deviceid = deviceid;
     61 
     62     if (!_XReply(dpy, (xReply*) &reply, 0, xFalse))
     63         goto error;
     64 
     65     if (reply.length < INT_MAX / 4)
     66     {
     67 	*ndevices_return = reply.num_devices;
     68 	info = Xmalloc((reply.num_devices + 1) * sizeof(XIDeviceInfo));
     69 	buf = Xmalloc(reply.length * 4);
     70     }
     71     else
     72     {
     73 	*ndevices_return = 0;
     74 	info = NULL;
     75 	buf = NULL;
     76     }
     77 
     78     if (!info || !buf)
     79         goto error;
     80 
     81     _XRead(dpy, buf, reply.length * 4);
     82     ptr = buf;
     83     end = buf + reply.length * 4;
     84 
     85     /* info is a null-terminated array */
     86     info[reply.num_devices].name = NULL;
     87 
     88     for (i = 0; i < reply.num_devices; i++)
     89     {
     90         int             nclasses;
     91         size_t          sz;
     92         XIDeviceInfo    *lib = &info[i];
     93         xXIDeviceInfo   *wire = (xXIDeviceInfo*)ptr;
     94 
     95         if (ptr + sizeof(xXIDeviceInfo) > end)
     96             goto error_loop;
     97 
     98         lib->deviceid    = wire->deviceid;
     99         lib->use         = wire->use;
    100         lib->attachment  = wire->attachment;
    101         lib->enabled     = wire->enabled;
    102         nclasses         = wire->num_classes;
    103 
    104         ptr += sizeof(xXIDeviceInfo);
    105 
    106         if (ptr + wire->name_len > end)
    107             goto error_loop;
    108 
    109         lib->name = Xcalloc(wire->name_len + 1, 1);
    110         if (lib->name == NULL)
    111             goto error_loop;
    112         strncpy(lib->name, ptr, wire->name_len);
    113         lib->name[wire->name_len] = '\0';
    114         ptr += ((wire->name_len + 3)/4) * 4;
    115 
    116         sz = size_classes((xXIAnyInfo*)ptr, nclasses);
    117         lib->classes = Xmalloc(sz);
    118         if (lib->classes == NULL)
    119         {
    120             Xfree(lib->name);
    121             goto error_loop;
    122         }
    123         ptr += copy_classes(lib, (xXIAnyInfo*)ptr, &nclasses);
    124         /* We skip over unused classes */
    125         lib->num_classes = nclasses;
    126     }
    127 
    128     Xfree(buf);
    129     UnlockDisplay(dpy);
    130     SyncHandle();
    131     return info;
    132 
    133 error_loop:
    134     while (--i >= 0)
    135     {
    136         Xfree(info[i].name);
    137         Xfree(info[i].classes);
    138     }
    139 error:
    140     Xfree(info);
    141     Xfree(buf);
    142     UnlockDisplay(dpy);
    143 error_unlocked:
    144     SyncHandle();
    145     *ndevices_return = -1;
    146     return NULL;
    147 }
    148 
    149 void
    150 XIFreeDeviceInfo(XIDeviceInfo* info)
    151 {
    152     XIDeviceInfo *ptr = info;
    153     while(ptr && ptr->name)
    154     {
    155         Xfree(ptr->classes);
    156         Xfree(ptr->name);
    157         ptr++;
    158     }
    159     Xfree(info);
    160 }
    161