Mercurial > geeqie
annotate src/editors.c @ 1272:e0e12512cde2
read external editors from .desktop files
author | nadvornik |
---|---|
date | Sun, 01 Feb 2009 12:48:14 +0000 |
parents | 878718372aca |
children | 8fcdfacce91d |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
123
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
3 * (C) 2006 John Ellis |
475 | 4 * Copyright (C) 2008 The Geeqie Team |
9 | 5 * |
6 * Author: John Ellis | |
7 * | |
8 * This software is released under the GNU General Public License (GNU GPL). | |
9 * Please read the included file COPYING for more information. | |
10 * This software comes with no warranty of any kind, use at your own risk! | |
11 */ | |
12 | |
13 | |
281 | 14 #include "main.h" |
9 | 15 #include "editors.h" |
16 | |
669 | 17 #include "filedata.h" |
18 #include "filefilter.h" | |
1022
9962b24b6b43
Move miscellaneous functions to their own files (new misc.[ch]).
zas_
parents:
1000
diff
changeset
|
19 #include "misc.h" |
9 | 20 #include "ui_fileops.h" |
21 #include "ui_spinner.h" | |
22 #include "ui_utildlg.h" | |
1022
9962b24b6b43
Move miscellaneous functions to their own files (new misc.[ch]).
zas_
parents:
1000
diff
changeset
|
23 #include "utilops.h" |
9 | 24 |
25 #include <errno.h> | |
26 | |
27 | |
28 #define EDITOR_WINDOW_WIDTH 500 | |
29 #define EDITOR_WINDOW_HEIGHT 300 | |
30 | |
31 | |
32 | |
33 typedef struct _EditorVerboseData EditorVerboseData; | |
34 struct _EditorVerboseData { | |
35 GenericDialog *gd; | |
36 GtkWidget *button_close; | |
37 GtkWidget *button_stop; | |
38 GtkWidget *text; | |
39 GtkWidget *progress; | |
40 GtkWidget *spinner; | |
140 | 41 }; |
42 | |
43 typedef struct _EditorData EditorData; | |
44 struct _EditorData { | |
45 gint flags; | |
46 GPid pid; | |
47 GList *list; | |
9 | 48 gint count; |
49 gint total; | |
140 | 50 gboolean stopping; |
51 EditorVerboseData *vd; | |
52 EditorCallback callback; | |
53 gpointer data; | |
1272 | 54 const EditorDescription *editor; |
9 | 55 }; |
56 | |
57 | |
140 | 58 static void editor_verbose_window_progress(EditorData *ed, const gchar *text); |
59 static gint editor_command_next_start(EditorData *ed); | |
60 static gint editor_command_next_finish(EditorData *ed, gint status); | |
61 static gint editor_command_done(EditorData *ed); | |
1272 | 62 static gint editor_command_parse(const EditorDescription *editor, GList *list, gchar **output); |
9 | 63 |
64 /* | |
65 *----------------------------------------------------------------------------- | |
66 * external editor routines | |
67 *----------------------------------------------------------------------------- | |
68 */ | |
69 | |
1272 | 70 GHashTable *editors = NULL; |
71 | |
72 #ifdef G_KEY_FILE_DESKTOP_GROUP | |
73 #define DESKTOP_GROUP G_KEY_FILE_DESKTOP_GROUP | |
74 #else | |
75 #define DESKTOP_GROUP "Desktop Entry" | |
76 #endif | |
77 | |
78 void editor_description_free(EditorDescription *editor) | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
79 { |
1272 | 80 if (!editor) return; |
81 | |
82 g_free(editor->key); | |
83 g_free(editor->name); | |
84 g_free(editor->exec); | |
85 g_free(editor->menu_path); | |
86 g_free(editor->hotkey); | |
87 string_list_free(editor->ext_list); | |
88 g_free(editor->icon); | |
89 g_free(editor->file); | |
90 g_free(editor); | |
91 } | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
92 |
1272 | 93 static GList *editor_mime_types_to_extensions(gchar **mime_types) |
94 { | |
95 /* FIXME: this should be rewritten to use the shared mime database, as soon as we switch to gio */ | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
96 |
1272 | 97 static const gchar *conv_table[][2] = { |
98 {"application/x-ufraw", "%raw"}, | |
99 {"image/*", "*"}, | |
100 {"image/bmp", ".bmp"}, | |
101 {"image/gif", ".gif"}, | |
102 {"image/jpeg", ".jpeg;.jpg"}, | |
103 {"image/jpg", ".jpg;.jpeg"}, | |
104 {"image/pcx", ".pcx"}, | |
105 {"image/png", ".png"}, | |
106 {"image/svg", ".svg"}, | |
107 {"image/svg+xml", ".svg"}, | |
108 {"image/svg+xml-compressed", ".svg"}, | |
109 {"image/tiff", ".tiff;.tif"}, | |
110 {"image/x-bmp", ".bmp"}, | |
111 {"image/x-canon-crw", ".crw"}, | |
112 {"image/x-cr2", ".cr2"}, | |
113 {"image/x-dcraw", "%raw"}, | |
114 {"image/x-ico", ".ico"}, | |
115 {"image/x-mrw", ".mrw"}, | |
116 {"image/x-MS-bmp", ".bmp"}, | |
117 {"image/x-nef", ".nef"}, | |
118 {"image/x-orf", ".orf"}, | |
119 {"image/x-pcx", ".pcx"}, | |
120 {"image/xpm", ".xpm"}, | |
121 {"image/x-png", ".png"}, | |
122 {"image/x-portable-anymap", ".pam"}, | |
123 {"image/x-portable-bitmap", ".pbm"}, | |
124 {"image/x-portable-graymap", ".pgm"}, | |
125 {"image/x-portable-pixmap", ".ppm"}, | |
126 {"image/x-psd", ".psd"}, | |
127 {"image/x-raf", ".raf"}, | |
128 {"image/x-sgi", ".sgi"}, | |
129 {"image/x-tga", ".tga"}, | |
130 {"image/x-xbitmap", ".xbm"}, | |
131 {"image/x-xcf", ".xcf"}, | |
132 {"image/x-xpixmap", ".xpm"}, | |
133 {"image/x-x3f", ".x3f"}, | |
134 {NULL, NULL}}; | |
135 | |
136 gint i, j; | |
137 GList *list = NULL; | |
138 | |
139 for (i = 0; mime_types[i]; i++) | |
140 for (j = 0; conv_table[j][0]; j++) | |
141 if (strcmp(mime_types[i], conv_table[j][0]) == 0) | |
142 list = g_list_concat(list, filter_to_list(conv_table[j][1])); | |
143 | |
144 return list; | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
145 } |
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
146 |
1272 | 147 static gboolean editor_read_desktop_file(const gchar *path) |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
148 { |
1272 | 149 GKeyFile *key_file; |
150 EditorDescription *editor; | |
151 gchar *extensions; | |
152 const gchar *key = filename_from_path(path); | |
153 gchar **categories, **only_show_in, **not_show_in; | |
154 | |
155 if (g_hash_table_lookup(editors, key)) return FALSE; /* the file found earlier wins */ | |
156 | |
157 key_file = g_key_file_new(); | |
158 if (!g_key_file_load_from_file(key_file, path, 0, NULL)) | |
159 { | |
160 g_key_file_free(key_file); | |
161 return FALSE; | |
162 } | |
163 | |
164 editor = g_new0(EditorDescription, 1); | |
165 | |
166 editor->key = g_strdup(key); | |
167 editor->file = g_strdup(path); | |
168 | |
169 g_hash_table_insert(editors, editor->key, editor); | |
170 | |
171 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "Hidden", NULL)) editor->hidden = TRUE; | |
172 | |
173 categories = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "Categories", NULL, NULL); | |
174 if (categories) | |
175 { | |
176 gboolean found = FALSE; | |
177 gint i; | |
178 for (i = 0; categories[i]; i++) | |
179 /* IMHO "Graphics" is exactly the category that we are interested in, so this does not have to be configurable */ | |
180 if (strcmp(categories[i], "Graphics") == 0 || | |
181 strcmp(categories[i], "X-Geeqie") == 0) | |
182 { | |
183 found = TRUE; | |
184 break; | |
185 } | |
186 if (!found) editor->hidden = TRUE; | |
187 g_strfreev(categories); | |
188 } | |
189 else | |
190 { | |
191 editor->hidden = TRUE; | |
192 } | |
193 | |
194 only_show_in = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "OnlyShowIn", NULL, NULL); | |
195 if (only_show_in) | |
196 { | |
197 gboolean found = FALSE; | |
198 gint i; | |
199 for (i = 0; only_show_in[i]; i++) | |
200 if (strcmp(only_show_in[i], "X-Geeqie") == 0) | |
201 { | |
202 found = TRUE; | |
203 break; | |
204 } | |
205 if (!found) editor->hidden = TRUE; | |
206 g_strfreev(only_show_in); | |
207 } | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
208 |
1272 | 209 not_show_in = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "NotShowIn", NULL, NULL); |
210 if (not_show_in) | |
211 { | |
212 gboolean found = FALSE; | |
213 gint i; | |
214 for (i = 0; not_show_in[i]; i++) | |
215 if (strcmp(not_show_in[i], "X-Geeqie") == 0) | |
216 { | |
217 found = TRUE; | |
218 break; | |
219 } | |
220 if (found) editor->hidden = TRUE; | |
221 g_strfreev(not_show_in); | |
222 } | |
223 | |
224 if (editor->hidden) | |
225 { | |
226 /* hidden editors will be deleted, no need to parse the rest */ | |
227 g_key_file_free(key_file); | |
228 return TRUE; | |
229 } | |
230 | |
231 editor->name = g_key_file_get_locale_string(key_file, DESKTOP_GROUP, "Name", NULL, NULL); | |
232 editor->icon = g_key_file_get_string(key_file, DESKTOP_GROUP, "Icon", NULL); | |
233 | |
234 editor->exec = g_key_file_get_string(key_file, DESKTOP_GROUP, "Exec", NULL); | |
235 | |
236 /* we take only editors that accept parameters, FIXME: the test can be improved */ | |
237 if (!strchr(editor->exec, '%')) editor->hidden = TRUE; | |
238 | |
239 editor->menu_path = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Menu-Path", NULL); | |
240 if (!editor->menu_path) editor->menu_path = g_strdup("EditMenu/ExternalMenu"); | |
241 | |
242 editor->hotkey = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Hotkey", NULL); | |
243 | |
244 extensions = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-File-Extensions", NULL); | |
245 if (extensions) | |
246 editor->ext_list = filter_to_list(extensions); | |
247 else | |
248 { | |
249 gchar **mime_types = g_key_file_get_string_list(key_file, DESKTOP_GROUP, "MimeType", NULL, NULL); | |
250 if (mime_types) | |
251 { | |
252 editor->ext_list = editor_mime_types_to_extensions(mime_types); | |
253 g_strfreev(mime_types); | |
254 if (!editor->ext_list) editor->hidden = TRUE; | |
255 } | |
256 | |
257 } | |
258 | |
259 | |
260 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Keep-Fullscreen", NULL)) editor->flags |= EDITOR_KEEP_FS; | |
261 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Verbose", NULL)) editor->flags |= EDITOR_VERBOSE; | |
262 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Verbose-Multi", NULL)) editor->flags |= EDITOR_VERBOSE_MULTI; | |
263 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "X-Geeqie-Filter", NULL)) editor->flags |= EDITOR_DEST; | |
264 if (g_key_file_get_boolean(key_file, DESKTOP_GROUP, "Terminal", NULL)) editor->flags |= EDITOR_TERMINAL; | |
265 | |
266 | |
267 editor->flags |= editor_command_parse(editor, NULL, NULL); | |
268 g_key_file_free(key_file); | |
269 | |
270 return TRUE; | |
768
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
271 } |
ff51413f098d
Use functions to set editors name and command and ensure they are
zas_
parents:
766
diff
changeset
|
272 |
1272 | 273 static gboolean editor_remove_desktop_file_cb(gpointer key, gpointer value, gpointer user_data) |
274 { | |
275 EditorDescription *editor = value; | |
276 return editor->hidden; | |
277 } | |
278 | |
279 static void editor_read_desktop_dir(const gchar *path) | |
9 | 280 { |
1272 | 281 DIR *dp; |
282 struct dirent *dir; | |
283 gchar *pathl; | |
284 | |
285 pathl = path_from_utf8(path); | |
286 dp = opendir(pathl); | |
287 g_free(pathl); | |
288 if (!dp) | |
289 { | |
290 /* dir not found */ | |
291 return; | |
292 } | |
293 while ((dir = readdir(dp)) != NULL) | |
294 { | |
295 gchar *namel = dir->d_name; | |
296 size_t len = strlen(namel); | |
297 | |
298 if (len > 8 && strncasecmp(namel + len - 8, ".desktop", 8) == 0) | |
299 { | |
300 gchar *name = path_to_utf8(namel); | |
301 gchar *dpath = g_build_filename(path, name, NULL); | |
302 editor_read_desktop_file(dpath); | |
303 g_free(dpath); | |
304 g_free(name); | |
305 } | |
306 } | |
307 closedir(dp); | |
308 } | |
309 | |
310 void editor_load_descriptions(void) | |
311 { | |
312 gchar *path; | |
313 gchar *xdg_data_dirs; | |
314 gchar *all_dirs; | |
315 gchar **split_dirs; | |
9 | 316 gint i; |
1272 | 317 |
318 if (!editors) | |
319 { | |
320 editors = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)editor_description_free); | |
321 } | |
9 | 322 |
1272 | 323 xdg_data_dirs = getenv("XDG_DATA_DIRS"); |
324 if (xdg_data_dirs && xdg_data_dirs[0]) | |
325 xdg_data_dirs = path_to_utf8(xdg_data_dirs); | |
326 else | |
327 xdg_data_dirs = g_strdup("/usr/share"); | |
328 | |
329 all_dirs = g_strconcat(get_rc_dir(), ":", GQ_APP_DIR, ":", xdg_data_dirs, NULL); | |
330 | |
331 g_free(xdg_data_dirs); | |
332 | |
333 split_dirs = g_strsplit(all_dirs, ":", 0); | |
334 | |
335 g_free(all_dirs); | |
336 | |
337 for (i = 0; split_dirs[i]; i++) | |
9 | 338 { |
1272 | 339 path = g_build_filename(split_dirs[i], "applications", NULL); |
340 editor_read_desktop_dir(path); | |
341 g_free(path); | |
9 | 342 } |
1272 | 343 |
344 g_strfreev(split_dirs); | |
345 | |
346 g_hash_table_foreach_remove(editors, editor_remove_desktop_file_cb, NULL); | |
9 | 347 } |
348 | |
1272 | 349 static void editor_list_add_cb(gpointer key, gpointer value, gpointer data) |
350 { | |
351 GList **listp = data; | |
352 EditorDescription *editor = value; | |
353 | |
354 /* do not show the special commands in any list, they are called explicitelly */ | |
355 if (strcmp(editor->key, CMD_COPY) == 0 || | |
356 strcmp(editor->key, CMD_MOVE) == 0 || | |
357 strcmp(editor->key, CMD_RENAME) == 0 || | |
358 strcmp(editor->key, CMD_DELETE) == 0 || | |
359 strcmp(editor->key, CMD_FOLDER) == 0) return; | |
360 | |
361 *listp = g_list_prepend(*listp, editor); | |
362 } | |
363 | |
364 GList *editor_list_get(void) | |
365 { | |
366 GList *editors_list = NULL; | |
367 g_hash_table_foreach(editors, editor_list_add_cb, &editors_list); | |
368 return editors_list; | |
369 } | |
370 | |
371 /* ------------------------------ */ | |
372 | |
373 | |
140 | 374 static void editor_verbose_data_free(EditorData *ed) |
375 { | |
376 if (!ed->vd) return; | |
377 g_free(ed->vd); | |
378 ed->vd = NULL; | |
379 } | |
380 | |
381 static void editor_data_free(EditorData *ed) | |
382 { | |
383 editor_verbose_data_free(ed); | |
384 g_free(ed); | |
385 } | |
386 | |
9 | 387 static void editor_verbose_window_close(GenericDialog *gd, gpointer data) |
388 { | |
140 | 389 EditorData *ed = data; |
9 | 390 |
391 generic_dialog_close(gd); | |
140 | 392 editor_verbose_data_free(ed); |
393 if (ed->pid == -1) editor_data_free(ed); /* the process has already terminated */ | |
9 | 394 } |
395 | |
396 static void editor_verbose_window_stop(GenericDialog *gd, gpointer data) | |
397 { | |
140 | 398 EditorData *ed = data; |
399 ed->stopping = TRUE; | |
400 ed->count = 0; | |
401 editor_verbose_window_progress(ed, _("stopping...")); | |
9 | 402 } |
403 | |
404 static void editor_verbose_window_enable_close(EditorVerboseData *vd) | |
405 { | |
406 vd->gd->cancel_cb = editor_verbose_window_close; | |
407 | |
408 spinner_set_interval(vd->spinner, -1); | |
409 gtk_widget_set_sensitive(vd->button_stop, FALSE); | |
410 gtk_widget_set_sensitive(vd->button_close, TRUE); | |
411 } | |
412 | |
140 | 413 static EditorVerboseData *editor_verbose_window(EditorData *ed, const gchar *text) |
9 | 414 { |
415 EditorVerboseData *vd; | |
416 GtkWidget *scrolled; | |
417 GtkWidget *hbox; | |
418 gchar *buf; | |
419 | |
420 vd = g_new0(EditorVerboseData, 1); | |
421 | |
1174
0bea79d87065
Drop useless wmclass stuff. Gtk will take care of it and as said in the documentation using gtk_window_set_wmclass() is sort of pointless.
zas_
parents:
1055
diff
changeset
|
422 vd->gd = file_util_gen_dlg(_("Edit command results"), "editor_results", |
9 | 423 NULL, FALSE, |
140 | 424 NULL, ed); |
9 | 425 buf = g_strdup_printf(_("Output of %s"), text); |
426 generic_dialog_add_message(vd->gd, NULL, buf, NULL); | |
427 g_free(buf); | |
428 vd->button_stop = generic_dialog_add_button(vd->gd, GTK_STOCK_STOP, NULL, | |
429 editor_verbose_window_stop, FALSE); | |
430 gtk_widget_set_sensitive(vd->button_stop, FALSE); | |
431 vd->button_close = generic_dialog_add_button(vd->gd, GTK_STOCK_CLOSE, NULL, | |
432 editor_verbose_window_close, TRUE); | |
433 gtk_widget_set_sensitive(vd->button_close, FALSE); | |
434 | |
435 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
436 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
437 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), | |
438 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
439 gtk_box_pack_start(GTK_BOX(vd->gd->vbox), scrolled, TRUE, TRUE, 5); | |
440 gtk_widget_show(scrolled); | |
441 | |
442 vd->text = gtk_text_view_new(); | |
443 gtk_text_view_set_editable(GTK_TEXT_VIEW(vd->text), FALSE); | |
444 gtk_widget_set_size_request(vd->text, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_HEIGHT); | |
445 gtk_container_add(GTK_CONTAINER(scrolled), vd->text); | |
446 gtk_widget_show(vd->text); | |
447 | |
448 hbox = gtk_hbox_new(FALSE, 0); | |
449 gtk_box_pack_start(GTK_BOX(vd->gd->vbox), hbox, FALSE, FALSE, 0); | |
450 gtk_widget_show(hbox); | |
451 | |
452 vd->progress = gtk_progress_bar_new(); | |
453 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(vd->progress), 0.0); | |
454 gtk_box_pack_start(GTK_BOX(hbox), vd->progress, TRUE, TRUE, 0); | |
455 gtk_widget_show(vd->progress); | |
456 | |
457 vd->spinner = spinner_new(NULL, SPINNER_SPEED); | |
458 gtk_box_pack_start(GTK_BOX(hbox), vd->spinner, FALSE, FALSE, 0); | |
459 gtk_widget_show(vd->spinner); | |
442 | 460 |
9 | 461 gtk_widget_show(vd->gd->dialog); |
462 | |
140 | 463 ed->vd = vd; |
9 | 464 return vd; |
465 } | |
466 | |
467 static void editor_verbose_window_fill(EditorVerboseData *vd, gchar *text, gint len) | |
468 { | |
469 GtkTextBuffer *buffer; | |
470 GtkTextIter iter; | |
471 | |
472 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(vd->text)); | |
473 gtk_text_buffer_get_iter_at_offset(buffer, &iter, -1); | |
474 gtk_text_buffer_insert(buffer, &iter, text, len); | |
475 } | |
476 | |
140 | 477 static void editor_verbose_window_progress(EditorData *ed, const gchar *text) |
9 | 478 { |
140 | 479 if (!ed->vd) return; |
480 | |
481 if (ed->total) | |
9 | 482 { |
1000
4fe8f9656107
For the sake of consistency, use glib basic types everywhere.
zas_
parents:
995
diff
changeset
|
483 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ed->vd->progress), (gdouble)ed->count / ed->total); |
9 | 484 } |
485 | |
140 | 486 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ed->vd->progress), (text) ? text : ""); |
9 | 487 } |
488 | |
489 static gboolean editor_verbose_io_cb(GIOChannel *source, GIOCondition condition, gpointer data) | |
490 { | |
140 | 491 EditorData *ed = data; |
9 | 492 gchar buf[512]; |
493 gsize count; | |
494 | |
140 | 495 if (condition & G_IO_IN) |
9 | 496 { |
140 | 497 while (g_io_channel_read_chars(source, buf, sizeof(buf), &count, NULL) == G_IO_STATUS_NORMAL) |
498 { | |
499 if (!g_utf8_validate(buf, count, NULL)) | |
9 | 500 { |
140 | 501 gchar *utf8; |
444 | 502 |
140 | 503 utf8 = g_locale_to_utf8(buf, count, NULL, NULL, NULL); |
504 if (utf8) | |
9 | 505 { |
140 | 506 editor_verbose_window_fill(ed->vd, utf8, -1); |
507 g_free(utf8); | |
9 | 508 } |
509 else | |
510 { | |
288
d1f74154463e
Replace occurences of Geeqie / geeqie by constants defined in main.h.
zas_
parents:
283
diff
changeset
|
511 editor_verbose_window_fill(ed->vd, "Error converting text to valid utf8\n", -1); |
9 | 512 } |
513 } | |
140 | 514 else |
515 { | |
516 editor_verbose_window_fill(ed->vd, buf, count); | |
517 } | |
518 } | |
9 | 519 } |
520 | |
140 | 521 if (condition & (G_IO_ERR | G_IO_HUP)) |
9 | 522 { |
140 | 523 g_io_channel_shutdown(source, TRUE, NULL); |
9 | 524 return FALSE; |
525 } | |
526 | |
527 return TRUE; | |
528 } | |
529 | |
138 | 530 typedef enum { |
531 PATH_FILE, | |
1272 | 532 PATH_FILE_URL, |
140 | 533 PATH_DEST |
138 | 534 } PathType; |
535 | |
536 | |
1272 | 537 static gchar *editor_command_path_parse(const FileData *fd, PathType type, const EditorDescription *editor) |
123
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
538 { |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
539 GString *string; |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
540 gchar *pathl; |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
541 const gchar *p = NULL; |
123
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
542 |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
543 string = g_string_new(""); |
442 | 544 |
1272 | 545 if (type == PATH_FILE || type == PATH_FILE_URL) |
138 | 546 { |
1272 | 547 GList *work = editor->ext_list; |
442 | 548 |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
549 if (!work) |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
550 p = fd->path; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
551 else |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
552 { |
516 | 553 while (work) |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
554 { |
444 | 555 GList *work2; |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
556 gchar *ext = work->data; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
557 work = work->next; |
442 | 558 |
559 if (strcmp(ext, "*") == 0 || | |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
560 strcasecmp(ext, fd->extension) == 0) |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
561 { |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
562 p = fd->path; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
563 break; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
564 } |
442 | 565 |
444 | 566 work2 = fd->sidecar_files; |
516 | 567 while (work2) |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
568 { |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
569 FileData *sfd = work2->data; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
570 work2 = work2->next; |
442 | 571 |
147
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
572 if (strcasecmp(ext, sfd->extension) == 0) |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
573 { |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
574 p = sfd->path; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
575 break; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
576 } |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
577 } |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
578 if (p) break; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
579 } |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
580 if (!p) return NULL; |
b2266996fa83
added possibility to specify prefered file type for external commands
nadvornik
parents:
140
diff
changeset
|
581 } |
138 | 582 } |
140 | 583 else if (type == PATH_DEST) |
138 | 584 { |
585 if (fd->change && fd->change->dest) | |
586 p = fd->change->dest; | |
587 else | |
588 p = ""; | |
589 } | |
444 | 590 |
123
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
591 while (*p != '\0') |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
592 { |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
593 /* must escape \, ", `, and $ to avoid problems, |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
594 * we assume system shell supports bash-like escaping |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
595 */ |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
596 if (strchr("\\\"`$", *p) != NULL) |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
597 { |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
598 string = g_string_append_c(string, '\\'); |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
599 } |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
600 string = g_string_append_c(string, *p); |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
601 p++; |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
602 } |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
603 |
1272 | 604 if (type == PATH_FILE_URL) g_string_prepend(string, "file://"); |
123
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
605 pathl = path_from_utf8(string->str); |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
606 g_string_free(string, TRUE); |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
607 |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
608 return pathl; |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
609 } |
3602a4aa7c71
Sat Dec 2 20:15:22 2006 John Ellis <johne@verizon.net>
gqview
parents:
60
diff
changeset
|
610 |
9 | 611 |
1272 | 612 static gint editor_command_parse(const EditorDescription *editor, GList *list, gchar **output) |
9 | 613 { |
140 | 614 gint flags = 0; |
1272 | 615 const gchar *p; |
140 | 616 GString *result = NULL; |
442 | 617 |
140 | 618 if (output) |
619 result = g_string_new(""); | |
620 | |
1272 | 621 if (editor->exec[0] == '\0') |
140 | 622 { |
623 flags |= EDITOR_ERROR_EMPTY; | |
624 goto err; | |
625 } | |
669 | 626 |
1272 | 627 p = editor->exec; |
669 | 628 /* skip leading whitespaces if any */ |
629 while (g_ascii_isspace(*p)) p++; | |
442 | 630 |
140 | 631 /* command */ |
442 | 632 |
140 | 633 while (*p) |
634 { | |
635 if (*p != '%') | |
636 { | |
637 if (output) result = g_string_append_c(result, *p); | |
638 } | |
639 else /* *p == '%' */ | |
640 { | |
641 gchar *pathl = NULL; | |
9 | 642 |
140 | 643 p++; |
442 | 644 |
645 switch (*p) | |
140 | 646 { |
1272 | 647 case 'f': /* single file */ |
648 case 'u': /* single url */ | |
140 | 649 flags |= EDITOR_FOR_EACH; |
650 if (flags & EDITOR_SINGLE_COMMAND) | |
651 { | |
652 flags |= EDITOR_ERROR_INCOMPATIBLE; | |
653 goto err; | |
654 } | |
655 if (output) | |
656 { | |
657 /* use the first file from the list */ | |
442 | 658 if (!list || !list->data) |
140 | 659 { |
660 flags |= EDITOR_ERROR_NO_FILE; | |
661 goto err; | |
662 } | |
669 | 663 pathl = editor_command_path_parse((FileData *)list->data, |
1272 | 664 (*p == 'f') ? PATH_FILE : PATH_FILE_URL, |
665 editor); | |
442 | 666 if (!pathl) |
140 | 667 { |
668 flags |= EDITOR_ERROR_NO_FILE; | |
669 goto err; | |
670 } | |
671 result = g_string_append_c(result, '"'); | |
672 result = g_string_append(result, pathl); | |
673 g_free(pathl); | |
674 result = g_string_append_c(result, '"'); | |
675 } | |
442 | 676 break; |
60
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
677 |
1272 | 678 case 'F': |
679 case 'U': | |
140 | 680 flags |= EDITOR_SINGLE_COMMAND; |
681 if (flags & (EDITOR_FOR_EACH | EDITOR_DEST)) | |
682 { | |
683 flags |= EDITOR_ERROR_INCOMPATIBLE; | |
684 goto err; | |
685 } | |
686 | |
687 if (output) | |
688 { | |
689 /* use whole list */ | |
690 GList *work = list; | |
691 gboolean ok = FALSE; | |
444 | 692 |
140 | 693 while (work) |
694 { | |
695 FileData *fd = work->data; | |
1272 | 696 pathl = editor_command_path_parse(fd, (*p == 'F') ? PATH_FILE : PATH_FILE_URL, editor); |
140 | 697 |
698 if (pathl) | |
699 { | |
700 ok = TRUE; | |
701 if (work != list) g_string_append_c(result, ' '); | |
702 result = g_string_append_c(result, '"'); | |
703 result = g_string_append(result, pathl); | |
704 g_free(pathl); | |
705 result = g_string_append_c(result, '"'); | |
706 } | |
707 work = work->next; | |
708 } | |
442 | 709 if (!ok) |
140 | 710 { |
711 flags |= EDITOR_ERROR_NO_FILE; | |
712 goto err; | |
713 } | |
714 } | |
442 | 715 break; |
1272 | 716 case 'i': |
717 if (output) | |
718 { | |
719 result = g_string_append(result, editor->icon); | |
720 } | |
721 break; | |
722 case 'c': | |
723 if (output) | |
724 { | |
725 result = g_string_append(result, editor->name); | |
726 } | |
727 break; | |
728 case 'k': | |
729 if (output) | |
730 { | |
731 result = g_string_append(result, editor->file); | |
732 } | |
733 break; | |
669 | 734 case '%': |
735 /* %% = % escaping */ | |
736 if (output) result = g_string_append_c(result, *p); | |
737 break; | |
1272 | 738 case 'd': |
739 case 'D': | |
740 case 'n': | |
741 case 'N': | |
742 case 'v': | |
743 case 'm': | |
744 /* deprecated according to spec, ignore */ | |
745 break; | |
140 | 746 default: |
747 flags |= EDITOR_ERROR_SYNTAX; | |
748 goto err; | |
749 } | |
750 } | |
751 p++; | |
9 | 752 } |
753 | |
140 | 754 if (output) *output = g_string_free(result, FALSE); |
755 return flags; | |
756 | |
442 | 757 |
140 | 758 err: |
442 | 759 if (output) |
9 | 760 { |
140 | 761 g_string_free(result, TRUE); |
762 *output = NULL; | |
763 } | |
764 return flags; | |
765 } | |
766 | |
1272 | 767 |
140 | 768 static void editor_child_exit_cb (GPid pid, gint status, gpointer data) |
769 { | |
770 EditorData *ed = data; | |
771 g_spawn_close_pid(pid); | |
772 ed->pid = -1; | |
442 | 773 |
140 | 774 editor_command_next_finish(ed, status); |
775 } | |
776 | |
777 | |
1272 | 778 static gint editor_command_one(const EditorDescription *editor, GList *list, EditorData *ed) |
140 | 779 { |
780 gchar *command; | |
781 FileData *fd = list->data; | |
782 GPid pid; | |
442 | 783 gint standard_output; |
784 gint standard_error; | |
140 | 785 gboolean ok; |
786 | |
787 ed->pid = -1; | |
1272 | 788 ed->flags = editor->flags | editor_command_parse(editor, list, &command); |
140 | 789 |
790 ok = !(ed->flags & EDITOR_ERROR_MASK); | |
791 | |
792 if (ok) | |
793 { | |
737
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
794 ok = (options->shell.path && *options->shell.path); |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
795 if (!ok) log_printf("ERROR: empty shell command\n"); |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
796 |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
797 if (ok) |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
798 { |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
799 ok = (access(options->shell.path, X_OK) == 0); |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
800 if (!ok) log_printf("ERROR: cannot execute shell command '%s'\n", options->shell.path); |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
801 } |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
802 |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
803 if (!ok) ed->flags |= EDITOR_ERROR_CANT_EXEC; |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
804 } |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
805 |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
806 if (ok) |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
807 { |
443 | 808 gchar *working_directory; |
809 gchar *args[4]; | |
737
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
810 guint n = 0; |
443 | 811 |
812 working_directory = remove_level_from_path(fd->path); | |
737
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
813 args[n++] = options->shell.path; |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
814 if (options->shell.options && *options->shell.options) |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
815 args[n++] = options->shell.options; |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
816 args[n++] = command; |
8a8873e7a552
Make shell command and its option rc file options instead of hardcoded strings.
zas_
parents:
731
diff
changeset
|
817 args[n] = NULL; |
443 | 818 |
1272 | 819 if ((ed->flags & EDITOR_DEST) && fd->change && fd->change->dest) /* FIXME: error handling */ |
820 { | |
821 setenv("GEEQIE_DESTINATION", fd->change->dest, TRUE); | |
822 } | |
823 else | |
824 { | |
825 unsetenv("GEEQIE_DESTINATION"); | |
826 } | |
827 | |
442 | 828 ok = g_spawn_async_with_pipes(working_directory, args, NULL, |
140 | 829 G_SPAWN_DO_NOT_REAP_CHILD, /* GSpawnFlags */ |
442 | 830 NULL, NULL, |
831 &pid, | |
832 NULL, | |
833 ed->vd ? &standard_output : NULL, | |
834 ed->vd ? &standard_error : NULL, | |
140 | 835 NULL); |
443 | 836 |
837 g_free(working_directory); | |
442 | 838 |
140 | 839 if (!ok) ed->flags |= EDITOR_ERROR_CANT_EXEC; |
840 } | |
841 | |
442 | 842 if (ok) |
140 | 843 { |
844 g_child_watch_add(pid, editor_child_exit_cb, ed); | |
845 ed->pid = pid; | |
846 } | |
442 | 847 |
140 | 848 if (ed->vd) |
849 { | |
850 if (!ok) | |
9 | 851 { |
140 | 852 gchar *buf; |
853 | |
1272 | 854 buf = g_strdup_printf(_("Failed to run command:\n%s\n"), editor->file); |
140 | 855 editor_verbose_window_fill(ed->vd, buf, strlen(buf)); |
856 g_free(buf); | |
857 | |
858 } | |
442 | 859 else |
140 | 860 { |
861 GIOChannel *channel_output; | |
862 GIOChannel *channel_error; | |
444 | 863 |
140 | 864 channel_output = g_io_channel_unix_new(standard_output); |
865 g_io_channel_set_flags(channel_output, G_IO_FLAG_NONBLOCK, NULL); | |
926 | 866 g_io_channel_set_encoding(channel_output, NULL, NULL); |
140 | 867 |
868 g_io_add_watch_full(channel_output, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR | G_IO_HUP, | |
869 editor_verbose_io_cb, ed, NULL); | |
870 g_io_channel_unref(channel_output); | |
871 | |
872 channel_error = g_io_channel_unix_new(standard_error); | |
873 g_io_channel_set_flags(channel_error, G_IO_FLAG_NONBLOCK, NULL); | |
926 | 874 g_io_channel_set_encoding(channel_error, NULL, NULL); |
140 | 875 |
876 g_io_add_watch_full(channel_error, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR | G_IO_HUP, | |
877 editor_verbose_io_cb, ed, NULL); | |
878 g_io_channel_unref(channel_error); | |
879 } | |
880 } | |
442 | 881 |
140 | 882 g_free(command); |
883 | |
884 return ed->flags & EDITOR_ERROR_MASK; | |
885 } | |
886 | |
887 static gint editor_command_next_start(EditorData *ed) | |
888 { | |
889 if (ed->vd) editor_verbose_window_fill(ed->vd, "\n", 1); | |
890 | |
891 if (ed->list && ed->count < ed->total) | |
892 { | |
893 FileData *fd; | |
894 gint error; | |
895 | |
896 fd = ed->list->data; | |
897 | |
898 if (ed->vd) | |
899 { | |
900 editor_verbose_window_progress(ed, (ed->flags & EDITOR_FOR_EACH) ? fd->path : _("running...")); | |
901 } | |
902 ed->count++; | |
903 | |
1272 | 904 error = editor_command_one(ed->editor, ed->list, ed); |
140 | 905 if (!error && ed->vd) |
906 { | |
907 gtk_widget_set_sensitive(ed->vd->button_stop, (ed->list != NULL) ); | |
908 if (ed->flags & EDITOR_FOR_EACH) | |
9 | 909 { |
140 | 910 editor_verbose_window_fill(ed->vd, fd->path, strlen(fd->path)); |
911 editor_verbose_window_fill(ed->vd, "\n", 1); | |
9 | 912 } |
913 } | |
140 | 914 |
442 | 915 if (!error) |
140 | 916 return 0; |
917 else | |
918 /* command was not started, call the finish immediately */ | |
919 return editor_command_next_finish(ed, 0); | |
920 } | |
442 | 921 |
140 | 922 /* everything is done */ |
237
404629011caa
Add missing return at the end of editor_command_next_start().
zas_
parents:
196
diff
changeset
|
923 return editor_command_done(ed); |
140 | 924 } |
925 | |
926 static gint editor_command_next_finish(EditorData *ed, gint status) | |
927 { | |
928 gint cont = ed->stopping ? EDITOR_CB_SKIP : EDITOR_CB_CONTINUE; | |
929 | |
930 if (status) | |
931 ed->flags |= EDITOR_ERROR_STATUS; | |
932 | |
933 if (ed->flags & EDITOR_FOR_EACH) | |
934 { | |
935 /* handle the first element from the list */ | |
936 GList *fd_element = ed->list; | |
444 | 937 |
140 | 938 ed->list = g_list_remove_link(ed->list, fd_element); |
939 if (ed->callback) | |
911 | 940 { |
140 | 941 cont = ed->callback(ed->list ? ed : NULL, ed->flags, fd_element, ed->data); |
911 | 942 if (ed->stopping && cont == EDITOR_CB_CONTINUE) cont = EDITOR_CB_SKIP; |
943 } | |
140 | 944 filelist_free(fd_element); |
9 | 945 } |
946 else | |
947 { | |
140 | 948 /* handle whole list */ |
949 if (ed->callback) | |
950 cont = ed->callback(NULL, ed->flags, ed->list, ed->data); | |
951 filelist_free(ed->list); | |
952 ed->list = NULL; | |
953 } | |
9 | 954 |
140 | 955 if (cont == EDITOR_CB_SUSPEND) |
956 return ed->flags & EDITOR_ERROR_MASK; | |
957 else if (cont == EDITOR_CB_SKIP) | |
958 return editor_command_done(ed); | |
959 else | |
960 return editor_command_next_start(ed); | |
961 } | |
9 | 962 |
140 | 963 static gint editor_command_done(EditorData *ed) |
964 { | |
965 gint flags; | |
9 | 966 |
140 | 967 if (ed->vd) |
968 { | |
444 | 969 const gchar *text; |
970 | |
140 | 971 if (ed->count == ed->total) |
9 | 972 { |
140 | 973 text = _("done"); |
9 | 974 } |
975 else | |
976 { | |
140 | 977 text = _("stopped by user"); |
9 | 978 } |
140 | 979 editor_verbose_window_progress(ed, text); |
980 editor_verbose_window_enable_close(ed->vd); | |
981 } | |
982 | |
983 /* free the not-handled items */ | |
984 if (ed->list) | |
985 { | |
986 ed->flags |= EDITOR_ERROR_SKIPPED; | |
987 if (ed->callback) ed->callback(NULL, ed->flags, ed->list, ed->data); | |
988 filelist_free(ed->list); | |
989 ed->list = NULL; | |
990 } | |
9 | 991 |
140 | 992 ed->count = 0; |
993 | |
994 flags = ed->flags & EDITOR_ERROR_MASK; | |
995 | |
996 if (!ed->vd) editor_data_free(ed); | |
997 | |
998 return flags; | |
999 } | |
1000 | |
1001 void editor_resume(gpointer ed) | |
1002 { | |
1003 editor_command_next_start(ed); | |
1004 } | |
443 | 1005 |
140 | 1006 void editor_skip(gpointer ed) |
1007 { | |
442 | 1008 editor_command_done(ed); |
9 | 1009 } |
1010 | |
1272 | 1011 static gint editor_command_start(const EditorDescription *editor, const gchar *text, GList *list, EditorCallback cb, gpointer data) |
140 | 1012 { |
1013 EditorData *ed; | |
1272 | 1014 gint flags = editor->flags; |
442 | 1015 |
140 | 1016 if (flags & EDITOR_ERROR_MASK) return flags & EDITOR_ERROR_MASK; |
1017 | |
1018 ed = g_new0(EditorData, 1); | |
1019 ed->list = filelist_copy(list); | |
1020 ed->flags = flags; | |
1272 | 1021 ed->editor = editor; |
140 | 1022 ed->total = (flags & EDITOR_SINGLE_COMMAND) ? 1 : g_list_length(list); |
1023 ed->count = 0; | |
1024 ed->stopping = FALSE; | |
1025 ed->callback = cb; | |
1026 ed->data = data; | |
442 | 1027 |
140 | 1028 if ((flags & EDITOR_VERBOSE_MULTI) && list && list->next) |
1029 flags |= EDITOR_VERBOSE; | |
442 | 1030 |
140 | 1031 if (flags & EDITOR_VERBOSE) |
1032 editor_verbose_window(ed, text); | |
442 | 1033 |
1034 editor_command_next_start(ed); | |
140 | 1035 /* errors from editor_command_next_start will be handled via callback */ |
1036 return flags & EDITOR_ERROR_MASK; | |
1037 } | |
1038 | |
1272 | 1039 gboolean is_valid_editor_command(const gchar *key) |
444 | 1040 { |
1272 | 1041 if (!key) return FALSE; |
1042 return g_hash_table_lookup(editors, key) != NULL; | |
444 | 1043 } |
1044 | |
1272 | 1045 gint start_editor_from_filelist_full(const gchar *key, GList *list, EditorCallback cb, gpointer data) |
9 | 1046 { |
140 | 1047 gint error; |
1272 | 1048 EditorDescription *editor; |
1049 if (!key) return FALSE; | |
1050 | |
1051 editor = g_hash_table_lookup(editors, key); | |
9 | 1052 |
444 | 1053 if (!list) return FALSE; |
1272 | 1054 if (!editor) return FALSE; |
1055 | |
1056 error = editor_command_start(editor, editor->name, list, cb, data); | |
9 | 1057 |
1272 | 1058 if (error & EDITOR_ERROR_MASK) |
669 | 1059 { |
1272 | 1060 gchar *text = g_strdup_printf(_("%s\n\"%s\""), editor_get_error_str(error), editor->file); |
669 | 1061 |
1062 file_util_warning_dialog(_("Invalid editor command"), text, GTK_STOCK_DIALOG_ERROR, NULL); | |
1063 g_free(text); | |
1064 } | |
1065 | |
140 | 1066 return error; |
9 | 1067 } |
1068 | |
1272 | 1069 gint start_editor_from_filelist(const gchar *key, GList *list) |
140 | 1070 { |
1272 | 1071 return start_editor_from_filelist_full(key, list, NULL, NULL); |
140 | 1072 } |
1073 | |
1272 | 1074 gint start_editor_from_file_full(const gchar *key, FileData *fd, EditorCallback cb, gpointer data) |
9 | 1075 { |
1076 GList *list; | |
140 | 1077 gint error; |
9 | 1078 |
138 | 1079 if (!fd) return FALSE; |
9 | 1080 |
138 | 1081 list = g_list_append(NULL, fd); |
1272 | 1082 error = start_editor_from_filelist_full(key, list, cb, data); |
9 | 1083 g_list_free(list); |
140 | 1084 return error; |
9 | 1085 } |
60
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1086 |
1272 | 1087 gint start_editor_from_file(const gchar *key, FileData *fd) |
136 | 1088 { |
1272 | 1089 return start_editor_from_file_full(key, fd, NULL, NULL); |
136 | 1090 } |
1091 | |
1272 | 1092 gint editor_window_flag_set(const gchar *key) |
60
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1093 { |
1272 | 1094 EditorDescription *editor; |
1095 if (!key) return TRUE; | |
1096 | |
1097 editor = g_hash_table_lookup(editors, key); | |
1098 if (!editor) return TRUE; | |
60
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1099 |
1272 | 1100 return (editor->flags & EDITOR_KEEP_FS); |
60
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1101 } |
9c0c402b0ef3
Mon Jun 13 17:31:46 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1102 |
1272 | 1103 gint editor_is_filter(const gchar *key) |
753 | 1104 { |
1272 | 1105 EditorDescription *editor; |
1106 if (!key) return TRUE; | |
1107 | |
1108 editor = g_hash_table_lookup(editors, key); | |
1109 if (!editor) return TRUE; | |
753 | 1110 |
1272 | 1111 return (editor->flags & EDITOR_DEST); |
753 | 1112 } |
1113 | |
140 | 1114 const gchar *editor_get_error_str(gint flags) |
1115 { | |
1116 if (flags & EDITOR_ERROR_EMPTY) return _("Editor template is empty."); | |
1117 if (flags & EDITOR_ERROR_SYNTAX) return _("Editor template has incorrect syntax."); | |
1118 if (flags & EDITOR_ERROR_INCOMPATIBLE) return _("Editor template uses incompatible macros."); | |
1119 if (flags & EDITOR_ERROR_NO_FILE) return _("Can't find matching file type."); | |
1120 if (flags & EDITOR_ERROR_CANT_EXEC) return _("Can't execute external editor."); | |
1121 if (flags & EDITOR_ERROR_STATUS) return _("External editor returned error status."); | |
1122 if (flags & EDITOR_ERROR_SKIPPED) return _("File was skipped."); | |
1123 return _("Unknown error."); | |
1124 } | |
731
fa8f7d7396cf
Introduce an helper function that returns the name of an editor.
zas_
parents:
730
diff
changeset
|
1125 |
1272 | 1126 const gchar *editor_get_name(const gchar *key) |
731
fa8f7d7396cf
Introduce an helper function that returns the name of an editor.
zas_
parents:
730
diff
changeset
|
1127 { |
1272 | 1128 EditorDescription *editor = g_hash_table_lookup(editors, key); |
731
fa8f7d7396cf
Introduce an helper function that returns the name of an editor.
zas_
parents:
730
diff
changeset
|
1129 |
1272 | 1130 if (!editor) return NULL; |
1131 | |
1132 return editor->name; | |
731
fa8f7d7396cf
Introduce an helper function that returns the name of an editor.
zas_
parents:
730
diff
changeset
|
1133 } |
1055
1646720364cf
Adding a vim modeline to all files - patch by Klaus Ethgen
nadvornik
parents:
1022
diff
changeset
|
1134 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ |