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