From 59669bc867932d3196073525db87b43d534f0cef Mon Sep 17 00:00:00 2001 From: nathan Date: Wed, 12 Oct 2016 18:09:17 +0200 Subject: [PATCH] Fixed issues when running JavaFX or SWT on the swing EDT. --- src/dorkbox/systemTray/SystemTray.java | 25 ++++++++++-- src/dorkbox/systemTray/util/JavaFX.java | 52 ++++++++++++++++--------- src/dorkbox/systemTray/util/Swt.java | 27 +++++++++++-- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/dorkbox/systemTray/SystemTray.java b/src/dorkbox/systemTray/SystemTray.java index be7f795..a5b4abc 100644 --- a/src/dorkbox/systemTray/SystemTray.java +++ b/src/dorkbox/systemTray/SystemTray.java @@ -26,6 +26,8 @@ import java.io.PrintStream; import java.net.URL; import java.util.concurrent.atomic.AtomicReference; +import javax.swing.SwingUtilities; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -573,10 +575,26 @@ class SystemTray implements Menu { } } + if (isJavaFxLoaded) { + // This will initialize javaFX dispatch methods + JavaFX.init(); + } + else if (isSwtLoaded) { + // This will initialize swt dispatch methods + Swt.init(); + } - // if it's native + linux, have to do GTK instead. Don't need to be on the dispatch thread though. - // _AwtTray must be constructed on the EDT... - if (OS.isLinux() && NativeUI.class.isAssignableFrom(trayType) && trayType == _AwtTray.class) { + if ((isJavaFxLoaded || isSwtLoaded) && SwingUtilities.isEventDispatchThread()) { + // oh boy! This WILL NOT WORK. Let the dev know + throw new RuntimeException("SystemTray initialization can not occur on the swing Event Dispatch Thread (EDT)"); + } + + // javaFX and SWT should not start on the EDT!! + + // if it's linux + native menus must not start on the EDT! + // _AwtTray must be constructed on the EDT however... + if (isJavaFxLoaded || isSwtLoaded || + (OS.isLinux() && NativeUI.class.isAssignableFrom(trayType) && trayType == _AwtTray.class)) { try { reference.set((Menu) trayType.getConstructors()[0].newInstance(systemTray)); logger.info("Successfully Loaded: {}", trayType.getSimpleName()); @@ -619,7 +637,6 @@ class SystemTray implements Menu { "configuration"); } - // These install a shutdown hook in JavaFX/SWT, so that when the main window is closed -- the system tray is ALSO closed. if (ENABLE_SHUTDOWN_HOOK) { if (isJavaFxLoaded) { diff --git a/src/dorkbox/systemTray/util/JavaFX.java b/src/dorkbox/systemTray/util/JavaFX.java index 2ec0493..5694fce 100644 --- a/src/dorkbox/systemTray/util/JavaFX.java +++ b/src/dorkbox/systemTray/util/JavaFX.java @@ -29,24 +29,47 @@ public class JavaFX { // Methods are cached for performance - private static Method isEventThread; - private static Method dispatchMethod; + private static final Method dispatchMethod; + private static final Method isEventThreadMethod; - public static - void dispatch(final Runnable runnable) { - // javafx.application.Platform.runLater(runnable); + static { + Method _isEventThreadMethod = null; + Method _dispatchMethod = null; try { - if (dispatchMethod == null) { - Class clazz = Class.forName("javafx.application.Platform"); - dispatchMethod = clazz.getMethod("runLater"); - } + Class clazz = Class.forName("javafx.application.Platform"); + _dispatchMethod = clazz.getMethod("runLater", Runnable.class); - dispatchMethod.invoke(null, runnable); + clazz = Class.forName("javafx.application.Platform"); + _isEventThreadMethod = clazz.getMethod("isFxApplicationThread"); } catch (Throwable e) { if (SystemTray.DEBUG) { SystemTray.logger.error("Cannot initialize JavaFX", e); } + } + + dispatchMethod = _dispatchMethod; + isEventThreadMethod = _isEventThreadMethod; + } + + public static + void init() { + // empty method to initialize class + + if (dispatchMethod == null || isEventThreadMethod == null) { + SystemTray.logger.error("Unable to initialize JavaFX! Please create an issue with your OS and Java " + + "version so we may further investigate this issue."); + } + } + + + public static + void dispatch(final Runnable runnable) { +// javafx.application.Platform.runLater(runnable); + + try { + dispatchMethod.invoke(null, runnable); + } catch (Throwable e) { SystemTray.logger.error("Unable to execute JavaFX runLater(). Please create an issue with your OS and Java " + "version so we may further investigate this issue."); } @@ -57,15 +80,8 @@ class JavaFX { // javafx.application.Platform.isFxApplicationThread(); try { - if (isEventThread == null) { - Class clazz = Class.forName("javafx.application.Platform"); - isEventThread = clazz.getMethod("isFxApplicationThread"); - } - return (Boolean) isEventThread.invoke(null); + return (Boolean) isEventThreadMethod.invoke(null); } catch (Throwable e) { - if (SystemTray.DEBUG) { - SystemTray.logger.error("Cannot initialize JavaFX", e); - } SystemTray.logger.error("Unable to check if JavaFX is in the event thread. Please create an issue with your OS and Java " + "version so we may further investigate this issue."); } diff --git a/src/dorkbox/systemTray/util/Swt.java b/src/dorkbox/systemTray/util/Swt.java index 563b261..5c99b44 100644 --- a/src/dorkbox/systemTray/util/Swt.java +++ b/src/dorkbox/systemTray/util/Swt.java @@ -15,6 +15,10 @@ */ package dorkbox.systemTray.util; +import static dorkbox.systemTray.SystemTray.logger; + +import org.eclipse.swt.widgets.Display; + /** * Utility methods for SWT. *

@@ -22,16 +26,31 @@ package dorkbox.systemTray.util; */ public class Swt { + private static final Display currentDisplay; + + static { + // we have to save this, otherwise it is "null" when methods are run from the swing EDT. + currentDisplay = Display.getCurrent(); + } + + + public static + void init() { + // empty method to initialize class + if (currentDisplay == null) { + logger.error("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."); + }; + } + public static void dispatch(final Runnable runnable) { - org.eclipse.swt.widgets.Display.getCurrent() - .syncExec(runnable); + currentDisplay.syncExec(runnable); } public static void onShutdown(final Runnable runnable) { - org.eclipse.swt.widgets.Display.getCurrent() - .getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() { + currentDisplay.getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() { @Override public void handleEvent(final org.eclipse.swt.widgets.Event event) {