xiselectev.c revision 7e31ba66
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#include "dixstruct.h"
31#include "windowstr.h"
32#include "exglobals.h"
33#include "exevents.h"
34#include <X11/extensions/XI2proto.h>
35#include "inpututils.h"
36
37#include "xiselectev.h"
38
39/**
40 * Ruleset:
41 * - if A has XIAllDevices, B may select on device X
42 * - If A has XIAllDevices, B may select on XIAllMasterDevices
43 * - If A has XIAllMasterDevices, B may select on device X
44 * - If A has XIAllMasterDevices, B may select on XIAllDevices
45 * - if A has device X, B may select on XIAllDevices/XIAllMasterDevices
46 */
47static int check_for_touch_selection_conflicts(ClientPtr B, WindowPtr win, int deviceid)
48{
49    OtherInputMasks *inputMasks = wOtherInputMasks(win);
50    InputClients *A = NULL;
51
52    if (inputMasks)
53        A = inputMasks->inputClients;
54    for (; A; A = A->next) {
55        DeviceIntPtr tmp;
56
57        if (CLIENT_ID(A->resource) == B->index)
58            continue;
59
60        if (deviceid == XIAllDevices)
61            tmp = inputInfo.all_devices;
62        else if (deviceid == XIAllMasterDevices)
63            tmp = inputInfo.all_master_devices;
64        else
65            dixLookupDevice(&tmp, deviceid, serverClient, DixReadAccess);
66        if (!tmp)
67            return BadImplementation;       /* this shouldn't happen */
68
69        /* A has XIAllDevices */
70        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_devices, XI_TouchBegin)) {
71            if (deviceid == XIAllDevices)
72                return BadAccess;
73        }
74
75        /* A has XIAllMasterDevices */
76        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_master_devices, XI_TouchBegin)) {
77            if (deviceid == XIAllMasterDevices)
78                return BadAccess;
79        }
80
81        /* A has this device */
82        if (xi2mask_isset_for_device(A->xi2mask, tmp, XI_TouchBegin))
83            return BadAccess;
84    }
85
86    return Success;
87}
88
89
90/**
91 * Check the given mask (in len bytes) for invalid mask bits.
92 * Invalid mask bits are any bits above XI2LastEvent.
93 *
94 * @return BadValue if at least one invalid bit is set or Success otherwise.
95 */
96int
97XICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len)
98{
99    if (len >= XIMaskLen(XI2LASTEVENT)) {
100        int i;
101
102        for (i = XI2LASTEVENT + 1; i < len * 8; i++) {
103            if (BitIsOn(mask, i)) {
104                client->errorValue = i;
105                return BadValue;
106            }
107        }
108    }
109
110    return Success;
111}
112
113int _X_COLD
114SProcXISelectEvents(ClientPtr client)
115{
116    int i;
117    int len;
118    xXIEventMask *evmask;
119
120    REQUEST(xXISelectEventsReq);
121    swaps(&stuff->length);
122    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
123    swapl(&stuff->win);
124    swaps(&stuff->num_masks);
125
126    len = stuff->length - bytes_to_int32(sizeof(xXISelectEventsReq));
127    evmask = (xXIEventMask *) &stuff[1];
128    for (i = 0; i < stuff->num_masks; i++) {
129        if (len < bytes_to_int32(sizeof(xXIEventMask)))
130            return BadLength;
131        len -= bytes_to_int32(sizeof(xXIEventMask));
132        swaps(&evmask->deviceid);
133        swaps(&evmask->mask_len);
134        if (len < evmask->mask_len)
135            return BadLength;
136        len -= evmask->mask_len;
137        evmask =
138            (xXIEventMask *) (((char *) &evmask[1]) + evmask->mask_len * 4);
139    }
140
141    return (ProcXISelectEvents(client));
142}
143
144int
145ProcXISelectEvents(ClientPtr client)
146{
147    int rc, num_masks;
148    WindowPtr win;
149    DeviceIntPtr dev;
150    DeviceIntRec dummy;
151    xXIEventMask *evmask;
152    int *types = NULL;
153    int len;
154
155    REQUEST(xXISelectEventsReq);
156    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
157
158    if (stuff->num_masks == 0)
159        return BadValue;
160
161    rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess);
162    if (rc != Success)
163        return rc;
164
165    len = sz_xXISelectEventsReq;
166
167    /* check request validity */
168    evmask = (xXIEventMask *) &stuff[1];
169    num_masks = stuff->num_masks;
170    while (num_masks--) {
171        len += sizeof(xXIEventMask) + evmask->mask_len * 4;
172
173        if (bytes_to_int32(len) > stuff->length)
174            return BadLength;
175
176        if (evmask->deviceid != XIAllDevices &&
177            evmask->deviceid != XIAllMasterDevices)
178            rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
179        else {
180            /* XXX: XACE here? */
181        }
182        if (rc != Success)
183            return rc;
184
185        /* hierarchy event mask is not allowed on devices */
186        if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) {
187            unsigned char *bits = (unsigned char *) &evmask[1];
188
189            if (BitIsOn(bits, XI_HierarchyChanged)) {
190                client->errorValue = XI_HierarchyChanged;
191                return BadValue;
192            }
193        }
194
195        /* Raw events may only be selected on root windows */
196        if (win->parent && evmask->mask_len >= 1) {
197            unsigned char *bits = (unsigned char *) &evmask[1];
198
199            if (BitIsOn(bits, XI_RawKeyPress) ||
200                BitIsOn(bits, XI_RawKeyRelease) ||
201                BitIsOn(bits, XI_RawButtonPress) ||
202                BitIsOn(bits, XI_RawButtonRelease) ||
203                BitIsOn(bits, XI_RawMotion) ||
204                BitIsOn(bits, XI_RawTouchBegin) ||
205                BitIsOn(bits, XI_RawTouchUpdate) ||
206                BitIsOn(bits, XI_RawTouchEnd)) {
207                client->errorValue = XI_RawKeyPress;
208                return BadValue;
209            }
210        }
211
212        if (evmask->mask_len >= 1) {
213            unsigned char *bits = (unsigned char *) &evmask[1];
214
215            /* All three touch events must be selected at once */
216            if ((BitIsOn(bits, XI_TouchBegin) ||
217                 BitIsOn(bits, XI_TouchUpdate) ||
218                 BitIsOn(bits, XI_TouchOwnership) ||
219                 BitIsOn(bits, XI_TouchEnd)) &&
220                (!BitIsOn(bits, XI_TouchBegin) ||
221                 !BitIsOn(bits, XI_TouchUpdate) ||
222                 !BitIsOn(bits, XI_TouchEnd))) {
223                client->errorValue = XI_TouchBegin;
224                return BadValue;
225            }
226
227            /* Only one client per window may select for touch events on the
228             * same devices, including master devices.
229             * XXX: This breaks if a device goes from floating to attached. */
230            if (BitIsOn(bits, XI_TouchBegin)) {
231                rc = check_for_touch_selection_conflicts(client,
232                                                         win,
233                                                         evmask->deviceid);
234                if (rc != Success)
235                    return rc;
236            }
237        }
238
239        if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],
240                                   evmask->mask_len * 4) != Success)
241            return BadValue;
242
243        evmask =
244            (xXIEventMask *) (((unsigned char *) evmask) +
245                              evmask->mask_len * 4);
246        evmask++;
247    }
248
249    if (bytes_to_int32(len) != stuff->length)
250        return BadLength;
251
252    /* Set masks on window */
253    evmask = (xXIEventMask *) &stuff[1];
254    num_masks = stuff->num_masks;
255    while (num_masks--) {
256        if (evmask->deviceid == XIAllDevices ||
257            evmask->deviceid == XIAllMasterDevices) {
258            dummy.id = evmask->deviceid;
259            dev = &dummy;
260        }
261        else
262            dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
263        if (XISetEventMask(dev, win, client, evmask->mask_len * 4,
264                           (unsigned char *) &evmask[1]) != Success)
265            return BadAlloc;
266        evmask =
267            (xXIEventMask *) (((unsigned char *) evmask) +
268                              evmask->mask_len * 4);
269        evmask++;
270    }
271
272    RecalculateDeliverableEvents(win);
273
274    free(types);
275    return Success;
276}
277
278int _X_COLD
279SProcXIGetSelectedEvents(ClientPtr client)
280{
281    REQUEST(xXIGetSelectedEventsReq);
282    swaps(&stuff->length);
283    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
284    swapl(&stuff->win);
285
286    return (ProcXIGetSelectedEvents(client));
287}
288
289int
290ProcXIGetSelectedEvents(ClientPtr client)
291{
292    int rc, i;
293    WindowPtr win;
294    char *buffer = NULL;
295    xXIGetSelectedEventsReply reply;
296    OtherInputMasks *masks;
297    InputClientsPtr others = NULL;
298    xXIEventMask *evmask = NULL;
299    DeviceIntPtr dev;
300
301    REQUEST(xXIGetSelectedEventsReq);
302    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
303
304    rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess);
305    if (rc != Success)
306        return rc;
307
308    reply = (xXIGetSelectedEventsReply) {
309        .repType = X_Reply,
310        .RepType = X_XIGetSelectedEvents,
311        .sequenceNumber = client->sequence,
312        .length = 0,
313        .num_masks = 0
314    };
315
316    masks = wOtherInputMasks(win);
317    if (masks) {
318        for (others = wOtherInputMasks(win)->inputClients; others;
319             others = others->next) {
320            if (SameClient(others, client)) {
321                break;
322            }
323        }
324    }
325
326    if (!others) {
327        WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
328        return Success;
329    }
330
331    buffer =
332        calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE));
333    if (!buffer)
334        return BadAlloc;
335
336    evmask = (xXIEventMask *) buffer;
337    for (i = 0; i < MAXDEVICES; i++) {
338        int j;
339        const unsigned char *devmask = xi2mask_get_one_mask(others->xi2mask, i);
340
341        if (i > 2) {
342            rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess);
343            if (rc != Success)
344                continue;
345        }
346
347        for (j = xi2mask_mask_size(others->xi2mask) - 1; j >= 0; j--) {
348            if (devmask[j] != 0) {
349                int mask_len = (j + 4) / 4;     /* j is an index, hence + 4, not + 3 */
350
351                evmask->deviceid = i;
352                evmask->mask_len = mask_len;
353                reply.num_masks++;
354                reply.length += sizeof(xXIEventMask) / 4 + evmask->mask_len;
355
356                if (client->swapped) {
357                    swaps(&evmask->deviceid);
358                    swaps(&evmask->mask_len);
359                }
360
361                memcpy(&evmask[1], devmask, j + 1);
362                evmask = (xXIEventMask *) ((char *) evmask +
363                                           sizeof(xXIEventMask) + mask_len * 4);
364                break;
365            }
366        }
367    }
368
369    WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
370
371    if (reply.num_masks)
372        WriteToClient(client, reply.length * 4, buffer);
373
374    free(buffer);
375    return Success;
376}
377
378void
379SRepXIGetSelectedEvents(ClientPtr client,
380                        int len, xXIGetSelectedEventsReply * rep)
381{
382    swaps(&rep->sequenceNumber);
383    swapl(&rep->length);
384    swaps(&rep->num_masks);
385    WriteToClient(client, len, rep);
386}
387