Home | History | Annotate | Line # | Download | only in src
      1 /************************************************************
      2 
      3 Copyright 2009 Red Hat, Inc.
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of the author shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from the author.
     24 
     25 */
     26 
     27 /***********************************************************************
     28  *
     29  * XISelectEvent - Select for XI2 events.
     30  *
     31  */
     32 
     33 #ifdef HAVE_CONFIG_H
     34 #include <config.h>
     35 #endif
     36 
     37 #include <stdint.h>
     38 #include <X11/Xlibint.h>
     39 #include <X11/extensions/XI2proto.h>
     40 #include <X11/extensions/XInput2.h>
     41 #include <X11/extensions/extutil.h>
     42 #include <X11/extensions/ge.h>
     43 #include <X11/extensions/geproto.h>
     44 #include "XIint.h"
     45 #include <limits.h>
     46 
     47 int
     48 XISelectEvents(Display* dpy, Window win, XIEventMask* masks, int num_masks)
     49 {
     50     XIEventMask  *current;
     51     xXISelectEventsReq  *req;
     52     xXIEventMask mask;
     53     int i;
     54     int len = 0;
     55     int r = Success;
     56     int max_mask_len = 0;
     57     char *buff;
     58 
     59     XExtDisplayInfo *info = XInput_find_display(dpy);
     60     LockDisplay(dpy);
     61     if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) {
     62         r = NoSuchExtension;
     63         goto out_unlocked;
     64     }
     65 
     66     for (i = 0; i < num_masks; i++) {
     67         current = &masks[i];
     68         if (current->mask_len > INT_MAX - 3 ||
     69             (current->mask_len + 3)/4 >= 0xffff) {
     70             r = -1;
     71             goto out;
     72         }
     73         if (current->mask_len > max_mask_len)
     74             max_mask_len = current->mask_len;
     75     }
     76 
     77     /* max_mask_len is in bytes, but we need 4-byte units on the wire,
     78      * and they need to be padded with 0 */
     79     buff = calloc(4, ((max_mask_len + 3)/4));
     80     if (!buff) {
     81         r = -1;
     82         goto out;
     83     }
     84 
     85     GetReq(XISelectEvents, req);
     86 
     87     req->reqType = info->codes->major_opcode;
     88     req->ReqType = X_XISelectEvents;
     89     req->win = win;
     90     req->num_masks = num_masks;
     91 
     92     /* get the right length */
     93     for (i = 0; i < num_masks; i++)
     94     {
     95         len++;
     96         current = &masks[i];
     97         len += (current->mask_len + 3)/4;
     98     }
     99 
    100     SetReqLen(req, len, len);
    101 
    102     for (i = 0; i < num_masks; i++)
    103     {
    104         current = &masks[i];
    105         mask.deviceid = current->deviceid;
    106         mask.mask_len = (current->mask_len + 3)/4;
    107 
    108         memset(buff, 0, max_mask_len);
    109         memcpy(buff, current->mask, current->mask_len);
    110         Data(dpy, (char*)&mask, sizeof(xXIEventMask));
    111         Data(dpy, buff, mask.mask_len * 4);
    112     }
    113 
    114     free(buff);
    115 out:
    116     UnlockDisplay(dpy);
    117 out_unlocked:
    118     SyncHandle();
    119     return r;
    120 
    121 }
    122 
    123 XIEventMask*
    124 XIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return)
    125 {
    126     unsigned int i, len = 0;
    127     unsigned char *mask;
    128     XIEventMask *mask_out = NULL;
    129     xXIEventMask *mask_in = NULL, *mi;
    130     xXIGetSelectedEventsReq *req;
    131     xXIGetSelectedEventsReply reply;
    132     XExtDisplayInfo *info = XInput_find_display(dpy);
    133     size_t rbytes;
    134 
    135     *num_masks_return = -1;
    136     LockDisplay(dpy);
    137     if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1)
    138         goto out_unlocked;
    139 
    140     GetReq(XIGetSelectedEvents, req);
    141 
    142     req->reqType = info->codes->major_opcode;
    143     req->ReqType = X_XIGetSelectedEvents;
    144     req->win = win;
    145 
    146     if (!_XReply(dpy, (xReply *) &reply, 0, xFalse))
    147         goto out;
    148 
    149     if (reply.num_masks == 0)
    150     {
    151         *num_masks_return = 0;
    152         goto out;
    153     }
    154 
    155     if (reply.length < (INT_MAX >> 2)) {
    156         rbytes = (unsigned long) reply.length << 2;
    157         mask_in = Xmalloc(rbytes);
    158     }
    159     if (!mask_in) {
    160         _XEatDataWords(dpy, reply.length);
    161         goto out;
    162     }
    163 
    164     _XRead(dpy, (char*)mask_in, rbytes);
    165 
    166     /*
    167      * This function takes interleaved xXIEventMask structs & masks off
    168      * the wire, such as this 3 mask reply:
    169      *   [struct a][masks a][struct b][masks b][struct c][masks c]
    170      * And generates a memory buffer to be returned to callers in which
    171      * they are not interleaved, so that callers can treat the returned
    172      * pointer as a simple array of XIEventMask structs, such as:
    173      *   [struct a][struct b][struct c][masks a][masks b][masks c]
    174      */
    175     len = reply.num_masks * sizeof(XIEventMask);
    176 
    177     for (i = 0, mi = mask_in; i < reply.num_masks; i++)
    178     {
    179         unsigned int mask_bytes = mi->mask_len * 4;
    180         len += mask_bytes;
    181         if (len > INT_MAX)
    182             goto out;
    183         if ((sizeof(xXIEventMask) + mask_bytes) > rbytes)
    184             goto out;
    185         rbytes -= (sizeof(xXIEventMask) + mask_bytes);
    186         mi = (xXIEventMask*)((char*)mi + mask_bytes);
    187         mi++;
    188     }
    189 
    190     mask_out = Xmalloc(len);
    191     if (!mask_out)
    192         goto out;
    193 
    194     mi = mask_in;
    195     mask = (unsigned char*)&mask_out[reply.num_masks];
    196     for (i = 0; i < reply.num_masks; i++)
    197     {
    198         mask_out[i].deviceid = mi->deviceid;
    199         mask_out[i].mask_len = mi->mask_len * 4;
    200         mask_out[i].mask = mask;
    201         memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len);
    202         mask += mask_out[i].mask_len;
    203         mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4);
    204         mi++;
    205     }
    206 
    207     *num_masks_return = reply.num_masks;
    208 
    209 out:
    210     Xfree(mask_in);
    211 
    212     UnlockDisplay(dpy);
    213 
    214 out_unlocked:
    215     SyncHandle();
    216 
    217     return mask_out;
    218 }
    219