Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Williams2018-07-12 16:14:54 -0400
committerEric Williams2018-08-14 10:51:19 -0400
commitf0fe56670826e5b46e2c9a52c132ec39f531e136 (patch)
treef6d509251f92ea8e583bd09986c1e0ec1ae88e17
parentdfb0cb3dbe3b038908c695231ad8a8f200ee1500 (diff)
downloadeclipse.platform.swt-f0fe56670826e5b46e2c9a52c132ec39f531e136.tar.gz
eclipse.platform.swt-f0fe56670826e5b46e2c9a52c132ec39f531e136.tar.xz
eclipse.platform.swt-f0fe56670826e5b46e2c9a52c132ec39f531e136.zip
Bug 536141: [Webkit2][Gtk] BrowserFunction lost after page reload on
Linux/GTK The main cause of this bug is that web pages load too quickly -- by the time the BrowserFunctions are re-registered asynchronously from Java, the extension has loaded the page. BEFORE THIS PATCH: BrowserFunctions were registered asynchronously from Java into the web extension (C). This was done either at the outset (WebBrowser.createFunction()), or after every page load (Webkit.webkit_load_changed() callback). AFTER THIS PATCH: The fix is relatively straightforward, yet GDBus adds a lot of overhead. Instead of constantly registering BrowserFunctions from Java, we load them into the web extension on creation. This hands off the responsibility of re-registering BrowserFunctions to the web extension, which reduces overhead and ensures the functions are registered/executed before the page loads. The BrowserFunctions are stored at the C level in the extension, using a linked list. Whenever the "object-cleared" callback is triggered in the extension, the linked list is iterated over and any BrowserFunctions for that page are re-registered. Chronological ordering of information flow from SWT -> web extension via GDBus. 1) SWT Webkit class is loaded. SWT GDBus server is created. 2) SWT Webkit creates the extension, passing it the information of the SWT Webkit GDBus server. 3) The extension's initialization callback is called in C. 4) In this callback the extension contacts the SWT Webkit GDBus server and provides it with information such as its PID and name. 5) SWT Webkit acknowledges this information, and sends back any BrowserFunctions that were created before the extension loaded. 6) The extension adds these BrowserFunctions to its linked list. 7) Any subsequent BrowserFunctions are added to the extension's linked list by calling the extension's GDBus server synchronously. In the event of a GDBus timeout (happens sometimes when running tests), the GDBus call is made asynchronously. This functionality can be tested with the attached snippet. AllBrowserTests pass without issue, and there are no visible Browser issues in the IDE. The plugin attached to the initial bug report is now functional. Change-Id: Iddc5f2e69f0a7fd4500bd8228f0bc46c4b3a6322 Signed-off-by: Eric Williams <ericwill@redhat.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c169
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c11
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h11
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java192
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c20
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c241
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h59
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java97
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java261
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java11
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug536141_BrowserFunctionLostReload.java158
14 files changed, 1174 insertions, 59 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
index 08e24009d6..596c69a177 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -16235,6 +16235,91 @@ fail:
}
#endif
+#ifndef NO__1g_1dbus_1proxy_1call
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call)
+ (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1, jintLong arg2, jint arg3, jint arg4, jintLong arg5, jintLong arg6, jintLongArray arg7)
+{
+ jbyte *lparg1=NULL;
+ jintLong *lparg7=NULL;
+ OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1call_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg7) if ((lparg7 = (*env)->GetIntLongArrayElements(env, arg7, NULL)) == NULL) goto fail;
+/*
+ g_dbus_proxy_call((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, arg6, (GError **)lparg7);
+*/
+ {
+ OS_LOAD_FUNCTION(fp, g_dbus_proxy_call)
+ if (fp) {
+ ((void (CALLING_CONVENTION*)(GDBusProxy *, const gchar *, GVariant *, jint, jint, GCancellable *, jintLong, GError **))fp)((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, arg6, (GError **)lparg7);
+ }
+ }
+fail:
+ if (arg7 && lparg7) (*env)->ReleaseIntLongArrayElements(env, arg7, lparg7, 0);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1call_FUNC);
+}
+#endif
+
+#ifndef NO__1g_1dbus_1proxy_1call_1finish
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call_1finish)
+ (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1, jintLongArray arg2)
+{
+ jintLong *lparg2=NULL;
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1call_1finish_FUNC);
+ if (arg2) if ((lparg2 = (*env)->GetIntLongArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ rc = (jintLong)g_dbus_proxy_call_finish((GDBusProxy *)arg0, (GAsyncResult *)arg1, (GError **)lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseIntLongArrayElements(env, arg2, lparg2, 0);
+ OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1call_1finish_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1g_1dbus_1proxy_1call_1sync
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call_1sync)
+ (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1, jintLong arg2, jint arg3, jint arg4, jintLong arg5, jintLongArray arg6)
+{
+ jbyte *lparg1=NULL;
+ jintLong *lparg6=NULL;
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1call_1sync_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg6) if ((lparg6 = (*env)->GetIntLongArrayElements(env, arg6, NULL)) == NULL) goto fail;
+ rc = (jintLong)g_dbus_proxy_call_sync((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, (GError **)lparg6);
+fail:
+ if (arg6 && lparg6) (*env)->ReleaseIntLongArrayElements(env, arg6, lparg6, 0);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1call_1sync_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1g_1dbus_1proxy_1new_1for_1bus_1sync
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1new_1for_1bus_1sync)
+ (JNIEnv *env, jclass that, jint arg0, jint arg1, jintLong arg2, jbyteArray arg3, jbyteArray arg4, jbyteArray arg5, jintLong arg6, jintLongArray arg7)
+{
+ jbyte *lparg3=NULL;
+ jbyte *lparg4=NULL;
+ jbyte *lparg5=NULL;
+ jintLong *lparg7=NULL;
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1new_1for_1bus_1sync_FUNC);
+ if (arg3) if ((lparg3 = (*env)->GetByteArrayElements(env, arg3, NULL)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = (*env)->GetByteArrayElements(env, arg4, NULL)) == NULL) goto fail;
+ if (arg5) if ((lparg5 = (*env)->GetByteArrayElements(env, arg5, NULL)) == NULL) goto fail;
+ if (arg7) if ((lparg7 = (*env)->GetIntLongArrayElements(env, arg7, NULL)) == NULL) goto fail;
+ rc = (jintLong)g_dbus_proxy_new_for_bus_sync(arg0, arg1, (GDBusInterfaceInfo *)arg2, (const gchar *)lparg3, (const gchar *)lparg4, (const gchar *)lparg5, (GCancellable *)arg6, (GError **)lparg7);
+fail:
+ if (arg7 && lparg7) (*env)->ReleaseIntLongArrayElements(env, arg7, lparg7, 0);
+ if (arg5 && lparg5) (*env)->ReleaseByteArrayElements(env, arg5, lparg5, 0);
+ if (arg4 && lparg4) (*env)->ReleaseByteArrayElements(env, arg4, lparg4, 0);
+ if (arg3 && lparg3) (*env)->ReleaseByteArrayElements(env, arg3, lparg3, 0);
+ OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1new_1for_1bus_1sync_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1g_1error_1free
JNIEXPORT void JNICALL OS_NATIVE(_1g_1error_1free)
(JNIEnv *env, jclass that, jintLong arg0)
@@ -17970,6 +18055,50 @@ JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1value_1peek_1pointer)
}
#endif
+#ifndef NO__1g_1variant_1builder_1add_1value
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1variant_1builder_1add_1value)
+ (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
+{
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1builder_1add_1value_FUNC);
+ g_variant_builder_add_value((GVariantBuilder *)arg0, (GVariant *)arg1);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1builder_1add_1value_FUNC);
+}
+#endif
+
+#ifndef NO__1g_1variant_1builder_1end
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1variant_1builder_1end)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1builder_1end_FUNC);
+ rc = (jintLong)g_variant_builder_end((GVariantBuilder *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1builder_1end_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1g_1variant_1builder_1new
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1variant_1builder_1new)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1builder_1new_FUNC);
+ rc = (jintLong)g_variant_builder_new((const GVariantType *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1builder_1new_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1g_1variant_1builder_1unref
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1variant_1builder_1unref)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1builder_1unref_FUNC);
+ g_variant_builder_unref((GVariantBuilder *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1builder_1unref_FUNC);
+}
+#endif
+
#ifndef NO__1g_1variant_1get_1boolean
JNIEXPORT jboolean JNICALL OS_NATIVE(_1g_1variant_1get_1boolean)
(JNIEnv *env, jclass that, jintLong arg0)
@@ -18070,6 +18199,18 @@ JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1variant_1get_1type_1string)
}
#endif
+#ifndef NO__1g_1variant_1get_1uint64
+JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1get_1uint64)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1get_1uint64_FUNC);
+ rc = (jlong)g_variant_get_uint64((GVariant *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1get_1uint64_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1g_1variant_1is_1of_1type
JNIEXPORT jboolean JNICALL OS_NATIVE(_1g_1variant_1is_1of_1type)
(JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1)
@@ -18178,6 +18319,34 @@ fail:
}
#endif
+#ifndef NO__1g_1variant_1new_1uint64
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1variant_1new_1uint64)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1new_1uint64_FUNC);
+ rc = (jintLong)g_variant_new_uint64(arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1new_1uint64_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO__1g_1variant_1type_1new
+JNIEXPORT jintLong JNICALL OS_NATIVE(_1g_1variant_1type_1new)
+ (JNIEnv *env, jclass that, jbyteArray arg0)
+{
+ jbyte *lparg0=NULL;
+ jintLong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1type_1new_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ rc = (jintLong)g_variant_type_new((const gchar *)lparg0);
+fail:
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1type_1new_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1getpid
JNIEXPORT jint JNICALL OS_NATIVE(_1getpid)
(JNIEnv *env, jclass that)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h
index bcce6b32a0..9ccc85811c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_custom.h
@@ -67,6 +67,7 @@
#define g_thread_init_LIB LIB_GTHREAD
#define ubuntu_menu_proxy_get_LIB LIB_GTK
#define FcConfigAppFontAddFile_LIB LIB_FONTCONFIG
+#define g_dbus_proxy_call_LIB LIB_GLIB
// GTK3 only
#define g_bytes_new_LIB LIB_GLIB
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
index d5e53977d1..6491dd15eb 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
@@ -1333,6 +1333,10 @@ char * OS_nativeFunctionNames[] = {
"_1g_1dbus_1method_1invocation_1return_1value",
"_1g_1dbus_1node_1info_1lookup_1interface",
"_1g_1dbus_1node_1info_1new_1for_1xml",
+ "_1g_1dbus_1proxy_1call",
+ "_1g_1dbus_1proxy_1call_1finish",
+ "_1g_1dbus_1proxy_1call_1sync",
+ "_1g_1dbus_1proxy_1new_1for_1bus_1sync",
"_1g_1error_1free",
"_1g_1error_1get_1message",
"_1g_1file_1get_1uri",
@@ -1513,6 +1517,10 @@ char * OS_nativeFunctionNames[] = {
"_1g_1utf8_1to_1utf16___3BJ_3J_3J_3J",
#endif
"_1g_1value_1peek_1pointer",
+ "_1g_1variant_1builder_1add_1value",
+ "_1g_1variant_1builder_1end",
+ "_1g_1variant_1builder_1new",
+ "_1g_1variant_1builder_1unref",
"_1g_1variant_1get_1boolean",
"_1g_1variant_1get_1byte",
"_1g_1variant_1get_1child_1value",
@@ -1521,6 +1529,7 @@ char * OS_nativeFunctionNames[] = {
"_1g_1variant_1get_1string",
"_1g_1variant_1get_1type",
"_1g_1variant_1get_1type_1string",
+ "_1g_1variant_1get_1uint64",
"_1g_1variant_1is_1of_1type",
"_1g_1variant_1n_1children",
"_1g_1variant_1new_1boolean",
@@ -1529,6 +1538,8 @@ char * OS_nativeFunctionNames[] = {
"_1g_1variant_1new_1int32",
"_1g_1variant_1new_1string",
"_1g_1variant_1new_1tuple",
+ "_1g_1variant_1new_1uint64",
+ "_1g_1variant_1type_1new",
"_1gdk_1keymap_1translate_1keyboard_1state",
"_1getpid",
"_1glib_1major_1version",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
index fd55aea6d2..70894d8d40 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
@@ -1319,6 +1319,10 @@ typedef enum {
_1g_1dbus_1method_1invocation_1return_1value_FUNC,
_1g_1dbus_1node_1info_1lookup_1interface_FUNC,
_1g_1dbus_1node_1info_1new_1for_1xml_FUNC,
+ _1g_1dbus_1proxy_1call_FUNC,
+ _1g_1dbus_1proxy_1call_1finish_FUNC,
+ _1g_1dbus_1proxy_1call_1sync_FUNC,
+ _1g_1dbus_1proxy_1new_1for_1bus_1sync_FUNC,
_1g_1error_1free_FUNC,
_1g_1error_1get_1message_FUNC,
_1g_1file_1get_1uri_FUNC,
@@ -1499,6 +1503,10 @@ typedef enum {
_1g_1utf8_1to_1utf16___3BJ_3J_3J_3J_FUNC,
#endif
_1g_1value_1peek_1pointer_FUNC,
+ _1g_1variant_1builder_1add_1value_FUNC,
+ _1g_1variant_1builder_1end_FUNC,
+ _1g_1variant_1builder_1new_FUNC,
+ _1g_1variant_1builder_1unref_FUNC,
_1g_1variant_1get_1boolean_FUNC,
_1g_1variant_1get_1byte_FUNC,
_1g_1variant_1get_1child_1value_FUNC,
@@ -1507,6 +1515,7 @@ typedef enum {
_1g_1variant_1get_1string_FUNC,
_1g_1variant_1get_1type_FUNC,
_1g_1variant_1get_1type_1string_FUNC,
+ _1g_1variant_1get_1uint64_FUNC,
_1g_1variant_1is_1of_1type_FUNC,
_1g_1variant_1n_1children_FUNC,
_1g_1variant_1new_1boolean_FUNC,
@@ -1515,6 +1524,8 @@ typedef enum {
_1g_1variant_1new_1int32_FUNC,
_1g_1variant_1new_1string_FUNC,
_1g_1variant_1new_1tuple_FUNC,
+ _1g_1variant_1new_1uint64_FUNC,
+ _1g_1variant_1type_1new_FUNC,
_1gdk_1keymap_1translate_1keyboard_1state_FUNC,
_1getpid_FUNC,
_1glib_1major_1version_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index a894399983..221e1a6c1f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -204,6 +204,16 @@ public class OS extends C {
* @category gdbus */
public static final int G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1);
+ // Proxy flags found here: https://developer.gnome.org/gio/stable/GDBusProxy.html#GDBusProxyFlags
+ public static final int G_DBUS_PROXY_FLAGS_NONE = 0;
+ public static final int G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = 1;
+ public static final int G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = 2;
+ public static final int G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = 3;
+ public static final int G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES = 4;
+ public static final int G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION = 5;
+
+ public static final int G_DBUS_CALL_FLAGS_NONE = 0;
+ public static final int G_DBUS_CALL_FLAGS_NO_AUTO_START = (1<<0);
/**
* DBus Data types as defined by:
@@ -220,8 +230,12 @@ public class OS extends C {
/** @category gdbus */
public static final String DBUS_TYPE_STRING_ARRAY = "as";
/** @category gdbus */
+ public static final String DBUS_TYPE_STRUCT_ARRAY_BROWSER_FUNCS = "a(tss)";
+ /** @category gdbus */
public static final String DBUS_TYPE_INT32 = "i";
/** @category gdbus */
+ public static final String DBUS_TYPE_UINT64 = "t";
+ /** @category gdbus */
public static final String DBUS_TYPE_DOUBLE = "d";
/** @category gdbus */
public static final String DBUS_TYPE_STRUCT = "r"; // Not used by Dbus, but implemented by GDBus.
@@ -245,9 +259,13 @@ public class OS extends C {
/** @category gdbus */
public static final byte[] G_VARIANT_TYPE_IN32 = ascii(DBUS_TYPE_INT32);
/** @category gdbus */
+ public static final byte[] G_VARIANT_TYPE_UINT64 = ascii(DBUS_TYPE_UINT64);
+ /** @category gdbus */
public static final byte[] G_VARIANT_TYPE_DOUBLE = ascii(DBUS_TYPE_DOUBLE);
/** @category gdbus */
public static final byte[] G_VARIANT_TYPE_TUPLE = ascii(DBUS_TYPE_STRUCT);
+ /** @category gdbus */
+ public static final byte[] G_VARIANT_TYPE_ARRAY_BROWSER_FUNCS = ascii(DBUS_TYPE_STRUCT_ARRAY_BROWSER_FUNCS);
/** Signals */
@@ -4261,6 +4279,79 @@ public static final void setDarkThemePreferred(boolean preferred){
GTK.gtk_application_prefer_dark_theme);
}
+/**
+ * @param info cast=(GDBusInterfaceInfo *)
+ * @param name cast=(const gchar *)
+ * @param object_path cast=(const gchar *)
+ * @param interface_name cast=(const gchar *)
+ * @param cancellable cast=(GCancellable *)
+ * @param error cast=(GError **)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_dbus_proxy_new_for_bus_sync (int bus_type, int flags, long /*int*/ info, byte [] name, byte [] object_path, byte [] interface_name,
+ long /*int*/ cancellable, long /*int*/[] error);
+public static final long /*int*/ g_dbus_proxy_new_for_bus_sync (int bus_type, int flags, long /*int*/ info, byte [] name, byte [] object_path, byte [] interface_name,
+ long /*int*/ cancellable, long /*int*/[] error) {
+ lock.lock();
+ try {
+ return _g_dbus_proxy_new_for_bus_sync (bus_type, flags, info, name, object_path, interface_name, cancellable, error);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param proxy cast=(GDBusProxy *)
+ * @param method_name cast=(const gchar *)
+ * @param parameters cast=(GVariant *)
+ * @param cancellable cast=(GCancellable *)
+ * @param error cast=(GError **)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_dbus_proxy_call_sync (long /*int*/ proxy, byte[] method_name, long /*int*/ parameters, int flags, int timeout_msec, long /*int*/ cancellable, long /*int*/[] error);
+public static final long /*int*/ g_dbus_proxy_call_sync (long /*int*/ proxy, byte[] method_name, long /*int*/ parameters, int flags, int timeout_msec, long /*int*/ cancellable, long /*int*/[] error) {
+ lock.lock();
+ try {
+ return _g_dbus_proxy_call_sync (proxy, method_name, parameters, flags, timeout_msec, cancellable, error);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @method flags=dynamic
+ * @param proxy cast=(GDBusProxy *)
+ * @param method_name cast=(const gchar *)
+ * @param parameters cast=(GVariant *)
+ * @param cancellable cast=(GCancellable *)
+ * @param error cast=(GError **)
+ * @category gdbus
+ */
+public static final native void _g_dbus_proxy_call (long /*int*/ proxy, byte[] method_name, long /*int*/ parameters, int flags, int timeout_msec, long /*int*/ cancellable, long /*int*/ callback, long /*int*/[] error);
+public static final void g_dbus_proxy_call (long /*int*/ proxy, byte[] method_name, long /*int*/ parameters, int flags, int timeout_msec, long /*int*/ cancellable, long /*int*/ callback, long /*int*/[] error) {
+ lock.lock();
+ try {
+ _g_dbus_proxy_call (proxy, method_name, parameters, flags, timeout_msec, cancellable, callback, error);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param proxy cast=(GDBusProxy *)
+ * @param res cast=(GAsyncResult *)
+ * @param error cast=(GError **)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_dbus_proxy_call_finish (long /*int*/ proxy, long /*int*/ res, long /*int*/[] error);
+public static final long /*int*/ g_dbus_proxy_call_finish (long /*int*/ proxy, long /*int*/ res, long /*int*/[] error) {
+ lock.lock();
+ try {
+ return _g_dbus_proxy_call_finish (proxy, res, error);
+ } finally {
+ lock.unlock();
+ }
+}
/**
* @param xml_data cast=(const gchar *)
@@ -4354,6 +4445,82 @@ public static final void g_dbus_method_invocation_return_value (long /*int*/ inv
}
/**
+ * @param type cast=(const GVariantType *)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_variant_builder_new (long /*int*/ type);
+/** @category gdbus */
+public static final long /*int*/ g_variant_builder_new (long /*int*/ type) {
+ lock.lock();
+ try {
+ return _g_variant_builder_new(type);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param builder cast=(GVariantBuilder *)
+ * @param value cast=(GVariant *)
+ * @category gdbus
+ */
+public static final native void /*int*/ _g_variant_builder_add_value (long /*int*/ builder, long /*int*/ value);
+/** @category gdbus */
+public static final void /*int*/ g_variant_builder_add_value (long /*int*/ builder, long /*int*/ value) {
+ lock.lock();
+ try {
+ _g_variant_builder_add_value(builder, value);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param type cast=(const gchar *)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_variant_type_new (byte [] type);
+/** @category gdbus */
+public static final long /*int*/ g_variant_type_new (byte [] type) {
+ lock.lock();
+ try {
+ return _g_variant_type_new(type);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param builder cast=(GVariantBuilder *)
+ * @category gdbus
+ */
+public static final native long /*int*/ _g_variant_builder_end (long /*int*/ builder);
+/** @category gdbus */
+public static final long /*int*/ g_variant_builder_end (long /*int*/ builder) {
+ lock.lock();
+ try {
+ return _g_variant_builder_end(builder);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param builder cast=(GVariantBuilder *)
+ * @category gdbus
+ */
+public static final native void /*int*/ _g_variant_builder_unref (long /*int*/ builder);
+/** @category gdbus */
+public static final void /*int*/ g_variant_builder_unref (long /*int*/ builder) {
+ lock.lock();
+ try {
+ _g_variant_builder_unref(builder);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
* @param intval cast=(gint32)
* @category gdbus
*/
@@ -4447,6 +4614,31 @@ public static final double g_variant_get_double (long /*int*/ gvariant) {
}
}
+public static final native long /*int*/ _g_variant_new_uint64 (long value);
+public static final long /*int*/ g_variant_new_uint64 (long value) {
+ lock.lock();
+ try {
+ return _g_variant_new_uint64 (value);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param gvariant cast=(GVariant *)
+ * @category gdbus
+ */
+public static final native long _g_variant_get_uint64 (long /*int*/ gvariant);
+/** @category gdbus */
+public static final long g_variant_get_uint64 (long /*int*/ gvariant) {
+ lock.lock();
+ try {
+ return _g_variant_get_uint64 (gvariant);
+ } finally {
+ lock.unlock();
+ }
+}
+
/**
* @param gvariant cast=(GVariant *)
* @param length cast=(gsize *)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
index de6febe682..686437b6e5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk.c
@@ -2921,6 +2921,26 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1get_1main_1reso
}
#endif
+#ifndef NO__1webkit_1web_1view_1get_1page_1id
+JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1get_1page_1id)
+ (JNIEnv *env, jclass that, jintLong arg0)
+{
+ jintLong rc = 0;
+ WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1view_1get_1page_1id_FUNC);
+/*
+ rc = (jintLong)webkit_web_view_get_page_id(arg0);
+*/
+ {
+ WebKitGTK_LOAD_FUNCTION(fp, webkit_web_view_get_page_id)
+ if (fp) {
+ rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong))fp)(arg0);
+ }
+ }
+ WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1view_1get_1page_1id_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1webkit_1web_1view_1get_1progress
JNIEXPORT jdouble JNICALL WebKitGTK_NATIVE(_1webkit_1web_1view_1get_1progress)
(JNIEnv *env, jclass that, jintLong arg0)
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);
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h
index 72a507ba81..4d2713cd76 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h
@@ -1,4 +1,4 @@
-/*******************************************************************************
+ /*******************************************************************************
* Copyright (c) 2017 Red Hat and others. All rights reserved.
* The contents of this file are made available under the terms
* of the GNU Lesser General Public License (LGPL) Version 2.1 that
@@ -12,12 +12,9 @@
* Contributors:
* Red Hat - initial API and implementation
*******************************************************************************/
-
-
#ifndef INC_webkit_extension_H
#define INC_webkit_extension_H
-
#include <string.h>
#include <glib.h>
@@ -29,12 +26,10 @@
#include <unistd.h>
#include <stdio.h>
-
// These 2 are only for getpid();
#include <sys/types.h>
#include <unistd.h>
-
#include <webkit2/webkit-web-extension.h>
#include <JavaScriptCore/JavaScript.h>
@@ -42,22 +37,40 @@
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#define WEBKITGTK_EXTENSION_DBUS_NAME_PREFIX "org.eclipse.swt.webkitgtk_extension"
+#define WEBKITGTK_EXTENSION_DBUS_PATH_PREFIX "/org/eclipse/swt/webkitgtk_extension/gdbus/"
+#define WEBKITGTK_EXTENSION_DBUS_INTERFACE "org.eclipse.swt.webkitgtk_extension.gdbusInterface"
+
+#define WEBKIT_MAIN_PROCESS_DBUS_NAME_PREFIX "org.eclipse.swt"
+#define WEBKIT_MAIN_PROCESS_DBUS_PATH_PREFIX "/org/eclipse/swt/gdbus/"
+
+static gchar* webkitgtk_extension_dbus_name;
+static gchar* webkitgtk_extension_dbus_path;
+
+static WebKitWebExtension *this_extension;
+
+static GDBusNodeInfo *dbus_node;
+static GDBusInterfaceInfo *dbus_interface;
+static gchar* dbus_introspection_xml;
+static gchar* dbus_introspection_xml_template =
+"<node>"
+ "<interface name='%s'>"
+
+ "<method name='webkitgtk_extension_register_function'>"
+ "<arg type='t' name='page_id' direction='in'/>"
+ "<arg type='s' name='script' direction='in'/>"
+ "<arg type='s' name='url' direction='in'/>"
+ "<arg type='b' name='result' direction='out'/>"
+ "</method>"
+
+ "<method name='webkitgtk_extension_deregister_function'>"
+ "<arg type='t' name='page_id' direction='in'/>"
+ "<arg type='s' name='script' direction='in'/>"
+ "<arg type='s' name='url' direction='in'/>"
+ "<arg type='b' name='result' direction='out'/>"
+ "</method>"
+
+ "</interface>"
+"</node>";
#endif /*INC_webkit_extension_H*/
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
index 32ad50e13e..84ee7e587d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.c
@@ -167,6 +167,7 @@ char * WebKitGTK_nativeFunctionNames[] = {
"_1webkit_1web_1view_1get_1load_1status",
"_1webkit_1web_1view_1get_1main_1frame",
"_1webkit_1web_1view_1get_1main_1resource",
+ "_1webkit_1web_1view_1get_1page_1id",
"_1webkit_1web_1view_1get_1progress",
"_1webkit_1web_1view_1get_1settings",
"_1webkit_1web_1view_1get_1title",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
index dab44c08fe..22196ffafa 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_stats.h
@@ -177,6 +177,7 @@ typedef enum {
_1webkit_1web_1view_1get_1load_1status_FUNC,
_1webkit_1web_1view_1get_1main_1frame_FUNC,
_1webkit_1web_1view_1get_1main_1resource_FUNC,
+ _1webkit_1web_1view_1get_1page_1id_FUNC,
_1webkit_1web_1view_1get_1progress_FUNC,
_1webkit_1web_1view_1get_1settings_FUNC,
_1webkit_1web_1view_1get_1title_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
index 81b218af3c..470ae9959f 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebKit.java
@@ -127,6 +127,7 @@ class WebKit extends WebBrowser {
*/
long /*int*/ webView;
long /*int*/ scrolledWindow;
+ long pageId;
/** Webkit1 only. Used by the externalObject for javascript callback to java. */
long /*int*/ webViewData;
@@ -419,12 +420,52 @@ class WebKit extends WebBrowser {
@Override
public void createFunction(BrowserFunction function) {
if (WEBKIT2) {
- if (!Webkit2Extension.gdbus_init()) {
- System.err.println("SWT Webkit Warning: Webkit extension failed to initialize. BrowserFunction will not work.: " + function.name);
+ if (!WebkitGDBus.initialized) {
+ System.err.println("SWT webkit: WebkitGDBus and/or Webkit2Extension not loaded, BrowserFunction will not work." +
+ "Tried to create "+ function.name);
return;
}
}
super.createFunction(function);
+ if (WEBKIT2) {
+ String url = this.getUrl().isEmpty() ? "nullURL" : this.getUrl();
+ /*
+ * If the proxy to the extension has not yet been loaded, store the BrowserFunction page ID,
+ * function string, and URL in a HashMap. Once the proxy to the extension is loaded, these
+ * functions will be sent to and registered in the extension.
+ */
+ if (!WebkitGDBus.proxyToExtension) {
+ WebkitGDBus.functionsPending = true;
+ ArrayList<ArrayList<String>> list = new ArrayList<>();
+ ArrayList<String> functionAndUrl = new ArrayList<>();
+ functionAndUrl.add(0, function.functionString);
+ functionAndUrl.add(1, url);
+ list.add(functionAndUrl);
+ ArrayList<ArrayList<String>> existing = WebkitGDBus.pendingBrowserFunctions.putIfAbsent(this.pageId, list);
+ if (existing != null) {
+ existing.add(functionAndUrl);
+ }
+ } else {
+ // If the proxy to the extension is already loaded, register the function in the extension via DBus
+ boolean successful = webkit_extension_modify_function(this.pageId, function.functionString, url, "register");
+ if (!successful) {
+ System.err.println("SWT webkit: failure registering BrowserFunction " + function.name);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void destroyFunction (BrowserFunction function) {
+ // Only deregister functions if the proxy to the extension has been loaded
+ if (WebkitGDBus.proxyToExtension && WEBKIT2) {
+ String url = this.getUrl().isEmpty() ? "nullURL" : this.getUrl();
+ boolean successful = webkit_extension_modify_function(this.pageId, function.functionString, url, "deregister");
+ if (!successful) {
+ System.err.println("SWT webkit: failure deregistering BrowserFunction from extension " + function.name);
+ }
+ }
+ super.destroyFunction(function);
}
private static String getInternalErrorMsg () {
@@ -458,6 +499,7 @@ class WebKit extends WebBrowser {
static class Webkit2Extension {
/** Note, if updating this, you need to change it also in webkitgtk_extension.c */
private static final String javaScriptFunctionName = "webkit2callJava"; // $NON-NLS-1$
+ private static final String webkitWebExtensionIdentifier = "webkitWebExtensionIdentifer"; // $NON-NLS-1$
private static Callback initializeWebExtensions_callback;
private static int uniqueID = OS.getpid();
@@ -470,6 +512,9 @@ class WebKit extends WebBrowser {
static String getJavaScriptFunctionName() {
return javaScriptFunctionName;
}
+ static String getWebExtensionIdentifer() {
+ return webkitWebExtensionIdentifier;
+ }
static String getJavaScriptFunctionDeclaration(long /*int*/ webView) {
return "if (!window.callJava) {\n"
+ " window.callJava = function callJava(index, token, args) {\n"
@@ -479,6 +524,12 @@ class WebKit extends WebBrowser {
}
static void init() {
+ /*
+ * Initialize GDBus before the extension, as the extension initialization callback at the C level
+ * sends data back to SWT via GDBus. Failure to load GDBus here will result in crashes.
+ * See bug 536141.
+ */
+ gdbus_init();
initializeWebExtensions_callback = new Callback(Webkit2Extension.class, "initializeWebExtensions_callback", void.class, new Type [] {long.class, long.class});
if (initializeWebExtensions_callback.getAddress() == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
if (WebKitGTK.webkit_get_minor_version() >= 4) { // Callback exists only since 2.04
@@ -1199,6 +1250,7 @@ public void create (Composite parent, int style) {
OS.g_signal_connect (webView, OS.focus_out_event, JSDOMEventProc.getAddress (), WIDGET_EVENT);
// if connecting any other special gtk event to webkit, add SWT.* to w2_passThroughSwtEvents above.
}
+ this.pageId = WebKitGTK.webkit_web_view_get_page_id (webView);
if (WEBKIT1) {
OS.g_signal_connect (webView, OS.button_press_event, JSDOMEventProc.getAddress (), 0);
OS.g_signal_connect (webView, OS.button_release_event, JSDOMEventProc.getAddress (), 0);
@@ -1522,6 +1574,46 @@ void nonBlockingExecute(String script) {
}
}
+/**
+ * Modifies a BrowserFunction in the web extension. This method can be used to register/deregister BrowserFunctions
+ * in the web extension, so that those BrowserFunctions are executed upon triggering of the object_cleared callback (in
+ * the extension, not in Java).
+ *
+ * This function will return true if: the operation succeeds synchronously, or if the synchronous call timed out and an
+ * asynchronous call was performed instead. All other cases will return false.
+ *
+ * Supported actions: "register" and "deregister"
+ *
+ * @param pageId the page ID of the WebKit instance/web page
+ * @param function the function string
+ * @param url the URL
+ * @param action the action being performed on the function, which will be used to form the DBus method name.
+ * @return true if the action succeeded (or was performed asynchronously), false if it failed
+ */
+private boolean webkit_extension_modify_function (long pageId, String function, String url, String action){
+ long /*int*/ args[] = { OS.g_variant_new_uint64(pageId),
+ OS.g_variant_new_string (Converter.javaStringToCString(function)),
+ OS.g_variant_new_string (Converter.javaStringToCString(url))};
+ final long /*int*/ argsTuple = OS.g_variant_new_tuple(args, args.length);
+ if (argsTuple == 0) return false;
+ String dbusMethodName = "webkitgtk_extension_" + action + "_function";
+ Object returnVal = WebkitGDBus.callExtensionSync(argsTuple, dbusMethodName);
+ if (returnVal instanceof Boolean) {
+ return (Boolean) returnVal;
+ } else if (returnVal instanceof String) {
+ String returnString = (String) returnVal;
+ /*
+ * Call the extension asynchronously if a synchronous call times out.
+ * Note: this is a pretty rare case, and usually only happens when running test cases.
+ * See bug 536141.
+ */
+ if ("timeout".equals(returnString)) {
+ return WebkitGDBus.callExtensionAsync(argsTuple, dbusMethodName);
+ }
+ }
+ return false;
+}
+
@Override
public boolean execute (String script) {
if (WEBKIT2){
@@ -3284,7 +3376,6 @@ long /*int*/ webkit_load_changed (long /*int*/ web_view, int status, long user_d
return handleLoadCommitted (uri, true);
}
case WebKitGTK.WEBKIT2_LOAD_FINISHED: {
- registerBrowserFunctions(); // Bug 508217
addEventHandlers (web_view, true);
long /*int*/ title = WebKitGTK.webkit_web_view_get_title (webView);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
index de2dc641ea..d7ec16e391 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
@@ -15,6 +15,8 @@
package org.eclipse.swt.browser;
+import java.util.*;
+
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.gtk.*;
@@ -33,11 +35,29 @@ import org.eclipse.swt.internal.gtk.*;
*/
class WebkitGDBus {
private static String DBUS_SERVICE_NAME;
- private static final String DBUS_OBJECT_NAME = "/org/eclipse/swt/gdbus";
+ private static final String DBUS_OBJECT_PATH = "/org/eclipse/swt/gdbus";
private static final String INTERFACE_NAME = "org.eclipse.swt.gdbusInterface";
+ private static final String EXTENSION_INTERFACE_NAME = "org.eclipse.swt.webkitgtk_extension.gdbusInterface";
+ private static String EXTENSION_DBUS_NAME;
+ private static String EXTENSION_DBUS_PATH;
/** Accepted methods over gdbus */
private static final String webkit2callJava = WebKit.Webkit2Extension.getJavaScriptFunctionName();
+ private static final String webkitWebExtensionIdentifier = WebKit.Webkit2Extension.getWebExtensionIdentifer();
+
+ /** Proxy connection to the web extension.*/
+ static long /*int*/ proxy;
+ /** A field that is set to true if the proxy connection has been established, false otherwise */
+ static boolean proxyToExtension;
+ /** Set to true if there are <code>BrowserFunction</code> objects waiting to be registered with the web extension.*/
+ static boolean functionsPending;
+ /**
+ * HashMap that stores any BrowserFunctions which have been created but not yet registered with the web extension.
+ * These functions will be registered with the web extension as soon as the proxy to the extension is set up.
+ *
+ * The format of the HashMap is (page ID, list of function string and URL).
+ */
+ static HashMap<Long, ArrayList<ArrayList<String>>> pendingBrowserFunctions = new HashMap<>();
/**
@@ -77,6 +97,11 @@ class WebkitGDBus {
+ " <arg type='" + OS.DBUS_TYPE_SINGLE_COMPLETE + "' name='arguments' direction='in'/>"
+ " <arg type='" + OS.DBUS_TYPE_SINGLE_COMPLETE + "' name='result' direction='out'/>"
+ " </method>"
+ + " <method name='" + webkitWebExtensionIdentifier + "'>"
+ + " <arg type='"+ OS.DBUS_TYPE_STRING + "' name='webExtensionDbusName' direction='in'/>"
+ + " <arg type='"+ OS.DBUS_TYPE_STRING + "' name='webExtensionDbusPath' direction='in'/>"
+ + " <arg type='"+ OS.DBUS_TYPE_STRUCT_ARRAY_BROWSER_FUNCS + "' name='result' direction='out'/>"
+ + " </method>"
+ " </interface>"
+ "</node>";
@@ -96,6 +121,9 @@ class WebkitGDBus {
private static Callback onNameLostCallback;
private static Callback handleMethodCallback;
+ /** Callback for asynchronous proxy calls to the extension */
+ private static Callback callExtensionAsyncCallback;
+
static {
onBusAcquiredCallback = new Callback (WebkitGDBus.class, "onBusAcquiredCallback", 3); //$NON-NLS-1$
if (onBusAcquiredCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
@@ -108,9 +136,12 @@ class WebkitGDBus {
handleMethodCallback = new Callback (WebkitGDBus.class, "handleMethodCallback", 8); //$NON-NLS-1$
if (handleMethodCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+ callExtensionAsyncCallback = new Callback (WebkitGDBus.class, "callExtensionAsyncCallback", 3); //$NON-NLS-1$
+ if (callExtensionAsyncCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
}
- static private boolean initialized;
+ static boolean initialized;
/** This method is not intended to be referenced by clients. Internal class. */
static void init(String uniqueId) {
@@ -169,7 +200,7 @@ class WebkitGDBus {
// Other times it validates it fine. We ignore for now as 32bit will be dropped anyway.
OS.g_dbus_connection_register_object(
connection,
- Converter.javaStringToCString(DBUS_OBJECT_NAME),
+ Converter.javaStringToCString(DBUS_OBJECT_PATH),
interface_info,
vtable,
0, // user_data
@@ -177,7 +208,7 @@ class WebkitGDBus {
error);
if (error[0] != 0) {
- System.err.println("SWT WebkitGDBus: Failed to register object: " + DBUS_OBJECT_NAME);
+ System.err.println("SWT WebkitGDBus: Failed to register object: " + DBUS_OBJECT_PATH);
return 0;
}
}
@@ -236,19 +267,123 @@ class WebkitGDBus {
String java_method_name = Converter.cCharPtrToJavaString(method_name, false);
Object result = null;
- if (java_method_name != null && java_method_name.equals(webkit2callJava)) {
- try {
- Object [] java_parameters = (Object []) convertGVariantToJava(gvar_parameters);
- result = WebKit.Webkit2Extension.webkit2callJavaCallback(java_parameters);
- } catch (Exception e) {
- // gdbus should always return to prevent extension from hanging.
- result = (String) WebBrowser.CreateErrorString (e.getLocalizedMessage ());
- System.err.println("SWT Webkit: Exception occured in Webkit2 callback logic. Bug?");
+ if (java_method_name != null) {
+ if (java_method_name.equals(webkit2callJava)) {
+ try {
+ Object [] java_parameters = (Object []) convertGVariantToJava(gvar_parameters);
+ result = WebKit.Webkit2Extension.webkit2callJavaCallback(java_parameters);
+ } catch (Exception e) {
+ // gdbus should always return to prevent extension from hanging.
+ result = (String) WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ System.err.println("SWT Webkit: Exception occured in Webkit2 callback logic. Bug?");
+ }
+ } else if (java_method_name.equals(webkitWebExtensionIdentifier)) {
+ Object [] nameArray = (Object []) convertGVariantToJava(gvar_parameters);
+ if (nameArray [0] != null && nameArray[0] instanceof String) EXTENSION_DBUS_NAME = (String) nameArray[0];
+ if (nameArray [1] != null && nameArray[1] instanceof String) EXTENSION_DBUS_PATH = (String) nameArray[1];
+ proxyToExtension = proxyToExtensionInit();
+ if (proxyToExtension) {
+ invokeReturnValueExtensionIdentifier(pendingBrowserFunctions, invocation);
+ } else {
+ invokeReturnValueExtensionIdentifier(null, invocation);
+ System.err.println("SWT webkit: proxy to web extension failed to load, BrowserFunction may not work.");
+ }
+ return 0;
+ }
+ } else {
+ result = (String) "SWT webkit: GDBus called an unknown method?";
+ System.err.println("SWT webkit: Received a call from an unknown method: " + java_method_name);
+ }
+ invokeReturnValue(result, invocation);
+ return 0;
+ }
+
+ @SuppressWarnings("unused")
+ private static long /*int*/ callExtensionAsyncCallback (long /*int*/ source_object, long /*int*/ res, long /*int*/ user_data) {
+ long /*int*/[] gerror = new long /*int*/[1];
+ long /*int*/ result = OS.g_dbus_proxy_call_finish (proxy, res, gerror);
+ if (gerror[0] != 0){
+ long /*int*/ errMsg = OS.g_error_get_message(gerror[0]);
+ String msg = Converter.cCharPtrToJavaString(errMsg, false);
+ System.err.println("SWT webkit: There was an error executing something asynchronously with the extension (Java callback).");
+ System.err.println("SWT webkit: the error message provided is " + msg);
+ OS.g_error_free(gerror[0]);
+ }
+ return 0;
+ }
+
+ /**
+ * Returns a GVariant to the DBus invocation of the extension identifier method. When the extension
+ * is initialized it sends a DBus message to the SWT webkit instance. As a return value, the SWT webkit
+ * instance sends any BrowserFunctions that have been registered. If no functions have been registered,
+ * an "empty" function with a page ID of -1 is sent.
+ *
+ * @param map the HashMap of BrowserFunctions waiting to be registered in the extension, or null
+ * if you'd like to explicitly send an empty function signature
+ * @param invocation the GDBus invocation to return the value on
+ */
+ private static void invokeReturnValueExtensionIdentifier (HashMap<Long, ArrayList<ArrayList<String>>> map,
+ long /*int*/ invocation) {
+ long /*int*/ resultGVariant;
+ long /*int*/ builder;
+ long /*int*/ type = OS.g_variant_type_new(OS.G_VARIANT_TYPE_ARRAY_BROWSER_FUNCS);
+ builder = OS.g_variant_builder_new(type);
+ if (builder == 0) return;
+ Object [] tupleArray = new Object[3];
+ boolean sendEmptyFunction;
+ if (map == null) {
+ sendEmptyFunction = true;
+ } else {
+ sendEmptyFunction = map.isEmpty() && !functionsPending;
+ }
+ /*
+ * No functions to register, send a page ID of -1 and empty strings.
+ */
+ if (sendEmptyFunction) {
+ tupleArray[0] = (long)-1;
+ tupleArray[1] = "";
+ tupleArray[2] = "";
+ long /*int*/ tupleGVariant = convertJavaToGVariant(tupleArray);
+ if (tupleGVariant != 0) {
+ OS.g_variant_builder_add_value(builder, tupleGVariant);
+ } else {
+ System.err.println("SWT webkit: error creating empty BrowserFunction GVariant tuple, skipping.");
}
} else {
- result = (String) "SWT Webkit: Gdbus called an unknown method?";
- System.err.println("SWT WebkitGDBus: Received a call from an unknown method: " + java_method_name);
+ for (long id : map.keySet()) {
+ ArrayList<ArrayList<String>> list = map.get(id);
+ if (list != null) {
+ for (ArrayList<String> stringList : list) {
+ Object [] stringArray = stringList.toArray();
+ if (stringArray.length > 2) {
+ System.err.println("SWT webkit: String array with BrowserFunction and URL should never have"
+ + "more than 2 Strings");
+ }
+ tupleArray[0] = id;
+ System.arraycopy(stringArray, 0, tupleArray, 1, 2);
+ long /*int*/ tupleGVariant = convertJavaToGVariant(tupleArray);
+ if (tupleGVariant != 0) {
+ OS.g_variant_builder_add_value(builder, tupleGVariant);
+ } else {
+ System.err.println("SWT webkit: error creating BrowserFunction GVariant tuple, skipping.");
+ }
+ }
+ }
+ }
+ }
+ resultGVariant = OS.g_variant_builder_end(builder);
+ String typeString = Converter.cCharPtrToJavaString(OS.g_variant_get_type_string(resultGVariant), false);
+ if (!OS.DBUS_TYPE_STRUCT_ARRAY_BROWSER_FUNCS.equals(typeString)) {
+ System.err.println("An error packaging the GVariant occurred: type mismatch.");
}
+ long /*int*/ [] variants = {resultGVariant};
+ long /*int*/ finalGVariant = OS.g_variant_new_tuple(variants, 1);
+ OS.g_dbus_method_invocation_return_value(invocation, finalGVariant);
+ OS.g_variant_builder_unref(builder);
+ return;
+ }
+
+ private static void invokeReturnValue (Object result, long /*int*/ invocation) {
long /*int*/ resultGVariant = 0;
try {
resultGVariant = convertJavaToGVariant(new Object [] {result}); // Result has to be a tuple.
@@ -258,10 +393,98 @@ class WebkitGDBus {
resultGVariant = convertJavaToGVariant(new Object [] {errMsg});
}
OS.g_dbus_method_invocation_return_value(invocation, resultGVariant);
- return 0; // void return value.
+ return; // void return value.
}
+ /**
+ * Initializes the proxy connection to the web extension.
+ *
+ * @return true if establishing the proxy connections succeeded,
+ * false otherwise
+ */
+ private static boolean proxyToExtensionInit() {
+ if (proxy != 0) {
+ return true;
+ } else {
+ if (EXTENSION_DBUS_NAME != null && EXTENSION_DBUS_PATH != null) {
+ long /*int*/ [] error = new long /*int*/ [1];
+ byte [] name = Converter.javaStringToCString(EXTENSION_DBUS_NAME);
+ byte [] path = Converter.javaStringToCString(EXTENSION_DBUS_PATH);
+ byte [] interfaceName = Converter.javaStringToCString(EXTENSION_INTERFACE_NAME);
+ proxy = OS.g_dbus_proxy_new_for_bus_sync(OS.G_BUS_TYPE_SESSION, OS.G_DBUS_PROXY_FLAGS_NONE, 0, name, path, interfaceName, 0, error);
+ if (error[0] != 0) {
+ long /*int*/ errMsg = OS.g_error_get_message(error[0]);
+ String msg = Converter.cCharPtrToJavaString(errMsg, false);
+ OS.g_error_free(error[0]);
+ System.err.println("SWT webkit: there was an error establishing the proxy connection to the extension. " +
+ " The error is " + msg);
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Calls the web extension synchronously. Returns true if the operation succeeded, and false
+ * otherwise (or if the operation times out).
+ *
+ * @param params a pointer to the GVariant containing the parameters
+ * @param methodName a String representing the DBus method name in the extension
+ * @return an Object representing the return value from DBus in boolean form
+ */
+ static Object callExtensionSync (long /*int*/ params, String methodName) {
+ long /*int*/[] gerror = new long /*int*/ [1]; // GError **
+ long /*int*/ gVariant = OS.g_dbus_proxy_call_sync(proxy, Converter.javaStringToCString(methodName),
+ params, OS.G_DBUS_CALL_FLAGS_NO_AUTO_START, 1000, 0, gerror);
+ if (gerror[0] != 0) {
+ long /*int*/ errMsg = OS.g_error_get_message(gerror[0]);
+ String msg = Converter.cCharPtrToJavaString(errMsg, false);
+ /*
+ * Don't print console warnings for timeout errors, as we can handle these ourselves.
+ * Note, most timeout errors happen only when running test cases, not during "normal" use.
+ */
+ if (msg != null && (!msg.contains("Timeout") && !msg.contains("timeout"))) {
+ System.err.println("SWT webkit: There was an error executing something synchronously with the extension.");
+ System.err.println("SWT webkit: The error message is: " + msg);
+ return (Object) false;
+ }
+ OS.g_error_free(gerror[0]);
+ return (Object) "timeout";
+ }
+ Object resultObject = gVariant != 0 ? convertGVariantToJava(gVariant) : (Object) false;
+ // Sometimes we get back tuples from GDBus, which get converted into Object arrays. In this case
+ // we only care about the first value, since the extension never returns anything more than that.
+ if (resultObject instanceof Object[]) {
+ return ((Object []) resultObject)[0];
+ }
+ return resultObject;
+ }
+ /**
+ * Calls the web extension asynchronously. Note, this method returning true does not
+ * guarantee the operation's success, it only means no errors occurred.
+ *
+ * @param params a pointer to the GVariant containing the parameters
+ * @param methodName a String representing the DBus method name in the extension
+ * @return true if the extension was called without errors, false otherwise
+ */
+ static boolean callExtensionAsync (long /*int*/ params, String methodName) {
+ long /*int*/[] gerror = new long /*int*/ [1]; // GError **
+ OS.g_dbus_proxy_call(proxy, Converter.javaStringToCString(methodName),
+ params, OS.G_DBUS_CALL_FLAGS_NO_AUTO_START, 1000, 0, callExtensionAsyncCallback.getAddress(), gerror);
+ if (gerror[0] != 0) {
+ long /*int*/ errMsg = OS.g_error_get_message(gerror[0]);
+ String msg = Converter.cCharPtrToJavaString(errMsg, false);
+ System.err.println("SWT webkit: There was an error executing something asynchronously with the extension.");
+ System.err.println("SWT webkit: The error message is: " + msg);
+ OS.g_error_free(gerror[0]);
+ return false;
+ }
+ return true;
+ }
/* TYPE NOTES
*
@@ -314,6 +537,10 @@ class WebkitGDBus {
return new Double(OS.g_variant_get_double(gVariant));
}
+ if (OS.g_variant_is_of_type(gVariant, OS.G_VARIANT_TYPE_UINT64)){
+ return new Long(OS.g_variant_get_uint64(gVariant));
+ }
+
if (OS.g_variant_is_of_type(gVariant, OS.G_VARIANT_TYPE_STRING)){
return Converter.cCharPtrToJavaString(OS.g_variant_get_string(gVariant, null), false);
}
@@ -346,6 +573,10 @@ class WebkitGDBus {
return OS.g_variant_new_byte(WebkitGDBus.SWT_DBUS_MAGIC_NUMBER_NULL); // see: WebKitGTK.java 'TYPE NOTES'
}
+ if (javaObject instanceof Long) {
+ return OS.g_variant_new_uint64((Long) javaObject);
+ }
+
if (javaObject instanceof String) {
return OS.g_variant_new_string (Converter.javaStringToCString((String) javaObject));
}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
index 11ccd2261f..c1df6956a2 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/internal/webkit/WebKitGTK.java
@@ -1722,6 +1722,17 @@ public static final long /*int*/ webkit_web_view_get_main_frame (long /*int*/ we
}
/** @method flags=dynamic */
+public static final native long /*int*/ _webkit_web_view_get_page_id (long /*int*/ web_view);
+public static final long /*int*/ webkit_web_view_get_page_id (long /*int*/ web_view) {
+ lock.lock();
+ try {
+ return _webkit_web_view_get_page_id (web_view);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/** @method flags=dynamic */
public static final native double _webkit_web_view_get_progress (long /*int*/ web_view);
public static final double webkit_web_view_get_progress (long /*int*/ web_view) {
assert WEBKIT1 : Webkit1AssertMsg;
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug536141_BrowserFunctionLostReload.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug536141_BrowserFunctionLostReload.java
new file mode 100644
index 0000000000..09dec0b2aa
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug536141_BrowserFunctionLostReload.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Red Hat and others. All rights reserved.
+ * The contents of this file are made available under the terms
+ * of the GNU Lesser General Public License (LGPL) Version 2.1 that
+ * accompanies this distribution (lgpl-v21.txt). The LGPL is also
+ * available at http://www.gnu.org/licenses/lgpl.html. If the version
+ * of the LGPL at http://www.gnu.org is different to the version of
+ * the LGPL accompanying this distribution and there is any conflict
+ * between the two license versions, the terms of the LGPL accompanying
+ * this distribution shall govern.
+ *
+ * Contributors:
+ * Red Hat - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.BrowserFunction;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/*
+ * Title: Bug 536141: [Webkit2][Gtk] BrowserFunction lost after page reload on Linux/GTK
+ * How to run: Read the instructions printed in the console
+ * Bug description: N/A
+ * Expected results: BrowserFunctions should be added/removed as expected, see instructions for details
+ * GTK Version(s):
+ */
+public class Bug536141_BrowserFunctionLostReload {
+
+ static int count = 0;
+
+ public static void main(String[] args) {
+ Display display = new Display();
+ Shell shell = new Shell(display);
+ shell.setSize(500, 600);
+
+ GridLayout gridLayout = new GridLayout();
+ shell.setLayout(gridLayout);
+
+ final Text jsConsole = new Text(shell, SWT.BORDER);
+// jsConsole.setText("document.body.innerHTML = theJavaFunction(123, 'hello', null, true)");
+ jsConsole.setText("document.body.innerHTML = theJavaFunction()"); // Case where there are no paramaters.
+ jsConsole.setSelection(jsConsole.getText().length());
+ GridData data = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+ jsConsole.setLayoutData(data);
+
+ final Browser browser = new Browser(shell, SWT.NONE);
+ browser.setText("hello <b>world!</b>");
+ data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ browser.setLayoutData(data);
+
+ jsConsole.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.keyCode == 13) { // 13 = Enter
+ browser.execute(jsConsole.getText());
+ }
+ }
+ });
+
+ Button loadNewPage = new Button(shell, SWT.PUSH);
+ loadNewPage.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ loadNewPage.setText("Load new page");
+ loadNewPage.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ browser.setText("New page!" + count++);
+ }
+ });
+
+
+ // BrowserFunction Code
+ @SuppressWarnings("unused")
+ final BrowserFunction function = new CustomFunction (browser, "theJavaFunction");
+
+ Button create = new Button (shell, SWT.PUSH);
+ create.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ create.setText("Create function");
+ create.addSelectionListener(new SelectionListener () {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {}
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ System.out.println("creating function");
+ @SuppressWarnings("unused")
+ final BrowserFunction function2 = new CustomFunction (browser, "theJavaFunction2");
+ }
+ });
+
+ Button destroy = new Button (shell, SWT.PUSH);
+ destroy.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ destroy.setText("Destroy function");
+ destroy.addSelectionListener(new SelectionListener () {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {}
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ System.out.println("destroying function");
+ function.dispose();
+ }
+ });
+ shell.open();
+ System.out.println("INSTRUCTIONS: pressing the \"Create function\" button will create a function called theJavaFunction2.");
+ System.out.println("Pressing the \"Destroy function\" button will destory the function called theJavaFunction.");
+ System.out.println("To test that theJavaFunction2 was created, add the \"2\""
+ + " at the end of theJavaFunction in the console and press enter.");
+ System.out.println("To test that theJavaFunction was deleted, remove the \"2\""
+ + " at the end of theJavaFunction in the console and press enter.");
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+ display.dispose();
+ }
+
+ static class CustomFunction extends BrowserFunction { // copied from snippet 307
+ CustomFunction (Browser browser, String name) {
+ super (browser, name);
+ }
+ @Override
+ public Object function (Object[] arguments) {
+ System.out.println ("theJavaFunction() called from javascript with args:");
+ for (int i = 0; i < arguments.length; i++) {
+ Object arg = arguments[i];
+ if (arg == null) {
+ System.out.println ("\t-->null");
+ } else {
+ System.out.println ("\t-->" + arg.getClass ().getName () + ": " + arg.toString ());
+ }
+ }
+ return arguments;
+// return new Point(1, 2);
+
+// Object returnValue = new Object[] {
+// new Short ((short)3),
+// new Boolean (true),
+// null,
+// new Object[] {"a string", new Boolean (false)},
+// "hi",
+// new Float (2.0f / 3.0f),
+// };
+// return returnValue;
+
+// return new Double(42.0);
+ }
+ }
+}

Back to the top