1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 1 окт. 2019 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <ui/tk/tk.h> 23 24 namespace lsp 25 { 26 namespace tk 27 { ~IStyleListener()28 IStyleListener::~IStyleListener() 29 { 30 } 31 notify(ui_atom_t property)32 void IStyleListener::notify(ui_atom_t property) 33 { 34 } 35 LSPStyle()36 LSPStyle::LSPStyle() 37 { 38 nLock = 0; 39 bDelayed = false; 40 } 41 ~LSPStyle()42 LSPStyle::~LSPStyle() 43 { 44 do_destroy(); 45 } 46 init()47 status_t LSPStyle::init() 48 { 49 return STATUS_OK; 50 } 51 destroy()52 void LSPStyle::destroy() 53 { 54 do_destroy(); 55 } 56 do_destroy()57 void LSPStyle::do_destroy() 58 { 59 // Unlock all pending transactions 60 nLock = 0; 61 delayed_notify(); 62 63 // Unlink from parents and remove all children 64 for (size_t i=0, n=vParents.size(); i<n; ++i) 65 { 66 LSPStyle *parent = vParents.at(i); 67 if (parent != NULL) 68 parent->vChildren.remove(this); 69 } 70 71 // Unlink from children and remove all children 72 for (size_t i=0, n=vChildren.size(); i<n; ++i) 73 { 74 LSPStyle *child = vChildren.at(i); 75 if (child != NULL) 76 { 77 child->vParents.remove(this); 78 child->sync(); 79 } 80 } 81 vChildren.flush(); 82 83 // Synchronize state with listeners and remove them all 84 sync(); 85 vListeners.flush(); 86 87 // Destroy stored properties 88 for (size_t i=0, n=vProperties.size(); i<n; ++i) 89 undef_property(vProperties.at(i)); 90 vProperties.flush(); 91 } 92 undef_property(property_t * property)93 void LSPStyle::undef_property(property_t *property) 94 { 95 if (property == NULL) 96 return; 97 98 switch (property->type) 99 { 100 case PT_STRING: 101 if (property->v.sValue != NULL) 102 ::free(property->v.sValue); 103 break; 104 default: 105 break; 106 } 107 108 property->type = PT_UNKNOWN; 109 } 110 copy_property(property_t * dst,const property_t * src)111 status_t LSPStyle::copy_property(property_t *dst, const property_t *src) 112 { 113 // Check type of property 114 if (src->type != dst->type) 115 return STATUS_OK; 116 117 // Update contents 118 switch (src->type) 119 { 120 case PT_INT: 121 if (dst->v.iValue != src->v.iValue) 122 ++dst->changes; 123 dst->v.iValue = src->v.iValue; 124 break; 125 case PT_FLOAT: 126 if (dst->v.fValue != src->v.fValue) 127 ++dst->changes; 128 dst->v.fValue = src->v.fValue; 129 break; 130 case PT_BOOL: 131 if (dst->v.bValue != src->v.bValue) 132 ++dst->changes; 133 dst->v.bValue = src->v.bValue; 134 break; 135 case PT_STRING: 136 { 137 // Value does match? 138 if (::strcmp(dst->v.sValue, src->v.sValue) == 0) 139 break; 140 141 // Update value 142 char *tmp = ::strdup(src->v.sValue); 143 if (tmp == NULL) 144 return STATUS_NO_MEM; 145 ::free(dst->v.sValue); 146 dst->v.sValue = tmp; 147 ++dst->changes; 148 break; 149 } 150 } 151 152 return STATUS_OK; 153 } 154 create_property(ui_atom_t id,const property_t * src)155 LSPStyle::property_t *LSPStyle::create_property(ui_atom_t id, const property_t *src) 156 { 157 // Allocate property 158 property_t *dst = vProperties.add(); 159 if (dst == NULL) 160 return NULL; 161 162 // Init contents 163 switch (src->type) 164 { 165 case PT_INT: dst->v.iValue = src->v.iValue; break; 166 case PT_FLOAT: dst->v.fValue = src->v.fValue; break; 167 case PT_BOOL: dst->v.bValue = src->v.bValue; break; 168 case PT_STRING: 169 { 170 // Update value 171 if ((dst->v.sValue = ::strdup(src->v.sValue)) == NULL) 172 { 173 vProperties.remove(dst); 174 return NULL; 175 } 176 break; 177 } 178 default: 179 return NULL; 180 } 181 182 dst->id = id; 183 dst->refs = 0; 184 dst->type = src->type; 185 dst->changes = 0; 186 dst->flags = F_DEFAULT; 187 dst->owner = this; 188 189 return dst; 190 } 191 create_property(ui_atom_t id,ui_property_type_t type)192 LSPStyle::property_t *LSPStyle::create_property(ui_atom_t id, ui_property_type_t type) 193 { 194 // Allocate property 195 property_t *dst = vProperties.add(); 196 if (dst == NULL) 197 return NULL; 198 199 // Init contents 200 switch (type) 201 { 202 case PT_INT: dst->v.iValue = 0; break; 203 case PT_FLOAT: dst->v.fValue = 0.0; break; 204 case PT_BOOL: dst->v.bValue = 0; break; 205 case PT_STRING: 206 if ((dst->v.sValue = ::strdup("")) == NULL) 207 { 208 vProperties.remove(dst); 209 return NULL; 210 } 211 break; 212 default: 213 return NULL; 214 } 215 216 dst->id = id; 217 dst->refs = 0; 218 dst->type = type; 219 dst->changes = 0; 220 dst->flags = F_DEFAULT; 221 dst->owner = this; 222 223 return dst; 224 } 225 sync_property(property_t * p)226 status_t LSPStyle::sync_property(property_t *p) 227 { 228 if (!(p->flags & F_DEFAULT)) 229 return STATUS_OK; 230 231 property_t *parent = get_parent_property(p->id); 232 size_t changes = p->changes; 233 status_t res = (parent != NULL) ? copy_property(p, parent) : set_property_default(p); 234 if ((res == STATUS_OK) && (changes != p->changes)) 235 { 236 notify_listeners(p); 237 notify_children(p); 238 } 239 return res; 240 } 241 set_property_default(property_t * p)242 status_t LSPStyle::set_property_default(property_t *p) 243 { 244 switch (p->type) 245 { 246 case PT_INT: 247 if (p->v.iValue == 0) 248 return STATUS_OK; 249 p->v.iValue = 0; 250 break; 251 case PT_FLOAT: 252 if (p->v.fValue == 0) 253 return STATUS_OK; 254 p->v.fValue = 0; 255 break; 256 case PT_BOOL: 257 if (p->v.bValue == false) 258 return STATUS_OK; 259 p->v.bValue = false; 260 break; 261 case PT_STRING: 262 { 263 char *tmp = ::strdup(""); 264 if (tmp == NULL) 265 return STATUS_NO_MEM; 266 ::free(p->v.sValue); 267 p->v.sValue = tmp; 268 break; 269 } 270 default: 271 return STATUS_BAD_TYPE; 272 } 273 274 p->flags |= F_DEFAULT; 275 ++p->changes; 276 return STATUS_OK; 277 } 278 sync()279 void LSPStyle::sync() 280 { 281 // For each property: copy value from parent and notify children and listeners for changes 282 property_t *vp = vProperties.get_array(); 283 for (size_t i=0, n=vProperties.size(); i < n; ++i) 284 sync_property(&vp[i]); 285 286 // Call all children for sync() 287 for (size_t i=0, n=vChildren.size(); i<n; ++i) 288 { 289 LSPStyle *child = vChildren.at(i); 290 if (child != NULL) 291 child->sync(); 292 } 293 } 294 delayed_notify()295 void LSPStyle::delayed_notify() 296 { 297 size_t notified; 298 299 if (bDelayed) 300 return; 301 302 bDelayed = true; // Disallow delayed notify because it is already active 303 do 304 { 305 notified = 0; 306 for (size_t i=0, n=vProperties.size(); i < n; ++i) 307 { 308 property_t *prop = vProperties.at(i); 309 310 // Notify if notification is pending 311 if (prop->flags & F_NTF_LISTENERS) 312 { 313 prop->flags &= ~F_NTF_LISTENERS; 314 notify_listeners(prop); 315 ++notified; 316 } 317 if (prop->flags & F_NTF_CHILDREN) 318 { 319 prop->flags &= ~F_NTF_CHILDREN; 320 notify_children(prop); 321 ++notified; 322 } 323 } 324 } while (notified > 0); 325 bDelayed = false; 326 } 327 notify_change(property_t * prop)328 void LSPStyle::notify_change(property_t *prop) 329 { 330 // Find the matching property (if present) 331 property_t *p = get_property(prop->id); 332 333 // Property not found? 334 if (p == NULL) 335 { 336 notify_children(prop); // Just bypass event to children 337 return; 338 } 339 else if (!(p->flags & F_DEFAULT)) // Not default property? Ignore the event 340 return; 341 342 // Get parent Property 343 property_t *parent = get_parent_property(prop->id); 344 if (parent != NULL) 345 { 346 // Parent property has been changed? 347 size_t change = p->changes; 348 status_t res = copy_property(p, parent); 349 if ((res == STATUS_OK) && (change == p->changes)) 350 return; 351 } 352 else 353 { 354 // Copy property value and notify listener and children only if property has changed 355 size_t change = p->changes; 356 status_t res = copy_property(p, prop); 357 if ((res == STATUS_OK) && (change == p->changes)) 358 return; 359 } 360 361 // Notify children and listeners about property change 362 notify_listeners(p); 363 notify_children(p); 364 } 365 notify_children(property_t * prop)366 void LSPStyle::notify_children(property_t *prop) 367 { 368 // In transaction, just set notification flag instead of issuing notification procedure 369 if ((nLock > 0) && (prop->owner == this)) 370 { 371 prop->flags |= F_NTF_CHILDREN; 372 return; 373 } 374 375 // Notify all children about property change 376 for (size_t i=0, n=vChildren.size(); i<n; ++i) 377 { 378 LSPStyle *child = vChildren.at(i); 379 if (child != NULL) 380 child->notify_change(prop); 381 } 382 } 383 notify_listeners(property_t * prop)384 void LSPStyle::notify_listeners(property_t *prop) 385 { 386 // In transaction, just set notification flag instead of issuing notification procedure 387 if ((nLock > 0) && (prop->owner == this)) 388 { 389 prop->flags |= F_NTF_LISTENERS; 390 return; 391 } 392 393 // Notify all listeners about property change 394 ui_atom_t id = prop->id; 395 for (size_t i=0, n=vListeners.size(); i<n; ++i) 396 { 397 listener_t *lst = vListeners.at(i); 398 if ((lst != NULL) && (lst->nId == id)) 399 lst->pListener->notify(id); 400 } 401 } 402 add_child(LSPStyle * child,ssize_t idx)403 status_t LSPStyle::add_child(LSPStyle *child, ssize_t idx) 404 { 405 // Check arguments 406 if (child == NULL) 407 return STATUS_BAD_ARGUMENTS; 408 if (idx < 0) 409 idx = vChildren.size(); 410 else if (size_t(idx) > vChildren.size()) 411 return STATUS_INVALID_VALUE; 412 413 // Check 414 if (vChildren.index_of(child) >= 0) 415 return STATUS_ALREADY_EXISTS; 416 if ((child == this) || (child->has_child(this, true))) 417 return STATUS_BAD_HIERARCHY; 418 419 // Make bindings 420 if (!vChildren.insert(child, idx)) 421 return STATUS_NO_MEM; 422 if (!child->vParents.add(this)) 423 { 424 vChildren.remove(child); 425 return STATUS_NO_MEM; 426 } 427 428 // Synchronize state 429 child->sync(); 430 431 return STATUS_OK; 432 } 433 add_parent(LSPStyle * parent,ssize_t idx)434 status_t LSPStyle::add_parent(LSPStyle *parent, ssize_t idx) 435 { 436 // Check arguments 437 if (parent == NULL) 438 return STATUS_BAD_ARGUMENTS; 439 if (idx < 0) 440 idx = vParents.size(); 441 else if (size_t(idx) > vParents.size()) 442 return STATUS_INVALID_VALUE; 443 444 // Check 445 if (vParents.index_of(parent) >= 0) 446 return STATUS_ALREADY_EXISTS; 447 if ((parent == this) || (this->has_child(parent, true))) 448 return STATUS_BAD_HIERARCHY; 449 450 // Make bindings 451 if (!vParents.insert(parent, idx)) 452 return STATUS_NO_MEM; 453 if (!parent->vChildren.add(this)) 454 { 455 vParents.remove(parent); 456 return STATUS_NO_MEM; 457 } 458 459 // Synchronize state 460 sync(); 461 462 return STATUS_OK; 463 } 464 remove_child(LSPStyle * child)465 status_t LSPStyle::remove_child(LSPStyle *child) 466 { 467 if (child == NULL) 468 return STATUS_BAD_ARGUMENTS; 469 470 if (!vChildren.remove(child, true)) 471 return STATUS_NOT_FOUND; 472 473 child->vParents.remove(this); 474 child->sync(); 475 476 return STATUS_OK; 477 } 478 remove_parent(LSPStyle * parent)479 status_t LSPStyle::remove_parent(LSPStyle *parent) 480 { 481 if (parent == NULL) 482 return STATUS_BAD_ARGUMENTS; 483 484 if (!vParents.remove(parent)) 485 return STATUS_NOT_FOUND; 486 487 parent->vChildren.remove(this); 488 sync(); 489 490 return STATUS_OK; 491 } 492 has_child(LSPStyle * child,bool recursive)493 bool LSPStyle::has_child(LSPStyle *child, bool recursive) 494 { 495 if ((child == NULL) || (child == this)) 496 return false; 497 498 // First, lookup self children 499 if (vChildren.index_of(child) >= 0) 500 return true; 501 else if (!recursive) 502 return false; 503 504 // Second, lookup recursive 505 for (size_t i=0, n=vChildren.size(); i<n; ++i) 506 { 507 LSPStyle *s = vChildren.at(i); 508 if ((s != NULL) && (s->has_child(child, recursive))) 509 return true; 510 } 511 512 return false; 513 } 514 has_parent(LSPStyle * parent,bool recursive)515 bool LSPStyle::has_parent(LSPStyle *parent, bool recursive) 516 { 517 if ((parent == NULL) || (parent == this)) 518 return false; 519 520 // First, lookup self children 521 if (vParents.index_of(parent) >= 0) 522 return true; 523 else if (!recursive) 524 return false; 525 526 // Second, lookup recursively parents 527 for (size_t i=0, n=vParents.size(); i<n; ++i) 528 { 529 LSPStyle *s = vParents.at(i); 530 if ((s != NULL) && (s->has_parent(parent, recursive))) 531 return true; 532 } 533 534 return false; 535 } 536 is_bound(ui_atom_t id,IStyleListener * listener) const537 bool LSPStyle::is_bound(ui_atom_t id, IStyleListener *listener) const 538 { 539 const listener_t *pv = vListeners.get_array(); 540 for (size_t i=0, n=vListeners.size(); i<n; ++i) 541 { 542 const listener_t *p = &pv[i]; 543 if ((p->nId == id) && (p->pListener == listener)) 544 return true; 545 } 546 return false; 547 } 548 bind(ui_atom_t id,ui_property_type_t type,IStyleListener * listener)549 status_t LSPStyle::bind(ui_atom_t id, ui_property_type_t type, IStyleListener *listener) 550 { 551 property_t *p = get_property(id); 552 listener_t *lst = NULL; 553 554 // Property has been found? 555 if (p == NULL) 556 { 557 // Lookup parent property 558 property_t *parent = get_parent_property(id); 559 560 // Create property 561 p = (parent != NULL) ? create_property(id, parent) : create_property(id, type); 562 if (p == NULL) 563 return STATUS_NO_MEM; 564 565 // Allocate listener binding 566 lst = vListeners.add(); 567 if (listener == NULL) 568 { 569 undef_property(p); 570 vProperties.remove(p); 571 return STATUS_NO_MEM; 572 } 573 } 574 else 575 { 576 // Check that not already bound 577 if (is_bound(id, listener)) 578 return STATUS_ALREADY_BOUND; 579 580 // Just allocate listener binding 581 lst = vListeners.add(); 582 if (listener == NULL) 583 return STATUS_NO_MEM; 584 } 585 586 // Save listener to allocated binding 587 lst->nId = p->id; 588 lst->pListener = listener; 589 ++p->refs; 590 591 notify_listeners(p); 592 notify_children(p); 593 594 return STATUS_OK; 595 } 596 unbind(ui_atom_t id,IStyleListener * listener)597 status_t LSPStyle::unbind(ui_atom_t id, IStyleListener *listener) 598 { 599 // Find listener binding 600 listener_t *lst = NULL; 601 listener_t *pv = vListeners.get_array(); 602 for (size_t i=0, n=vListeners.size(); i<n; ++i) 603 { 604 listener_t *p = &pv[i]; 605 if ((p->nId == id) && (p->pListener == listener)) 606 { 607 lst = p; 608 break; 609 } 610 } 611 612 if (lst == NULL) 613 return STATUS_NOT_BOUND; 614 615 // Get property 616 property_t *p = get_property(id); 617 if (p == NULL) 618 return STATUS_CORRUPTED; // This actually should not ever happen 619 620 // Decrement number of references 621 if ((--p->refs) <= 0) 622 { 623 undef_property(p); 624 property_t *parent = get_parent_property(p->id); 625 notify_children((parent != NULL) ? parent : p); 626 vProperties.remove(p); 627 } 628 629 // Remove listener binding 630 vListeners.remove(lst); 631 632 return STATUS_OK; 633 } 634 get_property(ui_atom_t id)635 LSPStyle::property_t *LSPStyle::get_property(ui_atom_t id) 636 { 637 for (size_t i=0, n=vProperties.size(); i<n; ++i) 638 { 639 property_t *p = vProperties.at(i); 640 if ((p != NULL) && (p->id == id)) 641 return p; 642 } 643 return NULL; 644 } 645 get_parent_property(ui_atom_t id)646 LSPStyle::property_t *LSPStyle::get_parent_property(ui_atom_t id) 647 { 648 // Lookup parents in reverse order 649 for (ssize_t i=vParents.size() - 1; i >= 0; --i) 650 { 651 LSPStyle *curr = vParents.at(i); 652 if (curr == NULL) 653 continue; 654 655 // Try to fetch property first 656 property_t *p = curr->get_property(id); 657 if (p == NULL) // Property not found? 658 p = curr->get_parent_property(id); // Search parents recursively 659 if (p != NULL) 660 return p; 661 } 662 663 return NULL; 664 } 665 get_property_recursive(ui_atom_t id)666 LSPStyle::property_t *LSPStyle::get_property_recursive(ui_atom_t id) 667 { 668 property_t *p = get_property(id); 669 return (p != NULL) ? p : get_parent_property(id); 670 } 671 begin()672 void LSPStyle::begin() 673 { 674 ++nLock; 675 } 676 end()677 void LSPStyle::end() 678 { 679 if (nLock == 0) 680 return; 681 if (!(--nLock)) // last end() ? 682 delayed_notify(); 683 } 684 get_int(ui_atom_t id,ssize_t * dst) const685 status_t LSPStyle::get_int(ui_atom_t id, ssize_t *dst) const 686 { 687 const property_t *prop = get_property_recursive(id); 688 if (prop == NULL) 689 { 690 *dst = 0; 691 return STATUS_OK; 692 } 693 else if (prop->type != PT_INT) 694 return STATUS_BAD_TYPE; 695 if (dst != NULL) 696 *dst = prop->v.iValue; 697 return STATUS_OK; 698 } 699 get_float(ui_atom_t id,float * dst) const700 status_t LSPStyle::get_float(ui_atom_t id, float *dst) const 701 { 702 const property_t *prop = get_property_recursive(id); 703 if (prop == NULL) 704 { 705 *dst = 0.0f; 706 return STATUS_OK; 707 } 708 else if (prop->type != PT_FLOAT) 709 return STATUS_BAD_TYPE; 710 if (dst != NULL) 711 *dst = prop->v.fValue; 712 return STATUS_OK; 713 } 714 get_bool(ui_atom_t id,bool * dst) const715 status_t LSPStyle::get_bool(ui_atom_t id, bool *dst) const 716 { 717 const property_t *prop = get_property_recursive(id); 718 if (prop == NULL) 719 { 720 *dst = false; 721 return STATUS_OK; 722 } 723 else if (prop->type != PT_BOOL) 724 return STATUS_BAD_TYPE; 725 if (dst != NULL) 726 *dst = prop->v.bValue; 727 return STATUS_OK; 728 } 729 get_string(ui_atom_t id,LSPString * dst) const730 status_t LSPStyle::get_string(ui_atom_t id, LSPString *dst) const 731 { 732 const property_t *prop = get_property_recursive(id); 733 if (prop == NULL) 734 { 735 if (dst != NULL) 736 dst->truncate(); 737 return STATUS_OK; 738 } 739 else if (prop->type != PT_STRING) 740 return STATUS_BAD_TYPE; 741 742 if (dst == NULL) 743 return STATUS_OK; 744 return (dst->set_utf8(prop->v.sValue)) ? STATUS_OK : STATUS_NO_MEM; 745 } 746 get_string(ui_atom_t id,const char ** dst) const747 status_t LSPStyle::get_string(ui_atom_t id, const char **dst) const 748 { 749 const property_t *prop = get_property_recursive(id); 750 if (prop == NULL) 751 { 752 if (dst != NULL) 753 *dst = ""; 754 return STATUS_OK; 755 } 756 else if (prop->type != PT_STRING) 757 return STATUS_BAD_TYPE; 758 759 if (dst != NULL) 760 *dst = prop->v.sValue; 761 return STATUS_OK; 762 } 763 is_default(ui_atom_t id) const764 bool LSPStyle::is_default(ui_atom_t id) const 765 { 766 const property_t *prop = get_property_recursive(id); 767 return (prop != NULL) ? (prop->flags & F_DEFAULT) : false; 768 } 769 exists(ui_atom_t id) const770 bool LSPStyle::exists(ui_atom_t id) const 771 { 772 const property_t *prop = get_property_recursive(id); 773 return (prop != NULL); 774 } 775 get_type(ui_atom_t id) const776 ssize_t LSPStyle::get_type(ui_atom_t id) const 777 { 778 const property_t *prop = get_property_recursive(id); 779 return (prop != NULL) ? prop->type : PT_UNKNOWN; 780 } 781 set_property(ui_atom_t id,property_t * src)782 status_t LSPStyle::set_property(ui_atom_t id, property_t *src) 783 { 784 status_t res = STATUS_OK; 785 property_t *p = get_property(id); 786 if (p == NULL) 787 { 788 // Allocate new property 789 p = create_property(id, src); 790 if (p == NULL) 791 return STATUS_NO_MEM; 792 p->flags &= ~F_DEFAULT; 793 notify_listeners(p); 794 notify_children(p); 795 } 796 else 797 { 798 // Notify only if value has changed 799 size_t change = p->changes; 800 res = copy_property(p, src); 801 802 if (res == STATUS_OK) 803 { 804 p->flags &= ~F_DEFAULT; 805 if (change != p->changes) 806 { 807 notify_listeners(p); 808 notify_children(p); 809 } 810 } 811 } 812 813 return res; 814 } 815 set_int(ui_atom_t id,ssize_t value)816 status_t LSPStyle::set_int(ui_atom_t id, ssize_t value) 817 { 818 property_t tmp; 819 tmp.type = PT_INT; 820 tmp.v.iValue = value; 821 return set_property(id, &tmp); 822 } 823 set_float(ui_atom_t id,float value)824 status_t LSPStyle::set_float(ui_atom_t id, float value) 825 { 826 property_t tmp; 827 tmp.type = PT_FLOAT; 828 tmp.v.fValue = value; 829 return set_property(id, &tmp); 830 } 831 set_bool(ui_atom_t id,bool value)832 status_t LSPStyle::set_bool(ui_atom_t id, bool value) 833 { 834 property_t tmp; 835 tmp.type = PT_BOOL; 836 tmp.v.bValue = value; 837 return set_property(id, &tmp); 838 } 839 set_string(ui_atom_t id,const LSPString * value)840 status_t LSPStyle::set_string(ui_atom_t id, const LSPString *value) 841 { 842 if (value == NULL) 843 return STATUS_BAD_ARGUMENTS; 844 845 property_t tmp; 846 tmp.type = PT_STRING; 847 tmp.v.sValue = const_cast<char *>(value->get_utf8()); 848 return set_property(id, &tmp); 849 } 850 set_string(ui_atom_t id,const char * value)851 status_t LSPStyle::set_string(ui_atom_t id, const char *value) 852 { 853 if (value == NULL) 854 return STATUS_BAD_ARGUMENTS; 855 856 property_t tmp; 857 tmp.type = PT_STRING; 858 tmp.v.sValue = const_cast<char *>(value); 859 return set_property(id, &tmp); 860 } 861 set_default(ui_atom_t id)862 status_t LSPStyle::set_default(ui_atom_t id) 863 { 864 property_t *p = get_property(id); 865 if (p == NULL) 866 return STATUS_NOT_FOUND; 867 else if (p->flags & F_DEFAULT) 868 return STATUS_OK; 869 870 // Initialize property with default value 871 p->flags |= F_DEFAULT; 872 return sync_property(p); 873 } 874 875 } /* namespace tk */ 876 } /* namespace lsp */ 877