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