mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-23 10:53:27 +08: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:
parent
e3682995f5
commit
074dd8c35f
@ -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,9 +4123,9 @@ typedef enum SDL_HintPriority
|
||||
* \sa SDL_ResetHint
|
||||
* \sa SDL_SetHint
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_SetHintWithPriority(const char *name,
|
||||
const char *value,
|
||||
SDL_HintPriority priority);
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_SetHintWithPriority(const char *name,
|
||||
const char *value,
|
||||
SDL_HintPriority priority);
|
||||
|
||||
/**
|
||||
* Set a hint with normal 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,37 +4222,48 @@ 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.
|
||||
*
|
||||
* \sa SDL_DelHintCallback
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_AddHintCallback(const char *name,
|
||||
SDL_HintCallback callback,
|
||||
void *userdata);
|
||||
SDL_HintCallback callback,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* Remove a function watching a particular hint.
|
||||
@ -4264,13 +4273,15 @@ 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
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DelHintCallback(const char *name,
|
||||
SDL_HintCallback callback,
|
||||
void *userdata);
|
||||
SDL_HintCallback callback,
|
||||
void *userdata);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
@ -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();
|
||||
|
336
src/SDL_hints.c
336
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;
|
||||
}
|
||||
if (hint->value != value &&
|
||||
(!value || !hint->value || SDL_strcmp(hint->value, value) != 0)) {
|
||||
const SDL_PropertiesID hints = GetHintProperties(SDL_TRUE);
|
||||
if (!hints) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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,104 +103,118 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
|
||||
SDL_free(old_value);
|
||||
}
|
||||
hint->priority = priority;
|
||||
return SDL_TRUE;
|
||||
retval = 0;
|
||||
}
|
||||
} else { // Couldn't find the hint? Add a new one.
|
||||
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
|
||||
if (hint) {
|
||||
hint->value = value ? SDL_strdup(value) : NULL;
|
||||
hint->priority = priority;
|
||||
hint->callbacks = NULL;
|
||||
retval = (SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL) != -1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
hint->value = value ? SDL_strdup(value) : NULL;
|
||||
hint->priority = priority;
|
||||
hint->callbacks = NULL;
|
||||
hint->next = SDL_hints;
|
||||
SDL_hints = hint;
|
||||
return SDL_TRUE;
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool SDL_ResetHint(const char *name)
|
||||
int SDL_ResetHint(const char *name)
|
||||
{
|
||||
const char *env;
|
||||
SDL_Hint *hint;
|
||||
SDL_HintWatch *entry;
|
||||
|
||||
if (!name) {
|
||||
return SDL_FALSE;
|
||||
if (!name || !*name) {
|
||||
return SDL_InvalidParamError("name");
|
||||
}
|
||||
|
||||
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_HintWatch *next = entry->next;
|
||||
entry->callback(entry->userdata, name, hint->value, env);
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
SDL_free(hint->value);
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
const char *env = SDL_getenv(name);
|
||||
|
||||
const SDL_PropertiesID hints = GetHintProperties(SDL_FALSE);
|
||||
if (!hints) {
|
||||
return -1;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
void SDL_ResetHints(void)
|
||||
{
|
||||
const char *env;
|
||||
SDL_Hint *hint;
|
||||
SDL_HintWatch *entry;
|
||||
int retval = -1;
|
||||
|
||||
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 */
|
||||
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, 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;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
SDL_UnlockProperties(hints);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool SDL_SetHint(const char *name, const char *value)
|
||||
static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, const char *name)
|
||||
{
|
||||
SDL_Hint *hint = SDL_GetPointerProperty(hints, name, NULL);
|
||||
if (!hint) {
|
||||
return; // uh...okay.
|
||||
}
|
||||
|
||||
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, name, hint->value, env);
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
SDL_free(hint->value);
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
break;
|
||||
const SDL_PropertiesID hints = GetHintProperties(SDL_FALSE);
|
||||
if (!hints) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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,102 +253,92 @@ 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;
|
||||
} else {
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
hint->callbacks = NULL;
|
||||
retval = SDL_SetPointerPropertyWithCleanup(hints, name, hint, CleanupHintProperty, NULL);
|
||||
}
|
||||
hint->name = SDL_strdup(name);
|
||||
if (!hint->name) {
|
||||
SDL_free(entry);
|
||||
SDL_free(hint);
|
||||
return -1;
|
||||
}
|
||||
hint->value = NULL;
|
||||
hint->priority = SDL_HINT_DEFAULT;
|
||||
hint->callbacks = NULL;
|
||||
hint->next = SDL_hints;
|
||||
SDL_hints = hint;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
if (prev) {
|
||||
prev->next = entry->next;
|
||||
} else {
|
||||
hint->callbacks = entry->next;
|
||||
}
|
||||
SDL_free(entry);
|
||||
break;
|
||||
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 {
|
||||
hint->callbacks = entry->next;
|
||||
}
|
||||
prev = entry;
|
||||
SDL_free(entry);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
prev = entry;
|
||||
}
|
||||
}
|
||||
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,29 +194,25 @@ 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) {
|
||||
// Requires Vista:
|
||||
pInitializeSRWLock = (pfnInitializeSRWLock)GetProcAddress(kernel32, "InitializeSRWLock");
|
||||
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive)GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
|
||||
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive)GetProcAddress(kernel32, "AcquireSRWLockExclusive");
|
||||
// Requires 7:
|
||||
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive)GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
|
||||
if (pInitializeSRWLock && pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
|
||||
impl = &SDL_mutex_impl_srw;
|
||||
}
|
||||
// Try faster implementation for Windows 7 and newer
|
||||
HMODULE kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
|
||||
if (kernel32) {
|
||||
// Requires Vista:
|
||||
pInitializeSRWLock = (pfnInitializeSRWLock)GetProcAddress(kernel32, "InitializeSRWLock");
|
||||
pReleaseSRWLockExclusive = (pfnReleaseSRWLockExclusive)GetProcAddress(kernel32, "ReleaseSRWLockExclusive");
|
||||
pAcquireSRWLockExclusive = (pfnAcquireSRWLockExclusive)GetProcAddress(kernel32, "AcquireSRWLockExclusive");
|
||||
// Requires 7:
|
||||
pTryAcquireSRWLockExclusive = (pfnTryAcquireSRWLockExclusive)GetProcAddress(kernel32, "TryAcquireSRWLockExclusive");
|
||||
if (pInitializeSRWLock && pReleaseSRWLockExclusive && pAcquireSRWLockExclusive && pTryAcquireSRWLockExclusive) {
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user