1c27c18e8Smrg/************************************************************
2c27c18e8Smrg
3c27c18e8SmrgCopyright 2009 Red Hat, Inc.
4c27c18e8Smrg
5c27c18e8SmrgPermission to use, copy, modify, distribute, and sell this software and its
6c27c18e8Smrgdocumentation for any purpose is hereby granted without fee, provided that
7c27c18e8Smrgthe above copyright notice appear in all copies and that both that
8c27c18e8Smrgcopyright notice and this permission notice appear in supporting
9c27c18e8Smrgdocumentation.
10c27c18e8Smrg
11c27c18e8SmrgThe above copyright notice and this permission notice shall be included in
12c27c18e8Smrgall copies or substantial portions of the Software.
13c27c18e8Smrg
14c27c18e8SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c27c18e8SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c27c18e8SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17c27c18e8SmrgAUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18c27c18e8SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19c27c18e8SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20c27c18e8Smrg
21c27c18e8SmrgExcept as contained in this notice, the name of the author shall not be
22c27c18e8Smrgused in advertising or otherwise to promote the sale, use or other dealings
23c27c18e8Smrgin this Software without prior written authorization from the author.
24c27c18e8Smrg
25c27c18e8Smrg*/
26c27c18e8Smrg
27c27c18e8Smrg/***********************************************************************
28c27c18e8Smrg *
29c27c18e8Smrg * XISelectEvent - Select for XI2 events.
30c27c18e8Smrg *
31c27c18e8Smrg */
32c27c18e8Smrg
33f1ee322dSmrg#ifdef HAVE_CONFIG_H
34f1ee322dSmrg#include <config.h>
35f1ee322dSmrg#endif
36c27c18e8Smrg
37c27c18e8Smrg#include <stdint.h>
38c27c18e8Smrg#include <X11/Xlibint.h>
39c27c18e8Smrg#include <X11/extensions/XI2proto.h>
40c27c18e8Smrg#include <X11/extensions/XInput2.h>
41c27c18e8Smrg#include <X11/extensions/extutil.h>
42c27c18e8Smrg#include <X11/extensions/ge.h>
43c27c18e8Smrg#include <X11/extensions/geproto.h>
44c27c18e8Smrg#include "XIint.h"
45190694daSmrg#include <limits.h>
46c27c18e8Smrg
47c27c18e8Smrgint
48c27c18e8SmrgXISelectEvents(Display* dpy, Window win, XIEventMask* masks, int num_masks)
49c27c18e8Smrg{
50c27c18e8Smrg    XIEventMask  *current;
51c27c18e8Smrg    xXISelectEventsReq  *req;
52c27c18e8Smrg    xXIEventMask mask;
53c27c18e8Smrg    int i;
54c27c18e8Smrg    int len = 0;
553e256790Smrg    int r = Success;
5610baa824Smrg    int max_mask_len = 0;
5710baa824Smrg    char *buff;
58c27c18e8Smrg
59c27c18e8Smrg    XExtDisplayInfo *info = XInput_find_display(dpy);
60c27c18e8Smrg    LockDisplay(dpy);
61b789ec8aSmrg    if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1) {
623e256790Smrg        r = NoSuchExtension;
6364276682Smrg        goto out_unlocked;
643e256790Smrg    }
6510baa824Smrg
6610baa824Smrg    for (i = 0; i < num_masks; i++) {
6710baa824Smrg        current = &masks[i];
6810baa824Smrg        if (current->mask_len > INT_MAX - 3 ||
6910baa824Smrg            (current->mask_len + 3)/4 >= 0xffff) {
7010baa824Smrg            r = -1;
7110baa824Smrg            goto out;
7210baa824Smrg        }
7310baa824Smrg        if (current->mask_len > max_mask_len)
7410baa824Smrg            max_mask_len = current->mask_len;
7510baa824Smrg    }
7610baa824Smrg
7710baa824Smrg    /* max_mask_len is in bytes, but we need 4-byte units on the wire,
7810baa824Smrg     * and they need to be padded with 0 */
7910baa824Smrg    buff = calloc(4, ((max_mask_len + 3)/4));
8010baa824Smrg    if (!buff) {
8110baa824Smrg        r = -1;
8210baa824Smrg        goto out;
8310baa824Smrg    }
8410baa824Smrg
85c27c18e8Smrg    GetReq(XISelectEvents, req);
86c27c18e8Smrg
87c27c18e8Smrg    req->reqType = info->codes->major_opcode;
88c27c18e8Smrg    req->ReqType = X_XISelectEvents;
89c27c18e8Smrg    req->win = win;
90c27c18e8Smrg    req->num_masks = num_masks;
91c27c18e8Smrg
92c27c18e8Smrg    /* get the right length */
93c27c18e8Smrg    for (i = 0; i < num_masks; i++)
94c27c18e8Smrg    {
95c27c18e8Smrg        len++;
96c27c18e8Smrg        current = &masks[i];
97c27c18e8Smrg        len += (current->mask_len + 3)/4;
98c27c18e8Smrg    }
99c27c18e8Smrg
100c27c18e8Smrg    SetReqLen(req, len, len);
101c27c18e8Smrg
102c27c18e8Smrg    for (i = 0; i < num_masks; i++)
103c27c18e8Smrg    {
104c27c18e8Smrg        current = &masks[i];
105c27c18e8Smrg        mask.deviceid = current->deviceid;
106c27c18e8Smrg        mask.mask_len = (current->mask_len + 3)/4;
10710baa824Smrg
10810baa824Smrg        memset(buff, 0, max_mask_len);
109c27c18e8Smrg        memcpy(buff, current->mask, current->mask_len);
110b789ec8aSmrg        Data(dpy, (char*)&mask, sizeof(xXIEventMask));
111c27c18e8Smrg        Data(dpy, buff, mask.mask_len * 4);
112c27c18e8Smrg    }
113c27c18e8Smrg
11410baa824Smrg    free(buff);
1153e256790Smrgout:
116c27c18e8Smrg    UnlockDisplay(dpy);
11764276682Smrgout_unlocked:
118c27c18e8Smrg    SyncHandle();
1193e256790Smrg    return r;
120c27c18e8Smrg
121c27c18e8Smrg}
122c27c18e8Smrg
123c27c18e8SmrgXIEventMask*
124c27c18e8SmrgXIGetSelectedEvents(Display* dpy, Window win, int *num_masks_return)
125c27c18e8Smrg{
126190694daSmrg    unsigned int i, len = 0;
127c27c18e8Smrg    unsigned char *mask;
128c27c18e8Smrg    XIEventMask *mask_out = NULL;
129c27c18e8Smrg    xXIEventMask *mask_in = NULL, *mi;
130c27c18e8Smrg    xXIGetSelectedEventsReq *req;
131c27c18e8Smrg    xXIGetSelectedEventsReply reply;
13237eb1ca1Smrg    XExtDisplayInfo *info = XInput_find_display(dpy);
133190694daSmrg    size_t rbytes;
134c27c18e8Smrg
1353e256790Smrg    *num_masks_return = -1;
136c27c18e8Smrg    LockDisplay(dpy);
137b789ec8aSmrg    if (_XiCheckExtInit(dpy, XInput_2_0, info) == -1)
13864276682Smrg        goto out_unlocked;
139c27c18e8Smrg
140c27c18e8Smrg    GetReq(XIGetSelectedEvents, req);
141c27c18e8Smrg
142c27c18e8Smrg    req->reqType = info->codes->major_opcode;
143c27c18e8Smrg    req->ReqType = X_XIGetSelectedEvents;
144c27c18e8Smrg    req->win = win;
145c27c18e8Smrg
146c27c18e8Smrg    if (!_XReply(dpy, (xReply *) &reply, 0, xFalse))
1473e256790Smrg        goto out;
148c27c18e8Smrg
149c27c18e8Smrg    if (reply.num_masks == 0)
150c27c18e8Smrg    {
151c27c18e8Smrg        *num_masks_return = 0;
1523e256790Smrg        goto out;
153c27c18e8Smrg    }
154c27c18e8Smrg
155190694daSmrg    if (reply.length < (INT_MAX >> 2)) {
156190694daSmrg        rbytes = (unsigned long) reply.length << 2;
157190694daSmrg        mask_in = Xmalloc(rbytes);
158190694daSmrg    }
159190694daSmrg    if (!mask_in) {
160190694daSmrg        _XEatDataWords(dpy, reply.length);
1613e256790Smrg        goto out;
162190694daSmrg    }
163c27c18e8Smrg
164190694daSmrg    _XRead(dpy, (char*)mask_in, rbytes);
165c27c18e8Smrg
16610baa824Smrg    /*
16710baa824Smrg     * This function takes interleaved xXIEventMask structs & masks off
16810baa824Smrg     * the wire, such as this 3 mask reply:
16910baa824Smrg     *   [struct a][masks a][struct b][masks b][struct c][masks c]
17010baa824Smrg     * And generates a memory buffer to be returned to callers in which
17110baa824Smrg     * they are not interleaved, so that callers can treat the returned
17210baa824Smrg     * pointer as a simple array of XIEventMask structs, such as:
17310baa824Smrg     *   [struct a][struct b][struct c][masks a][masks b][masks c]
174c27c18e8Smrg     */
175c27c18e8Smrg    len = reply.num_masks * sizeof(XIEventMask);
176c27c18e8Smrg
177c27c18e8Smrg    for (i = 0, mi = mask_in; i < reply.num_masks; i++)
178c27c18e8Smrg    {
179190694daSmrg        unsigned int mask_bytes = mi->mask_len * 4;
180190694daSmrg        len += mask_bytes;
181190694daSmrg        if (len > INT_MAX)
182190694daSmrg            goto out;
183190694daSmrg        if ((sizeof(xXIEventMask) + mask_bytes) > rbytes)
184190694daSmrg            goto out;
185190694daSmrg        rbytes -= (sizeof(xXIEventMask) + mask_bytes);
186190694daSmrg        mi = (xXIEventMask*)((char*)mi + mask_bytes);
187c27c18e8Smrg        mi++;
188c27c18e8Smrg    }
189c27c18e8Smrg
190c27c18e8Smrg    mask_out = Xmalloc(len);
191c27c18e8Smrg    if (!mask_out)
1923e256790Smrg        goto out;
193c27c18e8Smrg
194c27c18e8Smrg    mi = mask_in;
195c27c18e8Smrg    mask = (unsigned char*)&mask_out[reply.num_masks];
196c27c18e8Smrg    for (i = 0; i < reply.num_masks; i++)
197c27c18e8Smrg    {
198c27c18e8Smrg        mask_out[i].deviceid = mi->deviceid;
199c27c18e8Smrg        mask_out[i].mask_len = mi->mask_len * 4;
200c27c18e8Smrg        mask_out[i].mask = mask;
201c27c18e8Smrg        memcpy(mask_out[i].mask, &mi[1], mask_out[i].mask_len);
202c27c18e8Smrg        mask += mask_out[i].mask_len;
203c27c18e8Smrg        mi = (xXIEventMask*)((char*)mi + mi->mask_len * 4);
204c27c18e8Smrg        mi++;
205c27c18e8Smrg    }
206c27c18e8Smrg
207c27c18e8Smrg    *num_masks_return = reply.num_masks;
208c27c18e8Smrg
2093e256790Smrgout:
2103e256790Smrg    Xfree(mask_in);
211c27c18e8Smrg
212c27c18e8Smrg    UnlockDisplay(dpy);
21364276682Smrg
21464276682Smrgout_unlocked:
215c27c18e8Smrg    SyncHandle();
216c27c18e8Smrg
2173e256790Smrg    return mask_out;
218c27c18e8Smrg}
219