--- old/src/java.desktop/share/classes/java/awt/SequencedEvent.java 2018-10-29 11:02:08.000000000 -0700 +++ new/src/java.desktop/share/classes/java/awt/SequencedEvent.java 2018-10-29 11:02:08.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,9 @@ import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.LinkedList; + import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.SunToolkit; @@ -53,9 +55,11 @@ java.awt.event.FocusEvent.FOCUS_LAST + 1; private static final LinkedList list = new LinkedList<>(); + private static final Object SEQUENCED_EVENT_KEY = new Object(); + private final AWTEvent nested; - private AppContext appContext; - private boolean disposed; + private volatile AppContext appContext; + private volatile boolean disposed; private static boolean fxAppThreadIsDispatchThread; private Thread fxCheckSequenceThread; @@ -133,6 +137,8 @@ if (getFirst() != this) { if (EventQueue.isDispatchThread()) { if (Thread.currentThread() instanceof EventDispatchThread) { + getWaitingEvents().add(this); + dispatchWaitingEvents(); EventDispatchThread edt = (EventDispatchThread) Thread.currentThread(); edt.pumpEvents(ID, () -> !SequencedEvent.this.isFirstOrDisposed()); @@ -175,6 +181,38 @@ } /** + * Dispatching waiting events if such event became first or disposed. + */ + private static void dispatchWaitingEvents() { + ArrayList waitingEvents = getWaitingEvents(); + for (int i = 0; i < waitingEvents.size(); i++) { + SequencedEvent event = waitingEvents.get(i); + if (event.isFirstOrDisposed()) { + // found the first event, need to dispatch it/recheck the queue + waitingEvents.remove(i); + if (!event.disposed) { + event.dispatch(); + } + i = 0; // start from the beginning + } + } + } + + /** + * Returns the list of waiting events per-Appcontext. + */ + @SuppressWarnings("unchecked") + private static ArrayList getWaitingEvents() { + AppContext appContext = AppContext.getAppContext(); + Object list = appContext.get(SEQUENCED_EVENT_KEY); + if (list == null) { + list = new ArrayList<>(); + appContext.put(SEQUENCED_EVENT_KEY, list); + } + return (ArrayList) list; + } + + /** * true only if event exists and nested source appContext is disposed. */ private static final boolean isOwnerAppContextDisposed(SequencedEvent se) { @@ -241,7 +279,7 @@ } // Wake myself up if (appContext != null) { - SunToolkit.postEvent(appContext, new SentEvent()); + SunToolkit.postEvent(appContext, new Wakeup()); } SequencedEvent next = null; @@ -251,17 +289,40 @@ if (list.getFirst() == this) { list.removeFirst(); - - if (!list.isEmpty()) { - next = list.getFirst(); - } } else { list.remove(this); } - } + if (!list.isEmpty()) { + next = list.getFirst(); + } + } // Wake up waiting threads - if (next != null && next.appContext != null) { - SunToolkit.postEvent(next.appContext, new SentEvent()); + if (next != null) { + if (next.appContext != null) { + SunToolkit.postEvent(next.appContext, new Wakeup()); + } else { + // Appcontext of the next event still unknown, try all + for (AppContext appContext : AppContext.getAppContexts()) { + SunToolkit.postEvent(appContext, new Wakeup()); + } + } + } + } + + /** + * This event is used to wakeup the EDT if it waiting for a SequencedEvent. + */ + private static final class Wakeup extends AWTEvent implements ActiveEvent { + + private static final long serialVersionUID = -4585374989028949074L; + + Wakeup() { + super(new Object(), SequencedEvent.ID); + } + + @Override + public void dispatch() { + dispatchWaitingEvents(); } } }