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.
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
{
32 int (*callback
)(const char *,gpointer
);
37 open_external_editor_cb(gpointer data
)
39 struct open_external_editor_cb_args
*args
;
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
)
62 g_free(args
->cb_data
);
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
));
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
);
80 DPRINTF("open_external_editor_cb, open error, %s\n",
87 nb
= read(fd
, buf
, XT_EE_BUFSZ
);
89 g_string_free(contents
, TRUE
);
90 show_oops(args
->tab
, strerror(errno
));
95 contents
= g_string_append(contents
, buf
);
103 DPRINTF("external_editor_cb: contents updated\n");
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 */
122 g_free(args
->cb_data
);
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
];
145 if (external_editor
== NULL
)
151 filename
= g_malloc(strlen(temp_dir
) + strlen(PS
"xxxtermXXXXXX") +
153 sprintf(filename
, "%s" PS
"xxxtermXXXXXX%s", temp_dir
, suffix
);
155 /* Create a temporary file */
156 fd
= mkstemps(filename
, strlen(suffix
));
158 show_oops(t
, "Cannot create temporary file");
163 while (nb
< strlen(contents
)) {
164 if (strlen(contents
) - nb
> XT_EE_BUFSZ
)
167 cnt
= strlen(contents
) - nb
;
169 rv
= write(fd
, contents
+nb
, cnt
);
173 show_oops(t
,strerror(errno
));
184 show_oops(t
,"Cannot stat file: %s\n", strerror(errno
));
189 DPRINTF("edit_src: external_editor: %s\n", external_editor
);
192 for (ptr
= external_editor
; nb
< sizeof(command
) - 1 && *ptr
; ptr
++) {
195 if (strncasecmp(ptr
, "<file>", 6) == 0) {
196 strlcpy(command
+nb
, filename
,
197 sizeof(command
) - nb
);
199 nb
+= strlen(filename
);
202 command
[nb
++] = *ptr
;
206 DPRINTF("edit_src: Launching program %s\n", command
);
212 show_oops(t
, "can't fork to execute editor");
218 a
= g_malloc(sizeof(struct open_external_editor_cb_args
));
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
,
233 /* XXX KILL system PLEASE */
234 rv
= system(command
);
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
));
255 edit_src(struct tab
*t
, struct karg
*args
)
257 WebKitWebFrame
*frame
;
258 WebKitWebDataSource
*ds
;
260 struct edit_src_cb_args
*ext_args
;
262 if (external_editor
== NULL
){
263 show_oops(t
,"Setting external_editor not set");
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.");
274 contents
= webkit_web_data_source_get_data(ds
);
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
);
287 struct edit_element_cb_args
{
288 WebKitDOMElement
*active
;
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
)
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
);
316 edit_element(struct tab
*t
, struct karg
*a
)
318 WebKitDOMHTMLDocument
*doc
;
319 WebKitDOMElement
*active_element
;
320 WebKitDOMHTMLTextAreaElement
*ta
;
321 WebKitDOMHTMLInputElement
*el
;
323 struct edit_element_cb_args
*args
;
325 if (external_editor
== NULL
){
326 show_oops(t
,"Setting external_editor not set");
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!");
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
)
352 args
->active
= active_element
;
354 open_external_editor(t
, contents
, NULL
, &edit_element_cb
, args
);
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");
369 edit_src(struct tab
*t
, struct karg
*args
)
371 show_oops(t
, "external editor feature requires webkit >= 1.5.0");