Atlas - SDL_hints.c
Home / ext / SDL / src Lines: 1 | Size: 11842 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 25#ifdef SDL_PLATFORM_ANDROID 26#include "core/android/SDL_android.h" 27#endif 28 29typedef struct SDL_HintWatch 30{ 31 SDL_HintCallback callback; 32 void *userdata; 33 struct SDL_HintWatch *next; 34} SDL_HintWatch; 35 36typedef struct SDL_Hint 37{ 38 char *value; 39 SDL_HintPriority priority; 40 SDL_HintWatch *callbacks; 41} SDL_Hint; 42 43static SDL_AtomicU32 SDL_hint_props; 44 45 46void SDL_InitHints(void) 47{ 48} 49 50void SDL_QuitHints(void) 51{ 52 SDL_PropertiesID props; 53 do { 54 props = SDL_GetAtomicU32(&SDL_hint_props); 55 } while (!SDL_CompareAndSwapAtomicU32(&SDL_hint_props, props, 0)); 56 57 if (props) { 58 SDL_DestroyProperties(props); 59 } 60} 61 62static SDL_PropertiesID GetHintProperties(bool create) 63{ 64 SDL_PropertiesID props = SDL_GetAtomicU32(&SDL_hint_props); 65 if (!props && create) { 66 props = SDL_CreateProperties(); 67 if (!SDL_CompareAndSwapAtomicU32(&SDL_hint_props, 0, props)) { 68 // Somebody else created hint properties before us, just use those 69 SDL_DestroyProperties(props); 70 props = SDL_GetAtomicU32(&SDL_hint_props); 71 } 72 } 73 return props; 74} 75 76static void SDLCALL CleanupHintProperty(void *userdata, void *value) 77{ 78 SDL_Hint *hint = (SDL_Hint *) value; 79 SDL_free(hint->value); 80 81 SDL_HintWatch *entry = hint->callbacks; 82 while (entry) { 83 SDL_HintWatch *freeable = entry; 84 entry = entry->next; 85 SDL_free(freeable); 86 } 87 SDL_free(hint); 88} 89 90static const char *GetHintEnvironmentVariable(const char *name) 91{ 92 const char *result = SDL_getenv(name); 93 if (!result && name && *name) { 94 // fall back to old (SDL2) names of environment variables that 95 // are important to users (e.g. many use SDL_VIDEODRIVER=wayland) 96 if (SDL_strcmp(name, SDL_HINT_VIDEO_DRIVER) == 0) { 97 result = SDL_getenv("SDL_VIDEODRIVER"); 98 } else if (SDL_strcmp(name, SDL_HINT_AUDIO_DRIVER) == 0) { 99 result = SDL_getenv("SDL_AUDIODRIVER"); 100 } 101 } 102 return result; 103} 104 105bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriority priority) 106{ 107 CHECK_PARAM(!name || !*name) { 108 return SDL_InvalidParamError("name"); 109 } 110 111 const char *env = GetHintEnvironmentVariable(name); 112 if (env && (priority < SDL_HINT_OVERRIDE)) { 113 return SDL_SetError("An environment variable is taking priority"); 114 } 115 116 const SDL_PropertiesID hints = GetHintProperties(true); 117 if (!hints) { 118 return false; 119 } 120 121 bool result = false; 122 123 SDL_LockProperties(hints); 124 125 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 126 if (hint) { 127 if (priority >= hint->priority) { 128 if (hint->value != value && (!value || !hint->value || SDL_strcmp(hint->value, value) != 0)) { 129 char *old_value = hint->value; 130 131 hint->value = value ? SDL_strdup(value) : NULL; 132 SDL_HintWatch *entry = hint->callbacks; 133 while (entry) { 134 // Save the next entry in case this one is deleted 135 SDL_HintWatch *next = entry->next; 136 entry->callback(entry->userdata, name, old_value, value); 137 entry = next; 138 } 139 SDL_free(old_value); 140 } 141 hint->priority = priority; 142 result = true; 143 } 144 } else { // Couldn't find the hint? Add a new one. 145 hint = (SDL_Hint *)SDL_malloc(sizeof(*hint)); 146 if (hint) { 147 hint->value = value ? SDL_strdup(value) : NULL; 148 hint->priority = priority; 149 hint->callbacks = NULL; 150 result = SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL); 151 } 152 } 153 154#ifdef SDL_PLATFORM_ANDROID 155 if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) { 156 // Special handling for this hint, which needs to persist outside the normal application flow 157 Android_SetAllowRecreateActivity(SDL_GetStringBoolean(value, false)); 158 } 159#endif // SDL_PLATFORM_ANDROID 160 161 SDL_UnlockProperties(hints); 162 163 return result; 164} 165 166bool SDL_ResetHint(const char *name) 167{ 168 CHECK_PARAM(!name || !*name) { 169 return SDL_InvalidParamError("name"); 170 } 171 172 const char *env = GetHintEnvironmentVariable(name); 173 174 const SDL_PropertiesID hints = GetHintProperties(false); 175 if (!hints) { 176 return false; 177 } 178 179 bool result = false; 180 181 SDL_LockProperties(hints); 182 183 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 184 if (hint) { 185 if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) { 186 for (SDL_HintWatch *entry = hint->callbacks; entry;) { 187 // Save the next entry in case this one is deleted 188 SDL_HintWatch *next = entry->next; 189 entry->callback(entry->userdata, name, hint->value, env); 190 entry = next; 191 } 192 } 193 SDL_free(hint->value); 194 hint->value = NULL; 195 hint->priority = SDL_HINT_DEFAULT; 196 result = true; 197 } 198 199#ifdef SDL_PLATFORM_ANDROID 200 if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) { 201 // Special handling for this hint, which needs to persist outside the normal application flow 202 if (env) { 203 Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false)); 204 } else { 205 Android_SetAllowRecreateActivity(false); 206 } 207 } 208#endif // SDL_PLATFORM_ANDROID 209 210 SDL_UnlockProperties(hints); 211 212 return result; 213} 214 215static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, const char *name) 216{ 217 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 218 if (!hint) { 219 return; // uh...okay. 220 } 221 222 const char *env = GetHintEnvironmentVariable(name); 223 if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) { 224 SDL_HintWatch *entry = hint->callbacks; 225 while (entry) { 226 // Save the next entry in case this one is deleted 227 SDL_HintWatch *next = entry->next; 228 entry->callback(entry->userdata, name, hint->value, env); 229 entry = next; 230 } 231 } 232 SDL_free(hint->value); 233 hint->value = NULL; 234 hint->priority = SDL_HINT_DEFAULT; 235 236#ifdef SDL_PLATFORM_ANDROID 237 if (SDL_strcmp(name, SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY) == 0) { 238 // Special handling for this hint, which needs to persist outside the normal application flow 239 if (env) { 240 Android_SetAllowRecreateActivity(SDL_GetStringBoolean(env, false)); 241 } else { 242 Android_SetAllowRecreateActivity(false); 243 } 244 } 245#endif // SDL_PLATFORM_ANDROID 246} 247 248void SDL_ResetHints(void) 249{ 250 SDL_EnumerateProperties(GetHintProperties(false), ResetHintsCallback, NULL); 251} 252 253bool SDL_SetHint(const char *name, const char *value) 254{ 255 return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL); 256} 257 258const char *SDL_GetHint(const char *name) 259{ 260 if (!name) { 261 return NULL; 262 } 263 264 const char *result = GetHintEnvironmentVariable(name); 265 266 const SDL_PropertiesID hints = GetHintProperties(false); 267 if (hints) { 268 SDL_LockProperties(hints); 269 270 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 271 if (hint) { 272 if (!result || hint->priority == SDL_HINT_OVERRIDE) { 273 result = SDL_GetPersistentString(hint->value); 274 } 275 } 276 277 SDL_UnlockProperties(hints); 278 } 279 280 return result; 281} 282 283int SDL_GetStringInteger(const char *value, int default_value) 284{ 285 if (!value || !*value) { 286 return default_value; 287 } 288 if (SDL_strcasecmp(value, "false") == 0) { 289 return 0; 290 } 291 if (SDL_strcasecmp(value, "true") == 0) { 292 return 1; 293 } 294 if (*value == '-' || SDL_isdigit(*value)) { 295 return SDL_atoi(value); 296 } 297 return default_value; 298} 299 300bool SDL_GetStringBoolean(const char *value, bool default_value) 301{ 302 if (!value || !*value) { 303 return default_value; 304 } 305 if (*value == '0' || SDL_strcasecmp(value, "false") == 0) { 306 return false; 307 } 308 return true; 309} 310 311bool SDL_GetHintBoolean(const char *name, bool default_value) 312{ 313 const char *hint = SDL_GetHint(name); 314 return SDL_GetStringBoolean(hint, default_value); 315} 316 317bool SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) 318{ 319 CHECK_PARAM(!name || !*name) { 320 return SDL_InvalidParamError("name"); 321 } 322 CHECK_PARAM(!callback) { 323 return SDL_InvalidParamError("callback"); 324 } 325 326 const SDL_PropertiesID hints = GetHintProperties(true); 327 if (!hints) { 328 return false; 329 } 330 331 SDL_HintWatch *entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry)); 332 if (!entry) { 333 return false; 334 } 335 entry->callback = callback; 336 entry->userdata = userdata; 337 338 bool result = false; 339 340 SDL_LockProperties(hints); 341 342 SDL_RemoveHintCallback(name, callback, userdata); 343 344 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 345 if (hint) { 346 result = true; 347 } else { // Need to add a hint entry for this watcher 348 hint = (SDL_Hint *)SDL_malloc(sizeof(*hint)); 349 if (!hint) { 350 SDL_free(entry); 351 SDL_UnlockProperties(hints); 352 return false; 353 } else { 354 hint->value = NULL; 355 hint->priority = SDL_HINT_DEFAULT; 356 hint->callbacks = NULL; 357 result = SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL); 358 } 359 } 360 361 // Add it to the callbacks for this hint 362 entry->next = hint->callbacks; 363 hint->callbacks = entry; 364 365 // Now call it with the current value 366 const char *value = SDL_GetHint(name); 367 callback(userdata, name, value, value); 368 369 SDL_UnlockProperties(hints); 370 371 return result; 372} 373 374void SDL_RemoveHintCallback(const char *name, SDL_HintCallback callback, void *userdata) 375{ 376 if (!name || !*name) { 377 return; 378 } 379 380 const SDL_PropertiesID hints = GetHintProperties(false); 381 if (!hints) { 382 return; 383 } 384 385 SDL_LockProperties(hints); 386 SDL_Hint *hint = (SDL_Hint *)SDL_GetPointerProperty(hints, name, NULL); 387 if (hint) { 388 SDL_HintWatch *prev = NULL; 389 for (SDL_HintWatch *entry = hint->callbacks; entry; entry = entry->next) { 390 if ((callback == entry->callback) && (userdata == entry->userdata)) { 391 if (prev) { 392 prev->next = entry->next; 393 } else { 394 hint->callbacks = entry->next; 395 } 396 SDL_free(entry); 397 break; 398 } 399 prev = entry; 400 } 401 } 402 SDL_UnlockProperties(hints); 403} 404 405[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.