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