xiselectev.c revision 9ace9065
1/*
2 * Copyright 2008 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 * Author: Peter Hutterer
24 */
25
26#ifdef HAVE_DIX_CONFIG_H
27#include <dix-config.h>
28#endif
29
30
31#include "dixstruct.h"
32#include "windowstr.h"
33#include "exglobals.h"
34#include "exevents.h"
35#include <X11/extensions/XI2proto.h>
36
37#include "xiselectev.h"
38
39/**
40 * Check the given mask (in len bytes) for invalid mask bits.
41 * Invalid mask bits are any bits above XI2LastEvent.
42 *
43 * @return BadValue if at least one invalid bit is set or Success otherwise.
44 */
45int XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len)
46{
47    if (len >= XIMaskLen(XI2LASTEVENT))
48    {
49        int i;
50        for (i = XI2LASTEVENT + 1; i < len * 8; i++)
51        {
52            if (BitIsOn(mask, i))
53            {
54                client->errorValue = i;
55                return BadValue;
56            }
57        }
58    }
59
60    return Success;
61}
62
63int
64SProcXISelectEvents(ClientPtr client)
65{
66    char n;
67    int i;
68    xXIEventMask* evmask;
69
70    REQUEST(xXISelectEventsReq);
71    swaps(&stuff->length, n);
72    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
73    swapl(&stuff->win, n);
74    swaps(&stuff->num_masks, n);
75
76    evmask = (xXIEventMask*)&stuff[1];
77    for (i = 0; i < stuff->num_masks; i++)
78    {
79        swaps(&evmask->deviceid, n);
80        swaps(&evmask->mask_len, n);
81        evmask = (xXIEventMask*)(((char*)&evmask[1]) + evmask->mask_len * 4);
82    }
83
84    return (ProcXISelectEvents(client));
85}
86
87int
88ProcXISelectEvents(ClientPtr client)
89{
90    int rc, num_masks;
91    WindowPtr win;
92    DeviceIntPtr dev;
93    DeviceIntRec dummy;
94    xXIEventMask *evmask;
95    int *types = NULL;
96    int len;
97
98    REQUEST(xXISelectEventsReq);
99    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
100
101    if (stuff->num_masks == 0)
102        return BadValue;
103
104    rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess);
105    if (rc != Success)
106        return rc;
107
108    len = sz_xXISelectEventsReq;
109
110    /* check request validity */
111    evmask = (xXIEventMask*)&stuff[1];
112    num_masks = stuff->num_masks;
113    while(num_masks--)
114    {
115        len += sizeof(xXIEventMask) + evmask->mask_len * 4;
116
117        if (bytes_to_int32(len) > stuff->length)
118            return BadLength;
119
120        if (evmask->deviceid != XIAllDevices &&
121            evmask->deviceid != XIAllMasterDevices)
122            rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
123        else {
124            /* XXX: XACE here? */
125        }
126        if (rc != Success)
127            return rc;
128
129        /* hierarchy event mask is not allowed on devices */
130        if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1)
131        {
132            unsigned char *bits = (unsigned char*)&evmask[1];
133            if (BitIsOn(bits, XI_HierarchyChanged))
134            {
135                client->errorValue = XI_HierarchyChanged;
136                return BadValue;
137            }
138        }
139
140        /* Raw events may only be selected on root windows */
141        if (win->parent && evmask->mask_len >= 1)
142        {
143            unsigned char *bits = (unsigned char*)&evmask[1];
144            if (BitIsOn(bits, XI_RawKeyPress) ||
145                BitIsOn(bits, XI_RawKeyRelease) ||
146                BitIsOn(bits, XI_RawButtonPress) ||
147                BitIsOn(bits, XI_RawButtonRelease) ||
148                BitIsOn(bits, XI_RawMotion))
149            {
150                client->errorValue = XI_RawKeyPress;
151                return BadValue;
152            }
153        }
154
155        if (XICheckInvalidMaskBits(client, (unsigned char*)&evmask[1],
156                                   evmask->mask_len * 4) != Success)
157            return BadValue;
158
159        evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4);
160        evmask++;
161    }
162
163    if (bytes_to_int32(len) != stuff->length)
164        return BadLength;
165
166    /* Set masks on window */
167    evmask = (xXIEventMask*)&stuff[1];
168    num_masks = stuff->num_masks;
169    while(num_masks--)
170    {
171        if (evmask->deviceid == XIAllDevices ||
172            evmask->deviceid == XIAllMasterDevices)
173        {
174            dummy.id = evmask->deviceid;
175            dev = &dummy;
176        } else
177            dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
178        if (XISetEventMask(dev, win, client, evmask->mask_len * 4,
179                           (unsigned char*)&evmask[1]) != Success)
180            return BadAlloc;
181        evmask = (xXIEventMask*)(((unsigned char*)evmask) + evmask->mask_len * 4);
182        evmask++;
183    }
184
185    RecalculateDeliverableEvents(win);
186
187    free(types);
188    return Success;
189}
190
191
192int
193SProcXIGetSelectedEvents(ClientPtr client)
194{
195    char n;
196
197    REQUEST(xXIGetSelectedEventsReq);
198    swaps(&stuff->length, n);
199    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
200    swapl(&stuff->win, n);
201
202    return (ProcXIGetSelectedEvents(client));
203}
204
205int
206ProcXIGetSelectedEvents(ClientPtr client)
207{
208    int rc, i;
209    WindowPtr win;
210    char n;
211    char *buffer = NULL;
212    xXIGetSelectedEventsReply reply;
213    OtherInputMasks *masks;
214    InputClientsPtr others = NULL;
215    xXIEventMask *evmask = NULL;
216    DeviceIntPtr dev;
217
218    REQUEST(xXIGetSelectedEventsReq);
219    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
220
221    rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess);
222    if (rc != Success)
223        return rc;
224
225    reply.repType = X_Reply;
226    reply.RepType = X_XIGetSelectedEvents;
227    reply.length = 0;
228    reply.sequenceNumber = client->sequence;
229    reply.num_masks = 0;
230
231    masks = wOtherInputMasks(win);
232    if (masks)
233    {
234	for (others = wOtherInputMasks(win)->inputClients; others;
235	     others = others->next) {
236	    if (SameClient(others, client)) {
237                break;
238            }
239        }
240    }
241
242    if (!others)
243    {
244        WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
245        return Success;
246    }
247
248    buffer = calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE));
249    if (!buffer)
250        return BadAlloc;
251
252    evmask = (xXIEventMask*)buffer;
253    for (i = 0; i < MAXDEVICES; i++)
254    {
255        int j;
256        unsigned char *devmask = others->xi2mask[i];
257
258        if (i > 2)
259        {
260            rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess);
261            if (rc != Success)
262                continue;
263        }
264
265
266        for (j = XI2MASKSIZE - 1; j >= 0; j--)
267        {
268            if (devmask[j] != 0)
269            {
270                int mask_len = (j + 4)/4; /* j is an index, hence + 4, not + 3 */
271                evmask->deviceid = i;
272                evmask->mask_len = mask_len;
273                reply.num_masks++;
274                reply.length += sizeof(xXIEventMask)/4 + evmask->mask_len;
275
276                if (client->swapped)
277                {
278                    swaps(&evmask->deviceid, n);
279                    swaps(&evmask->mask_len, n);
280                }
281
282                memcpy(&evmask[1], devmask, j + 1);
283                evmask = (xXIEventMask*)((char*)evmask +
284                           sizeof(xXIEventMask) + mask_len * 4);
285                break;
286            }
287        }
288    }
289
290    WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
291
292    if (reply.num_masks)
293        WriteToClient(client, reply.length * 4, buffer);
294
295    free(buffer);
296    return Success;
297}
298
299void SRepXIGetSelectedEvents(ClientPtr client,
300                            int len, xXIGetSelectedEventsReply *rep)
301{
302    char n;
303
304    swaps(&rep->sequenceNumber, n);
305    swapl(&rep->length, n);
306    swaps(&rep->num_masks, n);
307    WriteToClient(client, len, (char *)rep);
308}
309
310
311