Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/SDL_properties.c
9896 views
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
27
typedef 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
45
typedef struct
46
{
47
SDL_HashTable *props;
48
SDL_Mutex *lock;
49
} SDL_Properties;
50
51
static SDL_InitState SDL_properties_init;
52
static SDL_HashTable *SDL_properties;
53
static SDL_AtomicU32 SDL_last_properties_id;
54
static SDL_AtomicU32 SDL_global_properties;
55
56
57
static 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
79
static void SDLCALL SDL_FreeProperty(void *data, const void *key, const void *value)
80
{
81
SDL_FreePropertyWithCleanup(key, value, data, true);
82
}
83
84
static 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
93
bool 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
105
static 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
111
void 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
137
static bool SDL_CheckInitProperties(void)
138
{
139
return SDL_InitProperties();
140
}
141
142
SDL_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
156
SDL_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
200
typedef struct CopyOnePropertyData
201
{
202
SDL_Properties *dst_properties;
203
bool result;
204
} CopyOnePropertyData;
205
206
static 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
251
bool SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst)
252
{
253
if (!src) {
254
return SDL_InvalidParamError("src");
255
}
256
if (!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
if (!src_properties) {
265
return SDL_InvalidParamError("src");
266
}
267
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)dst, (const void **)&dst_properties);
268
if (!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
286
bool SDL_LockProperties(SDL_PropertiesID props)
287
{
288
SDL_Properties *properties = NULL;
289
290
if (!props) {
291
return SDL_InvalidParamError("props");
292
}
293
294
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
295
if (!properties) {
296
return SDL_InvalidParamError("props");
297
}
298
299
SDL_LockMutex(properties->lock);
300
return true;
301
}
302
303
void 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
319
static bool SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL_Property *property)
320
{
321
SDL_Properties *properties = NULL;
322
bool result = true;
323
324
if (!props) {
325
SDL_FreePropertyWithCleanup(NULL, property, NULL, true);
326
return SDL_InvalidParamError("props");
327
}
328
if (!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
if (!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
355
bool 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
381
bool 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
398
static void SDLCALL CleanupFreeableProperty(void *userdata, void *value)
399
{
400
SDL_free(value);
401
}
402
403
bool SDL_SetFreeableProperty(SDL_PropertiesID props, const char *name, void *value)
404
{
405
return SDL_SetPointerPropertyWithCleanup(props, name, value, CleanupFreeableProperty, NULL);
406
}
407
408
static void SDLCALL CleanupSurface(void *userdata, void *value)
409
{
410
SDL_Surface *surface = (SDL_Surface *)value;
411
412
//SDL_DestroySurface(surface);
413
}
414
415
bool SDL_SetSurfaceProperty(SDL_PropertiesID props, const char *name, SDL_Surface *surface)
416
{
417
return SDL_SetPointerPropertyWithCleanup(props, name, surface, CleanupSurface, NULL);
418
}
419
420
bool 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
441
bool 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
452
bool 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
463
bool 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
474
bool SDL_HasProperty(SDL_PropertiesID props, const char *name)
475
{
476
return (SDL_GetPropertyType(props, name) != SDL_PROPERTY_TYPE_INVALID);
477
}
478
479
SDL_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
508
void *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
542
const 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
600
Sint64 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
644
float 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
688
bool 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
732
bool SDL_ClearProperty(SDL_PropertiesID props, const char *name)
733
{
734
return SDL_PrivateSetProperty(props, name, NULL);
735
}
736
737
typedef struct EnumerateOnePropertyData
738
{
739
SDL_EnumeratePropertiesCallback callback;
740
void *userdata;
741
SDL_PropertiesID props;
742
} EnumerateOnePropertyData;
743
744
745
static 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
754
bool SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata)
755
{
756
SDL_Properties *properties = NULL;
757
758
if (!props) {
759
return SDL_InvalidParamError("props");
760
}
761
if (!callback) {
762
return SDL_InvalidParamError("callback");
763
}
764
765
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
766
if (!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
780
static 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
807
bool SDL_DumpProperties(SDL_PropertiesID props)
808
{
809
return SDL_EnumerateProperties(props, SDL_DumpPropertiesCallback, NULL);
810
}
811
812
void 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
826