src/SDL_hints.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 29 Aug 2013 08:26:24 -0700
changeset 7716 be4cda94bce2
parent 7432 58908b180ebd
child 7719 31b5f9ff36ca
permissions -rw-r--r--
Christoph Mallon: Simplify assignment.
     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                 hint->value = value ? SDL_strdup(value) : NULL;
    79             }
    80             hint->priority = priority;
    81             return SDL_TRUE;
    82         }
    83     }
    84 
    85     /* Couldn't find the hint, add a new one */
    86     hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
    87     if (!hint) {
    88         return SDL_FALSE;
    89     }
    90     hint->name = SDL_strdup(name);
    91     hint->value = value ? SDL_strdup(value) : NULL;
    92     hint->priority = priority;
    93     hint->callbacks = NULL;
    94     hint->next = SDL_hints;
    95     SDL_hints = hint;
    96     return SDL_TRUE;
    97 }
    98 
    99 SDL_bool
   100 SDL_SetHint(const char *name, const char *value)
   101 {
   102     return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL);
   103 }
   104 
   105 const char *
   106 SDL_GetHint(const char *name)
   107 {
   108     const char *env;
   109     SDL_Hint *hint;
   110 
   111     env = SDL_getenv(name);
   112     for (hint = SDL_hints; hint; hint = hint->next) {
   113         if (SDL_strcmp(name, hint->name) == 0) {
   114             if (!env || hint->priority == SDL_HINT_OVERRIDE) {
   115                 return hint->value;
   116             }
   117             break;
   118         }
   119     }
   120     return env;
   121 }
   122 
   123 void
   124 SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   125 {
   126     SDL_Hint *hint;
   127     SDL_HintWatch *entry;
   128     const char *value;
   129 
   130     if (!name || !*name) {
   131         SDL_InvalidParamError("name");
   132         return;
   133     }
   134     if (!callback) {
   135         SDL_InvalidParamError("callback");
   136         return;
   137     }
   138 
   139     SDL_DelHintCallback(name, callback, userdata);
   140 
   141     entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
   142     entry->callback = callback;
   143     entry->userdata = userdata;
   144 
   145     for (hint = SDL_hints; hint; hint = hint->next) {
   146         if (SDL_strcmp(name, hint->name) == 0) {
   147             break;
   148         }
   149     }
   150     if (!hint) {
   151         /* Need to add a hint entry for this watcher */
   152         hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
   153         if (!hint) {
   154             return;
   155         }
   156         hint->name = SDL_strdup(name);
   157         hint->value = NULL;
   158         hint->priority = SDL_HINT_DEFAULT;
   159         hint->callbacks = NULL;
   160         hint->next = SDL_hints;
   161         SDL_hints = hint;
   162     }
   163 
   164     /* Add it to the callbacks for this hint */
   165     entry->next = hint->callbacks;
   166     hint->callbacks = entry;
   167 
   168     /* Now call it with the current value */
   169     value = SDL_GetHint(name);
   170     callback(userdata, name, value, value);
   171 }
   172 
   173 void
   174 SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
   175 {
   176     SDL_Hint *hint;
   177     SDL_HintWatch *entry, *prev;
   178 
   179     for (hint = SDL_hints; hint; hint = hint->next) {
   180         if (SDL_strcmp(name, hint->name) == 0) {
   181             prev = NULL;
   182             for (entry = hint->callbacks; entry; entry = entry->next) {
   183                 if (callback == entry->callback && userdata == entry->userdata) {
   184                     if (prev) {
   185                         prev->next = entry->next;
   186                     } else {
   187                         hint->callbacks = entry->next;
   188                     }
   189                     SDL_free(entry);
   190                     break;
   191                 }
   192                 prev = entry;
   193             }
   194             return;
   195         }
   196     }
   197 }
   198 
   199 void SDL_ClearHints(void)
   200 {
   201     SDL_Hint *hint;
   202     SDL_HintWatch *entry;
   203 
   204     while (SDL_hints) {
   205         hint = SDL_hints;
   206         SDL_hints = hint->next;
   207 
   208         SDL_free(hint->name);
   209         if (hint->value) {
   210             SDL_free(hint->value);
   211         }
   212         for (entry = hint->callbacks; entry; ) {
   213             SDL_HintWatch *freeable = entry;
   214             entry = entry->next;
   215             SDL_free(freeable);
   216         }
   217         SDL_free(hint);
   218     }
   219 }
   220 
   221 /* vi: set ts=4 sw=4 expandtab: */