mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-10-26 12:27:44 +00:00 
			
		
		
		
	hints: Change hints to be backed by Properties, add documentation. (#9892)
This makes the subsystem thread-safe, more performant, and cleans up the code a little. Also removed SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS, since setting this hint programmatically initializes properties, which creates a lock, so we can't check hints while creating locks. The slim reader-writer locks have been the default for ages and are solid, so we'll just use those when available.
This commit is contained in:
		| @@ -755,6 +755,8 @@ SDL_AddHintCallback() now returns a standard int result instead of void, returni | ||||
|  | ||||
| Calling SDL_GetHint() with the name of the hint being changed from within a hint callback will now return the new value rather than the old value. The old value is still passed as a parameter to the hint callback. | ||||
|  | ||||
| SDL_SetHint, SDL_SetHintWithPriority, and SDL_ResetHint now return int (-1 on error, 0 on success) instead of SDL_bool (SDL_FALSE on error, SDL_TRUE on success). | ||||
|  | ||||
| The environment variables SDL_VIDEODRIVER and SDL_AUDIODRIVER have been renamed to SDL_VIDEO_DRIVER and SDL_AUDIO_DRIVER. | ||||
|  | ||||
| The environment variables SDL_VIDEO_X11_WMCLASS and SDL_VIDEO_WAYLAND_WMCLASS have been removed and replaced by either using the appindentifier param to SDL_SetAppMetadata() or setting SDL_PROP_APP_METADATA_IDENTIFIER_STRING with SDL_SetAppMetadataProperty() | ||||
| @@ -799,6 +801,7 @@ The following hints have been removed: | ||||
| * SDL_HINT_VIDEO_X11_XINERAMA - Xinerama no longer supported by the X11 backend | ||||
| * SDL_HINT_VIDEO_X11_XVIDMODE - Xvidmode no longer supported by the X11 backend | ||||
| * SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING - SDL now properly handles the 0x406D1388 Exception if no debugger intercepts it, preventing its propagation. | ||||
| * SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS - Slim Reader/Writer Locks are always used if available | ||||
| * SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 - replaced with SDL_HINT_WINDOWS_CLOSE_ON_ALT_F4, defaulting to SDL_TRUE | ||||
| * SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING | ||||
| * SDL_HINT_AUDIO_DEVICE_APP_NAME - replaced by either using the appname param to SDL_SetAppMetadata() or setting SDL_PROP_APP_METADATA_NAME_STRING with SDL_SetAppMetadataProperty() | ||||
|   | ||||
| @@ -3837,27 +3837,6 @@ extern "C" { | ||||
|  */ | ||||
| #define SDL_HINT_WINDOWS_RAW_KEYBOARD   "SDL_WINDOWS_RAW_KEYBOARD" | ||||
|  | ||||
| /** | ||||
|  * A variable controlling whether SDL uses Critical Sections for mutexes on | ||||
|  * Windows. | ||||
|  * | ||||
|  * On Windows 7 and newer, Slim Reader/Writer Locks are available. They offer | ||||
|  * better performance, allocate no kernel resources and use less memory. SDL | ||||
|  * will fall back to Critical Sections on older OS versions or if forced to by | ||||
|  * this hint. | ||||
|  * | ||||
|  * The variable can be set to the following values: | ||||
|  * | ||||
|  * - "0": Use SRW Locks when available, otherwise fall back to Critical | ||||
|  *   Sections. (default) | ||||
|  * - "1": Force the use of Critical Sections in all cases. | ||||
|  * | ||||
|  * This hint should be set before SDL is initialized. | ||||
|  * | ||||
|  * \since This hint is available since SDL 3.0.0. | ||||
|  */ | ||||
| #define SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS "SDL_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS" | ||||
|  | ||||
| /** | ||||
|  * A variable controlling whether SDL uses Kernel Semaphores on Windows. | ||||
|  * | ||||
| @@ -4133,7 +4112,10 @@ typedef enum SDL_HintPriority | ||||
|  * \param name the hint to set. | ||||
|  * \param value the value of the hint variable. | ||||
|  * \param priority the SDL_HintPriority level for the hint. | ||||
|  * \returns SDL_TRUE if the hint was set, SDL_FALSE otherwise. | ||||
|  * \returns 0 on success or a negative error code on failure; call | ||||
|  *          SDL_GetError() for more information. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
| @@ -4141,7 +4123,7 @@ typedef enum SDL_HintPriority | ||||
|  * \sa SDL_ResetHint | ||||
|  * \sa SDL_SetHint | ||||
|  */ | ||||
| extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHintWithPriority(const char *name, | ||||
| extern SDL_DECLSPEC int SDLCALL SDL_SetHintWithPriority(const char *name, | ||||
|                                                         const char *value, | ||||
|                                                         SDL_HintPriority priority); | ||||
|  | ||||
| @@ -4154,7 +4136,10 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHintWithPriority(const char *name, | ||||
|  * | ||||
|  * \param name the hint to set. | ||||
|  * \param value the value of the hint variable. | ||||
|  * \returns SDL_TRUE if the hint was set, SDL_FALSE otherwise. | ||||
|  * \returns 0 on success or a negative error code on failure; call | ||||
|  *          SDL_GetError() for more information. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
| @@ -4162,8 +4147,7 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHintWithPriority(const char *name, | ||||
|  * \sa SDL_ResetHint | ||||
|  * \sa SDL_SetHintWithPriority | ||||
|  */ | ||||
| extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name, | ||||
|                                              const char *value); | ||||
| extern SDL_DECLSPEC int SDLCALL SDL_SetHint(const char *name, const char *value); | ||||
|  | ||||
| /** | ||||
|  * Reset a hint to the default value. | ||||
| @@ -4173,14 +4157,17 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name, | ||||
|  * change. | ||||
|  * | ||||
|  * \param name the hint to set. | ||||
|  * \returns SDL_TRUE if the hint was set, SDL_FALSE otherwise. | ||||
|  * \returns 0 on success or a negative error code on failure; call | ||||
|  *          SDL_GetError() for more information. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_SetHint | ||||
|  * \sa SDL_ResetHints | ||||
|  */ | ||||
| extern SDL_DECLSPEC SDL_bool SDLCALL SDL_ResetHint(const char *name); | ||||
| extern SDL_DECLSPEC int SDLCALL SDL_ResetHint(const char *name); | ||||
|  | ||||
| /** | ||||
|  * Reset all hints to the default values. | ||||
| @@ -4189,6 +4176,8 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_ResetHint(const char *name); | ||||
|  * variable, or NULL if the environment isn't set. Callbacks will be called | ||||
|  * normally with this change. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_ResetHint | ||||
| @@ -4201,6 +4190,13 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetHints(void); | ||||
|  * \param name the hint to query. | ||||
|  * \returns the string value of a hint or NULL if the hint isn't set. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread, however | ||||
|  *               the return value only remains valid until the hint is | ||||
|  *               changed; if another thread might do so, the app should | ||||
|  *               supply locks and/or make a copy of the string. Note that | ||||
|  *               using a hint callback instead is always thread-safe, as SDL | ||||
|  *               holds a lock on the thread subsystem during the callback. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_SetHint | ||||
| @@ -4216,6 +4212,8 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); | ||||
|  * \returns the boolean value of a hint or the provided default value if the | ||||
|  *          hint does not exist. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_GetHint | ||||
| @@ -4224,29 +4222,40 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); | ||||
| extern SDL_DECLSPEC SDL_bool SDLCALL SDL_GetHintBoolean(const char *name, SDL_bool default_value); | ||||
|  | ||||
| /** | ||||
|  * Type definition of the hint callback function. | ||||
|  * A callback used to send notifications of hint value changes. | ||||
|  * | ||||
|  * This is called an initial time during SDL_AddHintCallback with the hint's | ||||
|  * current value, and then again each time the hint's value changes. | ||||
|  * | ||||
|  * \param userdata what was passed as `userdata` to SDL_AddHintCallback(). | ||||
|  * \param name what was passed as `name` to SDL_AddHintCallback(). | ||||
|  * \param oldValue the previous hint value. | ||||
|  * \param newValue the new value hint is to be set to. | ||||
|  * | ||||
|  * \threadsafety This callback is fired from whatever thread is setting a | ||||
|  *               new hint value. SDL holds a lock on the hint subsystem when | ||||
|  *               calling this callback. | ||||
|  * | ||||
|  * \since This datatype is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_AddHintCallback | ||||
|  */ | ||||
| typedef void (SDLCALL *SDL_HintCallback)(void *userdata, const char *name, const char *oldValue, const char *newValue); | ||||
|  | ||||
| /** | ||||
|  * Add a function to watch a particular hint. | ||||
|  * | ||||
|  * The callback function is called _during_ this function, to provide it an | ||||
|  * initial value, and again each time the hint's value changes. | ||||
|  * | ||||
|  * \param name the hint to watch. | ||||
|  * \param callback an SDL_HintCallback function that will be called when the | ||||
|  * \param callback An SDL_HintCallback function that will be called when the | ||||
|  *                 hint value changes. | ||||
|  * \param userdata a pointer to pass to the callback function. | ||||
|  * \returns 0 on success or a negative error code on failure; call | ||||
|  *          SDL_GetError() for more information. | ||||
|  * | ||||
|  * \threadsafety It is **NOT** safe to call this function from two threads at | ||||
|  *               once. | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
| @@ -4264,6 +4273,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddHintCallback(const char *name, | ||||
|  *                 hint value changes. | ||||
|  * \param userdata a pointer being passed to the callback function. | ||||
|  * | ||||
|  * \threadsafety It is safe to call this function from any thread. | ||||
|  * | ||||
|  * \since This function is available since SDL 3.0.0. | ||||
|  * | ||||
|  * \sa SDL_AddHintCallback | ||||
|   | ||||
| @@ -255,10 +255,12 @@ void SDL_InitMainThread(void) | ||||
|     SDL_InitLog(); | ||||
|     SDL_InitProperties(); | ||||
|     SDL_GetGlobalProperties(); | ||||
|     SDL_InitHints(); | ||||
| } | ||||
|  | ||||
| static void SDL_QuitMainThread(void) | ||||
| { | ||||
|     SDL_QuitHints(); | ||||
|     SDL_QuitProperties(); | ||||
|     SDL_QuitLog(); | ||||
|     SDL_QuitFilesystem(); | ||||
| @@ -623,7 +625,6 @@ void SDL_Quit(void) | ||||
| #endif | ||||
|  | ||||
|     SDL_SetObjectsInvalid(); | ||||
|     SDL_ClearHints(); | ||||
|     SDL_AssertionsQuit(); | ||||
|  | ||||
|     SDL_QuitPixelFormatDetails(); | ||||
|   | ||||
							
								
								
									
										298
									
								
								src/SDL_hints.c
									
									
									
									
									
								
							
							
						
						
									
										298
									
								
								src/SDL_hints.c
									
									
									
									
									
								
							| @@ -22,9 +22,6 @@ | ||||
|  | ||||
| #include "SDL_hints_c.h" | ||||
|  | ||||
| /* Assuming there aren't many hints set and they aren't being queried in | ||||
|    critical performance paths, we'll just use linked lists here. | ||||
|  */ | ||||
| typedef struct SDL_HintWatch | ||||
| { | ||||
|     SDL_HintCallback callback; | ||||
| @@ -34,42 +31,71 @@ typedef struct SDL_HintWatch | ||||
|  | ||||
| typedef struct SDL_Hint | ||||
| { | ||||
|     char *name; | ||||
|     char *value; | ||||
|     SDL_HintPriority priority; | ||||
|     SDL_HintWatch *callbacks; | ||||
|     struct SDL_Hint *next; | ||||
| } SDL_Hint; | ||||
|  | ||||
| static SDL_Hint *SDL_hints; | ||||
| static SDL_PropertiesID SDL_hint_props = 0; | ||||
|  | ||||
| SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriority priority) | ||||
| static SDL_PropertiesID GetHintProperties(SDL_bool create) | ||||
| { | ||||
|     const char *env; | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry; | ||||
|     if (!SDL_hint_props && create) { | ||||
|         SDL_hint_props = SDL_CreateProperties(); | ||||
|     } | ||||
|     return SDL_hint_props; | ||||
| } | ||||
|  | ||||
|     if (!name) { | ||||
|         return SDL_FALSE; | ||||
| void SDL_InitHints(void) | ||||
| { | ||||
|     // Just make sure the hint properties are created on the main thread | ||||
|     (void)GetHintProperties(SDL_TRUE); | ||||
| } | ||||
|  | ||||
| static void SDLCALL CleanupHintProperty(void *userdata, void *value) | ||||
| { | ||||
|     SDL_Hint *hint = (SDL_Hint *) value; | ||||
|     SDL_free(hint->value); | ||||
|  | ||||
|     SDL_HintWatch *entry = hint->callbacks; | ||||
|     while (entry) { | ||||
|         SDL_HintWatch *freeable = entry; | ||||
|         entry = entry->next; | ||||
|         SDL_free(freeable); | ||||
|     } | ||||
|     SDL_free(hint); | ||||
| } | ||||
|  | ||||
| int SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPriority priority) | ||||
| { | ||||
|     if (!name || !*name) { | ||||
|         return SDL_InvalidParamError("name"); | ||||
|     } | ||||
|  | ||||
|     env = SDL_getenv(name); | ||||
|     if (env && priority < SDL_HINT_OVERRIDE) { | ||||
|         return SDL_FALSE; | ||||
|     const char *env = SDL_getenv(name); | ||||
|     if (env && (priority < SDL_HINT_OVERRIDE)) { | ||||
|         return SDL_SetError("An environment variable is taking priority"); | ||||
|     } | ||||
|  | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         if (SDL_strcmp(name, hint->name) == 0) { | ||||
|             if (priority < hint->priority) { | ||||
|                 return SDL_FALSE; | ||||
|     const SDL_PropertiesID hints = GetHintProperties(SDL_TRUE); | ||||
|     if (!hints) { | ||||
|         return -1; | ||||
|     } | ||||
|             if (hint->value != value && | ||||
|                 (!value || !hint->value || SDL_strcmp(hint->value, value) != 0)) { | ||||
|  | ||||
|     int retval = -1; | ||||
|  | ||||
|     SDL_LockProperties(hints); | ||||
|  | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (hint) { | ||||
|         if (priority >= hint->priority) { | ||||
|             if (hint->value != value && (!value || !hint->value || SDL_strcmp(hint->value, value) != 0)) { | ||||
|                 char *old_value = hint->value; | ||||
|  | ||||
|                 hint->value = value ? SDL_strdup(value) : NULL; | ||||
|                 for (entry = hint->callbacks; entry;) { | ||||
|                     /* Save the next entry in case this one is deleted */ | ||||
|                 SDL_HintWatch *entry = hint->callbacks; | ||||
|                 while (entry) { | ||||
|                     // Save the next entry in case this one is deleted | ||||
|                     SDL_HintWatch *next = entry->next; | ||||
|                     entry->callback(entry->userdata, name, old_value, value); | ||||
|                     entry = next; | ||||
| @@ -77,42 +103,45 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr | ||||
|                 SDL_free(old_value); | ||||
|             } | ||||
|             hint->priority = priority; | ||||
|             return SDL_TRUE; | ||||
|             retval = 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Couldn't find the hint, add a new one */ | ||||
|     } else {  // Couldn't find the hint? Add a new one. | ||||
|         hint = (SDL_Hint *)SDL_malloc(sizeof(*hint)); | ||||
|     if (!hint) { | ||||
|         return SDL_FALSE; | ||||
|     } | ||||
|     hint->name = SDL_strdup(name); | ||||
|         if (hint) { | ||||
|             hint->value = value ? SDL_strdup(value) : NULL; | ||||
|             hint->priority = priority; | ||||
|             hint->callbacks = NULL; | ||||
|     hint->next = SDL_hints; | ||||
|     SDL_hints = hint; | ||||
|     return SDL_TRUE; | ||||
| } | ||||
|  | ||||
| SDL_bool SDL_ResetHint(const char *name) | ||||
| { | ||||
|     const char *env; | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry; | ||||
|  | ||||
|     if (!name) { | ||||
|         return SDL_FALSE; | ||||
|             retval = (SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL) != -1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     env = SDL_getenv(name); | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         if (SDL_strcmp(name, hint->name) == 0) { | ||||
|             if ((!env && hint->value) || | ||||
|                 (env && !hint->value) || | ||||
|                 (env && SDL_strcmp(env, hint->value) != 0)) { | ||||
|                 for (entry = hint->callbacks; entry;) { | ||||
|                     /* Save the next entry in case this one is deleted */ | ||||
|     SDL_UnlockProperties(hints); | ||||
|  | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| int SDL_ResetHint(const char *name) | ||||
| { | ||||
|     if (!name || !*name) { | ||||
|         return SDL_InvalidParamError("name"); | ||||
|     } | ||||
|  | ||||
|     const char *env = SDL_getenv(name); | ||||
|  | ||||
|     const SDL_PropertiesID hints = GetHintProperties(SDL_FALSE); | ||||
|     if (!hints) { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     int retval = -1; | ||||
|  | ||||
|     SDL_LockProperties(hints); | ||||
|  | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (hint) { | ||||
|         if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) { | ||||
|             for (SDL_HintWatch *entry = hint->callbacks; entry;) { | ||||
|                 // Save the next entry in case this one is deleted | ||||
|                 SDL_HintWatch *next = entry->next; | ||||
|                 entry->callback(entry->userdata, name, hint->value, env); | ||||
|                 entry = next; | ||||
| @@ -121,60 +150,71 @@ SDL_bool SDL_ResetHint(const char *name) | ||||
|         SDL_free(hint->value); | ||||
|         hint->value = NULL; | ||||
|         hint->priority = SDL_HINT_DEFAULT; | ||||
|             return SDL_TRUE; | ||||
|         retval = 0; | ||||
|     } | ||||
|     } | ||||
|     return SDL_FALSE; | ||||
|  | ||||
|     SDL_UnlockProperties(hints); | ||||
|  | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| void SDL_ResetHints(void) | ||||
| static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, const char *name) | ||||
| { | ||||
|     const char *env; | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry; | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (!hint) { | ||||
|         return;  // uh...okay. | ||||
|     } | ||||
|  | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         env = SDL_getenv(hint->name); | ||||
|         if ((!env && hint->value) || | ||||
|             (env && !hint->value) || | ||||
|             (env && SDL_strcmp(env, hint->value) != 0)) { | ||||
|             for (entry = hint->callbacks; entry;) { | ||||
|                 /* Save the next entry in case this one is deleted */ | ||||
|     const char *env = SDL_getenv(name); | ||||
|     if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) { | ||||
|         SDL_HintWatch *entry = hint->callbacks; | ||||
|         while (entry) { | ||||
|             // Save the next entry in case this one is deleted | ||||
|             SDL_HintWatch *next = entry->next; | ||||
|                 entry->callback(entry->userdata, hint->name, hint->value, env); | ||||
|             entry->callback(entry->userdata, name, hint->value, env); | ||||
|             entry = next; | ||||
|         } | ||||
|     } | ||||
|     SDL_free(hint->value); | ||||
|     hint->value = NULL; | ||||
|     hint->priority = SDL_HINT_DEFAULT; | ||||
|     } | ||||
| } | ||||
|  | ||||
| SDL_bool SDL_SetHint(const char *name, const char *value) | ||||
| void SDL_ResetHints(void) | ||||
| { | ||||
|     SDL_EnumerateProperties(GetHintProperties(SDL_FALSE), ResetHintsCallback, NULL); | ||||
| } | ||||
|  | ||||
| int SDL_SetHint(const char *name, const char *value) | ||||
| { | ||||
|     return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL); | ||||
| } | ||||
|  | ||||
| const char *SDL_GetHint(const char *name) | ||||
| { | ||||
|     const char *env; | ||||
|     SDL_Hint *hint; | ||||
|  | ||||
|     if (!name) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     env = SDL_getenv(name); | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         if (SDL_strcmp(name, hint->name) == 0) { | ||||
|             if (!env || hint->priority == SDL_HINT_OVERRIDE) { | ||||
|                 return SDL_GetPersistentString(hint->value); | ||||
|     const SDL_PropertiesID hints = GetHintProperties(SDL_FALSE); | ||||
|     if (!hints) { | ||||
|         return NULL; | ||||
|     } | ||||
|             break; | ||||
|  | ||||
|     const char *retval = SDL_getenv(name); | ||||
|  | ||||
|     SDL_LockProperties(hints); | ||||
|  | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (hint) { | ||||
|         if (!retval || hint->priority == SDL_HINT_OVERRIDE) { | ||||
|             retval = SDL_GetPersistentString(hint->value); | ||||
|         } | ||||
|     } | ||||
|     return env; | ||||
|  | ||||
|     SDL_UnlockProperties(hints); | ||||
|  | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| int SDL_GetStringInteger(const char *value, int default_value) | ||||
| @@ -213,71 +253,75 @@ SDL_bool SDL_GetHintBoolean(const char *name, SDL_bool default_value) | ||||
|  | ||||
| int SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) | ||||
| { | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry; | ||||
|     const char *value; | ||||
|  | ||||
|     if (!name || !*name) { | ||||
|         return SDL_InvalidParamError("name"); | ||||
|     } | ||||
|     if (!callback) { | ||||
|     } else if (!callback) { | ||||
|         return SDL_InvalidParamError("callback"); | ||||
|     } | ||||
|  | ||||
|     SDL_DelHintCallback(name, callback, userdata); | ||||
|     const SDL_PropertiesID hints = GetHintProperties(SDL_TRUE); | ||||
|     if (!hints) { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry)); | ||||
|     SDL_HintWatch *entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry)); | ||||
|     if (!entry) { | ||||
|         return -1; | ||||
|     } | ||||
|     entry->callback = callback; | ||||
|     entry->userdata = userdata; | ||||
|  | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         if (SDL_strcmp(name, hint->name) == 0) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     if (!hint) { | ||||
|         /* Need to add a hint entry for this watcher */ | ||||
|     int retval = -1; | ||||
|  | ||||
|     SDL_LockProperties(hints); | ||||
|  | ||||
|     SDL_DelHintCallback(name, callback, userdata); | ||||
|  | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (hint) { | ||||
|         retval = 0; | ||||
|     } else {  // Need to add a hint entry for this watcher | ||||
|         hint = (SDL_Hint *)SDL_malloc(sizeof(*hint)); | ||||
|         if (!hint) { | ||||
|             SDL_free(entry); | ||||
|             return -1; | ||||
|         } | ||||
|         hint->name = SDL_strdup(name); | ||||
|         if (!hint->name) { | ||||
|             SDL_free(entry); | ||||
|             SDL_free(hint); | ||||
|             return -1; | ||||
|         } | ||||
|         } else { | ||||
|             hint->value = NULL; | ||||
|             hint->priority = SDL_HINT_DEFAULT; | ||||
|             hint->callbacks = NULL; | ||||
|         hint->next = SDL_hints; | ||||
|         SDL_hints = hint; | ||||
|             retval = SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Add it to the callbacks for this hint */ | ||||
|     // Add it to the callbacks for this hint | ||||
|     entry->next = hint->callbacks; | ||||
|     hint->callbacks = entry; | ||||
|  | ||||
|     /* Now call it with the current value */ | ||||
|     value = SDL_GetHint(name); | ||||
|     // Now call it with the current value | ||||
|     const char *value = SDL_GetHint(name); | ||||
|     callback(userdata, name, value, value); | ||||
|     return 0; | ||||
|  | ||||
|     SDL_UnlockProperties(hints); | ||||
|  | ||||
|     return retval; | ||||
| } | ||||
|  | ||||
| void SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata) | ||||
| { | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry, *prev; | ||||
|     if (!name || !*name) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     for (hint = SDL_hints; hint; hint = hint->next) { | ||||
|         if (SDL_strcmp(name, hint->name) == 0) { | ||||
|             prev = NULL; | ||||
|             for (entry = hint->callbacks; entry; entry = entry->next) { | ||||
|                 if (callback == entry->callback && userdata == entry->userdata) { | ||||
|     const SDL_PropertiesID hints = GetHintProperties(SDL_FALSE); | ||||
|     if (!hints) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     SDL_LockProperties(hints); | ||||
|     SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL); | ||||
|     if (hint) { | ||||
|         SDL_HintWatch *prev = NULL; | ||||
|         for (SDL_HintWatch *entry = hint->callbacks; entry; entry = entry->next) { | ||||
|             if ((callback == entry->callback) && (userdata == entry->userdata)) { | ||||
|                 if (prev) { | ||||
|                     prev->next = entry->next; | ||||
|                 } else { | ||||
| @@ -288,27 +332,13 @@ void SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *user | ||||
|             } | ||||
|             prev = entry; | ||||
|         } | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     SDL_UnlockProperties(hints); | ||||
| } | ||||
|  | ||||
| void SDL_ClearHints(void) | ||||
| void SDL_QuitHints(void) | ||||
| { | ||||
|     SDL_Hint *hint; | ||||
|     SDL_HintWatch *entry; | ||||
|  | ||||
|     while (SDL_hints) { | ||||
|         hint = SDL_hints; | ||||
|         SDL_hints = hint->next; | ||||
|  | ||||
|         SDL_free(hint->name); | ||||
|         SDL_free(hint->value); | ||||
|         for (entry = hint->callbacks; entry;) { | ||||
|             SDL_HintWatch *freeable = entry; | ||||
|             entry = entry->next; | ||||
|             SDL_free(freeable); | ||||
|         } | ||||
|         SDL_free(hint); | ||||
|     } | ||||
|     SDL_DestroyProperties(SDL_hint_props); | ||||
|     SDL_hint_props = 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -25,8 +25,9 @@ | ||||
| #ifndef SDL_hints_c_h_ | ||||
| #define SDL_hints_c_h_ | ||||
|  | ||||
| extern void SDL_InitHints(void); | ||||
| extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value); | ||||
| extern int SDL_GetStringInteger(const char *value, int default_value); | ||||
| extern void SDL_ClearHints(void); | ||||
| extern void SDL_QuitHints(void); | ||||
|  | ||||
| #endif /* SDL_hints_c_h_ */ | ||||
|   | ||||
| @@ -711,7 +711,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_RenderViewportSet,(SDL_Renderer *a),(a),return) | ||||
| SDL_DYNAPI_PROC(SDL_AssertState,SDL_ReportAssertion,(SDL_AssertData *a, const char *b, const char *c, int d),(a,b,c,d),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_RequestAndroidPermission,(const char *a, SDL_RequestAndroidPermissionCallback b, void *c),(a,b,c),return) | ||||
| SDL_DYNAPI_PROC(void,SDL_ResetAssertionReport,(void),(),) | ||||
| SDL_DYNAPI_PROC(SDL_bool,SDL_ResetHint,(const char *a),(a),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_ResetHint,(const char *a),(a),return) | ||||
| SDL_DYNAPI_PROC(void,SDL_ResetHints,(void),(),) | ||||
| SDL_DYNAPI_PROC(void,SDL_ResetKeyboard,(void),(),) | ||||
| SDL_DYNAPI_PROC(void,SDL_ResetLogPriorities,(void),(),) | ||||
| @@ -762,8 +762,8 @@ SDL_DYNAPI_PROC(int,SDL_SetGamepadPlayerIndex,(SDL_Gamepad *a, int b),(a,b),retu | ||||
| SDL_DYNAPI_PROC(int,SDL_SetGamepadSensorEnabled,(SDL_Gamepad *a, SDL_SensorType b, SDL_bool c),(a,b,c),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetHapticAutocenter,(SDL_Haptic *a, int b),(a,b),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetHapticGain,(SDL_Haptic *a, int b),(a,b),return) | ||||
| SDL_DYNAPI_PROC(SDL_bool,SDL_SetHint,(const char *a, const char *b),(a,b),return) | ||||
| SDL_DYNAPI_PROC(SDL_bool,SDL_SetHintWithPriority,(const char *a, const char *b, SDL_HintPriority c),(a,b,c),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetHint,(const char *a, const char *b),(a,b),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetHintWithPriority,(const char *a, const char *b, SDL_HintPriority c),(a,b,c),return) | ||||
| SDL_DYNAPI_PROC(void,SDL_SetJoystickEventsEnabled,(SDL_bool a),(a),) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetJoystickLED,(SDL_Joystick *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return) | ||||
| SDL_DYNAPI_PROC(int,SDL_SetJoystickPlayerIndex,(SDL_Joystick *a, int b),(a,b),return) | ||||
|   | ||||
| @@ -194,14 +194,11 @@ static const SDL_mutex_impl_t SDL_mutex_impl_cs = { | ||||
| SDL_Mutex *SDL_CreateMutex(void) | ||||
| { | ||||
|     if (!SDL_mutex_impl_active.Create) { | ||||
|         // Default to fallback implementation | ||||
| #ifdef SDL_PLATFORM_WINRT | ||||
|         const SDL_mutex_impl_t *impl = &SDL_mutex_impl_srw; | ||||
| #else | ||||
|         const SDL_mutex_impl_t *impl = &SDL_mutex_impl_cs; | ||||
|  | ||||
|         if (!SDL_GetHintBoolean(SDL_HINT_WINDOWS_FORCE_MUTEX_CRITICAL_SECTIONS, SDL_FALSE)) { | ||||
| #ifdef SDL_PLATFORM_WINRT | ||||
|             // Link statically on this platform | ||||
|             impl = &SDL_mutex_impl_srw; | ||||
| #else | ||||
|         // Try faster implementation for Windows 7 and newer | ||||
|         HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll")); | ||||
|         if (kernel32) { | ||||
| @@ -215,8 +212,7 @@ SDL_Mutex *SDL_CreateMutex(void) | ||||
|                 impl = &SDL_mutex_impl_srw; | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|         } | ||||
| #endif // SDL_PLATFORM_WINRT | ||||
|  | ||||
|         // Copy instead of using pointer to save one level of indirection | ||||
|         SDL_copyp(&SDL_mutex_impl_active, impl); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ryan C. Gordon
					Ryan C. Gordon