xiproperty.c revision 6747b715
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 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 1042 swaps(&stuff->length, n); 1043 1044 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 1045 return (ProcXListDeviceProperties(client)); 1046} 1047 1048int 1049SProcXChangeDeviceProperty (ClientPtr client) 1050{ 1051 char n; 1052 REQUEST(xChangeDevicePropertyReq); 1053 1054 swaps(&stuff->length, n); 1055 swapl(&stuff->property, n); 1056 swapl(&stuff->type, n); 1057 swapl(&stuff->nUnits, n); 1058 REQUEST_SIZE_MATCH(xChangeDevicePropertyReq); 1059 return (ProcXChangeDeviceProperty(client)); 1060} 1061 1062int 1063SProcXDeleteDeviceProperty (ClientPtr client) 1064{ 1065 char n; 1066 REQUEST(xDeleteDevicePropertyReq); 1067 1068 swaps(&stuff->length, n); 1069 swapl(&stuff->property, n); 1070 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 1071 return (ProcXDeleteDeviceProperty(client)); 1072} 1073 1074int 1075SProcXGetDeviceProperty (ClientPtr client) 1076{ 1077 char n; 1078 REQUEST(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 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 1086 return (ProcXGetDeviceProperty(client)); 1087} 1088 1089 1090/* Reply swapping */ 1091 1092void 1093SRepXListDeviceProperties(ClientPtr client, int size, 1094 xListDevicePropertiesReply *rep) 1095{ 1096 char n; 1097 swaps(&rep->sequenceNumber, n); 1098 swapl(&rep->length, n); 1099 swaps(&rep->nAtoms, n); 1100 /* properties will be swapped later, see ProcXListDeviceProperties */ 1101 WriteToClient(client, size, (char*)rep); 1102} 1103 1104void 1105SRepXGetDeviceProperty(ClientPtr client, int size, 1106 xGetDevicePropertyReply *rep) 1107{ 1108 char n; 1109 1110 swaps(&rep->sequenceNumber, n); 1111 swapl(&rep->length, n); 1112 swapl(&rep->propertyType, n); 1113 swapl(&rep->bytesAfter, n); 1114 swapl(&rep->nItems, n); 1115 /* data will be swapped, see ProcXGetDeviceProperty */ 1116 WriteToClient(client, size, (char*)rep); 1117} 1118 1119/* XI2 Request/reply handling */ 1120int 1121ProcXIListProperties(ClientPtr client) 1122{ 1123 Atom *atoms; 1124 xXIListPropertiesReply rep; 1125 int natoms; 1126 DeviceIntPtr dev; 1127 int rc = Success; 1128 1129 REQUEST(xXIListPropertiesReq); 1130 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1131 1132 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixListPropAccess); 1133 if (rc != Success) 1134 return rc; 1135 1136 rc = list_atoms(dev, &natoms, &atoms); 1137 if (rc != Success) 1138 return rc; 1139 1140 rep.repType = X_Reply; 1141 rep.RepType = X_XIListProperties; 1142 rep.length = natoms; 1143 rep.sequenceNumber = client->sequence; 1144 rep.num_properties = natoms; 1145 1146 WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep); 1147 if (natoms) 1148 { 1149 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; 1150 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 1151 free(atoms); 1152 } 1153 return rc; 1154} 1155 1156int 1157ProcXIChangeProperty(ClientPtr client) 1158{ 1159 int rc; 1160 DeviceIntPtr dev; 1161 int totalSize; 1162 unsigned long len; 1163 1164 REQUEST(xXIChangePropertyReq); 1165 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1166 UpdateCurrentTime(); 1167 1168 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); 1169 if (rc != Success) 1170 return rc; 1171 1172 rc = check_change_property(client, stuff->property, stuff->type, 1173 stuff->format, stuff->mode, stuff->num_items); 1174 len = stuff->num_items; 1175 if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) 1176 return BadLength; 1177 1178 totalSize = len * (stuff->format/8); 1179 REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize); 1180 1181 rc = change_property(client, dev, stuff->property, stuff->type, 1182 stuff->format, stuff->mode, len, (void*)&stuff[1]); 1183 return rc; 1184} 1185 1186int 1187ProcXIDeleteProperty(ClientPtr client) 1188{ 1189 DeviceIntPtr dev; 1190 int rc; 1191 REQUEST(xXIDeletePropertyReq); 1192 1193 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1194 UpdateCurrentTime(); 1195 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixSetPropAccess); 1196 if (rc != Success) 1197 return rc; 1198 1199 if (!ValidAtom(stuff->property)) 1200 { 1201 client->errorValue = stuff->property; 1202 return BadAtom; 1203 } 1204 1205 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 1206 return rc; 1207} 1208 1209 1210int 1211ProcXIGetProperty(ClientPtr client) 1212{ 1213 REQUEST(xXIGetPropertyReq); 1214 DeviceIntPtr dev; 1215 xXIGetPropertyReply reply; 1216 int length; 1217 int rc, format, nitems, bytes_after; 1218 char *data; 1219 Atom type; 1220 1221 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1222 if (stuff->delete) 1223 UpdateCurrentTime(); 1224 rc = dixLookupDevice (&dev, stuff->deviceid, client, 1225 stuff->delete ? DixSetPropAccess : 1226 DixGetPropAccess); 1227 if (rc != Success) 1228 return rc; 1229 1230 rc = get_property(client, dev, stuff->property, stuff->type, 1231 stuff->delete, stuff->offset, stuff->len, 1232 &bytes_after, &type, &format, &nitems, &length, &data); 1233 1234 if (rc != Success) 1235 return rc; 1236 1237 reply.repType = X_Reply; 1238 reply.RepType = X_XIGetProperty; 1239 reply.sequenceNumber = client->sequence; 1240 reply.num_items = nitems; 1241 reply.format = format; 1242 reply.bytes_after = bytes_after; 1243 reply.type = type; 1244 reply.length = bytes_to_int32(length); 1245 1246 if (length && stuff->delete && (reply.bytes_after == 0)) 1247 send_property_event(dev, stuff->property, XIPropertyDeleted); 1248 1249 WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply); 1250 1251 if (length) 1252 { 1253 switch (reply.format) { 1254 case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; 1255 case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; 1256 default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; 1257 } 1258 WriteSwappedDataToClient(client, length, data); 1259 } 1260 1261 /* delete the Property */ 1262 if (stuff->delete && (reply.bytes_after == 0)) 1263 { 1264 XIPropertyPtr prop, *prev; 1265 for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next) 1266 { 1267 if (prop->propertyName == stuff->property) 1268 { 1269 *prev = prop->next; 1270 XIDestroyDeviceProperty(prop); 1271 break; 1272 } 1273 } 1274 } 1275 1276 return Success; 1277} 1278 1279int 1280SProcXIListProperties(ClientPtr client) 1281{ 1282 char n; 1283 REQUEST(xXIListPropertiesReq); 1284 1285 swaps(&stuff->length, n); 1286 swaps(&stuff->deviceid, n); 1287 1288 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1289 return (ProcXIListProperties(client)); 1290} 1291 1292int 1293SProcXIChangeProperty(ClientPtr client) 1294{ 1295 char n; 1296 REQUEST(xXIChangePropertyReq); 1297 1298 swaps(&stuff->length, n); 1299 swaps(&stuff->deviceid, n); 1300 swapl(&stuff->property, n); 1301 swapl(&stuff->type, n); 1302 swapl(&stuff->num_items, n); 1303 REQUEST_SIZE_MATCH(xXIChangePropertyReq); 1304 return (ProcXIChangeProperty(client)); 1305} 1306 1307int 1308SProcXIDeleteProperty(ClientPtr client) 1309{ 1310 char n; 1311 REQUEST(xXIDeletePropertyReq); 1312 1313 swaps(&stuff->length, n); 1314 swaps(&stuff->deviceid, n); 1315 swapl(&stuff->property, n); 1316 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1317 return (ProcXIDeleteProperty(client)); 1318} 1319 1320int 1321SProcXIGetProperty(ClientPtr client) 1322{ 1323 char n; 1324 REQUEST(xXIGetPropertyReq); 1325 1326 swaps(&stuff->length, n); 1327 swaps(&stuff->deviceid, n); 1328 swapl(&stuff->property, n); 1329 swapl(&stuff->type, n); 1330 swapl(&stuff->offset, n); 1331 swapl(&stuff->len, n); 1332 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1333 return (ProcXIGetProperty(client)); 1334} 1335 1336 1337void 1338SRepXIListProperties(ClientPtr client, int size, 1339 xXIListPropertiesReply *rep) 1340{ 1341 char n; 1342 swaps(&rep->sequenceNumber, n); 1343 swapl(&rep->length, n); 1344 swaps(&rep->num_properties, n); 1345 /* properties will be swapped later, see ProcXIListProperties */ 1346 WriteToClient(client, size, (char*)rep); 1347} 1348 1349void 1350SRepXIGetProperty(ClientPtr client, int size, 1351 xXIGetPropertyReply *rep) 1352{ 1353 char n; 1354 1355 swaps(&rep->sequenceNumber, n); 1356 swapl(&rep->length, n); 1357 swapl(&rep->type, n); 1358 swapl(&rep->bytes_after, n); 1359 swapl(&rep->num_items, n); 1360 /* data will be swapped, see ProcXIGetProperty */ 1361 WriteToClient(client, size, (char*)rep); 1362} 1363