Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c')
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c241
1 files changed, 223 insertions, 18 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c
index 2dbc28c16c..fd958309a8 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c
@@ -13,7 +13,6 @@ gint32 parentUniqueId = 0;
guchar SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY = 101;
guchar SWT_DBUS_MAGIC_NUMBER_NULL = 48;
-
// +-------------+----------------------------------------------------------------
// | Misc Helpers|
// +-------------+
@@ -35,6 +34,13 @@ static const gchar base_service_name[] = "org.eclipse.swt"; // Base name. Full n
static const gchar object_name[] = "/org/eclipse/swt/gdbus";
static const gchar interface[] = "org.eclipse.swt.gdbusInterface";
+typedef struct {
+ guint64 page_id;
+ const gchar *function;
+ const gchar *url;
+} BrowserFunction;
+
+GSList *function_list = NULL;
GDBusProxy *proxy = NULL; // The proxy that we work with
void proxy_init () {
@@ -72,10 +78,12 @@ GVariant * callMainProc(char * methodName, GVariant * params) {
// Error checking.
if (result == NULL) {
- if (error != NULL)
- g_error("SWT Webextension: Call failed because '%s.' Probably didn't handle type properly, could be an SWT bug. Signature: %s\n", error->message, g_variant_get_type_string(params));
- else
- g_error("SWT Webextension: Call failed for an unknown reason.\n");
+ if (error != NULL) {
+ g_error("SWT web extension: Call failed because '%s.'\n", error->message);
+ }
+ else {
+ g_error("SWT web extension: Call failed for an unknown reason.\n");
+ }
return NULL;
}
@@ -289,17 +297,124 @@ static JSValueRef webkit2callJava (JSContextRef context,
return retVal;
}
+static void web_page_created_callback(WebKitWebExtension *extension, WebKitWebPage *web_page, gpointer user_data) {
+ // Observation. This seems to be called only once.
+}
+
+/**
+ * Returns the main frame of the WebPage with the given ID
+ */
+static WebKitFrame *webkitgtk_extension_get_main_frame (const guint64 id) {
+ WebKitWebPage *web_page = webkit_web_extension_get_page (this_extension, id);
+ return webkit_web_page_get_main_frame (web_page);
+}
+
+/*
+ * Execute the Javascript for the given page and URL.
+ */
+static gboolean webkitgtk_extension_execute_script (const guint64 page_id, const gchar* script, const gchar* url) {
+ WebKitFrame *main_frame = webkitgtk_extension_get_main_frame (page_id);
+
+ JSStringRef url_string = JSStringCreateWithUTF8CString (url);
+ JSStringRef script_string = JSStringCreateWithUTF8CString (script);
+
+ JSGlobalContextRef context = webkit_frame_get_javascript_global_context (main_frame);
+
+ JSValueRef exception;
+ JSValueRef result = JSEvaluateScript(context, script_string, NULL, url_string, 0, &exception);
+ if (!result) {
+ JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL);
+ size_t exceptionUTF8Size = JSStringGetMaximumUTF8CStringSize(exceptionIString);
+ char* exceptionUTF8 = (char*)malloc(exceptionUTF8Size);
+ JSStringGetUTF8CString(exceptionIString, exceptionUTF8, exceptionUTF8Size);
+ g_error("SWT web extension: failed to execute script exception: %s\n", exceptionUTF8);
+ free(exceptionUTF8);
+ JSStringRelease(exceptionIString);
+ }
+
+ JSStringRelease (url_string);
+ JSStringRelease (script_string);
+
+ return result != NULL;
+}
+
+void execute_browser_functions(gconstpointer item, gpointer page) {
+ BrowserFunction *function = (BrowserFunction *) item;
+ if (function != NULL && function->page_id == GPOINTER_TO_UINT(page)) {
+ webkitgtk_extension_execute_script(function->page_id, function->function, function->url);
+ }
+ return;
+}
+
+gint find_browser_function (gconstpointer item, gconstpointer target) {
+ BrowserFunction *element = (BrowserFunction *) item;
+ BrowserFunction *remove = (BrowserFunction *) target;
+ if (element->page_id == remove->page_id && g_strcmp0(element->function, remove->function) == 0 &&
+ g_strcmp0(element->url, remove->url) == 0) {
+ return 0;
+ }
+ return 1;
+}
+
+void add_browser_function(guint64 page_id, const gchar *function, const gchar *url) {
+ BrowserFunction *func = g_slice_new0(BrowserFunction);
+ func->page_id = page_id;
+ func->function = function;
+ func->url = url;
+ function_list = g_slist_append(function_list, func);
+}
+
+void remove_browser_function(guint64 page_id, const gchar *function, const gchar *url) {
+ BrowserFunction *func = g_slice_new0(BrowserFunction);
+ func->page_id = page_id;
+ func->function = function;
+ func->url = url;
+ GSList *to_remove = g_slist_find_custom(function_list, func, find_browser_function);
+ if (to_remove != NULL) {
+ function_list = g_slist_delete_link(function_list, to_remove);
+ }
+ g_slice_free(BrowserFunction, func);
+}
+
+void unpack_browser_function_array(GVariant *array) {
+ GVariantIter iter;
+ GVariant *child;
+
+ g_variant_iter_init (&iter, array);
+ while ((child = g_variant_iter_next_value (&iter))) {
+ gsize length = (int)g_variant_n_children (child);
+ if (length > 3) {
+ // If the length is longer than three, something went wrong and this tuple should be skipped
+ g_warning("SWT web extension: there was an error unpacking the GVariant tuple for a BrowserFunction in the web extension.\n");
+ continue;
+ }
+ guint64 page = g_variant_get_uint64(g_variant_get_child_value(child, 0));
+ if (page == -1) {
+ // Empty or malformed BrowserFunction, skip this one
+ continue;
+ } else {
+ const gchar *function = g_variant_get_string(g_variant_get_child_value(child, 1), NULL);
+ const gchar *url = g_variant_get_string(g_variant_get_child_value(child, 2), NULL);
+ if (function != NULL && url != NULL) {
+ add_browser_function(page, function, url);
+ } else {
+ g_warning("SWT web extension: there was an error unpacking the function string or URL.\n");
+ }
+ }
+ g_variant_unref (child);
+ }
+}
/*
- * Everytime a webpage is loaded, we should re-register the 'webkit2callJava' function.
+ * Every time a webpage is loaded, we should re-register the 'webkit2callJava' function.
+ * Additionally, we re-register all BrowserFunctions that are stored in the function_list
+ * GSList.
*/
-static void window_object_cleared_callback (WebKitScriptWorld *world,
- WebKitWebPage *web_page,
+static void window_object_cleared_callback (WebKitScriptWorld *world, WebKitWebPage *web_page,
WebKitFrame *frame,
- gpointer user_data)
-{
- // Observation: This is called everytime a webpage is loaded.
- JSGlobalContextRef jsContext;
+ gpointer user_data) {
+ // Observation: This is called every time a webpage is loaded.
+ JSGlobalContextRef jsContext;
JSObjectRef globalObject;
JSValueRef exception = 0;
@@ -314,23 +429,113 @@ static void window_object_cleared_callback (WebKitScriptWorld *world,
if (exception) {
g_print("OJSObjectSetProperty exception occurred");
}
+
+ /*
+ * Iterate over the list of BrowserFunctions and execute each one of them for the current page.
+ * This ensures that BrowserFunctions are not lost on page reloads. See bug 536141.
+ */
+ if (function_list != NULL) {
+ guint64 page_id = webkit_web_page_get_id (web_page);
+ if (page_id != -1) {
+ g_slist_foreach(function_list, (GFunc)execute_browser_functions, GUINT_TO_POINTER(page_id));
+ } else {
+ g_warning("SWT web extension: there was an error fetching the page ID in the object_cleared callback.\n");
+ }
+ }
}
-static void web_page_created_callback(WebKitWebExtension *extension, WebKitWebPage *web_page, gpointer user_data) {
- // Observation. This seems to be called only once.
+static void
+webkitgtk_extension_handle_method_call (GDBusConnection *connection, const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data) {
+ gboolean result = FALSE;
+ const gchar *script;
+ const gchar *url;
+ guint64 page_id;
+ // Check method names
+ if (g_strcmp0(method_name, "webkitgtk_extension_register_function") == 0) {
+ g_variant_get(parameters, "(t&s&s)", &page_id, &script, &url);
+ if (page_id != -1) {
+ result = TRUE;
+ // Return before processing the linked list, to prevent DBus from hanging
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", result));
+ add_browser_function(page_id, script, url);
+ return;
+ }
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", result));
+ return;
+ }
+ if (g_strcmp0(method_name, "webkitgtk_extension_deregister_function") == 0) {
+ g_variant_get(parameters, "(t&s&s)", &page_id, &script, &url);
+ if (page_id != -1) {
+ result = TRUE;
+ // Return before processing the linked list, to prevent DBus from hanging
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", result));
+ remove_browser_function(page_id, script, url);
+ return;
+ }
+ g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", result));
+ return;
+ }
+ g_error ("UNKNOWN method %s\n", method_name);
}
-G_MODULE_EXPORT void
-webkit_web_extension_initialize_with_user_data(WebKitWebExtension *extension, GVariant *user_data)
-{
+static const GDBusInterfaceVTable interface_vtable = {webkitgtk_extension_handle_method_call, NULL, NULL};
+
+static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) {
+ dbus_interface = g_dbus_node_info_lookup_interface(dbus_node, WEBKITGTK_EXTENSION_DBUS_INTERFACE);
+ guint registration_id = g_dbus_connection_register_object(connection,
+ webkitgtk_extension_dbus_path,
+ dbus_interface,
+ &interface_vtable, NULL, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert(registration_id > 0);
+
+ GVariant *g_var_result = callMainProc("webkitWebExtensionIdentifer", g_variant_new ("(ss)",
+ webkitgtk_extension_dbus_name, webkitgtk_extension_dbus_path));
+ if (g_variant_is_of_type(g_var_result, G_VARIANT_TYPE_TUPLE)) {
+ unpack_browser_function_array(g_variant_get_child_value(g_var_result, 0));
+ } else {
+ g_warning("SWT web extension: on_bus_acquired return value from SWT was an unexpected type (not a tuple).\n");
+ }
+ return;
+}
+
+G_MODULE_EXPORT void webkit_web_extension_initialize_with_user_data(WebKitWebExtension *extension, GVariant *user_data) {
// To debug this extension:
// - ensure this is build with debug flags (look for '-g*' in make_linux, or 'SWT_LIB_DEBUG' macro.
// - connect to WebKitWebProcess with pid of this extension. Use below to print it:
- // g_print("Webext pid: %d (To debug, attach to WebKitWebProcess with this pid)\n", getpid());
+ // g_print("Webext pid: %d (To debug, attach to WebKitWebProcess with this pid)\n", getpid());
+ this_extension = extension;
parentUniqueId = g_variant_get_int32(user_data);
g_signal_connect(extension, "page-created", G_CALLBACK(web_page_created_callback), NULL);
// To hook into javascript execution:
g_signal_connect (webkit_script_world_get_default (), "window-object-cleared", G_CALLBACK (window_object_cleared_callback), NULL);
+
+ // Create DBus server for this web extension
+ webkitgtk_extension_dbus_name = combineStrInt((char *) WEBKITGTK_EXTENSION_DBUS_NAME_PREFIX, (gint32) getpid());
+ webkitgtk_extension_dbus_path = combineStrInt((char *) WEBKITGTK_EXTENSION_DBUS_PATH_PREFIX, (gint32) getpid());
+
+ dbus_introspection_xml = g_new (gchar, strlen(dbus_introspection_xml_template) + strlen(WEBKITGTK_EXTENSION_DBUS_INTERFACE) + 1);
+ g_sprintf (dbus_introspection_xml, dbus_introspection_xml_template, WEBKITGTK_EXTENSION_DBUS_INTERFACE);
+ dbus_node = g_dbus_node_info_new_for_xml (dbus_introspection_xml, NULL);
+ g_assert (dbus_node != NULL);
+
+ guint owner_id;
+ owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ webkitgtk_extension_dbus_name,
+ G_BUS_NAME_OWNER_FLAGS_REPLACE | G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+ on_bus_acquired,
+ NULL, /* on_name_acquired */
+ NULL, /* on_name_lost */
+ NULL,
+ NULL);
+ g_assert (owner_id != 0);
}

Back to the top