diff --git a/glib/glib.symbols b/glib/glib.symbols
index a8b7b44..1436a12 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1549,6 +1549,7 @@ g_get_user_cache_dir
 g_get_user_config_dir
 g_get_user_data_dir
 g_get_user_special_dir
+g_get_user_named_dir
 #ifndef _WIN64
 g_get_user_name PRIVATE
 #endif
diff --git a/glib/gutils.c b/glib/gutils.c
index 858603b..34b5b7e 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -1465,6 +1465,7 @@ static  gchar   *g_user_config_dir = NULL;
 static  gchar  **g_system_config_dirs = NULL;
 
 static  gchar  **g_user_special_dirs = NULL;
+static  GHashTable *g_user_named_dirs = NULL;
 
 /* fifteen minutes of fame for everybody */
 #define G_USER_DIRS_EXPIRE      15 * 60
@@ -2366,6 +2367,7 @@ load_user_special_dirs (void)
     {
       gchar *buffer = lines[i];
       gchar *d, *p;
+      gchar *key;
       gint len;
       gboolean is_relative = FALSE;
       GUserDirectory directory;
@@ -2378,7 +2380,9 @@ load_user_special_dirs (void)
       p = buffer;
       while (*p == ' ' || *p == '\t')
 	p++;
-      
+
+      key = p;
+
       if (strncmp (p, "XDG_DESKTOP_DIR", strlen ("XDG_DESKTOP_DIR")) == 0)
         {
           directory = G_USER_DIRECTORY_DESKTOP;
@@ -2420,13 +2424,20 @@ load_user_special_dirs (void)
           p += strlen ("XDG_VIDEOS_DIR");
         }
       else
-	continue;
+        {
+          directory = G_USER_N_DIRECTORIES;
+          while (*p != '=' && *p != '\0')
+            p++;
+        }
 
       while (*p == ' ' || *p == '\t')
 	p++;
 
       if (*p != '=')
 	continue;
+
+      *p = '\0';
+
       p++;
 
       while (*p == ' ' || *p == '\t')
@@ -2455,14 +2466,22 @@ load_user_special_dirs (void)
       len = strlen (d);
       if (d[len - 1] == '/')
         d[len - 1] = 0;
-      
+
       if (is_relative)
         {
           g_get_any_init ();
-          g_user_special_dirs[directory] = g_build_filename (g_home_dir, d, NULL);
+          if (directory < G_USER_N_DIRECTORIES)
+            g_user_special_dirs[directory] = g_build_filename (g_home_dir, d, NULL);
+          g_hash_table_insert (g_user_named_dirs, g_strdup (key),
+            g_build_filename (g_home_dir, d, NULL));
         }
       else
-	g_user_special_dirs[directory] = g_strdup (d);
+        {
+          if (directory < G_USER_N_DIRECTORIES)
+            g_user_special_dirs[directory] = g_strdup (d);
+          g_hash_table_insert (g_user_named_dirs, g_strdup (key), g_strdup (d));
+        }
+
     }
 
   g_strfreev (lines);
@@ -2471,6 +2490,34 @@ load_user_special_dirs (void)
 
 #endif /* G_OS_UNIX && !HAVE_CARBON */
 
+static void
+g_ensure_user_special_dirs ()
+{
+  G_LOCK (g_utils_global);
+
+  if (G_UNLIKELY (g_user_special_dirs == NULL))
+    {
+      g_user_named_dirs = g_hash_table_new_full (
+        g_str_hash, g_str_equal, g_free, g_free);
+      g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
+
+      load_user_special_dirs ();
+
+      /* Special-case desktop for historical compatibility */
+      if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
+        {
+          g_get_any_init ();
+
+          g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] =
+            g_build_filename (g_home_dir, "Desktop", NULL);
+          g_hash_table_insert (g_user_named_dirs, g_strdup ("XDG_DESKTOP_DIR"),
+            g_build_filename (g_home_dir, "Desktop", NULL));
+        }
+    }
+
+  G_UNLOCK (g_utils_global);
+}
+
 /**
  * g_get_user_special_dir:
  * @directory: the logical id of special directory
@@ -2482,9 +2529,7 @@ load_user_special_dirs (void)
  * falls back to <filename>$HOME/Desktop</filename> when XDG special
  * user directories have not been set up. 
  *
- * Depending on the platform, the user might be able to change the path
- * of the special directory without requiring the session to restart; GLib
- * will not reflect any change once the special directories are loaded.
+ * See g_get_user_named_dir() for a more generic version of this function.
  *
  * Return value: the path to the specified special directory, or %NULL
  *   if the logical id was not found. The returned string is owned by
@@ -2498,27 +2543,37 @@ g_get_user_special_dir (GUserDirectory directory)
   g_return_val_if_fail (directory >= G_USER_DIRECTORY_DESKTOP &&
                         directory < G_USER_N_DIRECTORIES, NULL);
 
-  G_LOCK (g_utils_global);
-
-  if (G_UNLIKELY (g_user_special_dirs == NULL))
-    {
-      g_user_special_dirs = g_new0 (gchar *, G_USER_N_DIRECTORIES);
-
-      load_user_special_dirs ();
+  g_ensure_user_special_dirs ();
 
-      /* Special-case desktop for historical compatibility */
-      if (g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] == NULL)
-        {
-          g_get_any_init ();
-
-          g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] =
-            g_build_filename (g_home_dir, "Desktop", NULL);
-        }
-    }
+  return g_user_special_dirs[directory];
+}
 
-  G_UNLOCK (g_utils_global);
+/**
+ * g_get_user_named_dir:
+ * @directory: the string id of a named directory
+ *
+ * Returns the full path of a named directory using its string id, such
+ * as for example "XDG_DOWNLOAD_DIR".
+ *
+ * On Unix this is done through the XDG special user directories which
+ * are read from ~/.config/user-dirs.dir and /etc/xdg/user-dirs.conf.
+ *
+ * Depending on the platform, the user might be able to change the path
+ * of the special directory without requiring the session to restart; GLib
+ * will not reflect any change once the special directories are loaded.
+ *
+ * Return value: the path to the specified special directory, or %NULL
+ *   if the string id was not found. The returned string is owned by
+ *   GLib and should not be modified or freed.
+ *
+ * Since: 2.22
+ */
+G_CONST_RETURN gchar *
+g_get_user_named_dir (const gchar* directory)
+{
+  g_ensure_user_special_dirs ();
 
-  return g_user_special_dirs[directory];
+  return g_hash_table_lookup (g_user_named_dirs, directory);
 }
 
 #ifdef G_OS_WIN32
diff --git a/glib/gutils.h b/glib/gutils.h
index 68a27ed..68c08ef 100644
--- a/glib/gutils.h
+++ b/glib/gutils.h
@@ -191,6 +191,8 @@ typedef enum {
 
 G_CONST_RETURN gchar* g_get_user_special_dir (GUserDirectory directory);
 
+G_CONST_RETURN gchar* g_get_user_named_dir (const gchar* directory);
+
 typedef struct _GDebugKey	GDebugKey;
 struct _GDebugKey
 {
