From 23ffd02b6519044a6d40083a1b9ecf3e84a0d2e3 Mon Sep 17 00:00:00 2001 From: Robinson Date: Wed, 27 Jan 2021 01:37:53 +0100 Subject: [PATCH] SWT no longer using reflection (using trampoline class for access) --- src/dorkbox/util/swt/Swt.java | 127 ++++------------------------ src/dorkbox/util/swt/SwtAccess.java | 117 +++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 111 deletions(-) diff --git a/src/dorkbox/util/swt/Swt.java b/src/dorkbox/util/swt/Swt.java index eb087ba..02b0aed 100644 --- a/src/dorkbox/util/swt/Swt.java +++ b/src/dorkbox/util/swt/Swt.java @@ -15,15 +15,9 @@ */ package dorkbox.util.swt; -import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Display; - -import dorkbox.os.OS; - /** * Utility methods for SWT. SWT is always available for compiling, so it is not necessary to use reflection to compile it. *

@@ -35,33 +29,13 @@ class Swt { public final static boolean isGtk3; private static final int version; - private static final Display currentDisplay; - private static final Thread currentDisplayThread; - + // NOTE: This class cannot have SWT **ANYTHING** in it static { // There is a silly amount of redirection, simply because we have to be able to access SWT, but only if it's in use. + // Since this class is the place other code interacts with, we can use SWT stuff if necessary without loading/linking // the SWT classes by accident - - - boolean isSwtLoadable_ = isLoadable(); - - version = SWT.getVersion(); - isLoaded = isSwtLoadable_; - isGtk3 = isSwtLoadable_ && isGtk3(); - - - // we MUST save this on init, otherwise it is "null" when methods are run from the swing EDT. - currentDisplay = org.eclipse.swt.widgets.Display.getCurrent(); - currentDisplayThread = currentDisplay.getThread(); - } - - /** - * This uses reflection to check if SWT is loadable and if certain classes are available. - * @return true if SWT is loadable - */ - static boolean isLoadable() { Class swtErrorClass = AccessController.doPrivileged(new PrivilegedAction>() { @Override public @@ -79,78 +53,20 @@ class Swt { }); if (swtErrorClass != null) { - try { - return org.eclipse.swt.SWT.isLoadable(); - } catch (Exception ignored) { - } - } + // this means that SWT is available in the system at runtime. We use the error class because that DOES NOT intitialize anything + boolean isSwtLoadable_ = SwtAccess.isLoadable(); + version = SwtAccess.getVersion(); + isLoaded = isSwtLoadable_; + isGtk3 = isSwtLoadable_ && SwtAccess.isGtk3(); - return false; + SwtAccess.init(); + } else { + version = 0; + isLoaded = false; + isGtk3 = false; + } } - /** - * This is only necessary for linux. - * - * @return true if SWT is GTK3. False if SWT is GTK2. If for some reason we DO NOT KNOW, then we return false (GTK2). - */ - static boolean isGtk3() { - if (!OS.isLinux()) { - return false; - } - - // required to use reflection, because this is an internal class - final String SWT_INTERNAL_CLASS = "org.eclipse.swt.internal.gtk.OS"; - Class osClass = AccessController.doPrivileged(new PrivilegedAction>() { - @Override - public - Class run() { - try { - return Class.forName(SWT_INTERNAL_CLASS, true, ClassLoader.getSystemClassLoader()); - } catch (Exception ignored) { - } - - try { - return Class.forName(SWT_INTERNAL_CLASS, true, Thread.currentThread().getContextClassLoader()); - } catch (Exception ignored) { - } - - return null; - } - }); - - - if (osClass == null) { - return false; - } - - final Class clazz = osClass; - Method method = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public - Method run() { - try { - return clazz.getMethod("gtk_major_version"); - } catch (Exception e) { - return null; - } - } - }); - - if (method == null) { - return false; - } - - int version = 0; - try { - version = ((Number)method.invoke(osClass)).intValue(); - } catch (Exception ignored) { - // this method doesn't exist. - } - - return version == 3; - } - - public static int getVersion() { return version; @@ -158,27 +74,16 @@ class Swt { public static void dispatch(final Runnable runnable) { - currentDisplay.syncExec(runnable); + SwtAccess.dispatch(runnable); } public static boolean isEventThread() { - return Thread.currentThread() == currentDisplayThread; + return SwtAccess.isEventThread(); } public static void onShutdown(final Runnable runnable) { - // currentDisplay.getShells() must only be called inside the event thread! - if (isEventThread()) { - SwtAccess.onShutdown(currentDisplay, runnable); - } else { - dispatch(new Runnable() { - @Override - public - void run() { - SwtAccess.onShutdown(currentDisplay, runnable); - } - }); - } + SwtAccess.onShutdown(runnable); } } diff --git a/src/dorkbox/util/swt/SwtAccess.java b/src/dorkbox/util/swt/SwtAccess.java index 5186627..8d20bb1 100644 --- a/src/dorkbox/util/swt/SwtAccess.java +++ b/src/dorkbox/util/swt/SwtAccess.java @@ -1,7 +1,31 @@ package dorkbox.util.swt; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; + +import dorkbox.os.OS; + public class SwtAccess { + private static Display currentDisplay = null; + private static Thread currentDisplayThread = null; + + public static + void init() { + // we MUST save this on init, otherwise it is "null" when methods are run from the swing EDT. + currentDisplay = org.eclipse.swt.widgets.Display.getCurrent(); + currentDisplayThread = currentDisplay.getThread(); + } + + static + boolean isLoadable() { + return org.eclipse.swt.SWT.isLoadable(); + } + static void onShutdown(final org.eclipse.swt.widgets.Display currentDisplay, final Runnable runnable) { // currentDisplay.getShells() must only be called inside the event thread! @@ -15,4 +39,97 @@ class SwtAccess { } }); } + + static + int getVersion() { + return SWT.getVersion(); + } + + /** + * This is only necessary for linux. + * + * @return true if SWT is GTK3. False if SWT is GTK2. If for some reason we DO NOT KNOW, then we return false (GTK2). + */ + static boolean isGtk3() { + if (!OS.isLinux()) { + return false; + } + + // required to use reflection, because this is an internal class! + final String SWT_INTERNAL_CLASS = "org.eclipse.swt.internal.gtk.OS"; + Class osClass = AccessController.doPrivileged(new PrivilegedAction>() { + @Override + public + Class run() { + try { + return Class.forName(SWT_INTERNAL_CLASS, true, ClassLoader.getSystemClassLoader()); + } catch (Exception ignored) { + } + + try { + return Class.forName(SWT_INTERNAL_CLASS, true, Thread.currentThread().getContextClassLoader()); + } catch (Exception ignored) { + } + + return null; + } + }); + + + if (osClass == null) { + return false; + } + + final Class clazz = osClass; + Method method = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public + Method run() { + try { + return clazz.getMethod("gtk_major_version"); + } catch (Exception e) { + return null; + } + } + }); + + if (method == null) { + return false; + } + + int version = 0; + try { + version = ((Number)method.invoke(osClass)).intValue(); + } catch (Exception ignored) { + // this method doesn't exist. + } + + return version == 3; + } + + static + void dispatch(final Runnable runnable) { + currentDisplay.syncExec(runnable); + } + + static + boolean isEventThread() { + return Thread.currentThread() == currentDisplayThread; + } + + static + void onShutdown(final Runnable runnable) { + // currentDisplay.getShells() must only be called inside the event thread! + if (isEventThread()) { + SwtAccess.onShutdown(currentDisplay, runnable); + } else { + dispatch(new Runnable() { + @Override + public + void run() { + SwtAccess.onShutdown(currentDisplay, runnable); + } + }); + } + } }