read external editors from .desktop files
authorVladimir Nadvornik <nadvornik@suse.cz>
Sun, 1 Feb 2009 12:48:14 +0000 (12:48 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Sun, 1 Feb 2009 12:48:14 +0000 (12:48 +0000)
29 files changed:
Makefile.am
configure.in
plugins/Makefile.am [new file with mode: 0644]
plugins/symlink/Makefile.am [new file with mode: 0644]
plugins/symlink/symlink.desktop [new file with mode: 0644]
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

index c3c646c..f82d0fe 100644 (file)
@@ -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
 
index 19a0a47..200cfae 100644 (file)
@@ -208,6 +208,9 @@ AC_DEFINE_UNQUOTED(GQ_HTMLDIR, "$htmldir", [Location of html documentation])
 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 @@ AC_CONFIG_FILES([
     src/icons/svg/Makefile
     po/Makefile.in
     doc/Makefile
+    plugins/Makefile
+    plugins/symlink/Makefile
     geeqie.spec
 ])
 
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..55129fb
--- /dev/null
@@ -0,0 +1,2 @@
+SUBDIRS = symlink
+
diff --git a/plugins/symlink/Makefile.am b/plugins/symlink/Makefile.am
new file mode 100644 (file)
index 0000000..90188c1
--- /dev/null
@@ -0,0 +1,5 @@
+
+qq_desktopdir = $(pkgdatadir)/applications
+qq_desktop_DATA = symlink.desktop
+
+
diff --git a/plugins/symlink/symlink.desktop b/plugins/symlink/symlink.desktop
new file mode 100644 (file)
index 0000000..86ca452
--- /dev/null
@@ -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
index 562ad29..0d63632 100644 (file)
@@ -44,7 +44,7 @@ typedef enum {
        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 @@ struct _SortData
 
        SortModeType mode;
        SortActionType action;
+       const gchar *filter_key;
+       
        SortSelectionType selection;
 
        GtkWidget *folder_group;
@@ -282,13 +284,12 @@ static void bar_sort_bookmark_select_folder(SortData *sd, FileData *source, cons
                        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_bookmark_select(const gchar *path, gpointer data)
                }
 }
 
-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 *bar_sort_new(LayoutWindow *lw)
        GtkWidget *tbar;
        GtkWidget *combo;
        SortModeType mode;
-       guint i;
+       GList *editors_list, *work;
+       gboolean have_filter;
 
        if (!lw) return NULL;
 
@@ -562,7 +575,9 @@ GtkWidget *bar_sort_new(LayoutWindow *lw)
        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 @@ GtkWidget *bar_sort_new(LayoutWindow *lw)
                             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);
 
index cda9eb5..7c06582 100644 (file)
@@ -654,18 +654,17 @@ static GList *collection_table_popup_file_list(CollectTable *ct)
 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);
                }
 }
index a3be433..d3708d5 100644 (file)
@@ -947,14 +947,14 @@ static gint collection_window_keypress(GtkWidget *widget, GdkEventKey *event, gp
                                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;
 }
 
index 1b85dc0..b307271 100644 (file)
@@ -2051,13 +2051,13 @@ static void dupe_window_remove_selection(DupeWindow *dw, GtkWidget *listview)
        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_select_dupes_set2_cb(GtkWidget *widget, gpointer data)
 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 @@ static gint dupe_window_keypress_cb(GtkWidget *widget, GdkEventKey *event, gpoin
                                        break;
                                }
                        }
-
+#if 0
                if (edit_val >= 0)
                        {
                        dupe_window_edit_selected(dw, edit_val);
                        }
+#endif
                }
        else
                {
index 2a648fd..c749192 100644 (file)
@@ -44,7 +44,6 @@ typedef struct _EditorData EditorData;
 struct _EditorData {
        gint flags;
        GPid pid;
-       gchar *command_template;
        GList *list;
        gint count;
        gint total;
@@ -52,41 +51,15 @@ struct _EditorData {
        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 @@ static gint editor_command_done(EditorData *ed);
  *-----------------------------------------------------------------------------
  */
 
-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 */
+       
+       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;
        
-       options->editor[n].name = name ? utf8_validate_or_convert(name) : 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;
 
-       g_free(options->editor[n].command);
-       options->editor[n].command = command ? utf8_validate_or_convert(command) : NULL;
+       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);
+               }
+
+       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;    
+}
+
+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_reset_defaults(void)
+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);
+               }
+
+       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);
 
