xiselectev.c revision 7e31ba66
16747b715Smrg/*
26747b715Smrg * Copyright 2008 Red Hat, Inc.
36747b715Smrg *
46747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
56747b715Smrg * copy of this software and associated documentation files (the "Software"),
66747b715Smrg * to deal in the Software without restriction, including without limitation
76747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
86747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
96747b715Smrg * Software is furnished to do so, subject to the following conditions:
106747b715Smrg *
116747b715Smrg * The above copyright notice and this permission notice (including the next
126747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
136747b715Smrg * Software.
146747b715Smrg *
156747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
206747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
216747b715Smrg * DEALINGS IN THE SOFTWARE.
226747b715Smrg *
236747b715Smrg * Author: Peter Hutterer
246747b715Smrg */
256747b715Smrg
266747b715Smrg#ifdef HAVE_DIX_CONFIG_H
276747b715Smrg#include <dix-config.h>
286747b715Smrg#endif
296747b715Smrg
306747b715Smrg#include "dixstruct.h"
316747b715Smrg#include "windowstr.h"
326747b715Smrg#include "exglobals.h"
336747b715Smrg#include "exevents.h"
346747b715Smrg#include <X11/extensions/XI2proto.h>
35f7df2e56Smrg#include "inpututils.h"
366747b715Smrg
376747b715Smrg#include "xiselectev.h"
386747b715Smrg
39f7df2e56Smrg/**
40f7df2e56Smrg * Ruleset:
41f7df2e56Smrg * - if A has XIAllDevices, B may select on device X
42f7df2e56Smrg * - If A has XIAllDevices, B may select on XIAllMasterDevices
43f7df2e56Smrg * - If A has XIAllMasterDevices, B may select on device X
44f7df2e56Smrg * - If A has XIAllMasterDevices, B may select on XIAllDevices
45f7df2e56Smrg * - if A has device X, B may select on XIAllDevices/XIAllMasterDevices
46f7df2e56Smrg */
47f7df2e56Smrgstatic int check_for_touch_selection_conflicts(ClientPtr B, WindowPtr win, int deviceid)
48f7df2e56Smrg{
49f7df2e56Smrg    OtherInputMasks *inputMasks = wOtherInputMasks(win);
50f7df2e56Smrg    InputClients *A = NULL;
51f7df2e56Smrg
52f7df2e56Smrg    if (inputMasks)
53f7df2e56Smrg        A = inputMasks->inputClients;
54f7df2e56Smrg    for (; A; A = A->next) {
55f7df2e56Smrg        DeviceIntPtr tmp;
56f7df2e56Smrg
57f7df2e56Smrg        if (CLIENT_ID(A->resource) == B->index)
58f7df2e56Smrg            continue;
59f7df2e56Smrg
60f7df2e56Smrg        if (deviceid == XIAllDevices)
61f7df2e56Smrg            tmp = inputInfo.all_devices;
62f7df2e56Smrg        else if (deviceid == XIAllMasterDevices)
63f7df2e56Smrg            tmp = inputInfo.all_master_devices;
64f7df2e56Smrg        else
65f7df2e56Smrg            dixLookupDevice(&tmp, deviceid, serverClient, DixReadAccess);
66f7df2e56Smrg        if (!tmp)
67f7df2e56Smrg            return BadImplementation;       /* this shouldn't happen */
68f7df2e56Smrg
69f7df2e56Smrg        /* A has XIAllDevices */
70f7df2e56Smrg        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_devices, XI_TouchBegin)) {
71f7df2e56Smrg            if (deviceid == XIAllDevices)
72f7df2e56Smrg                return BadAccess;
73f7df2e56Smrg        }
74f7df2e56Smrg
75f7df2e56Smrg        /* A has XIAllMasterDevices */
76f7df2e56Smrg        if (xi2mask_isset_for_device(A->xi2mask, inputInfo.all_master_devices, XI_TouchBegin)) {
77f7df2e56Smrg            if (deviceid == XIAllMasterDevices)
78f7df2e56Smrg                return BadAccess;
79f7df2e56Smrg        }
80f7df2e56Smrg
81f7df2e56Smrg        /* A has this device */
82f7df2e56Smrg        if (xi2mask_isset_for_device(A->xi2mask, tmp, XI_TouchBegin))
83f7df2e56Smrg            return BadAccess;
84f7df2e56Smrg    }
85f7df2e56Smrg
86f7df2e56Smrg    return Success;
87f7df2e56Smrg}
88f7df2e56Smrg
89f7df2e56Smrg
906747b715Smrg/**
916747b715Smrg * Check the given mask (in len bytes) for invalid mask bits.
926747b715Smrg * Invalid mask bits are any bits above XI2LastEvent.
936747b715Smrg *
946747b715Smrg * @return BadValue if at least one invalid bit is set or Success otherwise.
956747b715Smrg */
96f7df2e56Smrgint
97f7df2e56SmrgXICheckInvalidMaskBits(ClientPtr client, unsigned char *mask, int len)
986747b715Smrg{
99f7df2e56Smrg    if (len >= XIMaskLen(XI2LASTEVENT)) {
1006747b715Smrg        int i;
101f7df2e56Smrg
102f7df2e56Smrg        for (i = XI2LASTEVENT + 1; i < len * 8; i++) {
103f7df2e56Smrg            if (BitIsOn(mask, i)) {
1049ace9065Smrg                client->errorValue = i;
1056747b715Smrg                return BadValue;
1069ace9065Smrg            }
1079ace9065Smrg        }
1086747b715Smrg    }
1096747b715Smrg
1106747b715Smrg    return Success;
1116747b715Smrg}
1126747b715Smrg
1137e31ba66Smrgint _X_COLD
1146747b715SmrgSProcXISelectEvents(ClientPtr client)
1156747b715Smrg{
1166747b715Smrg    int i;
1170b0d8713Smrg    int len;
118f7df2e56Smrg    xXIEventMask *evmask;
1196747b715Smrg
1206747b715Smrg    REQUEST(xXISelectEventsReq);
121f7df2e56Smrg    swaps(&stuff->length);
1226747b715Smrg    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
123f7df2e56Smrg    swapl(&stuff->win);
124f7df2e56Smrg    swaps(&stuff->num_masks);
1256747b715Smrg
1260b0d8713Smrg    len = stuff->length - bytes_to_int32(sizeof(xXISelectEventsReq));
127f7df2e56Smrg    evmask = (xXIEventMask *) &stuff[1];
128f7df2e56Smrg    for (i = 0; i < stuff->num_masks; i++) {
1290b0d8713Smrg        if (len < bytes_to_int32(sizeof(xXIEventMask)))
1300b0d8713Smrg            return BadLength;
1310b0d8713Smrg        len -= bytes_to_int32(sizeof(xXIEventMask));
132f7df2e56Smrg        swaps(&evmask->deviceid);
133f7df2e56Smrg        swaps(&evmask->mask_len);
1340b0d8713Smrg        if (len < evmask->mask_len)
1350b0d8713Smrg            return BadLength;
1360b0d8713Smrg        len -= evmask->mask_len;
137f7df2e56Smrg        evmask =
138f7df2e56Smrg            (xXIEventMask *) (((char *) &evmask[1]) + evmask->mask_len * 4);
1396747b715Smrg    }
1406747b715Smrg
1416747b715Smrg    return (ProcXISelectEvents(client));
1426747b715Smrg}
1436747b715Smrg
1446747b715Smrgint
1456747b715SmrgProcXISelectEvents(ClientPtr client)
1466747b715Smrg{
1476747b715Smrg    int rc, num_masks;
1486747b715Smrg    WindowPtr win;
1496747b715Smrg    DeviceIntPtr dev;
1506747b715Smrg    DeviceIntRec dummy;
1516747b715Smrg    xXIEventMask *evmask;
1526747b715Smrg    int *types = NULL;
1536747b715Smrg    int len;
1546747b715Smrg
1556747b715Smrg    REQUEST(xXISelectEventsReq);
1566747b715Smrg    REQUEST_AT_LEAST_SIZE(xXISelectEventsReq);
1576747b715Smrg
1586747b715Smrg    if (stuff->num_masks == 0)
1596747b715Smrg        return BadValue;
1606747b715Smrg
1616747b715Smrg    rc = dixLookupWindow(&win, stuff->win, client, DixReceiveAccess);
1626747b715Smrg    if (rc != Success)
1636747b715Smrg        return rc;
1646747b715Smrg
1656747b715Smrg    len = sz_xXISelectEventsReq;
1666747b715Smrg
1676747b715Smrg    /* check request validity */
168f7df2e56Smrg    evmask = (xXIEventMask *) &stuff[1];
1696747b715Smrg    num_masks = stuff->num_masks;
170f7df2e56Smrg    while (num_masks--) {
1716747b715Smrg        len += sizeof(xXIEventMask) + evmask->mask_len * 4;
1726747b715Smrg
1736747b715Smrg        if (bytes_to_int32(len) > stuff->length)
1746747b715Smrg            return BadLength;
1756747b715Smrg
1766747b715Smrg        if (evmask->deviceid != XIAllDevices &&
1776747b715Smrg            evmask->deviceid != XIAllMasterDevices)
1786747b715Smrg            rc = dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
1796747b715Smrg        else {
1806747b715Smrg            /* XXX: XACE here? */
1816747b715Smrg        }
1826747b715Smrg        if (rc != Success)
1836747b715Smrg            return rc;
1846747b715Smrg
1856747b715Smrg        /* hierarchy event mask is not allowed on devices */
186f7df2e56Smrg        if (evmask->deviceid != XIAllDevices && evmask->mask_len >= 1) {
187f7df2e56Smrg            unsigned char *bits = (unsigned char *) &evmask[1];
188f7df2e56Smrg
189f7df2e56Smrg            if (BitIsOn(bits, XI_HierarchyChanged)) {
1909ace9065Smrg                client->errorValue = XI_HierarchyChanged;
1916747b715Smrg                return BadValue;
1929ace9065Smrg            }
1936747b715Smrg        }
1946747b715Smrg
1956747b715Smrg        /* Raw events may only be selected on root windows */
196f7df2e56Smrg        if (win->parent && evmask->mask_len >= 1) {
197f7df2e56Smrg            unsigned char *bits = (unsigned char *) &evmask[1];
198f7df2e56Smrg
1996747b715Smrg            if (BitIsOn(bits, XI_RawKeyPress) ||
2006747b715Smrg                BitIsOn(bits, XI_RawKeyRelease) ||
2016747b715Smrg                BitIsOn(bits, XI_RawButtonPress) ||
2026747b715Smrg                BitIsOn(bits, XI_RawButtonRelease) ||
203f7df2e56Smrg                BitIsOn(bits, XI_RawMotion) ||
204f7df2e56Smrg                BitIsOn(bits, XI_RawTouchBegin) ||
205f7df2e56Smrg                BitIsOn(bits, XI_RawTouchUpdate) ||
206f7df2e56Smrg                BitIsOn(bits, XI_RawTouchEnd)) {
2079ace9065Smrg                client->errorValue = XI_RawKeyPress;
2086747b715Smrg                return BadValue;
2099ace9065Smrg            }
2106747b715Smrg        }
2116747b715Smrg
212f7df2e56Smrg        if (evmask->mask_len >= 1) {
213f7df2e56Smrg            unsigned char *bits = (unsigned char *) &evmask[1];
214f7df2e56Smrg
215f7df2e56Smrg            /* All three touch events must be selected at once */
216f7df2e56Smrg            if ((BitIsOn(bits, XI_TouchBegin) ||
217f7df2e56Smrg                 BitIsOn(bits, XI_TouchUpdate) ||
218f7df2e56Smrg                 BitIsOn(bits, XI_TouchOwnership) ||
219f7df2e56Smrg                 BitIsOn(bits, XI_TouchEnd)) &&
220f7df2e56Smrg                (!BitIsOn(bits, XI_TouchBegin) ||
221f7df2e56Smrg                 !BitIsOn(bits, XI_TouchUpdate) ||
222f7df2e56Smrg                 !BitIsOn(bits, XI_TouchEnd))) {
223f7df2e56Smrg                client->errorValue = XI_TouchBegin;
224f7df2e56Smrg                return BadValue;
225f7df2e56Smrg            }
226f7df2e56Smrg
227f7df2e56Smrg            /* Only one client per window may select for touch events on the
228f7df2e56Smrg             * same devices, including master devices.
229f7df2e56Smrg             * XXX: This breaks if a device goes from floating to attached. */
230f7df2e56Smrg            if (BitIsOn(bits, XI_TouchBegin)) {
231f7df2e56Smrg                rc = check_for_touch_selection_conflicts(client,
232f7df2e56Smrg                                                         win,
233f7df2e56Smrg                                                         evmask->deviceid);
234f7df2e56Smrg                if (rc != Success)
235f7df2e56Smrg                    return rc;
236f7df2e56Smrg            }
237f7df2e56Smrg        }
238f7df2e56Smrg
239f7df2e56Smrg        if (XICheckInvalidMaskBits(client, (unsigned char *) &evmask[1],
2406747b715Smrg                                   evmask->mask_len * 4) != Success)
2416747b715Smrg            return BadValue;
2426747b715Smrg
243f7df2e56Smrg        evmask =
244f7df2e56Smrg            (xXIEventMask *) (((unsigned char *) evmask) +
245f7df2e56Smrg                              evmask->mask_len * 4);
2466747b715Smrg        evmask++;
2476747b715Smrg    }
2486747b715Smrg
2496747b715Smrg    if (bytes_to_int32(len) != stuff->length)
2506747b715Smrg        return BadLength;
2516747b715Smrg
2526747b715Smrg    /* Set masks on window */
253f7df2e56Smrg    evmask = (xXIEventMask *) &stuff[1];
2546747b715Smrg    num_masks = stuff->num_masks;
255f7df2e56Smrg    while (num_masks--) {
2566747b715Smrg        if (evmask->deviceid == XIAllDevices ||
257f7df2e56Smrg            evmask->deviceid == XIAllMasterDevices) {
2586747b715Smrg            dummy.id = evmask->deviceid;
2596747b715Smrg            dev = &dummy;
260f7df2e56Smrg        }
261f7df2e56Smrg        else
2626747b715Smrg            dixLookupDevice(&dev, evmask->deviceid, client, DixUseAccess);
2636747b715Smrg        if (XISetEventMask(dev, win, client, evmask->mask_len * 4,
264f7df2e56Smrg                           (unsigned char *) &evmask[1]) != Success)
2656747b715Smrg            return BadAlloc;
266f7df2e56Smrg        evmask =
267f7df2e56Smrg            (xXIEventMask *) (((unsigned char *) evmask) +
268f7df2e56Smrg                              evmask->mask_len * 4);
2696747b715Smrg        evmask++;
2706747b715Smrg    }
2716747b715Smrg
2726747b715Smrg    RecalculateDeliverableEvents(win);
2736747b715Smrg
2746747b715Smrg    free(types);
2756747b715Smrg    return Success;
2766747b715Smrg}
2776747b715Smrg
2787e31ba66Smrgint _X_COLD
2796747b715SmrgSProcXIGetSelectedEvents(ClientPtr client)
2806747b715Smrg{
2816747b715Smrg    REQUEST(xXIGetSelectedEventsReq);
282f7df2e56Smrg    swaps(&stuff->length);
2836747b715Smrg    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
284f7df2e56Smrg    swapl(&stuff->win);
2856747b715Smrg
2866747b715Smrg    return (ProcXIGetSelectedEvents(client));
2876747b715Smrg}
2886747b715Smrg
2896747b715Smrgint
2906747b715SmrgProcXIGetSelectedEvents(ClientPtr client)
2916747b715Smrg{
2926747b715Smrg    int rc, i;
2936747b715Smrg    WindowPtr win;
2946747b715Smrg    char *buffer = NULL;
2956747b715Smrg    xXIGetSelectedEventsReply reply;
2966747b715Smrg    OtherInputMasks *masks;
2976747b715Smrg    InputClientsPtr others = NULL;
2986747b715Smrg    xXIEventMask *evmask = NULL;
2996747b715Smrg    DeviceIntPtr dev;
3006747b715Smrg
3016747b715Smrg    REQUEST(xXIGetSelectedEventsReq);
3026747b715Smrg    REQUEST_SIZE_MATCH(xXIGetSelectedEventsReq);
3036747b715Smrg
3046747b715Smrg    rc = dixLookupWindow(&win, stuff->win, client, DixGetAttrAccess);
3056747b715Smrg    if (rc != Success)
3066747b715Smrg        return rc;
3076747b715Smrg
308f7df2e56Smrg    reply = (xXIGetSelectedEventsReply) {
309f7df2e56Smrg        .repType = X_Reply,
310f7df2e56Smrg        .RepType = X_XIGetSelectedEvents,
311f7df2e56Smrg        .sequenceNumber = client->sequence,
312f7df2e56Smrg        .length = 0,
313f7df2e56Smrg        .num_masks = 0
314f7df2e56Smrg    };
3156747b715Smrg
3166747b715Smrg    masks = wOtherInputMasks(win);
317f7df2e56Smrg    if (masks) {
318f7df2e56Smrg        for (others = wOtherInputMasks(win)->inputClients; others;
319f7df2e56Smrg             others = others->next) {
320f7df2e56Smrg            if (SameClient(others, client)) {
3216747b715Smrg                break;
3226747b715Smrg            }
3236747b715Smrg        }
3246747b715Smrg    }
3256747b715Smrg
326f7df2e56Smrg    if (!others) {
3276747b715Smrg        WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
3286747b715Smrg        return Success;
3296747b715Smrg    }
3306747b715Smrg
331f7df2e56Smrg    buffer =
332f7df2e56Smrg        calloc(MAXDEVICES, sizeof(xXIEventMask) + pad_to_int32(XI2MASKSIZE));
3336747b715Smrg    if (!buffer)
3346747b715Smrg        return BadAlloc;
3356747b715Smrg
336f7df2e56Smrg    evmask = (xXIEventMask *) buffer;
337f7df2e56Smrg    for (i = 0; i < MAXDEVICES; i++) {
3386747b715Smrg        int j;
339f7df2e56Smrg        const unsigned char *devmask = xi2mask_get_one_mask(others->xi2mask, i);
3406747b715Smrg
341f7df2e56Smrg        if (i > 2) {
3426747b715Smrg            rc = dixLookupDevice(&dev, i, client, DixGetAttrAccess);
3436747b715Smrg            if (rc != Success)
3446747b715Smrg                continue;
3456747b715Smrg        }
3466747b715Smrg
347f7df2e56Smrg        for (j = xi2mask_mask_size(others->xi2mask) - 1; j >= 0; j--) {
348f7df2e56Smrg            if (devmask[j] != 0) {
349f7df2e56Smrg                int mask_len = (j + 4) / 4;     /* j is an index, hence + 4, not + 3 */
3506747b715Smrg
3516747b715Smrg                evmask->deviceid = i;
3526747b715Smrg                evmask->mask_len = mask_len;
3536747b715Smrg                reply.num_masks++;
354f7df2e56Smrg                reply.length += sizeof(xXIEventMask) / 4 + evmask->mask_len;
3556747b715Smrg
356f7df2e56Smrg                if (client->swapped) {
357f7df2e56Smrg                    swaps(&evmask->deviceid);
358f7df2e56Smrg                    swaps(&evmask->mask_len);
3596747b715Smrg                }
3606747b715Smrg
3616747b715Smrg                memcpy(&evmask[1], devmask, j + 1);
362f7df2e56Smrg                evmask = (xXIEventMask *) ((char *) evmask +
363f7df2e56Smrg                                           sizeof(xXIEventMask) + mask_len * 4);
3646747b715Smrg                break;
3656747b715Smrg            }
3666747b715Smrg        }
3676747b715Smrg    }
3686747b715Smrg
3696747b715Smrg    WriteReplyToClient(client, sizeof(xXIGetSelectedEventsReply), &reply);
3706747b715Smrg
3716747b715Smrg    if (reply.num_masks)
3726747b715Smrg        WriteToClient(client, reply.length * 4, buffer);
3736747b715Smrg
3746747b715Smrg    free(buffer);
3756747b715Smrg    return Success;
3766747b715Smrg}
3776747b715Smrg
378f7df2e56Smrgvoid
379f7df2e56SmrgSRepXIGetSelectedEvents(ClientPtr client,
380f7df2e56Smrg                        int len, xXIGetSelectedEventsReply * rep)
3816747b715Smrg{
382f7df2e56Smrg    swaps(&rep->sequenceNumber);
383f7df2e56Smrg    swapl(&rep->length);
384f7df2e56Smrg    swaps(&rep->num_masks);
385f7df2e56Smrg    WriteToClient(client, len, rep);
3866747b715Smrg}
387