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