xiquerydevice.c (17808B)
1 /* 2 * Copyright © 2009 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 * Authors: Peter Hutterer 24 * 25 */ 26 27 /** 28 * @file Protocol handling for the XIQueryDevice request/reply. 29 */ 30 31 #ifdef HAVE_DIX_CONFIG_H 32 #include <dix-config.h> 33 #endif 34 35 #include "inputstr.h" 36 #include <X11/X.h> 37 #include <X11/Xatom.h> 38 #include <X11/extensions/XI2proto.h> 39 #include "xkbstr.h" 40 #include "xkbsrv.h" 41 #include "xserver-properties.h" 42 #include "exevents.h" 43 #include "xace.h" 44 #include "inpututils.h" 45 46 #include "exglobals.h" 47 #include "privates.h" 48 49 #include "xiquerydevice.h" 50 51 static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); 52 static int 53 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info); 54 static int SizeDeviceInfo(DeviceIntPtr dev); 55 static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info); 56 int _X_COLD 57 SProcXIQueryDevice(ClientPtr client) 58 { 59 REQUEST(xXIQueryDeviceReq); 60 REQUEST_SIZE_MATCH(xXIQueryDeviceReq); 61 62 swaps(&stuff->length); 63 swaps(&stuff->deviceid); 64 65 return ProcXIQueryDevice(client); 66 } 67 68 int 69 ProcXIQueryDevice(ClientPtr client) 70 { 71 xXIQueryDeviceReply rep; 72 DeviceIntPtr dev = NULL; 73 int rc = Success; 74 int i = 0, len = 0; 75 char *info, *ptr; 76 Bool *skip = NULL; 77 78 REQUEST(xXIQueryDeviceReq); 79 REQUEST_SIZE_MATCH(xXIQueryDeviceReq); 80 81 if (stuff->deviceid != XIAllDevices && 82 stuff->deviceid != XIAllMasterDevices) { 83 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); 84 if (rc != Success) { 85 client->errorValue = stuff->deviceid; 86 return rc; 87 } 88 len += SizeDeviceInfo(dev); 89 } 90 else { 91 skip = calloc(sizeof(Bool), inputInfo.numDevices); 92 if (!skip) 93 return BadAlloc; 94 95 for (dev = inputInfo.devices; dev; dev = dev->next, i++) { 96 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); 97 if (!skip[i]) 98 len += SizeDeviceInfo(dev); 99 } 100 101 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) { 102 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); 103 if (!skip[i]) 104 len += SizeDeviceInfo(dev); 105 } 106 } 107 108 info = calloc(1, len); 109 if (!info) { 110 free(skip); 111 return BadAlloc; 112 } 113 114 rep = (xXIQueryDeviceReply) { 115 .repType = X_Reply, 116 .RepType = X_XIQueryDevice, 117 .sequenceNumber = client->sequence, 118 .length = len / 4, 119 .num_devices = 0 120 }; 121 122 ptr = info; 123 if (dev) { 124 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info); 125 if (client->swapped) 126 SwapDeviceInfo(dev, (xXIDeviceInfo *) info); 127 info += len; 128 rep.num_devices = 1; 129 } 130 else { 131 i = 0; 132 for (dev = inputInfo.devices; dev; dev = dev->next, i++) { 133 if (!skip[i]) { 134 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info); 135 if (client->swapped) 136 SwapDeviceInfo(dev, (xXIDeviceInfo *) info); 137 info += len; 138 rep.num_devices++; 139 } 140 } 141 142 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) { 143 if (!skip[i]) { 144 len = ListDeviceInfo(client, dev, (xXIDeviceInfo *) info); 145 if (client->swapped) 146 SwapDeviceInfo(dev, (xXIDeviceInfo *) info); 147 info += len; 148 rep.num_devices++; 149 } 150 } 151 } 152 153 len = rep.length * 4; 154 WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); 155 WriteToClient(client, len, ptr); 156 free(ptr); 157 free(skip); 158 return rc; 159 } 160 161 void 162 SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply * rep) 163 { 164 swaps(&rep->sequenceNumber); 165 swapl(&rep->length); 166 swaps(&rep->num_devices); 167 168 /* Device info is already swapped, see ProcXIQueryDevice */ 169 170 WriteToClient(client, size, rep); 171 } 172 173 /** 174 * @return Whether the device should be included in the returned list. 175 */ 176 static Bool 177 ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev) 178 { 179 /* if all devices are not being queried, only master devices are */ 180 if (deviceid == XIAllDevices || IsMaster(dev)) { 181 int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); 182 183 if (rc == Success) 184 return FALSE; 185 } 186 return TRUE; 187 } 188 189 /** 190 * @return The number of bytes needed to store this device's xXIDeviceInfo 191 * (and its classes). 192 */ 193 static int 194 SizeDeviceInfo(DeviceIntPtr dev) 195 { 196 int len = sizeof(xXIDeviceInfo); 197 198 /* 4-padded name */ 199 len += pad_to_int32(strlen(dev->name)); 200 201 return len + SizeDeviceClasses(dev); 202 203 } 204 205 /* 206 * @return The number of bytes needed to store this device's classes. 207 */ 208 int 209 SizeDeviceClasses(DeviceIntPtr dev) 210 { 211 int len = 0; 212 213 if (dev->button) { 214 len += sizeof(xXIButtonInfo); 215 len += dev->button->numButtons * sizeof(Atom); 216 len += pad_to_int32(bits_to_bytes(dev->button->numButtons)); 217 } 218 219 if (dev->key) { 220 XkbDescPtr xkb = dev->key->xkbInfo->desc; 221 222 len += sizeof(xXIKeyInfo); 223 len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); 224 } 225 226 if (dev->valuator) { 227 int i; 228 229 len += (sizeof(xXIValuatorInfo)) * dev->valuator->numAxes; 230 231 for (i = 0; i < dev->valuator->numAxes; i++) { 232 if (dev->valuator->axes[i].scroll.type != SCROLL_TYPE_NONE) 233 len += sizeof(xXIScrollInfo); 234 } 235 } 236 237 if (dev->touch) 238 len += sizeof(xXITouchInfo); 239 240 if (dev->gesture) 241 len += sizeof(xXIGestureInfo); 242 243 return len; 244 } 245 246 /** 247 * Get pointers to button information areas holding button mask and labels. 248 */ 249 static void 250 ButtonInfoData(xXIButtonInfo *info, int *mask_words, unsigned char **mask, 251 Atom **atoms) 252 { 253 *mask_words = bytes_to_int32(bits_to_bytes(info->num_buttons)); 254 *mask = (unsigned char*) &info[1]; 255 *atoms = (Atom*) ((*mask) + (*mask_words) * 4); 256 } 257 258 /** 259 * Write button information into info. 260 * @return Number of bytes written into info. 261 */ 262 int 263 ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info, Bool reportState) 264 { 265 unsigned char *bits; 266 Atom *labels; 267 int mask_len; 268 int i; 269 270 if (!dev || !dev->button) 271 return 0; 272 273 info->type = ButtonClass; 274 info->num_buttons = dev->button->numButtons; 275 ButtonInfoData(info, &mask_len, &bits, &labels); 276 info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + 277 info->num_buttons + mask_len; 278 info->sourceid = dev->button->sourceid; 279 280 memset(bits, 0, mask_len * 4); 281 282 if (reportState) 283 for (i = 0; i < dev->button->numButtons; i++) 284 if (BitIsOn(dev->button->down, i)) 285 SetBit(bits, i); 286 287 memcpy(labels, dev->button->labels, dev->button->numButtons * sizeof(Atom)); 288 289 return info->length * 4; 290 } 291 292 static void 293 SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info) 294 { 295 Atom *btn; 296 int mask_len; 297 unsigned char *mask; 298 299 int i; 300 ButtonInfoData(info, &mask_len, &mask, &btn); 301 302 swaps(&info->type); 303 swaps(&info->length); 304 swaps(&info->sourceid); 305 306 for (i = 0 ; i < info->num_buttons; i++, btn++) 307 swapl(btn); 308 309 swaps(&info->num_buttons); 310 } 311 312 /** 313 * Write key information into info. 314 * @return Number of bytes written into info. 315 */ 316 int 317 ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info) 318 { 319 int i; 320 XkbDescPtr xkb = dev->key->xkbInfo->desc; 321 uint32_t *kc; 322 323 info->type = KeyClass; 324 info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; 325 info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes; 326 info->sourceid = dev->key->sourceid; 327 328 kc = (uint32_t *) &info[1]; 329 for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) 330 *kc = i; 331 332 return info->length * 4; 333 } 334 335 static void 336 SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info) 337 { 338 uint32_t *key; 339 int i; 340 341 swaps(&info->type); 342 swaps(&info->length); 343 swaps(&info->sourceid); 344 345 for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes; 346 i++, key++) 347 swapl(key); 348 349 swaps(&info->num_keycodes); 350 } 351 352 /** 353 * List axis information for the given axis. 354 * 355 * @return The number of bytes written into info. 356 */ 357 int 358 ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info, int axisnumber, 359 Bool reportState) 360 { 361 ValuatorClassPtr v = dev->valuator; 362 363 info->type = ValuatorClass; 364 info->length = sizeof(xXIValuatorInfo) / 4; 365 info->label = v->axes[axisnumber].label; 366 info->min.integral = v->axes[axisnumber].min_value; 367 info->min.frac = 0; 368 info->max.integral = v->axes[axisnumber].max_value; 369 info->max.frac = 0; 370 info->value = double_to_fp3232(v->axisVal[axisnumber]); 371 info->resolution = v->axes[axisnumber].resolution; 372 info->number = axisnumber; 373 info->mode = valuator_get_mode(dev, axisnumber); 374 info->sourceid = v->sourceid; 375 376 if (!reportState) 377 info->value = info->min; 378 379 return info->length * 4; 380 } 381 382 static void 383 SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info) 384 { 385 swaps(&info->type); 386 swaps(&info->length); 387 swapl(&info->label); 388 swapl(&info->min.integral); 389 swapl(&info->min.frac); 390 swapl(&info->max.integral); 391 swapl(&info->max.frac); 392 swapl(&info->value.integral); 393 swapl(&info->value.frac); 394 swapl(&info->resolution); 395 swaps(&info->number); 396 swaps(&info->sourceid); 397 } 398 399 int 400 ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info, int axisnumber) 401 { 402 ValuatorClassPtr v = dev->valuator; 403 AxisInfoPtr axis = &v->axes[axisnumber]; 404 405 if (axis->scroll.type == SCROLL_TYPE_NONE) 406 return 0; 407 408 info->type = XIScrollClass; 409 info->length = sizeof(xXIScrollInfo) / 4; 410 info->number = axisnumber; 411 switch (axis->scroll.type) { 412 case SCROLL_TYPE_VERTICAL: 413 info->scroll_type = XIScrollTypeVertical; 414 break; 415 case SCROLL_TYPE_HORIZONTAL: 416 info->scroll_type = XIScrollTypeHorizontal; 417 break; 418 default: 419 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n", 420 axis->scroll.type); 421 break; 422 } 423 info->increment = double_to_fp3232(axis->scroll.increment); 424 info->sourceid = v->sourceid; 425 426 info->flags = 0; 427 428 if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE) 429 info->flags |= XIScrollFlagNoEmulation; 430 if (axis->scroll.flags & SCROLL_FLAG_PREFERRED) 431 info->flags |= XIScrollFlagPreferred; 432 433 return info->length * 4; 434 } 435 436 static void 437 SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info) 438 { 439 swaps(&info->type); 440 swaps(&info->length); 441 swaps(&info->number); 442 swaps(&info->sourceid); 443 swaps(&info->scroll_type); 444 swapl(&info->increment.integral); 445 swapl(&info->increment.frac); 446 } 447 448 /** 449 * List multitouch information 450 * 451 * @return The number of bytes written into info. 452 */ 453 int 454 ListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) 455 { 456 touch->type = XITouchClass; 457 touch->length = sizeof(xXITouchInfo) >> 2; 458 touch->sourceid = dev->touch->sourceid; 459 touch->mode = dev->touch->mode; 460 touch->num_touches = dev->touch->num_touches; 461 462 return touch->length << 2; 463 } 464 465 static void 466 SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) 467 { 468 swaps(&touch->type); 469 swaps(&touch->length); 470 swaps(&touch->sourceid); 471 } 472 473 static Bool ShouldListGestureInfo(ClientPtr client) 474 { 475 /* libxcb 14.1 and older are not forwards-compatible with new device classes as it does not 476 * properly ignore unknown device classes. Since breaking libxcb would break quite a lot of 477 * applications, we instead report Gesture device class only if the client advertised support 478 * for XI 2.4. Clients may still not work in cases when a client advertises XI 2.4 support 479 * and then a completely separate module within the client uses broken libxcb to call 480 * XIQueryDevice. 481 */ 482 XIClientPtr pXIClient = dixLookupPrivate(&client->devPrivates, XIClientPrivateKey); 483 if (pXIClient->major_version) { 484 return version_compare(pXIClient->major_version, pXIClient->minor_version, 2, 4) >= 0; 485 } 486 return FALSE; 487 } 488 489 /** 490 * List gesture information 491 * 492 * @return The number of bytes written into info. 493 */ 494 static int 495 ListGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture) 496 { 497 gesture->type = XIGestureClass; 498 gesture->length = sizeof(xXIGestureInfo) >> 2; 499 gesture->sourceid = dev->gesture->sourceid; 500 gesture->num_touches = dev->gesture->max_touches; 501 502 return gesture->length << 2; 503 } 504 505 static void 506 SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture) 507 { 508 swaps(&gesture->type); 509 swaps(&gesture->length); 510 swaps(&gesture->sourceid); 511 } 512 513 int 514 GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment) 515 { 516 DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED); 517 int use; 518 519 if (IsMaster(dev)) { 520 DeviceIntPtr paired = GetPairedDevice(dev); 521 522 use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; 523 *attachment = (paired ? paired->id : 0); 524 } 525 else if (!IsFloating(dev)) { 526 use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; 527 *attachment = master->id; 528 } 529 else 530 use = XIFloatingSlave; 531 532 return use; 533 } 534 535 /** 536 * Write the info for device dev into the buffer pointed to by info. 537 * 538 * @return The number of bytes used. 539 */ 540 static int 541 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info) 542 { 543 char *any = (char *) &info[1]; 544 int len = 0, total_len = 0; 545 546 info->deviceid = dev->id; 547 info->use = GetDeviceUse(dev, &info->attachment); 548 info->num_classes = 0; 549 info->name_len = strlen(dev->name); 550 info->enabled = dev->enabled; 551 total_len = sizeof(xXIDeviceInfo); 552 553 len = pad_to_int32(info->name_len); 554 memset(any, 0, len); 555 strncpy(any, dev->name, info->name_len); 556 any += len; 557 total_len += len; 558 559 total_len += ListDeviceClasses(client, dev, any, &info->num_classes); 560 return total_len; 561 } 562 563 /** 564 * Write the class info of the device into the memory pointed to by any, set 565 * nclasses to the number of classes in total and return the number of bytes 566 * written. 567 */ 568 int 569 ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, 570 char *any, uint16_t * nclasses) 571 { 572 int total_len = 0; 573 int len; 574 int i; 575 int rc; 576 577 /* Check if the current device state should be suppressed */ 578 rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); 579 580 if (dev->button) { 581 (*nclasses)++; 582 len = ListButtonInfo(dev, (xXIButtonInfo *) any, rc == Success); 583 any += len; 584 total_len += len; 585 } 586 587 if (dev->key) { 588 (*nclasses)++; 589 len = ListKeyInfo(dev, (xXIKeyInfo *) any); 590 any += len; 591 total_len += len; 592 } 593 594 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) { 595 (*nclasses)++; 596 len = ListValuatorInfo(dev, (xXIValuatorInfo *) any, i, rc == Success); 597 any += len; 598 total_len += len; 599 } 600 601 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) { 602 len = ListScrollInfo(dev, (xXIScrollInfo *) any, i); 603 if (len) 604 (*nclasses)++; 605 any += len; 606 total_len += len; 607 } 608 609 if (dev->touch) { 610 (*nclasses)++; 611 len = ListTouchInfo(dev, (xXITouchInfo *) any); 612 any += len; 613 total_len += len; 614 } 615 616 if (dev->gesture && ShouldListGestureInfo(client)) { 617 (*nclasses)++; 618 len = ListGestureInfo(dev, (xXIGestureInfo *) any); 619 any += len; 620 total_len += len; 621 } 622 623 return total_len; 624 } 625 626 static void 627 SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info) 628 { 629 char *any = (char *) &info[1]; 630 int i; 631 632 /* Skip over name */ 633 any += pad_to_int32(info->name_len); 634 635 for (i = 0; i < info->num_classes; i++) { 636 int len = ((xXIAnyInfo *) any)->length; 637 638 switch (((xXIAnyInfo *) any)->type) { 639 case XIButtonClass: 640 SwapButtonInfo(dev, (xXIButtonInfo *) any); 641 break; 642 case XIKeyClass: 643 SwapKeyInfo(dev, (xXIKeyInfo *) any); 644 break; 645 case XIValuatorClass: 646 SwapValuatorInfo(dev, (xXIValuatorInfo *) any); 647 break; 648 case XIScrollClass: 649 SwapScrollInfo(dev, (xXIScrollInfo *) any); 650 break; 651 case XITouchClass: 652 SwapTouchInfo(dev, (xXITouchInfo *) any); 653 break; 654 case XIGestureClass: 655 SwapGestureInfo(dev, (xXIGestureInfo *) any); 656 break; 657 } 658 659 any += len * 4; 660 } 661 662 swaps(&info->deviceid); 663 swaps(&info->use); 664 swaps(&info->attachment); 665 swaps(&info->num_classes); 666 swaps(&info->name_len); 667 668 }