XISelEv.c revision 64276682
1/************************************************************
2
3Copyright 2009 Red Hat, Inc.
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of the author shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in 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
47int
48XISelectEvents(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);
115out:
116    UnlockDisplay(dpy);
117out_unlocked:
118    SyncHandle();
119    return r;
120
121}
122
123XIEventMask*
124XIGetSelectedEvents(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
209out:
210    Xfree(mask_in);
211
212    UnlockDisplay(dpy);
213
214out_unlocked:
215    SyncHandle();
216
217    return mask_out;
218}
219