xiquerydevice.c revision f7df2e56
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 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 * Write button information into info. 242 * @return Number of bytes written into info. 243 */ 244int 245ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info, Bool reportState) 246{ 247 unsigned char *bits; 248 int mask_len; 249 int i; 250 251 if (!dev || !dev->button) 252 return 0; 253 254 mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons)); 255 256 info->type = ButtonClass; 257 info->num_buttons = dev->button->numButtons; 258 info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + 259 info->num_buttons + mask_len; 260 info->sourceid = dev->button->sourceid; 261 262 bits = (unsigned char *) &info[1]; 263 memset(bits, 0, mask_len * 4); 264 265 if (reportState) 266 for (i = 0; i < dev->button->numButtons; i++) 267 if (BitIsOn(dev->button->down, i)) 268 SetBit(bits, i); 269 270 bits += mask_len * 4; 271 memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom)); 272 273 return info->length * 4; 274} 275 276static void 277SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo * info) 278{ 279 Atom *btn; 280 int i; 281 282 swaps(&info->type); 283 swaps(&info->length); 284 swaps(&info->sourceid); 285 286 for (i = 0, btn = (Atom *) &info[1]; i < info->num_buttons; i++, btn++) 287 swapl(btn); 288 289 swaps(&info->num_buttons); 290} 291 292/** 293 * Write key information into info. 294 * @return Number of bytes written into info. 295 */ 296int 297ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info) 298{ 299 int i; 300 XkbDescPtr xkb = dev->key->xkbInfo->desc; 301 uint32_t *kc; 302 303 info->type = KeyClass; 304 info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; 305 info->length = sizeof(xXIKeyInfo) / 4 + info->num_keycodes; 306 info->sourceid = dev->key->sourceid; 307 308 kc = (uint32_t *) &info[1]; 309 for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) 310 *kc = i; 311 312 return info->length * 4; 313} 314 315static void 316SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo * info) 317{ 318 uint32_t *key; 319 int i; 320 321 swaps(&info->type); 322 swaps(&info->length); 323 swaps(&info->sourceid); 324 325 for (i = 0, key = (uint32_t *) &info[1]; i < info->num_keycodes; 326 i++, key++) 327 swapl(key); 328 329 swaps(&info->num_keycodes); 330} 331 332/** 333 * List axis information for the given axis. 334 * 335 * @return The number of bytes written into info. 336 */ 337int 338ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info, int axisnumber, 339 Bool reportState) 340{ 341 ValuatorClassPtr v = dev->valuator; 342 343 info->type = ValuatorClass; 344 info->length = sizeof(xXIValuatorInfo) / 4; 345 info->label = v->axes[axisnumber].label; 346 info->min.integral = v->axes[axisnumber].min_value; 347 info->min.frac = 0; 348 info->max.integral = v->axes[axisnumber].max_value; 349 info->max.frac = 0; 350 info->value = double_to_fp3232(v->axisVal[axisnumber]); 351 info->resolution = v->axes[axisnumber].resolution; 352 info->number = axisnumber; 353 info->mode = valuator_get_mode(dev, axisnumber); 354 info->sourceid = v->sourceid; 355 356 if (!reportState) 357 info->value = info->min; 358 359 return info->length * 4; 360} 361 362static void 363SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo * info) 364{ 365 swaps(&info->type); 366 swaps(&info->length); 367 swapl(&info->label); 368 swapl(&info->min.integral); 369 swapl(&info->min.frac); 370 swapl(&info->max.integral); 371 swapl(&info->max.frac); 372 swaps(&info->number); 373 swaps(&info->sourceid); 374} 375 376int 377ListScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info, int axisnumber) 378{ 379 ValuatorClassPtr v = dev->valuator; 380 AxisInfoPtr axis = &v->axes[axisnumber]; 381 382 if (axis->scroll.type == SCROLL_TYPE_NONE) 383 return 0; 384 385 info->type = XIScrollClass; 386 info->length = sizeof(xXIScrollInfo) / 4; 387 info->number = axisnumber; 388 switch (axis->scroll.type) { 389 case SCROLL_TYPE_VERTICAL: 390 info->scroll_type = XIScrollTypeVertical; 391 break; 392 case SCROLL_TYPE_HORIZONTAL: 393 info->scroll_type = XIScrollTypeHorizontal; 394 break; 395 default: 396 ErrorF("[Xi] Unknown scroll type %d. This is a bug.\n", 397 axis->scroll.type); 398 break; 399 } 400 info->increment = double_to_fp3232(axis->scroll.increment); 401 info->sourceid = v->sourceid; 402 403 info->flags = 0; 404 405 if (axis->scroll.flags & SCROLL_FLAG_DONT_EMULATE) 406 info->flags |= XIScrollFlagNoEmulation; 407 if (axis->scroll.flags & SCROLL_FLAG_PREFERRED) 408 info->flags |= XIScrollFlagPreferred; 409 410 return info->length * 4; 411} 412 413static void 414SwapScrollInfo(DeviceIntPtr dev, xXIScrollInfo * info) 415{ 416 swaps(&info->type); 417 swaps(&info->length); 418 swaps(&info->number); 419 swaps(&info->sourceid); 420 swaps(&info->scroll_type); 421 swapl(&info->increment.integral); 422 swapl(&info->increment.frac); 423} 424 425/** 426 * List multitouch information 427 * 428 * @return The number of bytes written into info. 429 */ 430int 431ListTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) 432{ 433 touch->type = XITouchClass; 434 touch->length = sizeof(xXITouchInfo) >> 2; 435 touch->sourceid = dev->touch->sourceid; 436 touch->mode = dev->touch->mode; 437 touch->num_touches = dev->touch->num_touches; 438 439 return touch->length << 2; 440} 441 442static void 443SwapTouchInfo(DeviceIntPtr dev, xXITouchInfo * touch) 444{ 445 swaps(&touch->type); 446 swaps(&touch->length); 447 swaps(&touch->sourceid); 448} 449 450int 451GetDeviceUse(DeviceIntPtr dev, uint16_t * attachment) 452{ 453 DeviceIntPtr master = GetMaster(dev, MASTER_ATTACHED); 454 int use; 455 456 if (IsMaster(dev)) { 457 DeviceIntPtr paired = GetPairedDevice(dev); 458 459 use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; 460 *attachment = (paired ? paired->id : 0); 461 } 462 else if (!IsFloating(dev)) { 463 use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; 464 *attachment = master->id; 465 } 466 else 467 use = XIFloatingSlave; 468 469 return use; 470} 471 472/** 473 * Write the info for device dev into the buffer pointed to by info. 474 * 475 * @return The number of bytes used. 476 */ 477static int 478ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info) 479{ 480 char *any = (char *) &info[1]; 481 int len = 0, total_len = 0; 482 483 info->deviceid = dev->id; 484 info->use = GetDeviceUse(dev, &info->attachment); 485 info->num_classes = 0; 486 info->name_len = strlen(dev->name); 487 info->enabled = dev->enabled; 488 total_len = sizeof(xXIDeviceInfo); 489 490 len = pad_to_int32(info->name_len); 491 memset(any, 0, len); 492 strncpy(any, dev->name, info->name_len); 493 any += len; 494 total_len += len; 495 496 total_len += ListDeviceClasses(client, dev, any, &info->num_classes); 497 return total_len; 498} 499 500/** 501 * Write the class info of the device into the memory pointed to by any, set 502 * nclasses to the number of classes in total and return the number of bytes 503 * written. 504 */ 505int 506ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, 507 char *any, uint16_t * nclasses) 508{ 509 int total_len = 0; 510 int len; 511 int i; 512 int rc; 513 514 /* Check if the current device state should be suppressed */ 515 rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); 516 517 if (dev->button) { 518 (*nclasses)++; 519 len = ListButtonInfo(dev, (xXIButtonInfo *) any, rc == Success); 520 any += len; 521 total_len += len; 522 } 523 524 if (dev->key) { 525 (*nclasses)++; 526 len = ListKeyInfo(dev, (xXIKeyInfo *) any); 527 any += len; 528 total_len += len; 529 } 530 531 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) { 532 (*nclasses)++; 533 len = ListValuatorInfo(dev, (xXIValuatorInfo *) any, i, rc == Success); 534 any += len; 535 total_len += len; 536 } 537 538 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) { 539 len = ListScrollInfo(dev, (xXIScrollInfo *) any, i); 540 if (len) 541 (*nclasses)++; 542 any += len; 543 total_len += len; 544 } 545 546 if (dev->touch) { 547 (*nclasses)++; 548 len = ListTouchInfo(dev, (xXITouchInfo *) any); 549 any += len; 550 total_len += len; 551 } 552 553 return total_len; 554} 555 556static void 557SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo * info) 558{ 559 char *any = (char *) &info[1]; 560 int i; 561 562 /* Skip over name */ 563 any += pad_to_int32(info->name_len); 564 565 for (i = 0; i < info->num_classes; i++) { 566 int len = ((xXIAnyInfo *) any)->length; 567 568 switch (((xXIAnyInfo *) any)->type) { 569 case XIButtonClass: 570 SwapButtonInfo(dev, (xXIButtonInfo *) any); 571 break; 572 case XIKeyClass: 573 SwapKeyInfo(dev, (xXIKeyInfo *) any); 574 break; 575 case XIValuatorClass: 576 SwapValuatorInfo(dev, (xXIValuatorInfo *) any); 577 break; 578 case XIScrollClass: 579 SwapScrollInfo(dev, (xXIScrollInfo *) any); 580 break; 581 case XITouchClass: 582 SwapTouchInfo(dev, (xXITouchInfo *) any); 583 break; 584 585 } 586 587 any += len * 4; 588 } 589 590 swaps(&info->deviceid); 591 swaps(&info->use); 592 swaps(&info->attachment); 593 swaps(&info->num_classes); 594 swaps(&info->name_len); 595 596} 597