Updated Norwegian bokmål translation.
[platform/upstream/glib.git] / glib / gutils.c
index 1eee8b2..858603b 100644 (file)
@@ -40,6 +40,8 @@
 #include <string.h>
 #include <ctype.h>             /* For tolower() */
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
@@ -58,6 +60,7 @@
 #include "glib.h"
 #include "gprintfint.h"
 #include "gthreadprivate.h"
+#include "glibintl.h"
 #include "galias.h"
 
 #ifdef MAXPATHLEN
 #  include <direct.h>
 #  include <shlobj.h>
    /* older SDK (e.g. msvc 5.0) does not have these*/
+#  ifndef CSIDL_MYMUSIC
+#    define CSIDL_MYMUSIC 13
+#  endif
+#  ifndef CSIDL_MYVIDEO
+#    define CSIDL_MYVIDEO 14
+#  endif
 #  ifndef CSIDL_INTERNET_CACHE
 #    define CSIDL_INTERNET_CACHE 32
 #  endif
 #  ifndef CSIDL_COMMON_APPDATA
 #    define CSIDL_COMMON_APPDATA 35
 #  endif
+#  ifndef CSIDL_MYPICTURES
+#    define CSIDL_MYPICTURES 0x27
+#  endif
 #  ifndef CSIDL_COMMON_DOCUMENTS
 #    define CSIDL_COMMON_DOCUMENTS 46
 #  endif
 #  include <process.h>
 #endif
 
-#ifdef HAVE_CODESET
-#include <langinfo.h>
+#ifdef HAVE_CARBON
+#include <CoreServices/CoreServices.h>
 #endif
 
-#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
-#include <libintl.h>
+#ifdef HAVE_CODESET
+#include <langinfo.h>
 #endif
 
 const guint glib_major_version = GLIB_MAJOR_VERSION;
@@ -116,7 +128,59 @@ const guint glib_binary_age = GLIB_BINARY_AGE;
 
 #ifdef G_PLATFORM_WIN32
 
-G_WIN32_DLLMAIN_FOR_DLL_NAME (static, dll_name)
+static HMODULE glib_dll = NULL;
+
+#ifdef DLL_EXPORT
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+        DWORD     fdwReason,
+        LPVOID    lpvReserved)
+{
+  if (fdwReason == DLL_PROCESS_ATTACH)
+      glib_dll = hinstDLL;
+
+  return TRUE;
+}
+
+#endif
+
+gchar *
+_glib_get_dll_directory (void)
+{
+  gchar *retval;
+  gchar *p;
+  wchar_t wc_fn[MAX_PATH];
+
+#ifdef DLL_EXPORT
+  if (glib_dll == NULL)
+    return NULL;
+#endif
+
+  /* This code is different from that in
+   * g_win32_get_package_installation_directory_of_module() in that
+   * here we return the actual folder where the GLib DLL is. We don't
+   * do the check for it being in a "bin" or "lib" subfolder and then
+   * returning the parent of that.
+   *
+   * In a statically built GLib, glib_dll will be NULL and we will
+   * thus look up the application's .exe file's location.
+   */
+  if (!GetModuleFileNameW (glib_dll, wc_fn, MAX_PATH))
+    return NULL;
+
+  retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL);
+
+  p = strrchr (retval, G_DIR_SEPARATOR);
+  if (p == NULL)
+    {
+      /* Wtf? */
+      return NULL;
+    }
+  *p = '\0';
+
+  return retval;
+}
 
 #endif
 
