diff --git a/src/libmain.c b/src/libmain.c index cbe2cf1bd9..7c9faa532d 100644 --- a/src/libmain.c +++ b/src/libmain.c @@ -145,6 +145,117 @@ static GOptionEntry entries[] = }; +/* Information about command line entries that can not be stored in GOptionEntry. */ +typedef struct +{ + gboolean persistent; /* The option should be passed to "New Window" */ +} +GeanyOptionEntryAux; + + +static GeanyOptionEntryAux optentries_aux[] = { + {FALSE}, /* "column" */ + {TRUE}, /* "config" */ + {FALSE}, /* "ft-names */ + {FALSE}, /* "generate-tags" */ + {FALSE}, /* "no-preprocessing" */ +#ifdef HAVE_SOCKET + {FALSE}, /* "new-instance" */ + {FALSE}, /* "socket-file" */ + {FALSE}, /* "list-documents" */ +#endif + {FALSE}, /* "line" */ + {TRUE}, /* "no-msgwin" */ + {TRUE}, /* "no-ctags" */ +#ifdef HAVE_PLUGINS + {TRUE}, /* "no-plugins" */ +#endif + {FALSE}, /* "print-prefix" */ + {FALSE}, /* "read-only" */ + {FALSE}, /* "no-session" */ +#ifdef HAVE_VTE + {TRUE}, /* "no-terminal" */ + {TRUE}, /* "vte-lib" */ +#endif + {TRUE}, /* "verbose" */ + {FALSE}, /* "version" */ + {FALSE} /* "dummy" */ +}; + + +static gchar *option_entry_reverse_parse(const GOptionEntry *optentry) +{ + gchar *s = NULL; + + switch (optentry->arg) + { + case G_OPTION_ARG_NONE : + { + gboolean val = *(gboolean *)optentry->arg_data; + gboolean reverse = (optentry->flags & G_OPTION_FLAG_REVERSE); + + if ((val && !reverse) || (!val && reverse)) /* logical XOR */ + s = g_strdup_printf("--%s", optentry->long_name); + break; + } + + case G_OPTION_ARG_INT : + if (*(gint *)optentry->arg_data) + s = g_strdup_printf("--%s=%d", optentry->long_name, *(gint *)optentry->arg_data); + break; + + case G_OPTION_ARG_STRING : + case G_OPTION_ARG_FILENAME : + if (*(gchar **)optentry->arg_data) + { + s = g_strdup_printf("--%s=%s", optentry->long_name, *(gchar **)optentry->arg_data); + #ifdef G_OS_UNIX + if (optentry->arg == G_OPTION_ARG_FILENAME) + break; /* POSIX filenames are native */ + #endif + /* On conversion failure, return NULL to skip the option, instead of + a wrong UTF-8 "fallback" value. Besides, we currently have only + "config" and "vte-lib" here, and they're almost surely ascii. */ + SETPTR(s, g_locale_from_utf8(s, -1, NULL, NULL, NULL)); + } + break; + + default: + g_warning("%s: %s: %d\n", G_STRFUNC, "Unsupported option entry type", optentry->arg); + } + + return s; +} + + +/* get the options that should be passed to a new window */ +gchar **main_get_persistent_argv(void) +{ + gchar **argv; + int i, argc; + + for (i = 0, argc = 0; entries[i].long_name; i++) + if (optentries_aux[i].persistent) + argc++; + + argv = g_new(gchar *, argc + 1); + + for (i = 0, argc = 0; entries[i].long_name; i++) + { + if (optentries_aux[i].persistent) + { + char *option = option_entry_reverse_parse(&entries[i]); + + if (option) + argv[argc++] = option; + } + } + + argv[argc] = NULL; + return argv; +} + + static void setup_window_position(void) { /* interprets the saved window geometry */ @@ -225,7 +336,7 @@ static void apply_settings(void) static void main_init(void) { /* add our icon path in case we aren't installed in the system prefix */ - gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_dir(RESOURCE_DIR_ICON)); + gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_path(RESOURCE_PATH_ICON_DIR)); /* inits */ ui_init_stock_items(); @@ -396,8 +507,8 @@ static void change_working_directory_on_windows(void) static void setup_paths(void) { /* convert path names to locale encoding */ - app->datadir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DATA)); - app->docdir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DOC)); + app->datadir = utils_get_locale_from_utf8(utils_resource_path(RESOURCE_PATH_DATA_DIR)); + app->docdir = utils_get_locale_from_utf8(utils_resource_path(RESOURCE_PATH_DOC_DIR)); } @@ -454,7 +565,7 @@ void main_locale_init(const gchar *locale_dir, const gchar *package) #endif #ifdef G_OS_WIN32 - locale_dir = utils_resource_dir(RESOURCE_DIR_LOCALE); + locale_dir = utils_resource_path(RESOURCE_PATH_LOCALE_DIR); #endif (void) bindtextdomain(package, locale_dir); (void) bind_textdomain_codeset(package, "UTF-8"); @@ -569,7 +680,7 @@ static void parse_command_line_options(gint *argc, gchar ***argv) if (alternate_config) { geany_debug("alternate config: %s", alternate_config); - app->configdir = alternate_config; + app->configdir = g_strdup(alternate_config); } else { @@ -1033,7 +1144,7 @@ gint main_lib(gint argc, gchar **argv) setup_gtk2_styles(); #endif #ifdef ENABLE_NLS - main_locale_init(utils_resource_dir(RESOURCE_DIR_LOCALE), GETTEXT_PACKAGE); + main_locale_init(utils_resource_path(RESOURCE_PATH_LOCALE_DIR), GETTEXT_PACKAGE); #endif parse_command_line_options(&argc, &argv); diff --git a/src/main.h b/src/main.h index f2babac344..f806d2efc2 100644 --- a/src/main.h +++ b/src/main.h @@ -65,6 +65,8 @@ GeanyStatus; extern GeanyStatus main_status; +gchar **main_get_persistent_argv(void); + const gchar *main_get_version_string(void); gchar *main_get_argv_filename(const gchar *filename); diff --git a/src/plugins.c b/src/plugins.c index bcc42e9b90..ebe29b49e3 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -883,7 +883,7 @@ load_plugins_from_path(const gchar *path) static gchar *get_plugin_path(void) { - return g_strdup(utils_resource_dir(RESOURCE_DIR_PLUGIN)); + return g_strdup(utils_resource_path(RESOURCE_PATH_PLUGIN_DIR)); } diff --git a/src/utils.c b/src/utils.c index b6ad701345..2273e754eb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -32,6 +32,8 @@ #include "app.h" #include "dialogs.h" #include "document.h" +#include "keyfile.h" +#include "main.h" #include "prefs.h" #include "prefix.h" #include "sciwrappers.h" @@ -2108,83 +2110,96 @@ static gboolean is_osx_bundle(void) } -const gchar *utils_resource_dir(GeanyResourceDirType type) +const gchar *utils_resource_path(GeanyResourcePathType type) { - static const gchar *resdirs[RESOURCE_DIR_COUNT] = {NULL}; + static const gchar *respaths[RESOURCE_PATH_COUNT] = {NULL}; - if (!resdirs[RESOURCE_DIR_DATA]) + if (!respaths[RESOURCE_PATH_DATA_DIR]) { #ifdef G_OS_WIN32 gchar *prefix = win32_get_installation_dir(); - resdirs[RESOURCE_DIR_DATA] = g_build_filename(prefix, "data", NULL); - resdirs[RESOURCE_DIR_ICON] = g_build_filename(prefix, "share", "icons", NULL); - resdirs[RESOURCE_DIR_DOC] = g_build_filename(prefix, "doc", NULL); - resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(prefix, "share", "locale", NULL); - resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(prefix, "lib", "geany", NULL); + respaths[RESOURCE_PATH_DATA_DIR] = g_build_filename(prefix, "data", NULL); + respaths[RESOURCE_PATH_ICON_DIR] = g_build_filename(prefix, "share", "icons", NULL); + respaths[RESOURCE_PATH_DOC_DIR] = g_build_filename(prefix, "doc", NULL); + respaths[RESOURCE_PATH_LOCALE_DIR] = g_build_filename(prefix, "share", "locale", NULL); + respaths[RESOURCE_PATH_PLUGIN_DIR] = g_build_filename(prefix, "lib", "geany", NULL); + respaths[RESOURCE_PATH_EXECUTABLE] = g_build_filename(prefix, "bin", "geany", NULL); g_free(prefix); + if (!g_file_test(respaths[RESOURCE_PATH_EXECUTABLE], G_FILE_TEST_IS_EXECUTABLE)) + respaths[RESOURCE_PATH_EXECUTABLE] = "geany"; #else if (is_osx_bundle()) { # ifdef MAC_INTEGRATION gchar *prefix = gtkosx_application_get_resource_path(); - resdirs[RESOURCE_DIR_DATA] = g_build_filename(prefix, "share", "geany", NULL); - resdirs[RESOURCE_DIR_ICON] = g_build_filename(prefix, "share", "icons", NULL); - resdirs[RESOURCE_DIR_DOC] = g_build_filename(prefix, "share", "doc", "geany", "html", NULL); - resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(prefix, "share", "locale", NULL); - resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(prefix, "lib", "geany", NULL); + respaths[RESOURCE_PATH_DATA_DIR] = g_build_filename(prefix, "share", "geany", NULL); + respaths[RESOURCE_PATH_ICON_DIR] = g_build_filename(prefix, "share", "icons", NULL); + respaths[RESOURCE_PATH_DOC_DIR] = g_build_filename(prefix, "share", "doc", "geany", "html", NULL); + respaths[RESOURCE_PATH_LOCALE_DIR] = g_build_filename(prefix, "share", "locale", NULL); + respaths[RESOURCE_PATH_PLUGIN_DIR] = g_build_filename(prefix, "lib", "geany", NULL); + respaths[RESOURCE_PATH_EXECUTABLE] = gtkosx_application_get_executable_path(); g_free(prefix); + if (!respaths[RESOURCE_PATH_EXECUTABLE]) + respaths[RESOURCE_PATH_EXECUTABLE] = "geany"; # endif } else { - resdirs[RESOURCE_DIR_DATA] = g_build_filename(GEANY_DATADIR, "geany", NULL); - resdirs[RESOURCE_DIR_ICON] = g_build_filename(GEANY_DATADIR, "icons", NULL); - resdirs[RESOURCE_DIR_DOC] = g_build_filename(GEANY_DOCDIR, "html", NULL); - resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(GEANY_LOCALEDIR, NULL); - resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(GEANY_LIBDIR, "geany", NULL); + respaths[RESOURCE_PATH_DATA_DIR] = g_build_filename(GEANY_DATADIR, "geany", NULL); + respaths[RESOURCE_PATH_ICON_DIR] = g_build_filename(GEANY_DATADIR, "icons", NULL); + respaths[RESOURCE_PATH_DOC_DIR] = g_build_filename(GEANY_DOCDIR, "html", NULL); + respaths[RESOURCE_PATH_LOCALE_DIR] = g_build_filename(GEANY_LOCALEDIR, NULL); + respaths[RESOURCE_PATH_PLUGIN_DIR] = g_build_filename(GEANY_LIBDIR, "geany", NULL); + respaths[RESOURCE_PATH_EXECUTABLE] = g_build_filename(GEANY_PREFIX, "bin", "geany", NULL); + if (!g_file_test(respaths[RESOURCE_PATH_EXECUTABLE], G_FILE_TEST_IS_EXECUTABLE)) + respaths[RESOURCE_PATH_EXECUTABLE] = "geany"; } #endif } - return resdirs[type]; + return respaths[type]; } void utils_start_new_geany_instance(const gchar *doc_path) { - const gchar *command = is_osx_bundle() ? "open" : "geany"; - gchar *exec_path = g_find_program_in_path(command); + gchar **pers_argv = main_get_persistent_argv(); + gint pers_argc; + gchar **argv; + int argc; + GError *error = NULL; - if (exec_path) - { - GError *err = NULL; - const gchar *argv[6]; // max args + 1 - gint argc = 0; + /* count only, the for body is empty */ + for (pers_argc = 0; pers_argv[pers_argc]; pers_argc++); - argv[argc++] = exec_path; - if (is_osx_bundle()) - { - argv[argc++] = "-n"; - argv[argc++] = "-a"; - argv[argc++] = "Geany"; - argv[argc++] = doc_path; - } - else - { - argv[argc++] = "-i"; - argv[argc++] = doc_path; - } - argv[argc] = NULL; + argc = pers_argc + 3; /* exectuable, -i, , doc_path */ + argv = g_new(gchar *, argc + 1); - if (!utils_spawn_async(NULL, (gchar**) argv, NULL, 0, NULL, NULL, NULL, &err)) - { - g_printerr("Unable to open new window: %s", err->message); - g_error_free(err); - } - g_free(exec_path); + argv[0] = g_strdup(utils_resource_path(RESOURCE_PATH_EXECUTABLE)); + argv[1] = g_strdup("-i"); + + memcpy(argv + 2, pers_argv, pers_argc * sizeof(char *)); + g_free(pers_argv); /* elements are freed via argv */ + +#ifdef G_OS_UNIX + argv[argc - 1] = g_strdup(doc_path); /* POSIX filenames are native */ +#else + /* On conversion failure, pass the NULL to open an empty window, instead + of replacing it with a definitely wrong UTF-8 "fallback" file name. */ + argv[argc - 1] = doc_path ? g_locale_from_utf8(doc_path, -1, NULL, NULL, NULL) : NULL; +#endif + argv[argc] = NULL; + + /* Ensure the configuration is saved to disk before launching the new instance */ + configuration_save(); + + if (!spawn_async(NULL, NULL, argv, NULL, NULL, &error)) + { + ui_set_statusbar(TRUE, _("Unable to open new Geany window: %s"), error->message); + g_error_free(error); } - else - g_printerr("Unable to find 'geany'"); + + g_strfreev(argv); } diff --git a/src/utils.h b/src/utils.h index 85d830036c..980b76d9c0 100644 --- a/src/utils.h +++ b/src/utils.h @@ -202,14 +202,15 @@ const gchar *utils_find_open_xml_tag_pos(const gchar sel[], gint size); typedef enum { - RESOURCE_DIR_DATA, - RESOURCE_DIR_ICON, - RESOURCE_DIR_DOC, - RESOURCE_DIR_LOCALE, - RESOURCE_DIR_PLUGIN, + RESOURCE_PATH_DATA_DIR, + RESOURCE_PATH_ICON_DIR, + RESOURCE_PATH_DOC_DIR, + RESOURCE_PATH_LOCALE_DIR, + RESOURCE_PATH_PLUGIN_DIR, + RESOURCE_PATH_EXECUTABLE, - RESOURCE_DIR_COUNT -} GeanyResourceDirType; + RESOURCE_PATH_COUNT +} GeanyResourcePathType; gint utils_get_line_endings(const gchar* buffer, gsize size); @@ -308,7 +309,7 @@ gchar *utils_parse_and_format_build_date(const gchar *input); gchar *utils_get_user_config_dir(void); -const gchar *utils_resource_dir(GeanyResourceDirType type); +const gchar *utils_resource_path(GeanyResourcePathType type); void utils_start_new_geany_instance(const gchar *doc_path);