xiquerydevice.c revision 9ace9065
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 45#include "xiquerydevice.h" 46 47static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); 48static int 49ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info); 50static int SizeDeviceInfo(DeviceIntPtr dev); 51static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); 52int 53SProcXIQueryDevice(ClientPtr client) 54{ 55 char n; 56 57 REQUEST(xXIQueryDeviceReq); 58 59 swaps(&stuff->length, n); 60 swaps(&stuff->deviceid, n); 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 && stuff->deviceid != XIAllMasterDevices) 79 { 80 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); 81 if (rc != Success) 82 { 83 client->errorValue = stuff->deviceid; 84 return rc; 85 } 86 len += SizeDeviceInfo(dev); 87 } 88 else 89 { 90 skip = calloc(sizeof(Bool), inputInfo.numDevices); 91 if (!skip) 92 return BadAlloc; 93 94 for (dev = inputInfo.devices; dev; dev = dev->next, i++) 95 { 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 { 103 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); 104 if (!skip[i]) 105 len += SizeDeviceInfo(dev); 106 } 107 } 108 109 info = calloc(1, len); 110 if (!info) { 111 free(skip); 112 return BadAlloc; 113 } 114 115 memset(&rep, 0, sizeof(xXIQueryDeviceReply)); 116 rep.repType = X_Reply; 117 rep.RepType = X_XIQueryDevice; 118 rep.sequenceNumber = client->sequence; 119 rep.length = len/4; 120 rep.num_devices = 0; 121 122 ptr = info; 123 if (dev) 124 { 125 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 126 if (client->swapped) 127 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 128 info += len; 129 rep.num_devices = 1; 130 } else 131 { 132 i = 0; 133 for (dev = inputInfo.devices; dev; dev = dev->next, i++) 134 { 135 if (!skip[i]) 136 { 137 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 138 if (client->swapped) 139 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 140 info += len; 141 rep.num_devices++; 142 } 143 } 144 145 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) 146 { 147 if (!skip[i]) 148 { 149 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 150 if (client->swapped) 151 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 152 info += len; 153 rep.num_devices++; 154 } 155 } 156 } 157 158 len = rep.length * 4; 159 WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); 160 WriteToClient(client, len, ptr); 161 free(ptr); 162 free(skip); 163 return rc; 164} 165 166void 167SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) 168{ 169 char n; 170 171 swaps(&rep->sequenceNumber, n); 172 swapl(&rep->length, n); 173 swaps(&rep->num_devices, n); 174 175 /* Device info is already swapped, see ProcXIQueryDevice */ 176 177 WriteToClient(client, size, (char *)rep); 178} 179 180 181/** 182 * @return Whether the device should be included in the returned list. 183 */ 184static Bool 185ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev) 186{ 187 /* if all devices are not being queried, only master devices are */ 188 if (deviceid == XIAllDevices || IsMaster(dev)) 189 { 190 int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); 191 if (rc == Success) 192 return FALSE; 193 } 194 return TRUE; 195} 196 197/** 198 * @return The number of bytes needed to store this device's xXIDeviceInfo 199 * (and its classes). 200 */ 201static int 202SizeDeviceInfo(DeviceIntPtr dev) 203{ 204 int len = sizeof(xXIDeviceInfo); 205 206 /* 4-padded name */ 207 len += pad_to_int32(strlen(dev->name)); 208 209 return len + SizeDeviceClasses(dev); 210 211} 212 213/* 214 * @return The number of bytes needed to store this device's classes. 215 */ 216int 217SizeDeviceClasses(DeviceIntPtr dev) 218{ 219 int len = 0; 220 221 if (dev->button) 222 { 223 len += sizeof(xXIButtonInfo); 224 len += dev->button->numButtons * sizeof(Atom); 225 len += pad_to_int32(bits_to_bytes(dev->button->numButtons)); 226 } 227 228 if (dev->key) 229 { 230 XkbDescPtr xkb = dev->key->xkbInfo->desc; 231 len += sizeof(xXIKeyInfo); 232 len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); 233 } 234 235 if (dev->valuator) 236 len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; 237 238 return len; 239} 240 241 242/** 243 * Write button information into info. 244 * @return Number of bytes written into info. 245 */ 246int 247ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState) 248{ 249 unsigned char *bits; 250 int mask_len; 251 int i; 252 253 if (!dev || !dev->button) 254 return 0; 255 256 mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons)); 257 258 info->type = ButtonClass; 259 info->num_buttons = dev->button->numButtons; 260 info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + 261 info->num_buttons + mask_len; 262 info->sourceid = dev->button->sourceid; 263 264 bits = (unsigned char*)&info[1]; 265 memset(bits, 0, mask_len * 4); 266 267 if (reportState) 268 for (i = 0; i < dev->button->numButtons; i++) 269 if (BitIsOn(dev->button->down, i)) 270 SetBit(bits, i); 271 272 bits += mask_len * 4; 273 memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom)); 274 275 return info->length * 4; 276} 277 278static void 279SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) 280{ 281 char n; 282 Atom *btn; 283 int i; 284 swaps(&info->type, n); 285 swaps(&info->length, n); 286 swaps(&info->sourceid, n); 287 288 for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) 289 swaps(btn, n); 290 291 swaps(&info->num_buttons, n); 292} 293 294/** 295 * Write key information into info. 296 * @return Number of bytes written into info. 297 */ 298int 299ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) 300{ 301 int i; 302 XkbDescPtr xkb = dev->key->xkbInfo->desc; 303 uint32_t *kc; 304 305 info->type = KeyClass; 306 info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; 307 info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; 308 info->sourceid = dev->key->sourceid; 309 310 kc = (uint32_t*)&info[1]; 311 for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) 312 *kc = i; 313 314 return info->length * 4; 315} 316 317static void 318SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) 319{ 320 char n; 321 uint32_t *key; 322 int i; 323 swaps(&info->type, n); 324 swaps(&info->length, n); 325 swaps(&info->sourceid, n); 326 327 for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) 328 swapl(key, n); 329 330 swaps(&info->num_keycodes, n); 331} 332 333/** 334 * List axis information for the given axis. 335 * 336 * @return The number of bytes written into info. 337 */ 338int 339ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber, 340 Bool reportState) 341{ 342 ValuatorClassPtr v = dev->valuator; 343 344 info->type = ValuatorClass; 345 info->length = sizeof(xXIValuatorInfo)/4; 346 info->label = v->axes[axisnumber].label; 347 info->min.integral = v->axes[axisnumber].min_value; 348 info->min.frac = 0; 349 info->max.integral = v->axes[axisnumber].max_value; 350 info->max.frac = 0; 351 info->value.integral = (int)v->axisVal[axisnumber]; 352 info->value.frac = (int)(v->axisVal[axisnumber] * (1 << 16) * (1 << 16)); 353 info->resolution = v->axes[axisnumber].resolution; 354 info->number = axisnumber; 355 info->mode = valuator_get_mode(dev, axisnumber); 356 info->sourceid = v->sourceid; 357 358 if (!reportState) 359 info->value = info->min; 360 361 return info->length * 4; 362} 363 364static void 365SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) 366{ 367 char n; 368 swaps(&info->type, n); 369 swaps(&info->length, n); 370 swapl(&info->label, n); 371 swapl(&info->min.integral, n); 372 swapl(&info->min.frac, n); 373 swapl(&info->max.integral, n); 374 swapl(&info->max.frac, n); 375 swaps(&info->number, n); 376 swaps(&info->sourceid, n); 377} 378 379int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) 380{ 381 DeviceIntPtr master = dev->u.master; 382 int use; 383 384 if (IsMaster(dev)) 385 { 386 DeviceIntPtr paired = GetPairedDevice(dev); 387 use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; 388 *attachment = (paired ? paired->id : 0); 389 } else if (master) 390 { 391 use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; 392 *attachment = master->id; 393 } else 394 use = XIFloatingSlave; 395 396 return use; 397} 398 399/** 400 * Write the info for device dev into the buffer pointed to by info. 401 * 402 * @return The number of bytes used. 403 */ 404static int 405ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info) 406{ 407 char *any = (char*)&info[1]; 408 int len = 0, total_len = 0; 409 410 info->deviceid = dev->id; 411 info->use = GetDeviceUse(dev, &info->attachment); 412 info->num_classes = 0; 413 info->name_len = strlen(dev->name); 414 info->enabled = dev->enabled; 415 total_len = sizeof(xXIDeviceInfo); 416 417 len = pad_to_int32(info->name_len); 418 memset(any, 0, len); 419 strncpy(any, dev->name, info->name_len); 420 any += len; 421 total_len += len; 422 423 total_len += ListDeviceClasses(client, dev, any, &info->num_classes); 424 return total_len; 425} 426 427/** 428 * Write the class info of the device into the memory pointed to by any, set 429 * nclasses to the number of classes in total and return the number of bytes 430 * written. 431 */ 432int 433ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, 434 char *any, uint16_t *nclasses) 435{ 436 int total_len = 0; 437 int len; 438 int i; 439 int rc; 440 441 /* Check if the current device state should be suppressed */ 442 rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); 443 444 if (dev->button) 445 { 446 (*nclasses)++; 447 len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success); 448 any += len; 449 total_len += len; 450 } 451 452 if (dev->key) 453 { 454 (*nclasses)++; 455 len = ListKeyInfo(dev, (xXIKeyInfo*)any); 456 any += len; 457 total_len += len; 458 } 459 460 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) 461 { 462 (*nclasses)++; 463 len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success); 464 any += len; 465 total_len += len; 466 } 467 468 return total_len; 469} 470 471static void 472SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) 473{ 474 char n; 475 char *any = (char*)&info[1]; 476 int i; 477 478 /* Skip over name */ 479 any += pad_to_int32(info->name_len); 480 481 for (i = 0; i < info->num_classes; i++) 482 { 483 int len = ((xXIAnyInfo*)any)->length; 484 switch(((xXIAnyInfo*)any)->type) 485 { 486 case XIButtonClass: 487 SwapButtonInfo(dev, (xXIButtonInfo*)any); 488 break; 489 case XIKeyClass: 490 SwapKeyInfo(dev, (xXIKeyInfo*)any); 491 break; 492 case XIValuatorClass: 493 SwapValuatorInfo(dev, (xXIValuatorInfo*)any); 494 break; 495 } 496 497 any += len * 4; 498 } 499 500 swaps(&info->deviceid, n); 501 swaps(&info->use, n); 502 swaps(&info->attachment, n); 503 swaps(&info->num_classes, n); 504 swaps(&info->name_len, n); 505 506} 507