@@ -551,7 +615,7 @@ debug_key_matches (const gchar *key,
 /**
  * g_parse_debug_string:
  * @string: a list of debug options separated by colons, spaces, or
- * commas; or the string "all" to set all flags.
+ * commas, or %NULL.
  * @keys: pointer to an array of #GDebugKey which associate 
  *     strings with bit flags.
  * @nkeys: the number of #GDebugKey<!-- -->s in the array.
@@ -561,6 +625,10 @@ debug_key_matches (const gchar *key,
  * within GDK and GTK+ to parse the debug options passed on the
  * command line or through environment variables.
  *
+ * If @string is equal to "all", all flags are set.  If @string
+ * is equal to "help", all the available keys in @keys are printed
+ * out to standard error.
+ *
  * Returns: the combined set of bit flags.
  */
 guint       
@@ -571,7 +639,8 @@ g_parse_debug_string  (const gchar     *string,
   guint i;
   guint result = 0;
   
-  g_return_val_if_fail (string != NULL, 0);
+  if (string == NULL)
+    return 0;
 
   /* this function is used by gmem.c/gslice.c initialization code,
    * so introducing malloc dependencies here would require adaptions
@@ -583,6 +652,14 @@ g_parse_debug_string  (const gchar     *string,
       for (i=0; i<nkeys; i++)
        result |= keys[i].value;
     }
+  else if (!g_ascii_strcasecmp (string, "help"))
+    {
+      /* using stdio directly for the reason stated above */
+      fprintf (stderr, "Supported debug values: ");
+      for (i=0; i<nkeys; i++)
+       fprintf (stderr, " %s", keys[i].key);
+      fprintf (stderr, "\n");
+    }
   else
     {
       const gchar *p = string;
@@ -952,6 +1029,7 @@ g_get_current_dir (void)
 #else  /* !sun || !HAVE_GETCWD */
   while (max_len < G_MAXULONG / 2)
     {
+      g_free (buffer);
       buffer = g_new (gchar, max_len + 1);
       *buffer = 0;
       dir = getcwd (buffer, max_len);
@@ -959,7 +1037,6 @@ g_get_current_dir (void)
       if (dir || errno != ERANGE)
        break;
 
-      g_free (buffer);
       max_len *= 2;
     }
 #endif /* !sun || !HAVE_GETCWD */
@@ -1387,15 +1464,17 @@ static  gchar   *g_user_cache_dir = NULL;
 static  gchar   *g_user_config_dir = NULL;
 static  gchar  **g_system_config_dirs = NULL;
 
+static  gchar  **g_user_special_dirs = NULL;
+
+/* fifteen minutes of fame for everybody */
+#define G_USER_DIRS_EXPIRE      15 * 60
+
 #ifdef G_OS_WIN32
 
 static gchar *
 get_special_folder (int csidl)
 {
-  union {
-    char c[MAX_PATH+1];
-    wchar_t wc[MAX_PATH+1];
-  } path;
+  wchar_t path[MAX_PATH+1];
   HRESULT hr;
   LPITEMIDLIST pidl = NULL;
   BOOL b;
@@ -1404,9 +1483,9 @@ get_special_folder (int csidl)
   hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
   if (hr == S_OK)
     {
-      b = SHGetPathFromIDListW (pidl, path.wc);
+      b = SHGetPathFromIDListW (pidl, path);
       if (b)
-       retval = g_utf16_to_utf8 (path.wc, -1, NULL, NULL, NULL);
+       retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL);
       CoTaskMemFree (pidl);
     }
   return retval;
@@ -1415,18 +1494,24 @@ get_special_folder (int csidl)
 static char *
 get_windows_directory_root (void)
 {
-  char windowsdir[MAX_PATH];
+  wchar_t wwindowsdir[MAX_PATH];
 
-  if (GetWindowsDirectory (windowsdir, sizeof (windowsdir)))
+  if (GetWindowsDirectoryW (wwindowsdir, G_N_ELEMENTS (wwindowsdir)))
     {
       /* Usually X:\Windows, but in terminal server environments
        * might be an UNC path, AFAIK.
        */
-      char *p = (char *) g_path_skip_root (windowsdir);
+      char *windowsdir = g_utf16_to_utf8 (wwindowsdir, -1, NULL, NULL, NULL);
+      char *p;
+
+      if (windowsdir == NULL)
+       return g_strdup ("C:\\");
+
+      p = (char *) g_path_skip_root (windowsdir);
       if (G_IS_DIR_SEPARATOR (p[-1]) && p[-2] != ':')
        p--;
       *p = '\0';
-      return g_strdup (windowsdir);
+      return windowsdir;
     }
   else
     return g_strdup ("C:\\");
@@ -1741,13 +1826,33 @@ g_get_real_name (void)
 /**
  * g_get_home_dir:
  *
- * Gets the current user's home directory. 
+ * Gets the current user's home directory as defined in the 
+ * password database.
  *
  * Note that in contrast to traditional UNIX tools, this function 
  * prefers <filename>passwd</filename> entries over the <envar>HOME</envar> 
- * environment variable.
- *
- * Returns: the current user's home directory.
+ * environment variable. 
+ *
+ * One of the reasons for this decision is that applications in many 
+ * cases need special handling to deal with the case where 
+ * <envar>HOME</envar> is
+ * <simplelist>
+ *   <member>Not owned by the user</member>
+ *   <member>Not writeable</member>
+ *   <member>Not even readable</member>
+ * </simplelist>
+ * Since applications are in general <emphasis>not</emphasis> written 
+ * to deal with these situations it was considered better to make 
+ * g_get_home_dir() not pay attention to <envar>HOME</envar> and to 
+ * return the real home directory for the user. If applications
+ * want to pay attention to <envar>HOME</envar>, they can do:
+ * |[
+ *  const char *homedir = g_getenv ("HOME");
+ *   if (!homedir)
+ *      homedir = g_get_home_dir (<!-- -->);
+ * ]|
+ *
+ * Returns: the current user's home directory
  */
 G_CONST_RETURN gchar*
 g_get_home_dir (void)
@@ -1918,6 +2023,7 @@ g_get_application_name (void)
  * The application name will be used in contexts such as error messages,
  * or when displaying an application's name in the task list.
  * 
+ * Since: 2.2
  **/
 void
 g_set_application_name (const gchar *application_name)
@@ -1988,26 +2094,10 @@ g_get_user_data_dir (void)
   return data_dir;
 }
 
-/**
- * g_get_user_config_dir:
- * 
- * Returns a base directory in which to store user-specific application 
- * configuration information such as user preferences and settings. 
- *
- * On UNIX platforms this is determined using the mechanisms described in
- * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
- * XDG Base Directory Specification</ulink>
- * 
- * Return value: a string owned by GLib that must not be modified 
- *               or freed.
- * Since: 2.6
- **/
-G_CONST_RETURN gchar*
-g_get_user_config_dir (void)
+static void
+g_init_user_config_dir (void)
 {
-  gchar *config_dir;  
-
-  G_LOCK (g_utils_global);
+  gchar *config_dir;
 
   if (!g_user_config_dir)
     {
@@ -2028,14 +2118,35 @@ g_get_user_config_dir (void)
          else
            config_dir = g_build_filename (g_tmp_dir, g_user_name, ".config", NULL);
        }
+
       g_user_config_dir = config_dir;
     }
-  else
-    config_dir = g_user_config_dir;
+}
+
+/**
+ * g_get_user_config_dir:
+ * 
+ * Returns a base directory in which to store user-specific application 
+ * configuration information such as user preferences and settings. 
+ *
+ * On UNIX platforms this is determined using the mechanisms described in
+ * the <ulink url="http://www.freedesktop.org/Standards/basedir-spec">
+ * XDG Base Directory Specification</ulink>
+ * 
+ * Return value: a string owned by GLib that must not be modified 
+ *               or freed.
+ * Since: 2.6
+ **/
+G_CONST_RETURN gchar*
+g_get_user_config_dir (void)
+{
+  G_LOCK (g_utils_global);
+
+  g_init_user_config_dir ();
 
   G_UNLOCK (g_utils_global);
 
-  return config_dir;
+  return g_user_config_dir;
 }
 
 /**
@@ -2088,6 +2199,328 @@ g_get_user_cache_dir (void)
   return cache_dir;
 }
 
+#ifdef HAVE_CARBON
+
+static gchar *
+find_folder (OSType type)
+{
+  gchar *filename = NULL;
+  FSRef  found;
+
+  if (FSFindFolder (kUserDomain, type, kDontCreateFolder, &found) == noErr)
+    {
+      CFURLRef url = CFURLCreateFromFSRef (kCFAllocatorSystemDefault, &found);
+
+      if (url)
+       {
+         CFStringRef path = CFURLCopyFileSystemPath (url, kCFURLPOSIXPathStyle);
+
+         if (path)
+           {
+             filename = g_strdup (CFStringGetCStringPtr (path, kCFStringEncodingUTF8));
+
+             if (! filename)
+               {
+                 filename = g_new0 (gchar, CFStringGetLength (path) * 3 + 1);
+
+                 CFStringGetCString (path, filename,
+                                     CFStringGetLength (path) * 3 + 1,
+                                     kCFStringEncodingUTF8);
+               }
+
+             CFRelease (path);
+           }
+
+         CFRelease (url);
+       }
+    }
+
+  return filename;
+}
+
+static void
+load_user_special_dirs (void)
+{
+  g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = find_folder (kDesktopFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = find_folder (kDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = find_folder (kDesktopFolderType); /* XXX correct ? */
+  g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = find_folder (kMusicDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = find_folder (kPictureDocumentsFolderType);
+  g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = NULL;
+  g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = NULL;
+  g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = find_folder (kMovieDocumentsFolderType);
+}
+
+#endif /* HAVE_CARBON */
+
+#if defined(G_OS_WIN32)
+static void
+load_user_special_dirs (void)
+{
+  typedef HRESULT (WINAPI *t_SHGetKnownFolderPath) (const GUID *rfid,
+                                                   DWORD dwFlags,
+                                                   HANDLE hToken,
+                                                   PWSTR *ppszPath);
+  t_SHGetKnownFolderPath p_SHGetKnownFolderPath;
+  static const GUID FOLDERID_Downloads =
+    { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } };
+  static const GUID FOLDERID_Public =
+    { 0xDFDF76A2, 0xC82A, 0x4D63, { 0x90, 0x6A, 0x56, 0x44, 0xAC, 0x45, 0x73, 0x85 } };
+  wchar_t *wcp;
+
+  p_SHGetKnownFolderPath = (t_SHGetKnownFolderPath) GetProcAddress (LoadLibrary ("shell32.dll"),
+                                                                   "SHGetKnownFolderPath");
+
+  g_user_special_dirs[G_USER_DIRECTORY_DESKTOP] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+  g_user_special_dirs[G_USER_DIRECTORY_DOCUMENTS] = get_special_folder (CSIDL_PERSONAL);
+
+  if (p_SHGetKnownFolderPath == NULL)
+    {
+      g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+    }
+  else
+    {
+      wcp = NULL;
+      (*p_SHGetKnownFolderPath) (&FOLDERID_Downloads, 0, NULL, &wcp);
+      g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+      if (g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] == NULL)
+       g_user_special_dirs[G_USER_DIRECTORY_DOWNLOAD] = get_special_folder (CSIDL_DESKTOPDIRECTORY);
+      CoTaskMemFree (wcp);
+    }
+
+  g_user_special_dirs[G_USER_DIRECTORY_MUSIC] = get_special_folder (CSIDL_MYMUSIC);
+  g_user_special_dirs[G_USER_DIRECTORY_PICTURES] = get_special_folder (CSIDL_MYPICTURES);
+
+  if (p_SHGetKnownFolderPath == NULL)
+    {
+      /* XXX */
+      g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+    }
+  else
+    {
+      wcp = NULL;
+      (*p_SHGetKnownFolderPath) (&FOLDERID_Public, 0, NULL, &wcp);
+      g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = g_utf16_to_utf8 (wcp, -1, NULL, NULL, NULL);
+      if (g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] == NULL)
+       g_user_special_dirs[G_USER_DIRECTORY_PUBLIC_SHARE] = get_special_folder (CSIDL_COMMON_DOCUMENTS);
+      CoTaskMemFree (wcp);
+    }
+  
+  g_user_special_dirs[G_USER_DIRECTORY_TEMPLATES] = get_special_folder (CSIDL_TEMPLATES);
+  g_user_special_dirs[G_USER_DIRECTORY_VIDEOS] = get_special_folder (CSIDL_MYVIDEO);
+}
+#endif /* G_OS_WIN32 */
+
+static void g_init_user_config_dir (void);
+
+#if defined(G_OS_UNIX) && !defined(HAVE_CARBON)
+
+/* adapted from xdg-user-dir-lookup.c
+ *
+ * Copyright (C) 2007 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions: 
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software. 
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+static void
+load_user_special_dirs (void)
+{
+  gchar *config_file;
+  gchar *data;
+  gchar **lines;
+  gint n_lines, i;
+  
+  g_init_user_config_dir ();
+  config_file = g_build_filename (g_user_config_dir,
+                                  "user-dirs.dirs",
+                                  NULL);
+  
+  if (!g_file_get_contents (config_file, &data, NULL, NULL))
+    {
+      g_free (config_file);
+      return;
+    }
+
+  lines = g_strsplit (data, "\n", -1);
+  n_lines = g_strv_length (lines);
+  g_free (data);
+  
+  for (i = 0; i < n_lines; i++)
+    {
+      gchar *buffer = lines[i];
+      gchar *d, *p;
+      gint len;
+      gboolean is_relative = FALSE;
+      GUserDirectory directory;
+
+      /* Remove newline at end */
+      len = strlen (buffer);
+      if (len > 0 && buffer[len - 1] == '\n')
+       buffer[len - 1] = 0;
+      
+      p = buffer;
+      while (*p == ' ' || *p == '\t')
+       p++;
+      
+      if (strncmp (p, "XDG_DESKTOP_DIR", strlen ("XDG_DESKTOP_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DESKTOP;
+          p += strlen ("XDG_DESKTOP_DIR");
+        }
+      else if (strncmp (p, "XDG_DOCUMENTS_DIR", strlen ("XDG_DOCUMENTS_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DOCUMENTS;
+          p += strlen ("XDG_DOCUMENTS_DIR");
+        }
+      else if (strncmp (p, "XDG_DOWNLOAD_DIR", strlen ("XDG_DOWNLOAD_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_DOWNLOAD;
+          p += strlen ("XDG_DOWNLOAD_DIR");
+        }
+      else if (strncmp (p, "XDG_MUSIC_DIR", strlen ("XDG_MUSIC_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_MUSIC;
+          p += strlen ("XDG_MUSIC_DIR");
+        }
+      else if (strncmp (p, "XDG_PICTURES_DIR", strlen ("XDG_PICTURES_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_PICTURES;
+          p += strlen ("XDG_PICTURES_DIR");
+        }
+      else if (strncmp (p, "XDG_PUBLICSHARE_DIR", strlen ("XDG_PUBLICSHARE_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_PUBLIC_SHARE;
+          p += strlen ("XDG_PUBLICSHARE_DIR");
+        }
+      else if (strncmp (p, "XDG_TEMPLATES_DIR", strlen ("XDG_TEMPLATES_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_TEMPLATES;
+          p += strlen ("XDG_TEMPLATES_DIR");
+        }
+      else if (strncmp (p, "XDG_VIDEOS_DIR", strlen ("XDG_VIDEOS_DIR")) == 0)
+        {
+          directory = G_USER_DIRECTORY_VIDEOS;
+          p += strlen ("XDG_VIDEOS_DIR");
+        }
+      else
+       continue;
+
+      while (*p == ' ' || *p == '\t')
+       p++;
+
+      if (*p != '=')
+       continue;
+      p++;
+
+      while (*p == ' ' || *p == '\t')
+       p++;
+
+      if (*p != '"')
+       continue;
+      p++;
+
+      if (strncmp (p, "$HOME", 5) == 0)
+       {
+         p += 5;
+         is_relative = TRUE;
+       }
+      else if (*p != '/')
+       continue;
+
+      d = strrchr (p, '"');
+      if (!d)
+        continue;
+      *d = 0;
+
+      d = p;
+      
+      /* remove trailing slashes */
+      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);
+        }
+      else
+       g_user_special_dirs[directory] = g_strdup (d);
+    }
+
+  g_strfreev (lines);
+  g_free (config_file);
+}
+
+#endif /* G_OS_UNIX && !HAVE_CARBON */
+
+/**
+ * g_get_user_special_dir:
+ * @directory: the logical id of special directory
+ *
+ * Returns the full path of a special directory using its logical id.
+ *
+ * On Unix this is done using the XDG special user directories.
+ * For compatibility with existing practise, %G_USER_DIRECTORY_DESKTOP
+ * 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.
+ *
+ * Return value: the path to the specified special directory, or %NULL
+ *   if the logical id was not found. The returned string is owned by
+ *   GLib and should not be modified or freed.
+ *
+ * Since: 2.14
+ */
+G_CONST_RETURN gchar *
+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 ();
+
+      /* 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_UNLOCK (g_utils_global);
+
+  return g_user_special_dirs[directory];
+}
+
 #ifdef G_OS_WIN32
 
 #undef g_get_system_data_dirs
@@ -2100,7 +2533,7 @@ get_module_for_address (gconstpointer address)
   static gboolean beenhere = FALSE;
   typedef BOOL (WINAPI *t_GetModuleHandleExA) (DWORD, LPCTSTR, HMODULE *);
   static t_GetModuleHandleExA p_GetModuleHandleExA = NULL;
-  HMODULE hmodule;
+  HMODULE hmodule = NULL;
 
   if (!address)
     return NULL;
@@ -2130,27 +2563,14 @@ static gchar *
 get_module_share_dir (gconstpointer address)
 {
   HMODULE hmodule;
-  gchar *filename = NULL;
-  gchar *p, *retval;
-  wchar_t wfilename[MAX_PATH];
+  gchar *filename;
+  gchar *retval;
 
   hmodule = get_module_for_address (address);
   if (hmodule == NULL)
     return NULL;
 
-  if (GetModuleFileNameW (hmodule, wfilename, G_N_ELEMENTS (wfilename)))
-    filename = g_utf16_to_utf8 (wfilename, -1, NULL, NULL, NULL);
-
-  if (filename == NULL)
-    return NULL;
-
-  if ((p = strrchr (filename, G_DIR_SEPARATOR)) != NULL)
-    *p = '\0';
-
-  p = strrchr (filename, G_DIR_SEPARATOR);
-  if (p && (g_ascii_strcasecmp (p + 1, "bin") == 0))
-    *p = '\0';
-
+  filename = g_win32_get_package_installation_directory_of_module (hmodule);
   retval = g_build_filename (filename, "share", NULL);
   g_free (filename);
 
@@ -2158,18 +2578,19 @@ get_module_share_dir (gconstpointer address)
 }
 
 G_CONST_RETURN gchar * G_CONST_RETURN *
-g_win32_get_system_data_dirs_for_module (gconstpointer address)
+g_win32_get_system_data_dirs_for_module (void (*address_of_function)())
 {
   GArray *data_dirs;
   HMODULE hmodule;
   static GHashTable *per_module_data_dirs = NULL;
   gchar **retval;
   gchar *p;
+  gchar *exe_root;
       
-  if (address)
+  if (address_of_function)
     {
       G_LOCK (g_utils_global);
-      hmodule = get_module_for_address (address);
+      hmodule = get_module_for_address (address_of_function);
       if (hmodule != NULL)
        {
          if (per_module_data_dirs == NULL)
@@ -2207,9 +2628,9 @@ g_win32_get_system_data_dirs_for_module (gconstpointer address)
    * subdirectory of the installation directory for the package
    * our caller is a part of.
    *
-   * The address parameter, if non-NULL, points to a function in the
-   * calling module. Use that to determine that module's installation
-   * folder, and use its "share" subfolder.
+   * The address_of_function parameter, if non-NULL, points to a
+   * function in the calling module. Use that to determine that
+   * module's installation folder, and use its "share" subfolder.
    *
    * Additionally, also use the "share" subfolder of the installation
    * locations of GLib and the .exe file being run.
@@ -2221,21 +2642,28 @@ g_win32_get_system_data_dirs_for_module (gconstpointer address)
    * function.
    */
 
-  p = get_module_share_dir (address);
+  p = get_module_share_dir (address_of_function);
   if (p)
     g_array_append_val (data_dirs, p);
     
-  p = g_win32_get_package_installation_subdirectory (NULL, dll_name, "share");
-  if (p)
-    g_array_append_val (data_dirs, p);
+  if (glib_dll != NULL)
+    {
+      gchar *glib_root = g_win32_get_package_installation_directory_of_module (glib_dll);
+      p = g_build_filename (glib_root, "share", NULL);
+      if (p)
+       g_array_append_val (data_dirs, p);
+      g_free (glib_root);
+    }
   
-  p = g_win32_get_package_installation_subdirectory (NULL, NULL, "share");
+  exe_root = g_win32_get_package_installation_directory_of_module (NULL);
+  p = g_build_filename (exe_root, "share", NULL);
   if (p)
     g_array_append_val (data_dirs, p);
+  g_free (exe_root);
 
   retval = (gchar **) g_array_free (data_dirs, FALSE);
 
-  if (address)
+  if (address_of_function)
     {
       if (hmodule != NULL)
        g_hash_table_insert (per_module_data_dirs, hmodule, retval);
@@ -2808,38 +3236,43 @@ _g_utils_thread_init (void)
   g_get_language_names ();
 }
 
-#ifdef ENABLE_NLS
-
-#include <libintl.h>
-
 #ifdef G_OS_WIN32
 
 /**
  * _glib_get_locale_dir:
  *
- * Return the path to the lib\locale subfolder of the GLib
- * installation folder. The path is in the system codepage. We have to
- * use system codepage as bindtextdomain() doesn't have a UTF-8
- * interface.
+ * Return the path to the share\locale or lib\locale subfolder of the
+ * GLib installation folder. The path is in the system codepage. We
+ * have to use system codepage as bindtextdomain() doesn't have a
+ * UTF-8 interface.
  */
-static const gchar *
+static gchar *
 _glib_get_locale_dir (void)
 {
-  gchar *dir, *cp_dir;
+  gchar *install_dir = NULL, *locale_dir;
   gchar *retval = NULL;
 
-  dir = g_win32_get_package_installation_directory (GETTEXT_PACKAGE, dll_name);
-  cp_dir = g_win32_locale_filename_from_utf8 (dir);
-  g_free (dir);
+  if (glib_dll != NULL)
+    install_dir = g_win32_get_package_installation_directory_of_module (glib_dll);
 
-  if (cp_dir)
+  if (install_dir)
     {
-      /* Don't use g_build_filename() on pathnames in the system
-       * codepage. In CJK locales cp_dir might end with a double-byte
-       * character whose trailing byte is a backslash.
+      /*
+       * Append "/share/locale" or "/lib/locale" depending on whether
+       * autoconfigury detected GNU gettext or not.
        */
-      retval = g_strconcat (cp_dir, "\\lib\\locale", NULL);
-      g_free (cp_dir);
+      const char *p = GLIB_LOCALE_DIR + strlen (GLIB_LOCALE_DIR);
+      while (*--p != '/')
+       ;
+      while (*--p != '/')
+       ;
+
+      locale_dir = g_build_filename (install_dir, p, NULL);
+
+      retval = g_win32_locale_filename_from_utf8 (locale_dir);
+
+      g_free (install_dir);
+      g_free (locale_dir);
     }
 
   if (retval)
@@ -2849,30 +3282,43 @@ _glib_get_locale_dir (void)
 }
 
 #undef GLIB_LOCALE_DIR
-#define GLIB_LOCALE_DIR _glib_get_locale_dir ()
 
 #endif /* G_OS_WIN32 */
 
+/**
+ * glib_gettext:
+ * @str: The string to be translated
+ *
+ * Returns the translated string from the glib translations.
+ * This is an internal function and should only be used by
+ * the internals of glib (such as libgio).
+ *
+ * Returns: the transation of @str to the current locale
+ */
 G_CONST_RETURN gchar *
-_glib_gettext (const gchar *str)
+glib_gettext (const gchar *str)
 {
   static gboolean _glib_gettext_initialized = FALSE;
 
   if (!_glib_gettext_initialized)
     {
-      bindtextdomain(GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#ifdef G_OS_WIN32
+      gchar *tmp = _glib_get_locale_dir ();
+      bindtextdomain (GETTEXT_PACKAGE, tmp);
+      g_free (tmp);
+#else
+      bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
+#endif
 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 #    endif
       _glib_gettext_initialized = TRUE;
     }
   
-  return dgettext (GETTEXT_PACKAGE, str);
+  return g_dgettext (GETTEXT_PACKAGE, str);
 }
 
-#endif /* ENABLE_NLS */
-
-#ifdef G_OS_WIN32
+#if defined (G_OS_WIN32) && !defined (_WIN64)
 
 /* Binary compatibility versions. Not for newly compiled code. */