xiproperty.c revision 52397711
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 "exglobals.h" 38#include "exevents.h" 39#include "swaprep.h" 40 41#include "xiproperty.h" 42#include "xserver-properties.h" 43 44/** 45 * Properties used or alloced from inside the server. 46 */ 47static struct dev_properties 48{ 49 Atom type; 50 char *name; 51} dev_properties[] = { 52 {0, XI_PROP_ENABLED}, 53 {0, XATOM_FLOAT} 54}; 55 56static long XIPropHandlerID = 1; 57 58/** 59 * Return the type assigned to the specified atom or 0 if the atom isn't known 60 * to the DIX. 61 * 62 * If name is NULL, None is returned. 63 */ 64_X_EXPORT Atom 65XIGetKnownProperty(char *name) 66{ 67 int i; 68 69 if (!name) 70 return None; 71 72 for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++) 73 { 74 if (strcmp(name, dev_properties[i].name) == 0) 75 return dev_properties[i].type; 76 } 77 78 return 0; 79} 80 81/** 82 * Convert the given property's value(s) into @nelem_return integer values and 83 * store them in @buf_return. If @nelem_return is larger than the number of 84 * values in the property, @nelem_return is set to the number of values in the 85 * property. 86 * 87 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 88 * automatically and must be freed by the caller. 89 * 90 * Possible return codes. 91 * Success ... No error. 92 * BadMatch ... Wrong atom type, atom is not XA_INTEGER 93 * BadAlloc ... NULL passed as buffer and allocation failed. 94 * BadLength ... @buff is NULL but @nelem_return is non-zero. 95 * 96 * @param val The property value 97 * @param nelem_return The maximum number of elements to return. 98 * @param buf_return Pointer to an array of at least @nelem_return values. 99 * @return Success or the error code if an error occured. 100 */ 101_X_EXPORT int 102XIPropToInt(XIPropertyValuePtr val, int *nelem_return, int **buf_return) 103{ 104 int i; 105 int *buf; 106 107 if (val->type != XA_INTEGER) 108 return BadMatch; 109 if (!*buf_return && *nelem_return) 110 return BadLength; 111 112 switch(val->format) 113 { 114 case 8: 115 case 16: 116 case 32: 117 break; 118 default: 119 return BadValue; 120 } 121 122 buf = *buf_return; 123 124 if (!buf && !(*nelem_return)) 125 { 126 buf = xcalloc(val->size, sizeof(int)); 127 if (!buf) 128 return BadAlloc; 129 *buf_return = buf; 130 *nelem_return = val->size; 131 } else if (val->size < *nelem_return) 132 *nelem_return = val->size; 133 134 for (i = 0; i < val->size && i < *nelem_return; i++) 135 { 136 switch(val->format) 137 { 138 case 8: buf[i] = ((CARD8*)val->data)[i]; break; 139 case 16: buf[i] = ((CARD16*)val->data)[i]; break; 140 case 32: buf[i] = ((CARD32*)val->data)[i]; break; 141 } 142 } 143 144 return Success; 145} 146 147/** 148 * Convert the given property's value(s) into @nelem_return float values and 149 * store them in @buf_return. If @nelem_return is larger than the number of 150 * values in the property, @nelem_return is set to the number of values in the 151 * property. 152 * 153 * If *@buf_return is NULL and @nelem_return is 0, memory is allocated 154 * automatically and must be freed by the caller. 155 * 156 * Possible errors returned: 157 * Success 158 * BadMatch ... Wrong atom type, atom is not XA_FLOAT 159 * BadValue ... Wrong format, format is not 32 160 * BadAlloc ... NULL passed as buffer and allocation failed. 161 * BadLength ... @buff is NULL but @nelem_return is non-zero. 162 * 163 * @param val The property value 164 * @param nelem_return The maximum number of elements to return. 165 * @param buf_return Pointer to an array of at least @nelem_return values. 166 * @return Success or the error code if an error occured. 167 */ 168_X_EXPORT int 169XIPropToFloat(XIPropertyValuePtr val, int *nelem_return, float **buf_return) 170{ 171 int i; 172 float *buf; 173 174 if (!val->type || val->type != XIGetKnownProperty(XATOM_FLOAT)) 175 return BadMatch; 176 177 if (val->format != 32) 178 return BadValue; 179 if (!*buf_return && *nelem_return) 180 return BadLength; 181 182 buf = *buf_return; 183 184 if (!buf && !(*nelem_return)) 185 { 186 buf = xcalloc(val->size, sizeof(float)); 187 if (!buf) 188 return BadAlloc; 189 *buf_return = buf; 190 *nelem_return = val->size; 191 } else if (val->size < *nelem_return) 192 *nelem_return = val->size; 193 194 for (i = 0; i < val->size && i < *nelem_return; i++) 195 buf[i] = ((float*)val->data)[i]; 196 197 return Success; 198} 199 200/** 201 * Init those properties that are allocated by the server and most likely used 202 * by the DIX or the DDX. 203 */ 204void 205XIInitKnownProperties(void) 206{ 207 int i; 208 for (i = 0; i < (sizeof(dev_properties)/sizeof(struct dev_properties)); i++) 209 { 210 dev_properties[i].type = 211 MakeAtom(dev_properties[i].name, 212 strlen(dev_properties[i].name), 213 TRUE); 214 } 215} 216 217 218/* Registers a new property handler on the given device and returns a unique 219 * identifier for this handler. This identifier is required to unregister the 220 * property handler again. 221 * @return The handler's identifier or 0 if an error occured. 222 */ 223long 224XIRegisterPropertyHandler(DeviceIntPtr dev, 225 int (*SetProperty) (DeviceIntPtr dev, 226 Atom property, 227 XIPropertyValuePtr prop, 228 BOOL checkonly), 229 int (*GetProperty) (DeviceIntPtr dev, 230 Atom property), 231 int (*DeleteProperty) (DeviceIntPtr dev, 232 Atom property)) 233{ 234 XIPropertyHandlerPtr new_handler; 235 236 new_handler = xcalloc(1, sizeof(XIPropertyHandler)); 237 if (!new_handler) 238 return 0; 239 240 new_handler->id = XIPropHandlerID++; 241 new_handler->SetProperty = SetProperty; 242 new_handler->GetProperty = GetProperty; 243 new_handler->DeleteProperty = DeleteProperty; 244 new_handler->next = dev->properties.handlers; 245 dev->properties.handlers = new_handler; 246 247 return new_handler->id; 248} 249 250void 251XIUnregisterPropertyHandler(DeviceIntPtr dev, long id) 252{ 253 XIPropertyHandlerPtr curr, prev = NULL; 254 255 curr = dev->properties.handlers; 256 while(curr && curr->id != id) 257 { 258 prev = curr; 259 curr = curr->next; 260 } 261 262 if (!curr) 263 return; 264 265 if (!prev) /* first one */ 266 dev->properties.handlers = curr->next; 267 else 268 prev->next = curr->next; 269 270 xfree(curr); 271} 272 273static XIPropertyPtr 274XICreateDeviceProperty (Atom property) 275{ 276 XIPropertyPtr prop; 277 278 prop = (XIPropertyPtr)xalloc(sizeof(XIPropertyRec)); 279 if (!prop) 280 return NULL; 281 282 prop->next = NULL; 283 prop->propertyName = property; 284 prop->value.type = None; 285 prop->value.format = 0; 286 prop->value.size = 0; 287 prop->value.data = NULL; 288 prop->deletable = TRUE; 289 290 return prop; 291} 292 293static XIPropertyPtr 294XIFetchDeviceProperty(DeviceIntPtr dev, Atom property) 295{ 296 XIPropertyPtr prop; 297 298 for (prop = dev->properties.properties; prop; prop = prop->next) 299 if (prop->propertyName == property) 300 return prop; 301 return NULL; 302} 303 304static void 305XIDestroyDeviceProperty (XIPropertyPtr prop) 306{ 307 if (prop->value.data) 308 xfree(prop->value.data); 309 xfree(prop); 310} 311 312/* This function destroys all of the device's property-related stuff, 313 * including removing all device handlers. 314 * DO NOT CALL FROM THE DRIVER. 315 */ 316void 317XIDeleteAllDeviceProperties (DeviceIntPtr device) 318{ 319 XIPropertyPtr prop, next; 320 XIPropertyHandlerPtr curr_handler, next_handler; 321 devicePropertyNotify event; 322 323 for (prop = device->properties.properties; prop; prop = next) 324 { 325 next = prop->next; 326 327 event.type = DevicePropertyNotify; 328 event.deviceid = device->id; 329 event.state = PropertyDelete; 330 event.atom = prop->propertyName; 331 event.time = currentTime.milliseconds; 332 SendEventToAllWindows(device, DevicePropertyNotifyMask, 333 (xEvent*)&event, 1); 334 335 XIDestroyDeviceProperty(prop); 336 } 337 338 /* Now free all handlers */ 339 curr_handler = device->properties.handlers; 340 while(curr_handler) 341 { 342 next_handler = curr_handler->next; 343 xfree(curr_handler); 344 curr_handler = next_handler; 345 } 346} 347 348 349int 350XIDeleteDeviceProperty (DeviceIntPtr device, Atom property, Bool fromClient) 351{ 352 XIPropertyPtr prop, *prev; 353 devicePropertyNotify event; 354 int rc = Success; 355 356 for (prev = &device->properties.properties; (prop = *prev); prev = &(prop->next)) 357 if (prop->propertyName == property) 358 break; 359 360 if (fromClient && !prop->deletable) 361 return BadAccess; 362 363 /* Ask handlers if we may delete the property */ 364 if (device->properties.handlers) 365 { 366 XIPropertyHandlerPtr handler = device->properties.handlers; 367 while(handler) 368 { 369 if (handler->DeleteProperty) 370 rc = handler->DeleteProperty(device, prop->propertyName); 371 if (rc != Success) 372 return (rc); 373 handler = handler->next; 374 } 375 } 376 377 if (prop) 378 { 379 *prev = prop->next; 380 event.type = DevicePropertyNotify; 381 event.deviceid = device->id; 382 event.state = PropertyDelete; 383 event.atom = prop->propertyName; 384 event.time = currentTime.milliseconds; 385 SendEventToAllWindows(device, DevicePropertyNotifyMask, 386 (xEvent*)&event, 1); 387 XIDestroyDeviceProperty (prop); 388 } 389 390 return Success; 391} 392 393int 394XIChangeDeviceProperty (DeviceIntPtr dev, Atom property, Atom type, 395 int format, int mode, unsigned long len, 396 pointer value, Bool sendevent) 397{ 398 XIPropertyPtr prop; 399 devicePropertyNotify event; 400 int size_in_bytes; 401 int total_size; 402 unsigned long total_len; 403 XIPropertyValuePtr prop_value; 404 XIPropertyValueRec new_value; 405 Bool add = FALSE; 406 int rc; 407 408 size_in_bytes = format >> 3; 409 410 /* first see if property already exists */ 411 prop = XIFetchDeviceProperty (dev, property); 412 if (!prop) /* just add to list */ 413 { 414 prop = XICreateDeviceProperty (property); 415 if (!prop) 416 return(BadAlloc); 417 add = TRUE; 418 mode = PropModeReplace; 419 } 420 prop_value = &prop->value; 421 422 /* To append or prepend to a property the request format and type 423 must match those of the already defined property. The 424 existing format and type are irrelevant when using the mode 425 "PropModeReplace" since they will be written over. */ 426 427 if ((format != prop_value->format) && (mode != PropModeReplace)) 428 return(BadMatch); 429 if ((prop_value->type != type) && (mode != PropModeReplace)) 430 return(BadMatch); 431 new_value = *prop_value; 432 if (mode == PropModeReplace) 433 total_len = len; 434 else 435 total_len = prop_value->size + len; 436 437 if (mode == PropModeReplace || len > 0) 438 { 439 pointer new_data = NULL, old_data = NULL; 440 441 total_size = total_len * size_in_bytes; 442 new_value.data = (pointer)xalloc (total_size); 443 if (!new_value.data && total_size) 444 { 445 if (add) 446 XIDestroyDeviceProperty (prop); 447 return BadAlloc; 448 } 449 new_value.size = len; 450 new_value.type = type; 451 new_value.format = format; 452 453 switch (mode) { 454 case PropModeReplace: 455 new_data = new_value.data; 456 old_data = NULL; 457 break; 458 case PropModeAppend: 459 new_data = (pointer) (((char *) new_value.data) + 460 (prop_value->size * size_in_bytes)); 461 old_data = new_value.data; 462 break; 463 case PropModePrepend: 464 new_data = new_value.data; 465 old_data = (pointer) (((char *) new_value.data) + 466 (prop_value->size * size_in_bytes)); 467 break; 468 } 469 if (new_data) 470 memcpy ((char *) new_data, (char *) value, len * size_in_bytes); 471 if (old_data) 472 memcpy ((char *) old_data, (char *) prop_value->data, 473 prop_value->size * size_in_bytes); 474 475 if (dev->properties.handlers) 476 { 477 XIPropertyHandlerPtr handler; 478 BOOL checkonly = TRUE; 479 /* run through all handlers with checkonly TRUE, then again with 480 * checkonly FALSE. Handlers MUST return error codes on the 481 * checkonly run, errors on the second run are ignored */ 482 do 483 { 484 handler = dev->properties.handlers; 485 while(handler) 486 { 487 if (handler->SetProperty) 488 { 489 rc = handler->SetProperty(dev, prop->propertyName, 490 &new_value, checkonly); 491 if (checkonly && rc != Success) 492 { 493 if (new_value.data) 494 xfree (new_value.data); 495 return (rc); 496 } 497 } 498 handler = handler->next; 499 } 500 checkonly = !checkonly; 501 } while (!checkonly); 502 } 503 if (prop_value->data) 504 xfree (prop_value->data); 505 *prop_value = new_value; 506 } else if (len == 0) 507 { 508 /* do nothing */ 509 } 510 511 if (add) 512 { 513 prop->next = dev->properties.properties; 514 dev->properties.properties = prop; 515 } 516 517 if (sendevent) 518 { 519 event.type = DevicePropertyNotify; 520 event.deviceid = dev->id; 521 event.state = PropertyNewValue; 522 event.atom = prop->propertyName; 523 event.time = currentTime.milliseconds; 524 SendEventToAllWindows(dev, DevicePropertyNotifyMask, 525 (xEvent*)&event, 1); 526 } 527 return(Success); 528} 529 530int 531XIGetDeviceProperty (DeviceIntPtr dev, Atom property, XIPropertyValuePtr *value) 532{ 533 XIPropertyPtr prop = XIFetchDeviceProperty (dev, property); 534 int rc; 535 536 if (!prop) 537 { 538 *value = NULL; 539 return BadAtom; 540 } 541 542 /* If we can, try to update the property value first */ 543 if (dev->properties.handlers) 544 { 545 XIPropertyHandlerPtr handler = dev->properties.handlers; 546 while(handler) 547 { 548 if (handler->GetProperty) 549 { 550 rc = handler->GetProperty(dev, prop->propertyName); 551 if (rc != Success) 552 { 553 *value = NULL; 554 return rc; 555 } 556 } 557 handler = handler->next; 558 } 559 } 560 561 *value = &prop->value; 562 return Success; 563} 564 565int 566XISetDevicePropertyDeletable(DeviceIntPtr dev, Atom property, Bool deletable) 567{ 568 XIPropertyPtr prop = XIFetchDeviceProperty(dev, property); 569 570 if (!prop) 571 return BadAtom; 572 573 prop->deletable = deletable; 574 return Success; 575} 576 577int 578ProcXListDeviceProperties (ClientPtr client) 579{ 580 Atom *pAtoms = NULL, *temppAtoms; 581 xListDevicePropertiesReply rep; 582 int numProps = 0; 583 DeviceIntPtr dev; 584 XIPropertyPtr prop; 585 int rc = Success; 586 587 REQUEST(xListDevicePropertiesReq); 588 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 589 590 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixReadAccess); 591 if (rc != Success) 592 return rc; 593 594 for (prop = dev->properties.properties; prop; prop = prop->next) 595 numProps++; 596 if (numProps) 597 if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom)))) 598 return(BadAlloc); 599 600 rep.repType = X_Reply; 601 rep.RepType = X_ListDeviceProperties; 602 rep.length = (numProps * sizeof(Atom)) >> 2; 603 rep.sequenceNumber = client->sequence; 604 rep.nAtoms = numProps; 605 temppAtoms = pAtoms; 606 for (prop = dev->properties.properties; prop; prop = prop->next) 607 *temppAtoms++ = prop->propertyName; 608 609 WriteReplyToClient(client, sizeof(xListDevicePropertiesReply), &rep); 610 if (numProps) 611 { 612 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; 613 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); 614 xfree(pAtoms); 615 } 616 return rc; 617} 618 619int 620ProcXChangeDeviceProperty (ClientPtr client) 621{ 622 REQUEST(xChangeDevicePropertyReq); 623 DeviceIntPtr dev; 624 char format, mode; 625 unsigned long len; 626 int sizeInBytes; 627 int totalSize; 628 int rc; 629 630 REQUEST_AT_LEAST_SIZE(xChangeDevicePropertyReq); 631 UpdateCurrentTime(); 632 format = stuff->format; 633 mode = stuff->mode; 634 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 635 (mode != PropModePrepend)) 636 { 637 client->errorValue = mode; 638 return BadValue; 639 } 640 if ((format != 8) && (format != 16) && (format != 32)) 641 { 642 client->errorValue = format; 643 return BadValue; 644 } 645 len = stuff->nUnits; 646 if (len > ((0xffffffff - sizeof(xChangeDevicePropertyReq)) >> 2)) 647 return BadLength; 648 sizeInBytes = format>>3; 649 totalSize = len * sizeInBytes; 650 REQUEST_FIXED_SIZE(xChangeDevicePropertyReq, totalSize); 651 652 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess); 653 if (rc != Success) 654 return rc; 655 656 if (!ValidAtom(stuff->property)) 657 { 658 client->errorValue = stuff->property; 659 return(BadAtom); 660 } 661 if (!ValidAtom(stuff->type)) 662 { 663 client->errorValue = stuff->type; 664 return(BadAtom); 665 } 666 667 rc = XIChangeDeviceProperty(dev, stuff->property, 668 stuff->type, (int)format, 669 (int)mode, len, (pointer)&stuff[1], TRUE); 670 671 if (rc != Success) 672 client->errorValue = stuff->property; 673 return rc; 674} 675 676int 677ProcXDeleteDeviceProperty (ClientPtr client) 678{ 679 REQUEST(xDeleteDevicePropertyReq); 680 DeviceIntPtr dev; 681 int rc; 682 683 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 684 UpdateCurrentTime(); 685 rc = dixLookupDevice (&dev, stuff->deviceid, client, DixWriteAccess); 686 if (rc != Success) 687 return rc; 688 689 if (!ValidAtom(stuff->property)) 690 { 691 client->errorValue = stuff->property; 692 return (BadAtom); 693 } 694 695 rc = XIDeleteDeviceProperty(dev, stuff->property, TRUE); 696 return rc; 697} 698 699int 700ProcXGetDeviceProperty (ClientPtr client) 701{ 702 REQUEST(xGetDevicePropertyReq); 703 XIPropertyPtr prop, *prev; 704 XIPropertyValuePtr prop_value; 705 unsigned long n, len, ind; 706 DeviceIntPtr dev; 707 xGetDevicePropertyReply reply; 708 int rc; 709 710 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 711 if (stuff->delete) 712 UpdateCurrentTime(); 713 rc = dixLookupDevice (&dev, stuff->deviceid, client, 714 stuff->delete ? DixWriteAccess : 715 DixReadAccess); 716 if (rc != Success) 717 return rc; 718 719 if (!ValidAtom(stuff->property)) 720 { 721 client->errorValue = stuff->property; 722 return(BadAtom); 723 } 724 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) 725 { 726 client->errorValue = stuff->delete; 727 return(BadValue); 728 } 729 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) 730 { 731 client->errorValue = stuff->type; 732 return(BadAtom); 733 } 734 735 for (prev = &dev->properties.properties; (prop = *prev); prev = &prop->next) 736 if (prop->propertyName == stuff->property) 737 break; 738 739 reply.repType = X_Reply; 740 reply.RepType = X_GetDeviceProperty; 741 reply.sequenceNumber = client->sequence; 742 reply.deviceid = dev->id; 743 if (!prop) 744 { 745 reply.nItems = 0; 746 reply.length = 0; 747 reply.bytesAfter = 0; 748 reply.propertyType = None; 749 reply.format = 0; 750 WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply); 751 return(client->noClientException); 752 } 753 754 rc = XIGetDeviceProperty(dev, stuff->property, &prop_value); 755 if (rc != Success) 756 { 757 client->errorValue = stuff->property; 758 return rc; 759 } 760 761 /* If the request type and actual type don't match. Return the 762 property information, but not the data. */ 763 764 if (((stuff->type != prop_value->type) && 765 (stuff->type != AnyPropertyType)) 766 ) 767 { 768 reply.bytesAfter = prop_value->size; 769 reply.format = prop_value->format; 770 reply.length = 0; 771 reply.nItems = 0; 772 reply.propertyType = prop_value->type; 773 WriteReplyToClient(client, sizeof(xGetDevicePropertyReply), &reply); 774 return(client->noClientException); 775 } 776 777/* 778 * Return type, format, value to client 779 */ 780 n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */ 781 ind = stuff->longOffset << 2; 782 783 /* If longOffset is invalid such that it causes "len" to 784 be negative, it's a value error. */ 785 786 if (n < ind) 787 { 788 client->errorValue = stuff->longOffset; 789 return BadValue; 790 } 791 792 len = min(n - ind, 4 * stuff->longLength); 793 794 reply.bytesAfter = n - (ind + len); 795 reply.format = prop_value->format; 796 reply.length = (len + 3) >> 2; 797 if (prop_value->format) 798 reply.nItems = len / (prop_value->format / 8); 799 else 800 reply.nItems = 0; 801 reply.propertyType = prop_value->type; 802 803 if (stuff->delete && (reply.bytesAfter == 0)) 804 { 805 devicePropertyNotify event; 806 807 event.type = DevicePropertyNotify; 808 event.deviceid = dev->id; 809 event.state = PropertyDelete; 810 event.atom = prop->propertyName; 811 event.time = currentTime.milliseconds; 812 SendEventToAllWindows(dev, DevicePropertyNotifyMask, 813 (xEvent*)&event, 1); 814 } 815 816 WriteReplyToClient(client, sizeof(xGenericReply), &reply); 817 if (len) 818 { 819 switch (reply.format) { 820 case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; 821 case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; 822 default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; 823 } 824 WriteSwappedDataToClient(client, len, 825 (char *)prop_value->data + ind); 826 } 827 828 if (stuff->delete && (reply.bytesAfter == 0)) 829 { /* delete the Property */ 830 *prev = prop->next; 831 XIDestroyDeviceProperty (prop); 832 } 833 return(client->noClientException); 834} 835 836 837int 838SProcXListDeviceProperties (ClientPtr client) 839{ 840 char n; 841 REQUEST(xListDevicePropertiesReq); 842 843 swaps(&stuff->length, n); 844 845 REQUEST_SIZE_MATCH(xListDevicePropertiesReq); 846 return (ProcXListDeviceProperties(client)); 847} 848 849int 850SProcXChangeDeviceProperty (ClientPtr client) 851{ 852 char n; 853 REQUEST(xChangeDevicePropertyReq); 854 855 swaps(&stuff->length, n); 856 swapl(&stuff->property, n); 857 swapl(&stuff->type, n); 858 swapl(&stuff->nUnits, n); 859 REQUEST_SIZE_MATCH(xChangeDevicePropertyReq); 860 return (ProcXChangeDeviceProperty(client)); 861} 862 863int 864SProcXDeleteDeviceProperty (ClientPtr client) 865{ 866 char n; 867 REQUEST(xDeleteDevicePropertyReq); 868 869 swaps(&stuff->length, n); 870 swapl(&stuff->property, n); 871 REQUEST_SIZE_MATCH(xDeleteDevicePropertyReq); 872 return (ProcXDeleteDeviceProperty(client)); 873} 874 875int 876SProcXGetDeviceProperty (ClientPtr client) 877{ 878 char n; 879 REQUEST(xGetDevicePropertyReq); 880 881 swaps(&stuff->length, n); 882 swapl(&stuff->property, n); 883 swapl(&stuff->type, n); 884 swapl(&stuff->longOffset, n); 885 swapl(&stuff->longLength, n); 886 REQUEST_SIZE_MATCH(xGetDevicePropertyReq); 887 return (ProcXGetDeviceProperty(client)); 888} 889 890 891/* Reply swapping */ 892 893void 894SRepXListDeviceProperties(ClientPtr client, int size, 895 xListDevicePropertiesReply *rep) 896{ 897 char n; 898 swaps(&rep->sequenceNumber, n); 899 swapl(&rep->length, n); 900 swaps(&rep->nAtoms, n); 901 /* properties will be swapped later, see ProcXListDeviceProperties */ 902 WriteToClient(client, size, (char*)rep); 903} 904 905void 906SRepXGetDeviceProperty(ClientPtr client, int size, 907 xGetDevicePropertyReply *rep) 908{ 909 char n; 910 911 swaps(&rep->sequenceNumber, n); 912 swapl(&rep->length, n); 913 swapl(&rep->propertyType, n); 914 swapl(&rep->bytesAfter, n); 915 swapl(&rep->nItems, n); 916 /* data will be swapped, see ProcXGetDeviceProperty */ 917 WriteToClient(client, size, (char*)rep); 918} 919