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 51static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); 52static int 53 ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info); 54static int SizeDeviceInfo(DeviceIntPtr dev); 55static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info); 56int _X_COLD 57SProcXIQueryDevice(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 68int 69ProcXIQueryDevice(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 161void 162SRepXIQueryDevice(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 */ 176static Bool 177ShouldSkipDevice(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 */ 193static int 194SizeDeviceInfo(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 */ 208int 209SizeDeviceClasses(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 */ 249static void 250ButtonInfoData(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 */ 262int 263ListButtonInfo(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 292static void 293SwapButtonInfo(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 */ 316int 317ListKeyInfo(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 335static void 336SwapKeyInfo(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 */ 357int 358ListValuatorInfo(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 382static void 383SwapValuatorInfo(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 399int 400ListScrollInfo(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 436static void 437SwapScrollInfo(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 */ 453int 454ListTouchInfo(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 465static void 466SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) 467{ 468 swaps(&touch->type); 469 swaps(&touch->length); 470 swaps(&touch->sourceid); 471} 472 473static 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 */ 494static int 495ListGestureInfo(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 505static void 506SwapGestureInfo(DeviceIntPtr dev, xXIGestureInfo * gesture) 507{ 508 swaps(&gesture->type); 509 swaps(&gesture->length); 510 swaps(&gesture->sourceid); 511} 512 513int 514GetDeviceUse(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 */ 540static int 541ListDeviceInfo(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 */ 568int 569ListDeviceClasses(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 626static void 627SwapDeviceInfo(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} 669