-       for (i = 0; i < GQ_EDITOR_SLOTS; i++)
+       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_verbose_data_free(EditorData *ed)
 static void editor_data_free(EditorData *ed)
 {
        editor_verbose_data_free(ed);
-       g_free(ed->command_template);
        g_free(ed);
 }
 
@@ -281,11 +529,12 @@ static gboolean editor_verbose_io_cb(GIOChannel *source, GIOCondition condition,
 
 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 @@ static gchar *editor_command_path_parse(const FileData *fd, PathType type, const
 
        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 @@ static gchar *editor_command_path_parse(const FileData *fd, PathType type, const
                                        }
                                if (p) break;
                                }
-                       string_list_free(ext_list);
                        if (!p) return NULL;
                        }
                }
@@ -354,6 +601,7 @@ static gchar *editor_command_path_parse(const FileData *fd, PathType type, const
                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 @@ static gchar *editor_command_path_parse(const FileData *fd, PathType type, const
 }
 
 
-/*
- * 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 @@ gint editor_command_parse(const gchar *template, GList *list, gchar **output)
                        }
                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 @@ gint editor_command_parse(const gchar *template, GList *list, gchar **output)
                                                        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 @@ gint editor_command_parse(const gchar *template, GList *list, gchar **output)
                                                }
                                        break;
 
-                               case 'f':
+                               case 'F':
+                               case 'U':
                                        flags |= EDITOR_SINGLE_COMMAND;
                                        if (flags & (EDITOR_FOR_EACH | EDITOR_DEST))
                                                {
@@ -519,7 +693,7 @@ gint editor_command_parse(const gchar *template, GList *list, gchar **output)
                                                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 @@ gint editor_command_parse(const gchar *template, GList *list, gchar **output)
                                                        }
                                                }
                                        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 @@ err:
                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 void editor_child_exit_cb (GPid pid, gint status, gpointer data)
 }
 
 
-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 @@ static gint editor_command_one(const gchar *template, GList *list, EditorData *e
        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 @@ static gint editor_command_one(const gchar *template, GList *list, EditorData *e
                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 @@ static gint editor_command_one(const gchar *template, GList *list, EditorData *e
                        {
                        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 @@ static gint editor_command_next_start(EditorData *ed)
                        }
                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 @@ void editor_skip(gpointer ed)
        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 @@ static gint editor_command_start(const gchar *template, const gchar *text, GList
        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;
 
-       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);
+       error = editor_command_start(editor, editor->name, list, cb, data);
 
-       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 @@ gint start_editor_from_filelist_full(gint n, GList *list, EditorCallback cb, gpo
        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 @@ gint start_editor_from_file_full(gint n, FileData *fd, EditorCallback cb, gpoint
        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 @@ const gchar *editor_get_error_str(gint flags)
        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: */
index 347df38..b6951d2 100644 (file)
@@ -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 @@ enum {
                                   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 @@ data - generic pointer
 */
 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: */
index 95f755c..3eb580e 100644 (file)
@@ -431,6 +431,7 @@ static gint view_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpoi
                                stop_signal = FALSE;
                                break;
                        }
+#if 0
                if (n != -1)
                        {
                        if (!editor_window_flag_set(n))
@@ -440,6 +441,7 @@ static gint view_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpoi
                        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 @@ static void view_edit_cb(GtkWidget *widget, gpointer data)
 {
        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)
index ab1a65b..6364faf 100644 (file)
@@ -309,16 +309,15 @@ static void li_pop_menu_zoom_fit_cb(GtkWidget *widget, gpointer data)
 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)
index 475d11a..6d801eb 100644 (file)
@@ -902,18 +902,17 @@ static void layout_menu_edit_cb(GtkAction *action, gpointer data)
 {
        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 @@ void layout_edit_update_all(void)
                }
 }
 
