--- old/javafx-embed-swing/src/javafx/embed/swing/JFXPanel.java 2013-05-21 17:35:13.000000000 +0400 +++ new/javafx-embed-swing/src/javafx/embed/swing/JFXPanel.java 2013-05-21 17:35:12.000000000 +0400 @@ -660,7 +660,7 @@ @Override public void eventDispatched(AWTEvent event) { if (event instanceof sun.awt.UngrabEvent) { - Platform.runLater(new Runnable() { + SwingFXUtils.runOnFxThread(new Runnable() { @Override public void run() { if (JFXPanel.this.stagePeer != null) { @@ -693,7 +693,7 @@ updateComponentSize(); // see RT-23603 - Platform.runLater(new Runnable() { + SwingFXUtils.runOnFxThread(new Runnable() { @Override public void run() { if ((stage != null) && !stage.isShowing()) { @@ -711,7 +711,7 @@ * chain of parent components are removed. */ @Override public void removeNotify() { - Platform.runLater(new Runnable() { + SwingFXUtils.runOnFxThread(new Runnable() { @Override public void run() { if ((stage != null) && stage.isShowing()) { --- old/javafx-embed-swing/src/javafx/embed/swing/SwingDnD.java 2013-05-21 17:35:14.000000000 +0400 +++ new/javafx-embed-swing/src/javafx/embed/swing/SwingDnD.java 2013-05-21 17:35:14.000000000 +0400 @@ -166,7 +166,7 @@ } try { - dropTarget.handleDragLeave(); + getDropTarget().handleDragLeave(); } finally { endDnD(); } --- old/javafx-embed-swing/src/javafx/embed/swing/SwingFXUtils.java 2013-05-21 17:35:14.000000000 +0400 +++ new/javafx-embed-swing/src/javafx/embed/swing/SwingFXUtils.java 2013-05-21 17:35:14.000000000 +0400 @@ -26,15 +26,26 @@ package javafx.embed.swing; import java.awt.AlphaComposite; +import java.awt.EventQueue; import java.awt.Graphics2D; +import java.awt.SecondaryLoop; import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.IntBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.concurrent.atomic.AtomicBoolean; +import javafx.application.Platform; import javafx.scene.image.Image; import javafx.scene.image.PixelFormat; import javafx.scene.image.PixelReader; import javafx.scene.image.PixelWriter; import javafx.scene.image.WritableImage; import javafx.scene.image.WritablePixelFormat; +import com.sun.javafx.application.PlatformImpl; +import com.sun.javafx.tk.Toolkit; +import sun.awt.FwDispatcher; import sun.awt.image.IntegerComponentRaster; /** @@ -180,4 +191,74 @@ pr.getPixels(0, 0, iw, ih, pf, data, offset, scan); return bimg; } + + /** + * Invokes a runnable directly if called from the FX Application Thread, + * uses Platform.runLater otherwise + */ + public static void runOnFxThread(Runnable runnable) { + if (Platform.isFxApplicationThread()) { + runnable.run(); + } else { + Platform.runLater(runnable); + } + } + + private static class FwSecondaryLoop implements SecondaryLoop { + + private final AtomicBoolean isRunning = new AtomicBoolean(false); + + @Override public boolean enter() { + if (isRunning.compareAndSet(false, true)) { + PlatformImpl.runAndWait(new Runnable() { + @Override public void run() { + Toolkit.getToolkit().enterNestedEventLoop(FwSecondaryLoop.this); + } + }); + return true; + } + return false; + } + + @Override public boolean exit() { + if (isRunning.compareAndSet(true, false)) { + PlatformImpl.runAndWait(new Runnable() { + @Override public void run() { + Toolkit.getToolkit().exitNestedEventLoop(FwSecondaryLoop.this, null); + } + }); + return true; + } + return false; + } + } + + private static class FXDispatcher implements FwDispatcher { + @Override public boolean isDispatchThread() { + return Platform.isFxApplicationThread(); + } + + @Override public void scheduleDispatch(Runnable runnable) { + runOnFxThread(runnable); + } + + @Override public SecondaryLoop createSecondaryLoop() { + return new FwSecondaryLoop(); + } + } + + //Called with reflection from PlatformImpl to avoid dependency + public static void installFwEventQueue() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + EventQueue eq = AccessController.doPrivileged( + new PrivilegedAction() { + @Override public EventQueue run() { + return java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue(); + } + }); + + Method installDispatcher = eq.getClass().getDeclaredMethod("setFwDispatcher", FwDispatcher.class); + installDispatcher.setAccessible(true); + installDispatcher.invoke(eq, new FXDispatcher()); + } } --- old/javafx-ui-common/src/com/sun/javafx/application/PlatformImpl.java 2013-05-21 17:35:15.000000000 +0400 +++ new/javafx-ui-common/src/com/sun/javafx/application/PlatformImpl.java 2013-05-21 17:35:15.000000000 +0400 @@ -29,6 +29,8 @@ import com.sun.javafx.css.StyleManager; import com.sun.javafx.runtime.SystemProperties; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.security.AccessControlContext; import java.util.List; import java.util.Set; @@ -75,6 +77,7 @@ private static Boolean hasTouch; private static Boolean hasMultiTouch; private static Boolean hasPointer; + private static boolean isThreadMerged = false; /** * Set a flag indicating whether this application should show up in the @@ -143,6 +146,10 @@ if (s != null) { hasPointer = Boolean.valueOf(s); } + s = System.getProperty("javafx.embed.singleThread"); + if (s != null) { + isThreadMerged = Boolean.valueOf(s); + } return null; } }); @@ -172,6 +179,23 @@ r.run(); } }); + + //Initialize the thread merging mechanism + if (isThreadMerged) { + //Use reflection in case we are running compact profile + try { + Class swingFXUtilsClass = Class.forName("javafx.embed.swing.SwingFXUtils"); + Method installFwEventQueue = swingFXUtilsClass.getMethod("installFwEventQueue"); + + waitForStart(); + installFwEventQueue.invoke(null); + + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException("Property javafx.embed.singleThread is not supported"); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } } private static void waitForStart() {