Browse Source

Re-added SDL_getenv() as a thread-safe getenv() implementation

Sam Lantinga 7 months ago
parent
commit
28b94c4758

+ 2 - 0
docs/README-migration.md

@@ -1743,6 +1743,8 @@ Please note that the case-folding technique used by SDL3 will not produce correc
 
 SDL_strtoll(), SDL_strtoull(), SDL_lltoa(), and SDL_ulltoa() use long long values instead of 64-bit values, to match their C runtime counterparts.
 
+SDL_setenv() is not thread-safe and has been renamed SDL_setenv_unsafe().
+
 The following macros have been removed:
 * SDL_TABLESIZE() - use SDL_arraysize() instead
 

+ 19 - 2
include/SDL3/SDL_stdinc.h

@@ -1156,16 +1156,33 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyEnvironment(SDL_Environment *env);
 /**
  * Get the value of a variable in the environment.
  *
+ * This function uses SDL's cached copy of the environment and is thread-safe.
+ *
+ * \param name the name of the variable to get.
+ * \returns a pointer to the value of the variable or NULL if it can't be
+ *          found.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern SDL_DECLSPEC const char * SDLCALL SDL_getenv(const char *name);
+
+/**
+ * Get the value of a variable in the environment.
+ *
+ * This function bypasses SDL's cached copy of the environment and is not thread-safe.
+ *
  * \param name the name of the variable to get.
  * \returns a pointer to the value of the variable or NULL if it can't be
  *          found.
  *
  * \threadsafety This function is not thread safe, consider using
- *               SDL_GetEnvironmentVariable() instead.
+ *               SDL_getenv() instead.
  *
  * \since This function is available since SDL 3.0.0.
  *
- * \sa SDL_GetEnvironmentVariable
+ * \sa SDL_getenv
  */
 extern SDL_DECLSPEC const char * SDLCALL SDL_getenv_unsafe(const char *name);
 

+ 4 - 4
src/SDL_hints.c

@@ -72,7 +72,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
         return SDL_InvalidParamError("name");
     }
 
-    const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
+    const char *env = SDL_getenv(name);
     if (env && (priority < SDL_HINT_OVERRIDE)) {
         return SDL_SetError("An environment variable is taking priority");
     }
@@ -126,7 +126,7 @@ SDL_bool SDL_ResetHint(const char *name)
         return SDL_InvalidParamError("name");
     }
 