+#endif
+
 /*
  *-----------------------------------------------------------------------------
  * recent menu
@@ -1109,6 +1110,7 @@ static GtkActionEntry menu_entries[] = {
   { "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 @@ static GtkActionEntry menu_entries[] = {
   { "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 @@ static const gchar *menu_ui_description =
 "      <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 @@ static const gchar *menu_ui_description =
 "      <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 @@ static const gchar *menu_ui_description =
 "      <menuitem action='Maintenance'/>"
 "      <separator/>"
 "      <menuitem action='Wallpaper'/>"
+"      <separator/>"
+"      <menu action='ExternalMenu'>"
+"      </menu>"
 "    </menu>"
 "    <menu action='ViewMenu'>"
 "      <menuitem action='ViewInNewWindow'/>"
@@ -1386,6 +1371,7 @@ static const gchar *menu_ui_description =
 "      <menuitem action='SlideShow'/>"
 "      <menuitem action='SlideShowPause'/>"
 "      <menuitem action='Refresh'/>"
+"      <separator/>"
 "    </menu>"
 "    <menu action='HelpMenu'>"
 "      <separator/>"
@@ -1396,6 +1382,7 @@ static const gchar *menu_ui_description =
 "      <menuitem action='About'/>"
 "      <separator/>"
 "      <menuitem action='LogWindow'/>"
+"      <separator/>"
 "    </menu>"
 "  </menubar>"
 "<accelerator action='PrevImageAlt1'/>"
@@ -1503,6 +1490,116 @@ static void layout_actions_setup_marks(LayoutWindow *lw)
        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 @@ void layout_actions_setup(LayoutWindow *lw)
                }
        
        layout_actions_setup_marks(lw);
+       layout_actions_setup_editors(lw);
        layout_copy_path_update(lw);
 }
 
@@ -1775,7 +1873,7 @@ void layout_util_sync(LayoutWindow *lw)
        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);
 }
 
 /*
index dc19629..57e6832 100644 (file)
@@ -23,7 +23,7 @@ void layout_util_sync_thumb(LayoutWindow *lw);
 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);
index 961e914..f695620 100644 (file)
@@ -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 @@ gint main(gint argc, gchar *argv[])
        filter_add_defaults();
        filter_rebuild();
 
+       editor_load_descriptions();
+
        accel_map_load();
 
        if (startup_blank)
index 549bb21..c1f4b71 100644 (file)
@@ -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"
index eb237dc..509c1c6 100644 (file)
@@ -64,27 +64,23 @@ gpointer submenu_item_get_data(GtkWidget *menu)
  *-----------------------------------------------------------------------------
  */
 
-static void add_edit_items(GtkWidget *menu, GCallback func, GtkAccelGroup *accel_grp)
+static void add_edit_items(GtkWidget *menu, GCallback func)
 {
-       gint i;
+       GList *editors_list = editor_list_get();
+       GList *work = editors_list;
 
-       for (i = 0; i < GQ_EDITOR_GENERIC_SLOTS; i++)
+       while (work)
                {
-               gchar *text;
-               const gchar *name = editor_get_name(i);
-
-               if (!name) continue;
-
-               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);
+               const EditorDescription *editor = work->data;
+               work = work->next;
                
+               menu_item_add(menu, editor->name, func, editor->key);
                }
+       
+       g_list_free(editors_list);
 }
 
+
 GtkWidget *submenu_add_edit(GtkWidget *menu, GtkWidget **menu_item, GCallback func, gpointer data)
 {
        GtkWidget *item;
@@ -94,7 +90,7 @@ GtkWidget *submenu_add_edit(GtkWidget *menu, GtkWidget **menu_item, GCallback fu
 
        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);
 
index de93e3e..1dae788 100644 (file)
@@ -131,7 +131,8 @@ ConfOptions *init_options(ConfOptions *options)
        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 @@ void setup_default_options(ConfOptions *options)
        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);
index 3f5c93b..2a85d63 100644 (file)
@@ -110,9 +110,6 @@ struct _ConfOptions
                gboolean rectangular_selection;
        } collections;
 
-       /* editors */
-       Editor editor[GQ_EDITOR_SLOTS];
-
        /* shell */
        struct {
                gchar *path;
@@ -221,6 +218,7 @@ struct _ConfOptions
                        gint mode_state;
                        gint action_state;
                        gint selection_state;
+                       gchar *action_filter;
                } sort;
        } panels;
 
index b99a5f2..80b6ed2 100644 (file)
@@ -1330,7 +1330,7 @@ static gint pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpoin
                                stop_signal = FALSE;
                                break;
                        }
-
+#if 0
                if (n != -1 && fd)
                        {
                        if (!editor_window_flag_set(n))
@@ -1339,6 +1339,7 @@ static gint pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpoin
                                }
                        file_util_start_editor_from_file(n, fd, GTK_WIDGET(pr));
                        }
+#endif
                }
        else
                {
@@ -2669,20 +2670,19 @@ static void pan_edit_cb(GtkWidget *widget, gpointer data)
 {
        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);
                }
 }
 
index 0c8212a..c1a3722 100644 (file)
@@ -99,8 +99,6 @@ static GtkWidget *configwindow = NULL;
 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 @@ static void config_entry_to_option(GtkWidget *entry, gchar **option, gchar *(*fu
                }
 }
 
