SDL_ResetHint() no longer clears the callbacks associated with a hint Also added SDL_ResetHints() to reset all callbacks, and clarified that SDL_ClearHints() is just used for cleanup at shutdown. Fixes https://github.com/libsdl-org/SDL/issues/6313
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 9e8295b..b379dba 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -2424,6 +2424,19 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name,
extern DECLSPEC SDL_bool SDLCALL SDL_ResetHint(const char *name);
/**
+ * Reset all hints to the default values.
+ *
+ * This will reset all hints to the value of the associated environment variable, or NULL if the environment isn't set. Callbacks will be called normally with this change.
+ *
+ * \since This function is available since SDL 2.26.0.
+ *
+ * \sa SDL_GetHint
+ * \sa SDL_SetHint
+ * \sa SDL_ResetHint
+ */
+extern DECLSPEC void SDLCALL SDL_ResetHints(void);
+
+/**
* Get the value of a hint.
*
* \param name the hint to query
@@ -2496,9 +2509,13 @@ extern DECLSPEC void SDLCALL SDL_DelHintCallback(const char *name,
/**
* Clear all hints.
*
- * This function is automatically called during SDL_Quit().
+ * This function is automatically called during SDL_Quit(), and deletes all callbacks without calling them and frees all memory associated with hints. If you're calling this from application code you probably want to call SDL_ResetHints() instead.
+ *
+ * This function will be removed from the API the next time we rev the ABI.
*
* \since This function is available since SDL 2.0.0.
+ *
+ * \sa SDL_ResetHints
*/
extern DECLSPEC void SDLCALL SDL_ClearHints(void);
diff --git a/src/SDL_hints.c b/src/SDL_hints.c
index 93bcc47..901c58b 100644
--- a/src/SDL_hints.c
+++ b/src/SDL_hints.c
@@ -100,7 +100,6 @@ SDL_bool
SDL_ResetHint(const char *name)
{
const char *env;
- SDL_Hint *hint, *prev;
SDL_HintWatch *entry;
if (!name) {
@@ -108,7 +107,7 @@ SDL_ResetHint(const char *name)
}
env = SDL_getenv(name);
- for (prev = NULL, hint = SDL_hints; hint; prev = hint, hint = hint->next) {
+ for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
if ((env == NULL && hint->value != NULL) ||
(env != NULL && hint->value == NULL) ||
@@ -120,19 +119,39 @@ SDL_ResetHint(const char *name)
entry = next;
}
}
- if (prev) {
- prev->next = hint->next;
- } else {
- SDL_hints = hint->next;
- }
SDL_free(hint->value);
- SDL_free(hint);
+ hint->value = NULL;
+ hint->priority = SDL_HINT_DEFAULT;
return SDL_TRUE;
}
}
return SDL_FALSE;
}
+void
+SDL_ResetHints(void)
+{
+ const char *env;
+ SDL_HintWatch *entry;
+
+ for (hint = SDL_hints; hint; hint = hint->next) {
+ env = SDL_getenv(hint->name);
+ if ((env == NULL && hint->value != NULL) ||
+ (env != NULL && hint->value == NULL) ||
+ (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;
+ }
+}
+
SDL_bool
SDL_SetHint(const char *name, const char *value)
{
diff --git a/src/dynapi/SDL2.exports b/src/dynapi/SDL2.exports
index c2e903e..8cc0c61 100644
--- a/src/dynapi/SDL2.exports
+++ b/src/dynapi/SDL2.exports
@@ -865,3 +865,4 @@
++'_SDL_HasPrimarySelectionText'.'SDL2.dll'.'SDL_HasPrimarySelectionText'
++'_SDL_GameControllerGetSensorDataWithTimestamp'.'SDL2.dll'.'SDL_GameControllerGetSensorDataWithTimestamp'
++'_SDL_SensorGetDataWithTimestamp'.'SDL2.dll'.'SDL_SensorGetDataWithTimestamp'
+++'_SDL_ResetHints'.'SDL2.dll'.'SDL_ResetHints'
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index fc9255c..d5d782f 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -891,3 +891,4 @@
#define SDL_HasPrimarySelectionText SDL_HasPrimarySelectionText_REAL
#define SDL_GameControllerGetSensorDataWithTimestamp SDL_GameControllerGetSensorDataWithTimestamp_REAL
#define SDL_SensorGetDataWithTimestamp SDL_SensorGetDataWithTimestamp_REAL
+#define SDL_ResetHints SDL_ResetHints_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index f8d858d..435ccb4 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -974,3 +974,4 @@ SDL_DYNAPI_PROC(char*,SDL_GetPrimarySelectionText,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasPrimarySelectionText,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerGetSensorDataWithTimestamp,(SDL_GameController *a, SDL_SensorType b, Uint64 *c, float *d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_SensorGetDataWithTimestamp,(SDL_Sensor *a, Uint64 *b, float *c, int d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(void,SDL_ResetHints,(void),(),)
diff --git a/test/testautomation_hints.c b/test/testautomation_hints.c
index bbcc9fd..c3f5ddf 100644
--- a/test/testautomation_hints.c
+++ b/test/testautomation_hints.c
@@ -92,6 +92,11 @@ hints_getHint(void *arg)
return TEST_COMPLETED;
}
+static void SDLCALL hints_testHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+ *(char **)userdata = hint ? SDL_strdup(hint) : NULL;
+}
+
/**
* @brief Call to SDL_SetHint
*/
@@ -102,6 +107,7 @@ hints_setHint(void *arg)
const char *originalValue;
char *value;
const char *testValue;
+ char *callbackValue;
SDL_bool result;
int i, j;
@@ -192,6 +198,51 @@ hints_setHint(void *arg)
"testValue = %s, expected \"original\"",
testValue);
+ /* Make sure callback functionality works past a reset */
+ SDLTest_AssertPass("Call to SDL_AddHintCallback()");
+ callbackValue = NULL;
+ SDL_AddHintCallback(testHint, hints_testHintChanged, &callbackValue);
+ SDLTest_AssertCheck(
+ callbackValue && SDL_strcmp(callbackValue, "original") == 0,
+ "callbackValue = %s, expected \"original\"",
+ callbackValue);
+ SDL_free(callbackValue);
+
+ SDLTest_AssertPass("Call to SDL_SetHintWithPriority(\"temp\", SDL_HINT_OVERRIDE), using callback");
+ callbackValue = NULL;
+ SDL_SetHintWithPriority(testHint, "temp", SDL_HINT_OVERRIDE);
+ SDLTest_AssertCheck(
+ callbackValue && SDL_strcmp(callbackValue, "temp") == 0,
+ "callbackValue = %s, expected \"temp\"",
+ callbackValue);
+ SDL_free(callbackValue);
+
+ SDLTest_AssertPass("Call to SDL_ResetHint(), using callback");
+ callbackValue = NULL;
+ SDL_ResetHint(testHint);
+ SDLTest_AssertCheck(
+ callbackValue && SDL_strcmp(callbackValue, "original") == 0,
+ "callbackValue = %s, expected \"original\"",
+ callbackValue);
+
+ SDLTest_AssertPass("Call to SDL_SetHintWithPriority(\"temp\", SDL_HINT_OVERRIDE), using callback after reset");
+ callbackValue = NULL;
+ SDL_SetHintWithPriority(testHint, "temp", SDL_HINT_OVERRIDE);
+ SDLTest_AssertCheck(
+ callbackValue && SDL_strcmp(callbackValue, "temp") == 0,
+ "callbackValue = %s, expected \"temp\"",
+ callbackValue);
+ SDL_free(callbackValue);
+
+ SDLTest_AssertPass("Call to SDL_ResetHint(), after clearing callback");
+ callbackValue = NULL;
+ SDL_DelHintCallback(testHint, hints_testHintChanged, &callbackValue);
+ SDL_ResetHint(testHint);
+ SDLTest_AssertCheck(
+ callbackValue == NULL,
+ "callbackValue = %s, expected \"(null)\"",
+ callbackValue);
+
return TEST_COMPLETED;
}