xiproperty.c revision f7df2e56
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 < (sizeof(dev_properties) / sizeof(struct dev_properties)); 376 i++) { 377 if (strcmp(name, dev_properties[i].name) == 0) { 378 if (dev_properties[i].type == None) { 379 dev_properties[i].type = 380 MakeAtom(dev_properties[i].name, 381 strlen(dev_properties[i].name), TRUE); 382 } 383 384 return dev_properties[i].type; 385 } 386 } 387 388 return 0; 389} 390 391void 392XIResetProperties(void) 393{ 394 int i; 395 396 for (i = 0; i < (sizeof(dev_properties) / sizeof(struct dev_properties)); 397 i++) 398 dev_properties[i].type = None; 399} 400 401/** 402 * Convert the given property's value(s) into @nelem_return integer values and 403 * store them in @buf_return. If @nelem_return is larger than the number of 404 * values in the property, @nelem_return is set to the number of values in the 405 * property. 406 * 407 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 408 * automatically and must be freed by the caller. 409 * 410 * Possible return codes. 411 * Success ... No error. 412 * BadMatch ... Wrong atom type, atom is not XA_INTEGER 413 * BadAlloc ... NULL passed as buffer and allocation failed. 414 * BadLength ... @buff is NULL but @nelem_return is non-zero. 415 * 416 * @param val The property value 417 * @param nelem_return The maximum number of elements to return. 418 * @param buf_return Pointer to an array of at least @nelem_return values. 419 * @return Success or the error code if an error occured. 420 */ 421_X_EXPORT int 422XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return) 423{ 424 int i; 425 int *buf; 426 427 if (val->type != XA_INTEGER) 428 return BadMatch; 429 if (!*buf_return && *nelem_return) 430 return BadLength; 431 432 switch (val->format) { 433 case 8: 434 case 16: 435 case 32: 436 break; 437 default: 438 return BadValue; 439 } 440 441 buf = *buf_return; 442 443 if (!buf && !(*nelem_return)) { 444 buf = calloc(val->size, sizeof(int)); 445 if (!buf) 446 return BadAlloc; 447 *buf_return = buf; 448 *nelem_return = val->size; 449 } 450 else if (val->size < *nelem_return) 451 *nelem_return = val->size; 452 453 for (i = 0; i < val->size && i < *nelem_return; i++) { 454 switch (val->format) { 455 case 8: 456 buf[i] = ((CARD8 *) val->data)[i]; 457 break; 458 case 16: 459 buf[i] = ((CARD16 *) val->data)[i]; 460 break; 461 case 32: 462 buf[i] = ((CARD32 *) val->data)[i]; 463 break; 464 } 465 } 466 467 return Success; 468} 469 470/** 471 * Convert the given property's value(s) into @nelem_return float values and 472 * store them in @buf_return. If @nelem_return is larger than the number of 473 * values in the property, @nelem_return is set to the number of values in the 474 * property. 475 * 476 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 477 * automatically and must be freed by the caller. 478 * 479 * Possible errors returned: 480 * Success 481 * BadMatch ... Wrong atom type, atom is not XA_FLOAT 482 * BadValue ... Wrong format, format is not 32 483 * BadAlloc ... NULL passed as buffer and allocation failed. 484 * BadLength ... @buff is NULL but @nelem_return is non-zero. 485 * 486 * @param val The property value 487 * @param nelem_return The maximum number of elements to return. 488 * @param buf_return Pointer to an array of at least @nelem_return values. 489 * @return Success or the error code if an error occured. 490 */ 491_X_EXPORT int 492XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return) 493{ 494 int i; 495 float *buf; 496 497 if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT)) 498 return BadMatch; 499 500 if (val->format != 32) 501 return BadValue; 502 if (!*buf_return && *nelem_return) 503 return BadLength; 504 505 buf = *buf_return; 506 507 if (!buf && !(*nelem_return)) { 508 buf = calloc(val->size, sizeof(float)); 509 if (!buf) 510 return BadAlloc; 511 *buf_return = buf; 512 *nelem_return = val->size; 513 } 514 else if (val->size < *nelem_return) 515 *nelem_return = val->size; 516 517 for (i = 0; i < val->size && i < *nelem_return; i++) 518 buf[i] = ((float *) val->data)[i]; 519 520 return Success; 521} 522 523/* Registers a new property handler on the given device and returns a unique 524 * identifier for this handler. This identifier is required to unregister the 525 * property handler again. 526 * @return The handler's identifier or 0 if an error occured. 527 */ 528long 529XIRegisterPropertyHandler(DeviceIntPtr dev, 530 int (*SetProperty) (DeviceIntPtr dev, 531 Atom property, 532 XIPropertyValuePtr prop, 533 BOOL checkonly), 534 int (*GetProperty) (DeviceIntPtr dev, 535 Atom property), 536 int (*DeleteProperty) (DeviceIntPtr dev, 537 Atom property)) 538{ 539 XIPropertyHandlerPtr new_handler; 540 541 new_handler = calloc(1, sizeof(XIPropertyHandler)); 542 if (!new_handler) 543 return 0; 544 545 new_handler->id = XIPropHandlerID++; 546 new_handler->SetProperty = SetProperty; 547 new_handler->GetProperty = GetProperty; 548 new_handler->DeleteProperty = DeleteProperty; 549 new_handler->next = dev->properties.handlers; 550 dev->properties.handlers = new_handler; 551 552 return new_handler->id; 553} 554 555void 556XIUnregisterPropertyHandler(DeviceIntPtr dev, long id) 557{ 558 XIPropertyHandlerPtr curr, prev = NULL; 559 560 curr = dev->properties.handlers; 561 while (curr && curr->id != id) { 562 prev = curr; 563 curr = curr->next; 564 } 565 566 if (!curr) 567 return; 568 569 if (!prev) /* first one */ 570 dev->properties.handlers = curr->next; 571 else 572 prev->next = curr->next; 573 574 free(curr); 575} 576 577static XIPropertyPtr 578XICreateDeviceProperty(Atom property) 579{ 580 XIPropertyPtr prop; 581 582 prop = (XIPropertyPtr) malloc(sizeof(XIPropertyRec)); 583 if (!prop) 584 return NULL; 585 586 prop->next = NULL; 587 prop->propertyName = property; 588 prop->value.type = None; 589 prop->value.format = 0; 590 prop->value.size = 0; 591 prop->value.data = NULL; 592 prop->deletable = TRUE; 593 594 return prop; 595} 596 597static XIPropertyPtr 598XIFetchDeviceProperty(DeviceIntPtr dev, Atom property) 599{ 600 XIPropertyPtr prop; 601 602 for (prop = dev->properties.properties; prop; prop = prop->next) 603 if (prop->propertyName == property) 604 return prop; 605 return NULL; 606} 607 608static void 609XIDestroyDeviceProperty(XIPropertyPtr prop) 610{ 611 free(prop->value.data); 612 free(prop); 613} 614 615/* This function destroys all of the device's property-related stuff, 616 * including removing all device handlers. 617 * DO NOT CALL FROM THE DRIVER. 618 */ 619void 620XIDeleteAllDeviceProperties(DeviceIntPtr device) 621{ 622 XIPropertyPtr prop, next; 623 XIPropertyHandlerPtr curr_handler, next_handler; 624 625 for (prop = device->properties.properties; prop; prop = next) { 626 next = prop->next; 627 send_property_event(device, prop->propertyName, XIPropertyDeleted); 628 XIDestroyDeviceProperty(prop); 629 } 630 631 device->properties.properties = NULL; 632 633 /* Now free all handlers */ 634 curr_handler = device->properties.handlers; 635 while (curr_handler) { 636 next_handler = curr_handler->next; 637 free(curr_handler); 638 curr_handler = next_handler; 639 } 640 641 device->properties.handlers = NULL; 642} 643 644int 645XIDeleteDeviceProperty(DeviceIntPtr device, Atom property, Bool fromClient) 646{ 647 XIPropertyPtr prop, *prev; 648 int rc = Success; 649 650 for (prev = &device->properties.properties; (prop = *prev); 651 prev = &(prop->next)) 652 if (prop->propertyName == property) 653 break; 654 655 if (!prop) 656 return Success; 657 658 if (fromClient && !prop->deletable) 659 return BadAccess; 660 661 /* Ask handlers if we may delete the property */ 662 if (device->properties.handlers) { 663 XIPropertyHandlerPtr handler = device->properties.handlers; 664 665 while (handler) { 666 if (handler->DeleteProperty) 667 rc = handler->DeleteProperty(device, prop->propertyName); 668 if (rc != Success) 669 return rc; 670 handler = handler->next; 671 } 672 } 673 674 if (prop) { 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 rc = handler->SetProperty(dev, prop->propertyName, 771 &new_value, checkonly); 772 if (checkonly && rc != Success) { 773 free(new_value.data); 774 if (add) 775 XIDestroyDeviceProperty(prop); 776 return rc; 777 } 778 } 779 handler = handler->next; 780 } 781 checkonly = !checkonly; 782 } while (!checkonly); 783 } 784 free(prop_value->data); 785 *prop_value = new_value; 786 } 787 else if (len == 0) { 788 /* do nothing */ 789 } 790 791 if (add) { 792 prop->next = dev->properties.properties; 793 dev->properties.properties = prop; 794 } 795 796 if (sendevent) 797 send_property_event(dev, prop->propertyName, 798 (add) ? XIPropertyCreated : XIPropertyModified); 799 800 return Success; 801} 802 803int 804XIGetDeviceProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value) 805{ 806 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); 807 int rc; 808 809 if (!prop) { 810 *value = NULL; 811 return BadAtom; 812 } 813 814 /* If we can, try to update the property value first */ 815 if (dev->properties.handlers) { 816 XIPropertyHandlerPtr handler = dev->properties.handlers; 817 818 while (handler) { 819 if (handler->GetProperty) { 820 rc = handler->GetProperty(dev, prop->propertyName); 821 if (rc != Success) { 822 *value = NULL; 823 return rc; 824 } 825 } 826 handler = handler->next; 827 } 828 } 829 830 *value = &prop->value; 831 return Success; 832} 833 834int 835XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable) 836{ 837 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); 838 839 if (!prop) 840 return BadAtom; 841 842 prop->deletable = deletable; 843 return Success; 844} 845 846int 847ProcXListDeviceProperties(ClientPtr client) 848{ 849 Atom *atoms; 850 xListDevicePropertiesReply rep; 851 int natoms; 852 DeviceIntPtr dev; 853 int rc = Success; 854 855 REQUEST(xListDevicePropertiesReq); 856 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 857 858 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess); 859 if (rc != Success) 860 return rc; 861 862 rc = list_atoms(dev, &natoms, &atoms); 863 if (rc != Success) 864 return rc; 865 866 rep = (xListDevicePropertiesReply) { 867 .repType = X_Reply, 868 .RepType = X_ListDeviceProperties, 869 .sequenceNumber = client->sequence, 870 .length = natoms, 871 .nAtoms = natoms 872 }; 873 874 WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep); 875 if (natoms) { 876 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 877 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 878 free(atoms); 879 } 880 return rc; 881} 882 883int 884ProcXChangeDeviceProperty(ClientPtr client) 885{ 886 REQUEST(xChangeDevicePropertyReq); 887 DeviceIntPtr dev; 888 unsigned long len; 889 int totalSize; 890 int rc; 891 892 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 893 UpdateCurrentTime(); 894 895 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 896 if (rc != Success) 897 return rc; 898 899 rc = check_change_property(client, stuff->property, stuff->type, 900 stuff->format, stuff->mode, stuff->nUnits); 901 902 len = stuff->nUnits; 903 if (len > (bytes_to_int32(0xffffffff - sizeof(xChangeDevicePropertyReq)))) 904 return BadLength; 905 906 totalSize = len * (stuff->format / 8); 907 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize); 908 909 rc = change_property(client, dev, stuff->property, stuff->type, 910 stuff->format, stuff->mode, len, (void *) &stuff[1]); 911 return rc; 912} 913 914int 915ProcXDeleteDeviceProperty(ClientPtr client) 916{ 917 REQUEST(xDeleteDevicePropertyReq); 918 DeviceIntPtr dev; 919 int rc; 920 921 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 922 UpdateCurrentTime(); 923 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 924 if (rc != Success) 925 return rc; 926 927 if (!ValidAtom(stuff->property)) { 928 client->errorValue = stuff->property; 929 return BadAtom; 930 } 931 932 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 933 return rc; 934} 935 936int 937ProcXGetDeviceProperty(ClientPtr client) 938{ 939 REQUEST(xGetDevicePropertyReq); 940 DeviceIntPtr dev; 941 int length; 942 int rc, format, nitems, bytes_after; 943 char *data; 944 Atom type; 945 xGetDevicePropertyReply reply; 946 947 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 948 if (stuff->delete) 949 UpdateCurrentTime(); 950 rc = dixLookupDevice(&dev, stuff->deviceid, client, 951 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 952 if (rc != Success) 953 return rc; 954 955 rc = get_property(client, dev, stuff->property, stuff->type, 956 stuff->delete, stuff->longOffset, stuff->longLength, 957 &bytes_after, &type, &format, &nitems, &length, &data); 958 959 if (rc != Success) 960 return rc; 961 962 reply = (xGetDevicePropertyReply) { 963 .repType = X_Reply, 964 .RepType = X_GetDeviceProperty, 965 .sequenceNumber = client->sequence, 966 .length = bytes_to_int32(length), 967 .propertyType = type, 968 .bytesAfter = bytes_after, 969 .nItems = nitems, 970 .format = format, 971 .deviceid = dev->id 972 }; 973 974 if (stuff->delete && (reply.bytesAfter == 0)) 975 send_property_event(dev, stuff->property, XIPropertyDeleted); 976 977 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 978 979 if (length) { 980 switch (reply.format) { 981 case 32: 982 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 983 break; 984 case 16: 985 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 986 break; 987 default: 988 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 989 break; 990 } 991 WriteSwappedDataToClient(client, length, data); 992 } 993 994 /* delete the Property */ 995 if (stuff->delete && (reply.bytesAfter == 0)) { 996 XIPropertyPtr prop, *prev; 997 998 for (prev = &dev->properties.properties; (prop = *prev); 999 prev = &prop->next) { 1000 if (prop->propertyName == stuff->property) { 1001 *prev = prop->next; 1002 XIDestroyDeviceProperty(prop); 1003 break; 1004 } 1005 } 1006 } 1007 return Success; 1008} 1009 1010int 1011SProcXListDeviceProperties(ClientPtr client) 1012{ 1013 REQUEST(xListDevicePropertiesReq); 1014 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 1015 1016 swaps(&stuff->length); 1017 return (ProcXListDeviceProperties(client)); 1018} 1019 1020int 1021SProcXChangeDeviceProperty(ClientPtr client) 1022{ 1023 REQUEST(xChangeDevicePropertyReq); 1024 1025 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 1026 swaps(&stuff->length); 1027 swapl(&stuff->property); 1028 swapl(&stuff->type); 1029 swapl(&stuff->nUnits); 1030 return (ProcXChangeDeviceProperty(client)); 1031} 1032 1033int 1034SProcXDeleteDeviceProperty(ClientPtr client) 1035{ 1036 REQUEST(xDeleteDevicePropertyReq); 1037 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 1038 1039 swaps(&stuff->length); 1040 swapl(&stuff->property); 1041 return (ProcXDeleteDeviceProperty(client)); 1042} 1043 1044int 1045SProcXGetDeviceProperty(ClientPtr client) 1046{ 1047 REQUEST(xGetDevicePropertyReq); 1048 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 1049 1050 swaps(&stuff->length); 1051 swapl(&stuff->property); 1052 swapl(&stuff->type); 1053 swapl(&stuff->longOffset); 1054 swapl(&stuff->longLength); 1055 return (ProcXGetDeviceProperty(client)); 1056} 1057 1058/* Reply swapping */ 1059 1060void 1061SRepXListDeviceProperties(ClientPtr client, int size, 1062 xListDevicePropertiesReply * rep) 1063{ 1064 swaps(&rep->sequenceNumber); 1065 swapl(&rep->length); 1066 swaps(&rep->nAtoms); 1067 /* properties will be swapped later, see ProcXListDeviceProperties */ 1068 WriteToClient(client, size, rep); 1069} 1070 1071void 1072SRepXGetDeviceProperty(ClientPtr client, int size, 1073 xGetDevicePropertyReply * rep) 1074{ 1075 swaps(&rep->sequenceNumber); 1076 swapl(&rep->length); 1077 swapl(&rep->propertyType); 1078 swapl(&rep->bytesAfter); 1079 swapl(&rep->nItems); 1080 /* data will be swapped, see ProcXGetDeviceProperty */ 1081 WriteToClient(client, size, rep); 1082} 1083 1084/* XI2 Request/reply handling */ 1085int 1086ProcXIListProperties(ClientPtr client) 1087{ 1088 Atom *atoms; 1089 xXIListPropertiesReply rep; 1090 int natoms; 1091 DeviceIntPtr dev; 1092 int rc = Success; 1093 1094 REQUEST(xXIListPropertiesReq); 1095 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1096 1097 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixListPropAccess); 1098 if (rc != Success) 1099 return rc; 1100 1101 rc = list_atoms(dev, &natoms, &atoms); 1102 if (rc != Success) 1103 return rc; 1104 1105 rep = (xXIListPropertiesReply) { 1106 .repType = X_Reply, 1107 .RepType = X_XIListProperties, 1108 .sequenceNumber = client->sequence, 1109 .length = natoms, 1110 .num_properties = natoms 1111 }; 1112 1113 WriteReplyToClient(client, sizeof(xXIListPropertiesReply), &rep); 1114 if (natoms) { 1115 client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; 1116 WriteSwappedDataToClient(client, natoms * sizeof(Atom), atoms); 1117 free(atoms); 1118 } 1119 return rc; 1120} 1121 1122int 1123ProcXIChangeProperty(ClientPtr client) 1124{ 1125 int rc; 1126 DeviceIntPtr dev; 1127 int totalSize; 1128 unsigned long len; 1129 1130 REQUEST(xXIChangePropertyReq); 1131 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1132 UpdateCurrentTime(); 1133 1134 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1135 if (rc != Success) 1136 return rc; 1137 1138 rc = check_change_property(client, stuff->property, stuff->type, 1139 stuff->format, stuff->mode, stuff->num_items); 1140 len = stuff->num_items; 1141 if (len > bytes_to_int32(0xffffffff - sizeof(xXIChangePropertyReq))) 1142 return BadLength; 1143 1144 totalSize = len * (stuff->format / 8); 1145 REQUEST_FIXED_SIZE(xXIChangePropertyReq, totalSize); 1146 1147 rc = change_property(client, dev, stuff->property, stuff->type, 1148 stuff->format, stuff->mode, len, (void *) &stuff[1]); 1149 return rc; 1150} 1151 1152int 1153ProcXIDeleteProperty(ClientPtr client) 1154{ 1155 DeviceIntPtr dev; 1156 int rc; 1157 1158 REQUEST(xXIDeletePropertyReq); 1159 1160 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1161 UpdateCurrentTime(); 1162 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixSetPropAccess); 1163 if (rc != Success) 1164 return rc; 1165 1166 if (!ValidAtom(stuff->property)) { 1167 client->errorValue = stuff->property; 1168 return BadAtom; 1169 } 1170 1171 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 1172 return rc; 1173} 1174 1175int 1176ProcXIGetProperty(ClientPtr client) 1177{ 1178 REQUEST(xXIGetPropertyReq); 1179 DeviceIntPtr dev; 1180 xXIGetPropertyReply reply; 1181 int length; 1182 int rc, format, nitems, bytes_after; 1183 char *data; 1184 Atom type; 1185 1186 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1187 if (stuff->delete) 1188 UpdateCurrentTime(); 1189 rc = dixLookupDevice(&dev, stuff->deviceid, client, 1190 stuff->delete ? DixSetPropAccess : DixGetPropAccess); 1191 if (rc != Success) 1192 return rc; 1193 1194 rc = get_property(client, dev, stuff->property, stuff->type, 1195 stuff->delete, stuff->offset, stuff->len, 1196 &bytes_after, &type, &format, &nitems, &length, &data); 1197 1198 if (rc != Success) 1199 return rc; 1200 1201 reply = (xXIGetPropertyReply) { 1202 .repType = X_Reply, 1203 .RepType = X_XIGetProperty, 1204 .sequenceNumber = client->sequence, 1205 .length = bytes_to_int32(length), 1206 .type = type, 1207 .bytes_after = bytes_after, 1208 .num_items = nitems, 1209 .format = format 1210 }; 1211 1212 if (length && stuff->delete && (reply.bytes_after == 0)) 1213 send_property_event(dev, stuff->property, XIPropertyDeleted); 1214 1215 WriteReplyToClient(client, sizeof(xXIGetPropertyReply), &reply); 1216 1217 if (length) { 1218 switch (reply.format) { 1219 case 32: 1220 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; 1221 break; 1222 case 16: 1223 client->pSwapReplyFunc = (ReplySwapPtr) CopySwap16Write; 1224 break; 1225 default: 1226 client->pSwapReplyFunc = (ReplySwapPtr) WriteToClient; 1227 break; 1228 } 1229 WriteSwappedDataToClient(client, length, data); 1230 } 1231 1232 /* delete the Property */ 1233 if (stuff->delete && (reply.bytes_after == 0)) { 1234 XIPropertyPtr prop, *prev; 1235 1236 for (prev = &dev->properties.properties; (prop = *prev); 1237 prev = &prop->next) { 1238 if (prop->propertyName == stuff->property) { 1239 *prev = prop->next; 1240 XIDestroyDeviceProperty(prop); 1241 break; 1242 } 1243 } 1244 } 1245 1246 return Success; 1247} 1248 1249int 1250SProcXIListProperties(ClientPtr client) 1251{ 1252 REQUEST(xXIListPropertiesReq); 1253 REQUEST_SIZE_MATCH(xXIListPropertiesReq); 1254 1255 swaps(&stuff->length); 1256 swaps(&stuff->deviceid); 1257 return (ProcXIListProperties(client)); 1258} 1259 1260int 1261SProcXIChangeProperty(ClientPtr client) 1262{ 1263 REQUEST(xXIChangePropertyReq); 1264 1265 REQUEST_AT_LEAST_SIZE(xXIChangePropertyReq); 1266 swaps(&stuff->length); 1267 swaps(&stuff->deviceid); 1268 swapl(&stuff->property); 1269 swapl(&stuff->type); 1270 swapl(&stuff->num_items); 1271 return (ProcXIChangeProperty(client)); 1272} 1273 1274int 1275SProcXIDeleteProperty(ClientPtr client) 1276{ 1277 REQUEST(xXIDeletePropertyReq); 1278 REQUEST_SIZE_MATCH(xXIDeletePropertyReq); 1279 1280 swaps(&stuff->length); 1281 swaps(&stuff->deviceid); 1282 swapl(&stuff->property); 1283 return (ProcXIDeleteProperty(client)); 1284} 1285 1286int 1287SProcXIGetProperty(ClientPtr client) 1288{ 1289 REQUEST(xXIGetPropertyReq); 1290 REQUEST_SIZE_MATCH(xXIGetPropertyReq); 1291 1292 swaps(&stuff->length); 1293 swaps(&stuff->deviceid); 1294 swapl(&stuff->property); 1295 swapl(&stuff->type); 1296 swapl(&stuff->offset); 1297 swapl(&stuff->len); 1298 return (ProcXIGetProperty(client)); 1299} 1300 1301void 1302SRepXIListProperties(ClientPtr client, int size, xXIListPropertiesReply * rep) 1303{ 1304 swaps(&rep->sequenceNumber); 1305 swapl(&rep->length); 1306 swaps(&rep->num_properties); 1307 /* properties will be swapped later, see ProcXIListProperties */ 1308 WriteToClient(client, size, rep); 1309} 1310 1311void 1312SRepXIGetProperty(ClientPtr client, int size, xXIGetPropertyReply * rep) 1313{ 1314 swaps(&rep->sequenceNumber); 1315 swapl(&rep->length); 1316 swapl(&rep->type); 1317 swapl(&rep->bytes_after); 1318 swapl(&rep->num_items); 1319 /* data will be swapped, see ProcXIGetProperty */ 1320 WriteToClient(client, size, rep); 1321} 1322