+#if 0
 static void config_parse_editor_entries(GtkWidget **editor_name_entry, GtkWidget **editor_command_entry)
 {
        gint i;
@@ -223,7 +222,7 @@ static void config_parse_editor_entries(GtkWidget **editor_name_entry, GtkWidget
 
        g_string_free(errmsg, TRUE);
 }
-
+#endif
 
 static void config_window_apply(void)
 {
@@ -231,8 +230,8 @@ static void config_window_apply(void)
        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 @@ static void filter_disable_cb(GtkWidget *widget, gpointer data)
                                 !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 @@ static void editor_help_cb(GtkWidget *widget, gpointer data)
 {
        help_window_show("editors");
 }
+#endif
 
 static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
 {
@@ -1389,7 +1390,7 @@ static void config_tab_filtering(GtkWidget *notebook)
        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 @@ static void config_tab_editors(GtkWidget *notebook)
        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 @@ static void config_tab_advanced(GtkWidget *notebook)
 
                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 @@ static void config_window_create(void)
        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);
 
index 9e78ed7..a89ed3f 100644 (file)
@@ -353,6 +353,7 @@ gboolean save_options_to(const gchar *utf8_path, ConfOptions *options)
        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 @@ gboolean save_options_to(const gchar *utf8_path, ConfOptions *options)
        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 @@ gboolean save_options_to(const gchar *utf8_path, ConfOptions *options)
                g_free(qname);
                g_free(qcommand);
                }
-
+#endif
 
        WRITE_SUBTITLE("Exif Options");
        secure_fprintf(ssi, "# Display: 0: never\n"
@@ -734,6 +735,7 @@ gboolean load_options_from(const gchar *utf8_path, ConfOptions *options)
                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 @@ gboolean load_options_from(const gchar *utf8_path, ConfOptions *options)
                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 @@ gboolean load_options_from(const gchar *utf8_path, ConfOptions *options)
                                }
                        continue;
                        }
-
+#endif
                /* Exif */
                if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
                        {
index 2977fa2..3893b2a 100644 (file)
@@ -657,12 +657,12 @@ static void search_result_remove_selection(SearchData *sd)
        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_select_none_cb(GtkWidget *widget, gpointer data)
 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 @@ static gint search_result_keypress_cb(GtkWidget *widget, GdkEventKey *event, gpo
                                stop_signal = FALSE;
                                break;
                        }
-
+#if 0
                if (edit_val >= 0)
                        {
                        search_result_edit_selected(sd, edit_val);
                        }
+#endif
                }
        else
                {
index 96e4d31..16548db 100644 (file)
@@ -38,14 +38,11 @@ typedef enum {
        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 _SecureSaveInfo SecureSaveInfo;
 
 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 @@ struct _SecureSaveInfo {
        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: */
index 2d5e0fe..b7261ed 100644 (file)
@@ -312,7 +312,7 @@ struct _UtilityData {
        /* 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 @@ static UtilityData *file_util_data_new(UtilityType type)
        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 @@ static void file_util_data_free(UtilityData *ud)
        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 @@ void file_util_perform_ci(UtilityData *ud)
        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 @@ static void file_util_rename_full(FileData *source_fd, GList *source_list, const
        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 @@ static void file_util_start_editor_full(gint n, FileData *source_fd, GList *sour
                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 @@ static void file_util_start_editor_full(gint n, FileData *source_fd, GList *sour
 
        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_rename_simple(FileData *fd, const gchar *dest_path, GtkWidget *pa
 }
 
 
-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)
index e335202..c56900a 100644 (file)
@@ -50,10 +50,10 @@ void file_util_move_simple(GList *list, const gchar *dest_path, GtkWidget *paren
 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);
 
index 890012c..1202678 100644 (file)
@@ -327,20 +327,18 @@ static void vd_drop_menu_filter_cb(GtkWidget *widget, gpointer data)
        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 @@ static void vd_drop_menu_filter_cb(GtkWidget *widget, gpointer data)
 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 @@ GtkWidget *vd_drop_menu(ViewDir *vd, gint active)
                                      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 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);
 
-               const gchar *name = editor_get_name(i);
-               if (!name || !editor_is_filter(i)) continue;
-
-               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);
index 7baffc1..37b9472 100644 (file)
@@ -299,16 +299,15 @@ GList *vf_pop_menu_file_list(ViewFile *vf)
 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);
 }