Mercurial > geeqie
changeset 1272:e0e12512cde2
read external editors from .desktop files
author | nadvornik |
---|---|
date | Sun, 01 Feb 2009 12:48:14 +0000 |
parents | 4fcdbb497df3 |
children | 1ac2baeb8dc9 |
files | Makefile.am configure.in plugins/Makefile.am plugins/symlink/Makefile.am plugins/symlink/symlink.desktop src/bar_sort.c src/collect-table.c src/collect.c src/dupe.c src/editors.c src/editors.h src/img-view.c src/layout_image.c src/layout_util.c src/layout_util.h src/main.c src/main.h src/menu.c src/options.c src/options.h src/pan-view.c src/preferences.c src/rcfile.c src/search.c src/typedefs.h src/utilops.c src/utilops.h src/view_dir.c src/view_file.c |
diffstat | 29 files changed, 745 insertions(+), 369 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.am Thu Jan 29 19:43:34 2009 +0000 +++ b/Makefile.am Sun Feb 01 12:48:14 2009 +0000 @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = src po doc -DIST_SUBDIRS = src po doc +SUBDIRS = src po doc plugins +DIST_SUBDIRS = src po doc plugins man_MANS = geeqie.1
--- a/configure.in Thu Jan 29 19:43:34 2009 +0000 +++ b/configure.in Sun Feb 01 12:48:14 2009 +0000 @@ -208,6 +208,9 @@ AC_SUBST(readmedir) AC_SUBST(htmldir) +eval "eval appdir=${datadir}/${PACKAGE}" +AC_DEFINE_UNQUOTED([GQ_APP_DIR], "$appdir", [Location of application data]) + # LIRC support # ---------------------------------------------------------------------- @@ -351,6 +354,8 @@ src/icons/svg/Makefile po/Makefile.in doc/Makefile + plugins/Makefile + plugins/symlink/Makefile geeqie.spec ])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/Makefile.am Sun Feb 01 12:48:14 2009 +0000 @@ -0,0 +1,2 @@ +SUBDIRS = symlink +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/symlink/Makefile.am Sun Feb 01 12:48:14 2009 +0000 @@ -0,0 +1,5 @@ + +qq_desktopdir = $(pkgdatadir)/applications +qq_desktop_DATA = symlink.desktop + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/symlink/symlink.desktop Sun Feb 01 12:48:14 2009 +0000 @@ -0,0 +1,24 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Symlink +#Name[cs]= + +# FIXME: this can't be an oneliner, it needs to be changed to a full +# featured script in separate file, with error handling etc. +# expansion of environment variables directly in Exec is not supported +# by the specification and it will be removed +Exec=ln -s %f "$GEEQIE_DESTINATION" + +# Desktop files that are usable only in Geeqie should be marked like this: +Categories=X-Geeqie; +OnlyShowIn=X-Geeqie; + +# Show in menu "File" +X-Geeqie-Menu-Path=FileMenu + +# This is a filter - $GEEQIE_DESTINATION is required +X-Geeqie-Filter=true + +# It can be made verbose +# X-Geeqie-Verbose=true
--- a/src/bar_sort.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/bar_sort.c Sun Feb 01 12:48:14 2009 +0000 @@ -44,7 +44,7 @@ BAR_SORT_COPY = 0, BAR_SORT_MOVE, BAR_SORT_FILTER, - BAR_SORT_ACTION_COUNT = BAR_SORT_FILTER + GQ_EDITOR_GENERIC_SLOTS + BAR_SORT_ACTION_COUNT } SortActionType; typedef enum { @@ -65,6 +65,8 @@ SortModeType mode; SortActionType action; + const gchar *filter_key; + SortSelectionType selection; GtkWidget *folder_group; @@ -282,13 +284,12 @@ file_util_move_simple(list, path, sd->lw->window); list = NULL; break; + case BAR_SORT_FILTER: + file_util_start_filter_from_filelist(sd->filter_key, list, path, sd->lw->window); + list = NULL; + layout_image_next(sd->lw); + break; default: - if (sd->action >= BAR_SORT_FILTER && sd->action < BAR_SORT_ACTION_COUNT) - { - file_util_start_filter_from_filelist(sd->action - BAR_SORT_FILTER, list, path, sd->lw->window); - list = NULL; - layout_image_next(sd->lw); - } break; } @@ -348,35 +349,46 @@ } } -static void bar_sort_set_action(SortData *sd, SortActionType action) +static void bar_sort_set_action(SortData *sd, SortActionType action, const gchar *filter_key) { options->panels.sort.action_state = sd->action = action; + if (action == BAR_SORT_FILTER) + { + if (!filter_key) filter_key = ""; + sd->filter_key = filter_key; + g_free(options->panels.sort.action_filter); + options->panels.sort.action_filter = g_strdup(filter_key); + } + else + { + sd->filter_key = NULL; + g_free(options->panels.sort.action_filter); + options->panels.sort.action_filter = g_strdup(""); + } } static void bar_sort_set_copy_cb(GtkWidget *button, gpointer data) { SortData *sd = data; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return; - bar_sort_set_action(sd, BAR_SORT_COPY); + bar_sort_set_action(sd, BAR_SORT_COPY, NULL); } static void bar_sort_set_move_cb(GtkWidget *button, gpointer data) { SortData *sd = data; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return; - bar_sort_set_action(sd, BAR_SORT_MOVE); + bar_sort_set_action(sd, BAR_SORT_MOVE, NULL); } static void bar_sort_set_filter_cb(GtkWidget *button, gpointer data) { SortData *sd = data; - guint n; + const gchar *key; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return; - n = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(button), "filter_idx")); - if (n == 0) return; - n--; - bar_sort_set_action(sd, BAR_SORT_FILTER + n); + key = g_object_get_data(G_OBJECT(button), "filter_key"); + bar_sort_set_action(sd, BAR_SORT_FILTER, key); } static void bar_sort_set_selection(SortData *sd, SortSelectionType selection) @@ -551,7 +563,8 @@ GtkWidget *tbar; GtkWidget *combo; SortModeType mode; - guint i; + GList *editors_list, *work; + gboolean have_filter; if (!lw) return NULL; @@ -562,7 +575,9 @@ mode = CLAMP(options->panels.sort.mode_state, 0, BAR_SORT_MODE_COUNT - 1); sd->action = CLAMP(options->panels.sort.action_state, 0, BAR_SORT_ACTION_COUNT - 1); - while (sd->action >= BAR_SORT_FILTER && !editor_is_filter(sd->action - BAR_SORT_FILTER)) sd->action--; + if (sd->action == BAR_SORT_FILTER && + (!options->panels.sort.action_filter || !options->panels.sort.action_filter[0])) + sd->action = BAR_SORT_COPY; sd->selection = CLAMP(options->panels.sort.selection_state, 0, BAR_SORT_SELECTION_COUNT - 1); sd->undo_src = NULL; @@ -598,21 +613,35 @@ G_CALLBACK(bar_sort_set_move_cb), sd); - for (i = 0; i < GQ_EDITOR_GENERIC_SLOTS; i++) + have_filter = FALSE; + editors_list = editor_list_get(); + work = editors_list; + while (work) { GtkWidget *button; + EditorDescription *editor = work->data; + work = work->next; + gboolean select = FALSE; + + if (!editor_is_filter(editor->key)) continue; - const gchar *name = editor_get_name(i); - if (!name || !editor_is_filter(i)) continue; + if (sd->action == BAR_SORT_FILTER && strcmp(editor->key, options->panels.sort.action_filter) == 0) + { + bar_sort_set_action(sd, sd->action, editor->key); + select = TRUE; + have_filter = TRUE; + } button = pref_radiobutton_new(sd->folder_group, buttongrp, - name, (sd->action == BAR_SORT_FILTER + i), + editor->name, select, G_CALLBACK(bar_sort_set_filter_cb), sd); - g_object_set_data(G_OBJECT(button), "filter_idx", GUINT_TO_POINTER(i + 1)); + g_object_set_data(G_OBJECT(button), "filter_key", editor->key); } - + g_list_free(editors_list); + + if (sd->action == BAR_SORT_FILTER && !have_filter) sd->action = BAR_SORT_COPY; sd->collection_group = pref_box_new(sd->vbox, FALSE, GTK_ORIENTATION_VERTICAL, 0);
--- a/src/collect-table.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/collect-table.c Sun Feb 01 12:48:14 2009 +0000 @@ -654,18 +654,17 @@ static void collection_table_popup_edit_cb(GtkWidget *widget, gpointer data) { CollectTable *ct; - gint n; + const gchar *key = data; GList *list; ct = submenu_item_get_data(widget); if (!ct) return; - n = GPOINTER_TO_INT(data); list = collection_table_popup_file_list(ct); if (list) { - file_util_start_editor_from_filelist(n, list, ct->listview); + file_util_start_editor_from_filelist(key, list, ct->listview); filelist_free(list); } }
--- a/src/collect.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/collect.c Sun Feb 01 12:48:14 2009 +0000 @@ -947,14 +947,14 @@ break; } } - +#if 0 if (edit_val != -1) { list = collection_table_selection_get_list(cw->table); file_util_start_editor_from_filelist(edit_val, list, cw->window); filelist_free(list); } - +#endif return stop_signal; }
--- a/src/dupe.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/dupe.c Sun Feb 01 12:48:14 2009 +0000 @@ -2051,13 +2051,13 @@ dupe_listview_realign_colors(dw); } -static void dupe_window_edit_selected(DupeWindow *dw, gint n) +static void dupe_window_edit_selected(DupeWindow *dw, const gchar *key) { GList *list; list = dupe_listview_get_selection(dw, dw->listview); - file_util_start_editor_from_filelist(n, list, dw->window); + file_util_start_editor_from_filelist(key, list, dw->window); filelist_free(list); } @@ -2139,13 +2139,12 @@ static void dupe_menu_edit_cb(GtkWidget *widget, gpointer data) { DupeWindow *dw; - gint n; + const gchar *key = data; dw = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); if (!dw) return; - dupe_window_edit_selected(dw, n); + dupe_window_edit_selected(dw, key); } static void dupe_menu_info_cb(GtkWidget *widget, gpointer data) @@ -2990,11 +2989,12 @@ break; } } - +#if 0 if (edit_val >= 0) { dupe_window_edit_selected(dw, edit_val); } +#endif } else {
--- a/src/editors.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/editors.c Sun Feb 01 12:48:14 2009 +0000 @@ -44,7 +44,6 @@ struct _EditorData { gint flags; GPid pid; - gchar *command_template; GList *list; gint count; gint total; @@ -52,41 +51,15 @@ EditorVerboseData *vd; EditorCallback callback; gpointer data; + const EditorDescription *editor; }; -static Editor editor_slot_defaults[GQ_EDITOR_SLOTS] = { - { N_("The Gimp"), "gimp-remote %{%raw;*}f" }, - { N_("XV"), "xv %f" }, - { N_("Xpaint"), "xpaint %f" }, - { N_("UFraw"), "ufraw %{%raw}p" }, - { N_("Symlink"), "ln -s %p %d"}, - { NULL, NULL }, - { NULL, NULL }, - { NULL, NULL }, - { N_("Rotate jpeg clockwise"), "%vif jpegtran -rotate 90 -copy all -outfile %{.jpg;.jpeg}p_tmp %{.jpg;.jpeg}p; then mv %{.jpg;.jpeg}p_tmp %{.jpg;.jpeg}p;else rm %{.jpg;.jpeg}p_tmp;fi" }, - { N_("Rotate jpeg counterclockwise"), "%vif jpegtran -rotate 270 -copy all -outfile %{.jpg;.jpeg}p_tmp %{.jpg;.jpeg}p; then mv %{.jpg;.jpeg}p_tmp %{.jpg;.jpeg}p;else rm %{.jpg;.jpeg}p_tmp;fi" }, - /* special slots */ -#if 1 - /* for testing */ - { N_("External Copy command"), "%vset -x;cp %p %d" }, - { N_("External Move command"), "%vset -x;mv %p %d" }, - { N_("External Rename command"), "%vset -x;mv %p %d" }, - { N_("External Delete command"), NULL }, - { N_("External New Folder command"), NULL }, -#else - { N_("External Copy command"), NULL }, - { N_("External Move command"), NULL }, - { N_("External Rename command"), NULL }, - { N_("External Delete command"), NULL }, - { N_("External New Folder command"), NULL }, -#endif -}; - static void editor_verbose_window_progress(EditorData *ed, const gchar *text); static gint editor_command_next_start(EditorData *ed); static gint editor_command_next_finish(EditorData *ed, gint status); static gint editor_command_done(EditorData *ed); +static gint editor_command_parse(const EditorDescription *editor, GList *list, gchar **output); /* *----------------------------------------------------------------------------- @@ -94,34 +67,310 @@ *----------------------------------------------------------------------------- */ -void editor_set_name(gint n, gchar *name) +GHashTable *editors = NULL; + +#ifdef G_KEY_FILE_DESKTOP_GROUP +#define DESKTOP_GROUP G_KEY_FILE_DESKTOP_GROUP +#else +#define DESKTOP_GROUP "Desktop Entry" +#endif + +void editor_description_free(EditorDescription *editor) { - if (n < 0 || n >= GQ_EDITOR_SLOTS) return; + if (!editor) return; + + g_free(editor->key); + g_free(editor->name); + g_free(editor->exec); + g_free(editor->menu_path); + g_free(editor->hotkey); + string_list_free(editor->ext_list); + g_free(editor->icon); + g_free(editor->file); + g_free(editor); +} - g_free(options->editor[n].name); +static GList *editor_mime_types_to_extensions(gchar **mime_types) +{ + /* FIXME: this should be rewritten to use the shared mime database, as soon as we switch to gio */ - options->editor[n].name = name ? utf8_validate_or_convert(name) : NULL; + static const gchar *conv_table[][2] = { + {"application/x-ufraw", "%raw"}, + {"image/*", "*"}, + {"image/bmp", ".bmp"}, + {"image/gif", ".gif"}, + {"image/jpeg", ".jpeg;.jpg"}, + {"image/jpg", ".jpg;.jpeg"}, + {"image/pcx", ".pcx"}, + {"image/png", ".png"}, + {"image/svg", ".svg"}, + {"image/svg+xml", ".svg"}, + {"image/svg+xml-compressed", ".svg"}, + {"image/tiff", ".tiff;.tif"}, + {"image/x-bmp", ".bmp"}, + {"image/x-canon-crw", ".crw"}, + {"image/x-cr2", ".cr2"}, + {"image/x-dcraw", "%raw"}, + {"image/x-ico", ".ico"}, + {"image/x-mrw", ".mrw"}, + {"image/x-MS-bmp", ".bmp"}, + {"image/x-nef", ".nef"}, + {"image/x-orf", ".orf"}, + {"image/x-pcx", ".pcx"}, + {"image/xpm", ".xpm"}, + {"image/x-png", ".png"}, + {"image/x-portable-anymap", ".pam"}, + {"image/x-portable-bitmap", ".pbm"}, + {"image/x-portable-graymap", ".pgm"}, + {"image/x-portable-pixmap", ".ppm"}, + {"image/x-psd", ".psd"}, + {"image/x-raf", ".raf"}, + {"image/x-sgi", ".sgi"}, + {"image/x-tga", ".tga"}, + {"image/x-xbitmap", ".xbm"}, + {"image/x-xcf", ".xcf"}, + {"image/x-xpixmap", ".xpm"}, + {"image/x-x3f", ".x3f"}, + {NULL, NULL}}; + + gint i, j; + GList *list = NULL; + + for (i = 0; mime_types[i]; i++) + for (j = 0; conv_table[j][0]; j++) + if (strcmp(mime_types[i], conv_table[j][0]) == 0) + list = g_list_concat(list, filter_to_list(conv_table[j][1])); + + return list; } -void editor_set_command(gint n, gchar *command) +static gboolean editor_read_desktop_file(const gchar *path) { - if (n < 0 || n >= GQ_EDITOR_SLOTS) return; + GKeyFile *key_file; + EditorDescription *editor; + gchar *extensions; + const gchar *key = filename_from_path(path); + gchar **categories, **only_show_in, **not_show_in; + + if (g_hash_table_lookup(editors, key)) return FALSE; /* the file found earlier wins */ + + key_file = g_key_file_new(); + if (!g_key_file_load_from_file(key_file, path, 0, NULL)) + { + g_key_file_free(key_file); + return FALSE; + } + + editor = g_new0(EditorDescription, 1); + + editor->key = g_strdup(key); + editor->file = g_strdup(path); + + g_hash_table_insert(editors, editor->key, editor); + + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "Hidden", NULL)) editor->hidden = TRUE; + + categories = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "Categories", NULL, NULL); + if (categories) + { + gboolean found = FALSE; + gint i; + for (i = 0; categories[i]; i++) + /* IMHO "Graphics" is exactly the category that we are interested in, so this does not have to be configurable */ + if (strcmp(categories[i], "Graphics") == 0 || + strcmp(categories[i], "X-Geeqie") == 0) + { + found = TRUE; + break; + } + if (!found) editor->hidden = TRUE; + g_strfreev(categories); + } + else + { + editor->hidden = TRUE; + } + + only_show_in = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "OnlyShowIn", NULL, NULL); + if (only_show_in) + { + gboolean found = FALSE; + gint i; + for (i = 0; only_show_in[i]; i++) + if (strcmp(only_show_in[i], "X-Geeqie") == 0) + { + found = TRUE; + break; + } + if (!found) editor->hidden = TRUE; + g_strfreev(only_show_in); + } - g_free(options->editor[n].command); - options->editor[n].command = command ? utf8_validate_or_convert(command) : NULL; + not_show_in = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "NotShowIn", NULL, NULL); + if (not_show_in) + { + gboolean found = FALSE; + gint i; + for (i = 0; not_show_in[i]; i++) + if (strcmp(not_show_in[i], "X-Geeqie") == 0) + { + found = TRUE; + break; + } + if (found) editor->hidden = TRUE; + g_strfreev(not_show_in); + } + + if (editor->hidden) + { + /* hidden editors will be deleted, no need to parse the rest */ + g_key_file_free(key_file); + return TRUE; + } + + editor->name = g_key_file_get_locale_string(key_file, DESKTOP_GROUP, "Name", NULL, NULL); + editor->icon = g_key_file_get_string(key_file, DESKTOP_GROUP, "Icon", NULL); + + editor->exec = g_key_file_get_string(key_file, DESKTOP_GROUP, "Exec", NULL); + + /* we take only editors that accept parameters, FIXME: the test can be improved */ + if (!strchr(editor->exec, '%')) editor->hidden = TRUE; + + editor->menu_path = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Menu-Path", NULL); + if (!editor->menu_path) editor->menu_path = g_strdup("EditMenu/ExternalMenu"); + + editor->hotkey = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Hotkey", NULL); + + extensions = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-File-Extensions", NULL); + if (extensions) + editor->ext_list = filter_to_list(extensions); + else + { + gchar **mime_types = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "MimeType", NULL, NULL); + if (mime_types) + { + editor->ext_list = editor_mime_types_to_extensions(mime_types); + g_strfreev(mime_types); + if (!editor->ext_list) editor->hidden = TRUE; + } + + } + + + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Keep-Fullscreen", NULL)) editor->flags |= EDITOR_KEEP_FS; + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Verbose", NULL)) editor->flags |= EDITOR_VERBOSE; + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Verbose-Multi", NULL)) editor->flags |= EDITOR_VERBOSE_MULTI; + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Filter", NULL)) editor->flags |= EDITOR_DEST; + if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "Terminal", NULL)) editor->flags |= EDITOR_TERMINAL; + + + editor->flags |= editor_command_parse(editor, NULL, NULL); + g_key_file_free(key_file); + + return TRUE; } -void editor_reset_defaults(void) +static gboolean editor_remove_desktop_file_cb(gpointer key, gpointer value, gpointer user_data) +{ + EditorDescription *editor = value; + return editor->hidden; +} + +static void editor_read_desktop_dir(const gchar *path) { + DIR *dp; + struct dirent *dir; + gchar *pathl; + + pathl = path_from_utf8(path); + dp = opendir(pathl); + g_free(pathl); + if (!dp) + { + /* dir not found */ + return; + } + while ((dir = readdir(dp)) != NULL) + { + gchar *namel = dir->d_name; + size_t len = strlen(namel); + + if (len > 8 && strncasecmp(namel + len - 8, ".desktop", 8) == 0) + { + gchar *name = path_to_utf8(namel); + gchar *dpath = g_build_filename(path, name, NULL); + editor_read_desktop_file(dpath); + g_free(dpath); + g_free(name); + } + } + closedir(dp); +} + +void editor_load_descriptions(void) +{ + gchar *path; + gchar *xdg_data_dirs; + gchar *all_dirs; + gchar **split_dirs; gint i; + + if (!editors) + { + editors = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)editor_description_free); + } - for (i = 0; i < GQ_EDITOR_SLOTS; i++) + xdg_data_dirs = getenv("XDG_DATA_DIRS"); + if (xdg_data_dirs && xdg_data_dirs[0]) + xdg_data_dirs = path_to_utf8(xdg_data_dirs); + else + xdg_data_dirs = g_strdup("/usr/share"); + + all_dirs = g_strconcat(get_rc_dir(), ":", GQ_APP_DIR, ":", xdg_data_dirs, NULL); + + g_free(xdg_data_dirs); + + split_dirs = g_strsplit(all_dirs, ":", 0); + + g_free(all_dirs); + + for (i = 0; split_dirs[i]; i++) { - editor_set_name(i, _(editor_slot_defaults[i].name)); - editor_set_command(i, _(editor_slot_defaults[i].command)); + path = g_build_filename(split_dirs[i], "applications", NULL); + editor_read_desktop_dir(path); + g_free(path); } + + g_strfreev(split_dirs); + + g_hash_table_foreach_remove(editors, editor_remove_desktop_file_cb, NULL); } +static void editor_list_add_cb(gpointer key, gpointer value, gpointer data) +{ + GList **listp = data; + EditorDescription *editor = value; + + /* do not show the special commands in any list, they are called explicitelly */ + if (strcmp(editor->key, CMD_COPY) == 0 || + strcmp(editor->key, CMD_MOVE) == 0 || + strcmp(editor->key, CMD_RENAME) == 0 || + strcmp(editor->key, CMD_DELETE) == 0 || + strcmp(editor->key, CMD_FOLDER) == 0) return; + + *listp = g_list_prepend(*listp, editor); +} + +GList *editor_list_get(void) +{ + GList *editors_list = NULL; + g_hash_table_foreach(editors, editor_list_add_cb, &editors_list); + return editors_list; +} + +/* ------------------------------ */ + + static void editor_verbose_data_free(EditorData *ed) { if (!ed->vd) return; @@ -132,7 +381,6 @@ static void editor_data_free(EditorData *ed) { editor_verbose_data_free(ed); - g_free(ed->command_template); g_free(ed); } @@ -281,11 +529,12 @@ typedef enum { PATH_FILE, + PATH_FILE_URL, PATH_DEST } PathType; -static gchar *editor_command_path_parse(const FileData *fd, PathType type, const gchar *extensions) +static gchar *editor_command_path_parse(const FileData *fd, PathType type, const EditorDescription *editor) { GString *string; gchar *pathl; @@ -293,10 +542,9 @@ string = g_string_new(""); - if (type == PATH_FILE) + if (type == PATH_FILE || type == PATH_FILE_URL) { - GList *ext_list = filter_to_list(extensions); - GList *work = ext_list; + GList *work = editor->ext_list; if (!work) p = fd->path; @@ -329,7 +577,6 @@ } if (p) break; } - string_list_free(ext_list); if (!p) return NULL; } } @@ -354,6 +601,7 @@ p++; } + if (type == PATH_FILE_URL) g_string_prepend(string, "file://"); pathl = path_from_utf8(string->str); g_string_free(string, TRUE); @@ -361,80 +609,25 @@ } -/* - * The supported macros for editor commands: - * - * %f first occurence replaced by quoted sequence of filenames, command is run once. - * only one occurence of this macro is supported. - * ([ls %f] results in [ls "file1" "file2" ... "lastfile"]) - * %p command is run for each filename in turn, each instance replaced with single filename. - * multiple occurences of this macro is supported for complex shell commands. - * This macro will BLOCK THE APPLICATION until it completes, since command is run once - * for every file in syncronous order. To avoid blocking add the %v macro, below. - * ([ls %p] results in [ls "file1"], [ls "file2"] ... [ls "lastfile"]) - * none if no macro is supplied, the result is equivalent to "command %f" - * ([ls] results in [ls "file1" "file2" ... "lastfile"]) - * - * Only one of the macros %f or %p may be used in a given commmand. - * - * %v must be the first two characters[1] in a command, causes a window to display - * showing the output of the command(s). - * %V same as %v except in the case of %p only displays a window for multiple files, - * operating on a single file is suppresses the output dialog. - * - * %w must be first two characters in a command, presence will disable full screen - * from exiting upon invocation. - * - * - * [1] Note: %v,%V may also be preceded by "%w". - */ - - -gint editor_command_parse(const gchar *template, GList *list, gchar **output) +static gint editor_command_parse(const EditorDescription *editor, GList *list, gchar **output) { gint flags = 0; - const gchar *p = template; + const gchar *p; GString *result = NULL; - gchar *extensions = NULL; if (output) result = g_string_new(""); - if (!template || template[0] == '\0') + if (editor->exec[0] == '\0') { flags |= EDITOR_ERROR_EMPTY; goto err; } + p = editor->exec; /* skip leading whitespaces if any */ while (g_ascii_isspace(*p)) p++; - /* global flags */ - while (*p == '%') - { - switch (*++p) - { - case 'w': - flags |= EDITOR_KEEP_FS; - p++; - break; - case 'v': - flags |= EDITOR_VERBOSE; - p++; - break; - case 'V': - flags |= EDITOR_VERBOSE_MULTI; - p++; - break; - default: - flags |= EDITOR_ERROR_SYNTAX; - goto err; - } - } - - /* skip whitespaces if any */ - while (g_ascii_isspace(*p)) p++; - /* command */ while (*p) @@ -445,34 +638,14 @@ } else /* *p == '%' */ { - extensions = NULL; gchar *pathl = NULL; p++; - /* for example "%f" or "%{.crw;.raw;.cr2}f" */ - if (*p == '{') - { - gchar *end; - - p++; - end = strchr(p, '}'); - if (!end) - { - flags |= EDITOR_ERROR_SYNTAX; - goto err; - } - - extensions = g_strndup(p, end - p); - p = end + 1; - } - switch (*p) { - case 'd': - flags |= EDITOR_DEST; - /* fall through */ - case 'p': + case 'f': /* single file */ + case 'u': /* single url */ flags |= EDITOR_FOR_EACH; if (flags & EDITOR_SINGLE_COMMAND) { @@ -488,8 +661,8 @@ goto err; } pathl = editor_command_path_parse((FileData *)list->data, - (flags & EDITOR_DEST) ? PATH_DEST : PATH_FILE, - extensions); + (*p == 'f') ? PATH_FILE : PATH_FILE_URL, + editor); if (!pathl) { flags |= EDITOR_ERROR_NO_FILE; @@ -502,7 +675,8 @@ } break; - case 'f': + case 'F': + case 'U': flags |= EDITOR_SINGLE_COMMAND; if (flags & (EDITOR_FOR_EACH | EDITOR_DEST)) { @@ -519,7 +693,7 @@ while (work) { FileData *fd = work->data; - pathl = editor_command_path_parse(fd, PATH_FILE, extensions); + pathl = editor_command_path_parse(fd, (*p == 'F') ? PATH_FILE : PATH_FILE_URL, editor); if (pathl) { @@ -539,16 +713,40 @@ } } break; + case 'i': + if (output) + { + result = g_string_append(result, editor->icon); + } + break; + case 'c': + if (output) + { + result = g_string_append(result, editor->name); + } + break; + case 'k': + if (output) + { + result = g_string_append(result, editor->file); + } + break; case '%': /* %% = % escaping */ if (output) result = g_string_append_c(result, *p); break; + case 'd': + case 'D': + case 'n': + case 'N': + case 'v': + case 'm': + /* deprecated according to spec, ignore */ + break; default: flags |= EDITOR_ERROR_SYNTAX; goto err; } - if (extensions) g_free(extensions); - extensions = NULL; } p++; } @@ -563,10 +761,10 @@ g_string_free(result, TRUE); *output = NULL; } - if (extensions) g_free(extensions); return flags; } + static void editor_child_exit_cb (GPid pid, gint status, gpointer data) { EditorData *ed = data; @@ -577,7 +775,7 @@ } -static gint editor_command_one(const gchar *template, GList *list, EditorData *ed) +static gint editor_command_one(const EditorDescription *editor, GList *list, EditorData *ed) { gchar *command; FileData *fd = list->data; @@ -587,7 +785,7 @@ gboolean ok; ed->pid = -1; - ed->flags = editor_command_parse(template, list, &command); + ed->flags = editor->flags | editor_command_parse(editor, list, &command); ok = !(ed->flags & EDITOR_ERROR_MASK); @@ -618,6 +816,15 @@ args[n++] = command; args[n] = NULL; + if ((ed->flags & EDITOR_DEST) && fd->change && fd->change->dest) /* FIXME: error handling */ + { + setenv("GEEQIE_DESTINATION", fd->change->dest, TRUE); + } + else + { + unsetenv("GEEQIE_DESTINATION"); + } + ok = g_spawn_async_with_pipes(working_directory, args, NULL, G_SPAWN_DO_NOT_REAP_CHILD, /* GSpawnFlags */ NULL, NULL, @@ -644,7 +851,7 @@ { gchar *buf; - buf = g_strdup_printf(_("Failed to run command:\n%s\n"), template); + buf = g_strdup_printf(_("Failed to run command:\n%s\n"), editor->file); editor_verbose_window_fill(ed->vd, buf, strlen(buf)); g_free(buf); @@ -694,7 +901,7 @@ } ed->count++; - error = editor_command_one(ed->command_template, ed->list, ed); + error = editor_command_one(ed->editor, ed->list, ed); if (!error && ed->vd) { gtk_widget_set_sensitive(ed->vd->button_stop, (ed->list != NULL) ); @@ -801,17 +1008,17 @@ editor_command_done(ed); } -static gint editor_command_start(const gchar *template, const gchar *text, GList *list, EditorCallback cb, gpointer data) +static gint editor_command_start(const EditorDescription *editor, const gchar *text, GList *list, EditorCallback cb, gpointer data) { EditorData *ed; - gint flags = editor_command_parse(template, NULL, NULL); + gint flags = editor->flags; if (flags & EDITOR_ERROR_MASK) return flags & EDITOR_ERROR_MASK; ed = g_new0(EditorData, 1); ed->list = filelist_copy(list); ed->flags = flags; - ed->command_template = g_strdup(template); + ed->editor = editor; ed->total = (flags & EDITOR_SINGLE_COMMAND) ? 1 : g_list_length(list); ed->count = 0; ed->stopping = FALSE; @@ -829,29 +1036,28 @@ return flags & EDITOR_ERROR_MASK; } -gboolean is_valid_editor_command(gint n) +gboolean is_valid_editor_command(const gchar *key) { - return (n >= 0 && n < GQ_EDITOR_SLOTS - && options->editor[n].command - && strlen(options->editor[n].command) > 0); + if (!key) return FALSE; + return g_hash_table_lookup(editors, key) != NULL; } -gint start_editor_from_filelist_full(gint n, GList *list, EditorCallback cb, gpointer data) +gint start_editor_from_filelist_full(const gchar *key, GList *list, EditorCallback cb, gpointer data) { - gchar *command; gint error; + EditorDescription *editor; + if (!key) return FALSE; + + editor = g_hash_table_lookup(editors, key); if (!list) return FALSE; - if (!is_valid_editor_command(n)) return FALSE; + if (!editor) return FALSE; + + error = editor_command_start(editor, editor->name, list, cb, data); - command = g_locale_from_utf8(options->editor[n].command, -1, NULL, NULL, NULL); - error = editor_command_start(command, options->editor[n].name, list, cb, data); - g_free(command); - - if (n < GQ_EDITOR_GENERIC_SLOTS && (error & EDITOR_ERROR_MASK)) + if (error & EDITOR_ERROR_MASK) { - gchar *text = g_strdup_printf(_("%s\n#%d \"%s\":\n%s"), editor_get_error_str(error), n+1, - options->editor[n].name, options->editor[n].command); + gchar *text = g_strdup_printf(_("%s\n\"%s\""), editor_get_error_str(error), editor->file); file_util_warning_dialog(_("Invalid editor command"), text, GTK_STOCK_DIALOG_ERROR, NULL); g_free(text); @@ -860,12 +1066,12 @@ return error; } -gint start_editor_from_filelist(gint n, GList *list) +gint start_editor_from_filelist(const gchar *key, GList *list) { - return start_editor_from_filelist_full(n, list, NULL, NULL); + return start_editor_from_filelist_full(key, list, NULL, NULL); } -gint start_editor_from_file_full(gint n, FileData *fd, EditorCallback cb, gpointer data) +gint start_editor_from_file_full(const gchar *key, FileData *fd, EditorCallback cb, gpointer data) { GList *list; gint error; @@ -873,28 +1079,36 @@ if (!fd) return FALSE; list = g_list_append(NULL, fd); - error = start_editor_from_filelist_full(n, list, cb, data); + error = start_editor_from_filelist_full(key, list, cb, data); g_list_free(list); return error; } -gint start_editor_from_file(gint n, FileData *fd) +gint start_editor_from_file(const gchar *key, FileData *fd) { - return start_editor_from_file_full(n, fd, NULL, NULL); + return start_editor_from_file_full(key, fd, NULL, NULL); } -gint editor_window_flag_set(gint n) +gint editor_window_flag_set(const gchar *key) { - if (!is_valid_editor_command(n)) return TRUE; + EditorDescription *editor; + if (!key) return TRUE; + + editor = g_hash_table_lookup(editors, key); + if (!editor) return TRUE; - return (editor_command_parse(options->editor[n].command, NULL, NULL) & EDITOR_KEEP_FS); + return (editor->flags & EDITOR_KEEP_FS); } -gint editor_is_filter(gint n) +gint editor_is_filter(const gchar *key) { - if (!is_valid_editor_command(n)) return FALSE; + EditorDescription *editor; + if (!key) return TRUE; + + editor = g_hash_table_lookup(editors, key); + if (!editor) return TRUE; - return (editor_command_parse(options->editor[n].command, NULL, NULL) & EDITOR_DEST); + return (editor->flags & EDITOR_DEST); } const gchar *editor_get_error_str(gint flags) @@ -909,13 +1123,12 @@ return _("Unknown error."); } -const gchar *editor_get_name(gint n) +const gchar *editor_get_name(const gchar *key) { - if (!is_valid_editor_command(n)) return NULL; + EditorDescription *editor = g_hash_table_lookup(editors, key); - if (options->editor[n].name && strlen(options->editor[n].name) > 0) - return options->editor[n].name; - - return _("(unknown)"); + if (!editor) return NULL; + + return editor->name; } /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/editors.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/editors.h Sun Feb 01 12:48:14 2009 +0000 @@ -18,6 +18,7 @@ #define EDITOR_KEEP_FS 0x00000001 #define EDITOR_VERBOSE 0x00000002 #define EDITOR_VERBOSE_MULTI 0x00000004 +#define EDITOR_TERMINAL 0x00000008 #define EDITOR_DEST 0x00000100 #define EDITOR_FOR_EACH 0x00000200 @@ -42,6 +43,11 @@ must be called later */ }; +extern GHashTable *editors; + +void editor_load_descriptions(void); +GList *editor_list_get(void); + /* Callback is called even on skipped files, with the EDITOR_ERROR_SKIPPED flag set. @@ -54,28 +60,23 @@ */ typedef gint (*EditorCallback) (gpointer ed, gint flags, GList *list, gpointer data); -void editor_set_name(gint n, gchar *name); -void editor_set_command(gint n, gchar *command); - void editor_resume(gpointer ed); void editor_skip(gpointer ed); -gint editor_command_parse(const gchar *template, GList *list, gchar **output); -void editor_reset_defaults(void); -gint start_editor_from_file(gint n, FileData *fd); -gint start_editor_from_filelist(gint n, GList *list); -gint start_editor_from_file_full(gint n, FileData *fd, EditorCallback cb, gpointer data); -gint start_editor_from_filelist_full(gint n, GList *list, EditorCallback cb, gpointer data); -gint editor_window_flag_set(gint n); -gint editor_is_filter(gint n); +gint start_editor_from_file(const gchar *key, FileData *fd); +gint start_editor_from_filelist(const gchar *key, GList *list); +gint start_editor_from_file_full(const gchar *key, FileData *fd, EditorCallback cb, gpointer data); +gint start_editor_from_filelist_full(const gchar *key, GList *list, EditorCallback cb, gpointer data); +gint editor_window_flag_set(const gchar *key); +gint editor_is_filter(const gchar *key); const gchar *editor_get_error_str(gint flags); -const gchar *editor_get_name(gint n); +const gchar *editor_get_name(const gchar *key); -gboolean is_valid_editor_command(gint n); +gboolean is_valid_editor_command(const gchar *key); #endif /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/img-view.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/img-view.c Sun Feb 01 12:48:14 2009 +0000 @@ -431,6 +431,7 @@ stop_signal = FALSE; break; } +#if 0 if (n != -1) { if (!editor_window_flag_set(n)) @@ -440,6 +441,7 @@ imd = view_window_active_image(vw); file_util_start_editor_from_file(n, image_get_fd(imd), imd->widget); } +#endif } else if (event->state & GDK_SHIFT_MASK) { @@ -1074,19 +1076,18 @@ { ViewWindow *vw; ImageWindow *imd; - gint n; + const gchar *key = data; vw = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); if (!vw) return; - if (!editor_window_flag_set(n)) + if (!editor_window_flag_set(key)) { view_fullscreen_toggle(vw, TRUE); } imd = view_window_active_image(vw); - file_util_start_editor_from_file(n, image_get_fd(imd), imd->widget); + file_util_start_editor_from_file(key, image_get_fd(imd), imd->widget); } static void view_alter_cb(GtkWidget *widget, gpointer data)
--- a/src/layout_image.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/layout_image.c Sun Feb 01 12:48:14 2009 +0000 @@ -309,16 +309,15 @@ static void li_pop_menu_edit_cb(GtkWidget *widget, gpointer data) { LayoutWindow *lw; - gint n; + const gchar *key = data; lw = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); - if (!editor_window_flag_set(n)) + if (!editor_window_flag_set(key)) { layout_image_full_screen_stop(lw); } - file_util_start_editor_from_file(n, layout_image_get_fd(lw), lw->window); + file_util_start_editor_from_file(key, layout_image_get_fd(lw), lw->window); } static void li_pop_menu_wallpaper_cb(GtkWidget *widget, gpointer data)
--- a/src/layout_util.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/layout_util.c Sun Feb 01 12:48:14 2009 +0000 @@ -902,18 +902,17 @@ { LayoutWindow *lw = data; GList *list; - gint n; - - n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(action), "edit_index")); - - if (!editor_window_flag_set(n)) + const gchar *key = gtk_action_get_name(action); + + if (!editor_window_flag_set(key)) layout_exit_fullscreen(lw); list = layout_selection_list(lw); - file_util_start_editor_from_filelist(n, list, lw->window); + file_util_start_editor_from_filelist(key, list, lw->window); filelist_free(list); } +#if 0 static void layout_menu_edit_update(LayoutWindow *lw) { gint i; @@ -969,6 +968,8 @@ } } +#endif + /* *----------------------------------------------------------------------------- * recent menu @@ -1109,6 +1110,7 @@ { "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL }, { "SelectMenu", NULL, N_("_Select"), NULL, NULL, NULL }, { "AdjustMenu", NULL, N_("_Adjust"), NULL, NULL, NULL }, + { "ExternalMenu", NULL, N_("E_xternal Editors"), NULL, NULL, NULL }, { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL }, { "DirMenu", NULL, N_("_View Directory as"), NULL, NULL, NULL }, { "ZoomMenu", NULL, N_("_Zoom"), NULL, NULL, NULL }, @@ -1145,17 +1147,6 @@ { "CloseWindow", GTK_STOCK_CLOSE,N_("C_lose window"), "<control>W", NULL, CB(layout_menu_close_cb) }, { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", NULL, CB(layout_menu_exit_cb) }, - { "Editor0", NULL, "editor0", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor1", NULL, "editor1", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor2", NULL, "editor2", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor3", NULL, "editor3", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor4", NULL, "editor4", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor5", NULL, "editor5", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor6", NULL, "editor6", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor7", NULL, "editor7", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor8", NULL, "editor8", NULL, NULL, CB(layout_menu_edit_cb) }, - { "Editor9", NULL, "editor9", NULL, NULL, CB(layout_menu_edit_cb) }, - { "RotateCW", NULL, N_("_Rotate clockwise"), "bracketright", NULL, CB(layout_menu_alter_90_cb) }, { "RotateCCW", NULL, N_("Rotate _counterclockwise"), "bracketleft", NULL, CB(layout_menu_alter_90cc_cb) }, { "Rotate180", NULL, N_("Rotate 1_80"), "<shift>R", NULL, CB(layout_menu_alter_180_cb) }, @@ -1279,12 +1270,14 @@ " <separator/>" " <menuitem action='CloseWindow'/>" " <menuitem action='Quit'/>" +" <separator/>" " </menu>" " <menu action='GoMenu'>" " <menuitem action='FirstImage'/>" " <menuitem action='PrevImage'/>" " <menuitem action='NextImage'/>" " <menuitem action='LastImage'/>" +" <separator/>" " </menu>" " <menu action='SelectMenu'>" " <menuitem action='SelectAll'/>" @@ -1295,17 +1288,6 @@ " <separator/>" " </menu>" " <menu action='EditMenu'>" -" <menuitem action='Editor0'/>" -" <menuitem action='Editor1'/>" -" <menuitem action='Editor2'/>" -" <menuitem action='Editor3'/>" -" <menuitem action='Editor4'/>" -" <menuitem action='Editor5'/>" -" <menuitem action='Editor6'/>" -" <menuitem action='Editor7'/>" -" <menuitem action='Editor8'/>" -" <menuitem action='Editor9'/>" -" <separator/>" " <menu action='AdjustMenu'>" " <menuitem action='RotateCW'/>" " <menuitem action='RotateCCW'/>" @@ -1321,6 +1303,9 @@ " <menuitem action='Maintenance'/>" " <separator/>" " <menuitem action='Wallpaper'/>" +" <separator/>" +" <menu action='ExternalMenu'>" +" </menu>" " </menu>" " <menu action='ViewMenu'>" " <menuitem action='ViewInNewWindow'/>" @@ -1386,6 +1371,7 @@ " <menuitem action='SlideShow'/>" " <menuitem action='SlideShowPause'/>" " <menuitem action='Refresh'/>" +" <separator/>" " </menu>" " <menu action='HelpMenu'>" " <separator/>" @@ -1396,6 +1382,7 @@ " <menuitem action='About'/>" " <separator/>" " <menuitem action='LogWindow'/>" +" <separator/>" " </menu>" " </menubar>" "<accelerator action='PrevImageAlt1'/>" @@ -1503,6 +1490,116 @@ g_string_free(desc, TRUE); } +static gint layout_actions_editor_sort(gconstpointer a, gconstpointer b) +{ + const EditorDescription *ea = a; + const EditorDescription *eb = b; + int ret; + + ret = strcmp(ea->menu_path, eb->menu_path); + if (ret != 0) return ret; + + return g_utf8_collate(ea->name, eb->name); +} + +static GList *layout_actions_editor_menu_path(EditorDescription *editor) +{ + gchar **split = g_strsplit(editor->menu_path, "/", 0); + gint i = 0; + GList *ret = NULL; + + if (split[0] == NULL) + { + g_strfreev(split); + return NULL; + } + + while(split[i]) + { + ret = g_list_prepend(ret, g_strdup(split[i])); + i++; + } + + g_strfreev(split); + + ret = g_list_prepend(ret, g_strdup(editor->key)); + + return g_list_reverse(ret); +} + +static void layout_actions_editor_add(GString *desc, GList *path, GList *old_path) +{ + gint to_open, to_close, i; + while (path && old_path && strcmp((gchar *)path->data, (gchar *)old_path->data) == 0) + { + path = path->next; + old_path = old_path->next; + } + to_open = g_list_length(path) - 1; + to_close = g_list_length(old_path) - 1; + + for (i = 0; i < to_close; i++) + { + g_string_append(desc, " </menu>"); + } + + for (i = 0; i < to_open; i++) + { + g_string_append_printf(desc, " <menu action='%s'>", (gchar *)path->data); + path = path->next; + } + + if (path) + g_string_append_printf(desc, " <menuitem action='%s'/>", (gchar *)path->data); +} + +static void layout_actions_setup_editors(LayoutWindow *lw) +{ + GError *error; + GList *editors_list; + GList *work; + GList *old_path; + GString *desc = g_string_new( + "<ui>" + " <menubar name='MainMenu'>"); + + editors_list = editor_list_get(); + editors_list = g_list_sort(editors_list, layout_actions_editor_sort); + + old_path = NULL; + work = editors_list; + while(work) + { + GList *path; + EditorDescription *editor = work->data; + GtkActionEntry entry = { editor->key, NULL, editor->name, editor->hotkey, NULL, G_CALLBACK(layout_menu_edit_cb) }; + gtk_action_group_add_actions(lw->action_group, &entry, 1, lw); + + path = layout_actions_editor_menu_path(editor); + layout_actions_editor_add(desc, path, old_path); + + string_list_free(old_path); + old_path = path; + work = work->next; + } + + layout_actions_editor_add(desc, NULL, old_path); + string_list_free(old_path); + + g_string_append(desc, " </menubar>" + "</ui>" ); + + error = NULL; + if (!gtk_ui_manager_add_ui_from_string(lw->ui_manager, desc->str, -1, &error)) + { + g_message("building menus failed: %s", error->message); + g_error_free(error); + exit(EXIT_FAILURE); + } + g_string_free(desc, TRUE); + g_list_free(editors_list); +} + void layout_actions_setup(LayoutWindow *lw) { GError *error; @@ -1539,6 +1636,7 @@ } layout_actions_setup_marks(lw); + layout_actions_setup_editors(lw); layout_copy_path_update(lw); } @@ -1775,7 +1873,7 @@ layout_util_sync_views(lw); layout_util_sync_thumb(lw); layout_menu_recent_update(lw); - layout_menu_edit_update(lw); +// layout_menu_edit_update(lw); } /*
--- a/src/layout_util.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/layout_util.h Sun Feb 01 12:48:14 2009 +0000 @@ -23,7 +23,7 @@ void layout_util_sync(LayoutWindow *lw); -void layout_edit_update_all(void); +//void layout_edit_update_all(void); void layout_recent_update_all(void); void layout_recent_add_path(const gchar *path);
--- a/src/main.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/main.c Sun Feb 01 12:48:14 2009 +0000 @@ -31,6 +31,7 @@ #include "cache_maint.h" #include "thumb.h" #include "metadata.h" +#include "editors.h" #include <gdk/gdkkeysyms.h> /* for keyboard values */ @@ -771,6 +772,8 @@ filter_add_defaults(); filter_rebuild(); + editor_load_descriptions(); + accel_map_load(); if (startup_blank)
--- a/src/main.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/main.h Sun Feb 01 12:48:14 2009 +0000 @@ -87,7 +87,6 @@ #define MOUSEWHEEL_SCROLL_SIZE 20 -#define GQ_EDITOR_GENERIC_SLOTS 10 #define GQ_DEFAULT_SHELL_PATH "/bin/sh" #define GQ_DEFAULT_SHELL_OPTIONS "-c"
--- a/src/menu.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/menu.c Sun Feb 01 12:48:14 2009 +0000 @@ -64,26 +64,22 @@ *----------------------------------------------------------------------------- */ -static void add_edit_items(GtkWidget *menu, GCallback func, GtkAccelGroup *accel_grp) +static void add_edit_items(GtkWidget *menu, GCallback func) { - gint i; - - for (i = 0; i < GQ_EDITOR_GENERIC_SLOTS; i++) - { - gchar *text; - const gchar *name = editor_get_name(i); + GList *editors_list = editor_list_get(); + GList *work = editors_list; - if (!name) continue; + while (work) + { + const EditorDescription *editor = work->data; + work = work->next; + + menu_item_add(menu, editor->name, func, editor->key); + } + + g_list_free(editors_list); +} - text = g_strdup_printf(_("_%d %s..."), i, name); - if (accel_grp) - add_menu_item(menu, text, accel_grp, i + 49, GDK_CONTROL_MASK, func, GINT_TO_POINTER(i)); - else - menu_item_add(menu, text, func, GINT_TO_POINTER(i)); - g_free(text); - - } -} GtkWidget *submenu_add_edit(GtkWidget *menu, GtkWidget **menu_item, GCallback func, gpointer data) { @@ -94,7 +90,7 @@ submenu = gtk_menu_new(); g_object_set_data(G_OBJECT(submenu), "submenu_data", data); - add_edit_items(submenu, func, NULL); + add_edit_items(submenu, func); gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
--- a/src/options.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/options.c Sun Feb 01 12:48:14 2009 +0000 @@ -131,7 +131,8 @@ options->panels.sort.enabled = FALSE; options->panels.sort.mode_state = 0; options->panels.sort.selection_state = 0; - + options->panels.sort.action_filter = NULL; + options->progressive_key_scrolling = TRUE; options->metadata.enable_metadata_dirs = FALSE; @@ -178,14 +179,6 @@ gchar *path; gint i; - for (i = 0; i < GQ_EDITOR_SLOTS; i++) - { - editor_set_name(i, NULL); - editor_set_command(i, NULL); - } - - editor_reset_defaults(); - bookmark_add_default(_("Home"), homedir()); path = g_build_filename(homedir(), "Desktop", NULL); bookmark_add_default(_("Desktop"), path);
--- a/src/options.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/options.h Sun Feb 01 12:48:14 2009 +0000 @@ -110,9 +110,6 @@ gboolean rectangular_selection; } collections; - /* editors */ - Editor editor[GQ_EDITOR_SLOTS]; - /* shell */ struct { gchar *path; @@ -221,6 +218,7 @@ gint mode_state; gint action_state; gint selection_state; + gchar *action_filter; } sort; } panels;
--- a/src/pan-view.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/pan-view.c Sun Feb 01 12:48:14 2009 +0000 @@ -1330,7 +1330,7 @@ stop_signal = FALSE; break; } - +#if 0 if (n != -1 && fd) { if (!editor_window_flag_set(n)) @@ -1339,6 +1339,7 @@ } file_util_start_editor_from_file(n, fd, GTK_WIDGET(pr)); } +#endif } else { @@ -2669,20 +2670,19 @@ { PanWindow *pw; FileData *fd; - gint n; + const gchar *key = data; pw = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); if (!pw) return; fd = pan_menu_click_fd(pw); if (fd) { - if (!editor_window_flag_set(n)) + if (!editor_window_flag_set(key)) { pan_fullscreen_toggle(pw, TRUE); } - file_util_start_editor_from_file(n, fd, pw->imd->widget); + file_util_start_editor_from_file(key, fd, pw->imd->widget); } }
--- a/src/preferences.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/preferences.c Sun Feb 01 12:48:14 2009 +0000 @@ -99,8 +99,6 @@ static GtkWidget *startup_path_entry; static GtkWidget *home_path_entry; static GtkListStore *filter_store = NULL; -static GtkWidget *editor_name_entry[GQ_EDITOR_SLOTS]; -static GtkWidget *editor_command_entry[GQ_EDITOR_SLOTS]; static GtkWidget *layout_widget; @@ -177,6 +175,7 @@ } } +#if 0 static void config_parse_editor_entries(GtkWidget **editor_name_entry, GtkWidget **editor_command_entry) { gint i; @@ -223,7 +222,7 @@ g_string_free(errmsg, TRUE); } - +#endif static void config_window_apply(void) { @@ -231,8 +230,8 @@ gint i; gint refresh = FALSE; - config_parse_editor_entries(editor_name_entry, editor_command_entry); - layout_edit_update_all(); +// config_parse_editor_entries(editor_name_entry, editor_command_entry); +// layout_edit_update_all(); config_entry_to_option(safe_delete_path_entry, &options->file_ops.safe_delete_path, remove_trailing_slash); @@ -874,6 +873,7 @@ !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))); } +#if 0 static void editor_default_ok_cb(GenericDialog *gd, gpointer data) { gint i; @@ -908,6 +908,7 @@ { help_window_show("editors"); } +#endif static void safe_delete_view_cb(GtkWidget *widget, gpointer data) { @@ -1389,7 +1390,7 @@ gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_widget_show(button); } - +#if 0 /* editors tab */ static void config_tab_editors(GtkWidget *notebook) { @@ -1466,6 +1467,7 @@ gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_widget_show(button); } +#endif /* properties tab */ static void config_tab_properties(GtkWidget *notebook) @@ -1756,7 +1758,7 @@ entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(entry), EDITOR_NAME_MAX_LENGTH); - gtk_widget_set_size_request(editor_name_entry[i], 30, -1); +// gtk_widget_set_size_request(editor_name_entry[i], 30, -1); if (options->color_profile.input_name[i]) { gtk_entry_set_text(GTK_ENTRY(entry), options->color_profile.input_name[i]); @@ -1862,7 +1864,7 @@ config_tab_image(notebook); config_tab_windows(notebook); config_tab_filtering(notebook); - config_tab_editors(notebook); +// config_tab_editors(notebook); config_tab_properties(notebook); config_tab_advanced(notebook);
--- a/src/rcfile.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/rcfile.c Sun Feb 01 12:48:14 2009 +0000 @@ -353,6 +353,7 @@ WRITE_INT(panels.sort.action_state); WRITE_INT(panels.sort.mode_state); WRITE_INT(panels.sort.selection_state); + WRITE_CHAR(panels.sort.action_filter); WRITE_SUBTITLE("Properties dialog Options"); WRITE_CHAR(properties.tabs_order); @@ -511,7 +512,7 @@ WRITE_CHAR(helpers.html_browser.command_name); WRITE_CHAR(helpers.html_browser.command_line); - +#if 0 WRITE_SUBTITLE("External Programs"); secure_fprintf(ssi, "# Maximum of %d programs (external_1 through external_%d)\n", GQ_EDITOR_GENERIC_SLOTS, GQ_EDITOR_GENERIC_SLOTS); secure_fprintf(ssi, "# external_%d through external_%d are used for file ops\n", GQ_EDITOR_GENERIC_SLOTS + 1, GQ_EDITOR_SLOTS); @@ -526,7 +527,7 @@ g_free(qname); g_free(qcommand); } - +#endif WRITE_SUBTITLE("Exif Options"); secure_fprintf(ssi, "# Display: 0: never\n" @@ -734,6 +735,7 @@ READ_INT(panels.sort.action_state); READ_INT(panels.sort.mode_state); READ_INT(panels.sort.selection_state); + READ_CHAR(panels.sort.action_filter); /* properties dialog options */ READ_CHAR(properties.tabs_order); @@ -878,7 +880,7 @@ READ_CHAR(helpers.html_browser.command_line); /* External Programs */ - +#if 0 if (is_numbered_option(option, "external_", &i)) { if (i > 0 && i <= GQ_EDITOR_SLOTS) @@ -891,7 +893,7 @@ } continue; } - +#endif /* Exif */ if (0 == g_ascii_strncasecmp(option, "exif.display.", 13)) {
--- a/src/search.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/search.c Sun Feb 01 12:48:14 2009 +0000 @@ -657,12 +657,12 @@ search_status_update(sd); } -static void search_result_edit_selected(SearchData *sd, gint n) +static void search_result_edit_selected(SearchData *sd, const gchar *key) { GList *list; list = search_result_selection_list(sd); - file_util_start_editor_from_filelist(n, list, sd->window); + file_util_start_editor_from_filelist(key, list, sd->window); filelist_free(list); } @@ -908,13 +908,12 @@ static void sr_menu_edit_cb(GtkWidget *widget, gpointer data) { SearchData *sd; - gint n; + const gchar *key = data; sd = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); if (!sd) return; - search_result_edit_selected(sd, n); + search_result_edit_selected(sd, key); } static void sr_menu_info_cb(GtkWidget *widget, gpointer data) @@ -1282,11 +1281,12 @@ stop_signal = FALSE; break; } - +#if 0 if (edit_val >= 0) { search_result_edit_selected(sd, edit_val); } +#endif } else {
--- a/src/typedefs.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/typedefs.h Sun Feb 01 12:48:14 2009 +0000 @@ -38,14 +38,11 @@ FILEVIEW_ICON } FileViewType; -typedef enum { - CMD_COPY = GQ_EDITOR_GENERIC_SLOTS, - CMD_MOVE, - CMD_RENAME, - CMD_DELETE, - CMD_FOLDER, - GQ_EDITOR_SLOTS -} SpecialEditor; +#define CMD_COPY "geeqie-copy-command.desktop" +#define CMD_MOVE "geeqie-move-command.desktop" +#define CMD_RENAME "geeqie-rename-command.desktop" +#define CMD_DELETE "geeqie-delete-command.desktop" +#define CMD_FOLDER "geeqie-folder-command.desktop" typedef enum { SORT_NONE, @@ -202,12 +199,22 @@ typedef struct _ExifData ExifData; -typedef struct _Editor Editor; -struct _Editor { - gchar *name; - gchar *command; +typedef struct _EditorDescription EditorDescription; + +struct _EditorDescription { + gchar *key; /* desktop file name, not including path, including extension */ + gchar *name; /* localized name presented to user */ + gchar *exec; + gchar *menu_path; + gchar *hotkey; + GList *ext_list; + gchar *icon; + gchar *file; + gint flags; + gboolean hidden; }; + struct _ImageLoader; typedef void (* ThumbLoaderFunc)(ThumbLoader *tl, gpointer data); @@ -745,6 +752,5 @@ gint unlink_on_error; /**< whether to remove temporary file on save failure, TRUE by default */ }; - #endif /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/utilops.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/utilops.c Sun Feb 01 12:48:14 2009 +0000 @@ -312,7 +312,7 @@ /* data for the operation itself, internal or external */ gboolean external; /* TRUE for external command, FALSE for internal */ - gint external_command; + gchar *external_command; gpointer resume_data; FileUtilDoneFunc done_func; @@ -345,7 +345,7 @@ ud->phase = UTILITY_PHASE_START; ud->update_idle_id = -1; ud->perform_idle_id = -1; - ud->external_command = -1; + ud->external_command = NULL; return ud; } @@ -363,6 +363,7 @@ if (ud->gd) generic_dialog_close(ud->gd); g_free(ud->dest_path); + g_free(ud->external_command); g_free(ud); } @@ -791,29 +792,29 @@ switch (ud->type) { case UTILITY_TYPE_COPY: - ud->external_command = CMD_COPY; + ud->external_command = g_strdup(CMD_COPY); break; case UTILITY_TYPE_MOVE: - ud->external_command = CMD_MOVE; + ud->external_command = g_strdup(CMD_MOVE); break; case UTILITY_TYPE_RENAME: case UTILITY_TYPE_RENAME_FOLDER: - ud->external_command = CMD_RENAME; + ud->external_command = g_strdup(CMD_RENAME); break; case UTILITY_TYPE_DELETE: case UTILITY_TYPE_DELETE_LINK: case UTILITY_TYPE_DELETE_FOLDER: - ud->external_command = CMD_DELETE; + ud->external_command = g_strdup(CMD_DELETE); break; case UTILITY_TYPE_CREATE_FOLDER: - ud->external_command = CMD_FOLDER; + ud->external_command = g_strdup(CMD_FOLDER); break; case UTILITY_TYPE_FILTER: case UTILITY_TYPE_EDITOR: - g_assert(ud->external_command != -1); /* it should be already set */ + g_assert(ud->external_command != NULL); /* it should be already set */ break; case UTILITY_TYPE_WRITE_METADATA: - ud->external_command = -1; + ud->external_command = NULL; } if (is_valid_editor_command(ud->external_command)) @@ -1809,7 +1810,7 @@ file_util_dialog_run(ud); } -static void file_util_start_editor_full(gint n, FileData *source_fd, GList *source_list, const gchar *dest_path, GtkWidget *parent, UtilityPhase phase) +static void file_util_start_editor_full(const gchar *key, FileData *source_fd, GList *source_list, const gchar *dest_path, GtkWidget *parent, UtilityPhase phase) { UtilityData *ud; GList *flist = filelist_copy(source_list); @@ -1828,7 +1829,7 @@ return; } - if (editor_is_filter(n)) + if (editor_is_filter(key)) ud = file_util_data_new(UTILITY_TYPE_FILTER); else ud = file_util_data_new(UTILITY_TYPE_EDITOR); @@ -1841,7 +1842,7 @@ ud->with_sidecars = TRUE; - ud->external_command = n; + ud->external_command = g_strdup(key); ud->dir_fd = NULL; ud->flist = flist; @@ -2331,24 +2332,24 @@ } -void file_util_start_editor_from_file(gint n, FileData *fd, GtkWidget *parent) +void file_util_start_editor_from_file(const gchar *key, FileData *fd, GtkWidget *parent) { - file_util_start_editor_full(n, fd, NULL, NULL, parent, UTILITY_PHASE_ENTERING); + file_util_start_editor_full(key, fd, NULL, NULL, parent, UTILITY_PHASE_ENTERING); } -void file_util_start_editor_from_filelist(gint n, GList *list, GtkWidget *parent) +void file_util_start_editor_from_filelist(const gchar *key, GList *list, GtkWidget *parent) { - file_util_start_editor_full(n, NULL, list, NULL, parent, UTILITY_PHASE_ENTERING); + file_util_start_editor_full(key, NULL, list, NULL, parent, UTILITY_PHASE_ENTERING); } -void file_util_start_filter_from_file(gint n, FileData *fd, const gchar *dest_path, GtkWidget *parent) +void file_util_start_filter_from_file(const gchar *key, FileData *fd, const gchar *dest_path, GtkWidget *parent) { - file_util_start_editor_full(n, fd, NULL, dest_path, parent, UTILITY_PHASE_ENTERING); + file_util_start_editor_full(key, fd, NULL, dest_path, parent, UTILITY_PHASE_ENTERING); } -void file_util_start_filter_from_filelist(gint n, GList *list, const gchar *dest_path, GtkWidget *parent) +void file_util_start_filter_from_filelist(const gchar *key, GList *list, const gchar *dest_path, GtkWidget *parent) { - file_util_start_editor_full(n, NULL, list, dest_path, parent, UTILITY_PHASE_ENTERING); + file_util_start_editor_full(key, NULL, list, dest_path, parent, UTILITY_PHASE_ENTERING); } void file_util_delete_dir(FileData *fd, GtkWidget *parent)
--- a/src/utilops.h Thu Jan 29 19:43:34 2009 +0000 +++ b/src/utilops.h Sun Feb 01 12:48:14 2009 +0000 @@ -50,10 +50,10 @@ void file_util_copy_simple(GList *list, const gchar *dest_path, GtkWidget *parent); void file_util_rename_simple(FileData *fd, const gchar *dest_path, GtkWidget *parent); -void file_util_start_editor_from_file(gint n, FileData *fd, GtkWidget *parent); -void file_util_start_editor_from_filelist(gint n, GList *list, GtkWidget *parent); -void file_util_start_filter_from_file(gint n, FileData *fd, const gchar *dest_path, GtkWidget *parent); -void file_util_start_filter_from_filelist(gint n, GList *list, const gchar *dest_path, GtkWidget *parent); +void file_util_start_editor_from_file(const gchar *key, FileData *fd, GtkWidget *parent); +void file_util_start_editor_from_filelist(const gchar *key, GList *list, GtkWidget *parent); +void file_util_start_filter_from_file(const gchar *key, FileData *fd, const gchar *dest_path, GtkWidget *parent); +void file_util_start_filter_from_filelist(const gchar *key, GList *list, const gchar *dest_path, GtkWidget *parent); void file_util_delete_dir(FileData *source_fd, GtkWidget *parent);
--- a/src/view_dir.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/view_dir.c Sun Feb 01 12:48:14 2009 +0000 @@ -327,20 +327,18 @@ ViewDir *vd = data; const gchar *path; GList *list; - guint n; - + const gchar *key; + if (!vd->drop_fd) return; - n = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(widget), "filter_idx")); - if (n == 0) return; - n--; + key = g_object_get_data(G_OBJECT(widget), "filter_key"); path = vd->drop_fd->path; list = vd->drop_list; vd->drop_list = NULL; - file_util_start_filter_from_filelist(n, list, path, vd->widget); + file_util_start_filter_from_filelist(key, list, path, vd->widget); } @@ -348,7 +346,8 @@ GtkWidget *vd_drop_menu(ViewDir *vd, gint active) { GtkWidget *menu; - guint i; + GList *editors_list = editor_list_get(); + GList *work = editors_list; menu = popup_menu_short_lived(); g_signal_connect(G_OBJECT(menu), "destroy", @@ -358,17 +357,19 @@ G_CALLBACK(vd_drop_menu_copy_cb), vd); menu_item_add_sensitive(menu, _("_Move"), active, G_CALLBACK(vd_drop_menu_move_cb), vd); - for (i = 0; i < GQ_EDITOR_GENERIC_SLOTS; i++) + while (work) { GtkWidget *item; - - const gchar *name = editor_get_name(i); - if (!name || !editor_is_filter(i)) continue; + const EditorDescription *editor = work->data; + work = work->next; + + if (!editor_is_filter(editor->key)) continue; + item = menu_item_add_sensitive(menu, editor->name, active, G_CALLBACK(vd_drop_menu_filter_cb), vd); - item = menu_item_add_sensitive(menu, name, active, G_CALLBACK(vd_drop_menu_filter_cb), vd); - - g_object_set_data(G_OBJECT(item), "filter_idx", GUINT_TO_POINTER(i + 1)); + g_object_set_data(G_OBJECT(item), "filter_key", editor->key); } + + g_list_free(editors_list); menu_item_add_divider(menu); menu_item_add_stock(menu, _("Cancel"), GTK_STOCK_CANCEL, NULL, vd);
--- a/src/view_file.c Thu Jan 29 19:43:34 2009 +0000 +++ b/src/view_file.c Sun Feb 01 12:48:14 2009 +0000 @@ -299,16 +299,15 @@ static void vf_pop_menu_edit_cb(GtkWidget *widget, gpointer data) { ViewFile *vf; - gint n; + const gchar *key = data; GList *list; vf = submenu_item_get_data(widget); - n = GPOINTER_TO_INT(data); if (!vf) return; list = vf_pop_menu_file_list(vf); - file_util_start_editor_from_filelist(n, list, vf->listview); + file_util_start_editor_from_filelist(key, list, vf->listview); filelist_free(list); }