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