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