8088132: [Swing, singleThread] ClassCastException in nested event loop when showing multiple message dialogs in SwingNode
Reviewed-by: serb
--- a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java Mon Sep 25 16:12:49 2017 +0530
+++ b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java Tue Sep 26 10:46:23 2017 +0530
@@ -30,6 +30,8 @@
import java.awt.peer.ComponentPeer;
import java.awt.peer.LightweightPeer;
import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.ListIterator;
@@ -77,6 +79,8 @@
private boolean consumeNextKeyTyped;
private Component restoreFocusTo;
+ private static boolean fxAppThreadIsDispatchThread;
+
static {
AWTAccessor.setDefaultKeyboardFocusManagerAccessor(
new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {
@@ -84,6 +88,13 @@
dkfm.consumeNextKeyTyped(e);
}
});
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ fxAppThreadIsDispatchThread =
+ "true".equals(System.getProperty("javafx.embed.singleThread"));
+ return null;
+ }
+ });
}
private static class TypeAheadMarker {
@@ -264,13 +275,41 @@
}
SunToolkit.postEvent(targetAppContext, se);
if (EventQueue.isDispatchThread()) {
- EventDispatchThread edt = (EventDispatchThread)
- Thread.currentThread();
- edt.pumpEvents(SentEvent.ID, new Conditional() {
+ if (Thread.currentThread() instanceof EventDispatchThread) {
+ EventDispatchThread edt = (EventDispatchThread)
+ Thread.currentThread();
+ edt.pumpEvents(SentEvent.ID, new Conditional() {
public boolean evaluate() {
return !se.dispatched && !targetAppContext.isDisposed();
}
});
+ } else {
+ if (fxAppThreadIsDispatchThread) {
+ Thread fxCheckDispatchThread = new Thread() {
+ @Override
+ public void run() {
+ while (!se.dispatched && !targetAppContext.isDisposed()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+ fxCheckDispatchThread.start();
+ try {
+ // check if event is dispatched or disposed
+ // but since this user app thread is same as
+ // dispatch thread in fx when run with
+ // javafx.embed.singleThread=true
+ // we do not wait infinitely to avoid deadlock
+ // as dispatch will ultimately be done by this thread
+ fxCheckDispatchThread.join(500);
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
} else {
synchronized (se) {
while (!se.dispatched && !targetAppContext.isDisposed()) {
--- a/src/java.desktop/share/classes/java/awt/SequencedEvent.java Mon Sep 25 16:12:49 2017 +0530
+++ b/src/java.desktop/share/classes/java/awt/SequencedEvent.java Tue Sep 26 10:46:23 2017 +0530
@@ -25,6 +25,8 @@
package java.awt;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.LinkedList;
import sun.awt.AWTAccessor;
import sun.awt.AppContext;
@@ -55,6 +57,8 @@
private AppContext appContext;
private boolean disposed;
+ private static boolean fxAppThreadIsDispatchThread;
+ private Thread fxCheckSequenceThread;
static {
AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {
public AWTEvent getNested(AWTEvent sequencedEvent) {
@@ -68,6 +72,13 @@
return new SequencedEvent(event);
}
});
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ fxAppThreadIsDispatchThread =
+ "true".equals(System.getProperty("javafx.embed.singleThread"));
+ return null;
+ }
+ });
}
/**
@@ -83,6 +94,21 @@
// All AWTEvents that are wrapped in SequencedEvents are (at
// least currently) implicitly generated by the system
SunToolkit.setSystemGenerated(nested);
+
+ if (fxAppThreadIsDispatchThread) {
+ fxCheckSequenceThread = new Thread() {
+ @Override
+ public void run() {
+ while(!isFirstOrDisposed()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+ }
synchronized (SequencedEvent.class) {
list.add(this);
}
@@ -106,13 +132,29 @@
if (getFirst() != this) {
if (EventQueue.isDispatchThread()) {
- EventDispatchThread edt = (EventDispatchThread)
- Thread.currentThread();
- edt.pumpEvents(SentEvent.ID, new Conditional() {
- public boolean evaluate() {
- return !SequencedEvent.this.isFirstOrDisposed();
+ if (Thread.currentThread() instanceof EventDispatchThread) {
+ EventDispatchThread edt = (EventDispatchThread)
+ Thread.currentThread();
+ edt.pumpEvents(SentEvent.ID, new Conditional() {
+ public boolean evaluate() {
+ return !SequencedEvent.this.isFirstOrDisposed();
+ }
+ });
+ } else {
+ if (fxAppThreadIsDispatchThread) {
+ fxCheckSequenceThread.start();
+ try {
+ // check if event is dispatched or disposed
+ // but since this user app thread is same as
+ // dispatch thread in fx when run with
+ // javafx.embed.singleThread=true
+ // we do not wait infinitely to avoid deadlock
+ // as dispatch will ultimately be done by this thread
+ fxCheckSequenceThread.join(500);
+ } catch (InterruptedException e) {
+ }
}
- });
+ }
} else {
while(!isFirstOrDisposed()) {
synchronized (SequencedEvent.class) {