Bladeren bron

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
Sam Lantinga 2 jaren geleden
bovenliggende
commit
64ea6cefaf
6 gewijzigde bestanden met toevoegingen van 99 en 9 verwijderingen
  1. 18 1
      include/SDL_hints.h
  2. 27 8
      src/SDL_hints.c
  3. 1 0
      src/dynapi/SDL2.exports
  4. 1 0
      src/dynapi/SDL_dynapi_overrides.h
  5. 1 0
      src/dynapi/SDL_dynapi_procs.h
  6. 51 0
      test/testautomation_hints.c

+ 18 - 1
include/SDL_hints.h

@@ -2423,6 +2423,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.
  *
@@ -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);
 

+ 27 - 8
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)
 {

+ 1 - 0
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'

+ 1 - 0
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

+ 1 - 0
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),(),)

+ 51 - 0
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;
 }