Added input mode.
authorDaniel Carl <danielcarl@gmx.de>
Thu, 22 Nov 2012 02:24:21 +0000 (03:24 +0100)
committerDaniel Carl <danielcarl@gmx.de>
Thu, 22 Nov 2012 02:24:21 +0000 (03:24 +0100)
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 [new file with mode: 0644]
src/dom.h [new file with mode: 0644]
src/main.c

diff --git a/src/dom.c b/src/dom.c
new file mode 100644 (file)
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 (file)
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 */
index e680cf8..250471d 100644 (file)
@@ -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;