XISelEv.c revision 10baa824
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;
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);
117    SyncHandle();
118    return r;
119
120}
121
122XIEventMask*
123XIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return)
124{
125    unsigned int i, len = 0;
126    unsigned char *mask;
127    XIEventMask *mask_out = NULL;
128    xXIEventMask *mask_in = NULL, *mi;
129    xXIGetSelectedEventsReq *req;
130    xXIGetSelectedEventsReply reply;
131    XExtDisplayInfo *info = XInput_find_display(dpy);
132    size_t rbytes;
133
134    *num_masks_return = -1;
135    LockDisplay(dpy);
136    if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1)
137        goto out;
138
139    GetReq(XIGetSelectedEvents, req);
140
141    req->reqType = info->codes->major_opcode;
142    req->ReqType = X_XIGetSelectedEvents;
143    req->win = win;
144
145    if (!_XReply(dpy, (xReply *) &reply, 0, xFalse))
146        goto out;
147
148    if (reply.num_masks == 0)
149    {
150        *num_masks_return = 0;
151        goto out;
152    }
153
154    if (reply.length < (INT_MAX >> 2)) {
155        rbytes = (unsigned long) reply.length << 2;
156        mask_in = Xmalloc(rbytes);
157    }
158    if (!mask_in) {
159        _XEatDataWords(dpy, reply.length);
160        goto out;
161    }
162
163    _XRead(dpy, (char*)mask_in, rbytes);
164
165    /*
166     * This function takes interleaved xXIEventMask structs & masks off
167     * the wire, such as this 3 mask reply:
168     *   [struct a][masks a][struct b][masks b][struct c][masks c]
169     * And generates a memory buffer to be returned to callers in which
170     * they are not interleaved, so that callers can treat the returned
171     * pointer as a simple array of XIEventMask structs, such as:
172     *   [struct a][struct b][struct c][masks a][masks b][masks c]
173     */
174    len = reply.num_masks * sizeof(XIEventMask);
175
176    for (i = 0, mi = mask_in; i < reply.num_masks; i++)
177    {
178        unsigned int mask_bytes = mi->mask_len * 4;
179        len += mask_bytes;
180        if (len > INT_MAX)
181            goto out;
182        if ((sizeof(xXIEventMask) + mask_bytes) > rbytes)
183            goto out;
184        rbytes -= (sizeof(xXIEventMask) + mask_bytes);
185        mi = (xXIEventMask*)((char*)mi + mask_bytes);
186        mi++;
187    }
188
189    mask_out = Xmalloc(len);
190    if (!mask_out)
191        goto out;
192
193    mi = mask_in;
194    mask = (unsigned char*)&mask_out[reply.num_masks];
195    for (i = 0; i < reply.num_masks; i++)
196    {
197        mask_out[i].deviceid = mi->deviceid;
198        mask_out[i].mask_len = mi->mask_len * 4;
199        mask_out[i].mask = mask;
200        memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len);
201        mask += mask_out[i].mask_len;
202        mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4);
203        mi++;
204    }
205
206    *num_masks_return = reply.num_masks;
207
208out:
209    Xfree(mask_in);
210
211    UnlockDisplay(dpy);
212    SyncHandle();
213
214    return mask_out;
215}
216