From fced22edf6e2200c58f4ead3ea18e7179339f901 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Thu, 22 Nov 2012 03:24:21 +0100 Subject: [PATCH] Added input mode. Allow to set the browser into input mode if a text-, password or textarea is focused on page load. Allow to switch to input mode, if an editable element is clicked. --- src/dom.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dom.h | 6 ++++ src/main.c | 27 +++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 src/dom.c create mode 100644 src/dom.h diff --git a/src/dom.c b/src/dom.c new file mode 100644 index 0000000..8bc34fd --- /dev/null +++ b/src/dom.c @@ -0,0 +1,86 @@ +#include "dom.h" +#include "main.h" + +static gboolean dom_auto_insert(WebKitDOMElement* element); +static gboolean dom_editable_focus_cb(WebKitDOMElement* element, WebKitDOMEvent* event); +static gboolean dom_is_editable(WebKitDOMElement* element); +static WebKitDOMElement* dom_get_active_element(WebKitDOMDocument* doc); + + +void dom_check_auto_insert(void) +{ + WebKitDOMDocument* doc = webkit_web_view_get_dom_document(vp.gui.webview); + WebKitDOMElement* active = dom_get_active_element(doc); + if (!dom_auto_insert(active)) { + WebKitDOMHTMLElement *element = webkit_dom_document_get_body(doc); + if (!element) { + element = WEBKIT_DOM_HTML_ELEMENT(webkit_dom_document_get_document_element(doc)); + } + webkit_dom_event_target_add_event_listener( + WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(dom_editable_focus_cb), true, NULL + ); + } +} + +static gboolean dom_auto_insert(WebKitDOMElement* element) +{ + if (dom_is_editable(element)) { + Arg a = {VP_MODE_INSERT}; + vp_set_mode(&a); + return TRUE; + } + return FALSE; +} + +static gboolean dom_editable_focus_cb(WebKitDOMElement* element, WebKitDOMEvent* event) +{ + webkit_dom_event_target_remove_event_listener( + WEBKIT_DOM_EVENT_TARGET(element), "focus", G_CALLBACK(dom_editable_focus_cb), true + ); + if (CLEAN_MODE(vp.state.mode) != VP_MODE_INSERT) { + WebKitDOMEventTarget* target = webkit_dom_event_get_target(event); + dom_auto_insert((void*)target); + } + return FALSE; +} + +/** + * Indicates if the given dom element is an editable element like text input, + * password or textarea. + */ +static gboolean dom_is_editable(WebKitDOMElement* element) +{ + if (!element) { + return FALSE; + } + + gchar* tagname = webkit_dom_node_get_node_name(WEBKIT_DOM_NODE(element)); + if (!g_strcmp0(tagname, "TEXTAREA")) { + return TRUE; + } + if (!g_strcmp0(tagname, "INPUT")) { + gchar *type = webkit_dom_element_get_attribute((void*)element, "type"); + if (!g_strcmp0(type, "text") || !g_strcmp0(type, "password")) { + return TRUE; + } + } + return FALSE; +} + +static WebKitDOMElement* dom_get_active_element(WebKitDOMDocument* doc) +{ + WebKitDOMDocument* d = NULL; + WebKitDOMElement* active = webkit_dom_html_document_get_active_element((void*)doc); + gchar* tagname = webkit_dom_element_get_tag_name(active); + + if (!g_strcmp0(tagname, "FRAME")) { + d = webkit_dom_html_frame_element_get_content_document(WEBKIT_DOM_HTML_FRAME_ELEMENT(active)); + return dom_get_active_element(d); + } + if (!g_strcmp0(tagname, "IFRAME")) { + d = webkit_dom_html_iframe_element_get_content_document(WEBKIT_DOM_HTML_IFRAME_ELEMENT(active)); + return dom_get_active_element(d); + } + return active; +} + diff --git a/src/dom.h b/src/dom.h new file mode 100644 index 0000000..2c1331e --- /dev/null +++ b/src/dom.h @@ -0,0 +1,6 @@ +#ifndef DOM_H +#define DOM_H + +void dom_check_auto_insert(void); + +#endif /* end of include guard: DOM_H */ diff --git a/src/main.c b/src/main.c index e680cf8..250471d 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ #include "setting.h" #include "config.h" #include "completion.h" +#include "dom.h" /* variables */ VpCore vp; @@ -47,6 +48,7 @@ static void vp_read_config(void); static void vp_init_gui(void); static void vp_init_files(void); static void vp_setup_signals(void); +static gboolean vp_notify_event_cb(GtkWidget* widget, GdkEvent* event, gpointer data); #ifdef FEATURE_COOKIE static void vp_set_cookie(SoupCookie* cookie); static const gchar* vp_get_cookies(SoupURI *uri); @@ -75,6 +77,7 @@ static void vp_webview_load_status_cb(WebKitWebView* view, GParamSpec* pspec, gp break; case WEBKIT_LOAD_FINISHED: + dom_check_auto_insert(); break; case WEBKIT_LOAD_FAILED: @@ -284,6 +287,7 @@ gboolean vp_set_mode(const Arg* arg) case VP_MODE_INSERT: gtk_widget_grab_focus(GTK_WIDGET(vp.gui.webview)); + vp_echo(VP_MSG_NORMAL, FALSE, "-- INPUT --"); break; case VP_MODE_PATH_THROUGH: @@ -516,6 +520,11 @@ static void vp_setup_signals(void) * instance is closed, the program will exit */ g_signal_connect(gui->window, "destroy", G_CALLBACK(vp_destroy_window_cb), NULL); g_signal_connect(G_OBJECT(gui->webview), "notify::load-status", G_CALLBACK(vp_webview_load_status_cb), NULL); + g_object_connect( + G_OBJECT(gui->webview), + "signal::event", G_CALLBACK(vp_notify_event_cb), NULL, + NULL + ); g_object_connect( G_OBJECT(gui->inputbox), @@ -536,6 +545,24 @@ static void vp_setup_signals(void) #endif } +static gboolean vp_notify_event_cb(GtkWidget* widget, GdkEvent* event, gpointer data) +{ + WebKitHitTestResult *result = NULL; + WebKitHitTestResultContext context; + if (CLEAN_MODE(vp.state.mode) == VP_MODE_NORMAL + && event->type == GDK_BUTTON_RELEASE + ) { + result = webkit_web_view_get_hit_test_result(vp.gui.webview, (GdkEventButton*)event); + g_object_get(result, "context", &context, NULL); + if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) { + Arg a = {VP_MODE_INSERT}; + vp_set_mode(&a); + } + } + + return FALSE; +} + int main(int argc, char* argv[]) { static gboolean ver = false; -- 2.20.1