xiproperty.c revision e383896c
1/* 2 * Copyright © 2006 Keith Packard 3 * Copyright © 2008 Peter Hutterer 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WAXIANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WAXIANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 26/* This code is a modified version of randr/rrproperty.c */ 27 28#ifdef HAVE_DIX_CONFIG_H 29#include <dix-config.h> 30#endif 31 32#include "dix.h" 33#include "inputstr.h" 34#include <X11/extensions/XI.h> 35#include <X11/Xatom.h> 36#include <X11/extensions/XIproto.h> 37#include <X11/extensions/XI2proto.h> 38#include "exglobals.h" 39#include "exevents.h" 40#include "swaprep.h" 41 42#include "xiproperty.h" 43#include "xserver-properties.h" 44 45/** 46 * Properties used or alloced from inside the server. 47 */ 48static struct dev_properties { 49 Atom type; 50 const char *name; 51} dev_properties[] = { 52 {0, XI_PROP_ENABLED}, 53 {0, XI_PROP_XTEST_DEVICE}, 54 {0, XATOM_FLOAT}, 55 {0, ACCEL_PROP_PROFILE_NUMBER}, 56 {0, ACCEL_PROP_CONSTANT_DECELERATION}, 57 {0, ACCEL_PROP_ADAPTIVE_DECELERATION}, 58 {0, ACCEL_PROP_VELOCITY_SCALING}, 59 {0, AXIS_LABEL_PROP}, 60 {0, AXIS_LABEL_PROP_REL_X}, 61 {0, AXIS_LABEL_PROP_REL_Y}, 62 {0, AXIS_LABEL_PROP_REL_Z}, 63 {0, AXIS_LABEL_PROP_REL_RX}, 64 {0, AXIS_LABEL_PROP_REL_RY}, 65 {0, AXIS_LABEL_PROP_REL_RZ}, 66 {0, AXIS_LABEL_PROP_REL_HWHEEL}, 67 {0, AXIS_LABEL_PROP_REL_DIAL}, 68 {0, AXIS_LABEL_PROP_REL_WHEEL}, 69 {0, AXIS_LABEL_PROP_REL_MISC}, 70 {0, AXIS_LABEL_PROP_REL_VSCROLL}, 71 {0, AXIS_LABEL_PROP_REL_HSCROLL}, 72 {0, AXIS_LABEL_PROP_ABS_X}, 73 {0, AXIS_LABEL_PROP_ABS_Y}, 74 {0, AXIS_LABEL_PROP_ABS_Z}, 75 {0, AXIS_LABEL_PROP_ABS_RX}, 76 {0, AXIS_LABEL_PROP_ABS_RY}, 77 {0, AXIS_LABEL_PROP_ABS_RZ}, 78 {0, AXIS_LABEL_PROP_ABS_THROTTLE}, 79 {0, AXIS_LABEL_PROP_ABS_RUDDER}, 80 {0, AXIS_LABEL_PROP_ABS_WHEEL}, 81 {0, AXIS_LABEL_PROP_ABS_GAS}, 82 {0, AXIS_LABEL_PROP_ABS_BRAKE}, 83 {0, AXIS_LABEL_PROP_ABS_HAT0X}, 84 {0, AXIS_LABEL_PROP_ABS_HAT0Y}, 85 {0, AXIS_LABEL_PROP_ABS_HAT1X}, 86 {0, AXIS_LABEL_PROP_ABS_HAT1Y}, 87 {0, AXIS_LABEL_PROP_ABS_HAT2X}, 88 {0, AXIS_LABEL_PROP_ABS_HAT2Y}, 89 {0, AXIS_LABEL_PROP_ABS_HAT3X}, 90 {0, AXIS_LABEL_PROP_ABS_HAT3Y}, 91 {0, AXIS_LABEL_PROP_ABS_PRESSURE}, 92 {0, AXIS_LABEL_PROP_ABS_DISTANCE}, 93 {0, AXIS_LABEL_PROP_ABS_TILT_X}, 94 {0, AXIS_LABEL_PROP_ABS_TILT_Y}, 95 {0, AXIS_LABEL_PROP_ABS_TOOL_WIDTH}, 96 {0, AXIS_LABEL_PROP_ABS_VOLUME}, 97 {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR}, 98 {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR}, 99 {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR}, 100 {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR}, 101 {0, AXIS_LABEL_PROP_ABS_MT_ORIENTATION}, 102 {0, AXIS_LABEL_PROP_ABS_MT_POSITION_X}, 103 {0, AXIS_LABEL_PROP_ABS_MT_POSITION_Y}, 104 {0, AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE}, 105 {0, AXIS_LABEL_PROP_ABS_MT_BLOB_ID}, 106 {0, AXIS_LABEL_PROP_ABS_MT_TRACKING_ID}, 107 {0, AXIS_LABEL_PROP_ABS_MT_PRESSURE}, 108 {0, AXIS_LABEL_PROP_ABS_MT_DISTANCE}, 109 {0, AXIS_LABEL_PROP_ABS_MT_TOOL_X}, 110 {0, AXIS_LABEL_PROP_ABS_MT_TOOL_Y}, 111 {0, AXIS_LABEL_PROP_ABS_MISC}, 112 {0, BTN_LABEL_PROP}, 113 {0, BTN_LABEL_PROP_BTN_UNKNOWN}, 114 {0, BTN_LABEL_PROP_BTN_WHEEL_UP}, 115 {0, BTN_LABEL_PROP_BTN_WHEEL_DOWN}, 116 {0, BTN_LABEL_PROP_BTN_HWHEEL_LEFT}, 117 {0, BTN_LABEL_PROP_BTN_HWHEEL_RIGHT}, 118 {0, BTN_LABEL_PROP_BTN_0}, 119 {0, BTN_LABEL_PROP_BTN_1}, 120 {0, BTN_LABEL_PROP_BTN_2}, 121 {0, BTN_LABEL_PROP_BTN_3}, 122 {0, BTN_LABEL_PROP_BTN_4}, 123 {0, BTN_LABEL_PROP_BTN_5}, 124 {0, BTN_LABEL_PROP_BTN_6}, 125 {0, BTN_LABEL_PROP_BTN_7}, 126 {0, BTN_LABEL_PROP_BTN_8}, 127 {0, BTN_LABEL_PROP_BTN_9}, 128 {0, BTN_LABEL_PROP_BTN_LEFT}, 129 {0, BTN_LABEL_PROP_BTN_RIGHT}, 130 {0, BTN_LABEL_PROP_BTN_MIDDLE}, 131 {0, BTN_LABEL_PROP_BTN_SIDE}, 132 {0, BTN_LABEL_PROP_BTN_EXTRA}, 133 {0, BTN_LABEL_PROP_BTN_FORWARD}, 134 {0, BTN_LABEL_PROP_BTN_BACK}, 135 {0, BTN_LABEL_PROP_BTN_TASK}, 136 {0, BTN_LABEL_PROP_BTN_TRIGGER}, 137 {0, BTN_LABEL_PROP_BTN_THUMB}, 138 {0, BTN_LABEL_PROP_BTN_THUMB2}, 139 {0, BTN_LABEL_PROP_BTN_TOP}, 140 {0, BTN_LABEL_PROP_BTN_TOP2}, 141 {0, BTN_LABEL_PROP_BTN_PINKIE}, 142 {0, BTN_LABEL_PROP_BTN_BASE}, 143 {0, BTN_LABEL_PROP_BTN_BASE2}, 144 {0, BTN_LABEL_PROP_BTN_BASE3}, 145 {0, BTN_LABEL_PROP_BTN_BASE4}, 146 {0, BTN_LABEL_PROP_BTN_BASE5}, 147 {0, BTN_LABEL_PROP_BTN_BASE6}, 148 {0, BTN_LABEL_PROP_BTN_DEAD}, 149 {0, BTN_LABEL_PROP_BTN_A}, 150 {0, BTN_LABEL_PROP_BTN_B}, 151 {0, BTN_LABEL_PROP_BTN_C}, 152 {0, BTN_LABEL_PROP_BTN_X}, 153 {0, BTN_LABEL_PROP_BTN_Y}, 154 {0, BTN_LABEL_PROP_BTN_Z}, 155 {0, BTN_LABEL_PROP_BTN_TL}, 156 {0, BTN_LABEL_PROP_BTN_TR}, 157 {0, BTN_LABEL_PROP_BTN_TL2}, 158 {0, BTN_LABEL_PROP_BTN_TR2}, 159 {0, BTN_LABEL_PROP_BTN_SELECT}, 160 {0, BTN_LABEL_PROP_BTN_START}, 161 {0, BTN_LABEL_PROP_BTN_MODE}, 162 {0, BTN_LABEL_PROP_BTN_THUMBL}, 163 {0, BTN_LABEL_PROP_BTN_THUMBR}, 164 {0, BTN_LABEL_PROP_BTN_TOOL_PEN}, 165 {0, BTN_LABEL_PROP_BTN_TOOL_RUBBER}, 166 {0, BTN_LABEL_PROP_BTN_TOOL_BRUSH}, 167 {0, BTN_LABEL_PROP_BTN_TOOL_PENCIL}, 168 {0, BTN_LABEL_PROP_BTN_TOOL_AIRBRUSH}, 169 {0, BTN_LABEL_PROP_BTN_TOOL_FINGER}, 170 {0, BTN_LABEL_PROP_BTN_TOOL_MOUSE}, 171 {0, BTN_LABEL_PROP_BTN_TOOL_LENS}, 172 {0, BTN_LABEL_PROP_BTN_TOUCH}, 173 {0, BTN_LABEL_PROP_BTN_STYLUS}, 174 {0, BTN_LABEL_PROP_BTN_STYLUS2}, 175 {0, BTN_LABEL_PROP_BTN_TOOL_DOUBLETAP}, 176 {0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP}, 177 {0, BTN_LABEL_PROP_BTN_GEAR_DOWN}, 178 {0, BTN_LABEL_PROP_BTN_GEAR_UP}, 179 {0, XI_PROP_TRANSFORM} 180}; 181 182static long XIPropHandlerID = 1; 183 184static void 185send_property_event(DeviceIntPtr dev, Atom property, int what) 186{ 187 int state = (what == XIPropertyDeleted) ? PropertyDelete : PropertyNewValue; 188 devicePropertyNotify event = { 189 .type = DevicePropertyNotify, 190 .deviceid = dev->id, 191 .state = state, 192 .atom = property, 193 .time = currentTime.milliseconds 194 }; 195 xXIPropertyEvent xi2 = { 196 .type = GenericEvent, 197 .extension = IReqCode, 198 .length = 0, 199 .evtype = XI_PropertyEvent, 200 .deviceid = dev->id, 201 .time = currentTime.milliseconds, 202 .property = property, 203 .what = what 204 }; 205 206 SendEventToAllWindows(dev, DevicePropertyNotifyMask, (xEvent *) &event, 1); 207 208 SendEventToAllWindows(dev, GetEventFilter(dev, (xEvent *) &xi2), 209 (xEvent *) &xi2, 1); 210} 211 212static int 213list_atoms(DeviceIntPtr dev, int *natoms, Atom **atoms_return) 214{ 215 XIPropertyPtr prop; 216 Atom *atoms = NULL; 217 int nprops = 0; 218 219 for (prop = dev->properties.properties; prop; prop = prop->next) 220 nprops++; 221 if (nprops) { 222 Atom *a; 223 224 atoms = xallocarray(nprops, sizeof(Atom)); 225 if (!atoms) 226 return BadAlloc; 227 a = atoms; 228 for (prop = dev->properties.properties; prop; prop = prop->next, a++) 229 *a = prop->propertyName; 230 } 231 232 *natoms = nprops; 233 *atoms_return = atoms; 234 return Success; 235} 236 237static int 238get_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type, 239 BOOL delete, int offset, int length, 240 int *bytes_after, Atom *type_return, int *format, int *nitems, 241 int *length_return, char **data) 242{ 243 unsigned long n, len, ind; 244 int rc; 245 XIPropertyPtr prop; 246 XIPropertyValuePtr prop_value; 247 248 if (!ValidAtom(property)) { 249 client->errorValue = property; 250 return BadAtom; 251 } 252 if ((delete != xTrue) && (delete != xFalse)) { 253 client->errorValue = delete; 254 return BadValue; 255 } 256 257 if ((type != AnyPropertyType) && !ValidAtom(type)) { 258 client->errorValue = type; 259 return BadAtom; 260 } 261 262 for (prop = dev->properties.properties; prop; prop = prop->next) 263 if (prop->propertyName == property) 264 break; 265 266 if (!prop) { 267 *bytes_after = 0; 268 *type_return = None; 269 *format = 0; 270 *nitems = 0; 271 *length_return = 0; 272 return Success; 273 } 274 275 rc = XIGetDeviceProperty(dev, property, &prop_value); 276 if (rc != Success) { 277 client->errorValue = property; 278 return rc; 279 } 280 281 /* If the request type and actual type don't match. Return the 282 property information, but not the data. */ 283 284 if (((type != prop_value->type) && (type != AnyPropertyType))) { 285 *bytes_after = prop_value->size; 286 *format = prop_value->format; 287 *length_return = 0; 288 *nitems = 0; 289 *type_return = prop_value->type; 290 return Success; 291 } 292 293 /* Return type, format, value to client */ 294 n = (prop_value->format / 8) * prop_value->size; /* size (bytes) of prop */ 295 ind = offset << 2; 296 297 /* If offset is invalid such that it causes "len" to 298 be negative, it's a value error. */ 299 300 if (n < ind) { 301 client->errorValue = offset; 302 return BadValue; 303 } 304 305 len = min(n - ind, 4 * length); 306 307 *bytes_after = n - (ind + len); 308 *format = prop_value->format; 309 *length_return = len; 310 if (prop_value->format) 311 *nitems = len / (prop_value->format / 8); 312 else 313 *nitems = 0; 314 *type_return = prop_value->type; 315 316 *data = (char *) prop_value->data + ind; 317 318 return Success; 319} 320 321static int 322check_change_property(ClientPtr client, Atom property, Atom type, int format, 323 int mode, int nitems) 324{ 325 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 326 (mode != PropModePrepend)) { 327 client->errorValue = mode; 328 return BadValue; 329 } 330 if ((format != 8) && (format != 16) && (format != 32)) { 331 client->errorValue = format; 332 return BadValue; 333 } 334 335 if (!ValidAtom(property)) { 336 client->errorValue = property; 337 return BadAtom; 338 } 339 if (!ValidAtom(type)) { 340 client->errorValue = type; 341 return BadAtom; 342 } 343 344 return Success; 345} 346 347static int 348change_property(ClientPtr client, DeviceIntPtr dev, Atom property, Atom type, 349 int format, int mode, int len, void *data) 350{ 351 int rc = Success; 352 353 rc = XIChangeDeviceProperty(dev, property, type, format, mode, len, data, 354 TRUE); 355 if (rc != Success) 356 client->errorValue = property; 357 358 return rc; 359} 360 361/** 362 * Return the atom assigned to the specified string or 0 if the atom isn't known 363 * to the DIX. 364 * 365 * If name is NULL, None is returned. 366 */ 367Atom 368XIGetKnownProperty(const char *name) 369{ 370 int i; 371 372 if (!name) 373 return None; 374 375 for (i = 0; i < ARRAY_SIZE(dev_properties); i++) { 376 if (strcmp(name, dev_properties[i].name) == 0) { 377 if (dev_properties[i].type == None) { 378 dev_properties[i].type = 379 MakeAtom(dev_properties[i].name, 380 strlen(dev_properties[i].name), TRUE); 381 } 382 383 return dev_properties[i].type; 384 } 385 } 386 387 return 0; 388} 389 390void 391XIResetProperties(void) 392{ 393 int i; 394 395 for (i = 0; i < ARRAY_SIZE(dev_properties); i++) 396 dev_properties[i].type = None; 397} 398 399/** 400 * Convert the given property's value(s) into @nelem_return integer values and 401 * store them in @buf_return. If @nelem_return is larger than the number of 402 * values in the property, @nelem_return is set to the number of values in the 403 * property. 404 * 405 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 406 * automatically and must be freed by the caller. 407 * 408 * Possible return codes. 409 * Success ... No error. 410 * BadMatch ... Wrong atom type, atom is not XA_INTEGER 411 * BadAlloc ... NULL passed as buffer and allocation failed. 412 * BadLength ... @buff is NULL but @nelem_return is non-zero. 413 * 414 * @param val The property value 415 * @param nelem_return The maximum number of elements to return. 416 * @param buf_return Pointer to an array of at least @nelem_return values. 417 * @return Success or the error code if an error occurred. 418 */ 419_X_EXPORT int 420XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return) 421{ 422 int i; 423 int *buf; 424 425 if (val->type != XA_INTEGER) 426 return BadMatch; 427 if (!*buf_return && *nelem_return) 428 return BadLength; 429 430 switch (val->format) { 431 case 8: 432 case 16: 433 case 32: 434 break; 435 default: 436 return BadValue; 437 } 438 439 buf = *buf_return; 440 441 if (!buf && !(*nelem_return)) { 442 buf = calloc(val->size, sizeof(int)); 443 if (!buf) 444 return BadAlloc; 445 *buf_return = buf; 446 *nelem_return = val->size; 447 } 448 else if (val->size < *nelem_return) 449 *nelem_return = val->size; 450 451 for (i = 0; i < val->size && i < *nelem_return; i++) { 452 switch (val->format) { 453 case 8: 454 buf[i] = ((CARD8 *) val->data)[i]; 455 break; 456 case 16: 457 buf[i] = ((CARD16 *) val->data)[i]; 458 break; 459 case 32: 460 buf[i] = ((CARD32 *) val->data)[i]; 461 break; 462 } 463 } 464 465 return Success; 466} 467 468/** 469 * Convert the given property's value(s) into @nelem_return float values and 470 * store them in @buf_return. If @nelem_return is larger than the number of 471 * values in the property, @nelem_return is set to the number of values in the 472 * property. 473 * 474 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 475 * automatically and must be freed by the caller. 476 * 477 * Possible errors returned: 478 * Success 479 * BadMatch ... Wrong atom type, atom is not XA_FLOAT 480 * BadValue ... Wrong format, format is not 32 481 * BadAlloc ... NULL passed as buffer and allocation failed. 482 * BadLength ... @buff is NULL but @nelem_return is non-zero. 483 * 484 * @param val The property value 485 * @param nelem_return The maximum number of elements to return. 486 * @param buf_return Pointer to an array of at least @nelem_return values. 487 * @return Success or the error code if an error occurred. 488 */ 489_X_EXPORT int 490XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return) 491{ 492 int i; 493 float *buf; 494 495 if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT)) 496 return BadMatch; 497 498 if (val->format != 32) 499 return BadValue; 500 if (!*buf_return && *nelem_return) 501 return BadLength; 502 503 buf = *buf_return; 504 505 if (!buf && !(*nelem_return)) { 506 buf = calloc(val->size, sizeof(float)); 507 if (!buf) 508 return BadAlloc; 509 *buf_return = buf; 510 *nelem_return = val->size; 511 } 512 else if (val->size < *nelem_return) 513 *nelem_return = val->size; 514 515 for (i = 0; i < val->size && i < *nelem_return; i++) 516 buf[i] = ((float *) val->data)[i]; 517 518 return Success; 519} 520 521/* Registers a new property handler on the given device and returns a unique 522 * identifier for this handler. This identifier is required to unregister the 523 * property handler again. 524 * @return The handler's identifier or 0 if an error occurred. 525 */ 526long 527XIRegisterPropertyHandler(DeviceIntPtr dev, 528 int (*SetProperty) (DeviceIntPtr dev, 529 Atom property, 530 XIPropertyValuePtr prop, 531 BOOL checkonly), 532 int (*GetProperty) (DeviceIntPtr dev, 533 Atom property), 534 int (*DeleteProperty) (DeviceIntPtr dev, 535 Atom property)) 536{ 537 XIPropertyHandlerPtr new_handler; 538 539 new_handler = calloc(1, sizeof(XIPropertyHandler)); 540 if (!new_handler) 541 return 0; 542 543 new_handler->id = XIPropHandlerID++; 544 new_handler->SetProperty = SetProperty; 545 new_handler->GetProperty = GetProperty; 546 new_handler->DeleteProperty = DeleteProperty; 547 new_handler->next = dev->properties.handlers; 548 dev->properties.handlers = new_handler; 549 550 return new_handler->id; 551} 552 553void 554XIUnregisterPropertyHandler(DeviceIntPtr dev, long id) 555{ 556 XIPropertyHandlerPtr curr, prev = NULL; 557 558 curr = dev->properties.handlers; 559 while (curr && curr->id != id) { 560 prev = curr; 561 curr = curr->next; 562 } 563 564 if (!curr) 565 return; 566 567 if (!prev) /* first one */ 568 dev->properties.handlers = curr->next; 569 else 570 prev->next = curr->next; 571 572 free(curr); 573} 574 575static XIPropertyPtr 576XICreateDeviceProperty(Atom property) 577{ 578 XIPropertyPtr prop; 579 580 prop = (XIPropertyPtr) malloc(sizeof(XIPropertyRec)); 581 if (!prop) 582 return NULL; 583 584 prop->next = NULL; 585 prop->propertyName = property; 586 prop->value.type = None; 587 prop->value.format = 0; 588 prop->value.size = 0; 589 prop->value.data = NULL; 590 prop->deletable = TRUE; 591 592 return prop; 593} 594 595static XIPropertyPtr 596XIFetchDeviceProperty(DeviceIntPtr dev, Atom property) 597{ 598 XIPropertyPtr prop; 599 600 for (prop = dev->properties.properties; prop; prop = prop->next) 601 if (prop->propertyName == property) 602 return prop; 603 return NULL; 604} 605 606static void 607XIDestroyDeviceProperty(XIPropertyPtr prop) 608{ 609 free(prop->value.data); 610 free(prop); 611} 612 613/* This function destroys all of the device's property-related stuff, 614 * including removing all device handlers. 615 * DO NOT CALL FROM THE DRIVER. 616 */ 617void 618XIDeleteAllDeviceProperties(DeviceIntPtr device) 619{ 620 XIPropertyPtr prop, next; 621 XIPropertyHandlerPtr curr_handler, next_handler; 622 623 UpdateCurrentTimeIf(); 624 for (prop = device->properties.properties; prop; prop = next) { 625 next = prop->next; 626 send_property_event(device, prop->propertyName, XIPropertyDeleted); 627 XIDestroyDeviceProperty(prop); 628 } 629 630 device->properties.properties = NULL; 631 632 /* Now free all handlers */ 633 curr_handler = device->properties.handlers; 634 while (curr_handler) { 635 next_handler = curr_handler->next; 636 free(curr_handler); 637 curr_handler = next_handler; 638 } 639 640 device->properties.handlers = NULL; 641} 642 643int 644XIDeleteDeviceProperty(DeviceIntPtr device, Atom property, Bool fromClient) 645{ 646 XIPropertyPtr prop, *prev; 647 int rc = Success; 648 649 for (prev = &device->properties.properties; (prop = *prev); 650 prev = &(prop->next)) 651 if (prop->propertyName == property) 652 break; 653 654 if (!prop) 655 return Success; 656 657 if (fromClient && !prop->deletable) 658 return BadAccess; 659 660 /* Ask handlers if we may delete the property */ 661 if (device->properties.handlers) { 662 XIPropertyHandlerPtr handler = device->properties.handlers; 663 664 while (handler) { 665 if (handler->DeleteProperty) 666 rc = handler->DeleteProperty(device, prop->propertyName); 667 if (rc != Success) 668 return rc; 669 handler = handler->next; 670 } 671 } 672 673 if (prop) { 674 UpdateCurrentTimeIf(); 675 *prev = prop->next; 676 send_property_event(device, prop->propertyName, XIPropertyDeleted); 677 XIDestroyDeviceProperty(prop); 678 } 679 680 return Success; 681} 682 683int 684XIChangeDeviceProperty(DeviceIntPtr dev, Atom property, Atom type, 685 int format, int mode, unsigned long len, 686 const void *value, Bool sendevent) 687{ 688 XIPropertyPtr prop; 689 int size_in_bytes; 690 unsigned long total_len; 691 XIPropertyValuePtr prop_value; 692 XIPropertyValueRec new_value; 693 Bool add = FALSE; 694 int rc; 695 696 size_in_bytes = format >> 3; 697 698 /* first see if property already exists */ 699 prop = XIFetchDeviceProperty(dev, property); 700 if (!prop) { /* just add to list */ 701 prop = XICreateDeviceProperty(property); 702 if (!prop) 703 return BadAlloc; 704 add = TRUE; 705 mode = PropModeReplace; 706 } 707 prop_value = &prop->value; 708 709 /* To append or prepend to a property the request format and type 710 must match those of the already defined property. The 711 existing format and type are irrelevant when using the mode 712 "PropModeReplace" since they will be written over. */ 713 714 if ((format != prop_value->format) && (mode != PropModeReplace)) 715 return BadMatch; 716 if ((prop_value->type != type) && (mode != PropModeReplace)) 717 return BadMatch; 718 new_value = *prop_value; 719 if (mode == PropModeReplace) 720 total_len = len; 721 else 722 total_len = prop_value->size + len; 723 724 if (mode == PropModeReplace || len > 0) { 725 void *new_data = NULL, *old_data = NULL; 726 727 new_value.data = xallocarray(total_len, size_in_bytes); 728 if (!new_value.data && total_len && size_in_bytes) { 729 if (add) 730 XIDestroyDeviceProperty(prop); 731 return BadAlloc; 732 } 733 new_value.size = len; 734 new_value.type = type; 735 new_value.format = format; 736 737 switch (mode) { 738 case PropModeReplace: 739 new_data = new_value.data; 740 old_data = NULL; 741 break; 742 case PropModeAppend: 743 new_data = (void *) (((char *) new_value.data) + 744 (prop_value->size * size_in_bytes)); 745 old_data = new_value.data; 746 break; 747 case PropModePrepend: 748 new_data = new_value.data; 749 old_data = (void *) (((char *) new_value.data) + 750 (prop_value->size * size_in_bytes)); 751 break; 752 } 753 if (new_data) 754 memcpy((char *) new_data, value, len * size_in_bytes); 755 if (old_data) 756 memcpy((char *) old_data, (char *) prop_value->data, 757 prop_value->size * size_in_bytes); 758 759 if (dev->properties.handlers) { 760 XIPropertyHandlerPtr handler; 761 BOOL checkonly = TRUE; 762 763 /* run through all handlers with checkonly TRUE, then again with 764 * checkonly FALSE. Handlers MUST return error codes on the 765 * checkonly run, errors on the second run are ignored */ 766 do { 767 handler = dev->properties.handlers; 768 while (handler) { 769 if (handler->SetProperty) { 770 input_lock(); 771 rc = handler->SetProperty(dev, prop->propertyName, 772 &new_value, checkonly); 773 input_unlock(); 774 if (checkonly && rc != Success) { 775 free(new_value.data); 776 if (add) 777 XIDestroyDeviceProperty(prop); 778 return rc; 779 } 780 } 781 handler = handler->next; 782 } 783 checkonly = !checkonly; 784 } while (!checkonly); 785 } 786 free(prop_value->data); 787 *prop_value = new_value; 788 } 789 else if (len == 0) { 790 /* do nothing */ 791 } 792 793 if (add) { 794 prop->next = dev->properties.properties; 795 dev->properties.properties = prop; 796 } 797 798 if (sendevent) { 799 UpdateCurrentTimeIf(); 800 send_property_event(dev, prop->propertyName, 801 (add) ? XIPropertyCreated : XIPropertyModified); 802 } 803 804 return Success; 805} 806 807int 808XIGetDeviceProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value) 809{ 810 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); 811 int rc; 812 813 if (!prop) { 814 *value = NULL; 815 return BadAtom; 816 } 817 818 /* If we can, try to update the property value first */ 819 if (dev->properties.handlers) { 820 XIPropertyHandlerPtr handler = dev->properties.handlers; 821 822 while (handler) { 823 if (handler->GetProperty) { 824 rc = handler->GetProperty(dev, prop->propertyName); 825 if (rc != Success) { 826 *value = NULL; 827 return rc; 828 } 829 } 830 handler = handler->next; 831 } 832 } 833 834 *value = &prop->value; 835 return Success; 836} 837 838int 839XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable) 840{ 841 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); 842 843 if (!prop) 844 return BadAtom; 845 846 prop->deletable = deletable; 847 return Success; 848} 849 850int 851ProcXListDeviceProperties(ClientPtr client) 852{ 853 Atom *atoms; 854 xListDevicePropertiesReply rep; 855 int natoms; 856 DeviceIntPtr dev; 857 int rc = Success; 858 859 REQUEST(xListDevicePropertiesReq); 860 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 861 862 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess); 863 if (rc != Success) 864 return rc; 865 866 rc = list_atoms(dev, &natoms, &atoms); 867 if (rc != Success) 868 return rc; 869 870 rep = (xListDevicePropertiesReply) { 871 .repType = X_Reply, 872 .RepType = X_ListDeviceProperties, 873 .sequenceNumber = client->sequence, 874 .length = natoms, 875 .nAtoms = natoms 876 }; 877 878 WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep); 879 if (natoms) { 880 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 881 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 882 free(atoms); 883 } 884 return rc; 885} 886 887int 888ProcXChangeDeviceProperty(ClientPtr client) 889{ 890 REQUEST(xChangeDevicePropertyReq); 891 DeviceIntPtr dev; 892 unsigned long len; 893 uint64_t totalSize; 894 int rc; 895 896 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 897 UpdateCurrentTime(); 898 899 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 900 if (rc != Success) 901 return rc; 902 903 rc = check_change_property(client, stuff->property, stuff->type, 904 stuff->format, stuff->mode, stuff->nUnits); 905 if (rc != Success) 906 return rc; 907 908 len = stuff->nUnits; 909 if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq)))) 910 return BadLength; 911 912 totalSize = len * (stuff->format / 8); 913 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize); 914 915 rc = change_property(client, dev, stuff->property, stuff->type, 916 stuff->format, stuff->mode, len, (void *) &stuff[1]); 917 return rc; 918} 919 920int 921ProcXDeleteDeviceProperty(ClientPtr client) 922{ 923 REQUEST(xDeleteDevicePropertyReq); 924 DeviceIntPtr dev; 925 int rc; 926 927 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 928 UpdateCurrentTime(); 929 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 930 if (rc != Success) 931 return rc; 932 933 if (!ValidAtom(stuff->property)) { 934 client->errorValue = stuff->property; 935 return BadAtom; 936 } 937 938 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 939 return rc; 940} 941 942int 943ProcXGetDeviceProperty(ClientPtr client) 944{ 945 REQUEST(xGetDevicePropertyReq); 946 DeviceIntPtr dev; 947 int length; 948 int rc, format, nitems, bytes_after; 949 char *data; 950 Atom type; 951 xGetDevicePropertyReply reply; 952 953 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 954 if (stuff->delete) 955 UpdateCurrentTime(); 956 rc = dixLookupDevice(&dev, stuff->deviceid, client, 957 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 958 if (rc != Success) 959 return rc; 960 961 rc = get_property(client, dev, stuff->property, stuff->type, 962 stuff->delete, stuff->longOffset, stuff->longLength, 963 &bytes_after, &type, &format, &nitems, &length, &data); 964 965 if (rc != Success) 966 return rc; 967 968 reply = (xGetDevicePropertyReply) { 969 .repType = X_Reply, 970 .RepType = X_GetDeviceProperty, 971 .sequenceNumber = client->sequence, 972 .length = bytes_to_int32(length), 973 .propertyType = type, 974 .bytesAfter = bytes_after, 975 .nItems = nitems, 976 .format = format, 977 .deviceid = dev->id 978 }; 979 980 if (stuff->delete && (reply.bytesAfter == 0)) 981 send_property_event(dev, stuff->property, XIPropertyDeleted); 982 983 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 984 985 if (length) { 986 switch (reply.format) { 987 case 32: 988 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 989 break; 990 case 16: 991 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 992 break; 993 default: 994 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 995 break; 996 } 997 WriteSwappedDataToClient(client, length, data); 998 } 999 1000 /* delete the Property */ 1001 if (stuff->delete && (reply.bytesAfter == 0)) { 1002 XIPropertyPtr prop, *prev; 1003 1004 for (prev = &dev->properties.properties; (prop = *prev); 1005 prev = &prop->next) { 1006 if (prop->propertyName == stuff->property) { 1007 *prev = prop->next; 1008 XIDestroyDeviceProperty(prop); 1009 break; 1010 } 1011 } 1012 } 1013 return Success; 1014} 1015 1016int _X_COLD 1017SProcXListDeviceProperties(ClientPtr client) 1018{ 1019 REQUEST(xListDevicePropertiesReq); 1020 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 1021 1022 swaps(&stuff->length); 1023 return (ProcXListDeviceProperties(client)); 1024} 1025 1026int _X_COLD 1027SProcXChangeDeviceProperty(ClientPtr client) 1028{ 1029 REQUEST(xChangeDevicePropertyReq); 1030 1031 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 1032 swaps(&stuff->length); 1033 swapl(&stuff->property); 1034 swapl(&stuff->type); 1035 swapl(&stuff->nUnits); 1036 return (ProcXChangeDeviceProperty(client)); 1037} 1038 1039int _X_COLD 1040SProcXDeleteDeviceProperty(ClientPtr client) 1041{ 1042 REQUEST(xDeleteDevicePropertyReq); 1043 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 1044 1045 swaps(&stuff->length); 1046 swapl(&stuff->property); 1047 return (ProcXDeleteDeviceProperty(client)); 1048} 1049 1050int _X_COLD 1051SProcXGetDeviceProperty(ClientPtr client) 1052{ 1053 REQUEST(xGetDevicePropertyReq); 1054 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 1055 1056 swaps(&stuff->length); 1057 swapl(&stuff->property); 1058 swapl(&stuff->type); 1059 swapl(&stuff->longOffset); 1060 swapl(&stuff->longLength); 1061 return (ProcXGetDeviceProperty(client)); 1062} 1063 1064/* Reply swapping */ 1065 1066void _X_COLD 1067SRepXListDeviceProperties(ClientPtr client, int size, 1068 xListDevicePropertiesReply * rep) 1069{ 1070 swaps(&rep->sequenceNumber); 1071 swapl(&rep->length); 1072 swaps(&rep->nAtoms); 1073 /* properties will be swapped later, see ProcXListDeviceProperties */ 1074 WriteToClient(client, size, rep); 1075} 1076 1077void _X_COLD 1078SRepXGetDeviceProperty(ClientPtr client, int size, 1079 xGetDevicePropertyReply * rep) 1080{ 1081 swaps(&rep->sequenceNumber); 1082 swapl(&rep->length); 1083 swapl(&rep->propertyType); 1084 swapl(&rep->bytesAfter); 1085 swapl(&rep->nItems); 1086 /* data will be swapped, see ProcXGetDeviceProperty */ 1087 WriteToClient(client, size, rep); 1088} 1089 1090/* XI2 Request/reply handling */ 1091int 1092ProcXIListProperties(ClientPtr client) 1093{ 1094 Atom *atoms; 1095 xXIListPropertiesReply rep; 1096 int natoms; 1097 DeviceIntPtr dev; 1098 int rc = Success; 1099 1100 REQUEST(xXIListPropertiesReq); 1101 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1102 1103 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess); 1104 if (rc != Success) 1105 return rc; 1106 1107 rc = list_atoms(dev, &natoms, &atoms); 1108 if (rc != Success) 1109 return rc; 1110 1111 rep = (xXIListPropertiesReply) { 1112 .repType = X_Reply, 1113 .RepType = X_XIListProperties, 1114 .sequenceNumber = client->sequence, 1115 .length = natoms, 1116 .num_properties = natoms 1117 }; 1118 1119 WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep); 1120 if (natoms) { 1121 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 1122 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 1123 free(atoms); 1124 } 1125 return rc; 1126} 1127 1128int 1129ProcXIChangeProperty(ClientPtr client) 1130{ 1131 int rc; 1132 DeviceIntPtr dev; 1133 uint64_t totalSize; 1134 unsigned long len; 1135 1136 REQUEST(xXIChangePropertyReq); 1137 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1138 UpdateCurrentTime(); 1139 1140 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1141 if (rc != Success) 1142 return rc; 1143 1144 rc = check_change_property(client, stuff->property, stuff->type, 1145 stuff->format, stuff->mode, stuff->num_items); 1146 if (rc != Success) 1147 return rc; 1148 1149 len = stuff->num_items; 1150 if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) 1151 return BadLength; 1152 1153 totalSize = len * (stuff->format / 8); 1154 REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize); 1155 1156 rc = change_property(client, dev, stuff->property, stuff->type, 1157 stuff->format, stuff->mode, len, (void *) &stuff[1]); 1158 return rc; 1159} 1160 1161int 1162ProcXIDeleteProperty(ClientPtr client) 1163{ 1164 DeviceIntPtr dev; 1165 int rc; 1166 1167 REQUEST(xXIDeletePropertyReq); 1168 1169 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1170 UpdateCurrentTime(); 1171 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1172 if (rc != Success) 1173 return rc; 1174 1175 if (!ValidAtom(stuff->property)) { 1176 client->errorValue = stuff->property; 1177 return BadAtom; 1178 } 1179 1180 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 1181 return rc; 1182} 1183 1184int 1185ProcXIGetProperty(ClientPtr client) 1186{ 1187 REQUEST(xXIGetPropertyReq); 1188 DeviceIntPtr dev; 1189 xXIGetPropertyReply reply; 1190 int length; 1191 int rc, format, nitems, bytes_after; 1192 char *data; 1193 Atom type; 1194 1195 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1196 if (stuff->delete) 1197 UpdateCurrentTime(); 1198 rc = dixLookupDevice(&dev, stuff->deviceid, client, 1199 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 1200 if (rc != Success) 1201 return rc; 1202 1203 rc = get_property(client, dev, stuff->property, stuff->type, 1204 stuff->delete, stuff->offset, stuff->len, 1205 &bytes_after, &type, &format, &nitems, &length, &data); 1206 1207 if (rc != Success) 1208 return rc; 1209 1210 reply = (xXIGetPropertyReply) { 1211 .repType = X_Reply, 1212 .RepType = X_XIGetProperty, 1213 .sequenceNumber = client->sequence, 1214 .length = bytes_to_int32(length), 1215 .type = type, 1216 .bytes_after = bytes_after, 1217 .num_items = nitems, 1218 .format = format 1219 }; 1220 1221 if (length && stuff->delete && (reply.bytes_after == 0)) 1222 send_property_event(dev, stuff->property, XIPropertyDeleted); 1223 1224 WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply); 1225 1226 if (length) { 1227 switch (reply.format) { 1228 case 32: 1229 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 1230 break; 1231 case 16: 1232 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1233 break; 1234 default: 1235 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 1236 break; 1237 } 1238 WriteSwappedDataToClient(client, length, data); 1239 } 1240 1241 /* delete the Property */ 1242 if (stuff->delete && (reply.bytes_after == 0)) { 1243 XIPropertyPtr prop, *prev; 1244 1245 for (prev = &dev->properties.properties; (prop = *prev); 1246 prev = &prop->next) { 1247 if (prop->propertyName == stuff->property) { 1248 *prev = prop->next; 1249 XIDestroyDeviceProperty(prop); 1250 break; 1251 } 1252 } 1253 } 1254 1255 return Success; 1256} 1257 1258int _X_COLD 1259SProcXIListProperties(ClientPtr client) 1260{ 1261 REQUEST(xXIListPropertiesReq); 1262 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1263 1264 swaps(&stuff->length); 1265 swaps(&stuff->deviceid); 1266 return (ProcXIListProperties(client)); 1267} 1268 1269int _X_COLD 1270SProcXIChangeProperty(ClientPtr client) 1271{ 1272 REQUEST(xXIChangePropertyReq); 1273 1274 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1275 swaps(&stuff->length); 1276 swaps(&stuff->deviceid); 1277 swapl(&stuff->property); 1278 swapl(&stuff->type); 1279 swapl(&stuff->num_items); 1280 return (ProcXIChangeProperty(client)); 1281} 1282 1283int _X_COLD 1284SProcXIDeleteProperty(ClientPtr client) 1285{ 1286 REQUEST(xXIDeletePropertyReq); 1287 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1288 1289 swaps(&stuff->length); 1290 swaps(&stuff->deviceid); 1291 swapl(&stuff->property); 1292 return (ProcXIDeleteProperty(client)); 1293} 1294 1295int _X_COLD 1296SProcXIGetProperty(ClientPtr client) 1297{ 1298 REQUEST(xXIGetPropertyReq); 1299 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1300 1301 swaps(&stuff->length); 1302 swaps(&stuff->deviceid); 1303 swapl(&stuff->property); 1304 swapl(&stuff->type); 1305 swapl(&stuff->offset); 1306 swapl(&stuff->len); 1307 return (ProcXIGetProperty(client)); 1308} 1309 1310void _X_COLD 1311SRepXIListProperties(ClientPtr client, int size, xXIListPropertiesReply * rep) 1312{ 1313 swaps(&rep->sequenceNumber); 1314 swapl(&rep->length); 1315 swaps(&rep->num_properties); 1316 /* properties will be swapped later, see ProcXIListProperties */ 1317 WriteToClient(client, size, rep); 1318} 1319 1320void _X_COLD 1321SRepXIGetProperty(ClientPtr client, int size, xXIGetPropertyReply * rep) 1322{ 1323 swaps(&rep->sequenceNumber); 1324 swapl(&rep->length); 1325 swapl(&rep->type); 1326 swapl(&rep->bytes_after); 1327 swapl(&rep->num_items); 1328 /* data will be swapped, see ProcXIGetProperty */ 1329 WriteToClient(client, size, rep); 1330} 1331