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