src/SDL_hints.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 13 Jul 2013 03:13:41 -0700
changeset 7432 58908b180ebd
parent 7191 75360622e65f
child 7716 be4cda94bce2
permissions -rw-r--r--
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.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     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_config.h"
    22 
    23 #include "SDL_hints.h"
    24 #include "SDL_error.h"
    25 
    26 
    27 /* Assuming there aren't many hints set and they aren't being queried in
    28    critical performance paths, we'll just use linked lists here.
    29  */
    30 typedef struct SDL_HintWatch {
    31     SDL_HintCallback callback;
    32     void *userdata;
    33     struct SDL_HintWatch *next;
    34 } SDL_HintWatch;
    35 
    36 typedef struct SDL_Hint {
    37     char *name;
    38     char *value;
    39     SDL_HintPriority priority;
    40     SDL_HintWatch *callbacks;
    41     struct SDL_Hint *next;
    42 } SDL_Hint;
    43 
    44 static SDL_Hint *SDL_hints;
    45 
    46 SDL_bool
    47 SDL_SetHintWithPriority(const char *name, const char *value,
    48                         SDL_HintPriority priority)
    49 {
    50     const char *env;
    51     SDL_Hint *hint;
    52     SDL_HintWatch *entry;
    53 
    54     if (!name || !value) {
    55         return SDL_FALSE;
    56     }
    57 
    58     env = SDL_getenv(name);
    59     if (env && priority < SDL_HINT_OVERRIDE) {
    60         return SDL_FALSE;
    61     }
    62 
    63     for (hint = SDL_hints; hint; hint = hint->next) {
    64         if (SDL_strcmp(name, hint->name) == 0) {
    65             if (priority < hint->priority) {
    66                 return SDL_FALSE;
    67             }
    68             if (!hint->value || !value || SDL_strcmp(hint->value, value) != 0) {
    69                 for (entry = hint->callbacks; entry; ) {
    70                     /* Save the next entry in case this one is deleted */
    71                     SDL_HintWatch *next = entry->next;
    72                     entry->callback(entry->userdata, name, hint->value, value);
    73                     entry = next;
    74                 }
    75                 if (hint->value) {
    76                     SDL_free(hint->value);
    77                 }
    78                 if (value) {
    79                     hint->value = SDL_strdup(value);
    80                 } else {
    81                     hint->value = NULL;
    82                 }
    83             }
    84             hint->priority = priority;
    85             return SDL_TRUE;
    86         }
    87     }
    88 
    89     /* Couldn't find the hint, add a new one */
    90     hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
    91     if (!hint) {
    92         return SDL_FALSE;
    93     }
    94     hint->name = SDL_strdup(name);
    95     hint->value = value ? SDL_strdup(value) : NULL;
    96     hint->priority = priority;
    97     hint->callbacks = NULL;
    98     hint->next = SDL_hints;
    99     SDL_hints = hint;
   100     return SDL_TRUE;
   101 }
   102 
   103 SDL_bool
   104 SDL_SetHint(const char *name, const char *value)
   105 {
   106     return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL);
   107 }
   108 
   109 const char *
   110 SDL_GetHint(const char *name)
   111 {
   112     const char *env;
   113     SDL_Hint *hint;
   114 
   115     env = SDL_getenv(name);
   116     for (hint = SDL_hints; hint; hint = hint->next) {
   117         if (SDL_strcmp(name, hint->name) == 0) {
   118             if (!env || hint->priority == SDL_HINT_OVERRIDE) {
   119                 return hint->value;
   120             }
   121             break;
   122         }
   123     }
   124     return env;
   125 }
   126 
   127 void
   128 SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   129 {
   130     SDL_Hint *hint;
   131     SDL_HintWatch *entry;
   132     const char *value;
   133 
   134     if (!name || !*name) {
   135         SDL_InvalidParamError("name");
   136         return;
   137     }
   138     if (!callback) {
   139         SDL_InvalidParamError("callback");
   140         return;
   141     }
   142 
   143     SDL_DelHintCallback(name, callback, userdata);
   144 
   145     entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
   146     entry->callback = callback;
   147     entry->userdata = userdata;
   148 
   149     for (hint = SDL_hints; hint; hint = hint->next) {
   150         if (SDL_strcmp(name, hint->name) == 0) {
   151             break;
   152         }
   153     }
   154     if (!hint) {
   155         /* Need to add a hint entry for this watcher */
   156         hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
   157         if (!hint) {
   158             return;
   159         }
   160         hint->name = SDL_strdup(name);
   161         hint->value = NULL;
   162         hint->priority = SDL_HINT_DEFAULT;
   163         hint->callbacks = NULL;
   164         hint->next = SDL_hints;
   165         SDL_hints = hint;
   166     }
   167 
   168     /* Add it to the callbacks for this hint */
   169     entry->next = hint->callbacks;
   170     hint->callbacks = entry;
   171 
   172     /* Now call it with the current value */
   173     value = SDL_GetHint(name);
   174     callback(userdata, name, value, value);
   175 }
   176 
   177 void
   178 SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   179 {
   180     SDL_Hint *hint;
   181     SDL_HintWatch *entry, *prev;
   182 
   183     for (hint = SDL_hints; hint; hint = hint->next) {
   184         if (SDL_strcmp(name, hint->name) == 0) {
   185             prev = NULL;
   186             for (entry = hint->callbacks; entry; entry = entry->next) {
   187                 if (callback == entry->callback && userdata == entry->userdata) {
   188                     if (prev) {
   189                         prev->next = entry->next;
   190                     } else {
   191                         hint->callbacks = entry->next;
   192                     }
   193                     SDL_free(entry);
   194                     break;
   195                 }
   196                 prev = entry;
   197             }
   198             return;
   199         }
   200     }
   201 }
   202 
   203 void SDL_ClearHints(void)
   204 {
   205     SDL_Hint *hint;
   206     SDL_HintWatch *entry;
   207 
   208     while (SDL_hints) {
   209         hint = SDL_hints;
   210         SDL_hints = hint->next;
   211 
   212         SDL_free(hint->name);
   213         if (hint->value) {
   214             SDL_free(hint->value);
   215         }
   216         for (entry = hint->callbacks; entry; ) {
   217             SDL_HintWatch *freeable = entry;
   218             entry = entry->next;
   219             SDL_free(freeable);
   220         }
   221         SDL_free(hint);
   222     }
   223 }
   224 
   225 /* vi: set ts=4 sw=4 expandtab: */