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