diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/file-utils.c | 85 | ||||
-rw-r--r-- | src/file-utils.h | 12 | ||||
-rw-r--r-- | src/interface-gtk/interface.c | 32 | ||||
-rw-r--r-- | src/main.c | 23 |
4 files changed, 118 insertions, 34 deletions
diff --git a/src/file-utils.c b/src/file-utils.c index 3f8f721..b7e5418 100644 --- a/src/file-utils.c +++ b/src/file-utils.c @@ -19,6 +19,7 @@ #include "config.h" #endif +#define _GNU_SOURCE #include <limits.h> #include <stdlib.h> #include <string.h> @@ -35,6 +36,10 @@ #include <glib.h> #include <glib/gstdio.h> +#ifdef G_OS_UNIX +#include <dlfcn.h> +#endif + #include "sciteco.h" #include "qreg.h" #include "interface.h" @@ -179,6 +184,86 @@ teco_file_is_visible(const gchar *path) #endif /* !G_OS_WIN32 */ +#ifdef G_OS_WIN32 + +gchar * +teco_file_get_program_path(void) +{ + TCHAR buf[MAX_PATH]; + if (!GetModuleFileNameW(NULL, buf, G_N_ELEMENTS(buf)) + return g_get_current_dir(); + g_autofree gchar *exe = g_utf16_to_utf8(buf, -1, NULL, NULL, NULL); + return g_path_get_dirname(exe); +} + +#elif defined(__linux__) + +gchar * +teco_file_get_program_path(void) +{ + gchar buf[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)-1); + if (G_UNLIKELY(len < 0)) + /* almost certainly wrong */ + return g_get_current_dir(); + buf[len] = '\0'; + + return g_path_get_dirname(buf); +} + +#elif defined(G_OS_UNIX) + +/* + * At least works on FreeBSD, even though it also has + * sysctl(KERN_PROC_PATHNAME). + * We assume it works on all other UNIXes as well. + */ +gchar * +teco_file_get_program_path(void) +{ + Dl_info info; + return dladdr(teco_file_get_program_path, &info) + ? g_path_get_dirname(info.dli_fname) : g_get_current_dir(); +} + +#else /* !G_OS_WIN32 && !__linux__ && !G_OS_UNIX */ + +/* + * This is almost guaranteed to be wrong, + * meaning that SciTECO cannot be made relocatable on these platforms. + * It may be worth evaluating argv[0] on these platforms. + */ +gchar * +teco_file_get_program_path(void) +{ + return g_get_current_dir(); +} + +#endif + +/** + * Get the datadir. + * + * By default it is hardcoded to an absolute path at + * build time. + * However, you can also build relocateable binaries + * where the datadir is relative to the program's executable. + * + * @note Beginning with glib v2.58, we could directly use + * g_canonicalize_filename(). + */ +gchar * +teco_file_get_datadir(void) +{ + if (g_path_is_absolute(SCITECODATADIR)) + return g_strdup(SCITECODATADIR); + + /* relocateable binary - datadir is relative to binary */ + g_autofree gchar *program_path = teco_file_get_program_path(); + g_autofree gchar *datadir = g_build_filename(program_path, SCITECODATADIR, NULL); + return teco_file_get_absolute_path(datadir); +} + /** * Perform tilde expansion on a file name or path. * diff --git a/src/file-utils.h b/src/file-utils.h index 4ee59e6..e974e2f 100644 --- a/src/file-utils.h +++ b/src/file-utils.h @@ -68,6 +68,18 @@ teco_file_normalize_path(gchar *path) gboolean teco_file_is_visible(const gchar *path); +/** + * Get absolute path of the program executable. + * + * This may return the current working directory on + * unsupported platforms. + * + * @return Newly-allocated path. + */ +gchar *teco_file_get_program_path(void); + +gchar *teco_file_get_datadir(void); + gchar *teco_file_expand_path(const gchar *path); /** diff --git a/src/interface-gtk/interface.c b/src/interface-gtk/interface.c index 3121b05..829310a 100644 --- a/src/interface-gtk/interface.c +++ b/src/interface-gtk/interface.c @@ -51,6 +51,7 @@ #include "sciteco.h" #include "error.h" #include "string-utils.h" +#include "file-utils.h" #include "cmdline.h" #include "qreg.h" #include "ring.h" @@ -1124,6 +1125,8 @@ teco_interface_event_loop(GError **error) } g_assert(scitecoconfig.data != NULL); + g_autofree gchar *datadir = teco_file_get_datadir(); + /* * Initialize the CSS variable provider and the CSS provider * for the included fallback.css. @@ -1138,14 +1141,7 @@ teco_interface_event_loop(GError **error) if (!g_file_test(user_css_file, G_FILE_TEST_IS_REGULAR)) { /* use fallback CSS */ g_free(user_css_file); - /* - * FIXME: See above for icons. - */ -#ifdef G_OS_WIN32 - user_css_file = g_build_filename(scitecoconfig.data, "fallback.css", NULL); -#else - user_css_file = g_build_filename(SCITECODATADIR, "fallback.css", NULL); -#endif + user_css_file = g_build_filename(datadir, "fallback.css", NULL); } GtkCssProvider *user_css_provider = gtk_css_provider_new(); @@ -1170,15 +1166,10 @@ teco_interface_event_loop(GError **error) /* * FIXME: This is necessary so that the icon themes are found in the same * directory as sciteco.exe. - * This fails of course when $SCITECOCONFIG is changed. - * We should perhaps always use the absolute path of sciteco.exe. - * If you want to install SciTECO differently, you can still set - * $XDG_DATA_DIRS. - * - * FIXME FIXME FIXME: This is also currently broken. */ - //g_autofree char *theme_path = g_build_filename(scitecoconfig.data, "icons"); - //gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), theme_path); + g_autofree gchar *program_path = teco_file_get_program_path(); + g_autofree gchar *theme_path = g_build_filename(program_path, "icons", NULL); + gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), theme_path); #else /* * Load icons for the GTK window. @@ -1186,17 +1177,16 @@ teco_interface_event_loop(GError **error) * as a resource will be used by default. */ static const gchar *icon_files[] = { - SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-48.png", - SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-32.png", - SCITECODATADIR G_DIR_SEPARATOR_S "sciteco-16.png" + "sciteco-48.png", "sciteco-32.png", "sciteco-16.png" }; GList *icon_list = NULL; for (gint i = 0; i < G_N_ELEMENTS(icon_files); i++) { - GdkPixbuf *icon_pixbuf = gdk_pixbuf_new_from_file(icon_files[i], NULL); + g_autofree gchar *icon_file = g_build_filename(datadir, icon_files[i], NULL); + GdkPixbuf *icon_pixbuf = gdk_pixbuf_new_from_file(icon_file, NULL); /* fail silently if there's a problem with one of the icons */ - if (icon_pixbuf) + if (G_LIKELY(icon_pixbuf != NULL)) icon_list = g_list_append(icon_list, icon_pixbuf); } @@ -77,15 +77,15 @@ volatile sig_atomic_t teco_interrupted = FALSE; * program's directory. */ static inline gchar * -teco_get_default_config_path(const gchar *program) +teco_get_default_config_path(void) { - return g_path_get_dirname(program); + return teco_file_get_program_path(); } #elif defined(G_OS_UNIX) && !defined(__HAIKU__) static inline gchar * -teco_get_default_config_path(const gchar *program) +teco_get_default_config_path(void) { return g_strdup(g_get_home_dir()); } @@ -99,7 +99,7 @@ teco_get_default_config_path(const gchar *program) * with config files. */ static inline gchar * -teco_get_default_config_path(const gchar *program) +teco_get_default_config_path(void) { return g_strdup(g_get_user_config_dir()); } @@ -210,7 +210,7 @@ teco_process_options(gchar ***argv) } static void -teco_initialize_environment(const gchar *program) +teco_initialize_environment(void) { g_autoptr(GError) error = NULL; gchar *abs_path; @@ -252,14 +252,11 @@ teco_initialize_environment(const gchar *program) /* * Initialize $SCITECOCONFIG and $SCITECOPATH */ - g_autofree gchar *default_configpath = teco_get_default_config_path(program); + g_autofree gchar *default_configpath = teco_get_default_config_path(); g_setenv("SCITECOCONFIG", default_configpath, FALSE); -#ifdef G_OS_WIN32 - g_autofree gchar *default_scitecopath = g_build_filename(default_configpath, "lib", NULL); - g_setenv("SCITECOPATH", default_scitecopath, FALSE); -#else - g_setenv("SCITECOPATH", SCITECOLIBDIR, FALSE); -#endif + g_autofree gchar *datadir = teco_file_get_datadir(); + g_autofree gchar *default_libdir = g_build_filename(datadir, "lib", NULL); + g_setenv("SCITECOPATH", default_libdir, FALSE); /* * $SCITECOCONFIG and $SCITECOPATH may still be relative. @@ -389,7 +386,7 @@ main(int argc, char **argv) /* current working directory ("$") */ teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_workingdir_new()); /* environment defaults and registers */ - teco_initialize_environment(argv_utf8[0]); + teco_initialize_environment(); teco_qreg_table_t local_qregs; teco_qreg_table_init(&local_qregs, TRUE); |