summaryrefslogtreecommitdiffstats
path: root/libgimpbase/gimpenv.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libgimpbase/gimpenv.c1260
1 files changed, 1260 insertions, 0 deletions
diff --git a/libgimpbase/gimpenv.c b/libgimpbase/gimpenv.c
new file mode 100644
index 0000000..d4040c8
--- /dev/null
+++ b/libgimpbase/gimpenv.c
@@ -0,0 +1,1260 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpenv.c
+ * Copyright (C) 1999 Tor Lillqvist <tml@iki.fi>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef PLATFORM_OSX
+#include <AppKit/AppKit.h>
+#endif
+
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+
+#undef GIMP_DISABLE_DEPRECATED
+#include "gimpbasetypes.h"
+
+#define __GIMP_ENV_C__
+#include "gimpenv.h"
+#include "gimpversion.h"
+#include "gimpreloc.h"
+
+#ifdef G_OS_WIN32
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <io.h>
+#ifndef S_IWUSR
+# define S_IWUSR _S_IWRITE
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP (_S_IWRITE>>3)
+#define S_IWOTH (_S_IWRITE>>6)
+#endif
+#ifndef S_ISDIR
+# define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
+# define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
+#endif
+#define uid_t gint
+#define gid_t gint
+#define geteuid() 0
+#define getegid() 0
+
+#include <shlobj.h>
+
+/* Constant available since Shell32.dll 4.72 */
+#ifndef CSIDL_APPDATA
+#define CSIDL_APPDATA 0x001a
+#endif
+
+#endif
+
+
+/**
+ * SECTION: gimpenv
+ * @title: gimpenv
+ * @short_description: Functions to access the GIMP environment.
+ *
+ * A set of functions to find the locations of GIMP's data directories
+ * and configuration files.
+ **/
+
+
+static gchar * gimp_env_get_dir (const gchar *gimp_env_name,
+ const gchar *compile_time_dir,
+ const gchar *relative_subdir);
+#ifdef G_OS_WIN32
+static gchar * get_special_folder (gint csidl);
+#endif
+
+
+const guint gimp_major_version = GIMP_MAJOR_VERSION;
+const guint gimp_minor_version = GIMP_MINOR_VERSION;
+const guint gimp_micro_version = GIMP_MICRO_VERSION;
+
+
+/**
+ * gimp_env_init:
+ * @plug_in: must be %TRUE if this function is called from a plug-in
+ *
+ * You don't need to care about this function. It is being called for
+ * you automatically (by means of the MAIN() macro that every plug-in
+ * runs). Calling it again will cause a fatal error.
+ *
+ * Since: 2.4
+ */
+void
+gimp_env_init (gboolean plug_in)
+{
+ static gboolean gimp_env_initialized = FALSE;
+ const gchar *data_home = g_get_user_data_dir ();
+
+ if (gimp_env_initialized)
+ g_error ("gimp_env_init() must only be called once!");
+
+ gimp_env_initialized = TRUE;
+
+#ifndef G_OS_WIN32
+ if (plug_in)
+ {
+ _gimp_reloc_init_lib (NULL);
+ }
+ else if (_gimp_reloc_init (NULL))
+ {
+ /* Set $LD_LIBRARY_PATH to ensure that plugins can be loaded. */
+
+ const gchar *ldpath = g_getenv ("LD_LIBRARY_PATH");
+ gchar *libdir = g_build_filename (gimp_installation_directory (),
+ "lib",
+ NULL);
+
+ if (ldpath && *ldpath)
+ {
+ gchar *tmp = g_strconcat (libdir, ":", ldpath, NULL);
+
+ g_setenv ("LD_LIBRARY_PATH", tmp, TRUE);
+
+ g_free (tmp);
+ }
+ else
+ {
+ g_setenv ("LD_LIBRARY_PATH", libdir, TRUE);
+ }
+
+ g_free (libdir);
+ }
+#endif
+
+ /* The user data directory (XDG_DATA_HOME on Unix) is used to store
+ * various data, like crash logs (win32) or recently used file history
+ * (by GTK+). Yet it may be absent, in particular on non-Linux
+ * platforms. Make sure it exists.
+ */
+ if (! g_file_test (data_home, G_FILE_TEST_IS_DIR))
+ {
+ if (g_mkdir_with_parents (data_home, S_IRUSR | S_IWUSR | S_IXUSR) != 0)
+ {
+ g_warning ("Failed to create the data directory '%s': %s",
+ data_home, g_strerror (errno));
+ }
+ }
+}
+
+/**
+ * gimp_directory:
+ *
+ * Returns the user-specific GIMP settings directory. If the
+ * environment variable GIMP2_DIRECTORY exists, it is used. If it is
+ * an absolute path, it is used as is. If it is a relative path, it
+ * is taken to be a subdirectory of the home directory. If it is a
+ * relative path, and no home directory can be determined, it is taken
+ * to be a subdirectory of gimp_data_directory().
+ *
+ * The usual case is that no GIMP2_DIRECTORY environment variable
+ * exists, and then we use the GIMPDIR subdirectory of the local
+ * configuration directory:
+ *
+ * - UNIX: $XDG_CONFIG_HOME (defaults to $HOME/.config/)
+ *
+ * - Windows: CSIDL_APPDATA
+ *
+ * - OSX (UNIX exception): the Application Support Directory.
+ *
+ * If neither the configuration nor home directory exist,
+ * g_get_user_config_dir() will return {tmp}/{user_name}/.config/ where
+ * the temporary directory {tmp} and the {user_name} are determined
+ * according to platform rules.
+ *
+ * In any case, we always return some non-empty string, whether it
+ * corresponds to an existing directory or not.
+ *
+ * In config files such as gimprc, the string ${gimp_dir} expands to
+ * this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8 (on Windows it is always
+ * UTF-8.)
+ *
+ * Returns: The user-specific GIMP settings directory.
+ **/
+const gchar *
+gimp_directory (void)
+{
+ static gchar *gimp_dir = NULL;
+ static gchar *last_env_gimp_dir = NULL;
+
+ const gchar *env_gimp_dir;
+
+ env_gimp_dir = g_getenv ("GIMP2_DIRECTORY");
+
+ if (gimp_dir)
+ {
+ gboolean gimp2_directory_changed = FALSE;
+
+ /* We have constructed the gimp_dir already. We can return
+ * gimp_dir unless some parameter gimp_dir depends on has
+ * changed. For now we just check for changes to GIMP2_DIRECTORY
+ */
+ gimp2_directory_changed =
+ (env_gimp_dir == NULL &&
+ last_env_gimp_dir != NULL) ||
+ (env_gimp_dir != NULL &&
+ last_env_gimp_dir == NULL) ||
+ (env_gimp_dir != NULL &&
+ last_env_gimp_dir != NULL &&
+ strcmp (env_gimp_dir, last_env_gimp_dir) != 0);
+
+ if (! gimp2_directory_changed)
+ {
+ return gimp_dir;
+ }
+ else
+ {
+ /* Free the old gimp_dir and go on to update it */
+ g_free (gimp_dir);
+ gimp_dir = NULL;
+ }
+ }
+
+ /* Remember the GIMP2_DIRECTORY to next invocation so we can check
+ * if it changes
+ */
+ g_free (last_env_gimp_dir);
+ last_env_gimp_dir = g_strdup (env_gimp_dir);
+
+ if (env_gimp_dir)
+ {
+ if (g_path_is_absolute (env_gimp_dir))
+ {
+ gimp_dir = g_strdup (env_gimp_dir);
+ }
+ else
+ {
+ const gchar *home_dir = g_get_home_dir ();
+
+ if (home_dir)
+ gimp_dir = g_build_filename (home_dir, env_gimp_dir, NULL);
+ else
+ gimp_dir = g_build_filename (gimp_data_directory (), env_gimp_dir, NULL);
+ }
+ }
+ else if (g_path_is_absolute (GIMPDIR))
+ {
+ gimp_dir = g_strdup (GIMPDIR);
+ }
+ else
+ {
+#ifdef PLATFORM_OSX
+
+ NSAutoreleasePool *pool;
+ NSArray *path;
+ NSString *library_dir;
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ path = NSSearchPathForDirectoriesInDomains (NSApplicationSupportDirectory,
+ NSUserDomainMask, YES);
+ library_dir = [path objectAtIndex:0];
+
+ gimp_dir = g_build_filename ([library_dir UTF8String],
+ GIMPDIR, GIMP_USER_VERSION, NULL);
+
+ [pool drain];
+
+#elif defined G_OS_WIN32
+
+ gchar *conf_dir = get_special_folder (CSIDL_APPDATA);
+
+ gimp_dir = g_build_filename (conf_dir,
+ GIMPDIR, GIMP_USER_VERSION, NULL);
+ g_free(conf_dir);
+
+#else /* UNIX */
+
+ /* g_get_user_config_dir () always returns a path as a non-null
+ * and non-empty string
+ */
+ gimp_dir = g_build_filename (g_get_user_config_dir (),
+ GIMPDIR, GIMP_USER_VERSION, NULL);
+
+#endif /* PLATFORM_OSX */
+ }
+
+ return gimp_dir;
+}
+
+#ifdef G_OS_WIN32
+
+/* Taken from glib 2.35 code. */
+static gchar *
+get_special_folder (int csidl)
+{
+ wchar_t path[MAX_PATH+1];
+ HRESULT hr;
+ LPITEMIDLIST pidl = NULL;
+ BOOL b;
+ gchar *retval = NULL;
+
+ hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
+ if (hr == S_OK)
+ {
+ b = SHGetPathFromIDListW (pidl, path);
+ if (b)
+ retval = g_utf16_to_utf8 (path, -1, NULL, NULL, NULL);
+ CoTaskMemFree (pidl);
+ }
+
+ return retval;
+}
+
+static HMODULE libgimpbase_dll = NULL;
+
+/* Minimal DllMain that just stores the handle to this DLL */
+
+BOOL WINAPI /* Avoid silly "no previous prototype" gcc warning */
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved);
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ libgimpbase_dll = hinstDLL;
+ break;
+ }
+
+ return TRUE;
+}
+
+#endif
+
+/**
+ * gimp_installation_directory:
+ *
+ * Returns the top installation directory of GIMP. On Unix the
+ * compile-time defined installation prefix is used. On Windows, the
+ * installation directory as deduced from the executable's full
+ * filename is used. On OSX we ask [NSBundle mainBundle] for the
+ * resource path to check if GIMP is part of a relocatable bundle.
+ *
+ * In config files such as gimprc, the string ${gimp_installation_dir}
+ * expands to this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.)
+ *
+ * Since: 2.8
+ *
+ * Returns: The toplevel installation directory of GIMP.
+ **/
+const gchar *
+gimp_installation_directory (void)
+{
+ static gchar *toplevel = NULL;
+
+ if (toplevel)
+ return toplevel;
+
+#ifdef G_OS_WIN32
+
+ toplevel = g_win32_get_package_installation_directory_of_module (libgimpbase_dll);
+ if (! toplevel)
+ g_error ("g_win32_get_package_installation_directory_of_module() failed");
+
+#elif PLATFORM_OSX
+
+ {
+ NSAutoreleasePool *pool;
+ NSString *resource_path;
+ gchar *basename;
+ gchar *dirname;
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ resource_path = [[NSBundle mainBundle] resourcePath];
+
+ basename = g_path_get_basename ([resource_path UTF8String]);
+ dirname = g_path_get_dirname ([resource_path UTF8String]);
+
+ if (! strcmp (basename, ".libs"))
+ {
+ /* we are running from the source dir, do normal unix things */
+
+ toplevel = _gimp_reloc_find_prefix (PREFIX);
+ }
+ else if (! strcmp (basename, "bin"))
+ {
+ /* we are running the main app, but not from a bundle, the resource
+ * path is the directory which contains the executable
+ */
+
+ toplevel = g_strdup (dirname);
+ }
+ else if (! strcmp (basename, "plug-ins"))
+ {
+ /* same for plug-ins, go three levels up from prefix/lib/gimp/x.y */
+
+ gchar *tmp = g_path_get_dirname (dirname);
+ gchar *tmp2 = g_path_get_dirname (tmp);
+
+ toplevel = g_path_get_dirname (tmp2);
+
+ g_free (tmp);
+ g_free (tmp2);
+ }
+ else
+ {
+ /* if none of the above match, we assume that we are really in a bundle */
+
+ toplevel = g_strdup ([resource_path UTF8String]);
+ }
+
+ g_free (basename);
+ g_free (dirname);
+
+ [pool drain];
+ }
+
+#else
+
+ toplevel = _gimp_reloc_find_prefix (PREFIX);
+
+#endif
+
+ return toplevel;
+}
+
+/**
+ * gimp_data_directory:
+ *
+ * Returns the default top directory for GIMP data. If the environment
+ * variable GIMP2_DATADIR exists, that is used. It should be an
+ * absolute pathname. Otherwise, on Unix the compile-time defined
+ * directory is used. On Windows, the installation directory as
+ * deduced from the executable's full filename is used.
+ *
+ * Note that the actual directories used for GIMP data files can be
+ * overridden by the user in the preferences dialog.
+ *
+ * In config files such as gimprc, the string ${gimp_data_dir} expands
+ * to this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.)
+ *
+ * Returns: The top directory for GIMP data.
+ **/
+const gchar *
+gimp_data_directory (void)
+{
+ static gchar *gimp_data_dir = NULL;
+
+ if (! gimp_data_dir)
+ {
+ gchar *tmp = g_build_filename ("share",
+ GIMP_PACKAGE,
+ GIMP_DATA_VERSION,
+ NULL);
+
+ gimp_data_dir = gimp_env_get_dir ("GIMP2_DATADIR", GIMPDATADIR, tmp);
+ g_free (tmp);
+ }
+
+ return gimp_data_dir;
+}
+
+/**
+ * gimp_locale_directory:
+ *
+ * Returns the top directory for GIMP locale files. If the environment
+ * variable GIMP2_LOCALEDIR exists, that is used. It should be an
+ * absolute pathname. Otherwise, on Unix the compile-time defined
+ * directory is used. On Windows, the installation directory as deduced
+ * from the executable's full filename is used.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * the C library, which isn't necessarily UTF-8. (On Windows, unlike
+ * the other similar functions here, the return value from this
+ * function is in the system codepage, never in UTF-8. It can thus be
+ * passed directly to the bindtextdomain() function from libintl which
+ * does not handle UTF-8.)
+ *
+ * Returns: The top directory for GIMP locale files.
+ */
+const gchar *
+gimp_locale_directory (void)
+{
+ static gchar *gimp_locale_dir = NULL;
+
+ if (! gimp_locale_dir)
+ {
+ gchar *tmp = g_build_filename ("share",
+ "locale",
+ NULL);
+
+ gimp_locale_dir = gimp_env_get_dir ("GIMP2_LOCALEDIR", LOCALEDIR, tmp);
+ g_free (tmp);
+
+#ifdef G_OS_WIN32
+ /* FIXME: g_win32_locale_filename_from_utf8() can actually return
+ * NULL (we had actual cases of this). Not sure exactly what
+ * gimp_locale_directory() should do when this happens. Anyway
+ * that's really broken, and something should be done some day
+ * about this!
+ */
+ tmp = g_win32_locale_filename_from_utf8 (gimp_locale_dir);
+ g_free (gimp_locale_dir);
+ gimp_locale_dir = tmp;
+#endif
+ }
+
+ return gimp_locale_dir;
+}
+
+/**
+ * gimp_sysconf_directory:
+ *
+ * Returns the top directory for GIMP config files. If the environment
+ * variable GIMP2_SYSCONFDIR exists, that is used. It should be an
+ * absolute pathname. Otherwise, on Unix the compile-time defined
+ * directory is used. On Windows, the installation directory as deduced
+ * from the executable's full filename is used.
+ *
+ * In config files such as gimprc, the string ${gimp_sysconf_dir}
+ * expands to this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.).
+ *
+ * Returns: The top directory for GIMP config files.
+ **/
+const gchar *
+gimp_sysconf_directory (void)
+{
+ static gchar *gimp_sysconf_dir = NULL;
+
+ if (! gimp_sysconf_dir)
+ {
+ gchar *tmp = g_build_filename ("etc",
+ GIMP_PACKAGE,
+ GIMP_SYSCONF_VERSION,
+ NULL);
+
+ gimp_sysconf_dir = gimp_env_get_dir ("GIMP2_SYSCONFDIR", GIMPSYSCONFDIR, tmp);
+ g_free (tmp);
+ }
+
+ return gimp_sysconf_dir;
+}
+
+/**
+ * gimp_plug_in_directory:
+ *
+ * Returns the default top directory for GIMP plug-ins and modules. If
+ * the environment variable GIMP2_PLUGINDIR exists, that is used. It
+ * should be an absolute pathname. Otherwise, on Unix the compile-time
+ * defined directory is used. On Windows, the installation directory
+ * as deduced from the executable's full filename is used.
+ *
+ * Note that the actual directories used for GIMP plug-ins and modules
+ * can be overridden by the user in the preferences dialog.
+ *
+ * In config files such as gimprc, the string ${gimp_plug_in_dir}
+ * expands to this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.)
+ *
+ * Returns: The top directory for GIMP plug_ins and modules.
+ **/
+const gchar *
+gimp_plug_in_directory (void)
+{
+ static gchar *gimp_plug_in_dir = NULL;
+
+ if (! gimp_plug_in_dir)
+ {
+ gchar *tmp = g_build_filename ("lib",
+ GIMP_PACKAGE,
+ GIMP_PLUGIN_VERSION,
+ NULL);
+
+ gimp_plug_in_dir = gimp_env_get_dir ("GIMP2_PLUGINDIR", PLUGINDIR, tmp);
+ g_free (tmp);
+ }
+
+ return gimp_plug_in_dir;
+}
+
+/**
+ * gimp_cache_directory:
+ *
+ * Returns the default top directory for GIMP cached files. If the
+ * environment variable GIMP2_CACHEDIR exists, that is used. It
+ * should be an absolute pathname. Otherwise, a subdirectory of the
+ * directory returned by g_get_user_cache_dir() is used.
+ *
+ * Note that the actual directories used for GIMP caches files can
+ * be overridden by the user in the preferences dialog.
+ *
+ * In config files such as gimprc, the string ${gimp_cache_dir}
+ * expands to this directory.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.).
+ *
+ * Since: 2.10.10
+ *
+ * Returns: The default top directory for GIMP cached files.
+ **/
+const gchar *
+gimp_cache_directory (void)
+{
+ static gchar *gimp_cache_dir = NULL;
+
+ if (! gimp_cache_dir)
+ {
+ gchar *tmp = g_build_filename (g_get_user_cache_dir (),
+ GIMP_PACKAGE,
+ GIMP_USER_VERSION,
+ NULL);
+
+ gimp_cache_dir = gimp_env_get_dir ("GIMP2_CACHEDIR", NULL, tmp);
+ g_free (tmp);
+ }
+
+ return gimp_cache_dir;
+}
+
+/**
+ * gimp_temp_directory:
+ *
+ * Returns the default top directory for GIMP temporary files. If the
+ * environment variable GIMP2_TEMPDIR exists, that is used. It
+ * should be an absolute pathname. Otherwise, a subdirectory of the
+ * directory returned by g_get_tmp_dir() is used.
+ *
+ * In config files such as gimprc, the string ${gimp_temp_dir} expands
+ * to this directory.
+ *
+ * Note that the actual directories used for GIMP temporary files can
+ * be overridden by the user in the preferences dialog.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.).
+ *
+ * Since: 2.10.10
+ *
+ * Returns: The default top directory for GIMP temporary files.
+ **/
+const gchar *
+gimp_temp_directory (void)
+{
+ static gchar *gimp_temp_dir = NULL;
+
+ if (! gimp_temp_dir)
+ {
+ gchar *tmp = g_build_filename (g_get_tmp_dir (),
+ GIMP_PACKAGE,
+ GIMP_USER_VERSION,
+ NULL);
+
+ gimp_temp_dir = gimp_env_get_dir ("GIMP2_TEMPDIR", NULL, tmp);
+ g_free (tmp);
+ }
+
+ return gimp_temp_dir;
+}
+
+static GFile *
+gimp_child_file (const gchar *parent,
+ const gchar *element,
+ va_list args)
+{
+ GFile *file = g_file_new_for_path (parent);
+
+ while (element)
+ {
+ GFile *child = g_file_get_child (file, element);
+
+ g_object_unref (file);
+ file = child;
+
+ element = va_arg (args, const gchar *);
+ }
+
+ return file;
+}
+
+/**
+ * gimp_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * user's GIMP directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the user's GIMP directory, or the data
+ * directory itself if @first_element is %NULL.
+ *
+ * See also: gimp_directory().
+ *
+ * Since: 2.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_installation_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * top installation directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the installation directory, or the installation
+ * directory itself if @first_element is %NULL.
+ *
+ * See also: gimp_installation_directory().
+ *
+ * Since: 2.10.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_installation_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_installation_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_data_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * data directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the data directory, or the data directory
+ * itself if @first_element is %NULL.
+ *
+ * See also: gimp_data_directory().
+ *
+ * Since: 2.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_data_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_data_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_locale_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * locale directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the locale directory, or the locale directory
+ * itself if @first_element is %NULL.
+ *
+ * See also: gimp_locale_directory().
+ *
+ * Since: 2.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_locale_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_locale_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_sysconf_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * sysconf directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the sysconf directory, or the sysconf directory
+ * itself if @first_element is %NULL.
+ *
+ * See also: gimp_sysconf_directory().
+ *
+ * Since: 2.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_sysconf_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_sysconf_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_plug_in_directory_file:
+ * @first_element: the first element of a path to a file in the
+ * plug-in directory, or %NULL.
+ * @...: a %NULL terminated list of the remaining elements of the path
+ * to the file.
+ *
+ * Returns a #GFile in the plug-in directory, or the plug-in directory
+ * itself if @first_element is %NULL.
+ *
+ * See also: gimp_plug_in_directory().
+ *
+ * Since: 2.10
+ *
+ * Returns: a new @GFile for the path, Free with g_object_unref().
+ **/
+GFile *
+gimp_plug_in_directory_file (const gchar *first_element,
+ ...)
+{
+ GFile *file;
+ va_list args;
+
+ va_start (args, first_element);
+ file = gimp_child_file (gimp_plug_in_directory (), first_element, args);
+ va_end (args);
+
+ return file;
+}
+
+/**
+ * gimp_user_directory:
+ * @type: the type of user directory to retrieve
+ *
+ * This procedure is deprecated! Use g_get_user_special_dir() instead.
+ *
+ * Returns: The path to the specified user directory, or %NULL if the
+ * logical ID was not found.
+ *
+ * Since: 2.4
+ **/
+const gchar *
+gimp_user_directory (GimpUserDirectory type)
+{
+ return g_get_user_special_dir ((GUserDirectory) type);
+}
+
+/**
+ * gimp_personal_rc_file:
+ * @basename: The basename of a rc_file.
+ *
+ * Returns the name of a file in the user-specific GIMP settings directory.
+ *
+ * The returned string is newly allocated and should be freed with
+ * g_free() after use. The returned string is in the encoding used for
+ * filenames by GLib, which isn't necessarily UTF-8. (On Windows it
+ * always is UTF-8.)
+ *
+ * Returns: The name of a file in the user-specific GIMP settings directory.
+ **/
+gchar *
+gimp_personal_rc_file (const gchar *basename)
+{
+ return g_build_filename (gimp_directory (), basename, NULL);
+}
+
+/**
+ * gimp_gtkrc:
+ *
+ * Returns the name of GIMP's application-specific gtkrc file.
+ *
+ * The returned string is owned by GIMP and must not be modified or
+ * freed. The returned string is in the encoding used for filenames by
+ * GLib, which isn't necessarily UTF-8. (On Windows it always is
+ * UTF-8.)
+ *
+ * Returns: The name of GIMP's application-specific gtkrc file.
+ **/
+const gchar *
+gimp_gtkrc (void)
+{
+ static gchar *gimp_gtkrc_filename = NULL;
+
+ if (! gimp_gtkrc_filename)
+ gimp_gtkrc_filename = g_build_filename (gimp_data_directory (),
+ "themes", "System", "gtkrc",
+ NULL);
+
+ return gimp_gtkrc_filename;
+}
+
+/**
+ * gimp_path_runtime_fix:
+ * @path: A pointer to a string (allocated with g_malloc) that is
+ * (or could be) a pathname.
+ *
+ * On Windows, this function checks if the string pointed to by @path
+ * starts with the compile-time prefix, and in that case, replaces the
+ * prefix with the run-time one. @path should be a pointer to a
+ * dynamically allocated (with g_malloc, g_strconcat, etc) string. If
+ * the replacement takes place, the original string is deallocated,
+ * and *@path is replaced with a pointer to a new string with the
+ * run-time prefix spliced in.
+ *
+ * On Linux, it does the same thing, but only if BinReloc support is enabled.
+ * On other Unices, it does nothing because those platforms don't have a
+ * way to find out where our binary is.
+ */
+static void
+gimp_path_runtime_fix (gchar **path)
+{
+#if defined (G_OS_WIN32) && defined (PREFIX)
+ gchar *p;
+
+ /* Yes, I do mean forward slashes below */
+ if (strncmp (*path, PREFIX "/", strlen (PREFIX "/")) == 0)
+ {
+ /* This is a compile-time entry. Replace the path with the
+ * real one on this machine.
+ */
+ p = *path;
+ *path = g_strconcat (gimp_installation_directory (),
+ "\\",
+ *path + strlen (PREFIX "/"),
+ NULL);
+ g_free (p);
+ }
+ /* Replace forward slashes with backslashes, just for
+ * completeness */
+ p = *path;
+ while ((p = strchr (p, '/')) != NULL)
+ {
+ *p = '\\';
+ p++;
+ }
+#elif defined (G_OS_WIN32)
+ /* without defineing PREFIX do something useful too */
+ gchar *p = *path;
+ if (!g_path_is_absolute (p))
+ {
+ *path = g_build_filename (gimp_installation_directory (), *path, NULL);
+ g_free (p);
+ }
+#else
+ gchar *p;
+
+ if (strncmp (*path, PREFIX G_DIR_SEPARATOR_S,
+ strlen (PREFIX G_DIR_SEPARATOR_S)) == 0)
+ {
+ /* This is a compile-time entry. Replace the path with the
+ * real one on this machine.
+ */
+ p = *path;
+ *path = g_build_filename (gimp_installation_directory (),
+ *path + strlen (PREFIX G_DIR_SEPARATOR_S),
+ NULL);
+ g_free (p);
+ }
+#endif
+}
+
+/**
+ * gimp_path_parse:
+ * @path: A list of directories separated by #G_SEARCHPATH_SEPARATOR.
+ * @max_paths: The maximum number of directories to return.
+ * @check: %TRUE if you want the directories to be checked.
+ * @check_failed: Returns a #GList of path elements for which the
+ * check failed.
+ *
+ * Returns: A #GList of all directories in @path.
+ **/
+GList *
+gimp_path_parse (const gchar *path,
+ gint max_paths,
+ gboolean check,
+ GList **check_failed)
+{
+ gchar **patharray;
+ GList *list = NULL;
+ GList *fail_list = NULL;
+ gint i;
+ gboolean exists = TRUE;
+
+ if (!path || !*path || max_paths < 1 || max_paths > 256)
+ return NULL;
+
+ patharray = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, max_paths);
+
+ for (i = 0; i < max_paths; i++)
+ {
+ GString *dir;
+
+ if (! patharray[i])
+ break;
+
+#ifndef G_OS_WIN32
+ if (*patharray[i] == '~')
+ {
+ dir = g_string_new (g_get_home_dir ());
+ g_string_append (dir, patharray[i] + 1);
+ }
+ else
+#endif
+ {
+ gimp_path_runtime_fix (&patharray[i]);
+ dir = g_string_new (patharray[i]);
+ }
+
+ if (check)
+ exists = g_file_test (dir->str, G_FILE_TEST_IS_DIR);
+
+ if (exists)
+ {
+ GList *dup;
+
+ /* check for duplicate entries, see bug #784502 */
+ for (dup = list; dup; dup = g_list_next (dup))
+ {
+ if (! strcmp (dir->str, dup->data))
+ break;
+ }
+
+ /* only add to the list if it's not a duplicate */
+ if (! dup)
+ list = g_list_prepend (list, g_strdup (dir->str));
+ }
+ else if (check_failed)
+ {
+ fail_list = g_list_prepend (fail_list, g_strdup (dir->str));
+ }
+
+ g_string_free (dir, TRUE);
+ }
+
+ g_strfreev (patharray);
+
+ list = g_list_reverse (list);
+
+ if (check && check_failed)
+ {
+ fail_list = g_list_reverse (fail_list);
+ *check_failed = fail_list;
+ }
+
+ return list;
+}
+
+/**
+ * gimp_path_to_str:
+ * @path: A list of directories as returned by gimp_path_parse().
+ *
+ * Returns: A searchpath string separated by #G_SEARCHPATH_SEPARATOR.
+ **/
+gchar *
+gimp_path_to_str (GList *path)
+{
+ GString *str = NULL;
+ GList *list;
+ gchar *retval = NULL;
+
+ for (list = path; list; list = g_list_next (list))
+ {
+ gchar *dir = list->data;
+
+ if (str)
+ {
+ g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
+ g_string_append (str, dir);
+ }
+ else
+ {
+ str = g_string_new (dir);
+ }
+ }
+
+ if (str)
+ retval = g_string_free (str, FALSE);
+
+ return retval;
+}
+
+/**
+ * gimp_path_free:
+ * @path: A list of directories as returned by gimp_path_parse().
+ *
+ * This function frees the memory allocated for the list and the strings
+ * it contains.
+ **/
+void
+gimp_path_free (GList *path)
+{
+ g_list_free_full (path, (GDestroyNotify) g_free);
+}
+
+/**
+ * gimp_path_get_user_writable_dir:
+ * @path: A list of directories as returned by gimp_path_parse().
+ *
+ * Note that you have to g_free() the returned string.
+ *
+ * Returns: The first directory in @path where the user has write permission.
+ **/
+gchar *
+gimp_path_get_user_writable_dir (GList *path)
+{
+ GList *list;
+ uid_t euid;
+ gid_t egid;
+ GStatBuf filestat;
+ gint err;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ euid = geteuid ();
+ egid = getegid ();
+
+ for (list = path; list; list = g_list_next (list))
+ {
+ gchar *dir = list->data;
+
+ /* check if directory exists */
+ err = g_stat (dir, &filestat);
+
+ /* this is tricky:
+ * if a file is e.g. owned by the current user but not user-writable,
+ * the user has no permission to write to the file regardless
+ * of his group's or other's write permissions
+ */
+ if (!err && S_ISDIR (filestat.st_mode) &&
+
+ ((filestat.st_mode & S_IWUSR) ||
+
+ ((filestat.st_mode & S_IWGRP) &&
+ (euid != filestat.st_uid)) ||
+
+ ((filestat.st_mode & S_IWOTH) &&
+ (euid != filestat.st_uid) &&
+ (egid != filestat.st_gid))))
+ {
+ return g_strdup (dir);
+ }
+ }
+
+ return NULL;
+}
+
+static gchar *
+gimp_env_get_dir (const gchar *gimp_env_name,
+ const gchar *compile_time_dir,
+ const gchar *relative_subdir)
+{
+ const gchar *env = g_getenv (gimp_env_name);
+
+ if (env)
+ {
+ if (! g_path_is_absolute (env))
+ g_error ("%s environment variable should be an absolute path.",
+ gimp_env_name);
+
+ return g_strdup (env);
+ }
+ else if (compile_time_dir)
+ {
+ gchar *retval = g_strdup (compile_time_dir);
+
+ gimp_path_runtime_fix (&retval);
+
+ return retval;
+ }
+ else if (! g_path_is_absolute (relative_subdir))
+ {
+ return g_build_filename (gimp_installation_directory (),
+ relative_subdir,
+ NULL);
+ }
+
+ return g_strdup (relative_subdir);
+}