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