summaryrefslogtreecommitdiff
path: root/src/SDL_hints.c
diff options
context:
space:
mode:
authorSam Lantinga <slouken@libsdl.org>2013-07-13 03:13:41 -0700
committerSam Lantinga <slouken@libsdl.org>2013-07-13 03:13:41 -0700
commit8f2f5f59d29e5b3aced79a64b217944ec5db47d3 (patch)
treecf1ce10081f60ede303fe56fd26bd55945900764 /src/SDL_hints.c
parent124aecc92cee209d0a8024dd66f789ea9482f917 (diff)
Added a hint to control the Windows timer resolution: SDL_HINT_TIMER_RESOLUTION
Added an API to watch hint changes: SDL_AddHintCallback(), SDL_DelHintCallback() You can now dynamically set the joystick background event hint.
Diffstat (limited to 'src/SDL_hints.c')
-rw-r--r--src/SDL_hints.c137
1 files changed, 111 insertions, 26 deletions
diff --git a/src/SDL_hints.c b/src/SDL_hints.c
index bd9404d46b..b00e961cc9 100644
--- a/src/SDL_hints.c
+++ b/src/SDL_hints.c
@@ -21,43 +21,35 @@
#include "SDL_config.h"
#include "SDL_hints.h"
-#include "SDL_hints_c.h"
+#include "SDL_error.h"
/* Assuming there aren't many hints set and they aren't being queried in
- critical performance paths, we'll just use a linked list here.
+ critical performance paths, we'll just use linked lists here.
*/
+typedef struct SDL_HintWatch {
+ SDL_HintCallback callback;
+ void *userdata;
+ struct SDL_HintWatch *next;
+} SDL_HintWatch;
+
typedef struct SDL_Hint {
char *name;
char *value;
SDL_HintPriority priority;
- SDL_HintChangedCb callback;
+ SDL_HintWatch *callbacks;
struct SDL_Hint *next;
} SDL_Hint;
static SDL_Hint *SDL_hints;
SDL_bool
-SDL_RegisterHintChangedCb(const char *name, SDL_HintChangedCb hintCb)
-{
- SDL_Hint *hint;
-
- for (hint = SDL_hints; hint; hint = hint->next) {
- if (SDL_strcmp(name, hint->name) == 0) {
- hint->callback = hintCb;
- return SDL_TRUE;
- }
- }
-
- return SDL_FALSE;
-}
-
-SDL_bool
SDL_SetHintWithPriority(const char *name, const char *value,
SDL_HintPriority priority)
{
const char *env;
SDL_Hint *hint;
+ SDL_HintWatch *entry;
if (!name || !value) {
return SDL_FALSE;
@@ -73,12 +65,21 @@ SDL_SetHintWithPriority(const char *name, const char *value,
if (priority < hint->priority) {
return SDL_FALSE;
}
- if (SDL_strcmp(hint->value, value) != 0) {
- if (hint->callback != NULL) {
- (*hint->callback)(name, hint->value, value);
+ if (!hint->value || !value || SDL_strcmp(hint->value, 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, value);
+ entry = next;
+ }
+ if (hint->value) {
+ SDL_free(hint->value);
+ }
+ if (value) {
+ hint->value = SDL_strdup(value);
+ } else {
+ hint->value = NULL;
}
- SDL_free(hint->value);
- hint->value = SDL_strdup(value);
}
hint->priority = priority;
return SDL_TRUE;
@@ -91,9 +92,9 @@ SDL_SetHintWithPriority(const char *name, const char *value,
return SDL_FALSE;
}
hint->name = SDL_strdup(name);
- hint->value = SDL_strdup(value);
+ hint->value = value ? SDL_strdup(value) : NULL;
hint->priority = priority;
- hint->callback = NULL;
+ hint->callbacks = NULL;
hint->next = SDL_hints;
SDL_hints = hint;
return SDL_TRUE;
@@ -123,16 +124,100 @@ SDL_GetHint(const char *name)
return env;
}
+void
+SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
+{
+ SDL_Hint *hint;
+ SDL_HintWatch *entry;
+ const char *value;
+
+ if (!name || !*name) {
+ SDL_InvalidParamError("name");
+ return;
+ }
+ if (!callback) {
+ SDL_InvalidParamError("callback");
+ return;
+ }
+
+ SDL_DelHintCallback(name, callback, userdata);
+
+ entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
+ 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 */
+ hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
+ if (!hint) {
+ return;
+ }
+ hint->name = SDL_strdup(name);
+ 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 */
+ entry->next = hint->callbacks;
+ hint->callbacks = entry;
+
+ /* Now call it with the current value */
+ value = SDL_GetHint(name);
+ callback(userdata, name, value, value);
+}
+
+void
+SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
+{
+ SDL_Hint *hint;
+ SDL_HintWatch *entry, *prev;
+
+ 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;
+ }
+ prev = entry;
+ }
+ return;
+ }
+ }
+}
+
void SDL_ClearHints(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);
+ if (hint->value) {
+ SDL_free(hint->value);
+ }
+ for (entry = hint->callbacks; entry; ) {
+ SDL_HintWatch *freeable = entry;
+ entry = entry->next;
+ SDL_free(freeable);
+ }
SDL_free(hint);
}
}