From: Daniel Carl Date: Tue, 11 Apr 2017 22:03:03 +0000 (+0200) Subject: Use script message handler to track elements focus changes. X-Git-Url: https://git.owens.tech///git?a=commitdiff_plain;h=246fd134d3850610d4c6d49f02783ae82e1b63fa;p=vimb.git Use script message handler to track elements focus changes. Use script message handler instead of dbus to track for focused editable elements to switch vimb into input mode or back to normal mode. --- diff --git a/src/ext-proxy.c b/src/ext-proxy.c index b17f081..daf04ce 100644 --- a/src/ext-proxy.c +++ b/src/ext-proxy.c @@ -32,10 +32,6 @@ static void on_proxy_created (GDBusProxy *proxy, GAsyncResult *result, gpointer data); static void dbus_call(Client *c, const char *method, GVariant *param, GAsyncReadyCallback callback); -static void on_editable_change_focus(GDBusConnection *connection, - const char *sender_name, const char *object_path, - const char *interface_name, const char *signal_name, - GVariant *parameters, gpointer data); static void on_web_extension_page_created(GDBusConnection *connection, const char *sender_name, const char *object_path, const char *interface_name, const char *signal_name, @@ -188,42 +184,6 @@ static void dbus_call(Client *c, const char *method, GVariant *param, g_dbus_proxy_call(c->dbusproxy, method, param, G_DBUS_CALL_FLAGS_NONE, -1, NULL, callback, c); } -/** - * Callback called if a editable element changes it's focus state. - */ -static void on_editable_change_focus(GDBusConnection *connection, - const char *sender_name, const char *object_path, - const char *interface_name, const char *signal_name, - GVariant *parameters, gpointer data) -{ - gboolean is_focused; - Client *c = (Client*)data; - g_variant_get(parameters, "(b)", &is_focused); - - /* Don't change the mode if we are in pass through mode. */ - if (c->mode->id == 'n' && is_focused) { - vb_enter(c, 'i'); - } else if (c->mode->id == 'i' && !is_focused) { - vb_enter(c, 'n'); - } - /* TODO allo strict-focus to ignore focus event for initial set focus */ -} - -/** - * Listen to the VerticalScroll signal of the webextension and set the scroll - * percent value on the client to update the statusbar. - */ -static void on_vertical_scroll(GDBusConnection *connection, - const char *sender_name, const char *object_path, - const char *interface_name, const char *signal_name, - GVariant *parameters, gpointer data) -{ - Client *c = (Client*)data; - g_variant_get(parameters, "(tt)", &c->state.scroll_max, &c->state.scroll_percent); - - vb_statusbar_update(c); -} - /** * Called when the web context created the page. * @@ -248,13 +208,6 @@ static void on_web_extension_page_created(GDBusConnection *connection, /* Set the dbus proxy on the right client based on page id. */ p->dbusproxy = (GDBusProxy*)data; - g_dbus_connection_signal_subscribe(connection, NULL, - VB_WEBEXTENSION_INTERFACE, "VerticalScroll", - VB_WEBEXTENSION_OBJECT_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE, - (GDBusSignalCallback)on_vertical_scroll, p, NULL); - g_dbus_connection_signal_subscribe(connection, NULL, - VB_WEBEXTENSION_INTERFACE, "EditableChangeFocus", - VB_WEBEXTENSION_OBJECT_PATH, NULL, G_DBUS_SIGNAL_FLAGS_NONE, - (GDBusSignalCallback)on_editable_change_focus, p, NULL); + /* TODO Subscribe to debus signals here. */ } } diff --git a/src/main.c b/src/main.c index f1a12e8..8ae8f52 100644 --- a/src/main.c +++ b/src/main.c @@ -91,6 +91,8 @@ static void vimb_cleanup(void); #endif static void vimb_setup(void); static WebKitWebView *webview_new(Client *c, WebKitWebView *webview); +static void on_script_message_focus(WebKitUserContentManager *manager, + WebKitJavascriptResult *message, Client *c); struct Vimb vb; @@ -1554,9 +1556,34 @@ static WebKitWebView *webview_new(Client *c, WebKitWebView *webview) webkit_user_script_unref(script); } + /* Inject the global utility script. */ + script = webkit_user_script_new(VIMB_UTIL, + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END, NULL, NULL); + webkit_user_content_manager_add_script(ucm, script); + webkit_user_script_unref(script); + + /* Setup script message handlers. */ + webkit_user_content_manager_register_script_message_handler(ucm, "focus"); + g_signal_connect(ucm, "script-message-received::focus", G_CALLBACK(on_script_message_focus), c); + return new; } +static void on_script_message_focus(WebKitUserContentManager *manager, + WebKitJavascriptResult *message, Client *c) +{ + gboolean is_focused; + + is_focused = (gboolean)util_js_result_as_number(message); + /* Don't change the mode if we are in pass through mode. */ + if (c->mode->id == 'n' && is_focused) { + vb_enter(c, 'i'); + } else if (c->mode->id == 'i' && !is_focused) { + vb_enter(c, 'n'); + } +} + int main(int argc, char* argv[]) { Client *c; diff --git a/src/scripts/vimb_util.js b/src/scripts/vimb_util.js new file mode 100644 index 0000000..df747fa --- /dev/null +++ b/src/scripts/vimb_util.js @@ -0,0 +1,38 @@ +/* Utility object injected into all frames. */ +var vimb = Object.freeze((function(){ + 'use strict'; + /* Checks if given element is editable */ + function isEditable(e) { + if (e) { + var name = e.tagName.toLowerCase(); + return e.isContentEditable + || name == "textarea" + || (name == "input" && /^(?:color|date|datetime|datetime-local|email|month|number|password|search|tel|text|time|url|week)$/i.test(e.type)); + } + return false; + } + + return { + init: function() { + var b = document.body; + b.addEventListener( + "focus", + function(ev) { + var e = ev.target, n; + if (isEditable(e)) { + window.webkit.messageHandlers.focus.postMessage(1); + } + }, + true + ); + b.addEventListener( + "blur", + function() { + window.webkit.messageHandlers.focus.postMessage(0); + }, + true + ); + } + }; +})()); +vimb.init(); diff --git a/src/util.c b/src/util.c index 29557f2..3430a58 100644 --- a/src/util.c +++ b/src/util.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -414,6 +415,35 @@ gboolean util_filename_fill_completion(Client *c, GtkListStore *store, const cha return found; } +char *util_js_result_as_string(WebKitJavascriptResult *result) +{ + JSValueRef value; + JSStringRef string; + size_t len; + char *retval = NULL; + + value = webkit_javascript_result_get_value(result); + string = JSValueToStringCopy(webkit_javascript_result_get_global_context(result), + value, NULL); + + len = JSStringGetMaximumUTF8CStringSize(string); + if (len) { + retval = g_malloc(len); + JSStringGetUTF8CString(string, retval, len); + } + JSStringRelease(string); + + return retval; +} + +double util_js_result_as_number(WebKitJavascriptResult *result) +{ + JSValueRef value = webkit_javascript_result_get_value(result); + + return JSValueToNumber(webkit_javascript_result_get_global_context(result), value, + NULL); +} + /** * Reads given input and try to parse ~/, ~user, $VAR or ${VAR} expansion * from the start of the input and moves the input pointer to the first diff --git a/src/util.h b/src/util.h index ca9ba68..a9fd042 100644 --- a/src/util.h +++ b/src/util.h @@ -43,6 +43,8 @@ GList *util_file_to_unique_list(const char *filename, Util_Content_Func func, guint max_items); gboolean util_fill_completion(GtkListStore *store, const char *input, GList *src); gboolean util_filename_fill_completion(Client *c, GtkListStore *store, const char *input); +char *util_js_result_as_string(WebKitJavascriptResult *result); +double util_js_result_as_number(WebKitJavascriptResult *result); gboolean util_parse_expansion(Client *c, const char **input, GString *str, int flags, const char *quoteable); char *util_str_replace(const char* search, const char* replace, const char* string); diff --git a/src/webextension/ext-main.c b/src/webextension/ext-main.c index ae1fe72..97e4261 100644 --- a/src/webextension/ext-main.c +++ b/src/webextension/ext-main.c @@ -36,13 +36,13 @@ static void add_onload_event_observers(WebKitDOMDocument *doc, static void emit_page_created(GDBusConnection *connection, guint64 pageid); static void emit_page_created_pending(GDBusConnection *connection); static void queue_page_created_signal(guint64 pageid); +#if 0 static void dbus_emit_signal(const char *name, WebKitWebExtension* extension, GVariant *data); +#endif static void dbus_handle_method_call(GDBusConnection *conn, const char *sender, const char *object_path, const char *interface_name, const char *method, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer data); -static void on_editable_change_focus(WebKitDOMEventTarget *target, - WebKitDOMEvent *event, WebKitWebExtension *extension); static void on_page_created(WebKitWebExtension *ext, WebKitWebPage *webpage, gpointer data); static void on_web_page_document_loaded(WebKitWebPage *webpage, gpointer extension); static gboolean on_web_page_send_request(WebKitWebPage *webpage, WebKitURIRequest *request, @@ -57,9 +57,6 @@ static const GDBusInterfaceVTable interface_vtable = { static const char introspection_xml[] = "" " " - " " - " " - " " " " " " " " @@ -180,6 +177,7 @@ static void on_dbus_connection_created(GObject *source_object, static void add_onload_event_observers(WebKitDOMDocument *doc, WebKitWebExtension *extension) { +#if 0 /* might soon be use for some events */ WebKitDOMEventTarget *target; /* Add the document to the table of known documents or if already exists @@ -192,15 +190,7 @@ static void add_onload_event_observers(WebKitDOMDocument *doc, * function is called with content document of an iframe. Else the event * observing does not work. */ target = WEBKIT_DOM_EVENT_TARGET(webkit_dom_document_get_default_view(doc)); - - webkit_dom_event_target_add_event_listener(target, "focus", - G_CALLBACK(on_editable_change_focus), TRUE, extension); - webkit_dom_event_target_add_event_listener(target, "blur", - G_CALLBACK(on_editable_change_focus), TRUE, extension); - /* Check for focused editable elements also if they where focused before - * the event observer where set up. */ - /* TODO this is not needed for strict-focus=on */ - on_editable_change_focus(target, NULL, extension); +#endif } /** @@ -255,6 +245,7 @@ static void queue_page_created_signal(guint64 pageid) ext.page_created_signals = g_array_append_val(ext.page_created_signals, pageid); } +#if 0 /** * Emits a signal over dbus. * @@ -279,6 +270,7 @@ static void dbus_emit_signal(const char *name, WebKitWebExtension* extension, g_error_free(error); } } +#endif /** * Handle dbus method calls. @@ -304,52 +296,6 @@ static void dbus_handle_method_call(GDBusConnection *conn, const char *sender, } } -/** - * Callback called if a editable element changes it focus state. - * Event target may be a WebKitDOMDocument (in case of iframe) or a - * WebKitDOMDOMWindow. - */ -static void on_editable_change_focus(WebKitDOMEventTarget *target, - WebKitDOMEvent *event, WebKitWebExtension *extension) -{ - gboolean input_focus; - WebKitDOMDocument *doc; - WebKitDOMElement *active; - - if (WEBKIT_DOM_IS_DOM_WINDOW(target)) { - g_object_get(target, "document", &doc, NULL); - } else { - /* target is a doc document */ - doc = WEBKIT_DOM_DOCUMENT(target); - } - active = webkit_dom_document_get_active_element(doc); - /* Don't do anything if there is no active element or the active element - * is the same as before. */ - if (!active || active == ext.active) { - return; - } - if (WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT(active)) { - WebKitDOMHTMLIFrameElement *iframe; - WebKitDOMDocument *subdoc; - - iframe = WEBKIT_DOM_HTML_IFRAME_ELEMENT(active); - subdoc = webkit_dom_html_iframe_element_get_content_document(iframe); - add_onload_event_observers(subdoc, extension); - return; - } - - ext.active = active; - - /* Check if the active element is an editable element. */ - input_focus = ext_dom_is_editable(active); - if (input_focus != ext.input_focus) { - ext.input_focus = input_focus; - - dbus_emit_signal("EditableChangeFocus", extension, - g_variant_new("(b)", input_focus)); - } -} - /** * Callback for web extensions page-created signal. */