## 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
AC_SUBST(readmedir)
AC_SUBST(htmldir)
+eval "eval appdir=${datadir}/${PACKAGE}"
+AC_DEFINE_UNQUOTED([GQ_APP_DIR], "$appdir", [Location of application data])
+
# LIRC support
# ----------------------------------------------------------------------
src/icons/svg/Makefile
po/Makefile.in
doc/Makefile
+ plugins/Makefile
+ plugins/symlink/Makefile
geeqie.spec
])
--- /dev/null
+SUBDIRS = symlink
+
--- /dev/null
+
+qq_desktopdir = $(pkgdatadir)/applications
+qq_desktop_DATA = symlink.desktop
+
+
--- /dev/null
+[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
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 {
SortModeType mode;
SortActionType action;
+ const gchar *filter_key;
+
SortSelectionType selection;
GtkWidget *folder_group;
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;
}
}
}
-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)
GtkWidget *tbar;
GtkWidget *combo;
SortModeType mode;
- guint i;
+ GList *editors_list, *work;
+ gboolean have_filter;
if (!lw) return NULL;
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;
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);
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);
}
}
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;
}
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);
}
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)
break;
}
}
-
+#if 0
if (edit_val >= 0)
{
dupe_window_edit_selected(dw, edit_val);
}
+#endif
}
else
{
struct _EditorData {
gint flags;
GPid pid;
- gchar *command_template;
GList *list;
gint count;
gint total;
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);
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
-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;
static void editor_data_free(EditorData *ed)
{
editor_verbose_data_free(ed);
- g_free(ed->command_template);
g_free(ed);
}
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;
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;
}
if (p) break;
}
- string_list_free(ext_list);
if (!p) return NULL;
}
}
p++;
}
+ if (type == PATH_FILE_URL) g_string_prepend(string, "file://");
pathl = path_from_utf8(string->str);
g_string_free(string, TRUE);
}
-/*
- * 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)
}
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)
{
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;
}
break;
- case 'f':
+ case 'F':
+ case 'U':
flags |= EDITOR_SINGLE_COMMAND;
if (flags & (EDITOR_FOR_EACH | EDITOR_DEST))
{
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)
{
}
}
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++;
}
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;
}
-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;
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);
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,
{
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);
}
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) );
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;
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);
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;
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)
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: */
#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
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.
*/
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: */
stop_signal = FALSE;
break;
}
+#if 0
if (n != -1)
{
if (!editor_window_flag_set(n))
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)
{
{
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)
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)
{
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;
}
}
+#endif
+
/*
*-----------------------------------------------------------------------------
* recent menu
{ "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 },
{ "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) },
" <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'/>"
" <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'/>"
" <menuitem action='Maintenance'/>"
" <separator/>"
" <menuitem action='Wallpaper'/>"
+" <separator/>"
+" <menu action='ExternalMenu'>"
+" </menu>"
" </menu>"
" <menu action='ViewMenu'>"
" <menuitem action='ViewInNewWindow'/>"
" <menuitem action='SlideShow'/>"
" <menuitem action='SlideShowPause'/>"
" <menuitem action='Refresh'/>"
+" <separator/>"
" </menu>"
" <menu action='HelpMenu'>"
" <separator/>"
" <menuitem action='About'/>"
" <separator/>"
" <menuitem action='LogWindow'/>"
+" <separator/>"
" </menu>"
" </menubar>"
"<accelerator action='PrevImageAlt1'/>"
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;
}
layout_actions_setup_marks(lw);
+ layout_actions_setup_editors(lw);
layout_copy_path_update(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);
}
/*
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);
#include "cache_maint.h"
#include "thumb.h"
#include "metadata.h"
+#include "editors.h"
#include <gdk/gdkkeysyms.h> /* for keyboard values */
filter_add_defaults();
filter_rebuild();
+ editor_load_descriptions();
+
accel_map_load();
if (startup_blank)
#define MOUSEWHEEL_SCROLL_SIZE 20
-#define GQ_EDITOR_GENERIC_SLOTS 10
#define GQ_DEFAULT_SHELL_PATH "/bin/sh"
#define GQ_DEFAULT_SHELL_OPTIONS "-c"
*-----------------------------------------------------------------------------
*/
-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;
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);
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;
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);
gboolean rectangular_selection;
} collections;
- /* editors */
- Editor editor[GQ_EDITOR_SLOTS];
-
/* shell */
struct {
gchar *path;
gint mode_state;
gint action_state;
gint selection_state;
+ gchar *action_filter;
} sort;
} panels;
stop_signal = FALSE;
break;
}
-
+#if 0
if (n != -1 && fd)
{
if (!editor_window_flag_set(n))
}
file_util_start_editor_from_file(n, fd, GTK_WIDGET(pr));
}
+#endif
}
else
{
{
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);
}
}
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;
}
}
+#if 0
static void config_parse_editor_entries(GtkWidget **editor_name_entry, GtkWidget **editor_command_entry)
{
gint i;
g_string_free(errmsg, TRUE);
}
-
+#endif
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);
!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
}
+#if 0
static void editor_default_ok_cb(GenericDialog *gd, gpointer data)
{
gint i;
{
help_window_show("editors");
}
+#endif
static void safe_delete_view_cb(GtkWidget *widget, gpointer data)
{
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)
{
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)
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]);
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);
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);
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);
g_free(qname);
g_free(qcommand);
}
-
+#endif
WRITE_SUBTITLE("Exif Options");
secure_fprintf(ssi, "# Display: 0: never\n"
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);
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)
}
continue;
}
-
+#endif
/* Exif */
if (0 == g_ascii_strncasecmp(option, "exif.display.", 13))
{
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);
}
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)
stop_signal = FALSE;
break;
}
-
+#if 0
if (edit_val >= 0)
{
search_result_edit_selected(sd, edit_val);
}
+#endif
}
else
{
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,
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);
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: */
/* 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;
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;
}
if (ud->gd) generic_dialog_close(ud->gd);
g_free(ud->dest_path);
+ g_free(ud->external_command);
g_free(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))
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);
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);
ud->with_sidecars = TRUE;
- ud->external_command = n;
+ ud->external_command = g_strdup(key);
ud->dir_fd = NULL;
ud->flist = flist;
}
-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)
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);
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);
}
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",
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);
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);
}