Fixed issues when running JavaFX or SWT on the swing EDT.

This commit is contained in:
nathan 2016-10-12 18:09:17 +02:00
parent bc4d22c586
commit 59669bc867
3 changed files with 78 additions and 26 deletions

View File

@ -26,6 +26,8 @@ import java.io.PrintStream;
import java.net.URL; import java.net.URL;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.swing.SwingUtilities;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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. if ((isJavaFxLoaded || isSwtLoaded) && SwingUtilities.isEventDispatchThread()) {
// _AwtTray must be constructed on the EDT... // oh boy! This WILL NOT WORK. Let the dev know
if (OS.isLinux() && NativeUI.class.isAssignableFrom(trayType) && trayType == _AwtTray.class) { 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 { try {
reference.set((Menu) trayType.getConstructors()[0].newInstance(systemTray)); reference.set((Menu) trayType.getConstructors()[0].newInstance(systemTray));
logger.info("Successfully Loaded: {}", trayType.getSimpleName()); logger.info("Successfully Loaded: {}", trayType.getSimpleName());
@ -619,7 +637,6 @@ class SystemTray implements Menu {
"configuration"); "configuration");
} }
// These install a shutdown hook in JavaFX/SWT, so that when the main window is closed -- the system tray is ALSO closed. // 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 (ENABLE_SHUTDOWN_HOOK) {
if (isJavaFxLoaded) { if (isJavaFxLoaded) {

View File

@ -29,24 +29,47 @@ public
class JavaFX { class JavaFX {
// Methods are cached for performance // Methods are cached for performance
private static Method isEventThread; private static final Method dispatchMethod;
private static Method dispatchMethod; private static final Method isEventThreadMethod;
public static static {
void dispatch(final Runnable runnable) { Method _isEventThreadMethod = null;
// javafx.application.Platform.runLater(runnable); Method _dispatchMethod = null;
try { try {
if (dispatchMethod == null) { Class<?> clazz = Class.forName("javafx.application.Platform");
Class<?> clazz = Class.forName("javafx.application.Platform"); _dispatchMethod = clazz.getMethod("runLater", Runnable.class);
dispatchMethod = clazz.getMethod("runLater");
}
dispatchMethod.invoke(null, runnable); clazz = Class.forName("javafx.application.Platform");
_isEventThreadMethod = clazz.getMethod("isFxApplicationThread");
} catch (Throwable e) { } catch (Throwable e) {
if (SystemTray.DEBUG) { if (SystemTray.DEBUG) {
SystemTray.logger.error("Cannot initialize JavaFX", e); 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 " + 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."); "version so we may further investigate this issue.");
} }
@ -57,15 +80,8 @@ class JavaFX {
// javafx.application.Platform.isFxApplicationThread(); // javafx.application.Platform.isFxApplicationThread();
try { try {
if (isEventThread == null) { return (Boolean) isEventThreadMethod.invoke(null);
Class<?> clazz = Class.forName("javafx.application.Platform");
isEventThread = clazz.getMethod("isFxApplicationThread");
}
return (Boolean) isEventThread.invoke(null);
} catch (Throwable e) { } 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 " + 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."); "version so we may further investigate this issue.");
} }

View File

@ -15,6 +15,10 @@
*/ */
package dorkbox.systemTray.util; package dorkbox.systemTray.util;
import static dorkbox.systemTray.SystemTray.logger;
import org.eclipse.swt.widgets.Display;
/** /**
* Utility methods for SWT. * Utility methods for SWT.
* <p> * <p>
@ -22,16 +26,31 @@ package dorkbox.systemTray.util;
*/ */
public public
class Swt { 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 public static
void dispatch(final Runnable runnable) { void dispatch(final Runnable runnable) {
org.eclipse.swt.widgets.Display.getCurrent() currentDisplay.syncExec(runnable);
.syncExec(runnable);
} }
public static public static
void onShutdown(final Runnable runnable) { void onShutdown(final Runnable runnable) {
org.eclipse.swt.widgets.Display.getCurrent() currentDisplay.getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() {
.getShells()[0].addListener(org.eclipse.swt.SWT.Close, new org.eclipse.swt.widgets.Listener() {
@Override @Override
public public
void handleEvent(final org.eclipse.swt.widgets.Event event) { void handleEvent(final org.eclipse.swt.widgets.Event event) {