Polished JavaFX and SWT dispatch access to remove hard dependency on
JavaFX and SWT. Now uses JNA to create the classes for SWT access + a mix of reflection. JavaFX uses reflection.
This commit is contained in:
parent
cdc2bbd2cf
commit
8ed1e0d3b0
@ -27,55 +27,81 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class JavaFX {
|
class JavaFX {
|
||||||
|
public final static boolean isLoaded;
|
||||||
|
public final static boolean isGtk3;
|
||||||
|
|
||||||
// Methods are cached for performance
|
// Methods are cached for performance
|
||||||
private static final Method dispatchMethod;
|
private static final Method dispatchMethod;
|
||||||
private static final Method isEventThreadMethod;
|
private static final Method isEventThreadMethod;
|
||||||
private static final Object isEventThreadObject;
|
private static final Object isEventThreadObject;
|
||||||
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
boolean isJavaFxLoaded_ = false;
|
||||||
|
boolean isJavaFxGtk3_ = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this is important to use reflection, because if JavaFX is not being used, calling getToolkit() will initialize it...
|
||||||
|
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||||
|
m.setAccessible(true);
|
||||||
|
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||||
|
|
||||||
|
// JavaFX Java7,8 is GTK2 only. Java9 can have it be GTK3 if -Djdk.gtk.version=3 is specified
|
||||||
|
// see http://mail.openjdk.java.net/pipermail/openjfx-dev/2016-May/019100.html
|
||||||
|
isJavaFxLoaded_ = (null != m.invoke(cl, "com.sun.javafx.tk.Toolkit")) || (null != m.invoke(cl, "javafx.application.Application"));
|
||||||
|
|
||||||
|
if (isJavaFxLoaded_) {
|
||||||
|
// JavaFX Java7,8 is GTK2 only. Java9 can MAYBE have it be GTK3 if `-Djdk.gtk.version=3` is specified
|
||||||
|
// see
|
||||||
|
// http://mail.openjdk.java.net/pipermail/openjfx-dev/2016-May/019100.html
|
||||||
|
// https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
||||||
|
// from the page: JavaFX 2.2.3 for Linux requires gtk2 2.18+.
|
||||||
|
|
||||||
|
isJavaFxGtk3_ = OS.javaVersion >= 9 && System.getProperty("jdk.gtk.version", "2").equals("3");
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Framework.class).debug("Error detecting if JavaFX is loaded", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoaded = isJavaFxLoaded_;
|
||||||
|
isGtk3 = isJavaFxGtk3_;
|
||||||
|
|
||||||
|
|
||||||
Method _isEventThreadMethod = null;
|
Method _isEventThreadMethod = null;
|
||||||
Method _dispatchMethod = null;
|
Method _dispatchMethod = null;
|
||||||
Object _isEventThreadObject = null;
|
Object _isEventThreadObject = null;
|
||||||
|
|
||||||
try {
|
if (isJavaFxLoaded_) {
|
||||||
Class<?> clazz = Class.forName("javafx.application.Platform");
|
try {
|
||||||
_dispatchMethod = clazz.getMethod("runLater", Runnable.class);
|
Class<?> clazz = Class.forName("javafx.application.Platform");
|
||||||
|
_dispatchMethod = clazz.getMethod("runLater", Runnable.class);
|
||||||
|
|
||||||
// JAVA 7
|
// JAVA 7
|
||||||
// javafx.application.Platform.isFxApplicationThread();
|
// javafx.application.Platform.isFxApplicationThread();
|
||||||
|
|
||||||
// JAVA 8
|
// JAVA 8
|
||||||
// com.sun.javafx.tk.Toolkit.getToolkit().isFxUserThread();
|
// com.sun.javafx.tk.Toolkit.getToolkit().isFxUserThread();
|
||||||
if (OS.javaVersion <= 7) {
|
if (OS.javaVersion <= 7) {
|
||||||
clazz = Class.forName("javafx.application.Platform");
|
clazz = Class.forName("javafx.application.Platform");
|
||||||
_isEventThreadMethod = clazz.getMethod("isFxApplicationThread");
|
_isEventThreadMethod = clazz.getMethod("isFxApplicationThread");
|
||||||
_isEventThreadObject = null;
|
_isEventThreadObject = null;
|
||||||
} else {
|
} else {
|
||||||
clazz = Class.forName("com.sun.javafx.tk.Toolkit");
|
clazz = Class.forName("com.sun.javafx.tk.Toolkit");
|
||||||
_isEventThreadMethod = clazz.getMethod("getToolkit");
|
_isEventThreadMethod = clazz.getMethod("getToolkit");
|
||||||
|
|
||||||
_isEventThreadObject = _isEventThreadMethod.invoke(null);
|
_isEventThreadObject = _isEventThreadMethod.invoke(null);
|
||||||
_isEventThreadMethod = _isEventThreadObject.getClass()
|
_isEventThreadMethod = _isEventThreadObject.getClass()
|
||||||
.getMethod("isFxUserThread", (java.lang.Class<?>[])null);
|
.getMethod("isFxUserThread", (java.lang.Class<?>[])null);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(JavaFX.class).error("Cannot initialize JavaFX", e);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
LoggerFactory.getLogger(JavaFX.class).error("Cannot initialize JavaFX", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchMethod = _dispatchMethod;
|
dispatchMethod = _dispatchMethod;
|
||||||
isEventThreadMethod = _isEventThreadMethod;
|
isEventThreadMethod = _isEventThreadMethod;
|
||||||
isEventThreadObject = _isEventThreadObject;
|
isEventThreadObject = _isEventThreadObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
|
||||||
void init() {
|
|
||||||
if (dispatchMethod == null || isEventThreadMethod == null) {
|
|
||||||
LoggerFactory.getLogger(JavaFX.class)
|
|
||||||
.error("Unable to initialize JavaFX! Please create an issue with your OS and Java " +
|
|
||||||
"version so we may further investigate this issue.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static
|
public static
|
||||||
void dispatch(final Runnable runnable) {
|
void dispatch(final Runnable runnable) {
|
||||||
|
@ -15,76 +15,194 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util;
|
package dorkbox.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javassist.ClassPool;
|
||||||
|
import javassist.CtClass;
|
||||||
|
import javassist.CtField;
|
||||||
|
import javassist.CtMethod;
|
||||||
|
import javassist.CtNewMethod;
|
||||||
|
import javassist.Modifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods for SWT. This will by written by {@link SwtBytecodeOverride}, via Javassist so we don't require a hard dependency on
|
* Utility methods for SWT. Some of the methods will be overwritten via Javassist so we don't require a hard dependency on SWT.
|
||||||
* SWT.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The methods/fields that this originated from * are commented out.
|
* SWT system tray types are GtkStatusIcon trays (so we don't want to use them)
|
||||||
* <p>
|
|
||||||
* SWT system tray types are just GTK trays.
|
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("Convert2Lambda")
|
||||||
public
|
public
|
||||||
class Swt {
|
class Swt {
|
||||||
private static final org.eclipse.swt.widgets.Display currentDisplay;
|
public final static boolean isLoaded;
|
||||||
private static final Thread currentDisplayThread;
|
public final static boolean isGtk3;
|
||||||
|
|
||||||
static {
|
private static final Object currentDisplay;
|
||||||
// we MUST save this, otherwise it is "null" when methods are run from the swing EDT.
|
private static final Thread currentDisplayThread;
|
||||||
currentDisplay = org.eclipse.swt.widgets.Display.getCurrent();
|
|
||||||
|
|
||||||
currentDisplayThread = currentDisplay.getThread();
|
// Methods are cached for performance
|
||||||
|
private static final Method syncExecMethod;
|
||||||
|
|
||||||
|
static {
|
||||||
|
boolean isSwtLoaded_ = false;
|
||||||
|
boolean isSwtGtk3_ = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// this is important to use reflection, because if JavaFX is not being used, calling getToolkit() will initialize it...
|
||||||
|
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
||||||
|
m.setAccessible(true);
|
||||||
|
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||||
|
|
||||||
|
// maybe we should load the SWT version? (In order for us to work with SWT, BOTH must be the same!!
|
||||||
|
// SWT is GTK2, but if -DSWT_GTK3=1 is specified, it can be GTK3
|
||||||
|
isSwtLoaded_ = null != m.invoke(cl, "org.eclipse.swt.widgets.Display");
|
||||||
|
|
||||||
|
if (isSwtLoaded_) {
|
||||||
|
// Necessary for us to work with SWT based on version info. We can try to set us to be compatible with whatever it is set to
|
||||||
|
// System.setProperty("SWT_GTK3", "0"); (or -DSWT_GTK3=1)
|
||||||
|
|
||||||
|
// was SWT forced?
|
||||||
|
String swt_gtk3 = System.getProperty("SWT_GTK3");
|
||||||
|
isSwtGtk3_ = swt_gtk3 != null && !swt_gtk3.equals("0");
|
||||||
|
if (!isSwtGtk3_) {
|
||||||
|
// check a different property
|
||||||
|
String property = System.getProperty("org.eclipse.swt.internal.gtk.version");
|
||||||
|
isSwtGtk3_ = property != null && !property.startsWith("2.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Framework.class).debug("Error detecting if SWT is loaded", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoaded = isSwtLoaded_;
|
||||||
|
isGtk3 = isSwtGtk3_;
|
||||||
|
|
||||||
|
// we MUST save this now, otherwise it is "null" when methods are run from the swing EDT.
|
||||||
|
//
|
||||||
|
// currentDisplay = org.eclipse.swt.widgets.Display.getCurrent();
|
||||||
|
// currentDisplayThread = currentDisplay.getThread();
|
||||||
|
|
||||||
|
Object _currentDisplay = null;
|
||||||
|
Thread _currentDisplayThread = null;
|
||||||
|
|
||||||
|
Method _syncExecMethod = null;
|
||||||
|
|
||||||
|
if (isSwtLoaded_) {
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName("org.eclipse.swt.widgets.Display");
|
||||||
|
Method getCurrentMethod = clazz.getMethod("getCurrent");
|
||||||
|
Method getThreadMethod = clazz.getMethod("getThread");
|
||||||
|
_syncExecMethod = clazz.getDeclaredMethod("syncExec", Runnable.class);
|
||||||
|
|
||||||
|
_currentDisplay = getCurrentMethod.invoke(null);
|
||||||
|
_currentDisplayThread = (Thread) getThreadMethod.invoke(_currentDisplay);
|
||||||
|
|
||||||
|
|
||||||
|
// re-write the part that is heavily SWT dependent, that cannot be done via reflection.
|
||||||
|
byte[] bytes;
|
||||||
|
String body;
|
||||||
|
CtMethod method;
|
||||||
|
CtField ctField;
|
||||||
|
|
||||||
|
ClassPool pool = ClassPool.getDefault();
|
||||||
|
CtClass swtOverriedClass = pool.get("dorkbox.util.Swt$SwtOverride");
|
||||||
|
|
||||||
|
// the abstractions for listener are REQUIRED by javassist.
|
||||||
|
{
|
||||||
|
CtClass listener = pool.makeClass("dorkbox.util.Swt_listener");
|
||||||
|
listener.addInterface(pool.get("org.eclipse.swt.widgets.Listener"));
|
||||||
|
|
||||||
|
ctField = new CtField(pool.get("java.lang.Runnable"), "runnable", listener);
|
||||||
|
ctField.setModifiers(Modifier.PROTECTED);
|
||||||
|
listener.addField(ctField);
|
||||||
|
|
||||||
|
method = CtNewMethod.make(CtClass.voidType, "handleEvent",
|
||||||
|
new CtClass[]{pool.get("org.eclipse.swt.widgets.Event")}, null,
|
||||||
|
"{" +
|
||||||
|
" this.runnable.run();" +
|
||||||
|
"}", listener);
|
||||||
|
listener.addMethod(method);
|
||||||
|
bytes = listener.toBytecode();
|
||||||
|
ClassLoaderUtil.defineClass(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
method = swtOverriedClass.getDeclaredMethod("onShutdown");
|
||||||
|
body = "{" +
|
||||||
|
"org.eclipse.swt.widgets.Display currentDisplay = (org.eclipse.swt.widgets.Display)$1;" +
|
||||||
|
"Runnable runnable = $2;" +
|
||||||
|
|
||||||
|
"dorkbox.util.Swt_listener listener = new dorkbox.util.Swt_listener();" +
|
||||||
|
"listener.runnable = runnable;" +
|
||||||
|
|
||||||
|
"org.eclipse.swt.widgets.Shell shell = currentDisplay.getShells()[0];" +
|
||||||
|
"shell.addListener(org.eclipse.swt.SWT.Close, listener);" +
|
||||||
|
"}";
|
||||||
|
method.setBody(body);
|
||||||
|
bytes = swtOverriedClass.toBytecode();
|
||||||
|
|
||||||
|
// define this new class in our current classloader
|
||||||
|
ClassLoaderUtil.defineClass(bytes);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Swt.class).error("Cannot initialize SWT", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDisplay = _currentDisplay;
|
||||||
|
currentDisplayThread = _currentDisplayThread;
|
||||||
|
syncExecMethod = _syncExecMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// this class is over-written via Javassist, because reflection cannot create anonymous classes. Javassist can, with caveats.
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public static
|
public static
|
||||||
void init() {
|
class SwtOverride {
|
||||||
if (currentDisplay == null) {
|
static
|
||||||
LoggerFactory.getLogger(Swt.class)
|
void onShutdown(final Object currentDisplay, final Runnable runnable) {
|
||||||
.error("Unable to get the current display for SWT. Please create an issue with your OS and Java " +
|
// currentDisplay.getShells() must only be called inside the event thread!
|
||||||
"version so we may further investigate this issue.");
|
|
||||||
}
|
// org.eclipse.swt.widgets.Shell shell = currentDisplay.getShells()[0];
|
||||||
// throw new RuntimeException("This should never happen, as this class is over-written at runtime.");
|
// shell.addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() {
|
||||||
|
// @Override
|
||||||
|
// public
|
||||||
|
// void handleEvent(final org.eclipse.swt.widgets.Event event) {
|
||||||
|
// runnable.run();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
throw new RuntimeException("This should never happen, as this class is over-written at runtime.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
public static
|
||||||
void dispatch(final Runnable runnable) {
|
void dispatch(final Runnable runnable) {
|
||||||
currentDisplay.syncExec(runnable);
|
// currentDisplay.syncExec(runnable);
|
||||||
// throw new RuntimeException("This should never happen, as this class is over-written at runtime.");
|
try {
|
||||||
|
syncExecMethod.invoke(currentDisplay, runnable);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LoggerFactory.getLogger(Swt.class)
|
||||||
|
.error("Unable to execute JavaFX runLater(). Please create an issue with your OS and Java " +
|
||||||
|
"version so we may further investigate this issue.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
public static
|
||||||
boolean isEventThread() {
|
boolean isEventThread() {
|
||||||
return Thread.currentThread() == currentDisplayThread;
|
return Thread.currentThread() == currentDisplayThread;
|
||||||
// throw new RuntimeException("This should never happen, as this class is over-written at runtime.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
public static
|
||||||
void onShutdown(final Runnable runnable) {
|
void onShutdown(final Runnable runnable) {
|
||||||
// currentDisplay.getShells() can only happen inside the event thread!
|
// currentDisplay.getShells() must only be called inside the event thread!
|
||||||
if (isEventThread()) {
|
if (isEventThread()) {
|
||||||
currentDisplay.getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() {
|
SwtOverride.onShutdown(currentDisplay, runnable);
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void handleEvent(final org.eclipse.swt.widgets.Event event) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
dispatch(new Runnable() {
|
dispatch(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
currentDisplay.getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() {
|
SwtOverride.onShutdown(currentDisplay, runnable);
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void handleEvent(final org.eclipse.swt.widgets.Event event) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// throw new RuntimeException("This should never happen, as this class is over-written at runtime.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,269 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2016 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.util;
|
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.AALOAD;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_FINAL;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_SUPER;
|
|
||||||
import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.ALOAD;
|
|
||||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
|
||||||
import static org.objectweb.asm.Opcodes.BIPUSH;
|
|
||||||
import static org.objectweb.asm.Opcodes.DUP;
|
|
||||||
import static org.objectweb.asm.Opcodes.GETSTATIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.GOTO;
|
|
||||||
import static org.objectweb.asm.Opcodes.ICONST_0;
|
|
||||||
import static org.objectweb.asm.Opcodes.ICONST_1;
|
|
||||||
import static org.objectweb.asm.Opcodes.IFEQ;
|
|
||||||
import static org.objectweb.asm.Opcodes.IFNONNULL;
|
|
||||||
import static org.objectweb.asm.Opcodes.IF_ACMPNE;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
|
|
||||||
import static org.objectweb.asm.Opcodes.IRETURN;
|
|
||||||
import static org.objectweb.asm.Opcodes.NEW;
|
|
||||||
import static org.objectweb.asm.Opcodes.PUTSTATIC;
|
|
||||||
import static org.objectweb.asm.Opcodes.RETURN;
|
|
||||||
|
|
||||||
import org.objectweb.asm.AnnotationVisitor;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
import org.objectweb.asm.FieldVisitor;
|
|
||||||
import org.objectweb.asm.Label;
|
|
||||||
import org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility methods for SWT. This will override {@link Swt} methods, and is written in Javassist. This is so we don't require a hard
|
|
||||||
* dependency on SWT.
|
|
||||||
* <p>
|
|
||||||
* The methods/fields that this originated from are commented out in the {@link Swt} class.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
class SwtBytecodeOverride {
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
// byte[] swtClassBytes = getSwtBytes();
|
|
||||||
//
|
|
||||||
// // whoosh, past the classloader and directly into memory. This will take precedence over the "proper" Swt class
|
|
||||||
// BootStrapClassLoader.defineClass(swtClassBytes);
|
|
||||||
|
|
||||||
// now we have to load various classes into the classloader
|
|
||||||
Class<?> aClass = Class.forName("org.eclipse.swt.widgets.Display");
|
|
||||||
Swt.init();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static
|
|
||||||
void init() {
|
|
||||||
// placeholder to initialize the class.
|
|
||||||
}
|
|
||||||
|
|
||||||
private static
|
|
||||||
byte[] getSwtBytes() throws Exception {
|
|
||||||
ClassWriter cw = new ClassWriter(0);
|
|
||||||
FieldVisitor fv;
|
|
||||||
MethodVisitor mv;
|
|
||||||
AnnotationVisitor av0;
|
|
||||||
|
|
||||||
cw.visit(52, ACC_PUBLIC + ACC_SUPER, "dorkbox/util/Swt", null, "java/lang/Object", null);
|
|
||||||
|
|
||||||
cw.visitSource("Swt.java", null);
|
|
||||||
|
|
||||||
cw.visitInnerClass("dorkbox/util/Swt$1", null, null, 0);
|
|
||||||
|
|
||||||
cw.visitInnerClass("dorkbox/util/Swt$2", null, null, 0);
|
|
||||||
|
|
||||||
{
|
|
||||||
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, "currentDisplay", "Lorg/eclipse/swt/widgets/Display;", null, null);
|
|
||||||
fv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL + ACC_STATIC, "currentDisplayThread", "Ljava/lang/Thread;", null, null);
|
|
||||||
fv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(35, l0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "org/eclipse/swt/widgets/Display", "getCurrent", "()Lorg/eclipse/swt/widgets/Display;", false);
|
|
||||||
mv.visitFieldInsn(PUTSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitLineNumber(37, l1);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "org/eclipse/swt/widgets/Display", "getThread", "()Ljava/lang/Thread;", false);
|
|
||||||
mv.visitFieldInsn(PUTSTATIC, "dorkbox/util/Swt", "currentDisplayThread", "Ljava/lang/Thread;");
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
mv.visitLineNumber(38, l2);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(1, 0);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(29, l0);
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitLocalVariable("this", "Ldorkbox/util/Swt;", null, l0, l1, 0);
|
|
||||||
mv.visitMaxs(1, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "init", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(42, l0);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitJumpInsn(IFNONNULL, l1);
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
mv.visitLineNumber(43, l2);
|
|
||||||
mv.visitLdcInsn(Type.getType("Ldorkbox/util/Swt;"));
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "org/slf4j/LoggerFactory", "getLogger", "(Ljava/lang/Class;)Lorg/slf4j/Logger;", false);
|
|
||||||
Label l3 = new Label();
|
|
||||||
mv.visitLabel(l3);
|
|
||||||
mv.visitLineNumber(44, l3);
|
|
||||||
mv.visitLdcInsn("Unable to get the current display for SWT. Please create an issue with your OS and Java version so we may further investigate this issue.");
|
|
||||||
mv.visitMethodInsn(INVOKEINTERFACE, "org/slf4j/Logger", "error", "(Ljava/lang/String;)V", true);
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitLineNumber(48, l1);
|
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
mv.visitMaxs(2, 0);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "dispatch", "(Ljava/lang/Runnable;)V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(52, l0);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "org/eclipse/swt/widgets/Display", "syncExec", "(Ljava/lang/Runnable;)V", false);
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitLineNumber(54, l1);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
mv.visitLocalVariable("runnable", "Ljava/lang/Runnable;", null, l0, l2, 0);
|
|
||||||
mv.visitMaxs(2, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "isEventThread", "()Z", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(58, l0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplayThread", "Ljava/lang/Thread;");
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitJumpInsn(IF_ACMPNE, l1);
|
|
||||||
mv.visitInsn(ICONST_1);
|
|
||||||
mv.visitInsn(IRETURN);
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitInsn(IRETURN);
|
|
||||||
mv.visitMaxs(2, 0);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "onShutdown", "(Ljava/lang/Runnable;)V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(65, l0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "dorkbox/util/Swt", "isEventThread", "()Z", false);
|
|
||||||
Label l1 = new Label();
|
|
||||||
mv.visitJumpInsn(IFEQ, l1);
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
mv.visitLineNumber(66, l2);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, "org/eclipse/swt/widgets/Display", "getShells", "()[Lorg/eclipse/swt/widgets/Shell;", false);
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitInsn(AALOAD);
|
|
||||||
mv.visitIntInsn(BIPUSH, 21);
|
|
||||||
mv.visitTypeInsn(NEW, "dorkbox/util/Swt$1");
|
|
||||||
mv.visitInsn(DUP);
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "dorkbox/util/Swt$1", "<init>", "(Ljava/lang/Runnable;)V", false);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL,
|
|
||||||
"org/eclipse/swt/widgets/Shell",
|
|
||||||
"addListener",
|
|
||||||
"(ILorg/eclipse/swt/widgets/Listener;)V",
|
|
||||||
false);
|
|
||||||
Label l3 = new Label();
|
|
||||||
mv.visitLabel(l3);
|
|
||||||
mv.visitLineNumber(73, l3);
|
|
||||||
Label l4 = new Label();
|
|
||||||
mv.visitJumpInsn(GOTO, l4);
|
|
||||||
mv.visitLabel(l1);
|
|
||||||
mv.visitLineNumber(74, l1);
|
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
|
||||||
mv.visitTypeInsn(NEW, "dorkbox/util/Swt$2");
|
|
||||||
mv.visitInsn(DUP);
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "dorkbox/util/Swt$2", "<init>", "(Ljava/lang/Runnable;)V", false);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "dorkbox/util/Swt", "dispatch", "(Ljava/lang/Runnable;)V", false);
|
|
||||||
mv.visitLabel(l4);
|
|
||||||
mv.visitLineNumber(89, l4);
|
|
||||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
|
||||||
mv.visitInsn(RETURN);
|
|
||||||
Label l5 = new Label();
|
|
||||||
mv.visitLabel(l5);
|
|
||||||
mv.visitLocalVariable("runnable", "Ljava/lang/Runnable;", null, l0, l5, 0);
|
|
||||||
mv.visitMaxs(5, 1);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
mv = cw.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "access$0", "()Lorg/eclipse/swt/widgets/Display;", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
Label l0 = new Label();
|
|
||||||
mv.visitLabel(l0);
|
|
||||||
mv.visitLineNumber(30, l0);
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "dorkbox/util/Swt", "currentDisplay", "Lorg/eclipse/swt/widgets/Display;");
|
|
||||||
mv.visitInsn(ARETURN);
|
|
||||||
mv.visitMaxs(1, 0);
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
cw.visitEnd();
|
|
||||||
|
|
||||||
return cw.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,7 +27,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
|
|
||||||
import dorkbox.util.Framework;
|
|
||||||
import dorkbox.util.JavaFX;
|
import dorkbox.util.JavaFX;
|
||||||
import dorkbox.util.Swt;
|
import dorkbox.util.Swt;
|
||||||
|
|
||||||
@ -36,9 +35,6 @@ class GtkEventDispatch {
|
|||||||
static boolean FORCE_GTK2 = false;
|
static boolean FORCE_GTK2 = false;
|
||||||
static boolean DEBUG = false;
|
static boolean DEBUG = false;
|
||||||
|
|
||||||
private static final boolean isSwtLoaded = Framework.isSwtLoaded;
|
|
||||||
private static final boolean isJavaFxLoaded = Framework.isJavaFxLoaded;
|
|
||||||
|
|
||||||
// have to save these in a field to prevent GC on the objects (since they go out-of-scope from java)
|
// have to save these in a field to prevent GC on the objects (since they go out-of-scope from java)
|
||||||
private static final LinkedList<Object> gtkCallbacks = new LinkedList<Object>();
|
private static final LinkedList<Object> gtkCallbacks = new LinkedList<Object>();
|
||||||
|
|
||||||
@ -135,7 +131,7 @@ class GtkEventDispatch {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isJavaFxLoaded) {
|
if (JavaFX.isLoaded) {
|
||||||
if (!JavaFX.isEventThread()) {
|
if (!JavaFX.isEventThread()) {
|
||||||
try {
|
try {
|
||||||
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
||||||
@ -161,7 +157,7 @@ class GtkEventDispatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isSwtLoaded) {
|
else if (Swt.isLoaded) {
|
||||||
if (!Swt.isEventThread()) {
|
if (!Swt.isEventThread()) {
|
||||||
// we have to WAIT until all events are done processing, OTHERWISE we have initialization issues
|
// we have to WAIT until all events are done processing, OTHERWISE we have initialization issues
|
||||||
try {
|
try {
|
||||||
@ -219,7 +215,7 @@ class GtkEventDispatch {
|
|||||||
public static
|
public static
|
||||||
void dispatch(final Runnable runnable) {
|
void dispatch(final Runnable runnable) {
|
||||||
if (GtkLoader.alreadyRunningGTK) {
|
if (GtkLoader.alreadyRunningGTK) {
|
||||||
if (isJavaFxLoaded) {
|
if (JavaFX.isLoaded) {
|
||||||
// JavaFX only
|
// JavaFX only
|
||||||
if (JavaFX.isEventThread()) {
|
if (JavaFX.isEventThread()) {
|
||||||
// Run directly on the JavaFX event thread
|
// Run directly on the JavaFX event thread
|
||||||
@ -232,7 +228,7 @@ class GtkEventDispatch {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSwtLoaded) {
|
if (Swt.isLoaded) {
|
||||||
if (Swt.isEventThread()) {
|
if (Swt.isEventThread()) {
|
||||||
// Run directly on the SWT event thread. If it's not on the dispatch thread, we can use raw GTK to put it there
|
// Run directly on the SWT event thread. If it's not on the dispatch thread, we can use raw GTK to put it there
|
||||||
runnable.run();
|
runnable.run();
|
||||||
|
@ -22,8 +22,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
import com.sun.jna.Function;
|
import com.sun.jna.Function;
|
||||||
import com.sun.jna.NativeLibrary;
|
import com.sun.jna.NativeLibrary;
|
||||||
|
|
||||||
import dorkbox.util.Framework;
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
|
import dorkbox.util.Swt;
|
||||||
import dorkbox.util.jna.JnaHelper;
|
import dorkbox.util.jna.JnaHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,7 +170,7 @@ class GtkLoader {
|
|||||||
|
|
||||||
// depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. It will EVENTUALLY run, so we
|
// depending on how the system is initialized, SWT may, or may not, have the gtk_main loop running. It will EVENTUALLY run, so we
|
||||||
// do not want to run our own GTK event loop.
|
// do not want to run our own GTK event loop.
|
||||||
_alreadyRunningGTK |= Framework.isSwtLoaded;
|
_alreadyRunningGTK |= Swt.isLoaded;
|
||||||
|
|
||||||
alreadyRunningGTK = _alreadyRunningGTK;
|
alreadyRunningGTK = _alreadyRunningGTK;
|
||||||
isGtk2 = _isGtk2;
|
isGtk2 = _isGtk2;
|
||||||
|
@ -35,10 +35,10 @@ import com.sun.jna.Pointer;
|
|||||||
import com.sun.jna.ptr.PointerByReference;
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
|
||||||
import dorkbox.util.FileUtil;
|
import dorkbox.util.FileUtil;
|
||||||
import dorkbox.util.Framework;
|
|
||||||
import dorkbox.util.MathUtil;
|
import dorkbox.util.MathUtil;
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.OSUtil;
|
import dorkbox.util.OSUtil;
|
||||||
|
import dorkbox.util.Swt;
|
||||||
import dorkbox.util.jna.linux.structs.GtkRequisition;
|
import dorkbox.util.jna.linux.structs.GtkRequisition;
|
||||||
import dorkbox.util.jna.linux.structs.GtkStyle;
|
import dorkbox.util.jna.linux.structs.GtkStyle;
|
||||||
import dorkbox.util.jna.linux.structs.PangoRectangle;
|
import dorkbox.util.jna.linux.structs.PangoRectangle;
|
||||||
@ -413,7 +413,7 @@ My ratio is 1.47674, that means I have no scaling at all when there is a 1.5 fac
|
|||||||
final AtomicInteger traySize = new AtomicInteger();
|
final AtomicInteger traySize = new AtomicInteger();
|
||||||
|
|
||||||
|
|
||||||
if (Framework.isSwtLoaded) {
|
if (Swt.isLoaded) {
|
||||||
} else {
|
} else {
|
||||||
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
GtkEventDispatch.dispatchAndWait(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user