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