replace enable external editor with enable signals
[xombrero.git] / externaleditor.c
blob5c891733c221a8d33f016c68eef850eca37f002a
1 /*
2 * Copyright (c) 2012 Elias Norberg <xyzzy@kudzu.se>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "xxxterm.h"
19 #if !defined(XT_SIGNALS_DISABLE) && (WEBKIT_CHECK_VERSION(1, 5, 0))
20 /* we got the DOM API we need */
22 struct edit_src_cb_args {
23 WebKitWebFrame *frame;
24 WebKitWebDataSource *data_src;
27 struct open_external_editor_cb_args {
28 int child_pid;
29 char *path;
30 time_t mtime;
31 struct tab *tab;
32 int (*callback)(const char *,gpointer);
33 gpointer cb_data;
36 int
37 open_external_editor_cb(gpointer data)
39 struct open_external_editor_cb_args *args;
40 struct stat st;
41 struct tab *t;
43 int fd = -1;
44 int rv, nb;
45 int status;
46 int found_tab = 0;
47 GString *contents = NULL;
48 char buf[XT_EE_BUFSZ];
50 args = (struct open_external_editor_cb_args*)data;
52 /* Check if tab is still open */
53 TAILQ_FOREACH(t, &tabs, entry)
54 if (t == args->tab) {
55 found_tab = 1;
56 break;
59 /* Tab was deleted */
60 if (!found_tab){
61 g_free(args->path);
62 g_free(args->cb_data);
63 g_free(args);
64 return (0);
67 rv = stat(args->path, &st);
68 if (rv == -1 && errno != ENOENT) {
69 DPRINTF("open_external_editor_cb: stat error, file %s, "
70 "error: %s\n", args->path, strerror(errno));
71 show_oops(args->tab, "stat error : %s", strerror(errno));
72 goto done;
73 } else if ( rv == 0 && st.st_mtime > args->mtime) {
74 DPRINTF("File %s has been modified\n", args->path);
75 args->mtime = st.st_mtime;
77 contents = g_string_sized_new(XT_EE_BUFSZ);
78 fd = open(args->path, O_RDONLY);
79 if (fd == -1) {
80 DPRINTF("open_external_editor_cb, open error, %s\n",
81 strerror(errno));
82 goto done;
85 nb = 0;
86 for (;;) {
87 nb = read(fd, buf, XT_EE_BUFSZ);
88 if (nb < 0) {
89 g_string_free(contents, TRUE);
90 show_oops(args->tab, strerror(errno));
91 goto done;
94 buf[nb] = '\0';
95 contents = g_string_append(contents, buf);
97 if (nb < XT_EE_BUFSZ)
98 break;
100 close(fd);
101 fd = -1;
103 DPRINTF("external_editor_cb: contents updated\n");
104 if (args->callback)
105 args->callback(contents->str, args->cb_data);
107 g_string_free(contents, TRUE);
110 /* Check if child has terminated */
111 rv = waitpid(args->child_pid, &status, WNOHANG);
112 if (rv == -1 /* || WIFEXITED(status) */) {
114 /* Delete the file */
115 unlink(args->path);
116 goto done;
119 return (1);
120 done:
121 g_free(args->path);
122 g_free(args->cb_data);
123 g_free(args);
125 if (fd != -1)
126 close(fd);
128 return (0);
132 open_external_editor(struct tab *t, const char *contents, const char *suffix,
133 int (*callback)(const char *, gpointer), gpointer cb_data)
135 struct open_external_editor_cb_args *a;
136 char command[PATH_MAX];
137 char *filename;
138 char *ptr;
139 int fd;
140 int nb, rv;
141 int cnt;
142 struct stat st;
143 pid_t pid;
145 if (external_editor == NULL)
146 return (0);
148 if (suffix == NULL)
149 suffix = "";
151 filename = g_malloc(strlen(temp_dir) + strlen("/xxxtermXXXXXX") +
152 strlen(suffix) + 1);
153 sprintf(filename, "%s/xxxtermXXXXXX%s", temp_dir, suffix);
155 /* Create a temporary file */
156 fd = mkstemps(filename, strlen(suffix));
157 if (fd == -1) {
158 show_oops(t, "Cannot create temporary file");
159 return (1);
162 nb = 0;
163 while (nb < strlen(contents)) {
164 if (strlen(contents) - nb > XT_EE_BUFSZ)
165 cnt = XT_EE_BUFSZ;
166 else
167 cnt = strlen(contents) - nb;
169 rv = write(fd, contents+nb, cnt);
170 if (rv < 0) {
171 g_free(filename);
172 close(fd);
173 show_oops(t,strerror(errno));
174 return (1);
177 nb += rv;
180 rv = fstat(fd, &st);
181 if (rv == -1){
182 g_free(filename);
183 close(fd);
184 show_oops(t,"Cannot stat file: %s\n", strerror(errno));
185 return (1);
187 close(fd);
189 DPRINTF("edit_src: external_editor: %s\n", external_editor);
191 nb = 0;
192 for (ptr = external_editor; nb < sizeof(command) - 1 && *ptr; ptr++) {
194 if (*ptr == '<') {
195 if (strncasecmp(ptr, "<file>", 6) == 0) {
196 strlcpy(command+nb, filename,
197 sizeof(command) - nb);
198 ptr += 5;
199 nb += strlen(filename);
201 } else
202 command[nb++] = *ptr;
204 command[nb] = '\0';
206 DPRINTF("edit_src: Launching program %s\n", command);
208 /* Launch editor */
209 pid = fork();
210 switch (pid) {
211 case -1:
212 show_oops(t, "can't fork to execute editor");
213 return (1);
214 case 0:
215 break;
216 default:
218 a = g_malloc(sizeof(struct open_external_editor_cb_args));
219 a->child_pid = pid;
220 a->path = filename;
221 a->tab = t;
222 a->mtime = st.st_mtime;
223 a->callback = callback;
224 a->cb_data = cb_data;
226 /* Check every 100 ms if file has changed */
227 g_timeout_add(100, (GSourceFunc)open_external_editor_cb,
228 (gpointer)a);
229 return (0);
232 /* child */
233 /* XXX KILL system PLEASE */
234 rv = system(command);
236 _exit(0);
237 /* NOTREACHED */
238 return (0);
242 edit_src_cb(const char *contents, gpointer data)
244 struct edit_src_cb_args *args;
246 args = (struct edit_src_cb_args *)data;
248 webkit_web_frame_load_string(args->frame, contents, NULL,
249 webkit_web_data_source_get_encoding(args->data_src),
250 webkit_web_frame_get_uri(args->frame));
251 return (0);
255 edit_src(struct tab *t, struct karg *args)
257 WebKitWebFrame *frame;
258 WebKitWebDataSource *ds;
259 GString *contents;
260 struct edit_src_cb_args *ext_args;
262 if (external_editor == NULL){
263 show_oops(t,"Setting external_editor not set");
264 return (1);
267 frame = webkit_web_view_get_focused_frame(t->wv);
268 ds = webkit_web_frame_get_data_source(frame);
269 if (webkit_web_data_source_is_loading(ds)) {
270 show_oops(t,"Webpage is still loading.");
271 return (1);
274 contents = webkit_web_data_source_get_data(ds);
275 if (!contents)
276 show_oops(t,"No contents - opening empty file");
278 ext_args = g_malloc(sizeof(struct edit_src_cb_args));
279 ext_args->frame = frame;
280 ext_args->data_src = ds;
282 /* Check every 100 ms if file has changed */
283 open_external_editor(t, contents->str, ".html", &edit_src_cb, ext_args);
284 return (0);
287 struct edit_element_cb_args {
288 WebKitDOMElement *active;
289 struct tab *tab;
293 edit_element_cb(const char *contents, gpointer data)
295 struct edit_element_cb_args *args;
296 WebKitDOMHTMLTextAreaElement *ta;
297 WebKitDOMHTMLInputElement *el;
299 args = (struct edit_element_cb_args*)data;
301 if (!args || !args->active)
302 return (0);
304 el = (WebKitDOMHTMLInputElement*)args->active;
305 ta = (WebKitDOMHTMLTextAreaElement*)args->active;
307 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
308 webkit_dom_html_input_element_set_value(el, contents);
309 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
310 webkit_dom_html_text_area_element_set_value(ta, contents);
312 return (0);
316 edit_element(struct tab *t, struct karg *a)
318 WebKitDOMHTMLDocument *doc;
319 WebKitDOMElement *active_element;
320 WebKitDOMHTMLTextAreaElement *ta;
321 WebKitDOMHTMLInputElement *el;
322 char *contents;
323 struct edit_element_cb_args *args;
325 if (external_editor == NULL){
326 show_oops(t,"Setting external_editor not set");
327 return (0);
330 doc = (WebKitDOMHTMLDocument*)webkit_web_view_get_dom_document(t->wv);
331 active_element = webkit_dom_html_document_get_active_element(doc);
332 el = (WebKitDOMHTMLInputElement*)active_element;
333 ta = (WebKitDOMHTMLTextAreaElement*)active_element;
335 if (doc == NULL || active_element == NULL ||
336 (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el) == 0 &&
337 WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta) == 0)) {
338 show_oops(t, "No active text element!");
339 return (1);
342 contents = "";
343 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
344 contents = webkit_dom_html_input_element_get_value(el);
345 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
346 contents = webkit_dom_html_text_area_element_get_value(ta);
348 if ((args = g_malloc(sizeof(struct edit_element_cb_args))) == NULL)
349 return (1);
351 args->tab = t;
352 args->active = active_element;
354 open_external_editor(t, contents, NULL, &edit_element_cb, args);
356 return (0);
359 #else /* Just to make things compile. */
362 edit_element(struct tab *t, struct karg *a)
364 show_oops(t, "external editor feature requires webkit >= 1.5.0");
365 return (1);
369 edit_src(struct tab *t, struct karg *args)
371 show_oops(t, "external editor feature requires webkit >= 1.5.0");
372 return (1);
375 #endif