-    const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
+    const char *env = SDL_getenv(name);
 
     const SDL_PropertiesID hints = GetHintProperties(false);
     if (!hints) {
@@ -165,7 +165,7 @@ static void SDLCALL ResetHintsCallback(void *userdata, SDL_PropertiesID hints, c
         return;  // uh...okay.
     }
 
-    const char *env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
+    const char *env = SDL_getenv(name);
     if ((!env && hint->value) || (env && !hint->value) || (env && SDL_strcmp(env, hint->value) != 0)) {
         SDL_HintWatch *entry = hint->callbacks;
         while (entry) {
@@ -196,7 +196,7 @@ const char *SDL_GetHint(const char *name)
         return NULL;
     }
 
-    const char *result = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
+    const char *result = SDL_getenv(name);
 
     const SDL_PropertiesID hints = GetHintProperties(false);
     if (hints) {

+ 1 - 1
src/audio/SDL_audiodev.c

@@ -87,7 +87,7 @@ static void SDL_EnumUnixAudioDevices_Internal(const bool recording, const bool c
     }
 
     // Figure out what our audio device is
-    audiodev = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "AUDIODEV");
+    audiodev = SDL_getenv("AUDIODEV");
     if (!audiodev) {
         if (classic) {
             audiodev = SDL_PATH_DEV_AUDIO;

+ 5 - 5
src/core/linux/SDL_ibus.c

@@ -331,14 +331,14 @@ static char *IBus_GetDBusAddressFilename(void)
     }
 
     // Use this environment variable if it exists.
-    addr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "IBUS_ADDRESS");
+    addr = SDL_getenv("IBUS_ADDRESS");
     if (addr && *addr) {
         return SDL_strdup(addr);
     }
 
     /* Otherwise, we have to get the hostname, display, machine id, config dir
        and look up the address from a filepath using all those bits, eek. */
-    disp_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "DISPLAY");
+    disp_env = SDL_getenv("DISPLAY");
 
     if (!disp_env || !*disp_env) {
         display = SDL_strdup(":0.0");
@@ -363,7 +363,7 @@ static char *IBus_GetDBusAddressFilename(void)
     }
 
     if (!*host) {
-        const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE");
+        const char *session = SDL_getenv("XDG_SESSION_TYPE");
         if (session && SDL_strcmp(session, "wayland") == 0) {
             host = "unix-wayland";
         } else {
@@ -373,11 +373,11 @@ static char *IBus_GetDBusAddressFilename(void)
 
     SDL_memset(config_dir, 0, sizeof(config_dir));
 
-    conf_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_CONFIG_HOME");
+    conf_env = SDL_getenv("XDG_CONFIG_HOME");
     if (conf_env && *conf_env) {
         SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
     } else {
-        const char *home_env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+        const char *home_env = SDL_getenv("HOME");
         if (!home_env || !*home_env) {
             SDL_free(display);
             return NULL;

+ 2 - 2
src/core/linux/SDL_ime.c

@@ -44,8 +44,8 @@ static void InitIME(void)
 {
     static bool inited = false;
 #ifdef HAVE_FCITX
-    const char *im_module = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_IM_MODULE");
-    const char *xmodifiers = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XMODIFIERS");
+    const char *im_module = SDL_getenv("SDL_IM_MODULE");
+    const char *xmodifiers = SDL_getenv("XMODIFIERS");
 #endif
 
     if (inited == true) {

+ 3 - 3
src/core/linux/SDL_sandbox.c

@@ -33,9 +33,9 @@ SDL_Sandbox SDL_DetectSandbox(void)
 
     /* For Snap, we check multiple variables because they might be set for
      * unrelated reasons. This is the same thing WebKitGTK does. */
-    if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP") != NULL &&
-        SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_NAME") != NULL &&
-        SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SNAP_REVISION") != NULL) {
+    if (SDL_getenv("SNAP") != NULL &&
+        SDL_getenv("SNAP_NAME") != NULL &&
+        SDL_getenv("SNAP_REVISION") != NULL) {
         return SDL_SANDBOX_SNAP;
     }
 

+ 2 - 1
src/dynapi/SDL_dynapi.sym

@@ -239,7 +239,6 @@ SDL3_0.0.0 {
     SDL_GetBasePath;
     SDL_GetBooleanProperty;
     SDL_GetCPUCacheLineSize;
-    SDL_GetNumLogicalCPUCores;
     SDL_GetCameraDriver;
     SDL_GetCameraFormat;
     SDL_GetCameraID;
@@ -414,6 +413,7 @@ SDL3_0.0.0 {
     SDL_GetNumJoystickBalls;
     SDL_GetNumJoystickButtons;
     SDL_GetNumJoystickHats;
+    SDL_GetNumLogicalCPUCores;
     SDL_GetNumRenderDrivers;
     SDL_GetNumVideoDrivers;
     SDL_GetNumberProperty;
@@ -1029,6 +1029,7 @@ SDL3_0.0.0 {
     SDL_fmod;
     SDL_fmodf;
     SDL_free;
+    SDL_getenv;
     SDL_getenv_unsafe;
     SDL_hid_ble_scan;
     SDL_hid_close;

+ 2 - 1
src/dynapi/SDL_dynapi_overrides.h

@@ -264,7 +264,6 @@
 #define SDL_GetBasePath SDL_GetBasePath_REAL
 #define SDL_GetBooleanProperty SDL_GetBooleanProperty_REAL
 #define SDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize_REAL
-#define SDL_GetNumLogicalCPUCores SDL_GetNumLogicalCPUCores_REAL
 #define SDL_GetCameraDriver SDL_GetCameraDriver_REAL
 #define SDL_GetCameraFormat SDL_GetCameraFormat_REAL
 #define SDL_GetCameraID SDL_GetCameraID_REAL
@@ -439,6 +438,7 @@
 #define SDL_GetNumJoystickBalls SDL_GetNumJoystickBalls_REAL
 #define SDL_GetNumJoystickButtons SDL_GetNumJoystickButtons_REAL
 #define SDL_GetNumJoystickHats SDL_GetNumJoystickHats_REAL
+#define SDL_GetNumLogicalCPUCores SDL_GetNumLogicalCPUCores_REAL
 #define SDL_GetNumRenderDrivers SDL_GetNumRenderDrivers_REAL
 #define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL
 #define SDL_GetNumberProperty SDL_GetNumberProperty_REAL
@@ -1054,6 +1054,7 @@
 #define SDL_fmod SDL_fmod_REAL
 #define SDL_fmodf SDL_fmodf_REAL
 #define SDL_free SDL_free_REAL
+#define SDL_getenv SDL_getenv_REAL
 #define SDL_getenv_unsafe SDL_getenv_unsafe_REAL
 #define SDL_hid_ble_scan SDL_hid_ble_scan_REAL
 #define SDL_hid_close SDL_hid_close_REAL

+ 2 - 1
src/dynapi/SDL_dynapi_procs.h

@@ -284,7 +284,6 @@ SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetBasePath,(void),(),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_GetBooleanProperty,(SDL_PropertiesID a, const char *b, SDL_bool c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return)
-SDL_DYNAPI_PROC(int,SDL_GetNumLogicalCPUCores,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetCameraDriver,(int a),(a),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_GetCameraFormat,(SDL_Camera *a, SDL_CameraSpec *b),(a,b),return)
 SDL_DYNAPI_PROC(SDL_CameraID,SDL_GetCameraID,(SDL_Camera *a),(a),return)
@@ -459,6 +458,7 @@ SDL_DYNAPI_PROC(int,SDL_GetNumJoystickAxes,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickBalls,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickButtons,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumJoystickHats,(SDL_Joystick *a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_GetNumLogicalCPUCores,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumRenderDrivers,(void),(),return)
 SDL_DYNAPI_PROC(int,SDL_GetNumVideoDrivers,(void),(),return)
 SDL_DYNAPI_PROC(Sint64,SDL_GetNumberProperty,(SDL_PropertiesID a, const char *b, Sint64 c),(a,b,c),return)
@@ -1063,6 +1063,7 @@ SDL_DYNAPI_PROC(float,SDL_floorf,(float a),(a),return)
 SDL_DYNAPI_PROC(double,SDL_fmod,(double a, double b),(a,b),return)
 SDL_DYNAPI_PROC(float,SDL_fmodf,(float a, float b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_free,(void *a),(a),)
+SDL_DYNAPI_PROC(const char*,SDL_getenv,(const char *a),(a),return)
 SDL_DYNAPI_PROC(const char*,SDL_getenv_unsafe,(const char *a),(a),return)
 SDL_DYNAPI_PROC(void,SDL_hid_ble_scan,(SDL_bool a),(a),)
 SDL_DYNAPI_PROC(int,SDL_hid_close,(SDL_hid_device *a),(a),return)

+ 1 - 1
src/filesystem/cocoa/SDL_sysfilesystem.m

@@ -144,7 +144,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder)
 
         switch (folder) {
         case SDL_FOLDER_HOME:
-            base = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+            base = SDL_getenv("HOME");
 
             if (!base) {
                 SDL_SetError("No $HOME environment variable available");

+ 1 - 1
src/filesystem/emscripten/SDL_sysfilesystem.c

@@ -93,7 +93,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder)
         return NULL;
     }
 
-    home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+    home = SDL_getenv("HOME");
     if (!home) {
         SDL_SetError("No $HOME environment variable available");
         return NULL;

+ 2 - 2
src/filesystem/haiku/SDL_sysfilesystem.cc

@@ -68,7 +68,7 @@ char *SDL_SYS_GetBasePath(void)
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     // !!! FIXME: is there a better way to do this?
-    const char *home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+    const char *home = SDL_getenv("HOME");
     const char *append = "/config/settings/";
     size_t len = SDL_strlen(home);
 
@@ -102,7 +102,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder)
     const char *home = NULL;
     char *result;
 
-    home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+    home = SDL_getenv("HOME");
     if (!home) {
         SDL_SetError("No $HOME environment variable available");
         return NULL;

+ 8 - 8
src/filesystem/unix/SDL_sysfilesystem.c

@@ -74,7 +74,7 @@ static char *readSymLink(const char *path)
 #ifdef SDL_PLATFORM_OPENBSD
 static char *search_path_for_binary(const char *bin)
 {
-    const char *envr_real = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "PATH");
+    const char *envr_real = SDL_getenv("PATH");
     char *envr;
     size_t alloc_size;
     char *exe = NULL;
@@ -163,7 +163,7 @@ char *SDL_SYS_GetBasePath(void)
             exe = search_path_for_binary(cmdline[0]);
         } else {
             if (exe && *exe == '.') {
-                const char *pwd = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "PWD");
+                const char *pwd = SDL_getenv("PWD");
                 if (pwd && *pwd) {
                     SDL_asprintf(&pwddst, "%s/%s", pwd, exe);
                 }
@@ -265,7 +265,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app)
      *
      * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
      */
-    const char *envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_DATA_HOME");
+    const char *envr = SDL_getenv("XDG_DATA_HOME");
     const char *append;
     char *result = NULL;
     char *ptr = NULL;
@@ -281,7 +281,7 @@ char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 
     if (!envr) {
         // You end up with "$HOME/.local/share/Game Name 2"
-        envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+        envr = SDL_getenv("HOME");
         if (!envr) {
             // we could take heroic measures with /etc/passwd, but oh well.
             SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set");
@@ -368,12 +368,12 @@ static char *xdg_user_dir_lookup_with_fallback (const char *type, const char *fa
   int relative;
   size_t l;
 
-  home_dir = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+  home_dir = SDL_getenv("HOME");
 
   if (!home_dir)
     goto error;
 
-  config_home = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_CONFIG_HOME");
+  config_home = SDL_getenv("XDG_CONFIG_HOME");
   if (!config_home || config_home[0] == 0)
     {
       l = SDL_strlen (home_dir) + SDL_strlen ("/.config/user-dirs.dirs") + 1;
@@ -495,7 +495,7 @@ static char *xdg_user_dir_lookup (const char *type)
     if (dir)
         return dir;
 
-    home_dir = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+    home_dir = SDL_getenv("HOME");
 
     if (!home_dir)
         return NULL;
@@ -533,7 +533,7 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder)
     */
     switch(folder) {
     case SDL_FOLDER_HOME:
-        param = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "HOME");
+        param = SDL_getenv("HOME");
 
         if (!param) {
             SDL_SetError("No $HOME environment variable available");

+ 1 - 1
src/haptic/SDL_haptic.c

@@ -537,7 +537,7 @@ SDL_bool SDL_SetHapticGain(SDL_Haptic *haptic, int gain)
     }
 
     // The user can use an environment variable to override the max gain.
-    env = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_HAPTIC_GAIN_MAX");
+    env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
     if (env) {
         max_gain = SDL_atoi(env);
 

+ 2 - 2
src/locale/unix/SDL_syslocale.c

@@ -78,13 +78,13 @@ bool SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
     *tmp = '\0';
 
     // LANG is the primary locale (maybe)
-    envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG");
+    envr = SDL_getenv("LANG");
     if (envr) {
         SDL_strlcpy(tmp, envr, buflen);
     }
 
     // fallback languages
-    envr = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANGUAGE");
+    envr = SDL_getenv("LANGUAGE");
     if (envr) {
         if (*tmp) {
             SDL_strlcat(tmp, ":", buflen);

+ 285 - 269
src/stdlib/SDL_getenv.c

@@ -20,7 +20,6 @@
 */
 #include "SDL_internal.h"
 
-#include "SDL_getenv_c.h"
 #include "../SDL_hashtable.h"
 
 #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
@@ -37,11 +36,6 @@
       (defined(HAVE_SETENV) || defined(HAVE_PUTENV)) && \
       (defined(HAVE_UNSETENV) || defined(HAVE_PUTENV))
 #define HAVE_LIBC_ENVIRONMENT
-#else
-#define HAVE_LOCAL_ENVIRONMENT
-#endif
-
-#if !defined(SDL_PLATFORM_WINDOWS)
 #if defined(SDL_PLATFORM_MACOS)
 #include <crt_externs.h>
 #define environ (*_NSGetEnviron())
@@ -51,7 +45,253 @@
 #else
 extern char **environ;
 #endif
-#endif // !SDL_PLATFORM_WINDOWS
+#else
+#define HAVE_LOCAL_ENVIRONMENT
+static char **environ;
+#endif
+
+
+struct SDL_Environment
+{
+    SDL_Mutex *lock;
+    SDL_HashTable *strings;
+};
+static SDL_Environment *SDL_environment;
+
+SDL_Environment *SDL_GetEnvironment(void)
+{
+    if (!SDL_environment) {
+        SDL_environment = SDL_CreateEnvironment(true);
+    }
+    return SDL_environment;
+}
+
+void SDL_CleanupEnvironment(void)
+{
+    SDL_Environment *env = SDL_environment;
+
+    if (env) {
+        SDL_environment = NULL;
+        SDL_DestroyEnvironment(env);
+    }
+}
+
+SDL_Environment *SDL_CreateEnvironment(SDL_bool populated)
+{
+    SDL_Environment *env = SDL_calloc(1, sizeof(*env));
+    if (!env) {
+        return NULL;
+    }
+
+    env->strings = SDL_CreateHashTable(NULL, 16, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeKey, false);
+    if (!env->strings) {
+        SDL_free(env);
+        return NULL;
+    }
+
+    // Don't fail if we can't create a mutex (e.g. on a single-thread environment)
+    env->lock = SDL_CreateMutex();
+
+    if (populated) {
+#ifdef SDL_PLATFORM_WINDOWS
+        LPWCH strings = GetEnvironmentStringsW();
+        if (strings) {
+            for (LPWCH string = strings; *string; string += SDL_wcslen(string) + 1) {
+                char *variable = WIN_StringToUTF8W(string);
+                if (!variable) {
+                    continue;
+                }
+
+                char *value = SDL_strchr(variable, '=');
+                if (!value || value == variable) {
+                    SDL_free(variable);
+                    continue;
+                }
+                *value++ = '\0';
+
+                SDL_InsertIntoHashTable(env->strings, variable, value);
+            }
+            FreeEnvironmentStringsW(strings);
+        }
+#else
+#ifdef SDL_PLATFORM_ANDROID
+        // Make sure variables from the application manifest are available
+        Android_JNI_GetManifestEnvironmentVariables();
+#endif
+        char **strings = environ;
+        if (strings) {
+            for (int i = 0; strings[i]; ++i) {
+                char *variable = SDL_strdup(strings[i]);
+                if (!variable) {
+                    continue;
+                }
+
+                char *value = SDL_strchr(variable, '=');
+                if (!value || value == variable) {
+                    SDL_free(variable);
+                    continue;
+                }
+                *value++ = '\0';
+
+                SDL_InsertIntoHashTable(env->strings, variable, value);
+            }
+        }
+#endif // SDL_PLATFORM_WINDOWS
+    }
+
+    return env;
+}
+
+const char *SDL_GetEnvironmentVariable(SDL_Environment *env, const char *name)
+{
+    const char *result = NULL;
+
+    if (!env) {
+        return NULL;
+    } else if (!name || *name == '\0') {
+        return NULL;
+    }
+
+    SDL_LockMutex(env->lock);
+    {
+        const char *value;
+
+        if (SDL_FindInHashTable(env->strings, name, (const void **)&value)) {
+            result = SDL_GetPersistentString(value);
+        }
+    }
+    SDL_UnlockMutex(env->lock);
+
+    return result;
+}
+
+char **SDL_GetEnvironmentVariables(SDL_Environment *env)
+{
+    char **result = NULL;
+
+    if (!env) {
+        SDL_InvalidParamError("env");
+        return NULL;
+    }
+
+    SDL_LockMutex(env->lock);
+    {
+        size_t count, length = 0;
+        void *iter;
+        const char *key, *value;
+
+        // First pass, get the size we need for all the strings
+        count = 0;
+        iter = NULL;
+        while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) {
+            length += SDL_strlen(key) + 1 + SDL_strlen(value) + 1;
+            ++count;
+        }
+
+        // Allocate memory for the strings
+        result = (char **)SDL_malloc((count + 1) * sizeof(*result) + length);
+        char *string = (char *)(result + count + 1);
+
+        // Second pass, copy the strings
+        count = 0;
+        iter = NULL;
+        while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) {
+            size_t len;
+
+            result[count] = string;
+            len = SDL_strlen(key);
+            SDL_memcpy(string, key, len);
+            string += len;
+            *string++ = '=';
+            len = SDL_strlen(value);
+            SDL_memcpy(string, value, len);
+            string += len;
+            *string++ = '\0';
+            ++count;
+        }
+        result[count] = NULL;
+    }
+    SDL_UnlockMutex(env->lock);
+
+    return result;
+}
+
+SDL_bool SDL_SetEnvironmentVariable(SDL_Environment *env, const char *name, const char *value, SDL_bool overwrite)
+{
+    bool result = false;
+
+    if (!env) {
+        return SDL_InvalidParamError("env");
+    } else if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) {
+        return SDL_InvalidParamError("name");
+    } else if (!value) {
+        return SDL_InvalidParamError("value");
+    }
+
+    SDL_LockMutex(env->lock);
+    {
+        const void *existing_value;
+        bool insert = true;
+
+        if (SDL_FindInHashTable(env->strings, name, &existing_value)) {
+            if (!overwrite) {
+                result = true;
+                insert = false;
+            } else {
+                SDL_RemoveFromHashTable(env->strings, name);
+            }
+        }
+
+        if (insert) {
+            char *string = NULL;
+            if (SDL_asprintf(&string, "%s=%s", name, value) > 0) {
+                size_t len = SDL_strlen(name);
+                string[len] = '\0';
+                name = string;
+                value = string + len + 1;
+                result = SDL_InsertIntoHashTable(env->strings, name, value);
+            }
+        }
+    }
+    SDL_UnlockMutex(env->lock);
+
+    return result;
+}
+
+SDL_bool SDL_UnsetEnvironmentVariable(SDL_Environment *env, const char *name)
+{
+    bool result = false;
+
+    if (!env) {
+        return SDL_InvalidParamError("env");
+    } else if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) {
+        return SDL_InvalidParamError("name");
+    }
+
+    SDL_LockMutex(env->lock);
+    {
+        const void *value;
+        if (SDL_FindInHashTable(env->strings, name, &value)) {
+            result = SDL_RemoveFromHashTable(env->strings, name);
+        } else {
+            result = true;
+        }
+    }
+    SDL_UnlockMutex(env->lock);
+
+    return result;
+}
+
+void SDL_DestroyEnvironment(SDL_Environment *env)
+{
+    if (!env || env == SDL_environment) {
+        return;
+    }
+
+    SDL_DestroyMutex(env->lock);
+    SDL_DestroyHashTable(env->strings);
+    SDL_free(env);
+}
 
 // Put a variable into the environment
 // Note: Name may not contain a '=' character. (Reference: http://www.unix.com/man-page/Linux/3/setenv/)
@@ -64,6 +304,8 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
         return -1;
     }
 
+    SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0));
+
     return setenv(name, value, overwrite);
 }
 // We have a real environment table, but no real setenv? Fake it w/ putenv.
@@ -77,6 +319,8 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
         return -1;
     }
 
+    SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0));
+
     if (getenv(name) != NULL) {
         if (!overwrite) {
             return 0; // leave the existing one there.
@@ -99,6 +343,8 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
         return -1;
     }
 
+    SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0));
+
     if (!overwrite) {
         if (GetEnvironmentVariableA(name, NULL, 0) > 0) {
             return 0; // asked not to overwrite existing value.
@@ -111,9 +357,6 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
 }
 #else // roll our own
 
-// We'll leak this, as environment variables are intended to persist past SDL_Quit()
-static char **SDL_env;
-
 int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
 {
     int added;
@@ -131,6 +374,8 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
         return 0;
     }
 
+    SDL_SetEnvironmentVariable(SDL_GetEnvironment(), name, value, (overwrite != 0));
+
     // Allocate memory for the variable
     len = SDL_strlen(name) + SDL_strlen(value) + 2;
     new_variable = (char *)SDL_malloc(len);
@@ -145,14 +390,14 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
     // Actually put it into the environment
     added = 0;
     i = 0;
-    if (SDL_env) {
+    if (environ) {
         // Check to see if it's already there...
         len = (value - name);
-        for (; SDL_env[i]; ++i) {
-            if (SDL_strncmp(SDL_env[i], name, len) == 0) {
+        for (; environ[i]; ++i) {
+            if (SDL_strncmp(environ[i], name, len) == 0) {
                 // If we found it, just replace the entry
-                SDL_free(SDL_env[i]);
-                SDL_env[i] = new_variable;
+                SDL_free(environ[i]);
+                environ[i] = new_variable;
                 added = 1;
                 break;
             }
@@ -161,11 +406,11 @@ int SDL_setenv_unsafe(const char *name, const char *value, int overwrite)
 
     // Didn't find it in the environment, expand and add
     if (!added) {
-        new_env = SDL_realloc(SDL_env, (i + 2) * sizeof(char *));
+        new_env = SDL_realloc(environ, (i + 2) * sizeof(char *));
         if (new_env) {
-            SDL_env = new_env;
-            SDL_env[i++] = new_variable;
-            SDL_env[i++] = (char *)0;
+            environ = new_env;
+            environ[i++] = new_variable;
+            environ[i++] = (char *)0;
             added = 1;
         } else {
             SDL_free(new_variable);
@@ -184,6 +429,8 @@ int SDL_unsetenv_unsafe(const char *name)
         return -1;
     }
 
+    SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name);
+
     return unsetenv(name);
 }
 // We have a real environment table, but no unsetenv? Fake it w/ putenv.
@@ -195,6 +442,8 @@ int SDL_unsetenv_unsafe(const char *name)
         return -1;
     }
 
+    SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name);
+
     // Hope this environment uses the non-standard extension of removing the environment variable if it has no '='
     return putenv(name);
 }
@@ -207,6 +456,8 @@ int SDL_unsetenv_unsafe(const char *name)
         return -1;
     }
 
+    SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name);
+
     if (!SetEnvironmentVariableA(name, NULL)) {
         return -1;
     }
@@ -222,13 +473,15 @@ int SDL_unsetenv_unsafe(const char *name)
         return -1;
     }
 
-    if (SDL_env) {
+    SDL_UnsetEnvironmentVariable(SDL_GetEnvironment(), name);
+
+    if (environ) {
         len = SDL_strlen(name);
-        for (i = 0; SDL_env[i]; ++i) {
-            if ((SDL_strncmp(SDL_env[i], name, len) == 0) &&
-                (SDL_env[i][len] == '=')) {
+        for (i = 0; environ[i]; ++i) {
+            if ((SDL_strncmp(environ[i], name, len) == 0) &&
+                (environ[i][len] == '=')) {
                 // Just clear out this entry for now
-                *SDL_env[i] = '\0';
+                *environ[i] = '\0';
                 break;
             }
         }
@@ -296,20 +549,19 @@ const char *SDL_getenv_unsafe(const char *name)
 const char *SDL_getenv_unsafe(const char *name)
 {
     size_t len, i;
-    char *value;
+    const char *value = NULL;
 
     // Input validation
     if (!name || *name == '\0') {
         return NULL;
     }
 
-    value = (char *)0;
-    if (SDL_env) {
+    if (environ) {
         len = SDL_strlen(name);
-        for (i = 0; SDL_env[i]; ++i) {
-            if ((SDL_strncmp(SDL_env[i], name, len) == 0) &&
-                (SDL_env[i][len] == '=')) {
-                value = &SDL_env[i][len + 1];
+        for (i = 0; environ[i]; ++i) {
+            if ((SDL_strncmp(environ[i], name, len) == 0) &&
+                (environ[i][len] == '=')) {
+                value = &environ[i][len + 1];
                 break;
             }
         }
@@ -318,243 +570,7 @@ const char *SDL_getenv_unsafe(const char *name)
 }
 #endif // HAVE_LIBC_ENVIRONMENT
 
-
-struct SDL_Environment
-{
-    SDL_Mutex *lock;
-    SDL_HashTable *strings;
-};
-static SDL_Environment *SDL_environment;
-
-SDL_Environment *SDL_GetEnvironment(void)
-{
-    if (!SDL_environment) {
-        SDL_environment = SDL_CreateEnvironment(true);
-    }
-    return SDL_environment;
-}
-
-void SDL_CleanupEnvironment(void)
-{
-    SDL_Environment *env = SDL_environment;
-
-    if (env) {
-        SDL_environment = NULL;
-        SDL_DestroyEnvironment(env);
-    }
-}
-
-SDL_Environment *SDL_CreateEnvironment(SDL_bool populated)
-{
-    SDL_Environment *env = SDL_calloc(1, sizeof(*env));
-    if (!env) {
-        return NULL;
-    }
-
-    env->strings = SDL_CreateHashTable(NULL, 16, SDL_HashString, SDL_KeyMatchString, SDL_NukeFreeKey, false);
-    if (!env->strings) {
-        SDL_free(env);
-        return NULL;
-    }
-
-    // Don't fail if we can't create a mutex (e.g. on a single-thread environment)
-    env->lock = SDL_CreateMutex();
-
-    if (populated) {
-#ifdef SDL_PLATFORM_WINDOWS
-        LPWCH strings = GetEnvironmentStringsW();
-        if (strings) {
-            for (LPWCH string = strings; *string; string += SDL_wcslen(string) + 1) {
-                char *variable = WIN_StringToUTF8W(string);
-                if (!variable) {
-                    continue;
-                }
-
-                char *value = SDL_strchr(variable, '=');
-                if (!value || value == variable) {
-                    SDL_free(variable);
-                    continue;
-                }
-                *value++ = '\0';
-
-                SDL_InsertIntoHashTable(env->strings, variable, value);
-            }
-            FreeEnvironmentStringsW(strings);
-        }
-#else
-#ifdef SDL_PLATFORM_ANDROID
-        // Make sure variables from the application manifest are available
-        Android_JNI_GetManifestEnvironmentVariables();
-#endif
-        char **strings = environ;
-        for (int i = 0; strings[i]; ++i) {
-            char *variable = SDL_strdup(strings[i]);
-            if (!variable) {
-                continue;
-            }
-
-            char *value = SDL_strchr(variable, '=');
-            if (!value || value == variable) {
-                SDL_free(variable);
-                continue;
-            }
-            *value++ = '\0';
-
-            SDL_InsertIntoHashTable(env->strings, variable, value);
-        }
-#endif // SDL_PLATFORM_WINDOWS
-    }
-
-    return env;
-}
-
-const char *SDL_GetEnvironmentVariable(SDL_Environment *env, const char *name)
-{
-    const char *result = NULL;
-
-    if (!env) {
-        return NULL;
-    } else if (!name || *name == '\0') {
-        return NULL;
-    }
-
-    SDL_LockMutex(env->lock);
-    {
-        const char *value;
-
-        if (SDL_FindInHashTable(env->strings, name, (const void **)&value)) {
-            result = SDL_GetPersistentString(value);
-        }
-    }
-    SDL_UnlockMutex(env->lock);
-
-    return result;
-}
-
-char **SDL_GetEnvironmentVariables(SDL_Environment *env)
-{
-    char **result = NULL;
-
-    if (!env) {
-        SDL_InvalidParamError("env");
-        return NULL;
-    }
-
-    SDL_LockMutex(env->lock);
-    {
-        size_t count, length = 0;
-        void *iter;
-        const char *key, *value;
-
-        // First pass, get the size we need for all the strings
-        count = 0;
-        iter = NULL;
-        while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) {
-            length += SDL_strlen(key) + 1 + SDL_strlen(value) + 1;
-            ++count;
-        }
-
-        // Allocate memory for the strings
-        result = (char **)SDL_malloc((count + 1) * sizeof(*result) + length);
-        char *string = (char *)(result + count + 1);
-
-        // Second pass, copy the strings
-        count = 0;
-        iter = NULL;
-        while (SDL_IterateHashTable(env->strings, (const void **)&key, (const void **)&value, &iter)) {
-            size_t len;
-
-            result[count] = string;
-            len = SDL_strlen(key);
-            SDL_memcpy(string, key, len);
-            string += len;
-            *string++ = '=';
-            len = SDL_strlen(value);
-            SDL_memcpy(string, value, len);
-            string += len;
-            *string++ = '\0';
-            ++count;
-        }
-        result[count] = NULL;
-    }
-    SDL_UnlockMutex(env->lock);
-
-    return result;
-}
-
-SDL_bool SDL_SetEnvironmentVariable(SDL_Environment *env, const char *name, const char *value, SDL_bool overwrite)
+const char *SDL_getenv(const char *name)
 {
-    bool result = false;
-
-    if (!env) {
-        return SDL_InvalidParamError("env");
-    } else if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) {
-        return SDL_InvalidParamError("name");
-    } else if (!value) {
-        return SDL_InvalidParamError("value");
-    }
-
-    SDL_LockMutex(env->lock);
-    {
-        const void *existing_value;
-        bool insert = true;
-
-        if (SDL_FindInHashTable(env->strings, name, &existing_value)) {
-            if (!overwrite) {
-                result = true;
-                insert = false;
-            } else {
-                SDL_RemoveFromHashTable(env->strings, name);
-            }
-        }
-
-        if (insert) {
-            char *string = NULL;
-            if (SDL_asprintf(&string, "%s=%s", name, value) > 0) {
-                size_t len = SDL_strlen(name);
-                string[len] = '\0';
-                name = string;
-                value = string + len + 1;
-                result = SDL_InsertIntoHashTable(env->strings, name, value);
-            }
-        }
-    }
-    SDL_UnlockMutex(env->lock);
-
-    return result;
-}
-
-SDL_bool SDL_UnsetEnvironmentVariable(SDL_Environment *env, const char *name)
-{
-    bool result = false;
-
-    if (!env) {
-        return SDL_InvalidParamError("env");
-    } else if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL) {
-        return SDL_InvalidParamError("name");
-    }
-
-    SDL_LockMutex(env->lock);
-    {
-        const void *value;
-        if (SDL_FindInHashTable(env->strings, name, &value)) {
-            result = SDL_RemoveFromHashTable(env->strings, name);
-        } else {
-            result = true;
-        }
-    }
-    SDL_UnlockMutex(env->lock);
-
-    return result;
-}
-
-void SDL_DestroyEnvironment(SDL_Environment *env)
-{
-    if (!env || env == SDL_environment) {
-        return;
-    }
-
-    SDL_DestroyMutex(env->lock);
-    SDL_DestroyHashTable(env->strings);
-    SDL_free(env);
+    return SDL_GetEnvironmentVariable(SDL_GetEnvironment(), name);
 }

+ 0 - 23
src/stdlib/SDL_getenv_c.h

@@ -1,23 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-#include "SDL_internal.h"
-
-extern void SDL_FreeEnvironmentMemory(void);

+ 4 - 4
src/stdlib/SDL_iconv.c

@@ -163,15 +163,15 @@ static const char *getlocale(char *buffer, size_t bufsize)
     const char *lang;
     char *ptr;
 
-    lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_ALL");
+    lang = SDL_getenv("LC_ALL");
     if (!lang) {
-        lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_CTYPE");
+        lang = SDL_getenv("LC_CTYPE");
     }
     if (!lang) {
-        lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_MESSAGES");
+        lang = SDL_getenv("LC_MESSAGES");
     }
     if (!lang) {
-        lang = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG");
+        lang = SDL_getenv("LANG");
     }
     if (!lang || !*lang || SDL_strcmp(lang, "C") == 0) {
         lang = "ASCII";

+ 2 - 2
src/video/SDL_egl.c

@@ -341,7 +341,7 @@ static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_
 
 #if !defined(SDL_VIDEO_STATIC_ANGLE) && !defined(SDL_VIDEO_DRIVER_VITA)
     /* A funny thing, loading EGL.so first does not work on the Raspberry, so we load libGL* first */
-    path = SDL_getenv_unsafe("SDL_VIDEO_GL_DRIVER");
+    path = SDL_getenv("SDL_VIDEO_GL_DRIVER");
     if (path) {
         opengl_dll_handle = SDL_LoadObject(path);
     }
@@ -401,7 +401,7 @@ static bool SDL_EGL_LoadLibraryInternal(SDL_VideoDevice *_this, const char *egl_
         if (egl_dll_handle) {
             SDL_UnloadObject(egl_dll_handle);
         }
-        path = SDL_getenv_unsafe("SDL_VIDEO_EGL_DRIVER");
+        path = SDL_getenv("SDL_VIDEO_EGL_DRIVER");
         if (!path) {
             path = DEFAULT_EGL;
         }

+ 3 - 3
src/video/wayland/SDL_waylandevents.c

@@ -1292,11 +1292,11 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
      */
 
     // Look up the preferred locale, falling back to "C" as default
-    locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_ALL");
+    locale = SDL_getenv("LC_ALL");
     if (!locale) {
-        locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LC_CTYPE");
+        locale = SDL_getenv("LC_CTYPE");
         if (!locale) {
-            locale = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "LANG");
+            locale = SDL_getenv("LANG");
             if (!locale) {
                 locale = "C";
             }

+ 2 - 2
src/video/wayland/SDL_waylandmessagebox.c

@@ -85,8 +85,8 @@ bool Wayland_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *butto
     SDL_Process *process;
 
     // Are we trying to connect to or are currently in a Wayland session?
-    if (!SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "WAYLAND_DISPLAY")) {
-        const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE");
+    if (!SDL_getenv("WAYLAND_DISPLAY")) {
+        const char *session = SDL_getenv("XDG_SESSION_TYPE");
         if (session && SDL_strcasecmp(session, "wayland") != 0) {
             return SDL_SetError("Not on a wayland display");
         }

+ 2 - 2
src/video/wayland/SDL_waylandmouse.c

@@ -345,7 +345,7 @@ static bool wayland_get_system_cursor(SDL_VideoData *vdata, SDL_CursorData *cdat
 
     // Fallback envvar if the DBus properties don't exist
     if (size <= 0) {
-        const char *xcursor_size = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XCURSOR_SIZE");
+        const char *xcursor_size = SDL_getenv("XCURSOR_SIZE");
         if (xcursor_size) {
             size = SDL_atoi(xcursor_size);
         }
@@ -381,7 +381,7 @@ static bool wayland_get_system_cursor(SDL_VideoData *vdata, SDL_CursorData *cdat
 
         // Fallback envvar if the DBus properties don't exist
         if (!xcursor_theme) {
-            xcursor_theme = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XCURSOR_THEME");
+            xcursor_theme = SDL_getenv("XCURSOR_THEME");
         }
 
         theme = WAYLAND_wl_cursor_theme_load(xcursor_theme, size, vdata->shm);

+ 1 - 1
src/video/wayland/SDL_waylandshmbuffer.c

@@ -80,7 +80,7 @@ static int CreateTempFD(off_t size)
         const char *xdg_path;
         char tmp_path[PATH_MAX];
 
-        xdg_path = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_RUNTIME_DIR");
+        xdg_path = SDL_getenv("XDG_RUNTIME_DIR");
         if (!xdg_path) {
             return -1;
         }

+ 2 - 2
src/video/wayland/SDL_waylandvideo.c

@@ -429,8 +429,8 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols)
     bool display_is_external = !!display;
 
     // Are we trying to connect to or are currently in a Wayland session?
-    if (!SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "WAYLAND_DISPLAY")) {
-        const char *session = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_SESSION_TYPE");
+    if (!SDL_getenv("WAYLAND_DISPLAY")) {
+        const char *session = SDL_getenv("XDG_SESSION_TYPE");
         if (session && SDL_strcasecmp(session, "wayland") != 0) {
             return NULL;
         }

+ 1 - 1
src/video/wayland/SDL_waylandwindow.c

@@ -1914,7 +1914,7 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
         /* Note that we don't check for empty strings, as that is still
          * considered a valid activation token!
          */
-        const char *activation_token = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XDG_ACTIVATION_TOKEN");
+        const char *activation_token = SDL_getenv("XDG_ACTIVATION_TOKEN");
         if (activation_token) {
             xdg_activation_v1_activate(c->activation_manager,
                                        activation_token,

+ 1 - 1
src/video/x11/SDL_x11keyboard.c

@@ -169,7 +169,7 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this)
         char *prev_locale = setlocale(LC_ALL, NULL);
         char *prev_xmods = X11_XSetLocaleModifiers(NULL);
         const char *new_xmods = "";
-        const char *env_xmods = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "XMODIFIERS");
+        const char *env_xmods = SDL_getenv("XMODIFIERS");
         bool has_dbus_ime_support = false;
 
         if (prev_locale) {

+ 1 - 1
src/video/x11/SDL_x11modes.c

@@ -248,7 +248,7 @@ static float GetGlobalContentScale(SDL_VideoDevice *_this)
 
         // If that failed, try the GDK_SCALE envvar...
         if (scale_factor <= 0.0) {
-            const char *scale_str = SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "GDK_SCALE");
+            const char *scale_str = SDL_getenv("GDK_SCALE");
             if (scale_str) {
                 scale_factor = SDL_atoi(scale_str);
             }