xiproperty.c revision 5a112b11
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 int 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 906 len = stuff->nUnits; 907 if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq)))) 908 return BadLength; 909 910 totalSize = len * (stuff->format / 8); 911 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize); 912 913 rc = change_property(client, dev, stuff->property, stuff->type, 914 stuff->format, stuff->mode, len, (void *) &stuff[1]); 915 return rc; 916} 917 918int 919ProcXDeleteDeviceProperty(ClientPtr client) 920{ 921 REQUEST(xDeleteDevicePropertyReq); 922 DeviceIntPtr dev; 923 int rc; 924 925 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 926 UpdateCurrentTime(); 927 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 928 if (rc != Success) 929 return rc; 930 931 if (!ValidAtom(stuff->property)) { 932 client->errorValue = stuff->property; 933 return BadAtom; 934 } 935 936 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 937 return rc; 938} 939 940int 941ProcXGetDeviceProperty(ClientPtr client) 942{ 943 REQUEST(xGetDevicePropertyReq); 944 DeviceIntPtr dev; 945 int length; 946 int rc, format, nitems, bytes_after; 947 char *data; 948 Atom type; 949 xGetDevicePropertyReply reply; 950 951 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 952 if (stuff->delete) 953 UpdateCurrentTime(); 954 rc = dixLookupDevice(&dev, stuff->deviceid, client, 955 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 956 if (rc != Success) 957 return rc; 958 959 rc = get_property(client, dev, stuff->property, stuff->type, 960 stuff->delete, stuff->longOffset, stuff->longLength, 961 &bytes_after, &type, &format, &nitems, &length, &data); 962 963 if (rc != Success) 964 return rc; 965 966 reply = (xGetDevicePropertyReply) { 967 .repType = X_Reply, 968 .RepType = X_GetDeviceProperty, 969 .sequenceNumber = client->sequence, 970 .length = bytes_to_int32(length), 971 .propertyType = type, 972 .bytesAfter = bytes_after, 973 .nItems = nitems, 974 .format = format, 975 .deviceid = dev->id 976 }; 977 978 if (stuff->delete && (reply.bytesAfter == 0)) 979 send_property_event(dev, stuff->property, XIPropertyDeleted); 980 981 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 982 983 if (length) { 984 switch (reply.format) { 985 case 32: 986 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 987 break; 988 case 16: 989 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 990 break; 991 default: 992 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 993 break; 994 } 995 WriteSwappedDataToClient(client, length, data); 996 } 997 998 /* delete the Property */ 999 if (stuff->delete && (reply.bytesAfter == 0)) { 1000 XIPropertyPtr prop, *prev; 1001 1002 for (prev = &dev->properties.properties; (prop = *prev); 1003 prev = &prop->next) { 1004 if (prop->propertyName == stuff->property) { 1005 *prev = prop->next; 1006 XIDestroyDeviceProperty(prop); 1007 break; 1008 } 1009 } 1010 } 1011 return Success; 1012} 1013 1014int _X_COLD 1015SProcXListDeviceProperties(ClientPtr client) 1016{ 1017 REQUEST(xListDevicePropertiesReq); 1018 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 1019 1020 swaps(&stuff->length); 1021 return (ProcXListDeviceProperties(client)); 1022} 1023 1024int _X_COLD 1025SProcXChangeDeviceProperty(ClientPtr client) 1026{ 1027 REQUEST(xChangeDevicePropertyReq); 1028 1029 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 1030 swaps(&stuff->length); 1031 swapl(&stuff->property); 1032 swapl(&stuff->type); 1033 swapl(&stuff->nUnits); 1034 return (ProcXChangeDeviceProperty(client)); 1035} 1036 1037int _X_COLD 1038SProcXDeleteDeviceProperty(ClientPtr client) 1039{ 1040 REQUEST(xDeleteDevicePropertyReq); 1041 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 1042 1043 swaps(&stuff->length); 1044 swapl(&stuff->property); 1045 return (ProcXDeleteDeviceProperty(client)); 1046} 1047 1048int _X_COLD 1049SProcXGetDeviceProperty(ClientPtr client) 1050{ 1051 REQUEST(xGetDevicePropertyReq); 1052 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 1053 1054 swaps(&stuff->length); 1055 swapl(&stuff->property); 1056 swapl(&stuff->type); 1057 swapl(&stuff->longOffset); 1058 swapl(&stuff->longLength); 1059 return (ProcXGetDeviceProperty(client)); 1060} 1061 1062/* Reply swapping */ 1063 1064void _X_COLD 1065SRepXListDeviceProperties(ClientPtr client, int size, 1066 xListDevicePropertiesReply * rep) 1067{ 1068 swaps(&rep->sequenceNumber); 1069 swapl(&rep->length); 1070 swaps(&rep->nAtoms); 1071 /* properties will be swapped later, see ProcXListDeviceProperties */ 1072 WriteToClient(client, size, rep); 1073} 1074 1075void _X_COLD 1076SRepXGetDeviceProperty(ClientPtr client, int size, 1077 xGetDevicePropertyReply * rep) 1078{ 1079 swaps(&rep->sequenceNumber); 1080 swapl(&rep->length); 1081 swapl(&rep->propertyType); 1082 swapl(&rep->bytesAfter); 1083 swapl(&rep->nItems); 1084 /* data will be swapped, see ProcXGetDeviceProperty */ 1085 WriteToClient(client, size, rep); 1086} 1087 1088/* XI2 Request/reply handling */ 1089int 1090ProcXIListProperties(ClientPtr client) 1091{ 1092 Atom *atoms; 1093 xXIListPropertiesReply rep; 1094 int natoms; 1095 DeviceIntPtr dev; 1096 int rc = Success; 1097 1098 REQUEST(xXIListPropertiesReq); 1099 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1100 1101 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess); 1102 if (rc != Success) 1103 return rc; 1104 1105 rc = list_atoms(dev, &natoms, &atoms); 1106 if (rc != Success) 1107 return rc; 1108 1109 rep = (xXIListPropertiesReply) { 1110 .repType = X_Reply, 1111 .RepType = X_XIListProperties, 1112 .sequenceNumber = client->sequence, 1113 .length = natoms, 1114 .num_properties = natoms 1115 }; 1116 1117 WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep); 1118 if (natoms) { 1119 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 1120 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 1121 free(atoms); 1122 } 1123 return rc; 1124} 1125 1126int 1127ProcXIChangeProperty(ClientPtr client) 1128{ 1129 int rc; 1130 DeviceIntPtr dev; 1131 int totalSize; 1132 unsigned long len; 1133 1134 REQUEST(xXIChangePropertyReq); 1135 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1136 UpdateCurrentTime(); 1137 1138 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1139 if (rc != Success) 1140 return rc; 1141 1142 rc = check_change_property(client, stuff->property, stuff->type, 1143 stuff->format, stuff->mode, stuff->num_items); 1144 len = stuff->num_items; 1145 if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) 1146 return BadLength; 1147 1148 totalSize = len * (stuff->format / 8); 1149 REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize); 1150 1151 rc = change_property(client, dev, stuff->property, stuff->type, 1152 stuff->format, stuff->mode, len, (void *) &stuff[1]); 1153 return rc; 1154} 1155 1156int 1157ProcXIDeleteProperty(ClientPtr client) 1158{ 1159 DeviceIntPtr dev; 1160 int rc; 1161 1162 REQUEST(xXIDeletePropertyReq); 1163 1164 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1165 UpdateCurrentTime(); 1166 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1167 if (rc != Success) 1168 return rc; 1169 1170 if (!ValidAtom(stuff->property)) { 1171 client->errorValue = stuff->property; 1172 return BadAtom; 1173 } 1174 1175 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 1176 return rc; 1177} 1178 1179int 1180ProcXIGetProperty(ClientPtr client) 1181{ 1182 REQUEST(xXIGetPropertyReq); 1183 DeviceIntPtr dev; 1184 xXIGetPropertyReply reply; 1185 int length; 1186 int rc, format, nitems, bytes_after; 1187 char *data; 1188 Atom type; 1189 1190 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1191 if (stuff->delete) 1192 UpdateCurrentTime(); 1193 rc = dixLookupDevice(&dev, stuff->deviceid, client, 1194 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 1195 if (rc != Success) 1196 return rc; 1197 1198 rc = get_property(client, dev, stuff->property, stuff->type, 1199 stuff->delete, stuff->offset, stuff->len, 1200 &bytes_after, &type, &format, &nitems, &length, &data); 1201 1202 if (rc != Success) 1203 return rc; 1204 1205 reply = (xXIGetPropertyReply) { 1206 .repType = X_Reply, 1207 .RepType = X_XIGetProperty, 1208 .sequenceNumber = client->sequence, 1209 .length = bytes_to_int32(length), 1210 .type = type, 1211 .bytes_after = bytes_after, 1212 .num_items = nitems, 1213 .format = format 1214 }; 1215 1216 if (length && stuff->delete && (reply.bytes_after == 0)) 1217 send_property_event(dev, stuff->property, XIPropertyDeleted); 1218 1219 WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply); 1220 1221 if (length) { 1222 switch (reply.format) { 1223 case 32: 1224 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 1225 break; 1226 case 16: 1227 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1228 break; 1229 default: 1230 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 1231 break; 1232 } 1233 WriteSwappedDataToClient(client, length, data); 1234 } 1235 1236 /* delete the Property */ 1237 if (stuff->delete && (reply.bytes_after == 0)) { 1238 XIPropertyPtr prop, *prev; 1239 1240 for (prev = &dev->properties.properties; (prop = *prev); 1241 prev = &prop->next) { 1242 if (prop->propertyName == stuff->property) { 1243 *prev = prop->next; 1244 XIDestroyDeviceProperty(prop); 1245 break; 1246 } 1247 } 1248 } 1249 1250 return Success; 1251} 1252 1253int _X_COLD 1254SProcXIListProperties(ClientPtr client) 1255{ 1256 REQUEST(xXIListPropertiesReq); 1257 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1258 1259 swaps(&stuff->length); 1260 swaps(&stuff->deviceid); 1261 return (ProcXIListProperties(client)); 1262} 1263 1264int _X_COLD 1265SProcXIChangeProperty(ClientPtr client) 1266{ 1267 REQUEST(xXIChangePropertyReq); 1268 1269 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1270 swaps(&stuff->length); 1271 swaps(&stuff->deviceid); 1272 swapl(&stuff->property); 1273 swapl(&stuff->type); 1274 swapl(&stuff->num_items); 1275 return (ProcXIChangeProperty(client)); 1276} 1277 1278int _X_COLD 1279SProcXIDeleteProperty(ClientPtr client) 1280{ 1281 REQUEST(xXIDeletePropertyReq); 1282 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1283 1284 swaps(&stuff->length); 1285 swaps(&stuff->deviceid); 1286 swapl(&stuff->property); 1287 return (ProcXIDeleteProperty(client)); 1288} 1289 1290int _X_COLD 1291SProcXIGetProperty(ClientPtr client) 1292{ 1293 REQUEST(xXIGetPropertyReq); 1294 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1295 1296 swaps(&stuff->length); 1297 swaps(&stuff->deviceid); 1298 swapl(&stuff->property); 1299 swapl(&stuff->type); 1300 swapl(&stuff->offset); 1301 swapl(&stuff->len); 1302 return (ProcXIGetProperty(client)); 1303} 1304 1305void _X_COLD 1306SRepXIListProperties(ClientPtr client, int size, xXIListPropertiesReply * rep) 1307{ 1308 swaps(&rep->sequenceNumber); 1309 swapl(&rep->length); 1310 swaps(&rep->num_properties); 1311 /* properties will be swapped later, see ProcXIListProperties */ 1312 WriteToClient(client, size, rep); 1313} 1314 1315void _X_COLD 1316SRepXIGetProperty(ClientPtr client, int size, xXIGetPropertyReply * rep) 1317{ 1318 swaps(&rep->sequenceNumber); 1319 swapl(&rep->length); 1320 swapl(&rep->type); 1321 swapl(&rep->bytes_after); 1322 swapl(&rep->num_items); 1323 /* data will be swapped, see ProcXIGetProperty */ 1324 WriteToClient(client, size, rep); 1325} 1326