rrproperty.c revision 4642e01f
1/* 2 * Copyright © 2006 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "randrstr.h" 24#include "propertyst.h" 25#include "swaprep.h" 26 27static int 28DeliverPropertyEvent(WindowPtr pWin, void *value) 29{ 30 xRROutputPropertyNotifyEvent *event = value; 31 RREventPtr *pHead, pRREvent; 32 ClientPtr client; 33 34 pHead = LookupIDByType(pWin->drawable.id, RREventType); 35 if (!pHead) 36 return WT_WALKCHILDREN; 37 38 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) 39 { 40 client = pRREvent->client; 41 if (client == serverClient || client->clientGone) 42 continue; 43 44 if (!(pRREvent->mask & RROutputPropertyNotifyMask)) 45 continue; 46 47 event->sequenceNumber = client->sequence; 48 event->window = pRREvent->window->drawable.id; 49 if (client->swapped) { 50 int n; 51 swaps(&event->sequenceNumber, n); 52 swapl(&event->window, n); 53 } 54 WriteEventsToClient(pRREvent->client, 1, (xEvent *)event); 55 } 56 57 return WT_WALKCHILDREN; 58} 59 60static void RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event) 61{ 62 if (!(dispatchException & (DE_RESET | DE_TERMINATE))) 63 WalkTree(pScreen, DeliverPropertyEvent, event); 64} 65 66void 67RRDeleteAllOutputProperties (RROutputPtr output) 68{ 69 RRPropertyPtr prop, next; 70 xRROutputPropertyNotifyEvent event; 71 72 for (prop = output->properties; prop; prop = next) 73 { 74 next = prop->next; 75 event.type = RREventBase + RRNotify; 76 event.subCode = RRNotify_OutputProperty; 77 event.output = output->id; 78 event.state = PropertyDelete; 79 event.atom = prop->propertyName; 80 event.timestamp = currentTime.milliseconds; 81 RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event); 82 if (prop->current.data) 83 xfree(prop->current.data); 84 if (prop->pending.data) 85 xfree(prop->pending.data); 86 xfree(prop); 87 } 88} 89 90static void 91RRInitOutputPropertyValue (RRPropertyValuePtr property_value) 92{ 93 property_value->type = None; 94 property_value->format = 0; 95 property_value->size = 0; 96 property_value->data = NULL; 97} 98 99static RRPropertyPtr 100RRCreateOutputProperty (Atom property) 101{ 102 RRPropertyPtr prop; 103 104 prop = (RRPropertyPtr)xalloc(sizeof(RRPropertyRec)); 105 if (!prop) 106 return NULL; 107 prop->next = NULL; 108 prop->propertyName = property; 109 prop->is_pending = FALSE; 110 prop->range = FALSE; 111 prop->immutable = FALSE; 112 prop->num_valid = 0; 113 prop->valid_values = NULL; 114 RRInitOutputPropertyValue (&prop->current); 115 RRInitOutputPropertyValue (&prop->pending); 116 return prop; 117} 118 119static void 120RRDestroyOutputProperty (RRPropertyPtr prop) 121{ 122 if (prop->valid_values) 123 xfree (prop->valid_values); 124 if (prop->current.data) 125 xfree(prop->current.data); 126 if (prop->pending.data) 127 xfree(prop->pending.data); 128 xfree(prop); 129} 130 131void 132RRDeleteOutputProperty (RROutputPtr output, Atom property) 133{ 134 RRPropertyPtr prop, *prev; 135 xRROutputPropertyNotifyEvent event; 136 137 for (prev = &output->properties; (prop = *prev); prev = &(prop->next)) 138 if (prop->propertyName == property) 139 break; 140 if (prop) 141 { 142 *prev = prop->next; 143 event.type = RREventBase + RRNotify; 144 event.subCode = RRNotify_OutputProperty; 145 event.output = output->id; 146 event.state = PropertyDelete; 147 event.atom = prop->propertyName; 148 event.timestamp = currentTime.milliseconds; 149 RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event); 150 RRDestroyOutputProperty (prop); 151 } 152} 153 154int 155RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type, 156 int format, int mode, unsigned long len, 157 pointer value, Bool sendevent, Bool pending) 158{ 159 RRPropertyPtr prop; 160 xRROutputPropertyNotifyEvent event; 161 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen); 162 int size_in_bytes; 163 int total_size; 164 unsigned long total_len; 165 RRPropertyValuePtr prop_value; 166 RRPropertyValueRec new_value; 167 Bool add = FALSE; 168 169 size_in_bytes = format >> 3; 170 171 /* first see if property already exists */ 172 prop = RRQueryOutputProperty (output, property); 173 if (!prop) /* just add to list */ 174 { 175 prop = RRCreateOutputProperty (property); 176 if (!prop) 177 return(BadAlloc); 178 add = TRUE; 179 mode = PropModeReplace; 180 } 181 if (pending && prop->is_pending) 182 prop_value = &prop->pending; 183 else 184 prop_value = &prop->current; 185 186 /* To append or prepend to a property the request format and type 187 must match those of the already defined property. The 188 existing format and type are irrelevant when using the mode 189 "PropModeReplace" since they will be written over. */ 190 191 if ((format != prop_value->format) && (mode != PropModeReplace)) 192 return(BadMatch); 193 if ((prop_value->type != type) && (mode != PropModeReplace)) 194 return(BadMatch); 195 new_value = *prop_value; 196 if (mode == PropModeReplace) 197 total_len = len; 198 else 199 total_len = prop_value->size + len; 200 201 if (mode == PropModeReplace || len > 0) 202 { 203 pointer new_data = NULL, old_data = NULL; 204 205 total_size = total_len * size_in_bytes; 206 new_value.data = (pointer)xalloc (total_size); 207 if (!new_value.data && total_size) 208 { 209 if (add) 210 RRDestroyOutputProperty (prop); 211 return BadAlloc; 212 } 213 new_value.size = len; 214 new_value.type = type; 215 new_value.format = format; 216 217 switch (mode) { 218 case PropModeReplace: 219 new_data = new_value.data; 220 old_data = NULL; 221 break; 222 case PropModeAppend: 223 new_data = (pointer) (((char *) new_value.data) + 224 (prop_value->size * size_in_bytes)); 225 old_data = new_value.data; 226 break; 227 case PropModePrepend: 228 new_data = new_value.data; 229 old_data = (pointer) (((char *) new_value.data) + 230 (prop_value->size * size_in_bytes)); 231 break; 232 } 233 if (new_data) 234 memcpy ((char *) new_data, (char *) value, len * size_in_bytes); 235 if (old_data) 236 memcpy ((char *) old_data, (char *) prop_value->data, 237 prop_value->size * size_in_bytes); 238 239 if (pending && pScrPriv->rrOutputSetProperty && 240 !pScrPriv->rrOutputSetProperty(output->pScreen, output, 241 prop->propertyName, &new_value)) 242 { 243 if (new_value.data) 244 xfree (new_value.data); 245 return (BadValue); 246 } 247 if (prop_value->data) 248 xfree (prop_value->data); 249 *prop_value = new_value; 250 } 251 252 else if (len == 0) 253 { 254 /* do nothing */ 255 } 256 257 if (add) 258 { 259 prop->next = output->properties; 260 output->properties = prop; 261 } 262 263 if (pending && prop->is_pending) 264 output->pendingProperties = TRUE; 265 266 if (sendevent) 267 { 268 event.type = RREventBase + RRNotify; 269 event.subCode = RRNotify_OutputProperty; 270 event.output = output->id; 271 event.state = PropertyNewValue; 272 event.atom = prop->propertyName; 273 event.timestamp = currentTime.milliseconds; 274 RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event); 275 } 276 return(Success); 277} 278 279Bool 280RRPostPendingProperties (RROutputPtr output) 281{ 282 RRPropertyValuePtr pending_value; 283 RRPropertyValuePtr current_value; 284 RRPropertyPtr property; 285 Bool ret = TRUE; 286 287 if (!output->pendingProperties) 288 return TRUE; 289 290 output->pendingProperties = FALSE; 291 for (property = output->properties; property; property = property->next) 292 { 293 /* Skip non-pending properties */ 294 if (!property->is_pending) 295 continue; 296 297 pending_value = &property->pending; 298 current_value = &property->current; 299 300 /* 301 * If the pending and current values are equal, don't mark it 302 * as changed (which would deliver an event) 303 */ 304 if (pending_value->type == current_value->type && 305 pending_value->format == current_value->format && 306 pending_value->size == current_value->size && 307 !memcmp (pending_value->data, current_value->data, 308 pending_value->size)) 309 continue; 310 311 if (RRChangeOutputProperty (output, property->propertyName, 312 pending_value->type, pending_value->format, 313 PropModeReplace, pending_value->size, 314 pending_value->data, TRUE, 315 FALSE) != Success) 316 ret = FALSE; 317 } 318 return ret; 319} 320 321RRPropertyPtr 322RRQueryOutputProperty (RROutputPtr output, Atom property) 323{ 324 RRPropertyPtr prop; 325 326 for (prop = output->properties; prop; prop = prop->next) 327 if (prop->propertyName == property) 328 return prop; 329 return NULL; 330} 331 332RRPropertyValuePtr 333RRGetOutputProperty (RROutputPtr output, Atom property, Bool pending) 334{ 335 RRPropertyPtr prop = RRQueryOutputProperty (output, property); 336 rrScrPrivPtr pScrPriv = rrGetScrPriv(output->pScreen); 337 338 if (!prop) 339 return NULL; 340 if (pending && prop->is_pending) 341 return &prop->pending; 342 else { 343#if RANDR_13_INTERFACE 344 /* If we can, try to update the property value first */ 345 if (pScrPriv->rrOutputGetProperty) 346 pScrPriv->rrOutputGetProperty(output->pScreen, output, 347 prop->propertyName); 348#endif 349 return &prop->current; 350 } 351} 352 353int 354RRConfigureOutputProperty (RROutputPtr output, Atom property, 355 Bool pending, Bool range, Bool immutable, 356 int num_values, INT32 *values) 357{ 358 RRPropertyPtr prop = RRQueryOutputProperty (output, property); 359 Bool add = FALSE; 360 INT32 *new_values; 361 362 if (!prop) 363 { 364 prop = RRCreateOutputProperty (property); 365 if (!prop) 366 return(BadAlloc); 367 add = TRUE; 368 } else if (prop->immutable && !immutable) 369 return(BadAccess); 370 371 /* 372 * ranges must have even number of values 373 */ 374 if (range && (num_values & 1)) 375 return BadMatch; 376 377 new_values = xalloc (num_values * sizeof (INT32)); 378 if (!new_values && num_values) 379 return BadAlloc; 380 if (num_values) 381 memcpy (new_values, values, num_values * sizeof (INT32)); 382 383 /* 384 * Property moving from pending to non-pending 385 * loses any pending values 386 */ 387 if (prop->is_pending && !pending) 388 { 389 if (prop->pending.data) 390 xfree (prop->pending.data); 391 RRInitOutputPropertyValue (&prop->pending); 392 } 393 394 prop->is_pending = pending; 395 prop->range = range; 396 prop->immutable = immutable; 397 prop->num_valid = num_values; 398 if (prop->valid_values) 399 xfree (prop->valid_values); 400 prop->valid_values = new_values; 401 402 if (add) { 403 prop->next = output->properties; 404 output->properties = prop; 405 } 406 407 return Success; 408} 409 410int 411ProcRRListOutputProperties (ClientPtr client) 412{ 413 REQUEST(xRRListOutputPropertiesReq); 414 Atom *pAtoms = NULL, *temppAtoms; 415 xRRListOutputPropertiesReply rep; 416 int numProps = 0; 417 RROutputPtr output; 418 RRPropertyPtr prop; 419 420 REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq); 421 422 output = LookupOutput (client, stuff->output, DixReadAccess); 423 424 if (!output) 425 return RRErrorBase + BadRROutput; 426 427 for (prop = output->properties; prop; prop = prop->next) 428 numProps++; 429 if (numProps) 430 if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom)))) 431 return(BadAlloc); 432 433 rep.type = X_Reply; 434 rep.length = (numProps * sizeof(Atom)) >> 2; 435 rep.sequenceNumber = client->sequence; 436 rep.nAtoms = numProps; 437 if (client->swapped) 438 { 439 int n; 440 swaps (&rep.sequenceNumber, n); 441 swapl (&rep.length, n); 442 swaps (&rep.nAtoms, n); 443 } 444 temppAtoms = pAtoms; 445 for (prop = output->properties; prop; prop = prop->next) 446 *temppAtoms++ = prop->propertyName; 447 448 WriteToClient(client, sizeof(xRRListOutputPropertiesReply), (char*)&rep); 449 if (numProps) 450 { 451 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; 452 WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms); 453 xfree(pAtoms); 454 } 455 return(client->noClientException); 456} 457 458int 459ProcRRQueryOutputProperty (ClientPtr client) 460{ 461 REQUEST(xRRQueryOutputPropertyReq); 462 xRRQueryOutputPropertyReply rep; 463 RROutputPtr output; 464 RRPropertyPtr prop; 465 char *extra = NULL; 466 467 REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq); 468 469 output = LookupOutput (client, stuff->output, DixReadAccess); 470 471 if (!output) 472 return RRErrorBase + BadRROutput; 473 474 prop = RRQueryOutputProperty (output, stuff->property); 475 if (!prop) 476 return BadName; 477 478 if (prop->num_valid) { 479 extra = xalloc(prop->num_valid * sizeof(INT32)); 480 if (!extra) 481 return BadAlloc; 482 } 483 rep.type = X_Reply; 484 rep.length = prop->num_valid; 485 rep.sequenceNumber = client->sequence; 486 rep.pending = prop->is_pending; 487 rep.range = prop->range; 488 rep.immutable = prop->immutable; 489 if (client->swapped) 490 { 491 int n; 492 swaps (&rep.sequenceNumber, n); 493 swapl (&rep.length, n); 494 } 495 WriteToClient (client, sizeof (xRRQueryOutputPropertyReply), (char*)&rep); 496 if (prop->num_valid) 497 { 498 memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32)); 499 client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write; 500 WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32), 501 extra); 502 xfree(extra); 503 } 504 return(client->noClientException); 505} 506 507int 508ProcRRConfigureOutputProperty (ClientPtr client) 509{ 510 REQUEST(xRRConfigureOutputPropertyReq); 511 RROutputPtr output; 512 int num_valid; 513 514 REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq); 515 516 output = LookupOutput (client, stuff->output, DixReadAccess); 517 518 if (!output) 519 return RRErrorBase + BadRROutput; 520 521 num_valid = stuff->length - (sizeof (xRRConfigureOutputPropertyReq) >> 2); 522 return RRConfigureOutputProperty (output, stuff->property, 523 stuff->pending, stuff->range, 524 FALSE, num_valid, 525 (INT32 *) (stuff + 1)); 526} 527 528int 529ProcRRChangeOutputProperty (ClientPtr client) 530{ 531 REQUEST(xRRChangeOutputPropertyReq); 532 RROutputPtr output; 533 char format, mode; 534 unsigned long len; 535 int sizeInBytes; 536 int totalSize; 537 int err; 538 539 REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq); 540 UpdateCurrentTime(); 541 format = stuff->format; 542 mode = stuff->mode; 543 if ((mode != PropModeReplace) && (mode != PropModeAppend) && 544 (mode != PropModePrepend)) 545 { 546 client->errorValue = mode; 547 return BadValue; 548 } 549 if ((format != 8) && (format != 16) && (format != 32)) 550 { 551 client->errorValue = format; 552 return BadValue; 553 } 554 len = stuff->nUnits; 555 if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2)) 556 return BadLength; 557 sizeInBytes = format>>3; 558 totalSize = len * sizeInBytes; 559 REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize); 560 561 output = LookupOutput (client, stuff->output, DixWriteAccess); 562 if (!output) 563 return RRErrorBase + BadRROutput; 564 565 if (!ValidAtom(stuff->property)) 566 { 567 client->errorValue = stuff->property; 568 return(BadAtom); 569 } 570 if (!ValidAtom(stuff->type)) 571 { 572 client->errorValue = stuff->type; 573 return(BadAtom); 574 } 575 576 err = RRChangeOutputProperty(output, stuff->property, 577 stuff->type, (int)format, 578 (int)mode, len, (pointer)&stuff[1], TRUE, TRUE); 579 if (err != Success) 580 return err; 581 else 582 return client->noClientException; 583} 584 585int 586ProcRRDeleteOutputProperty (ClientPtr client) 587{ 588 REQUEST(xRRDeleteOutputPropertyReq); 589 RROutputPtr output; 590 591 REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq); 592 UpdateCurrentTime(); 593 output = LookupOutput (client, stuff->output, DixWriteAccess); 594 if (!output) 595 return RRErrorBase + BadRROutput; 596 597 if (!ValidAtom(stuff->property)) 598 { 599 client->errorValue = stuff->property; 600 return (BadAtom); 601 } 602 603 604 RRDeleteOutputProperty(output, stuff->property); 605 return client->noClientException; 606} 607 608int 609ProcRRGetOutputProperty (ClientPtr client) 610{ 611 REQUEST(xRRGetOutputPropertyReq); 612 RRPropertyPtr prop, *prev; 613 RRPropertyValuePtr prop_value; 614 unsigned long n, len, ind; 615 RROutputPtr output; 616 xRRGetOutputPropertyReply reply; 617 char *extra = NULL; 618 619 REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq); 620 if (stuff->delete) 621 UpdateCurrentTime(); 622 output = LookupOutput (client, stuff->output, 623 stuff->delete ? DixWriteAccess : 624 DixReadAccess); 625 if (!output) 626 return RRErrorBase + BadRROutput; 627 628 if (!ValidAtom(stuff->property)) 629 { 630 client->errorValue = stuff->property; 631 return(BadAtom); 632 } 633 if ((stuff->delete != xTrue) && (stuff->delete != xFalse)) 634 { 635 client->errorValue = stuff->delete; 636 return(BadValue); 637 } 638 if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type)) 639 { 640 client->errorValue = stuff->type; 641 return(BadAtom); 642 } 643 644 for (prev = &output->properties; (prop = *prev); prev = &prop->next) 645 if (prop->propertyName == stuff->property) 646 break; 647 648 reply.type = X_Reply; 649 reply.sequenceNumber = client->sequence; 650 if (!prop) 651 { 652 reply.nItems = 0; 653 reply.length = 0; 654 reply.bytesAfter = 0; 655 reply.propertyType = None; 656 reply.format = 0; 657 if (client->swapped) { 658 int n; 659 660 swaps(&reply.sequenceNumber, n); 661 swapl(&reply.length, n); 662 swapl(&reply.propertyType, n); 663 swapl(&reply.bytesAfter, n); 664 swapl(&reply.nItems, n); 665 } 666 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply); 667 return(client->noClientException); 668 } 669 670 if (prop->immutable && stuff->delete) 671 return BadAccess; 672 673 prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending); 674 if (!prop_value) 675 return BadAtom; 676 677 /* If the request type and actual type don't match. Return the 678 property information, but not the data. */ 679 680 if (((stuff->type != prop_value->type) && 681 (stuff->type != AnyPropertyType)) 682 ) 683 { 684 reply.bytesAfter = prop_value->size; 685 reply.format = prop_value->format; 686 reply.length = 0; 687 reply.nItems = 0; 688 reply.propertyType = prop_value->type; 689 if (client->swapped) { 690 int n; 691 692 swaps(&reply.sequenceNumber, n); 693 swapl(&reply.length, n); 694 swapl(&reply.propertyType, n); 695 swapl(&reply.bytesAfter, n); 696 swapl(&reply.nItems, n); 697 } 698 WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply); 699 return(client->noClientException); 700 } 701 702/* 703 * Return type, format, value to client 704 */ 705 n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */ 706 ind = stuff->longOffset << 2; 707 708 /* If longOffset is invalid such that it causes "len" to 709 be negative, it's a value error. */ 710 711 if (n < ind) 712 { 713 client->errorValue = stuff->longOffset; 714 return BadValue; 715 } 716 717 len = min(n - ind, 4 * stuff->longLength); 718 719 if (len) { 720 extra = xalloc(len); 721 if (!extra) 722 return BadAlloc; 723 } 724 reply.bytesAfter = n - (ind + len); 725 reply.format = prop_value->format; 726 reply.length = (len + 3) >> 2; 727 if (prop_value->format) 728 reply.nItems = len / (prop_value->format / 8); 729 else 730 reply.nItems = 0; 731 reply.propertyType = prop_value->type; 732 733 if (stuff->delete && (reply.bytesAfter == 0)) 734 { 735 xRROutputPropertyNotifyEvent event; 736 737 event.type = RREventBase + RRNotify; 738 event.subCode = RRNotify_OutputProperty; 739 event.output = output->id; 740 event.state = PropertyDelete; 741 event.atom = prop->propertyName; 742 event.timestamp = currentTime.milliseconds; 743 RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event); 744 } 745 746 if (client->swapped) { 747 int n; 748 749 swaps(&reply.sequenceNumber, n); 750 swapl(&reply.length, n); 751 swapl(&reply.propertyType, n); 752 swapl(&reply.bytesAfter, n); 753 swapl(&reply.nItems, n); 754 } 755 WriteToClient(client, sizeof(xGenericReply), &reply); 756 if (len) 757 { 758 memcpy(extra, (char *)prop_value->data + ind, len); 759 switch (reply.format) { 760 case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break; 761 case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break; 762 default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break; 763 } 764 WriteSwappedDataToClient(client, len, 765 extra); 766 xfree(extra); 767 } 768 769 if (stuff->delete && (reply.bytesAfter == 0)) 770 { /* delete the Property */ 771 *prev = prop->next; 772 RRDestroyOutputProperty (prop); 773 } 774 return(client->noClientException); 775} 776 777