Atlas - SDL_properties.c
Home / ext / SDL / src Lines: 1 | Size: 24982 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#include "SDL_hints_c.h" 24#include "SDL_properties_c.h" 25 26 27typedef struct 28{ 29 SDL_PropertyType type; 30 31 union { 32 void *pointer_value; 33 char *string_value; 34 Sint64 number_value; 35 float float_value; 36 bool boolean_value; 37 } value; 38 39 char *string_storage; 40 41 SDL_CleanupPropertyCallback cleanup; 42 void *userdata; 43} SDL_Property; 44 45typedef struct 46{ 47 SDL_HashTable *props; 48 SDL_Mutex *lock; 49} SDL_Properties; 50 51static SDL_InitState SDL_properties_init; 52static SDL_HashTable *SDL_properties; 53static SDL_AtomicU32 SDL_last_properties_id; 54static SDL_AtomicU32 SDL_global_properties; 55 56 57static void SDL_FreePropertyWithCleanup(const void *key, const void *value, void *data, bool cleanup) 58{ 59 SDL_Property *property = (SDL_Property *)value; 60 if (property) { 61 switch (property->type) { 62 case SDL_PROPERTY_TYPE_POINTER: 63 if (property->cleanup && cleanup) { 64 property->cleanup(property->userdata, property->value.pointer_value); 65 } 66 break; 67 case SDL_PROPERTY_TYPE_STRING: 68 SDL_free(property->value.string_value); 69 break; 70 default: 71 break; 72 } 73 SDL_free(property->string_storage); 74 } 75 SDL_free((void *)key); 76 SDL_free((void *)value); 77} 78 79static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *value) 80{ 81 SDL_FreePropertyWithCleanup(key, value, data, true); 82} 83 84static void SDL_FreeProperties(SDL_Properties *properties) 85{ 86 if (properties) { 87 SDL_DestroyHashTable(properties->props); 88 SDL_DestroyMutex(properties->lock); 89 SDL_free(properties); 90 } 91} 92 93bool SDL_InitProperties(void) 94{ 95 if (!SDL_ShouldInit(&SDL_properties_init)) { 96 return true; 97 } 98 99 SDL_properties = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, NULL, NULL); 100 const bool initialized = (SDL_properties != NULL); 101 SDL_SetInitialized(&SDL_properties_init, initialized); 102 return initialized; 103} 104 105static bool SDLCALL FreeOneProperties(void *userdata, const SDL_HashTable *table, const void *key, const void *value) 106{ 107 SDL_FreeProperties((SDL_Properties *)value); 108 return true; // keep iterating. 109} 110 111void SDL_QuitProperties(void) 112{ 113 if (!SDL_ShouldQuit(&SDL_properties_init)) { 114 return; 115 } 116 117 SDL_PropertiesID props; 118 do { 119 props = SDL_GetAtomicU32(&SDL_global_properties); 120 } while (!SDL_CompareAndSwapAtomicU32(&SDL_global_properties, props, 0)); 121 122 if (props) { 123 SDL_DestroyProperties(props); 124 } 125 126 // this can't just DestroyHashTable with SDL_FreeProperties as the destructor, because 127 // other destructors under this might cause use to attempt a recursive lock on SDL_properties, 128 // which isn't allowed with rwlocks. So manually iterate and free everything. 129 SDL_HashTable *properties = SDL_properties; 130 SDL_properties = NULL; 131 SDL_IterateHashTable(properties, FreeOneProperties, NULL); 132 SDL_DestroyHashTable(properties); 133 134 SDL_SetInitialized(&SDL_properties_init, false); 135} 136 137static bool SDL_CheckInitProperties(void) 138{ 139 return SDL_InitProperties(); 140} 141 142SDL_PropertiesID SDL_GetGlobalProperties(void) 143{ 144 SDL_PropertiesID props = SDL_GetAtomicU32(&SDL_global_properties); 145 if (!props) { 146 props = SDL_CreateProperties(); 147 if (!SDL_CompareAndSwapAtomicU32(&SDL_global_properties, 0, props)) { 148 // Somebody else created global properties before us, just use those 149 SDL_DestroyProperties(props); 150 props = SDL_GetAtomicU32(&SDL_global_properties); 151 } 152 } 153 return props; 154} 155 156SDL_PropertiesID SDL_CreateProperties(void) 157{ 158 if (!SDL_CheckInitProperties()) { 159 return 0; 160 } 161 162 SDL_Properties *properties = (SDL_Properties *)SDL_calloc(1, sizeof(*properties)); 163 if (!properties) { 164 return 0; 165 } 166 167 properties->lock = SDL_CreateMutex(); 168 if (!properties->lock) { 169 SDL_free(properties); 170 return 0; 171 } 172 173 properties->props = SDL_CreateHashTable(0, false, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, NULL); 174 if (!properties->props) { 175 SDL_DestroyMutex(properties->lock); 176 SDL_free(properties); 177 return 0; 178 } 179 180 SDL_PropertiesID props = 0; 181 while (true) { 182 props = (SDL_GetAtomicU32(&SDL_last_properties_id) + 1); 183 if (props == 0) { 184 continue; 185 } else if (SDL_CompareAndSwapAtomicU32(&SDL_last_properties_id, props - 1, props)) { 186 break; 187 } 188 } 189 190 SDL_assert(!SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, NULL)); // should NOT be in the hash table already. 191 192 if (!SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties, false)) { 193 SDL_FreeProperties(properties); 194 return 0; 195 } 196 197 return props; // All done! 198} 199 200typedef struct CopyOnePropertyData 201{ 202 SDL_Properties *dst_properties; 203 bool result; 204} CopyOnePropertyData; 205 206static bool SDLCALL CopyOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value) 207{ 208 const SDL_Property *src_property = (const SDL_Property *)value; 209 if (src_property->cleanup) { 210 // Can't copy properties with cleanup functions, we don't know how to duplicate the data 211 return true; // keep iterating. 212 } 213 214 CopyOnePropertyData *data = (CopyOnePropertyData *) userdata; 215 SDL_Properties *dst_properties = data->dst_properties; 216 const char *src_name = (const char *)key; 217 SDL_Property *dst_property; 218 219 char *dst_name = SDL_strdup(src_name); 220 if (!dst_name) { 221 data->result = false; 222 return true; // keep iterating (I guess...?) 223 } 224 225 dst_property = (SDL_Property *)SDL_malloc(sizeof(*dst_property)); 226 if (!dst_property) { 227 SDL_free(dst_name); 228 data->result = false; 229 return true; // keep iterating (I guess...?) 230 } 231 232 SDL_copyp(dst_property, src_property); 233 if (src_property->type == SDL_PROPERTY_TYPE_STRING) { 234 dst_property->value.string_value = SDL_strdup(src_property->value.string_value); 235 if (!dst_property->value.string_value) { 236 SDL_free(dst_name); 237 SDL_free(dst_property); 238 data->result = false; 239 return true; // keep iterating (I guess...?) 240 } 241 } 242 243 if (!SDL_InsertIntoHashTable(dst_properties->props, dst_name, dst_property, true)) { 244 SDL_FreePropertyWithCleanup(dst_name, dst_property, NULL, false); 245 data->result = false; 246 } 247 248 return true; // keep iterating. 249} 250 251bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst) 252{ 253 CHECK_PARAM(!src) { 254 return SDL_InvalidParamError("src"); 255 } 256 CHECK_PARAM(!dst) { 257 return SDL_InvalidParamError("dst"); 258 } 259 260 SDL_Properties *src_properties = NULL; 261 SDL_Properties *dst_properties = NULL; 262 263 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)src, (const void **)&src_properties); 264 CHECK_PARAM(!src_properties) { 265 return SDL_InvalidParamError("src"); 266 } 267 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties); 268 CHECK_PARAM(!dst_properties) { 269 return SDL_InvalidParamError("dst"); 270 } 271 272 bool result = true; 273 SDL_LockMutex(src_properties->lock); 274 SDL_LockMutex(dst_properties->lock); 275 { 276 CopyOnePropertyData data = { dst_properties, true }; 277 SDL_IterateHashTable(src_properties->props, CopyOneProperty, &data); 278 result = data.result; 279 } 280 SDL_UnlockMutex(dst_properties->lock); 281 SDL_UnlockMutex(src_properties->lock); 282 283 return result; 284} 285 286bool SDL_LockProperties(SDL_PropertiesID props) 287{ 288 SDL_Properties *properties = NULL; 289 290 CHECK_PARAM(!props) { 291 return SDL_InvalidParamError("props"); 292 } 293 294 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 295 CHECK_PARAM(!properties) { 296 return SDL_InvalidParamError("props"); 297 } 298 299 SDL_LockMutex(properties->lock); 300 return true; 301} 302 303void SDL_UnlockProperties(SDL_PropertiesID props) 304{ 305 SDL_Properties *properties = NULL; 306 307 if (!props) { 308 return; 309 } 310 311 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 312 if (!properties) { 313 return; 314 } 315 316 SDL_UnlockMutex(properties->lock); 317} 318 319static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL_Property *property) 320{ 321 SDL_Properties *properties = NULL; 322 bool result = true; 323 324 CHECK_PARAM(!props) { 325 SDL_FreePropertyWithCleanup(NULL, property, NULL, true); 326 return SDL_InvalidParamError("props"); 327 } 328 CHECK_PARAM(!name || !*name) { 329 SDL_FreePropertyWithCleanup(NULL, property, NULL, true); 330 return SDL_InvalidParamError("name"); 331 } 332 333 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 334 CHECK_PARAM(!properties) { 335 SDL_FreePropertyWithCleanup(NULL, property, NULL, true); 336 return SDL_InvalidParamError("props"); 337 } 338 339 SDL_LockMutex(properties->lock); 340 { 341 SDL_RemoveFromHashTable(properties->props, name); 342 if (property) { 343 char *key = SDL_strdup(name); 344 if (!key || !SDL_InsertIntoHashTable(properties->props, key, property, false)) { 345 SDL_FreePropertyWithCleanup(key, property, NULL, true); 346 result = false; 347 } 348 } 349 } 350 SDL_UnlockMutex(properties->lock); 351 352 return result; 353} 354 355bool SDL_SetPointerPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, SDL_CleanupPropertyCallback cleanup, void *userdata) 356{ 357 SDL_Property *property; 358 359 if (!value) { 360 if (cleanup) { 361 cleanup(userdata, value); 362 } 363 return SDL_ClearProperty(props, name); 364 } 365 366 property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 367 if (!property) { 368 if (cleanup) { 369 cleanup(userdata, value); 370 } 371 SDL_FreePropertyWithCleanup(NULL, property, NULL, false); 372 return false; 373 } 374 property->type = SDL_PROPERTY_TYPE_POINTER; 375 property->value.pointer_value = value; 376 property->cleanup = cleanup; 377 property->userdata = userdata; 378 return SDL_PrivateSetProperty(props, name, property); 379} 380 381bool SDL_SetPointerProperty(SDL_PropertiesID props, const char *name, void *value) 382{ 383 SDL_Property *property; 384 385 if (!value) { 386 return SDL_ClearProperty(props, name); 387 } 388 389 property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 390 if (!property) { 391 return false; 392 } 393 property->type = SDL_PROPERTY_TYPE_POINTER; 394 property->value.pointer_value = value; 395 return SDL_PrivateSetProperty(props, name, property); 396} 397 398static void SDLCALL CleanupFreeableProperty(void *userdata, void *value) 399{ 400 SDL_free(value); 401} 402 403bool SDL_SetFreeableProperty(SDL_PropertiesID props, const char *name, void *value) 404{ 405 return SDL_SetPointerPropertyWithCleanup(props, name, value, CleanupFreeableProperty, NULL); 406} 407 408static void SDLCALL CleanupSurface(void *userdata, void *value) 409{ 410 SDL_Surface *surface = (SDL_Surface *)value; 411 412 SDL_DestroySurface(surface); 413} 414 415bool SDL_SetSurfaceProperty(SDL_PropertiesID props, const char *name, SDL_Surface *surface) 416{ 417 return SDL_SetPointerPropertyWithCleanup(props, name, surface, CleanupSurface, NULL); 418} 419 420bool SDL_SetStringProperty(SDL_PropertiesID props, const char *name, const char *value) 421{ 422 SDL_Property *property; 423 424 if (!value) { 425 return SDL_ClearProperty(props, name); 426 } 427 428 property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 429 if (!property) { 430 return false; 431 } 432 property->type = SDL_PROPERTY_TYPE_STRING; 433 property->value.string_value = SDL_strdup(value); 434 if (!property->value.string_value) { 435 SDL_free(property); 436 return false; 437 } 438 return SDL_PrivateSetProperty(props, name, property); 439} 440 441bool SDL_SetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 value) 442{ 443 SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 444 if (!property) { 445 return false; 446 } 447 property->type = SDL_PROPERTY_TYPE_NUMBER; 448 property->value.number_value = value; 449 return SDL_PrivateSetProperty(props, name, property); 450} 451 452bool SDL_SetFloatProperty(SDL_PropertiesID props, const char *name, float value) 453{ 454 SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 455 if (!property) { 456 return false; 457 } 458 property->type = SDL_PROPERTY_TYPE_FLOAT; 459 property->value.float_value = value; 460 return SDL_PrivateSetProperty(props, name, property); 461} 462 463bool SDL_SetBooleanProperty(SDL_PropertiesID props, const char *name, bool value) 464{ 465 SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property)); 466 if (!property) { 467 return false; 468 } 469 property->type = SDL_PROPERTY_TYPE_BOOLEAN; 470 property->value.boolean_value = value ? true : false; 471 return SDL_PrivateSetProperty(props, name, property); 472} 473 474bool SDL_HasProperty(SDL_PropertiesID props, const char *name) 475{ 476 return (SDL_GetPropertyType(props, name) != SDL_PROPERTY_TYPE_INVALID); 477} 478 479SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name) 480{ 481 SDL_Properties *properties = NULL; 482 SDL_PropertyType type = SDL_PROPERTY_TYPE_INVALID; 483 484 if (!props) { 485 return SDL_PROPERTY_TYPE_INVALID; 486 } 487 if (!name || !*name) { 488 return SDL_PROPERTY_TYPE_INVALID; 489 } 490 491 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 492 if (!properties) { 493 return SDL_PROPERTY_TYPE_INVALID; 494 } 495 496 SDL_LockMutex(properties->lock); 497 { 498 SDL_Property *property = NULL; 499 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 500 type = property->type; 501 } 502 } 503 SDL_UnlockMutex(properties->lock); 504 505 return type; 506} 507 508void *SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *default_value) 509{ 510 SDL_Properties *properties = NULL; 511 void *value = default_value; 512 513 if (!props) { 514 return value; 515 } 516 if (!name || !*name) { 517 return value; 518 } 519 520 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 521 if (!properties) { 522 return value; 523 } 524 525 // Note that taking the lock here only guarantees that we won't read the 526 // hashtable while it's being modified. The value itself can easily be 527 // freed from another thread after it is returned here. 528 SDL_LockMutex(properties->lock); 529 { 530 SDL_Property *property = NULL; 531 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 532 if (property->type == SDL_PROPERTY_TYPE_POINTER) { 533 value = property->value.pointer_value; 534 } 535 } 536 } 537 SDL_UnlockMutex(properties->lock); 538 539 return value; 540} 541 542const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, const char *default_value) 543{ 544 SDL_Properties *properties = NULL; 545 const char *value = default_value; 546 547 if (!props) { 548 return value; 549 } 550 if (!name || !*name) { 551 return value; 552 } 553 554 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 555 if (!properties) { 556 return value; 557 } 558 559 SDL_LockMutex(properties->lock); 560 { 561 SDL_Property *property = NULL; 562 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 563 switch (property->type) { 564 case SDL_PROPERTY_TYPE_STRING: 565 value = property->value.string_value; 566 break; 567 case SDL_PROPERTY_TYPE_NUMBER: 568 if (property->string_storage) { 569 value = property->string_storage; 570 } else { 571 SDL_asprintf(&property->string_storage, "%" SDL_PRIs64, property->value.number_value); 572 if (property->string_storage) { 573 value = property->string_storage; 574 } 575 } 576 break; 577 case SDL_PROPERTY_TYPE_FLOAT: 578 if (property->string_storage) { 579 value = property->string_storage; 580 } else { 581 SDL_asprintf(&property->string_storage, "%f", property->value.float_value); 582 if (property->string_storage) { 583 value = property->string_storage; 584 } 585 } 586 break; 587 case SDL_PROPERTY_TYPE_BOOLEAN: 588 value = property->value.boolean_value ? "true" : "false"; 589 break; 590 default: 591 break; 592 } 593 } 594 } 595 SDL_UnlockMutex(properties->lock); 596 597 return value; 598} 599 600Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 default_value) 601{ 602 SDL_Properties *properties = NULL; 603 Sint64 value = default_value; 604 605 if (!props) { 606 return value; 607 } 608 if (!name || !*name) { 609 return value; 610 } 611 612 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 613 if (!properties) { 614 return value; 615 } 616 617 SDL_LockMutex(properties->lock); 618 { 619 SDL_Property *property = NULL; 620 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 621 switch (property->type) { 622 case SDL_PROPERTY_TYPE_STRING: 623 value = (Sint64)SDL_strtoll(property->value.string_value, NULL, 0); 624 break; 625 case SDL_PROPERTY_TYPE_NUMBER: 626 value = property->value.number_value; 627 break; 628 case SDL_PROPERTY_TYPE_FLOAT: 629 value = (Sint64)SDL_round((double)property->value.float_value); 630 break; 631 case SDL_PROPERTY_TYPE_BOOLEAN: 632 value = property->value.boolean_value; 633 break; 634 default: 635 break; 636 } 637 } 638 } 639 SDL_UnlockMutex(properties->lock); 640 641 return value; 642} 643 644float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float default_value) 645{ 646 SDL_Properties *properties = NULL; 647 float value = default_value; 648 649 if (!props) { 650 return value; 651 } 652 if (!name || !*name) { 653 return value; 654 } 655 656 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 657 if (!properties) { 658 return value; 659 } 660 661 SDL_LockMutex(properties->lock); 662 { 663 SDL_Property *property = NULL; 664 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 665 switch (property->type) { 666 case SDL_PROPERTY_TYPE_STRING: 667 value = (float)SDL_atof(property->value.string_value); 668 break; 669 case SDL_PROPERTY_TYPE_NUMBER: 670 value = (float)property->value.number_value; 671 break; 672 case SDL_PROPERTY_TYPE_FLOAT: 673 value = property->value.float_value; 674 break; 675 case SDL_PROPERTY_TYPE_BOOLEAN: 676 value = (float)property->value.boolean_value; 677 break; 678 default: 679 break; 680 } 681 } 682 } 683 SDL_UnlockMutex(properties->lock); 684 685 return value; 686} 687 688bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, bool default_value) 689{ 690 SDL_Properties *properties = NULL; 691 bool value = default_value ? true : false; 692 693 if (!props) { 694 return value; 695 } 696 if (!name || !*name) { 697 return value; 698 } 699 700 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 701 if (!properties) { 702 return value; 703 } 704 705 SDL_LockMutex(properties->lock); 706 { 707 SDL_Property *property = NULL; 708 if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) { 709 switch (property->type) { 710 case SDL_PROPERTY_TYPE_STRING: 711 value = SDL_GetStringBoolean(property->value.string_value, default_value); 712 break; 713 case SDL_PROPERTY_TYPE_NUMBER: 714 value = (property->value.number_value != 0); 715 break; 716 case SDL_PROPERTY_TYPE_FLOAT: 717 value = (property->value.float_value != 0.0f); 718 break; 719 case SDL_PROPERTY_TYPE_BOOLEAN: 720 value = property->value.boolean_value; 721 break; 722 default: 723 break; 724 } 725 } 726 } 727 SDL_UnlockMutex(properties->lock); 728 729 return value; 730} 731 732bool SDL_ClearProperty(SDL_PropertiesID props, const char *name) 733{ 734 return SDL_PrivateSetProperty(props, name, NULL); 735} 736 737typedef struct EnumerateOnePropertyData 738{ 739 SDL_EnumeratePropertiesCallback callback; 740 void *userdata; 741 SDL_PropertiesID props; 742} EnumerateOnePropertyData; 743 744 745static bool SDLCALL EnumerateOneProperty(void *userdata, const SDL_HashTable *table, const void *key, const void *value) 746{ 747 (void) table; 748 (void) value; 749 const EnumerateOnePropertyData *data = (const EnumerateOnePropertyData *) userdata; 750 data->callback(data->userdata, data->props, (const char *)key); 751 return true; // keep iterating. 752} 753 754bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata) 755{ 756 SDL_Properties *properties = NULL; 757 758 CHECK_PARAM(!props) { 759 return SDL_InvalidParamError("props"); 760 } 761 CHECK_PARAM(!callback) { 762 return SDL_InvalidParamError("callback"); 763 } 764 765 SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties); 766 CHECK_PARAM(!properties) { 767 return SDL_InvalidParamError("props"); 768 } 769 770 SDL_LockMutex(properties->lock); 771 { 772 EnumerateOnePropertyData data = { callback, userdata, props }; 773 SDL_IterateHashTable(properties->props, EnumerateOneProperty, &data); 774 } 775 SDL_UnlockMutex(properties->lock); 776 777 return true; 778} 779 780static void SDLCALL SDL_DumpPropertiesCallback(void *userdata, SDL_PropertiesID props, const char *name) 781{ 782 switch (SDL_GetPropertyType(props, name)) { 783 case SDL_PROPERTY_TYPE_POINTER: 784 SDL_Log("%s: %p", name, SDL_GetPointerProperty(props, name, NULL)); 785 break; 786 case SDL_PROPERTY_TYPE_STRING: 787 SDL_Log("%s: \"%s\"", name, SDL_GetStringProperty(props, name, "")); 788 break; 789 case SDL_PROPERTY_TYPE_NUMBER: 790 { 791 Sint64 value = SDL_GetNumberProperty(props, name, 0); 792 SDL_Log("%s: %" SDL_PRIs64 " (%" SDL_PRIx64 ")", name, value, value); 793 } 794 break; 795 case SDL_PROPERTY_TYPE_FLOAT: 796 SDL_Log("%s: %g", name, SDL_GetFloatProperty(props, name, 0.0f)); 797 break; 798 case SDL_PROPERTY_TYPE_BOOLEAN: 799 SDL_Log("%s: %s", name, SDL_GetBooleanProperty(props, name, false) ? "true" : "false"); 800 break; 801 default: 802 SDL_Log("%s UNKNOWN TYPE", name); 803 break; 804 } 805} 806 807bool SDL_DumpProperties(SDL_PropertiesID props) 808{ 809 return SDL_EnumerateProperties(props, SDL_DumpPropertiesCallback, NULL); 810} 811 812void SDL_DestroyProperties(SDL_PropertiesID props) 813{ 814 if (props) { 815 // this can't just use RemoveFromHashTable with SDL_FreeProperties as the destructor, because 816 // other destructors under this might cause use to attempt a recursive lock on SDL_properties, 817 // which isn't allowed with rwlocks. So manually look it up and remove/free it. 818 SDL_Properties *properties = NULL; 819 if (SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties)) { 820 SDL_FreeProperties(properties); 821 SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props); 822 } 823 } 824} 825[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.