diff options
| author | Leo Ufimtsev | 2017-11-06 16:52:38 +0000 |
|---|---|---|
| committer | Leo Ufimtsev | 2017-12-01 18:45:15 +0000 |
| commit | 8009c3b86dee4f50191b785f9c121ef5cdd24746 (patch) | |
| tree | 5f6294dc2ffef1f164dda77b88c91b00de2fe096 | |
| parent | 382c1d03f132e44887b0dcb83fdb7f7578ef9db2 (diff) | |
| download | eclipse.platform.swt-8009c3b86dee4f50191b785f9c121ef5cdd24746.tar.gz eclipse.platform.swt-8009c3b86dee4f50191b785f9c121ef5cdd24746.tar.xz eclipse.platform.swt-8009c3b86dee4f50191b785f9c121ef5cdd24746.zip | |
Bug 510905 [Webkit2] BrowserFunction with return value back to
Javascript
(PRIOR TO MERGING, SWT BINARY REPO NEEDS TO BE PATCHED)
Webkit2 moved it's webprocess into a separate process.
For javascript to call a function, it needs to do so via the
separate process.
To interact with the separate process, we need to implement a
webextension, which is a separate '.so' file loaded at run time.
The extension needs to reside in it's own folder otherwise
webkit will try to load the other .so files as extensions.
(See Library.java changes).
Communication between the extension and the main process is done
via a gdbus channel. Javascript/Java types are packaged into
GVariants and transmitted via gdbus.
Compilation of the webextension requires webkit2gtk
package to be present on build servers.
Tests:
- All jUnits pass
- SWT Snippet (307) that use BrowserFunction work.
- Attached local snippet can be used to test sending various
paramaters over gdbus and receiving them back prints to main webview.
- Child eclipse works fine with the patch.
- Afaik, no known error/warnings are produced.
(If there are, let me know).
This might break 32bit build of SWT though, not tested on 32 bit.
Patch set log:
--------------
Patchset 6:
- Passing webview as string in javascript function.
Patchset 8:
- Implemented dynamic gdbus bindigs on SWT/Java side. Works.
(fairly large patch)
Patchset 9:
- Implemented gdbus bindings on client side, such that it can reach
server. (working)
Patchset 10:
- Added GVariant conversion functions on SWT side. Works.
- Moved code out of OS.java to reside only in WebKitGTK
Patchset 11:
- Figured out how to provide return value as an object array.
Added snippet to show how to provide a string return value. (working)
Patchset 12:
- Passed webview pointer, index and token to Java.
- Fixed typo in type definition.
> (Working)
Patchset 13:
- Now passing javascript arguments along through gdbus to java.
> (Working)
Patchset 14: (Week 46)
- Implemented support for 'null'. (use byte as magic number).
- Found that there is a bug in how I deal with return value in gdbus,
gdbus returns an array (always). Need to return first item in array.
Patchset 15: (Week 46)
- Implemented proper return value of java to javascript.
- Found that js calls with no paramaters call() fail, need to fix.
Patchset 16: (Week 46)
- Implemented support for empty arrays (including calls without args).
- Code tidy.
- Found that I need to implement input argument verification from JS
call and from java code ran by user, otherwise gdbus can crash.
Patchset 17: (Week 46)
- Implement checking of user-input arguments, to ensure it won't break
gdbus connection.
Patchset 18: (Week 46)
- Implemented checking of return value from userfunction, so bad
return value doesn't break gdbus.
- Code tidy/polish.
- Need to implement lazy loading of gdbus, only init gdbus for
the first function that we instantiate.
- Also still getting warning when loading webkit library.
Patchset 19: [Week 47]
- Implemented lazy loading of gdbus, to only load when needed.
- wrapped getPID() into lock, otherwise had strange debug/execution
behaviour.
Patchset 20: [Week 47]
- Two BrowserInstances with Two BrowserFunctions seem to hang (snippet),
(need to investigate)
Patchset 21: [W47]
- Removed redundant print statements. Cleaned up code.
Patchset 22: [W47]
- Moved Webkit extension initialization logic into a callback,
so that it's guaranteed to be loaded at the most optimal time.
(All jUnits pass).
Patchset 23: [W47]
- Removed redundant println.
Patchset 24: [W47]
- Implemented mechanism by which webextension is compiled and loaded
from a folder.
(This needs a patch to binary project's build.properties)
Patchset 25: [W47]
- Code tidy. Patch complete (ish).
Patchset 26: [W47]
- forgot to add files to patchset 25.
Patchset 27: [W47]
- Verified that Browser widget will continue to work if webextension
fails to load.
- Added relevant warnings.
Patchset 28:
- Minor update on SWT_LIB_VERSIONS.
Change-Id: Iccfc48bc78774ac4120aafd976186381f247c562
Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
19 files changed, 2243 insertions, 120 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java index d04ac5ccaa..8cb99b2961 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java @@ -403,7 +403,7 @@ public Object evaluate (String script) throws SWTException { BrowserFunction function = new EvaluateFunction (browser, ""); // $NON-NLS-1$ int index = getNextFunctionIndex (); function.index = index; - function.isEvaluate = true; + function.isEvaluate = true; // Note, Webkit2 doesn't use 'isEvaluate' machinery because it doesn't use a function for evaluation. registerFunction (function); String functionName = EXECUTE_ID + index; diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/common_j2se/org/eclipse/swt/internal/Library.java b/bundles/org.eclipse.swt/Eclipse SWT PI/common_j2se/org/eclipse/swt/internal/Library.java index d8cb3c47d2..e7774d63b3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/common_j2se/org/eclipse/swt/internal/Library.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/common_j2se/org/eclipse/swt/internal/Library.java @@ -12,6 +12,7 @@ package org.eclipse.swt.internal; import java.io.*; import java.net.*; +import java.util.function.*; import java.util.jar.*; public class Library { @@ -37,10 +38,15 @@ public class Library { * The JAVA and SWT versions */ public static final int JAVA_VERSION, SWT_VERSION; + public static final String USER_HOME; static final String SEPARATOR; static final String DELIMITER; + static final String JAVA_LIB_PATH = "java.library.path"; + static final String SWT_LIB_PATH = "swt.library.path"; + + /* 64-bit support */ static final boolean IS_64 = longConst() == (long /*int*/)longConst(); static final String SUFFIX_64 = "-64"; //$NON-NLS-1$ @@ -49,6 +55,7 @@ public class Library { static { DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$ SEPARATOR = System.getProperty("file.separator"); //$NON-NLS-1$ + USER_HOME = System.getProperty ("user.home"); SWT_LIB_DIR = ".swt" + SEPARATOR + "lib" + SEPARATOR + os() + SEPARATOR + arch(); //$NON-NLS-1$ $NON-NLS-2$ JAVA_VERSION = parseVersion(System.getProperty("java.version")); //$NON-NLS-1$ SWT_VERSION = SWT_VERSION(MAJOR_VERSION, MINOR_VERSION); @@ -128,10 +135,17 @@ public static int SWT_VERSION (int major, int minor) { return major * 1000 + minor; } -static boolean extract (String fileName, String mappedName, StringBuffer message) { +/** + * Extract file with 'mappedName' into path 'extractToFilePath'. Cleanup leftovers if extract failed. + * @param extractToFilePath full path of where the file is to be extacted to, inc name of file, + * e.g /home/USER/.swt/lib/linux/x86_64/libswt-MYLIB-gtk-4826.so + * @param mappedName file to be searched in jar. + * @return true upon success, failure if something went wrong. + */ +static boolean extract (String extractToFilePath, String mappedName, StringBuffer message) { FileOutputStream os = null; InputStream is = null; - File file = new File(fileName); + File file = new File(extractToFilePath); boolean extracted = false; try { if (!file.exists ()) { @@ -140,14 +154,14 @@ static boolean extract (String fileName, String mappedName, StringBuffer message extracted = true; int read; byte [] buffer = new byte [4096]; - os = new FileOutputStream (fileName); + os = new FileOutputStream (extractToFilePath); while ((read = is.read (buffer)) != -1) { os.write(buffer, 0, read); } os.close (); is.close (); - chmod ("755", fileName); - if (load (fileName, message)) return true; + chmod ("755", extractToFilePath); + return true; } } } catch (Throwable e) { @@ -253,19 +267,7 @@ public static void loadLibrary (String name, boolean mapName) { /* Compute the library name and mapped name */ String libName1, libName2, mappedName1, mappedName2; if (mapName) { - String version = System.getProperty ("swt.version"); //$NON-NLS-1$ - if (version == null) { - version = "" + MAJOR_VERSION; //$NON-NLS-1$ - /* Force 3 digits in minor version number */ - if (MINOR_VERSION < 10) { - version += "00"; //$NON-NLS-1$ - } else { - if (MINOR_VERSION < 100) version += "0"; //$NON-NLS-1$ - } - version += MINOR_VERSION; - /* No "r" until first revision */ - if (REVISION > 0) version += "r" + REVISION; //$NON-NLS-1$ - } + String version = getVersionString (); libName1 = name + "-" + Platform.PLATFORM + "-" + version; //$NON-NLS-1$ //$NON-NLS-2$ libName2 = name + "-" + Platform.PLATFORM; //$NON-NLS-1$ mappedName1 = mapLibraryName (libName1); @@ -277,7 +279,7 @@ public static void loadLibrary (String name, boolean mapName) { StringBuffer message = new StringBuffer(); /* Try loading library from swt library path */ - String path = System.getProperty ("swt.library.path"); //$NON-NLS-1$ + String path = System.getProperty (SWT_LIB_PATH); //$NON-NLS-1$ if (path != null) { path = new File (path).getAbsolutePath (); if (load (path + SEPARATOR + mappedName1, message)) return; @@ -288,13 +290,16 @@ public static void loadLibrary (String name, boolean mapName) { if (load (libName1, message)) return; if (mapName && load (libName2, message)) return; - /* Try loading library from the tmp directory if swt library path is not specified */ + /* Try loading library from the tmp directory if swt library path is not specified. + * Create the tmp folder if it doesn't exist. Tmp folder looks like this: + * ~/.swt/lib/<platform>/<arch>/ + */ String fileName1 = mappedName1; String fileName2 = mappedName2; if (path == null) { - path = System.getProperty ("user.home"); //$NON-NLS-1$ + path = USER_HOME; File dir = new File (path, SWT_LIB_DIR); - if ((dir.exists () && dir.isDirectory ()) || dir.mkdirs ()) { + if ((dir.exists () && dir.isDirectory ()) || dir.mkdirs ()) { // Create if not exist. path = dir.getAbsolutePath (); } else { /* fall back to using the home dir directory */ @@ -307,10 +312,16 @@ public static void loadLibrary (String name, boolean mapName) { if (mapName && load (path + SEPARATOR + fileName2, message)) return; } - /* Try extracting and loading library from jar */ + /* Try extracting and loading library from jar. */ if (path != null) { - if (extract (path + SEPARATOR + fileName1, mappedName1, message)) return; - if (mapName && extract (path + SEPARATOR + fileName2, mappedName2, message)) return; + if (extract (path + SEPARATOR + fileName1, mappedName1, message)) { + load(path + SEPARATOR + fileName1, message); + return; + } + if (mapName && extract (path + SEPARATOR + fileName2, mappedName2, message)) { + load(path + SEPARATOR + fileName2, message); + return; + } } /* Failed to find the library */ @@ -327,4 +338,100 @@ static String mapLibraryName (String libName) { return libName; } +/** + * @return String Combined SWT version like 4826 + */ +public static String getVersionString () { + String version = System.getProperty ("swt.version"); //$NON-NLS-1$ + if (version == null) { + version = "" + MAJOR_VERSION; //$NON-NLS-1$ + /* Force 3 digits in minor version number */ + if (MINOR_VERSION < 10) { + version += "00"; //$NON-NLS-1$ + } else { + if (MINOR_VERSION < 100) version += "0"; //$NON-NLS-1$ + } + version += MINOR_VERSION; + /* No "r" until first revision */ + if (REVISION > 0) version += "r" + REVISION; //$NON-NLS-1$ + } + return version; +} + +/** + * Locates a resource located either in java library path, swt library path, or attempts to extract it from inside swt.jar file. + * This function supports a single level subfolder, e.g SubFolder/resource. + * + * @param subDir 'null' or a folder name without slashes. E.g Correct: 'mysubdir', incorrect: '/subdir/'. + * Platform specific Slashes will be added automatically. + * @param resourceName e.g swt-webkitgtk + * @param mapResourceName true if you like platform specific mapping applied to resource name. e.g MyLib -> libMyLib-gtk-4826.so + */ +public static File findResource(String subDir, String resourceName, boolean mapResourceName){ + // subdir e.g: subdir + String maybeSubDirPath = subDir != null ? subDir + SEPARATOR : ""; // e.g: subdir/ or "" + String maybeSubDirPathWithPrefix = subDir != null ? SEPARATOR + maybeSubDirPath : ""; // e.g: /subdir/ or "" + final String finalResourceName = mapResourceName ? + mapLibraryName(resourceName + "-" + Platform.PLATFORM + "-" + getVersionString ()) // e.g libMyLib-gtk-3826.so + : resourceName; + + // 1) Look for the resource in the java/swt library path(s) + // This code commonly finds the resource if the swt project is a required project and the swt binary (for your platform) + // project is open in your workplace (found in the JAVA_LIBRARY_PATH) or if you're explicitly specified SWT_LIBRARY_PATH. + { + Function<String, File> lookForFileInPath = searchPath -> { + String classpath = System.getProperty(searchPath); + if (classpath != null){ + String[] paths = classpath.split(":"); + for (String path : paths) { + File file = new File(path + SEPARATOR + maybeSubDirPath + finalResourceName); + if (file.exists()){ + return file; + } + } + } + return null; + }; + File result = null; + for (String path : new String[] {JAVA_LIB_PATH,SWT_LIB_PATH}) { + result = lookForFileInPath.apply(path); + if (result != null) + return result; + } + } + + // 2) Need to try to pull the resource out of the swt.jar. + // Look for the resource in the user's home directory, (if already extracted in the temp swt folder. (~/.swt/lib...) + // Extract from the swt.jar if not there already. + { + // Developer note: + // To test this piece of code, you need to compile SWT into a jar and use it in a test project. E.g + // cd ~/git/eclipse.platform.swt.binaries/bundles/org.eclipse.swt.gtk.linux.x86_64/ + // mvn clean verify -Pbuild-individual-bundles -Dnative=gtk.linux.x86_64 + // then ./target/ will contain org.eclipse.swt.gtk.linux.x86_64-3.106.100-SNAPSHOT.jar (and it's source), + // you can copy those into your test swt project and test that your resource is extracted into something like ~/.swt/... + // Lastly, if using subDir, you need to edit the build.properties and specify the folder you wish to have included in your jar in the includes. + File file = new File (USER_HOME + SEPARATOR + SWT_LIB_DIR + maybeSubDirPathWithPrefix, finalResourceName); + if (file.exists()){ + return file; + } else { // Try to extract file from jar if not found. + + // Create temp directory if it doesn't exist + File tempDir = new File (USER_HOME, SWT_LIB_DIR + maybeSubDirPathWithPrefix); + if ((!tempDir.exists () || tempDir.isDirectory ())) { + tempDir.mkdirs (); + } + + StringBuffer message = new StringBuffer(""); + if (extract(file.getPath(), maybeSubDirPath + finalResourceName, message)) { + if (file.exists()) { + return file; + } + } + } + } + throw new UnsatisfiedLinkError("Could not find resource" + resourceName + (subDir != null ? " (in subdirectory: " + subDir + " )" : "")); +} + + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak index b9ec052d0d..3c83804a99 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/make_linux.mak @@ -13,8 +13,9 @@ # SWT debug flags for various SWT components. #SWT_WEBKIT_DEBUG = -DWEBKIT_DEBUG -#SWT_LIB_DEBUG=1 # to debug glue code in /bundles/org.eclipse.swt/bin/library. E.g os_custom.c:swt_fixed_forall(..) +#SWT_LIB_DEBUG=1 # to debug glue code in /bundles/org.eclipse.swt/bin/library. E.g os_custom.c:swt_fixed_forall(..) +# Can be set via environment like: export SWT_LIB_DEBUG=1 ifdef SWT_LIB_DEBUG SWT_DEBUG = -O0 -g3 -ggdb3 NO_STRIP=1 @@ -37,6 +38,7 @@ endif CAIRO_PREFIX = swt-cairo ATK_PREFIX = swt-atk WEBKIT_PREFIX = swt-webkit +WEBKIT_EXTENSION_PREFIX=swt-webkit2extension GLX_PREFIX = swt-glx SWT_LIB = lib$(SWT_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so @@ -44,8 +46,13 @@ AWT_LIB = lib$(AWT_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so SWTPI_LIB = lib$(SWTPI_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so CAIRO_LIB = lib$(CAIRO_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so ATK_LIB = lib$(ATK_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so -WEBKIT_LIB = lib$(WEBKIT_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so GLX_LIB = lib$(GLX_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so +WEBKIT_LIB = lib$(WEBKIT_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so +ALL_SWT_LIBS = $(SWT_LIB) $(AWT_LIB) $(SWTPI_LIB) $(CAIRO_LIB) $(ATK_LIB) $(GLX_LIB) $(WEBKIT_LIB) + +# Webkit extension lib has to be put into a separate folder and is treated differently from the other libraries. +WEBKIT_EXTENSION_LIB = lib$(WEBKIT_EXTENSION_PREFIX)-$(WS_PREFIX)-$(SWT_VERSION).so +WEBEXTENSION_DIR = webkitextensions$(maj_ver)$(min_ver) CAIROCFLAGS = `pkg-config --cflags cairo` CAIROLIBS = `pkg-config --libs-only-L cairo` -lcairo @@ -71,6 +78,10 @@ GLXLIBS = -lGL -lGLU -lm WEBKITLIBS = `pkg-config --libs-only-l gio-2.0` WEBKITCFLAGS = `pkg-config --cflags gio-2.0` + +WEBKIT_EXTENSION_CFLAGS=`pkg-config --cflags gtk+-3.0 webkit2gtk-web-extension-4.0` +WEBKIT_EXTENSION_LFLAGS=`pkg-config --libs gtk+-3.0 webkit2gtk-web-extension-4.0` + ifdef SWT_WEBKIT_DEBUG # don't use 'webkit2gtk-4.0' in production, as some systems might not have those libs and we get crashes. WEBKITLIBS += `pkg-config --libs-only-l webkit2gtk-4.0` @@ -177,7 +188,11 @@ atk_stats.o: atk_stats.c atk_structs.h atk_stats.h atk.h # # WebKit lib # +ifeq ($(GTK_VERSION), 3.0) +make_webkit: $(WEBKIT_LIB) make_webkit2extension #Webkit2 only used by gtk3. +else make_webkit: $(WEBKIT_LIB) +endif $(WEBKIT_LIB): $(WEBKIT_OBJECTS) $(CC) $(LFLAGS) -o $(WEBKIT_LIB) $(WEBKIT_OBJECTS) $(WEBKITLIBS) @@ -194,6 +209,16 @@ webkitgtk_stats.o: webkitgtk_stats.c webkitgtk_stats.h webkitgtk_custom.o: webkitgtk_custom.c $(CC) $(CFLAGS) $(WEBKITCFLAGS) -c webkitgtk_custom.c + +# Webkit2 extension is a seperate .so lib. +make_webkit2extension: $(WEBKIT_EXTENSION_LIB) + +$(WEBKIT_EXTENSION_LIB) : webkitgtk_extension.o + $(CC) $(LFLAGS) -o $@ $^ $(WEBKIT_EXTENSION_LFLAGS) + +webkitgtk_extension.o : webkitgtk_extension.c + $(CC) $(CFLAGS) $(WEBKIT_EXTENSION_CFLAGS) ${SWT_PTR_CFLAGS} -fPIC -c $^ + # # GLX lib # @@ -217,6 +242,13 @@ glx_stats.o: glx_stats.c glx_stats.h install: all cp *.so $(OUTPUT_DIR) + +install: all + cp $(ALL_SWT_LIBS) $(OUTPUT_DIR) +ifeq ($(GTK_VERSION), 3.0) # Copy webextension into it's own folder, but create folder first. + [ -d $(OUTPUT_DIR)/$(WEBEXTENSION_DIR) ] || mkdir $(OUTPUT_DIR)/$(WEBEXTENSION_DIR) # If folder not exist, make it. + cp $(WEBKIT_EXTENSION_LIB) $(OUTPUT_DIR)/$(WEBEXTENSION_DIR)/ +endif # # Clean # 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 db9b835c4e..3fe853f20c 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 @@ -6927,6 +6927,18 @@ JNIEXPORT jintLong JNICALL OS_NATIVE(_1gdk_1x11_1window_1lookup_1for_1display) } #endif +#ifndef NO__1getpid +JNIEXPORT jint JNICALL OS_NATIVE(_1getpid) + (JNIEnv *env, jclass that) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, _1getpid_FUNC); + rc = (jint)getpid(); + OS_NATIVE_EXIT(env, that, _1getpid_FUNC); + return rc; +} +#endif + #ifndef NO__1glib_1major_1version JNIEXPORT jint JNICALL OS_NATIVE(_1glib_1major_1version) (JNIEnv *env, jclass that) 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 dbb697a0b0..abba27976f 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 @@ -574,6 +574,7 @@ char * OS_nativeFunctionNames[] = { "_1gdk_1x11_1visual_1get_1xvisual", "_1gdk_1x11_1window_1get_1xid", "_1gdk_1x11_1window_1lookup_1for_1display", + "_1getpid", "_1glib_1major_1version", "_1glib_1micro_1version", "_1glib_1minor_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 18464f35ef..609ba771a8 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 @@ -584,6 +584,7 @@ typedef enum { _1gdk_1x11_1visual_1get_1xvisual_FUNC, _1gdk_1x11_1window_1get_1xid_FUNC, _1gdk_1x11_1window_1lookup_1for_1display_FUNC, + _1getpid_FUNC, _1glib_1major_1version_FUNC, _1glib_1micro_1version_FUNC, _1glib_1minor_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 1ca20754b5..79cc73579d 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 @@ -14989,6 +14989,20 @@ public static final void gtk_window_unmaximize(long /*int*/ handle) { lock.unlock(); } } + +// Technically works on OSX also, but currently only used on Linux. +// Once SWT is moved to Java 9, consider using 'ProcessHandle.current().getPid();' instead, +// but for now getpid() should do. +// https://stackoverflow.com/questions/35842/how-can-a-java-program-get-its-own-process-id +public static final native int _getpid (); +public static final int getpid() { + lock.lock(); + try { + return _getpid(); + } finally { + lock.unlock(); + } +} /** * @param dest cast=(void *) * @param src cast=(const void *),flags=no_out 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 1601b08203..9658c38b48 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 @@ -613,6 +613,445 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1SoupMessage_1request_1headers) } #endif +#ifndef NO__1g_1bus_1own_1name +JNIEXPORT jint JNICALL WebKitGTK_NATIVE(_1g_1bus_1own_1name) + (JNIEnv *env, jclass that, jint arg0, jbyteArray arg1, jint arg2, jintLong arg3, jintLong arg4, jintLong arg5, jintLong arg6, jintLong arg7) +{ + jbyte *lparg1=NULL; + jint rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1bus_1own_1name_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + rc = (jint)g_bus_own_name(arg0, lparg1, arg2, arg3, arg4, arg5, arg6, arg7); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_bus_own_name) + if (fp) { + rc = (jint)((jint (CALLING_CONVENTION*)(jint, jbyte *, jint, jintLong, jintLong, jintLong, jintLong, jintLong))fp)(arg0, lparg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1bus_1own_1name_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1dbus_1connection_1register_1object +JNIEXPORT jint JNICALL WebKitGTK_NATIVE(_1g_1dbus_1connection_1register_1object) + (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1, jintLong arg2, jintLongArray arg3, jintLong arg4, jintLong arg5, jintLongArray arg6) +{ + jbyte *lparg1=NULL; + jintLong *lparg3=NULL; + jintLong *lparg6=NULL; + jint rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1dbus_1connection_1register_1object_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; + if (arg3) if ((lparg3 = (*env)->GetIntLongArrayElements(env, arg3, NULL)) == NULL) goto fail; + if (arg6) if ((lparg6 = (*env)->GetIntLongArrayElements(env, arg6, NULL)) == NULL) goto fail; +/* + rc = (jint)g_dbus_connection_register_object(arg0, lparg1, arg2, lparg3, arg4, arg5, lparg6); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_dbus_connection_register_object) + if (fp) { + rc = (jint)((jint (CALLING_CONVENTION*)(jintLong, jbyte *, jintLong, jintLong *, jintLong, jintLong, jintLong *))fp)(arg0, lparg1, arg2, lparg3, arg4, arg5, lparg6); + } + } +fail: + if (arg6 && lparg6) (*env)->ReleaseIntLongArrayElements(env, arg6, lparg6, 0); + if (arg3 && lparg3) (*env)->ReleaseIntLongArrayElements(env, arg3, lparg3, 0); + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1dbus_1connection_1register_1object_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1dbus_1method_1invocation_1return_1value +JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1g_1dbus_1method_1invocation_1return_1value) + (JNIEnv *env, jclass that, jintLong arg0, jintLong arg1) +{ + WebKitGTK_NATIVE_ENTER(env, that, _1g_1dbus_1method_1invocation_1return_1value_FUNC); +/* + g_dbus_method_invocation_return_value(arg0, arg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_dbus_method_invocation_return_value) + if (fp) { + ((void (CALLING_CONVENTION*)(jintLong, jintLong))fp)(arg0, arg1); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1dbus_1method_1invocation_1return_1value_FUNC); +} +#endif + +#ifndef NO__1g_1dbus_1node_1info_1lookup_1interface +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1dbus_1node_1info_1lookup_1interface) + (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1) +{ + jbyte *lparg1=NULL; + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1dbus_1node_1info_1lookup_1interface_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + rc = (jintLong)g_dbus_node_info_lookup_interface(arg0, lparg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_dbus_node_info_lookup_interface) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong, jbyte *))fp)(arg0, lparg1); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1dbus_1node_1info_1lookup_1interface_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1dbus_1node_1info_1new_1for_1xml +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1dbus_1node_1info_1new_1for_1xml) + (JNIEnv *env, jclass that, jbyteArray arg0, jintLongArray arg1) +{ + jbyte *lparg0=NULL; + jintLong *lparg1=NULL; + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1dbus_1node_1info_1new_1for_1xml_FUNC); + if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; + if (arg1) if ((lparg1 = (*env)->GetIntLongArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + rc = (jintLong)g_dbus_node_info_new_for_xml(lparg0, lparg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_dbus_node_info_new_for_xml) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jbyte *, jintLong *))fp)(lparg0, lparg1); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseIntLongArrayElements(env, arg1, lparg1, 0); + if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1dbus_1node_1info_1new_1for_1xml_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1boolean +JNIEXPORT jboolean JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1boolean) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jboolean rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1boolean_FUNC); +/* + rc = (jboolean)g_variant_get_boolean(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_boolean) + if (fp) { + rc = (jboolean)((jboolean (CALLING_CONVENTION*)(jintLong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1boolean_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1byte +JNIEXPORT jbyte JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1byte) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jbyte rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1byte_FUNC); +/* + rc = (jbyte)g_variant_get_byte(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_byte) + if (fp) { + rc = (jbyte)((jbyte (CALLING_CONVENTION*)(jintLong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1byte_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1child_1value +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1child_1value) + (JNIEnv *env, jclass that, jintLong arg0, jint arg1) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1child_1value_FUNC); +/* + rc = (jintLong)g_variant_get_child_value(arg0, arg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_child_value) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong, jint))fp)(arg0, arg1); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1child_1value_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1double +JNIEXPORT jdouble JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1double) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jdouble rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1double_FUNC); +/* + rc = (jdouble)g_variant_get_double(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_double) + if (fp) { + rc = (jdouble)((jdouble (CALLING_CONVENTION*)(jintLong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1double_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1string +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1string) + (JNIEnv *env, jclass that, jintLong arg0, jlongArray arg1) +{ + jlong *lparg1=NULL; + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1string_FUNC); + if (arg1) if ((lparg1 = (*env)->GetLongArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + rc = (jintLong)g_variant_get_string(arg0, lparg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_string) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong, jlong *))fp)(arg0, lparg1); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseLongArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1string_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1type +JNIEXPORT jint JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1type) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jint rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1type_FUNC); +/* + rc = (jint)g_variant_get_type(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_type) + if (fp) { + rc = (jint)((jint (CALLING_CONVENTION*)(jintLong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1type_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1get_1type_1string +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1get_1type_1string) + (JNIEnv *env, jclass that, jintLong arg0) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1get_1type_1string_FUNC); +/* + rc = (jintLong)g_variant_get_type_string(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_get_type_string) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1get_1type_1string_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1is_1of_1type +JNIEXPORT jboolean JNICALL WebKitGTK_NATIVE(_1g_1variant_1is_1of_1type) + (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1) +{ + jbyte *lparg1=NULL; + jboolean rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1is_1of_1type_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + rc = (jboolean)g_variant_is_of_type(arg0, lparg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_is_of_type) + if (fp) { + rc = (jboolean)((jboolean (CALLING_CONVENTION*)(jintLong, jbyte *))fp)(arg0, lparg1); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1is_1of_1type_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1n_1children +JNIEXPORT jlong JNICALL WebKitGTK_NATIVE(_1g_1variant_1n_1children) + (JNIEnv *env, jclass that, jlong arg0) +{ + jlong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1n_1children_FUNC); +/* + rc = (jlong)g_variant_n_children(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_n_children) + if (fp) { + rc = (jlong)((jlong (CALLING_CONVENTION*)(jlong))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1n_1children_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1boolean +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1boolean) + (JNIEnv *env, jclass that, jboolean arg0) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1boolean_FUNC); +/* + rc = (jintLong)g_variant_new_boolean(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_boolean) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jboolean))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1boolean_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1byte +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1byte) + (JNIEnv *env, jclass that, jbyte arg0) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1byte_FUNC); +/* + rc = (jintLong)g_variant_new_byte(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_byte) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jbyte))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1byte_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1double +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1double) + (JNIEnv *env, jclass that, jdouble arg0) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1double_FUNC); +/* + rc = (jintLong)g_variant_new_double(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_double) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jdouble))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1double_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1int32 +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1int32) + (JNIEnv *env, jclass that, jint arg0) +{ + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1int32_FUNC); +/* + rc = (jintLong)g_variant_new_int32(arg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_int32) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jint))fp)(arg0); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1int32_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1string +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1string) + (JNIEnv *env, jclass that, jbyteArray arg0) +{ + jbyte *lparg0=NULL; + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1string_FUNC); + if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail; +/* + rc = (jintLong)g_variant_new_string(lparg0); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_string) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jbyte *))fp)(lparg0); + } + } +fail: + if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1string_FUNC); + return rc; +} +#endif + +#ifndef NO__1g_1variant_1new_1tuple +JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1g_1variant_1new_1tuple) + (JNIEnv *env, jclass that, jintLongArray arg0, jlong arg1) +{ + jintLong *lparg0=NULL; + jintLong rc = 0; + WebKitGTK_NATIVE_ENTER(env, that, _1g_1variant_1new_1tuple_FUNC); + if (arg0) if ((lparg0 = (*env)->GetIntLongArrayElements(env, arg0, NULL)) == NULL) goto fail; +/* + rc = (jintLong)g_variant_new_tuple(lparg0, arg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, g_variant_new_tuple) + if (fp) { + rc = (jintLong)((jintLong (CALLING_CONVENTION*)(jintLong *, jlong))fp)(lparg0, arg1); + } + } +fail: + if (arg0 && lparg0) (*env)->ReleaseIntLongArrayElements(env, arg0, lparg0, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1g_1variant_1new_1tuple_FUNC); + return rc; +} +#endif + #ifndef NO__1soup_1auth_1authenticate JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1soup_1auth_1authenticate) (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1, jbyteArray arg2) @@ -2420,6 +2859,46 @@ JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1context_1set_1favicon } #endif +#ifndef NO__1webkit_1web_1context_1set_1web_1extensions_1directory +JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1web_1context_1set_1web_1extensions_1directory) + (JNIEnv *env, jclass that, jintLong arg0, jbyteArray arg1) +{ + jbyte *lparg1=NULL; + WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1context_1set_1web_1extensions_1directory_FUNC); + if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail; +/* + webkit_web_context_set_web_extensions_directory(arg0, lparg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, webkit_web_context_set_web_extensions_directory) + if (fp) { + ((void (CALLING_CONVENTION*)(jintLong, jbyte *))fp)(arg0, lparg1); + } + } +fail: + if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0); + WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1context_1set_1web_1extensions_1directory_FUNC); +} +#endif + +#ifndef NO__1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data +JNIEXPORT void JNICALL WebKitGTK_NATIVE(_1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data) + (JNIEnv *env, jclass that, jlong arg0, jlong arg1) +{ + WebKitGTK_NATIVE_ENTER(env, that, _1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data_FUNC); +/* + webkit_web_context_set_web_extensions_initialization_user_data(arg0, arg1); +*/ + { + WebKitGTK_LOAD_FUNCTION(fp, webkit_web_context_set_web_extensions_initialization_user_data) + if (fp) { + ((void (CALLING_CONVENTION*)(jlong, jlong))fp)(arg0, arg1); + } + } + WebKitGTK_NATIVE_EXIT(env, that, _1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data_FUNC); +} +#endif + #ifndef NO__1webkit_1web_1data_1source_1get_1data JNIEXPORT jintLong JNICALL WebKitGTK_NATIVE(_1webkit_1web_1data_1source_1get_1data) (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 new file mode 100644 index 0000000000..81abcffd73 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.c @@ -0,0 +1,335 @@ +#include "webkitgtk_extension.h" + +/** + * Note: g_asserts() are active/working. (i.e not dissabled) + */ + +// +-------------+---------------------------------------------------------------- +// | Misc Globals| +// +-------------+ +gint32 parentUniqueId = 0; + +// see: WebKitGTK.java 'TYPE NOTES' +guchar SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY = 101; +guchar SWT_DBUS_MAGIC_NUMBER_NULL = 48; + + +// +-------------+---------------------------------------------------------------- +// | Misc Helpers| +// +-------------+ + +/* Combine String and int. + * @return char * should be free()'ed. + */ +char * combineStrInt(char * in_str, gint32 in_i) { + int new_str_len = strlen(in_str) + snprintf(NULL, 0, "%d", in_i) + 1; // str + int + \0 + char * out_str = malloc (new_str_len); + snprintf( out_str, new_str_len, "%s%d", in_str, in_i); + return out_str; +} + +// +-------------+---------------------------------------------------------------- +// | GDBus logic | +// +-------------+ +static const gchar base_service_name[] = "org.eclipse.swt"; // Base name. Full name has uniqueID appended. +static const gchar object_name[] = "/org/eclipse/swt/gdbus"; +static const gchar interface[] = "org.eclipse.swt.gdbusInterface"; + +GDBusProxy *proxy = NULL; // The proxy that we work with + +void proxy_init () { + g_assert(parentUniqueId != 0); + + if (proxy != NULL) { // Already initialized. + return; + } + const char * full_service_name = combineStrInt((char *) base_service_name, parentUniqueId); + + GError *error = NULL; // Some functions return errors through params + + // g_type_init(); // Not needed as of glib 2.36 + proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, full_service_name, object_name, interface, NULL, &error); + if ((proxy == NULL) || (error != NULL)) { + fprintf(stderr, "SWT Webextension: GDBus setupServer error. Could not connect to %s:%s on %s.\n", full_service_name, object_name, interface); + if (error != NULL) { + fprintf(stderr, " %s\n", error->message); + } + exit(0); + } +} + + +/** + * Caller should free the returned GVariant *. + */ +GVariant * callMainProc(char * methodName, GVariant * params) { + proxy_init(); + GError *error = NULL; // Some functions return errors through params + GVariant *result; // The value result from a call + + // Send a message + result = g_dbus_proxy_call_sync(proxy, methodName, params, 0, -1, NULL, &error); // You can make multiple calls + + // 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"); + return NULL; + } + + // Deal with result + return result; +} + + +// +--------------------------------------------------+------------------------------------- +// | JavaScriptCore to/from conversion GVariant logic | +// +--------------------------------------------------+ + +/** Return true if the given JSValueRef is one we can push over gdbus. False otherwise. + * We support basic types, nulls and arrays of basic types.*/ +gboolean is_js_valid(JSContextRef context, JSValueRef value) { + JSType type = JSValueGetType(context, value); + if (type == kJSTypeBoolean + || type == kJSTypeNumber + || type == kJSTypeString + || type == kJSTypeNull + || type == kJSTypeUndefined) { + return true; + } + if (type == kJSTypeObject && JSValueIsArray(context, value)) { + JSStringRef propertyName = JSStringCreateWithUTF8CString("length"); + JSObjectRef object = JSValueToObject(context, value, NULL); + JSValueRef valuePtr = JSObjectGetProperty(context, object, propertyName, NULL); + JSStringRelease(propertyName); + int length = (int) JSValueToNumber(context, valuePtr, NULL); + for (int i = 0; i < length; i++) { + const JSValueRef child = JSObjectGetPropertyAtIndex(context, object, i, NULL); + if (!is_js_valid(context, child)) { + return false; + } + } + return true; + } + return false; +} + +/* + * Developer note: + * JavaScriptCore defines a "Number" to be a double in general. It doesn't seem to be using "Int". + */ +static GVariant * convert_js_to_gvariant (JSContextRef context, JSValueRef value){ + g_assert(context != NULL); + g_assert(value != NULL); + JSType type = JSValueGetType(context, value); + + if (type == kJSTypeBoolean) { + gboolean result = JSValueToNumber(context, value, NULL) != 0; + return g_variant_new_boolean(result); + } + + if (type == kJSTypeNumber) { + double result = JSValueToNumber(context, value, NULL); + return g_variant_new_double(result); + } + + if (type == kJSTypeString) { + JSStringRef stringRef = JSValueToStringCopy(context, value, NULL); + size_t length = JSStringGetMaximumUTF8CStringSize(stringRef); + char* string = (char*) malloc(length); + JSStringGetUTF8CString(stringRef, string, length); + GVariant *variant = g_variant_new_string(string); + free(string); + return variant; + } + + if (type == kJSTypeNull || type == kJSTypeUndefined) { + return g_variant_new_byte(SWT_DBUS_MAGIC_NUMBER_NULL); + } + + if (type == kJSTypeObject) { + JSStringRef propertyName = JSStringCreateWithUTF8CString("length"); + JSObjectRef object = JSValueToObject(context, value, NULL); + JSValueRef valuePtr = JSObjectGetProperty(context, object, propertyName, NULL); + JSStringRelease(propertyName); + + if (JSValueGetType(context, valuePtr) == kJSTypeNumber) { + int length = (int) JSValueToNumber(context, valuePtr, NULL); + + if (length == 0) { + return g_variant_new_byte(SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY); + } + GVariant **children = g_new(GVariant *, length); + int i = 0; + for (i = 0; i < length; i++) { + const JSValueRef child = JSObjectGetPropertyAtIndex(context, object, i, NULL); + children[i] = convert_js_to_gvariant(context, child); + } + GVariant* variant = g_variant_new_tuple(children, length); + g_free(children); + return variant; + } + } + + // Get type value string + JSStringRef valueIString = JSValueToStringCopy(context, value, NULL); + size_t valueUTF8Size = JSStringGetMaximumUTF8CStringSize(valueIString); + char* valueUTF8 = (char*) malloc(valueUTF8Size); + JSStringGetUTF8CString(valueIString, valueUTF8, valueUTF8Size); + + g_warning("SWT Webextension: Unhandled type %d value: %s \n", type, valueUTF8); + free(valueUTF8); + JSStringRelease(valueIString); + + return NULL; +} + + +static JSValueRef convert_gvariant_to_js (JSContextRef context, GVariant * value){ + g_assert(context != NULL); + g_assert(value != NULL); + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_BYTE)) { // see: WebKitGTK.java 'TYPE NOTES' + guchar magic_number = g_variant_get_byte(value); + if (magic_number == SWT_DBUS_MAGIC_NUMBER_NULL) { + // 'JSValueMakeUndefined' is used as oppose to 'JSValueMakeNull' (from what I gather) for legacy reasons. + // I.e webkit1 used it, so we shall use it in webkit2 also. + return JSValueMakeUndefined(context); + } else if (magic_number == SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY) { + return JSObjectMakeArray(context, 0, NULL, NULL); // The empty array with no children. + } else { + g_error("Java sent an unknown magic number: '%d' , this should never happen. \n", magic_number); + } + } + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) { + return JSValueMakeBoolean(context, g_variant_get_boolean(value)); + } + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_DOUBLE)) { + return JSValueMakeNumber(context, g_variant_get_double(value)); + } + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + JSStringRef stringRef = JSStringCreateWithUTF8CString(g_variant_get_string(value, NULL)); + JSValueRef result = JSValueMakeString(context, stringRef); + JSStringRelease(stringRef); + return result; + } + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_TUPLE)) { + gsize length = (int) g_variant_n_children(value); + JSValueRef *children = g_new(JSValueRef, length); + + int i = 0; + for (i = 0; i < length; i++) { + children[i] = convert_gvariant_to_js(context, g_variant_get_child_value(value, i)); + } + JSValueRef result = JSObjectMakeArray(context, length, children, NULL); + g_free(children); + return result; + } + g_error("Unhandled type %s \n", g_variant_get_type_string(value)); + return NULL; +} + +// +--------------------+--------------------------------------------------------- +// | WebExtension Logic | +// +--------------------+ + +// Reached by calling "webkit2callJava();" in javascript console. +// Some basic c function to be exposed to the javascript environment +static JSValueRef webkit2callJava (JSContextRef context, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], // [String webview, double index, String Token, Object[] args] + JSValueRef *exception) { + g_assert (argumentCount == 4); + GVariant *g_var_params; // The parameters to a function call + + // Need to ensure user arguments won't break gdbus. + if (!is_js_valid(context, arguments[3])) { + g_warning("SWT Webextension: Arguments contain an invalid type (object). Only Number,Boolean,null,String and (mixed) arrays of basic types are supported"); + return 0; + } + + g_var_params = g_variant_new ("(@s@d@s@*)", // pointer to String, pointer to double, pointer to string, pointer to any type. + convert_js_to_gvariant(context, arguments[0]), // String webView + convert_js_to_gvariant(context, arguments[1]), // int index + convert_js_to_gvariant(context, arguments[2]), // String Token + convert_js_to_gvariant(context, arguments[3]) // js args + ); + + GVariant *g_var_result = callMainProc("webkit2callJava", g_var_params); + if (g_var_result == NULL) { + g_error("SWT Webextension: Java call returned NULL. This should never happpen\n"); + return 0; + } + + // gdbus dynamic call always returns an array(tuple) with return types. + // In our case, we return a single type or an array. + // E.g java:int -> gdbus:(i) (array containing one int) + // E.g java [int,str] -> gdbus:((is)) (array with array of (int+str). + // So we always extract the first child, convert and pass to js. + JSValueRef retVal = 0; + if (g_variant_is_of_type(g_var_result, G_VARIANT_TYPE_TUPLE)) { + if (g_variant_n_children(g_var_result) != 1) { + g_error("Should only receive a single item in the tuple, but length is: %lu\n", g_variant_n_children(g_var_result)); + } + retVal = convert_gvariant_to_js(context, g_variant_get_child_value(g_var_result, 0)); + } else { + g_error("SWT Webextension: Unsupported return type. Should be an array, but received a single type.\n"); + } + + g_variant_unref(g_var_result); + return retVal; +} + + +/* + * Everytime a webpage is loaded, we should re-register the 'webkit2callJava' function. + */ +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; + JSObjectRef globalObject; + JSValueRef exception = 0; + + jsContext = webkit_frame_get_javascript_context_for_script_world (frame, world); + globalObject = JSContextGetGlobalObject (jsContext); + + JSStringRef function_name = JSStringCreateWithUTF8CString("webkit2callJava"); // Func reference by javascript + JSObjectRef jsFunction = JSObjectMakeFunctionWithCallback(jsContext, function_name, webkit2callJava); // C reference to func + JSObjectSetProperty(jsContext, globalObject, function_name, jsFunction, + kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly, &exception); + + if (exception) { + g_print("OJSObjectSetProperty exception occurred"); + } +} + +static void web_page_created_callback(WebKitWebExtension *extension, WebKitWebPage *web_page, gpointer user_data) { + // Observation. This seems to be called only once. +} + +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()); + + 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); +} 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 new file mode 100644 index 0000000000..72a507ba81 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/library/webkitgtk_extension.h @@ -0,0 +1,63 @@ +/******************************************************************************* + * 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 + * 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 + *******************************************************************************/ + + +#ifndef INC_webkit_extension_H +#define INC_webkit_extension_H + + +#include <string.h> + +#include <glib.h> +#include <glib/gprintf.h> + +#include <gio/gio.h> +#include <stdlib.h> + +#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> +#include <JavaScriptCore/JSContextRef.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSStringRef.h> + + + + + + + + + + + + + + + + + + + +#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 098a4d5cd0..dd9b40f21d 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 @@ -52,6 +52,26 @@ char * WebKitGTK_nativeFunctionNames[] = { "_1SoupMessage_1method", "_1SoupMessage_1request_1body", "_1SoupMessage_1request_1headers", + "_1g_1bus_1own_1name", + "_1g_1dbus_1connection_1register_1object", + "_1g_1dbus_1method_1invocation_1return_1value", + "_1g_1dbus_1node_1info_1lookup_1interface", + "_1g_1dbus_1node_1info_1new_1for_1xml", + "_1g_1variant_1get_1boolean", + "_1g_1variant_1get_1byte", + "_1g_1variant_1get_1child_1value", + "_1g_1variant_1get_1double", + "_1g_1variant_1get_1string", + "_1g_1variant_1get_1type", + "_1g_1variant_1get_1type_1string", + "_1g_1variant_1is_1of_1type", + "_1g_1variant_1n_1children", + "_1g_1variant_1new_1boolean", + "_1g_1variant_1new_1byte", + "_1g_1variant_1new_1double", + "_1g_1variant_1new_1int32", + "_1g_1variant_1new_1string", + "_1g_1variant_1new_1tuple", "_1soup_1auth_1authenticate", "_1soup_1auth_1get_1host", "_1soup_1auth_1get_1scheme_1name", @@ -142,6 +162,8 @@ char * WebKitGTK_nativeFunctionNames[] = { "_1webkit_1web_1context_1get_1type", "_1webkit_1web_1context_1get_1website_1data_1manager", "_1webkit_1web_1context_1set_1favicon_1database_1directory", + "_1webkit_1web_1context_1set_1web_1extensions_1directory", + "_1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data", "_1webkit_1web_1data_1source_1get_1data", "_1webkit_1web_1data_1source_1get_1encoding", "_1webkit_1web_1frame_1get_1data_1source", 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 ea31d0f41e..55329c3581 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 @@ -62,6 +62,26 @@ typedef enum { _1SoupMessage_1method_FUNC, _1SoupMessage_1request_1body_FUNC, _1SoupMessage_1request_1headers_FUNC, + _1g_1bus_1own_1name_FUNC, + _1g_1dbus_1connection_1register_1object_FUNC, + _1g_1dbus_1method_1invocation_1return_1value_FUNC, + _1g_1dbus_1node_1info_1lookup_1interface_FUNC, + _1g_1dbus_1node_1info_1new_1for_1xml_FUNC, + _1g_1variant_1get_1boolean_FUNC, + _1g_1variant_1get_1byte_FUNC, + _1g_1variant_1get_1child_1value_FUNC, + _1g_1variant_1get_1double_FUNC, + _1g_1variant_1get_1string_FUNC, + _1g_1variant_1get_1type_FUNC, + _1g_1variant_1get_1type_1string_FUNC, + _1g_1variant_1is_1of_1type_FUNC, + _1g_1variant_1n_1children_FUNC, + _1g_1variant_1new_1boolean_FUNC, + _1g_1variant_1new_1byte_FUNC, + _1g_1variant_1new_1double_FUNC, + _1g_1variant_1new_1int32_FUNC, + _1g_1variant_1new_1string_FUNC, + _1g_1variant_1new_1tuple_FUNC, _1soup_1auth_1authenticate_FUNC, _1soup_1auth_1get_1host_FUNC, _1soup_1auth_1get_1scheme_1name_FUNC, @@ -152,6 +172,8 @@ typedef enum { _1webkit_1web_1context_1get_1type_FUNC, _1webkit_1web_1context_1get_1website_1data_1manager_FUNC, _1webkit_1web_1context_1set_1favicon_1database_1directory_FUNC, + _1webkit_1web_1context_1set_1web_1extensions_1directory_FUNC, + _1webkit_1web_1context_1set_1web_1extensions_1initialization_1user_1data_FUNC, _1webkit_1web_1data_1source_1get_1data_FUNC, _1webkit_1web_1data_1source_1get_1encoding_FUNC, _1webkit_1web_1frame_1get_1data_1source_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 31e78883a2..cfaa619f34 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 @@ -44,6 +44,14 @@ class WebKit extends WebBrowser { byte[] htmlBytes; BrowserFunction eventFunction; //Webkit1 only. + static final String reportErrMsg = "Please report this issue via: https://bugs.eclipse.org/bugs/enter_bug.cgi?" + + "alias=&assigned_to=platform-swt-inbox%40eclipse.org&attach_text=&blocked=&bug_file_loc=http%3A%2F%2F&bug_severity=normal" + + "&bug_status=NEW&comment=&component=SWT&contenttypeentry=&contenttypemethod=autodetect&contenttypeselection=text%2Fplain" + + "&data=&defined_groups=1&dependson=&description=&flag_type-1=X&flag_type-11=X&flag_type-12=X&flag_type-13=X&flag_type-14=X" + + "&flag_type-15=X&flag_type-16=X&flag_type-2=X&flag_type-4=X&flag_type-6=X&flag_type-7=X&flag_type-8=X&form_name=enter_bug" + + "&keywords=&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Linux&product=Platform&qa_contact=" + + "&rep_platform=PC&requestee_type-1=&requestee_type-2=&short_desc=[webkit2]BrowserProblem"; + static boolean bug522733FirstInstanceCreated = false; //Webkit2 workaround for Bug 522733 /** @@ -169,7 +177,7 @@ class WebKit extends WebBrowser { } if (WEBKIT2) { - new Webkit2JavaCallback(); + Webkit2Extension.init(); } else { JSObjectHasPropertyProc = new Callback (WebKit.class, "JSObjectHasPropertyProc", 3); //$NON-NLS-1$ if (JSObjectHasPropertyProc.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); @@ -292,100 +300,156 @@ 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); + return; + } + } + super.createFunction(function); + } /** - * For javascript to call java. - * This callback is special in that we link Javascript to a C function and a C function to - * the SWT java function. - * - * Note there is an architecture difference how callJava is implemented in Webkit1 vs Webkit2: + * This class deals with the Webkit2 extension. * - * Webkit1: See JSObjectHasPropertyProc. - * - * Webkit2: - callJava is implemented by connecting and calling a webkit signal: - * - webkit2JavaCallProc is linked from C to java. - * - Each webkit instance connects a signal (Webkit2JavaCallback.signal) to Webkit2JavaCallback.webkit2JavaCallProc - * via Webkit2JavaCallback.connectSignal(..) - * - (Note, webView is created with user_content_manager on webkit2.) - * - callJava is a wrapper that calls window.webkit.messageHandlers.webkit2JavaCallProc.postMessage([index,token, args]), - * which triggers the script-message-received::webkit2JavaCallProc signal and is forwarded to webkit2JavaCallProc. - **/ - static class Webkit2JavaCallback { - private static final String JavaScriptFunctionName = "webkit2JavaCallProc"; // $NON-NLS-1$ - private static final String Signal = "script-message-received::" + JavaScriptFunctionName; // $NON-NLS-1$ - - static final String JavaScriptFunctionDeclaration = - "if (!window.callJava) {\n" - + " window.callJava = function callJava(index, token, args) {\n" - + " window.webkit.messageHandlers." + JavaScriptFunctionName + ".postMessage([index,token, args]);\n" - + " }\n" - + "};\n"; - - private static Callback callback; - static { - callback = new Callback (Webkit2JavaCallback.class, JavaScriptFunctionName, void.class, new Type[] {long.class, long.class, long.class}); - if (callback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); - } + * Extension is separately loaded and deals Javascript callbacks to Java. + * Extension is needed so that Javascript can receive a return value from Java + * (for which currently there is no api in WebkitGtk 2.18) + */ + 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 Callback initializeWebExtensions_callback; + private static int uniqueID = OS.getpid(); /** - * This method is called directly from javascript via something like: <br> - * window.webkit.messageHandlers.webkit2JavaCallProc.postMessage('helloWorld') <br> - * - Note, this method is async when called from javascript. <br> - * - This method name MUST match: this.JavaScriptFunctionName <br> - * - This method somewhat mirrors 'long callJava(ctx,func...)'. Except that it doesn't return a value. - * Docu: <br> - * https://webkitgtk.org/reference/webkit2gtk/stable/WebKitUserContentManager.html#WebKitUserContentManager-script-message-received - * */ - @SuppressWarnings("unused") // Method is called only directly from javascript. - private static void webkit2JavaCallProc (long /*int*/ WebKitUserContentManagerPtr, long /*int*/ WebKitJavascriptResultPtr, long /*int*/ webViewPtr) { - try { - long /*int*/ context = WebKitGTK.webkit_javascript_result_get_global_context (WebKitJavascriptResultPtr); - long /*int*/ value = WebKitGTK.webkit_javascript_result_get_value (WebKitJavascriptResultPtr); - Object[] arguments = (Object[]) convertToJava(context, value); - if (arguments.length != 3) throw new IllegalArgumentException("Expected 3 args. Received: " + arguments.length); + * Don't continue initialization if something failed. This allows Browser to carryout some functionality + * even if the webextension failed to load. + */ + private static boolean loadFailed; - Double index = (Double) arguments[0]; - String token = (String) arguments[1]; + static String getJavaScriptFunctionName() { + return javaScriptFunctionName; + } + static String getJavaScriptFunctionDeclaration(long /*int*/ webView) { + return "if (!window.callJava) {\n" + + " window.callJava = function callJava(index, token, args) {\n" + + " return " + javaScriptFunctionName + "('" + String.valueOf(webView) + "', index, token, args);\n" + + " }\n" + + "};\n"; + } - Browser browser = FindBrowser(webViewPtr); - if (browser == null) throw new NullPointerException("Could not find assosiated browser instance for handle: " + webViewPtr); + static void 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); + OS.g_signal_connect (WebKitGTK.webkit_web_context_get_default(), WebKitGTK.initialize_web_extensions, initializeWebExtensions_callback.getAddress(), 0); + } + + /** + * GDbus initialization can cause performance slow downs. So we int GDBus in lazy way. + * It can be initialized upon first use of BrowserFunction. + */ + static boolean gdbus_init() { + if (!loadFailed) { + WebkitGDBus.init(String.valueOf(uniqueID)); + return true; + } else { + return false; + } + } - BrowserFunction function = browser.webBrowser.functions.get(index.intValue()); + /** + * This callback is called to initialize webextension. + * It is the optimum place to set extension directory and set initialization user data. + * + * I've experimented with loading webextension later (to see if we can get performance gains), + * but found breakage. Webkitgtk doc says it should be loaded as early as possible and specifically best + * to do it in this calllback. + * + * See documenation: WebKitWebExtension (Description) + */ + @SuppressWarnings("unused") // Only called directly from C + private static void initializeWebExtensions_callback (long /*int*/ WebKitWebContext, long /*int*/ user_data) { + + // 1) GDBus: + // Normally we'd first initialize gdbus channel. But gdbus makes Browser slower and isn't always needed. + // So WebkitGDBus is lazy-initialized, although it can be initialized here if gdbus is ever needed + // for more than BrowserFunction, like: + // WebkitGDBus.init(String.valueOf(uniqueID)); + // Also consider only loading gdbus if the extension initialized properly. + + // 2) Load Webkit Extension: + // Webkit extensions should be in their own directory. + String swtVersion = Library.getVersionString(); + File extension = Library.findResource("webkitextensions" + swtVersion,"swt-webkit2extension", true); + if (extension == null){ + System.err.println("SWT Webkit.java Error: Could not find webkit extension. BrowserFunction functionality will not be available. \n" + + "(swt version: " + swtVersion + ")"); + int [] vers = internalGetWebkitVersion(); + System.err.println(String.format("WebKit2Gtk version %s.%s.%s", vers[0], vers[1], vers[2])); + System.err.println(reportErrMsg); + loadFailed = true; + return; + } - if (function == null) throw new NullPointerException("Could not find function with index: " + index); - if (!token.equals(function.token)) throw new IllegalStateException("Function token missmatch. Expected:" + function.token + " actual:" + token); - if (! (arguments[2] instanceof Object[])) { - throw new IllegalArgumentException("Javascript did not provide any arguments. An empty callback [like call()] should still provide an empty array"); - } + String extensionsFolder = extension.getParent(); - try { - // TODO someday : Support return values. See Bug 510905 - function.function ((Object[]) arguments[2]); - } catch (Exception e) { - // Exception in user function. - // Normally we would return an error to javascript. See callJava(..). - // But support for returning item back to java not implemented yet. - } + /* Dev note: + * As per + * - WebkitSrc: WebKitExtensionManager.cpp, + * - IRC discussion with annulen + * you cannot load the webextension GModule directly, (webkitgtk 2.18). You can only specify directory and user data. + * So we need to treat this '.so' in a special way. + * (as a note, the webprocess would have to load the gmodule). + */ + WebKitGTK.webkit_web_context_set_web_extensions_directory(WebKitGTK.webkit_web_context_get_default(), Converter.wcsToMbcs (extensionsFolder, true)); + long /*int*/ gvariantUserData = WebKitGTK.g_variant_new_int32(uniqueID); + WebKitGTK.webkit_web_context_set_web_extensions_initialization_user_data(WebKitGTK.webkit_web_context_get_default(), gvariantUserData); - } catch (RuntimeException e) { - System.err.println("\nSWT Webkit2 internal error: Javascript callback from Webkit to Java encountered an error while processing the callback:"); - System.err.println("Please report this via: https://bugs.eclipse.org/bugs/enter_bug.cgi?alias=&assigned_to=platform-swt-inbox%40eclipse.org&attach_text=&blocked=&bug_file_loc=http%3A%2F%2F&bug_severity=normal&bug_status=NEW&comment=&component=SWT&contenttypeentry=&contenttypemethod=autodetect&contenttypeselection=text%2Fplain&data=&defined_groups=1&dependson=&description=&flag_type-1=X&flag_type-11=X&flag_type-12=X&flag_type-13=X&flag_type-14=X&flag_type-15=X&flag_type-16=X&flag_type-2=X&flag_type-4=X&flag_type-6=X&flag_type-7=X&flag_type-8=X&form_name=enter_bug&keywords=&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Linux&product=Platform&qa_contact=&rep_platform=PC&requestee_type-1=&requestee_type-2=&short_desc=&version=4.7"); - e.printStackTrace(); - } - return; } - /** Connect an instance of a webkit to the callback. */ - static void connectSignal(long /*int*/ WebKitUserContentManager, long /*int*/ webView) { - OS.g_signal_connect (WebKitUserContentManager, Converter.wcsToMbcs (Signal, true), callback.getAddress (), webView); - WebKitGTK.webkit_user_content_manager_register_script_message_handler(WebKitUserContentManager, Converter.wcsToMbcs(JavaScriptFunctionName, true)); + /** + * @param cb_args Raw callback arguments by function. + */ + static Object webkit2callJavaCallback(Object [] cb_args) { + assert cb_args.length == 4; + Object returnValue = null; + + Long webViewLocal = (Double.valueOf((String) cb_args[0])).longValue(); + Browser browser = FindBrowser((long /*int*/) webViewLocal.longValue()); + Integer functionIndex = ((Double) cb_args[1]).intValue(); + String token = (String) cb_args[2]; + + BrowserFunction function = browser.webBrowser.functions.get(functionIndex); + if (function == null) { + System.err.println("SWT Webkit Error: Failed to find function with index: " + functionIndex); + return null; + } + if (!function.token.equals(token)) { + System.err.println("SWT Webkit Error: token mismatch for function with index: " + functionIndex); + return null; + } + try { + // Call user code. Exceptions can occur. + Object [] user_args = (Object []) cb_args[3]; + returnValue = function.function(user_args); + } catch (Exception e ) { + // - Something went wrong in user code. + // - Dev note, webkit1 uses a browserFunction and function.isEvaluate for evaluate(), + // webkit2 doesn't, so we don't have 'if (function.isEvaluate)' logic here. + System.err.println("SWT Webkit: Exception occured in user code of function: " + function.name); + returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ()); + } + return returnValue; } } @Override String getJavaCallDeclaration() { if (WEBKIT2) { - return Webkit2JavaCallback.JavaScriptFunctionDeclaration; + return Webkit2Extension.getJavaScriptFunctionDeclaration(webView); } else { return super.getJavaCallDeclaration(); } @@ -837,14 +901,7 @@ public void create (Composite parent, int style) { OS.gtk_scrolled_window_set_policy (scrolledWindow, OS.GTK_POLICY_AUTOMATIC, OS.GTK_POLICY_AUTOMATIC); } - if (WEBKIT2) { - // On Webkit2, webView has to be created with UserContentManager so that Javascript callbacks work. See #508217 - long /*int*/ WebKitUserContentManager = WebKitGTK.webkit_user_content_manager_new(); - webView = WebKitGTK.webkit_web_view_new_with_user_content_manager (WebKitUserContentManager); - Webkit2JavaCallback.connectSignal(WebKitUserContentManager, webView); - } else { // Webkit1 - webView = WebKitGTK.webkit_web_view_new (); - } + webView = WebKitGTK.webkit_web_view_new (); // Bug 522733 Webkit2 workaround for crash // As of Webkitgtk 2.18, webkitgtk2 crashes if the first instance of webview is not referenced when JVM shuts down. 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 new file mode 100644 index 0000000000..db3244ee1a --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java @@ -0,0 +1,335 @@ +package org.eclipse.swt.browser; + +import org.eclipse.swt.*; +import org.eclipse.swt.internal.*; +import org.eclipse.swt.internal.webkit.*; + +/** + * Logic for Webkit to interact with it's Webkit extension via GDBus. + * + * While this class supports quite a bit of GDBus and gvariant support, it is by no means a complete + * implementation and it's tailored to support Java to Javascript conversion. (E.g all Numbers are converted to Double). + * If this is ever to be used outside of Webkit, then care must be taken to deal with + * cases that are not currently implemented/used. See: WebKitGTK.java 'TYPE NOTES' + * + * For hygiene purposes, GVariant types should not be leaving this class. Convert on the way in/out. + * + * @category gdbus + */ +class WebkitGDBus { + private static String DBUS_SERVICE_NAME; + private static final String DBUS_OBJECT_NAME = "/org/eclipse/swt/gdbus"; + private static final String INTERFACE_NAME = "org.eclipse.swt.gdbusInterface"; + + /** Accepted methods over gdbus */ + private static final String webkit2callJava = WebKit.Webkit2Extension.getJavaScriptFunctionName(); + + + /** + * Interface is read/parsed at run time. No compilation with gdbus-code-gen necessary. + * + * Note, + * - When calling a method via g_dbus_proxy_call_sync(..g_variant params..), + * the g_variant that describes parameters should only mirror incoming parameters. + * Each type is a separate argument. + * e.g: + * g_variant xml: + * "(si)", "string", 42 .. arg type='s' + * .. arg type='i' + * + * - Nested parameters need to have a 2nd bracket around them. + * e.g: + * g_variant xml: + * "((r)i)", *gvariant, 42 .. arg type='r' + * .. arg type='i' + * + * - '@' is a pointer to a gvariant. so '@r' is a pointer to nested type, i.e *gvariant + * + * To understand the mappings, it's good to understand DBus and GVariant's syntax: + * https://dbus.freedesktop.org/doc/dbus-specification.html#idm423 + * https://developer.gnome.org/glib/stable/glib-GVariantType.html + * + * Be mindful about only using supported DBUS_TYPE_* , as convert* methods might fail otherwise. + * Alternatively, modify convert* methods. + */ + private static final String dbus_introspection_xml = + "<node>" + + " <interface name='" + INTERFACE_NAME + "'>" + + " <method name='" + webkit2callJava + "'>" + + " <arg type='"+ WebKitGTK.DBUS_TYPE_STRING + "' name='webViewPtr' direction='in'/>" + + " <arg type='"+ WebKitGTK.DBUS_TYPE_DOUBLE + "' name='index' direction='in'/>" + + " <arg type='"+ WebKitGTK.DBUS_TYPE_STRING + "' name='token' direction='in'/>" + + " <arg type='" + WebKitGTK.DBUS_TYPE_SINGLE_COMPLETE + "' name='arguments' direction='in'/>" + + " <arg type='" + WebKitGTK.DBUS_TYPE_SINGLE_COMPLETE + "' name='result' direction='out'/>" + + " </method>" + + " </interface>" + + "</node>"; + + /** GDBusNodeInfo */ + private static Callback onBusAcquiredCallback; + private static Callback onNameAcquiredCallback; + private static Callback onNameLostCallback; + private static Callback handleMethodCallback; + + static { + onBusAcquiredCallback = new Callback (WebkitGDBus.class, "onBusAcquiredCallback", 3); //$NON-NLS-1$ + if (onBusAcquiredCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); + + onNameAcquiredCallback = new Callback (WebkitGDBus.class, "onNameAcquiredCallback", 3); //$NON-NLS-1$ + if (onNameAcquiredCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); + + onNameLostCallback = new Callback (WebkitGDBus.class, "onNameLostCallback", 3); //$NON-NLS-1$ + if (onNameLostCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); + + handleMethodCallback = new Callback (WebkitGDBus.class, "handleMethodCallback", 8); //$NON-NLS-1$ + if (handleMethodCallback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); + } + + static private boolean initialized; + static void init(String uniqueId) { + if (initialized) + return; + initialized = true; + DBUS_SERVICE_NAME = "org.eclipse.swt" + uniqueId; + int owner_id = WebKitGTK.g_bus_own_name(WebKitGTK.G_BUS_TYPE_SESSION, + Converter.javaStringToCString(DBUS_SERVICE_NAME), + WebKitGTK.G_BUS_NAME_OWNER_FLAGS_REPLACE | WebKitGTK.G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, + onBusAcquiredCallback.getAddress(), + onNameAcquiredCallback.getAddress(), // name_acquired_handler + onNameLostCallback.getAddress(), // name_lost_handler + 0, // user_data + 0); // user_data_free_func + + if (owner_id == 0) { + System.err.println("SWT WebkitGDBus: Failed to aquire bus name: " + DBUS_SERVICE_NAME); + } + } + + static void teardown_gdbus() { + // Currently GDBus is persistent across browser instances. + // If ever needed, gdbus can be disposed via: + // g_bus_unown_name (owner_id); // owner_id would need to be made global + // g_dbus_node_info_unref (gdBusNodeInfo); // introspection_data Would need to be made global + } + + /** + * @param connection GDBusConnection * + * @param name const gchar * + * @param user_data gpointer + * @return void. + */ + @SuppressWarnings("unused") // Callback Only called directly by JNI. + private static long /*int*/ onBusAcquiredCallback (long /*int*/ connection, long /*int*/ name, long /*int*/ user_data) { + long /*int*/ gdBusNodeInfo; + + // Parse XML + { + long /*int*/ [] error = new long /*int*/ [1]; + gdBusNodeInfo = WebKitGTK.g_dbus_node_info_new_for_xml(Converter.javaStringToCString(dbus_introspection_xml), error); + if (gdBusNodeInfo == 0 || error[0] != 0) { + System.err.println("SWT WebkitGDBus: Failed to get introspection data"); + } + assert gdBusNodeInfo != 0 : "SWT WebkitGDBus: introspection data should not be 0"; + } + + // Register object + { + long /*int*/ [] error = new long /*int*/ [1]; + long /*int*/ interface_info = WebKitGTK.g_dbus_node_info_lookup_interface(gdBusNodeInfo, Converter.javaStringToCString(INTERFACE_NAME)); + long /*int*/ vtable [] = { handleMethodCallback.getAddress(), 0, 0 }; + // SWT Dev Note: SWT Tool's "32/64 bit" checking mechanism sometimes get's confused by this method signature and shows an incorrect warning. + // Other times it validates it fine. We ignore for now as 32bit will be dropped anyway. + WebKitGTK.g_dbus_connection_register_object( + connection, + Converter.javaStringToCString(DBUS_OBJECT_NAME), + interface_info, + vtable, + 0, // user_data + 0, // user_data_free_func + error); + + if (error[0] != 0) { + System.err.println("SWT WebkitGDBus: Failed to register object: " + DBUS_OBJECT_NAME); + return 0; + } + } + + // Developer note: + // To verify that a gdbus interface is regisetered on the gdbus, you can use the 'gdbus' utility. + // e.g: + // gdbus introspect --session --dest org.eclipse <Press TAB KEY> // it should expand to something like: (uniqueID might be appended at the end). + // gdbus introspect --session --dest org.eclipse.swt // you can then get object info like: + // gdbus introspect --session --dest org.eclipse.swt --object-path /org/eclipse/swt/gdbus + + return 0; // Actual callback is void. + } + + + @SuppressWarnings("unused") // Callback Only called directly by JNI. + private static long /*int*/ onNameAcquiredCallback (long /*int*/ connection, long /*int*/ name, long /*int*/ user_data) { + // Currently not used, but can be used if acquring the gdbus name should trigger something to load. + return 0; + } + + + @SuppressWarnings("unused") // Callback Only called directly by JNI. + private static long /*int*/ onNameLostCallback (long /*int*/ connection, long /*int*/ name, long /*int*/ user_data) { + assert false : "This code should never have executed"; + System.err.println("SWT WebkitGDBus.java: Lost GDBus name. This should never occur"); + return 0; + } + + + + /** + * This is called when a client call one of the GDBus methods. + * + * Developer note: + * This method can be reached directly from GDBus cmd utility: + * gdbus call --session --dest org.eclipse.swt<UNIQUE_ID> --object-path /org/eclipse/swt/gdbus --method org.eclipse.swt.gdbusInterface.HelloWorld + * where as you tab complete, you append the UNIQUE_ID. + * + * @param connection GDBusConnection + * @param sender const gchar + * @param object_path const gchar + * @param interface_name const gchar + * @param method_name const gchar + * @param gvar_parameters GVariant + * @param invocation GDBusMethodInvocation + * @param user_data gpointer + * @return + */ + @SuppressWarnings("unused") // Callback only called directly by JNI. + private static long /*int*/ handleMethodCallback ( + long /*int*/ connection, long /*int*/ sender, + long /*int*/ object_path, long /*int*/ interface_name, + long /*int*/ method_name, long /*int*/ gvar_parameters, + long /*int*/ invocation, long /*int*/ user_data) { + + 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?"); + } + } 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); + } + long /*int*/ resultGVariant = 0; + try { + resultGVariant = convertJavaToGVariant(new Object [] {result}); // Result has to be a tuple. + } catch (SWTException e) { + // gdbus should always return to prevent extension from hanging. + String errMsg = (String) WebBrowser.CreateErrorString (e.getLocalizedMessage ()); + resultGVariant = convertJavaToGVariant(new Object [] {errMsg}); + } + WebKitGTK.g_dbus_method_invocation_return_value(invocation, resultGVariant); + return 0; // void return value. + } + + /** + * Converts the given GVariant to a Java object. + * (Only subset of types is currently supported). + * + * We assume that the given gvariant does not contain errors. (checked by webextension first). + * + * @param gVariant a pointer to the native GVariant + */ + private static Object convertGVariantToJava(long /*int*/ gVariant){ + + if (WebKitGTK.g_variant_is_of_type(gVariant, WebKitGTK.G_VARIANT_TYPE_BOOLEAN)){ + return new Boolean(WebKitGTK.g_variant_get_boolean(gVariant)); + } + + // see: WebKitGTK.java 'TYPE NOTES' + if (WebKitGTK.g_variant_is_of_type(gVariant, WebKitGTK.G_VARIANT_TYPE_BYTE)) { + byte byteVal = WebKitGTK.g_variant_get_byte(gVariant); + + switch (byteVal) { + case WebKitGTK.SWT_DBUS_MAGIC_NUMBER_NULL: + return null; + case WebKitGTK.SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY: + return new Object [0]; + default: + System.err.println("SWT Error, received unsupported byte type via gdbus: " + byteVal); + break; + } + } + + if (WebKitGTK.g_variant_is_of_type(gVariant, WebKitGTK.G_VARIANT_TYPE_DOUBLE)){ + return new Double(WebKitGTK.g_variant_get_double(gVariant)); + } + + if (WebKitGTK.g_variant_is_of_type(gVariant, WebKitGTK.G_VARIANT_TYPE_STRING)){ + return Converter.cCharPtrToJavaString(WebKitGTK.g_variant_get_string(gVariant, null), false); + } + + if (WebKitGTK.g_variant_is_of_type(gVariant, WebKitGTK.G_VARIANT_TYPE_TUPLE)){ + int length = (int)WebKitGTK.g_variant_n_children (gVariant); + Object[] result = new Object[length]; + for (int i = 0; i < length; i++) { + result[i] = convertGVariantToJava (WebKitGTK.g_variant_get_child_value(gVariant, i)); + } + return result; + } + + String typeString = Converter.cCharPtrToJavaString(WebKitGTK.g_variant_get_type_string(gVariant), false); + SWT.error (SWT.ERROR_INVALID_ARGUMENT, new Throwable("Unhandled variant type " + typeString )); + return null; + } + + /** + * Converts the given Java Object to a GVariant * representation. + * (Only subset of types is currently supported). + * + * We assume that input Object may contain invalid types. + * + * @return pointer GVariant * + */ + private static long /*int*/ convertJavaToGVariant(Object javaObject) throws SWTException { + + if (javaObject == null) { + return WebKitGTK.g_variant_new_byte(WebKitGTK.SWT_DBUS_MAGIC_NUMBER_NULL); // see: WebKitGTK.java 'TYPE NOTES' + } + + if (javaObject instanceof String) { + return WebKitGTK.g_variant_new_string (Converter.javaStringToCString((String) javaObject)); + } + + if (javaObject instanceof Boolean) { + return WebKitGTK.g_variant_new_boolean((Boolean) javaObject); + } + + // We treat Integer, Long, Double, Short as a 'double' because in Javascript these are all 'double'. + // Note, they all extend 'Number' java type, so they are an instance of it. + if (javaObject instanceof Number) { // see: WebKitGTK.java 'TYPE NOTES' + return WebKitGTK.g_variant_new_double (((Number) javaObject).doubleValue()); + } + + if (javaObject instanceof Object[]) { + Object[] arrayValue = (Object[]) javaObject; + int length = arrayValue.length; + + if (length == 0) { + return WebKitGTK.g_variant_new_byte(WebKitGTK.SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY); // see: WebKitGTK.java 'TYPE NOTES' + } + + long /*int*/ variants[] = new long /*int*/[length]; + + for (int i = 0; i < length; i++) { + variants[i] = convertJavaToGVariant(arrayValue[i]); + } + + return WebKitGTK.g_variant_new_tuple(variants, length); + } + System.err.println("SWT Webkit: Invalid object being returned to javascript: " + javaObject.toString() + "\n" + + "Only the following are supported: null, String, Boolean, Number(Long,Integer,Double...), Object[] of basic types"); + throw new SWTException(SWT.ERROR_INVALID_ARGUMENT, "Given object is not valid: " + javaObject.toString()); + } +} 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 3e7f961485..e92156539e 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 @@ -48,7 +48,11 @@ public class WebKitGTK extends C { System.out.println("SWT_LIB Webkit1 Webkitgtk:"+ webkit_major_version() +"."+ webkit_minor_version() + "." + webkit_micro_version() + " (webkitgtk < 2.5 is Webkit1)"); } if (WEBKIT2) { - System.out.println("SWT_LIB Webkit2 Webkitgtk:"+ webkit_get_major_version()+"."+ webkit_get_minor_version() + "." + webkit_get_micro_version() + " (webkitgtk >=2.5 is Webkit2)"); + String featureInfo = " Implemented: BrowserFunction over GDBus, \n" + + " not finished: setUrl(..postData)\n"; + System.out.println("SWT_LIB Webkit2 Webkitgtk:"+ webkit_get_major_version()+"."+ webkit_get_minor_version() + "." + + webkit_get_micro_version() + " (webkitgtk >=2.5 is Webkit2)\n" + + featureInfo); } } }; @@ -85,10 +89,14 @@ public class WebKitGTK extends C { /** Signals */ public static final byte[] authenticate = ascii ("authenticate"); // $NON-NLS-1$ // Webkit1 (soup) & Webkit2 WebkitWebView - public static final byte[] close_web_view = ascii ("close-web-view"); // $NON-NLS-1$ - public static final byte[] console_message = ascii ("console-message"); // $NON-NLS-1$ + + // Close webview + public static final byte[] close_web_view = ascii ("close-web-view"); // $NON-NLS-1$ // Webkit1 + public static final byte[] close = ascii ("close"); // $NON-NLS-1$ // Webkit2 + + public static final byte[] console_message = ascii ("console-message"); // $NON-NLS-1$ // Webkit1. (On W2 see 'console-message-sent'). Not printed to stderr on W2. + public static final byte[] context_menu = ascii ("context-menu"); // $NON-NLS-1$ - public static final byte[] close = ascii ("close"); // $NON-NLS-1$ public static final byte[] create = ascii ("create"); // $NON-NLS-1$ public static final byte[] create_web_view = ascii ("create-web-view"); // $NON-NLS-1$ public static final byte[] decide_policy = ascii ("decide-policy"); // $NON-NLS-1$ @@ -98,6 +106,7 @@ public class WebKitGTK extends C { public static final byte[] failed = ascii ("failed"); // $NON-NLS-1$ // Webkit2 public static final byte[] finished = ascii ("finished"); // $NON-NLS-1$ // Webkit2 + public static final byte[] initialize_web_extensions = ascii ("initialize-web-extensions"); // Webkit2 public static final byte[] hovering_over_link = ascii ("hovering-over-link"); // $NON-NLS-1$ // Webkit1 -> StatusTextListener.changed() public static final byte[] mouse_target_changed = ascii ("mouse-target-changed"); // $NON-NLS-1$ // Webkit2 -> StatusTextListener.changed() @@ -176,6 +185,92 @@ public class WebKitGTK extends C { public static final byte[] mouseup = ascii ("mouseup"); // $NON-NLS-1$ public static final byte[] mousewheel = ascii ("mousewheel"); // $NON-NLS-1$ + + + + + + /* + * GDBus related + */ + + /** @category gdbus */ + public static final int G_BUS_TYPE_STARTER = -1; //An alias for the message bus that activated the process, if any. + /** @category gdbus */ + public static final int G_BUS_TYPE_NONE = 0; // Not a message bus. + /** @category gdbus */ + public static final int G_BUS_TYPE_SYSTEM = 1; // The system-wide message bus. + /** @category gdbus */ + public static final int G_BUS_TYPE_SESSION = 2; //The login session message bus. + + /** @category gdbus */ + public static final int G_BUS_NAME_OWNER_FLAGS_NONE = 0; //No flags set. + /** @category gdbus */ + public static final int G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT = (1<<0); //Allow another message bus connection to claim the name. + /** @category gdbus */ + public static final int G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1); //If another message bus connection owns the name and have + // specified #G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, then take the name from the other connection. + + + /* TYPE NOTES + * + * GDBus doesn't support all the types that we need. I used encoded 'byte' to translate some types. + * + * - 'null' is not supported. I thought to potentially use 'maybe' types, but they imply a possible NULL of a certain type, but not null itself. + * so I use 'byte=48' (meaning '0' in ASCII) to denote null. + * + * - Empty arrays/structs are not supported by gdbus. + * "Container types ... Empty structures are not allowed; there must be at least one type code between the parentheses" + * src: https://dbus.freedesktop.org/doc/dbus-specification.html + * I used byte=101 (meaning 'e' in ASCII) to denote empty array. + * + * In Javascript all Number types seem to be 'double', (int/float/double/short -> Double). So we convert everything into double accordingly. + * + * DBus Type info: https://dbus.freedesktop.org/doc/dbus-specification.html#idm423 + * GDBus Type info: https://developer.gnome.org/glib/stable/glib-GVariantType.html + */ + + /* + * DBus types as defined by: + * https://dbus.freedesktop.org/doc/dbus-specification.html#idm423 + */ + /** @category gdbus */ + public static final String DBUS_TYPE_BYTE = "y"; // 8 bit, unsigned int. + /** @category gdbus */ + public static final String DBUS_TYPE_BOOLEAN = "b"; + /** @category gdbus */ + public static final String DBUS_TYPE_STRING = "s"; + /** @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. + /** @category gdbus */ + public static final String DBUS_TYPE_SINGLE_COMPLETE = "*"; + + + /** @category gdbus */ + public static final byte SWT_DBUS_MAGIC_NUMBER_EMPTY_ARRAY = 101; // See TYPE NOTE above + /** @category gdbus */ + public static final byte SWT_DBUS_MAGIC_NUMBER_NULL = 48; // See TYPE NOTE above + + /* + * GVariant Types + * These are for the most part quite similar to DBus types with a few differences. Read: + * https://developer.gnome.org/glib/stable/glib-GVariantType.html + */ + /** @category gdbus */ + public static final byte[] G_VARIANT_TYPE_BYTE = ascii(DBUS_TYPE_BYTE); + /** @category gdbus */ + public static final byte[] G_VARIANT_TYPE_BOOLEAN = ascii(DBUS_TYPE_BOOLEAN); + /** @category gdbus */ + public static final byte[] G_VARIANT_TYPE_STRING = ascii(DBUS_TYPE_STRING); + /** @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); + + + protected static byte [] ascii (String name) { int length = name.length (); char [] chars = new char [length]; @@ -1829,6 +1924,32 @@ public static final long /*int*/ webkit_web_view_new () { } } + +/** @method flags=dynamic */ // @param context cast=(WebKitWebContext*) @param directory cast=(const gchar *) +public static final native void _webkit_web_context_set_web_extensions_directory (long /*int*/ context, byte[] directory); +public static final void webkit_web_context_set_web_extensions_directory (long /*int*/ context, byte[] directory) { + assert WEBKIT2; + lock.lock(); + try { + _webkit_web_context_set_web_extensions_directory (context, directory); + } finally { + lock.unlock(); + } +} + +/** @method flags=dynamic */ +public static final native void _webkit_web_context_set_web_extensions_initialization_user_data(long /* int */ context, long /* int */ user_data); +public static final void webkit_web_context_set_web_extensions_initialization_user_data(long /* int */ context, + long /* int */ user_data) { + assert WEBKIT2; + lock.lock(); + try { + _webkit_web_context_set_web_extensions_initialization_user_data(context, user_data); + } finally { + lock.unlock(); + } +} + /** @method flags=dynamic */ public static final native long /*int*/ _webkit_user_content_manager_new(); public static final long /*int*/ webkit_user_content_manager_new() { @@ -2060,6 +2181,296 @@ public static final long /*int*/ webkit_uri_response_get_mime_type (long /*int* } } + + + + + +/* + * GDBus related + */ +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_dbus_node_info_new_for_xml (byte[] xml_data, long /*int*/[] error); +public static final long /*int*/ g_dbus_node_info_new_for_xml (byte[] xml_data, long /*int*/[] error) { + lock.lock(); + try { + return _g_dbus_node_info_new_for_xml (xml_data, error); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native int _g_bus_own_name (int bus_type, byte[] name, int flags, long /*int*/ bus_acquired_handler, long /*int*/ name_acquired_handler, long /*int*/ name_lost_handler, long /*int*/ user_data, long /*int*/ user_data_free_func); +public static final int g_bus_own_name (int bus_type, byte[] name, int flags, long /*int*/ bus_acquired_handler, long /*int*/ name_acquired_handler, long /*int*/ name_lost_handler, long /*int*/ user_data, long /*int*/ user_data_free_func) { + lock.lock(); + try { + return _g_bus_own_name(bus_type, name, flags, bus_acquired_handler, name_acquired_handler, name_lost_handler, user_data, user_data_free_func); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native int _g_dbus_connection_register_object (long /*int*/ connection, byte[] object_path, long /*int*/ interface_info, long /*int*/[] vtable, long /*int*/ user_data, long /*int*/ user_data_free_func, long /*int*/[] error); +public static final int g_dbus_connection_register_object (long /*int*/ connection, byte[] object_path, long /*int*/ interface_info, long /*int*/[] vtable, long /*int*/ user_data, long /*int*/ user_data_free_func, long /*int*/[] error) { + lock.lock(); + try { + return _g_dbus_connection_register_object( connection, object_path, interface_info, vtable, user_data, user_data_free_func, error); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_dbus_node_info_lookup_interface (long /*int*/ info, byte [] name); +public static final long /*int*/ g_dbus_node_info_lookup_interface (long /*int*/ info, byte [] name) { + lock.lock(); + try { + return _g_dbus_node_info_lookup_interface(info, name); + } finally { + lock.unlock(); + } +} + + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native void _g_dbus_method_invocation_return_value (long /*int*/ invocation, long /*int*/ parameters); +public static final void g_dbus_method_invocation_return_value (long /*int*/ invocation, long /*int*/ parameters) { + lock.lock(); + try { + _g_dbus_method_invocation_return_value (invocation, parameters); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_int32 (int intval); +public static final long /*int*/ g_variant_new_int32 (int intval) { + lock.lock(); + try { + return _g_variant_new_int32(intval); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + * @return guchar + */ +public static final native byte _g_variant_get_byte (long /*int*/ gvariant); +public static final byte g_variant_get_byte (long /*int*/ gvariant) { + lock.lock(); + try { + return _g_variant_get_byte (gvariant); + } finally { + lock.unlock(); + } +} +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native boolean /*int*/ _g_variant_get_boolean (long /*int*/ gvariant); +public static final boolean /*int*/ g_variant_get_boolean (long /*int*/ gvariant) { + lock.lock(); + try { + return _g_variant_get_boolean (gvariant); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_get_child_value (long /*int*/ gvariant, int index); +public static final long /*int*/ g_variant_get_child_value (long /*int*/ gvariant, int index) { + lock.lock(); + try { + return _g_variant_get_child_value (gvariant, index); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native double _g_variant_get_double (long /*int*/ gvariant); +public static final double g_variant_get_double (long /*int*/ gvariant) { + lock.lock(); + try { + return _g_variant_get_double (gvariant); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_get_string (long /*int*/ gvariant, long[] length); +public static final long /*int*/ g_variant_get_string (long /*int*/ gvariant, long[] length) { + lock.lock(); + try { + return _g_variant_get_string (gvariant, length); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native int _g_variant_get_type (long /*int*/ gvariant); +public static final int g_variant_get_type (long /*int*/ gvariant) { + lock.lock(); + try { + return _g_variant_get_type (gvariant); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_get_type_string (long /*int*/ gvariant); +public static final long /*int*/ g_variant_get_type_string (long /*int*/ gvariant) { + lock.lock(); + try { + return _g_variant_get_type_string (gvariant); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native boolean _g_variant_is_of_type (long /*int*/ gvariant, byte[] type); +public static final boolean g_variant_is_of_type (long /*int*/ gvariant, byte[] type) { + lock.lock(); + try { + return _g_variant_is_of_type (gvariant, type); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long _g_variant_n_children (long gvariant); +public static final long g_variant_n_children (long gvariant) { + lock.lock(); + try { + return _g_variant_n_children (gvariant); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_boolean (boolean value); +public static final long /*int*/ g_variant_new_boolean (boolean value) { + lock.lock(); + try { + return _g_variant_new_boolean (value); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_double (double value); +public static final long /*int*/ g_variant_new_double (double value) { + lock.lock(); + try { + return _g_variant_new_double (value); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_byte (byte value); +public static final long /*int*/ g_variant_new_byte (byte value) { + lock.lock(); + try { + return _g_variant_new_byte (value); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_tuple (long /*int*/[] items, long length); +public static final long /*int*/ g_variant_new_tuple (long /*int*/[] items, long length ) { + lock.lock(); + try { + return _g_variant_new_tuple (items, length); + } finally { + lock.unlock(); + } +} + +/** + * @method flags=dynamic + * @category gdbus + */ +public static final native long /*int*/ _g_variant_new_string (byte[] string); +public static final long /*int*/ g_variant_new_string (byte[] string) { + lock.lock(); + try { + return _g_variant_new_string (string); + } finally { + lock.unlock(); + } +} + + /* --------------------- start SWT natives --------------------- */ public static final native int JSClassDefinition_sizeof (); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/Converter.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/Converter.java index 8dc389540c..d0ca0677c6 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/Converter.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/Converter.java @@ -81,6 +81,16 @@ public static byte [] wcsToMbcs (String string, boolean terminate) { } /** + * Given a java String, convert it to a regular null terimnated C string, + * to be used when calling a native C function. + * @param string A java string. + * @return a pointer to a C String. In C, this would be a 'char *' + */ +public static byte [] javaStringToCString (String string) { + return wcsToMbcs(string, true); +} + +/** * This method takes a 'C' pointer (char *) or (gchar *), reads characters up to the terminating symbol '\0' and * converts it into a Java String. * diff --git a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_JsConsole.java b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_JsConsole.java new file mode 100644 index 0000000000..638591f827 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_JsConsole.java @@ -0,0 +1,111 @@ +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.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: [GTK3][Webkit2] Implement webkit2 support for browser function (Part 2: Java return a value from callback.) + * How to run: Snippet to execute javascript via input prompt, to test Browser Func return value ability. + * Bug description: + * Expected results: + * GTK Version(s): + */ +public class Bug510905_Browser_JsConsole { + + 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.BEGINNING, 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"); + + shell.open(); + 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); + } + } +} diff --git a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_TwoJsConsoles.java b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_TwoJsConsoles.java new file mode 100644 index 0000000000..f3dcacc4d7 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug510905_Browser_TwoJsConsoles.java @@ -0,0 +1,115 @@ +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.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/* + * Title: [GTK3][Webkit2] Implement webkit2 support for browser function (Part 2: Java return a value from callback.) + * How to run: Snippet to execute javascript via input prompt, to test Browser Func return value ability. + * Bug description: + * Expected results: + * GTK Version(s): + */ +public class Bug510905_Browser_TwoJsConsoles { + + static int count = 0; + + public static void main(String[] args) { + Display display = new Display(); + Shell shell = new Shell(display); + shell.setSize(500, 600); + + shell.setLayout(new RowLayout()); + + Composite leftBrowser = new Composite(shell, SWT.NONE); + Composite rightBrowser = new Composite(shell, SWT.None); + Button button = new Button (rightBrowser, SWT.PUSH); + button.setText("my button"); + + + final Browser browser = makeBrowserWithConsole(leftBrowser, "theJavaFunction"); + new CustomFunction (browser, "theJavaFunction"); + + final Browser browser2 = makeBrowserWithConsole(rightBrowser, "theJavaFunction"); + new CustomFunction (browser2, "theJavaFunction"); + + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + display.dispose(); + } + + /** + * @param leftBrowser + * @return + */ + private static Browser makeBrowserWithConsole(Composite leftBrowser, String funcName) { + GridLayout gridLayout = new GridLayout(); + leftBrowser.setLayout(gridLayout); + + final Text jsConsole = new Text(leftBrowser, SWT.BORDER); + jsConsole.setText("document.body.innerHTML = " + funcName + "(123)"); // 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(leftBrowser, 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(leftBrowser, SWT.PUSH); + loadNewPage.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + loadNewPage.setText("Load new Page"); + loadNewPage.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + browser.setText("New page!" + count++); + } + }); + return browser; + } + + 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; + } + } +} diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java index 1c3deb9241..5aa58f2aa7 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java @@ -2082,10 +2082,6 @@ public void test_BrowserFunction_callback_with_javaReturningInt () { // culprit seems to be the main_context_iteration() call in shell.setVisible(). // See Bug 509587. Solution: Webkit2. assumeFalse(webkit1SkipMsg(), isWebkit1); - - // Skip till Bug 510905 is implemented. - assumeFalse("Skipping test_BrowserFunction_callback_with_javaReturningInt. Java's callback to Javascript doesn't support return yet", isWebkit2); - AtomicInteger returnInt = new AtomicInteger(0); class JavascriptCallback extends BrowserFunction { // Note: Local class defined inside method. |
