2 * Copyright (c) 2012 Elias Norberg <xyzzy@kudzu.se>
3 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
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.
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.
20 #if !defined(XT_SIGNALS_DISABLE) && (WEBKIT_CHECK_VERSION(1, 5, 0))
21 /* we got the DOM API we need */
23 struct edit_src_cb_args
{
24 WebKitWebFrame
*frame
;
25 WebKitWebDataSource
*data_src
;
28 struct open_external_editor_cb_args
{
33 int (*callback
)(const char *,gpointer
);
38 open_external_editor_cb(gpointer data
)
40 struct open_external_editor_cb_args
*args
;
48 GString
*contents
= NULL
;
49 char buf
[XT_EE_BUFSZ
];
51 args
= (struct open_external_editor_cb_args
*)data
;
53 /* Check if tab is still open */
54 TAILQ_FOREACH(t
, &tabs
, entry
)
63 g_free(args
->cb_data
);
68 rv
= stat(args
->path
, &st
);
69 if (rv
== -1 && errno
!= ENOENT
) {
70 DPRINTF("open_external_editor_cb: stat error, file %s, "
71 "error: %s\n", args
->path
, strerror(errno
));
72 show_oops(args
->tab
, "stat error : %s", strerror(errno
));
74 } else if ( rv
== 0 && st
.st_mtime
> args
->mtime
) {
75 DPRINTF("File %s has been modified\n", args
->path
);
76 args
->mtime
= st
.st_mtime
;
78 contents
= g_string_sized_new(XT_EE_BUFSZ
);
79 fd
= open(args
->path
, O_RDONLY
);
81 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) */) {
113 /* Delete the file */
120 g_spawn_close_pid(args
->child_pid
);
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
)
136 struct open_external_editor_cb_args
*a
;
139 char filename
[PATH_MAX
];
145 if (external_editor
== NULL
)
151 snprintf(filename
, sizeof filename
, "%s" PS
"xombreroXXXXXX%s",
154 /* Create a temporary file */
155 fd
= mkstemps(filename
, strlen(suffix
));
157 show_oops(t
, "Cannot create temporary file");
162 while (nb
< strlen(contents
)) {
163 if (strlen(contents
) - nb
> XT_EE_BUFSZ
)
166 cnt
= strlen(contents
) - nb
;
168 rv
= write(fd
, contents
+nb
, cnt
);
171 show_oops(t
,strerror(errno
));
181 show_oops(t
,"Cannot stat file: %s\n", strerror(errno
));
186 DPRINTF("edit_src: external_editor: %s\n", external_editor
);
188 sv
= g_strsplit(external_editor
, "<file>", -1);
189 cmdstr
= g_strjoinv(filename
, sv
);
191 sv
= g_strsplit_set(cmdstr
, " \t", -1);
192 if (!g_spawn_async(NULL
, sv
, NULL
,
193 (G_SPAWN_SEARCH_PATH
| G_SPAWN_DO_NOT_REAP_CHILD
), NULL
, NULL
, &pid
,
195 show_oops(t
, "%s: could not spawn process");
205 a
= g_malloc(sizeof(struct open_external_editor_cb_args
));
207 a
->path
= g_strdup(filename
);
209 a
->mtime
= st
.st_mtime
;
210 a
->callback
= callback
;
211 a
->cb_data
= cb_data
;
213 /* Check every 100 ms if file has changed */
214 g_timeout_add(100, (GSourceFunc
)open_external_editor_cb
,
220 edit_src_cb(const char *contents
, gpointer data
)
222 struct edit_src_cb_args
*args
;
224 args
= (struct edit_src_cb_args
*)data
;
226 webkit_web_frame_load_string(args
->frame
, contents
, NULL
,
227 webkit_web_data_source_get_encoding(args
->data_src
),
228 webkit_web_frame_get_uri(args
->frame
));
233 edit_src(struct tab
*t
, struct karg
*args
)
235 WebKitWebFrame
*frame
;
236 WebKitWebDataSource
*ds
;
238 struct edit_src_cb_args
*ext_args
;
240 if (external_editor
== NULL
){
241 show_oops(t
,"Setting external_editor not set");
245 frame
= webkit_web_view_get_focused_frame(t
->wv
);
246 ds
= webkit_web_frame_get_data_source(frame
);
247 if (webkit_web_data_source_is_loading(ds
)) {
248 show_oops(t
,"Webpage is still loading.");
252 contents
= webkit_web_data_source_get_data(ds
);
254 show_oops(t
,"No contents - opening empty file");
256 ext_args
= g_malloc(sizeof(struct edit_src_cb_args
));
257 ext_args
->frame
= frame
;
258 ext_args
->data_src
= ds
;
260 /* Check every 100 ms if file has changed */
261 open_external_editor(t
, contents
->str
, ".html", &edit_src_cb
, ext_args
);
265 struct edit_element_cb_args
{
266 WebKitDOMElement
*active
;
271 edit_element_cb(const char *contents
, gpointer data
)
273 struct edit_element_cb_args
*args
;
274 WebKitDOMHTMLTextAreaElement
*ta
;
275 WebKitDOMHTMLInputElement
*el
;
277 args
= (struct edit_element_cb_args
*)data
;
279 if (!args
|| !args
->active
)
282 el
= (WebKitDOMHTMLInputElement
*)args
->active
;
283 ta
= (WebKitDOMHTMLTextAreaElement
*)args
->active
;
285 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el
))
286 webkit_dom_html_input_element_set_value(el
, contents
);
287 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta
))
288 webkit_dom_html_text_area_element_set_value(ta
, contents
);
294 edit_element(struct tab
*t
, struct karg
*a
)
296 WebKitDOMHTMLDocument
*doc
;
297 WebKitDOMElement
*active_element
;
298 WebKitDOMHTMLTextAreaElement
*ta
;
299 WebKitDOMHTMLInputElement
*el
;
301 struct edit_element_cb_args
*args
;
303 if (external_editor
== NULL
){
304 show_oops(t
,"Setting external_editor not set");
308 doc
= (WebKitDOMHTMLDocument
*)webkit_web_view_get_dom_document(t
->wv
);
309 active_element
= webkit_dom_html_document_get_active_element(doc
);
310 el
= (WebKitDOMHTMLInputElement
*)active_element
;
311 ta
= (WebKitDOMHTMLTextAreaElement
*)active_element
;
313 if (doc
== NULL
|| active_element
== NULL
||
314 (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el
) == 0 &&
315 WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta
) == 0)) {
316 show_oops(t
, "No active text element!");
321 if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el
))
322 contents
= webkit_dom_html_input_element_get_value(el
);
323 else if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(ta
))
324 contents
= webkit_dom_html_text_area_element_get_value(ta
);
326 if ((args
= g_malloc(sizeof(struct edit_element_cb_args
))) == NULL
)
330 args
->active
= active_element
;
332 open_external_editor(t
, contents
, NULL
, &edit_element_cb
, args
);
337 #else /* Just to make things compile. */
340 edit_element(struct tab
*t
, struct karg
*a
)
342 show_oops(t
, "external editor feature requires webkit >= 1.5.0");
347 edit_src(struct tab
*t
, struct karg
*args
)
349 show_oops(t
, "external editor feature requires webkit >= 1.5.0");