/* * Copyright (c) 2010-2013 Stefan Bolte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "dwb.h" #include "html.h" #include "util.h" #include "scripts.h" #define HTML_REMOVE_BUTTON "
×
" typedef struct _HtmlTable HtmlTable; struct _HtmlTable { const char *uri; const char *title; const char *file; int type; DwbStatus (*func)(GList *, HtmlTable *); }; static gboolean html_key_changed(WebKitDOMElement *target); void html_settings_changed(WebKitDOMElement *el); DwbStatus html_bookmarks(GList *, HtmlTable *); DwbStatus html_history(GList *, HtmlTable *); DwbStatus html_searchengines(GList *gl, HtmlTable *table); DwbStatus html_quickmarks(GList *, HtmlTable *); DwbStatus html_downloads(GList *, HtmlTable *); DwbStatus html_settings(GList *, HtmlTable *); DwbStatus html_startpage(GList *, HtmlTable *); DwbStatus html_scripts(GList *, HtmlTable *); DwbStatus html_keys(GList *, HtmlTable *); static HtmlTable table[] = { { "dwb:bookmarks", "Bookmarks", INFO_FILE, 0, html_bookmarks, }, { "dwb:quickmarks", "Quickmarks", INFO_FILE, 0, html_quickmarks, }, { "dwb:history", "History", INFO_FILE, 0, html_history, }, { "dwb:searchengines", "Searchengines", INFO_FILE, 0, html_searchengines, }, { "dwb:downloads", "Downloads", INFO_FILE, 0, html_downloads, }, { "dwb:keys", "Keys", INFO_FILE, 0, html_keys }, { "dwb:settings", "Settings", INFO_FILE, 0, html_settings }, { "dwb:script", "Scripts", NULL, 0, html_scripts }, { "dwb:startpage", NULL, NULL, 0, html_startpage }, }; static char current_uri[BUFFER_LENGTH]; DwbStatus html_load_page(WebKitWebView *wv, HtmlTable *t, char *panel) { char *filecontent; GString *content = g_string_new(NULL); char *path = util_get_data_file(t->file, "html"); char *headpath = util_get_data_file(HEAD_FILE, "html"); DwbStatus ret = STATUS_ERROR; if (path && headpath) { /* load head */ g_file_get_contents(headpath, &filecontent, NULL, NULL); g_string_append_printf(content, filecontent, t->title); g_free(filecontent); /* load content */ g_file_get_contents(path, &filecontent, NULL, NULL); if (panel) g_string_append_printf(content, filecontent, panel); webkit_web_frame_load_alternate_string(webkit_web_view_get_main_frame(wv), content->str, current_uri, current_uri); g_string_free(content, true); g_free(filecontent); ret = STATUS_OK; } g_free(headpath); g_free(path); return ret; } gboolean html_remove_item_cb(WebKitDOMElement *el, WebKitDOMEvent *ev, GList *gl) { char *navigation; const char *uri; WebKitDOMEventTarget *target = webkit_dom_event_get_target(ev); if (webkit_dom_element_has_attribute((void*)target, "navigation")) { navigation = webkit_dom_element_get_attribute(WEBKIT_DOM_ELEMENT(target), "navigation"); uri = webkit_web_view_get_uri(WEBVIEW(gl)); if (!g_strcmp0(uri, "dwb:history")) dwb_remove_history(navigation); else if (!g_strcmp0(uri, "dwb:bookmarks")) dwb_remove_bookmark(navigation); else if (!g_strcmp0(uri, "dwb:quickmarks")) dwb_remove_quickmark(navigation); else if (!g_strcmp0(uri, "dwb:downloads")) dwb_remove_download(navigation); else if (!g_strcmp0(uri, "dwb:searchengines")) dwb_remove_search_engine(navigation); } else if (webkit_dom_element_has_attribute((void*) target, "href")) { char *href = webkit_dom_element_get_attribute((void*) target, "href"); dwb_load_uri(gl, href); webkit_dom_event_prevent_default(ev); return true; } return false; } void html_load_status_cb(WebKitWebView *web, GParamSpec *p, GList *gl) { WebKitLoadStatus s = webkit_web_view_get_load_status(web); if (s == WEBKIT_LOAD_FINISHED) { WebKitDOMDocument *doc = webkit_web_view_get_dom_document(web); WebKitDOMHTMLElement *body = webkit_dom_document_get_body(doc); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(body), "click", G_CALLBACK(html_remove_item_cb), true, gl); g_signal_handlers_disconnect_by_func(web, html_load_status_cb, gl); } else if (s == WEBKIT_LOAD_FAILED) g_signal_handlers_disconnect_by_func(web, html_load_status_cb, gl); } DwbStatus html_navigation(GList *gl, GList *data, HtmlTable *table) { int i=0; WebKitWebView *wv = WEBVIEW(gl); DwbStatus ret; GString *panels = g_string_new(NULL); for (GList *l = data; l; l=l->next, i++, i%=2) { Navigation *n = l->data; g_string_append_printf(panels, "\n\ \n\ \n\ \n\
\n\ %s\n\
\n\n\
\n\ \n\ \n\ \n\
\n\ %s\n\
\n\
\n\ \n\ \n\ ×\n\ \n\ \n", n->first, n->second && g_strcmp0(n->second, "(null)") ? n->second : n->first, n->first, n->first, n->first, n->second); } if ( (ret = html_load_page(wv, table, panels->str)) == STATUS_OK) g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_load_status_cb), gl); g_string_free(panels, true); return ret; } DwbStatus html_bookmarks(GList *gl, HtmlTable *table) { dwb.fc.bookmarks = g_list_sort(dwb.fc.bookmarks, (GCompareFunc)util_navigation_compare_second); return html_navigation(gl, dwb.fc.bookmarks, table); } DwbStatus html_searchengines(GList *gl, HtmlTable *table) { WebKitWebView *wv = WEBVIEW(gl); DwbStatus ret; GString *panels = g_string_new(NULL); int i=0; for (GList *l = dwb.fc.se_completion; l; l=l->next, i++, i%=2) { Navigation *n = l->data; g_string_append_printf(panels, "\n\ \n\ \n\ \n\ %s\n\ \n\ \n\ \n\
\n\ %s\n\
\n\ \ ×\n\ \n", n->second, n->second, n->first, n->first, n->second); } if ( (ret = html_load_page(wv, table, panels->str)) == STATUS_OK) g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_load_status_cb), gl); g_string_free(panels, true); return ret; } DwbStatus html_history(GList *gl, HtmlTable *table) { return html_navigation(gl, dwb.fc.history, table); } void html_settings_changed(WebKitDOMElement *el) { char *id = webkit_dom_html_element_get_id(WEBKIT_DOM_HTML_ELEMENT(el)); char *value = NULL; char *type; if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(el)) { type = webkit_dom_element_get_attribute(el, "type"); if (!g_strcmp0(type, "checkbox")) { /* We need to dup "true" and "false", otherwise g_strstrip in * util_char_to_arg will cause a segfault */ if (webkit_dom_html_input_element_get_checked(WEBKIT_DOM_HTML_INPUT_ELEMENT(el)) ) value = g_strdup("true"); else value = g_strdup("false"); } else value = webkit_dom_html_input_element_get_value(WEBKIT_DOM_HTML_INPUT_ELEMENT(el)); } else if (WEBKIT_DOM_IS_HTML_SELECT_ELEMENT(el)) value = webkit_dom_html_select_element_get_value(WEBKIT_DOM_HTML_SELECT_ELEMENT(el)); dwb_set_setting(id, value, SET_GLOBAL); webkit_dom_element_blur(el); } gboolean html_settings_changed_cb(WebKitDOMElement *el, WebKitDOMEvent *ev, WebKitWebView *wv) { WebKitDOMEventTarget *target = webkit_dom_event_get_target(ev); html_settings_changed(WEBKIT_DOM_ELEMENT(target)); return true; } gboolean html_settings_really_changed_cb(WebKitDOMElement *el, WebKitDOMEvent *ev, WebKitWebView *wv) { webkit_dom_element_blur(el); return true; } gboolean html_keydown_settings_cb(WebKitDOMElement *el, WebKitDOMEvent *ev, WebKitWebView *wv) { glong val = webkit_dom_ui_event_get_key_code(WEBKIT_DOM_UI_EVENT(ev)); if (val == 13) { WebKitDOMEventTarget *target = webkit_dom_event_get_target(ev); if (target != NULL) html_settings_changed(WEBKIT_DOM_ELEMENT(target)); dwb_change_mode(NORMAL_MODE, false); return true; } return false; } gboolean html_keydown_cb(WebKitDOMElement *el, WebKitDOMEvent *ev, WebKitWebView *wv) { glong val = webkit_dom_ui_event_get_key_code(WEBKIT_DOM_UI_EVENT(ev)); if (val == 13) { WebKitDOMEventTarget *target = webkit_dom_event_get_target(ev); if (target != NULL && WEBKIT_DOM_IS_ELEMENT(target)) return html_key_changed(WEBKIT_DOM_ELEMENT(target)); } return false; } void html_settings_fill(char *key, WebSettings *s, WebKitWebView *wv) { char *value = util_arg_to_char(&s->arg, s->type); WebKitDOMDocument *doc = webkit_web_view_get_dom_document(wv); //WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc); WebKitDOMElement *e = webkit_dom_document_get_element_by_id(doc, key); if (s->type == BOOLEAN) { webkit_dom_html_input_element_set_checked(WEBKIT_DOM_HTML_INPUT_ELEMENT(e), s->arg.b); } else if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(e)) webkit_dom_html_input_element_set_value(WEBKIT_DOM_HTML_INPUT_ELEMENT(e), value ? value : ""); else if (WEBKIT_DOM_IS_HTML_SELECT_ELEMENT(e)) { char *lower = g_utf8_strdown(value, -1); webkit_dom_html_select_element_set_value(WEBKIT_DOM_HTML_SELECT_ELEMENT(e), lower); g_free(lower); } g_free(value); } void html_settings_load_cb(WebKitWebView *wv, GParamSpec *p, HtmlTable *table) { WebKitLoadStatus status = webkit_web_view_get_load_status(wv); if (status == WEBKIT_LOAD_FINISHED) { WebKitDOMDocument *doc = webkit_web_view_get_dom_document(wv); WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "keydown", G_CALLBACK(html_keydown_settings_cb), true, wv); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "change", G_CALLBACK(html_settings_changed_cb), true, wv); g_hash_table_foreach(dwb.settings, (GHFunc)html_settings_fill, wv); g_signal_handlers_disconnect_by_func(wv, html_settings_load_cb, table); } } DwbStatus html_settings(GList *gl, HtmlTable *table) { char *content = NULL; DwbStatus ret = STATUS_ERROR; WebKitWebView *wv = WEBVIEW(gl); char *path = util_get_data_file(SETTINGS_FILE, "html"); if (path != NULL) { g_file_get_contents(path, &content, NULL, NULL); ret = html_load_page(wv, table, content); g_free(path); g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_settings_load_cb), table); } g_free(content); return ret; } static gboolean html_custom_keys_changed_cb(WebKitDOMElement *target, WebKitDOMEvent *e, gpointer data) { WebKitDOMDocument *doc = webkit_dom_node_get_owner_document(WEBKIT_DOM_NODE(target)); WebKitDOMElement *text_area = webkit_dom_document_get_element_by_id(doc, "dwb_custom_keys_area"); char *value = webkit_dom_html_text_area_element_get_value(WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT(text_area)); util_set_file_content(dwb.files[FILES_CUSTOM_KEYS], value); g_free(value); dwb_init_custom_keys(true); dwb_set_normal_message(dwb.state.fview, true, "Custom keys saved"); dwb_change_mode(NORMAL_MODE, false); return true; } static gboolean html_key_changed(WebKitDOMElement *target) { g_return_val_if_fail(target != NULL, false); char *value; if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT(target)) value = webkit_dom_html_text_area_element_get_value(WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT(target)); else if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(target)) value = webkit_dom_html_input_element_get_value(WEBKIT_DOM_HTML_INPUT_ELEMENT(target)); else return false; char *id = webkit_dom_html_element_get_id(WEBKIT_DOM_HTML_ELEMENT(target)); if (g_strcmp0(id, "dwb_custom_keys_area")) { dwb_set_key(id, value); webkit_dom_element_blur(target); return true; } return false; } static gboolean html_changed_cb(WebKitDOMElement *input, WebKitDOMEvent *e, gpointer data) { WebKitDOMEventTarget *target = webkit_dom_event_get_target(e); return html_key_changed(WEBKIT_DOM_ELEMENT(target)); } void html_keys_load_cb(WebKitWebView *wv, GParamSpec *p, HtmlTable *table) { KeyMap *km; Navigation n; WebKitDOMElement *input; char *mod, *value; gsize length; if (webkit_web_view_get_load_status(wv) == WEBKIT_LOAD_FINISHED) { WebKitDOMDocument *doc = webkit_web_view_get_dom_document(wv); WebKitDOMDOMWindow *win = webkit_dom_document_get_default_view(doc); for (GList *l = dwb.keymap; l; l=l->next) { km = l->data; n = km->map->n; if (n.first == NULL) continue; input = webkit_dom_document_get_element_by_id(doc, n.first); if (input != NULL) { mod = dwb_modmask_to_string(km->mod); value = g_strdup_printf("%s%s%s", mod, strlen(mod) > 0 ? " " : "", km->key ? km->key : ""); webkit_dom_html_input_element_set_value(WEBKIT_DOM_HTML_INPUT_ELEMENT(input), value); g_free(mod); g_free(value); } } webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "change", G_CALLBACK(html_changed_cb), true, wv); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(win), "keydown", G_CALLBACK(html_keydown_cb), true, wv); WebKitDOMElement *textarea = webkit_dom_document_get_element_by_id(doc, "dwb_custom_keys_area"); WebKitDOMElement *button = webkit_dom_document_get_element_by_id(doc, "dwb_custom_keys_submit"); char *content = util_get_file_content(dwb.files[FILES_CUSTOM_KEYS], &length); if (content != NULL && length > 0) { webkit_dom_html_text_area_element_set_value(WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT(textarea), content); } webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(button), "click", G_CALLBACK(html_custom_keys_changed_cb), false, wv); FREE0(content); g_signal_handlers_disconnect_by_func(wv, html_keys_load_cb, table); } } DwbStatus html_keys(GList *gl, HtmlTable *table) { DwbStatus ret = STATUS_ERROR; char *content = NULL; WebKitWebView *wv = WEBVIEW(gl); char *path = util_get_data_file(KEY_FILE, "html"); if (path != NULL) { g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_keys_load_cb), table); g_file_get_contents(path, &content, NULL, NULL); ret = html_load_page(wv, table, content); g_free(path); } g_free(content); return ret; } DwbStatus html_quickmarks(GList *gl, HtmlTable *table) { DwbStatus ret; WebKitWebView *wv = WEBVIEW(gl); GString *panels = g_string_new(NULL); for (GList *gl = dwb.fc.quickmarks; gl; gl=gl->next) { Quickmark *q = gl->data; g_string_append_printf(panels, "\n\ \n\ \n\
%s
\n\ \n\ \n\
\n\ \n\
\n\ %s\n\
\n\
\n\
\n\ \n\ \n\ \n\
\n\ %s\n\
\n\
\n\ \n\ ×\n\ ", q->key, q->nav->first, q->nav->second && g_strcmp0(q->nav->second, "(null)") ? q->nav->second : q->nav->first, q->nav->first, q->nav->first, q->key, q->nav->first, q->nav->second); } if ( (ret = html_load_page(wv, table, panels->str)) == STATUS_OK) g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_load_status_cb), gl); g_string_free(panels, true); return ret; } DwbStatus html_downloads(GList *gl, HtmlTable *table) { DwbStatus ret; WebKitWebView *wv = WEBVIEW(gl); GString *panels = g_string_new(NULL); for (GList *gl = dwb.fc.downloads; gl; gl=gl->next) { Navigation *n = gl->data; g_string_append_printf(panels, "\n\ \n\ \n\ \n\ %s\n\ \n\ \ \n\ \n\ restart\n\ \n\ \ ×\n\ ", n->second, n->second, n->first, n->first, n->second); } if ( (ret = html_load_page(wv, table, panels->str)) == STATUS_OK) g_signal_connect(wv, "notify::load-status", G_CALLBACK(html_load_status_cb), gl); g_string_free(panels, true); return ret; } DwbStatus html_startpage(GList *gl, HtmlTable *table) { return dwb_open_startpage(gl); } gboolean html_scripts_confirm(WebKitDOMElement *el, WebKitDOMEvent *ev, GList *gl) { glong val = webkit_dom_ui_event_get_key_code(WEBKIT_DOM_UI_EVENT(ev)); if (val == 13 && webkit_dom_mouse_event_get_ctrl_key((void*)ev)) { char *html = webkit_dom_html_element_get_inner_text(WEBKIT_DOM_HTML_ELEMENT(el)); if (!scripts_execute_one(html)) dwb_set_error_message(dwb.state.fview, "An error occured"); else { dwb_set_normal_message(dwb.state.fview, true, "Execution successfull"); dwb_change_mode(NORMAL_MODE, false); } webkit_dom_event_prevent_default(ev); return true; } return false; } void html_scripts_load_status_cb(WebKitWebView *web, GParamSpec *p, GList *gl) { WebKitLoadStatus s = webkit_web_view_get_load_status(web); if (s == WEBKIT_LOAD_FINISHED) { WebKitDOMDocument *doc = webkit_web_view_get_dom_document(web); WebKitDOMElement *pre = webkit_dom_document_query_selector(doc, "pre", NULL); webkit_dom_element_focus(WEBKIT_DOM_ELEMENT(pre)); dwb_change_mode(INSERT_MODE); webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(pre), "keypress", G_CALLBACK(html_scripts_confirm), true, gl); g_signal_handlers_disconnect_by_func(web, html_scripts_load_status_cb, gl); } else if (s == WEBKIT_LOAD_FAILED) g_signal_handlers_disconnect_by_func(web, html_scripts_load_status_cb, gl); } DwbStatus html_scripts(GList *gl, HtmlTable *table) { g_signal_connect(WEBVIEW(gl), "notify::load-status", G_CALLBACK(html_scripts_load_status_cb), gl); webkit_web_frame_load_alternate_string(webkit_web_view_get_main_frame(WEBVIEW(gl)), "
", table->uri, table->uri);
    return STATUS_OK;
}

gboolean 
html_load(GList *gl, const char *uri) 
{
    gboolean ret = false;
    for (guint i=0; i