"Fossies" - the Fresh Open Source Software Archive 
Member "xombrero-1.6.4/externaleditor.c" (17 Feb 2015, 8596 Bytes) of package /linux/www/old/xombrero-1.6.4.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "externaleditor.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright (c) 2012 Elias Norberg <xyzzy@kudzu.se>
3 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <xombrero.h>
19
20 #if WEBKIT_CHECK_VERSION(1, 5, 0)
21 /* we got the DOM API we need */
22
23 struct edit_src_cb_args {
24 WebKitWebFrame *frame;
25 WebKitWebDataSource *data_src;
26 };
27
28 struct external_editor_args {
29 GPid child_pid;
30 char *path;
31 time_t mtime;
32 struct tab *tab;
33 int (*callback)(const char *,gpointer);
34 gpointer cb_data;
35 };
36
37 int
38 update_contents(struct external_editor_args *args)
39 {
40 struct stat st;
41 int fd = -1;
42 int rv, nb;
43 GString *contents = NULL;
44 char buf[XT_EE_BUFSZ];
45
46 rv = stat(args->path, &st);
47 if (rv == -1 && errno == ENOENT)
48 return (1);
49 else if (rv == 0 && st.st_mtime > args->mtime) {
50 DPRINTF("File %s has been modified\n", args->path);
51 args->mtime = st.st_mtime;
52
53 contents = g_string_sized_new(XT_EE_BUFSZ);
54 fd = open(args->path, O_RDONLY);
55 if (fd == -1) {
56 DPRINTF("open_external_editor_cb, open error, %s\n",
57 strerror(errno));
58 goto done;
59 }
60
61 for (;;) {
62 nb = read(fd, buf, XT_EE_BUFSZ);
63 if (nb < 0) {
64 g_string_free(contents, TRUE);
65 show_oops(args->tab, strerror(errno));
66 goto done;
67 }
68
69 buf[nb] = '\0';
70 contents = g_string_append(contents, buf);
71
72 if (nb < XT_EE_BUFSZ)
73 break;
74 }
75 close(fd);
76
77 DPRINTF("external_editor_cb: contents updated\n");
78 if (args->callback)
79 args->callback(contents->str, args->cb_data);
80
81 g_string_free(contents, TRUE);
82
83 return (0);
84 }
85
86 done:
87 if (fd != -1)
88 close(fd);
89 return (0);
90 }
91
92 void
93 external_editor_closed(GPid pid, gint status, gpointer data)
94 {
95 struct external_editor_args *args;
96 struct tab *t;
97 int found_tab = 0;
98
99 args = (struct external_editor_args *)data;
100
101 TAILQ_FOREACH(t, &tabs, entry)
102 if (t == args->tab) {
103 found_tab = 1;
104 break;
105 }
106
107 /* Tab was deleted */
108 if (!found_tab)
109 goto done;
110
111 /*
112 * unfortunately we can't check the exit status in glib < 2.34,
113 * otherwise a check and warning would be nice here
114 */
115 update_contents(args);
116
117 done:
118 unlink(args->path);
119 g_spawn_close_pid(pid);
120 }
121
122 int
123 open_external_editor_cb(gpointer data)
124 {
125 struct external_editor_args *args;
126 struct tab *t;
127 int found_tab = 0;
128
129 args = (struct external_editor_args*)data;
130
131 /* Check if tab is still open */
132 TAILQ_FOREACH(t, &tabs, entry)
133 if (t == args->tab) {
134 found_tab = 1;
135 break;
136 }
137
138 /* Tab was deleted */
139 if (!found_tab)
140 goto done;
141
142 if (update_contents(args))
143 goto done;
144
145 return (1);
146 done:
147 /* cleanup and remove from event loop */
148 g_free(args->path);
149 g_free(args->cb_data);
150 g_free(args);
151
152 return (0);
153 }
154
155 int
156 open_external_editor(struct tab *t, const char *contents,
157 int (*callback)(const char *, gpointer), gpointer cb_data)
158 {
159 struct stat st;
160 struct external_editor_args *a;
161 GPid pid;
162 char *cmdstr;
163 char filename[PATH_MAX];
164 char **sv;
165 int fd;
166 int nb, rv;
167 int cnt;
168
169 if (external_editor == NULL)
170 return (0);
171
172 snprintf(filename, sizeof filename, "%s" PS "xombreroXXXXXX", temp_dir);
173
174 /* Create a temporary file */
175 fd = g_mkstemp(filename);
176 if (fd == -1) {
177 show_oops(t, "Cannot create temporary file");
178 return (1);
179 }
180
181 nb = 0;
182 while (contents && nb < strlen(contents)) {
183 if (strlen(contents) - nb > XT_EE_BUFSZ)
184 cnt = XT_EE_BUFSZ;
185 else
186 cnt = strlen(contents) - nb;
187
188 rv = write(fd, contents+nb, cnt);
189 if (rv < 0) {
190 close(fd);
191 show_oops(t,strerror(errno));
192 return (1);
193 }
194
195 nb += rv;
196 }
197
198 rv = fstat(fd, &st);
199 if (rv == -1) {
200 close(fd);
201 show_oops(t,"Cannot stat file: %s\n", strerror(errno));
202 return (1);
203 }
204 close(fd);
205
206 DPRINTF("edit_src: external_editor: %s\n", external_editor);
207
208 sv = g_strsplit(external_editor, "<file>", -1);
209 cmdstr = g_strjoinv(filename, sv);
210 g_strfreev(sv);
211 sv = g_strsplit_set(cmdstr, " \t", -1);
212 if (!g_spawn_async(NULL, sv, NULL,
213 (G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), NULL, NULL, &pid,
214 NULL)) {
215 show_oops(t, "%s: could not spawn process");
216 g_strfreev(sv);
217 g_free(cmdstr);
218 return (1);
219 }
220
221 g_strfreev(sv);
222 g_free(cmdstr);
223
224 a = g_malloc(sizeof(struct external_editor_args));
225 a->child_pid = pid;
226 a->path = g_strdup(filename);
227 a->tab = t;
228 a->mtime = st.st_mtime;
229 a->callback = callback;
230 a->cb_data = cb_data;
231
232 /* Check every 100 ms if file has changed */
233 g_timeout_add(100, (GSourceFunc)open_external_editor_cb,
234 (gpointer)a);
235
236 /* Stop loop child has terminated */
237 g_child_watch_add(pid, external_editor_closed, (gpointer)a);
238
239 return (0);
240 }
241
242 int
243 edit_src_cb(const char *contents, gpointer data)
244 {
245 struct edit_src_cb_args *args;
246
247 args = (struct edit_src_cb_args *)data;
248
249 webkit_web_frame_load_string(args->frame, contents, NULL,
250 webkit_web_data_source_get_encoding(args->data_src),
251 webkit_web_frame_get_uri(args->frame));
252 return (0);
253 }
254
255 int
256 edit_src(struct tab *t, struct karg *args)
257 {
258 WebKitWebFrame *frame;
259 WebKitWebDataSource *ds;
260 GString *contents;
261 struct edit_src_cb_args *ext_args;
262
263 if (external_editor == NULL){
264 show_oops(t,"Setting external_editor not set");
265 return (1);
266 }
267
268 frame = webkit_web_view_get_focused_frame(t->wv);
269 ds = webkit_web_frame_get_data_source(frame);
270 if (webkit_web_data_source_is_loading(ds)) {
271 show_oops(t,"Webpage is still loading.");
272 return (1);
273 }
274
275 contents = webkit_web_data_source_get_data(ds);
276 if (!contents)
277 show_oops(t,"No contents - opening empty file");
278
279 ext_args = g_malloc(sizeof(struct edit_src_cb_args));
280 ext_args->frame = frame;
281 ext_args->data_src = ds;
282
283 /* Check every 100 ms if file has changed */
284 open_external_editor(t, contents ? contents->str : "", &edit_src_cb,
285 ext_args);
286 return (0);
287 }
288
289 struct edit_element_cb_args {
290 WebKitDOMElement *active;
291 struct tab *tab;
292 };
293
294 int
295 edit_element_cb(const char *contents, gpointer data)
296 {
297 struct edit_element_cb_args *args;
298 WebKitDOMHTMLTextAreaElement *ta;
299 WebKitDOMHTMLInputElement *el;
300
301 args = (struct edit_element_cb_args*)data;
302
303 if (!args || !args->active)
304 return (0);
305
306 el = (WebKitDOMHTMLInputElement*)args->active;
307 ta = (WebKitDOMHTMLTextAreaElement*)args->active;
308
309 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
310 webkit_dom_html_input_element_set_value(el, contents);
311 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
312 webkit_dom_html_text_area_element_set_value(ta, contents);
313
314 return (0);
315 }
316
317 int
318 edit_element(struct tab *t, struct karg *a)
319 {
320 WebKitDOMHTMLDocument *doc;
321 WebKitDOMElement *active_element;
322 WebKitDOMHTMLTextAreaElement *ta;
323 WebKitDOMHTMLInputElement *el;
324 char *contents;
325 struct edit_element_cb_args *args;
326
327 if (external_editor == NULL){
328 show_oops(t,"Setting external_editor not set");
329 return (0);
330 }
331
332 doc = (WebKitDOMHTMLDocument*)webkit_web_view_get_dom_document(t->wv);
333 active_element = webkit_dom_html_document_get_active_element(doc);
334 el = (WebKitDOMHTMLInputElement*)active_element;
335 ta = (WebKitDOMHTMLTextAreaElement*)active_element;
336
337 if (doc == NULL || active_element == NULL ||
338 (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el) == 0 &&
339 WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta) == 0)) {
340 show_oops(t, "No active text element!");
341 return (1);
342 }
343
344 contents = "";
345 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el))
346 contents = webkit_dom_html_input_element_get_value(el);
347 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta))
348 contents = webkit_dom_html_text_area_element_get_value(ta);
349
350 if ((args = g_malloc(sizeof(struct edit_element_cb_args))) == NULL)
351 return (1);
352
353 args->tab = t;
354 args->active = active_element;
355
356 open_external_editor(t, contents, &edit_element_cb, args);
357
358 return (0);
359 }
360
361 #else /* Just to make things compile. */
362
363 int
364 edit_element(struct tab *t, struct karg *a)
365 {
366 show_oops(t, "external editor feature requires webkit >= 1.5.0");
367 return (1);
368 }
369
370 int
371 edit_src(struct tab *t, struct karg *args)
372 {
373 show_oops(t, "external editor feature requires webkit >= 1.5.0");
374 return (1);
375 }
376
377 #endif