1 /*
   2  * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt;
  27 
  28 import java.awt.event.*;
  29 
  30 import java.awt.peer.ComponentPeer;
  31 
  32 import java.lang.ref.WeakReference;
  33 import java.lang.reflect.InvocationTargetException;
  34 
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 
  38 import java.util.EmptyStackException;
  39 
  40 import sun.awt.*;
  41 import sun.awt.dnd.SunDropTargetEvent;
  42 import sun.util.logging.PlatformLogger;
  43 
  44 import java.util.concurrent.locks.Condition;
  45 import java.util.concurrent.locks.Lock;
  46 import java.util.concurrent.atomic.AtomicInteger;
  47 
  48 import java.security.AccessControlContext;
  49 
  50 import jdk.internal.access.SharedSecrets;
  51 import jdk.internal.access.JavaSecurityAccess;
  52 
  53 /**
  54  * {@code EventQueue} is a platform-independent class
  55  * that queues events, both from the underlying peer classes
  56  * and from trusted application classes.
  57  * <p>
  58  * It encapsulates asynchronous event dispatch machinery which
  59  * extracts events from the queue and dispatches them by calling
  60  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  61  * on this {@code EventQueue} with the event to be dispatched
  62  * as an argument.  The particular behavior of this machinery is
  63  * implementation-dependent.  The only requirements are that events
  64  * which were actually enqueued to this queue (note that events
  65  * being posted to the {@code EventQueue} can be coalesced)
  66  * are dispatched:
  67  * <dl>
  68  *   <dt> Sequentially.
  69  *   <dd> That is, it is not permitted that several events from
  70  *        this queue are dispatched simultaneously.
  71  *   <dt> In the same order as they are enqueued.
  72  *   <dd> That is, if {@code AWTEvent}&nbsp;A is enqueued
  73  *        to the {@code EventQueue} before
  74  *        {@code AWTEvent}&nbsp;B then event B will not be
  75  *        dispatched before event A.
  76  * </dl>
  77  * <p>
  78  * Some browsers partition applets in different code bases into
  79  * separate contexts, and establish walls between these contexts.
  80  * In such a scenario, there will be one {@code EventQueue}
  81  * per context. Other browsers place all applets into the same
  82  * context, implying that there will be only a single, global
  83  * {@code EventQueue} for all applets. This behavior is
  84  * implementation-dependent.  Consult your browser's documentation
  85  * for more information.
  86  * <p>
  87  * For information on the threading issues of the event dispatch
  88  * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
  89  * >AWT Threading Issues</a>.
  90  *
  91  * @author Thomas Ball
  92  * @author Fred Ecks
  93  * @author David Mendenhall
  94  *
  95  * @since       1.1
  96  */
  97 public class EventQueue {
  98     private static final AtomicInteger threadInitNumber = new AtomicInteger();
  99 
 100     private static final int LOW_PRIORITY = 0;
 101     private static final int NORM_PRIORITY = 1;
 102     private static final int HIGH_PRIORITY = 2;
 103     private static final int ULTIMATE_PRIORITY = 3;
 104 
 105     private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
 106 
 107     /*
 108      * We maintain one Queue for each priority that the EventQueue supports.
 109      * That is, the EventQueue object is actually implemented as
 110      * NUM_PRIORITIES queues and all Events on a particular internal Queue
 111      * have identical priority. Events are pulled off the EventQueue starting
 112      * with the Queue of highest priority. We progress in decreasing order
 113      * across all Queues.
 114      */
 115     private Queue[] queues = new Queue[NUM_PRIORITIES];
 116 
 117     /*
 118      * The next EventQueue on the stack, or null if this EventQueue is
 119      * on the top of the stack.  If nextQueue is non-null, requests to post
 120      * an event are forwarded to nextQueue.
 121      */
 122     private EventQueue nextQueue;
 123 
 124     /*
 125      * The previous EventQueue on the stack, or null if this is the
 126      * "base" EventQueue.
 127      */
 128     private EventQueue previousQueue;
 129 
 130     /*
 131      * A single lock to synchronize the push()/pop() and related operations with
 132      * all the EventQueues from the AppContext. Synchronization on any particular
 133      * event queue(s) is not enough: we should lock the whole stack.
 134      */
 135     private final Lock pushPopLock;
 136     private final Condition pushPopCond;
 137 
 138     /*
 139      * Dummy runnable to wake up EDT from getNextEvent() after
 140      push/pop is performed
 141      */
 142     private static final Runnable dummyRunnable = new Runnable() {
 143         public void run() {
 144         }
 145     };
 146 
 147     private EventDispatchThread dispatchThread;
 148 
 149     private final ThreadGroup threadGroup =
 150         Thread.currentThread().getThreadGroup();
 151     private final ClassLoader classLoader =
 152         Thread.currentThread().getContextClassLoader();
 153 
 154     /*
 155      * The time stamp of the last dispatched InputEvent or ActionEvent.
 156      */
 157     private long mostRecentEventTime = System.currentTimeMillis();
 158 
 159     /*
 160      * The time stamp of the last KeyEvent .
 161      */
 162     private long mostRecentKeyEventTime = System.currentTimeMillis();
 163 
 164     /**
 165      * The modifiers field of the current event, if the current event is an
 166      * InputEvent or ActionEvent.
 167      */
 168     private WeakReference<AWTEvent> currentEvent;
 169 
 170     /*
 171      * Non-zero if a thread is waiting in getNextEvent(int) for an event of
 172      * a particular ID to be posted to the queue.
 173      */
 174     private volatile int waitForID;
 175 
 176     /*
 177      * AppContext corresponding to the queue.
 178      */
 179     private final AppContext appContext;
 180 
 181     private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
 182 
 183     private FwDispatcher fwDispatcher;
 184 
 185     private static volatile PlatformLogger eventLog;
 186 
 187     private static final PlatformLogger getEventLog() {
 188         if(eventLog == null) {
 189             eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
 190         }
 191         return eventLog;
 192     }
 193 
 194     static {
 195         AWTAccessor.setEventQueueAccessor(
 196             new AWTAccessor.EventQueueAccessor() {
 197                 public Thread getDispatchThread(EventQueue eventQueue) {
 198                     return eventQueue.getDispatchThread();
 199                 }
 200                 public boolean isDispatchThreadImpl(EventQueue eventQueue) {
 201                     return eventQueue.isDispatchThreadImpl();
 202                 }
 203                 public void removeSourceEvents(EventQueue eventQueue,
 204                                                Object source,
 205                                                boolean removeAllEvents)
 206                 {
 207                     eventQueue.removeSourceEvents(source, removeAllEvents);
 208                 }
 209                 public boolean noEvents(EventQueue eventQueue) {
 210                     return eventQueue.noEvents();
 211                 }
 212                 public void wakeup(EventQueue eventQueue, boolean isShutdown) {
 213                     eventQueue.wakeup(isShutdown);
 214                 }
 215                 public void invokeAndWait(Object source, Runnable r)
 216                     throws InterruptedException, InvocationTargetException
 217                 {
 218                     EventQueue.invokeAndWait(source, r);
 219                 }
 220                 public void setFwDispatcher(EventQueue eventQueue,
 221                                             FwDispatcher dispatcher) {
 222                     eventQueue.setFwDispatcher(dispatcher);
 223                 }
 224 
 225                 @Override
 226                 public long getMostRecentEventTime(EventQueue eventQueue) {
 227                     return eventQueue.getMostRecentEventTimeImpl();
 228                 }
 229             });
 230     }
 231 
 232     @SuppressWarnings("removal")
 233     private static boolean fxAppThreadIsDispatchThread =
 234             AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 235                 public Boolean run() {
 236                     return "true".equals(System.getProperty("javafx.embed.singleThread"));
 237                 }
 238             });
 239 
 240     /**
 241      * Initializes a new instance of {@code EventQueue}.
 242      */
 243     public EventQueue() {
 244         for (int i = 0; i < NUM_PRIORITIES; i++) {
 245             queues[i] = new Queue();
 246         }
 247         /*
 248          * NOTE: if you ever have to start the associated event dispatch
 249          * thread at this point, be aware of the following problem:
 250          * If this EventQueue instance is created in
 251          * SunToolkit.createNewAppContext() the started dispatch thread
 252          * may call AppContext.getAppContext() before createNewAppContext()
 253          * completes thus causing mess in thread group to appcontext mapping.
 254          */
 255 
 256         appContext = AppContext.getAppContext();
 257         pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);
 258         pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);
 259     }
 260 
 261     /**
 262      * Posts a 1.1-style event to the {@code EventQueue}.
 263      * If there is an existing event on the queue with the same ID
 264      * and event source, the source {@code Component}'s
 265      * {@code coalesceEvents} method will be called.
 266      *
 267      * @param theEvent an instance of {@code java.awt.AWTEvent},
 268      *          or a subclass of it
 269      * @throws NullPointerException if {@code theEvent} is {@code null}
 270      */
 271     public void postEvent(AWTEvent theEvent) {
 272         SunToolkit.flushPendingEvents(appContext);
 273         postEventPrivate(theEvent);
 274     }
 275 
 276     /**
 277      * Posts a 1.1-style event to the {@code EventQueue}.
 278      * If there is an existing event on the queue with the same ID
 279      * and event source, the source {@code Component}'s
 280      * {@code coalesceEvents} method will be called.
 281      *
 282      * @param theEvent an instance of {@code java.awt.AWTEvent},
 283      *          or a subclass of it
 284      */
 285     private void postEventPrivate(AWTEvent theEvent) {
 286         theEvent.isPosted = true;
 287         pushPopLock.lock();
 288         try {
 289             if (nextQueue != null) {
 290                 // Forward the event to the top of EventQueue stack
 291                 nextQueue.postEventPrivate(theEvent);
 292                 return;
 293             }
 294             if (dispatchThread == null) {
 295                 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
 296                     return;
 297                 } else {
 298                     initDispatchThread();
 299                 }
 300             }
 301             postEvent(theEvent, getPriority(theEvent));
 302         } finally {
 303             pushPopLock.unlock();
 304         }
 305     }
 306 
 307     private static int getPriority(AWTEvent theEvent) {
 308         if (theEvent instanceof PeerEvent) {
 309             PeerEvent peerEvent = (PeerEvent)theEvent;
 310             if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
 311                 return ULTIMATE_PRIORITY;
 312             }
 313             if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
 314                 return HIGH_PRIORITY;
 315             }
 316             if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
 317                 return LOW_PRIORITY;
 318             }
 319         }
 320         int id = theEvent.getID();
 321         if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
 322             return LOW_PRIORITY;
 323         }
 324         return NORM_PRIORITY;
 325     }
 326 
 327     /**
 328      * Posts the event to the internal Queue of specified priority,
 329      * coalescing as appropriate.
 330      *
 331      * @param theEvent an instance of {@code java.awt.AWTEvent},
 332      *          or a subclass of it
 333      * @param priority  the desired priority of the event
 334      */
 335     private void postEvent(AWTEvent theEvent, int priority) {
 336         if (coalesceEvent(theEvent, priority)) {
 337             return;
 338         }
 339 
 340         EventQueueItem newItem = new EventQueueItem(theEvent);
 341 
 342         cacheEQItem(newItem);
 343 
 344         boolean notifyID = (theEvent.getID() == this.waitForID);
 345 
 346         if (queues[priority].head == null) {
 347             boolean shouldNotify = noEvents();
 348             queues[priority].head = queues[priority].tail = newItem;
 349 
 350             if (shouldNotify) {
 351                 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
 352                     AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
 353                 }
 354                 pushPopCond.signalAll();
 355             } else if (notifyID) {
 356                 pushPopCond.signalAll();
 357             }
 358         } else {
 359             // The event was not coalesced or has non-Component source.
 360             // Insert it at the end of the appropriate Queue.
 361             queues[priority].tail.next = newItem;
 362             queues[priority].tail = newItem;
 363             if (notifyID) {
 364                 pushPopCond.signalAll();
 365             }
 366         }
 367     }
 368 
 369     private boolean coalescePaintEvent(PaintEvent e) {
 370         ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
 371         if (sourcePeer != null) {
 372             sourcePeer.coalescePaintEvent(e);
 373         }
 374         EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
 375         if (cache == null) {
 376             return false;
 377         }
 378         int index = eventToCacheIndex(e);
 379 
 380         if (index != -1 && cache[index] != null) {
 381             PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
 382             if (merged != null) {
 383                 cache[index].event = merged;
 384                 return true;
 385             }
 386         }
 387         return false;
 388     }
 389 
 390     private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
 391         Rectangle aRect = a.getUpdateRect();
 392         Rectangle bRect = b.getUpdateRect();
 393         if (bRect.contains(aRect)) {
 394             return b;
 395         }
 396         if (aRect.contains(bRect)) {
 397             return a;
 398         }
 399         return null;
 400     }
 401 
 402     private boolean coalesceMouseEvent(MouseEvent e) {
 403         EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
 404         if (cache == null) {
 405             return false;
 406         }
 407         int index = eventToCacheIndex(e);
 408         if (index != -1 && cache[index] != null) {
 409             cache[index].event = e;
 410             return true;
 411         }
 412         return false;
 413     }
 414 
 415     private boolean coalescePeerEvent(PeerEvent e) {
 416         EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
 417         if (cache == null) {
 418             return false;
 419         }
 420         int index = eventToCacheIndex(e);
 421         if (index != -1 && cache[index] != null) {
 422             e = e.coalesceEvents((PeerEvent)cache[index].event);
 423             if (e != null) {
 424                 cache[index].event = e;
 425                 return true;
 426             } else {
 427                 cache[index] = null;
 428             }
 429         }
 430         return false;
 431     }
 432 
 433     /*
 434      * Should avoid of calling this method by any means
 435      * as it's working time is dependent on EQ length.
 436      * In the worst case this method alone can slow down the entire application
 437      * 10 times by stalling the Event processing.
 438      * Only here by backward compatibility reasons.
 439      */
 440     private boolean coalesceOtherEvent(AWTEvent e, int priority) {
 441         int id = e.getID();
 442         Component source = (Component)e.getSource();
 443         for (EventQueueItem entry = queues[priority].head;
 444             entry != null; entry = entry.next)
 445         {
 446             // Give Component.coalesceEvents a chance
 447             if (entry.event.getSource() == source && entry.event.getID() == id) {
 448                 AWTEvent coalescedEvent = source.coalesceEvents(
 449                     entry.event, e);
 450                 if (coalescedEvent != null) {
 451                     entry.event = coalescedEvent;
 452                     return true;
 453                 }
 454             }
 455         }
 456         return false;
 457     }
 458 
 459     private boolean coalesceEvent(AWTEvent e, int priority) {
 460         if (!(e.getSource() instanceof Component)) {
 461             return false;
 462         }
 463         if (e instanceof PeerEvent) {
 464             return coalescePeerEvent((PeerEvent)e);
 465         }
 466         // The worst case
 467         if (((Component)e.getSource()).isCoalescingEnabled()
 468             && coalesceOtherEvent(e, priority))
 469         {
 470             return true;
 471         }
 472         if (e instanceof PaintEvent) {
 473             return coalescePaintEvent((PaintEvent)e);
 474         }
 475         if (e instanceof MouseEvent) {
 476             return coalesceMouseEvent((MouseEvent)e);
 477         }
 478         return false;
 479     }
 480 
 481     private void cacheEQItem(EventQueueItem entry) {
 482         int index = eventToCacheIndex(entry.event);
 483         if (index != -1 && entry.event.getSource() instanceof Component) {
 484             Component source = (Component)entry.event.getSource();
 485             if (source.eventCache == null) {
 486                 source.eventCache = new EventQueueItem[CACHE_LENGTH];
 487             }
 488             source.eventCache[index] = entry;
 489         }
 490     }
 491 
 492     private void uncacheEQItem(EventQueueItem entry) {
 493         int index = eventToCacheIndex(entry.event);
 494         if (index != -1 && entry.event.getSource() instanceof Component) {
 495             Component source = (Component)entry.event.getSource();
 496             if (source.eventCache == null) {
 497                 return;
 498             }
 499             source.eventCache[index] = null;
 500         }
 501     }
 502 
 503     private static final int PAINT = 0;
 504     private static final int UPDATE = 1;
 505     private static final int MOVE = 2;
 506     private static final int DRAG = 3;
 507     private static final int PEER = 4;
 508     private static final int CACHE_LENGTH = 5;
 509 
 510     private static int eventToCacheIndex(AWTEvent e) {
 511         switch(e.getID()) {
 512         case PaintEvent.PAINT:
 513             return PAINT;
 514         case PaintEvent.UPDATE:
 515             return UPDATE;
 516         case MouseEvent.MOUSE_MOVED:
 517             return MOVE;
 518         case MouseEvent.MOUSE_DRAGGED:
 519             // Return -1 for SunDropTargetEvent since they are usually synchronous
 520             // and we don't want to skip them by coalescing with MouseEvent or other drag events
 521             return e instanceof SunDropTargetEvent ? -1 : DRAG;
 522         default:
 523             return e instanceof PeerEvent ? PEER : -1;
 524         }
 525     }
 526 
 527     /**
 528      * Returns whether an event is pending on any of the separate
 529      * Queues.
 530      * @return whether an event is pending on any of the separate Queues
 531      */
 532     private boolean noEvents() {
 533         for (int i = 0; i < NUM_PRIORITIES; i++) {
 534             if (queues[i].head != null) {
 535                 return false;
 536             }
 537         }
 538 
 539         return true;
 540     }
 541 
 542     /**
 543      * Removes an event from the {@code EventQueue} and
 544      * returns it.  This method will block until an event has
 545      * been posted by another thread.
 546      * @return the next {@code AWTEvent}
 547      * @exception InterruptedException
 548      *            if any thread has interrupted this thread
 549      */
 550     public AWTEvent getNextEvent() throws InterruptedException {
 551         do {
 552             /*
 553              * SunToolkit.flushPendingEvents must be called outside
 554              * of the synchronized block to avoid deadlock when
 555              * event queues are nested with push()/pop().
 556              */
 557             SunToolkit.flushPendingEvents(appContext);
 558             pushPopLock.lock();
 559             try {
 560                 AWTEvent event = getNextEventPrivate();
 561                 if (event != null) {
 562                     return event;
 563                 }
 564                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
 565                 pushPopCond.await();
 566             } finally {
 567                 pushPopLock.unlock();
 568             }
 569         } while(true);
 570     }
 571 
 572     /*
 573      * Must be called under the lock. Doesn't call flushPendingEvents()
 574      */
 575     AWTEvent getNextEventPrivate() throws InterruptedException {
 576         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 577             if (queues[i].head != null) {
 578                 EventQueueItem entry = queues[i].head;
 579                 queues[i].head = entry.next;
 580                 if (entry.next == null) {
 581                     queues[i].tail = null;
 582                 }
 583                 uncacheEQItem(entry);
 584                 return entry.event;
 585             }
 586         }
 587         return null;
 588     }
 589 
 590     AWTEvent getNextEvent(int id) throws InterruptedException {
 591         do {
 592             /*
 593              * SunToolkit.flushPendingEvents must be called outside
 594              * of the synchronized block to avoid deadlock when
 595              * event queues are nested with push()/pop().
 596              */
 597             SunToolkit.flushPendingEvents(appContext);
 598             pushPopLock.lock();
 599             try {
 600                 for (int i = 0; i < NUM_PRIORITIES; i++) {
 601                     for (EventQueueItem entry = queues[i].head, prev = null;
 602                          entry != null; prev = entry, entry = entry.next)
 603                     {
 604                         if (entry.event.getID() == id) {
 605                             if (prev == null) {
 606                                 queues[i].head = entry.next;
 607                             } else {
 608                                 prev.next = entry.next;
 609                             }
 610                             if (queues[i].tail == entry) {
 611                                 queues[i].tail = prev;
 612                             }
 613                             uncacheEQItem(entry);
 614                             return entry.event;
 615                         }
 616                     }
 617                 }
 618                 waitForID = id;
 619                 pushPopCond.await();
 620                 waitForID = 0;
 621             } finally {
 622                 pushPopLock.unlock();
 623             }
 624         } while(true);
 625     }
 626 
 627     /**
 628      * Returns the first event on the {@code EventQueue}
 629      * without removing it.
 630      * @return the first event
 631      */
 632     public AWTEvent peekEvent() {
 633         pushPopLock.lock();
 634         try {
 635             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 636                 if (queues[i].head != null) {
 637                     return queues[i].head.event;
 638                 }
 639             }
 640         } finally {
 641             pushPopLock.unlock();
 642         }
 643 
 644         return null;
 645     }
 646 
 647     /**
 648      * Returns the first event with the specified id, if any.
 649      * @param id the id of the type of event desired
 650      * @return the first event of the specified id or {@code null}
 651      *    if there is no such event
 652      */
 653     public AWTEvent peekEvent(int id) {
 654         pushPopLock.lock();
 655         try {
 656             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 657                 EventQueueItem q = queues[i].head;
 658                 for (; q != null; q = q.next) {
 659                     if (q.event.getID() == id) {
 660                         return q.event;
 661                     }
 662                 }
 663             }
 664         } finally {
 665             pushPopLock.unlock();
 666         }
 667 
 668         return null;
 669     }
 670 
 671     private static final JavaSecurityAccess javaSecurityAccess =
 672         SharedSecrets.getJavaSecurityAccess();
 673 
 674     /**
 675      * Dispatches an event. The manner in which the event is
 676      * dispatched depends upon the type of the event and the
 677      * type of the event's source object:
 678      *
 679      * <table class="striped">
 680      * <caption>Event types, source types, and dispatch methods</caption>
 681      * <thead>
 682      *   <tr>
 683      *     <th scope="col">Event Type
 684      *     <th scope="col">Source Type
 685      *     <th scope="col">Dispatched To
 686      * </thead>
 687      * <tbody>
 688      *   <tr>
 689      *     <th scope="row">ActiveEvent
 690      *     <td>Any
 691      *     <td>event.dispatch()
 692      *   <tr>
 693      *     <th scope="row">Other
 694      *     <td>Component
 695      *     <td>source.dispatchEvent(AWTEvent)
 696      *   <tr>
 697      *     <th scope="row">Other
 698      *     <td>MenuComponent
 699      *     <td>source.dispatchEvent(AWTEvent)
 700      *   <tr>
 701      *     <th scope="row">Other
 702      *     <td>Other
 703      *     <td>No action (ignored)
 704      * </tbody>
 705      * </table>
 706      *
 707      * @param event an instance of {@code java.awt.AWTEvent},
 708      *          or a subclass of it
 709      * @throws NullPointerException if {@code event} is {@code null}
 710      * @since           1.2
 711      */
 712     protected void dispatchEvent(final AWTEvent event) {
 713         final Object src = event.getSource();
 714         final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
 715             public Void run() {
 716                 // In case fwDispatcher is installed and we're already on the
 717                 // dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
 718                 // dispatch the event straight away.
 719                 if (fwDispatcher == null || isDispatchThreadImpl()) {
 720                     dispatchEventImpl(event, src);
 721                 } else {
 722                     fwDispatcher.scheduleDispatch(new Runnable() {
 723                         @Override
 724                         public void run() {
 725                             if (dispatchThread.filterAndCheckEvent(event)) {
 726                                 dispatchEventImpl(event, src);
 727                             }
 728                         }
 729                     });
 730                 }
 731                 return null;
 732             }
 733         };
 734 
 735         @SuppressWarnings("removal")
 736         final AccessControlContext stack = AccessController.getContext();
 737         @SuppressWarnings("removal")
 738         final AccessControlContext srcAcc = getAccessControlContextFrom(src);
 739         @SuppressWarnings("removal")
 740         final AccessControlContext eventAcc = event.getAccessControlContext();
 741         if (srcAcc == null) {
 742             javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
 743         } else {
 744             javaSecurityAccess.doIntersectionPrivilege(
 745                 new PrivilegedAction<Void>() {
 746                     public Void run() {
 747                         javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
 748                         return null;
 749                     }
 750                 }, stack, srcAcc);
 751         }
 752     }
 753 
 754     @SuppressWarnings("removal")
 755     private static AccessControlContext getAccessControlContextFrom(Object src) {
 756         return src instanceof Component ?
 757             ((Component)src).getAccessControlContext() :
 758             src instanceof MenuComponent ?
 759                 ((MenuComponent)src).getAccessControlContext() :
 760                 src instanceof TrayIcon ?
 761                     ((TrayIcon)src).getAccessControlContext() :
 762                     null;
 763     }
 764 
 765     /**
 766      * Called from dispatchEvent() under a correct AccessControlContext
 767      */
 768     private void dispatchEventImpl(final AWTEvent event, final Object src) {
 769         event.isPosted = true;
 770         if (event instanceof ActiveEvent) {
 771             // This could become the sole method of dispatching in time.
 772             setCurrentEventAndMostRecentTimeImpl(event);
 773             ((ActiveEvent)event).dispatch();
 774         } else if (src instanceof Component) {
 775             ((Component)src).dispatchEvent(event);
 776             event.dispatched();
 777         } else if (src instanceof MenuComponent) {
 778             ((MenuComponent)src).dispatchEvent(event);
 779         } else if (src instanceof TrayIcon) {
 780             ((TrayIcon)src).dispatchEvent(event);
 781         } else if (src instanceof AWTAutoShutdown) {
 782             if (noEvents()) {
 783                 dispatchThread.stopDispatching();
 784             }
 785         } else {
 786             if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 787                 getEventLog().fine("Unable to dispatch event: " + event);
 788             }
 789         }
 790     }
 791 
 792     /**
 793      * Returns the timestamp of the most recent event that had a timestamp, and
 794      * that was dispatched from the {@code EventQueue} associated with the
 795      * calling thread. If an event with a timestamp is currently being
 796      * dispatched, its timestamp will be returned. If no events have yet
 797      * been dispatched, the EventQueue's initialization time will be
 798      * returned instead.In the current version of
 799      * the JDK, only {@code InputEvent}s,
 800      * {@code ActionEvent}s, and {@code InvocationEvent}s have
 801      * timestamps; however, future versions of the JDK may add timestamps to
 802      * additional event types. Note that this method should only be invoked
 803      * from an application's {@link #isDispatchThread event dispatching thread}.
 804      * If this method is
 805      * invoked from another thread, the current system time (as reported by
 806      * {@code System.currentTimeMillis()}) will be returned instead.
 807      *
 808      * @return the timestamp of the last {@code InputEvent},
 809      *         {@code ActionEvent}, or {@code InvocationEvent} to be
 810      *         dispatched, or {@code System.currentTimeMillis()} if this
 811      *         method is invoked on a thread other than an event dispatching
 812      *         thread
 813      * @see java.awt.event.InputEvent#getWhen
 814      * @see java.awt.event.ActionEvent#getWhen
 815      * @see java.awt.event.InvocationEvent#getWhen
 816      * @see #isDispatchThread
 817      *
 818      * @since 1.4
 819      */
 820     public static long getMostRecentEventTime() {
 821         return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
 822     }
 823     private long getMostRecentEventTimeImpl() {
 824         pushPopLock.lock();
 825         try {
 826             return (Thread.currentThread() == dispatchThread)
 827                 ? mostRecentEventTime
 828                 : System.currentTimeMillis();
 829         } finally {
 830             pushPopLock.unlock();
 831         }
 832     }
 833 
 834     /**
 835      * @return most recent event time on all threads.
 836      */
 837     long getMostRecentEventTimeEx() {
 838         pushPopLock.lock();
 839         try {
 840             return mostRecentEventTime;
 841         } finally {
 842             pushPopLock.unlock();
 843         }
 844     }
 845 
 846     /**
 847      * Returns the event currently being dispatched by the
 848      * {@code EventQueue} associated with the calling thread. This is
 849      * useful if a method needs access to the event, but was not designed to
 850      * receive a reference to it as an argument. Note that this method should
 851      * only be invoked from an application's event dispatching thread. If this
 852      * method is invoked from another thread, null will be returned.
 853      *
 854      * @return the event currently being dispatched, or null if this method is
 855      *         invoked on a thread other than an event dispatching thread
 856      * @since 1.4
 857      */
 858     public static AWTEvent getCurrentEvent() {
 859         return Toolkit.getEventQueue().getCurrentEventImpl();
 860     }
 861     private AWTEvent getCurrentEventImpl() {
 862         pushPopLock.lock();
 863         try {
 864             if (Thread.currentThread() == dispatchThread
 865                     || fxAppThreadIsDispatchThread) {
 866                 return (currentEvent != null)
 867                         ? currentEvent.get()
 868                         : null;
 869             }
 870             return null;
 871         } finally {
 872             pushPopLock.unlock();
 873         }
 874     }
 875 
 876     /**
 877      * Replaces the existing {@code EventQueue} with the specified one.
 878      * Any pending events are transferred to the new {@code EventQueue}
 879      * for processing by it.
 880      *
 881      * @param newEventQueue an {@code EventQueue}
 882      *          (or subclass thereof) instance to be use
 883      * @see      java.awt.EventQueue#pop
 884      * @throws NullPointerException if {@code newEventQueue} is {@code null}
 885      * @since           1.2
 886      */
 887     public void push(EventQueue newEventQueue) {
 888         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 889             getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
 890         }
 891 
 892         pushPopLock.lock();
 893         try {
 894             EventQueue topQueue = this;
 895             while (topQueue.nextQueue != null) {
 896                 topQueue = topQueue.nextQueue;
 897             }
 898             if (topQueue.fwDispatcher != null) {
 899                 throw new RuntimeException("push() to queue with fwDispatcher");
 900             }
 901             if ((topQueue.dispatchThread != null) &&
 902                 (topQueue.dispatchThread.getEventQueue() == this))
 903             {
 904                 newEventQueue.dispatchThread = topQueue.dispatchThread;
 905                 topQueue.dispatchThread.setEventQueue(newEventQueue);
 906             }
 907 
 908             // Transfer all events forward to new EventQueue.
 909             while (topQueue.peekEvent() != null) {
 910                 try {
 911                     // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
 912                     newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
 913                 } catch (InterruptedException ie) {
 914                     if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 915                         getEventLog().fine("Interrupted push", ie);
 916                     }
 917                 }
 918             }
 919 
 920             if (topQueue.dispatchThread != null) {
 921                 // Wake up EDT waiting in getNextEvent(), so it can
 922                 // pick up a new EventQueue. Post the waking event before
 923                 // topQueue.nextQueue is assigned, otherwise the event would
 924                 // go newEventQueue
 925                 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
 926             }
 927 
 928             newEventQueue.previousQueue = topQueue;
 929             topQueue.nextQueue = newEventQueue;
 930 
 931             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
 932                 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
 933             }
 934 
 935             pushPopCond.signalAll();
 936         } finally {
 937             pushPopLock.unlock();
 938         }
 939     }
 940 
 941     /**
 942      * Stops dispatching events using this {@code EventQueue}.
 943      * Any pending events are transferred to the previous
 944      * {@code EventQueue} for processing.
 945      * <p>
 946      * Warning: To avoid deadlock, do not declare this method
 947      * synchronized in a subclass.
 948      *
 949      * @exception EmptyStackException if no previous push was made
 950      *  on this {@code EventQueue}
 951      * @see      java.awt.EventQueue#push
 952      * @since           1.2
 953      */
 954     protected void pop() throws EmptyStackException {
 955         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 956             getEventLog().fine("EventQueue.pop(" + this + ")");
 957         }
 958 
 959         pushPopLock.lock();
 960         try {
 961             EventQueue topQueue = this;
 962             while (topQueue.nextQueue != null) {
 963                 topQueue = topQueue.nextQueue;
 964             }
 965             EventQueue prevQueue = topQueue.previousQueue;
 966             if (prevQueue == null) {
 967                 throw new EmptyStackException();
 968             }
 969 
 970             topQueue.previousQueue = null;
 971             prevQueue.nextQueue = null;
 972 
 973             // Transfer all events back to previous EventQueue.
 974             while (topQueue.peekEvent() != null) {
 975                 try {
 976                     prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
 977                 } catch (InterruptedException ie) {
 978                     if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 979                         getEventLog().fine("Interrupted pop", ie);
 980                     }
 981                 }
 982             }
 983 
 984             if ((topQueue.dispatchThread != null) &&
 985                 (topQueue.dispatchThread.getEventQueue() == this))
 986             {
 987                 prevQueue.dispatchThread = topQueue.dispatchThread;
 988                 topQueue.dispatchThread.setEventQueue(prevQueue);
 989             }
 990 
 991             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
 992                 appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
 993             }
 994 
 995             // Wake up EDT waiting in getNextEvent(), so it can
 996             // pick up a new EventQueue
 997             topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
 998 
 999             pushPopCond.signalAll();
1000         } finally {
1001             pushPopLock.unlock();
1002         }
1003     }
1004 
1005     /**
1006      * Creates a new {@code secondary loop} associated with this
1007      * event queue. Use the {@link SecondaryLoop#enter} and
1008      * {@link SecondaryLoop#exit} methods to start and stop the
1009      * event loop and dispatch the events from this queue.
1010      *
1011      * @return secondaryLoop A new secondary loop object, which can
1012      *                       be used to launch a new nested event
1013      *                       loop and dispatch events from this queue
1014      *
1015      * @see SecondaryLoop#enter
1016      * @see SecondaryLoop#exit
1017      *
1018      * @since 1.7
1019      */
1020     public SecondaryLoop createSecondaryLoop() {
1021         return createSecondaryLoop(null, null, 0);
1022     }
1023 
1024     private class FwSecondaryLoopWrapper implements SecondaryLoop {
1025         private final SecondaryLoop loop;
1026         private final EventFilter filter;
1027 
1028         public FwSecondaryLoopWrapper(SecondaryLoop loop, EventFilter filter) {
1029             this.loop = loop;
1030             this.filter = filter;
1031         }
1032 
1033         @Override
1034         public boolean enter() {
1035             if (filter != null) {
1036                 dispatchThread.addEventFilter(filter);
1037             }
1038             return loop.enter();
1039         }
1040 
1041         @Override
1042         public boolean exit() {
1043             if (filter != null) {
1044                 dispatchThread.removeEventFilter(filter);
1045             }
1046             return loop.exit();
1047         }
1048     }
1049 
1050     SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {
1051         pushPopLock.lock();
1052         try {
1053             if (nextQueue != null) {
1054                 // Forward the request to the top of EventQueue stack
1055                 return nextQueue.createSecondaryLoop(cond, filter, interval);
1056             }
1057             if (fwDispatcher != null) {
1058                 return new FwSecondaryLoopWrapper(fwDispatcher.createSecondaryLoop(), filter);
1059             }
1060             if (dispatchThread == null) {
1061                 initDispatchThread();
1062             }
1063             return new WaitDispatchSupport(dispatchThread, cond, filter, interval);
1064         } finally {
1065             pushPopLock.unlock();
1066         }
1067     }
1068 
1069     /**
1070      * Returns true if the calling thread is
1071      * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1072      * dispatch thread. Use this method to ensure that a particular
1073      * task is being executed (or not being) there.
1074      * <p>
1075      * Note: use the {@link #invokeLater} or {@link #invokeAndWait}
1076      * methods to execute a task in
1077      * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1078      * dispatch thread.
1079      *
1080      * @return true if running in
1081      * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1082      * dispatch thread
1083      * @see             #invokeLater
1084      * @see             #invokeAndWait
1085      * @see             Toolkit#getSystemEventQueue
1086      * @since           1.2
1087      */
1088     public static boolean isDispatchThread() {
1089         EventQueue eq = Toolkit.getEventQueue();
1090         return eq.isDispatchThreadImpl();
1091     }
1092 
1093     final boolean isDispatchThreadImpl() {
1094         EventQueue eq = this;
1095         pushPopLock.lock();
1096         try {
1097             EventQueue next = eq.nextQueue;
1098             while (next != null) {
1099                 eq = next;
1100                 next = eq.nextQueue;
1101             }
1102             if (eq.fwDispatcher != null) {
1103                 return eq.fwDispatcher.isDispatchThread();
1104             }
1105             return (Thread.currentThread() == eq.dispatchThread);
1106         } finally {
1107             pushPopLock.unlock();
1108         }
1109     }
1110 
1111     @SuppressWarnings({"deprecation", "removal"})
1112     final void initDispatchThread() {
1113         pushPopLock.lock();
1114         try {
1115             if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
1116                 dispatchThread = AccessController.doPrivileged(
1117                     new PrivilegedAction<EventDispatchThread>() {
1118                         public EventDispatchThread run() {
1119                             EventDispatchThread t =
1120                                 new EventDispatchThread(threadGroup,
1121                                                         name,
1122                                                         EventQueue.this);
1123                             t.setContextClassLoader(classLoader);
1124                             t.setPriority(Thread.NORM_PRIORITY + 1);
1125                             t.setDaemon(false);
1126                             AWTAutoShutdown.getInstance().notifyThreadBusy(t);
1127                             return t;
1128                         }
1129                     }
1130                 );
1131                 dispatchThread.start();
1132             }
1133         } finally {
1134             pushPopLock.unlock();
1135         }
1136     }
1137 
1138     final void detachDispatchThread(EventDispatchThread edt) {
1139         /*
1140          * Minimize discard possibility for non-posted events
1141          */
1142         SunToolkit.flushPendingEvents(appContext);
1143         /*
1144          * This synchronized block is to secure that the event dispatch
1145          * thread won't die in the middle of posting a new event to the
1146          * associated event queue. It is important because we notify
1147          * that the event dispatch thread is busy after posting a new event
1148          * to its queue, so the EventQueue.dispatchThread reference must
1149          * be valid at that point.
1150          */
1151         pushPopLock.lock();
1152         try {
1153             if (edt == dispatchThread) {
1154                 dispatchThread = null;
1155             }
1156             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1157             /*
1158              * Event was posted after EDT events pumping had stopped, so start
1159              * another EDT to handle this event
1160              */
1161             if (peekEvent() != null) {
1162                 initDispatchThread();
1163             }
1164         } finally {
1165             pushPopLock.unlock();
1166         }
1167     }
1168 
1169     /*
1170      * Gets the {@code EventDispatchThread} for this
1171      * {@code EventQueue}.
1172      * @return the event dispatch thread associated with this event queue
1173      *         or {@code null} if this event queue doesn't have a
1174      *         working thread associated with it
1175      * @see    java.awt.EventQueue#initDispatchThread
1176      * @see    java.awt.EventQueue#detachDispatchThread
1177      */
1178     final EventDispatchThread getDispatchThread() {
1179         pushPopLock.lock();
1180         try {
1181             return dispatchThread;
1182         } finally {
1183             pushPopLock.unlock();
1184         }
1185     }
1186 
1187     /*
1188      * Removes any pending events for the specified source object.
1189      * If removeAllEvents parameter is {@code true} then all
1190      * events for the specified source object are removed, if it
1191      * is {@code false} then {@code SequencedEvent}, {@code SentEvent},
1192      * {@code FocusEvent}, {@code WindowEvent}, {@code KeyEvent},
1193      * and {@code InputMethodEvent} are kept in the queue, but all other
1194      * events are removed.
1195      *
1196      * This method is normally called by the source's
1197      * {@code removeNotify} method.
1198      */
1199     final void removeSourceEvents(Object source, boolean removeAllEvents) {
1200         SunToolkit.flushPendingEvents(appContext);
1201         pushPopLock.lock();
1202         try {
1203             for (int i = 0; i < NUM_PRIORITIES; i++) {
1204                 EventQueueItem entry = queues[i].head;
1205                 EventQueueItem prev = null;
1206                 while (entry != null) {
1207                     if ((entry.event.getSource() == source)
1208                         && (removeAllEvents
1209                             || ! (entry.event instanceof SequencedEvent
1210                                   || entry.event instanceof SentEvent
1211                                   || entry.event instanceof FocusEvent
1212                                   || entry.event instanceof WindowEvent
1213                                   || entry.event instanceof KeyEvent
1214                                   || entry.event instanceof InputMethodEvent)))
1215                     {
1216                         if (entry.event instanceof SequencedEvent) {
1217                             ((SequencedEvent)entry.event).dispose();
1218                         }
1219                         if (entry.event instanceof SentEvent) {
1220                             ((SentEvent)entry.event).dispose();
1221                         }
1222                         if (entry.event instanceof InvocationEvent) {
1223                             AWTAccessor.getInvocationEventAccessor()
1224                                     .dispose((InvocationEvent)entry.event);
1225                         }
1226                         if (entry.event instanceof SunDropTargetEvent) {
1227                             ((SunDropTargetEvent)entry.event).dispose();
1228                         }
1229                         if (prev == null) {
1230                             queues[i].head = entry.next;
1231                         } else {
1232                             prev.next = entry.next;
1233                         }
1234                         uncacheEQItem(entry);
1235                     } else {
1236                         prev = entry;
1237                     }
1238                     entry = entry.next;
1239                 }
1240                 queues[i].tail = prev;
1241             }
1242         } finally {
1243             pushPopLock.unlock();
1244         }
1245     }
1246 
1247     synchronized long getMostRecentKeyEventTime() {
1248         pushPopLock.lock();
1249         try {
1250             return mostRecentKeyEventTime;
1251         } finally {
1252             pushPopLock.unlock();
1253         }
1254     }
1255 
1256     static void setCurrentEventAndMostRecentTime(AWTEvent e) {
1257         Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
1258     }
1259     private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
1260         pushPopLock.lock();
1261         try {
1262             if (!fxAppThreadIsDispatchThread && Thread.currentThread() != dispatchThread) {
1263                 return;
1264             }
1265 
1266             currentEvent = new WeakReference<>(e);
1267 
1268             // This series of 'instanceof' checks should be replaced with a
1269             // polymorphic type (for example, an interface which declares a
1270             // getWhen() method). However, this would require us to make such
1271             // a type public, or to place it in sun.awt. Both of these approaches
1272             // have been frowned upon. So for now, we hack.
1273             //
1274             // In tiger, we will probably give timestamps to all events, so this
1275             // will no longer be an issue.
1276             long mostRecentEventTime2 = Long.MIN_VALUE;
1277             if (e instanceof InputEvent) {
1278                 InputEvent ie = (InputEvent)e;
1279                 mostRecentEventTime2 = ie.getWhen();
1280                 if (e instanceof KeyEvent) {
1281                     mostRecentKeyEventTime = ie.getWhen();
1282                 }
1283             } else if (e instanceof InputMethodEvent) {
1284                 InputMethodEvent ime = (InputMethodEvent)e;
1285                 mostRecentEventTime2 = ime.getWhen();
1286             } else if (e instanceof ActionEvent) {
1287                 ActionEvent ae = (ActionEvent)e;
1288                 mostRecentEventTime2 = ae.getWhen();
1289             } else if (e instanceof InvocationEvent) {
1290                 InvocationEvent ie = (InvocationEvent)e;
1291                 mostRecentEventTime2 = ie.getWhen();
1292             }
1293             mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1294         } finally {
1295             pushPopLock.unlock();
1296         }
1297     }
1298 
1299     /**
1300      * Causes {@code runnable} to have its {@code run}
1301      * method called in the {@link #isDispatchThread dispatch thread} of
1302      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1303      * This will happen after all pending events are processed.
1304      *
1305      * @param runnable  the {@code Runnable} whose {@code run}
1306      *                  method should be executed
1307      *                  asynchronously in the
1308      *                  {@link #isDispatchThread event dispatch thread}
1309      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1310      * @see             #invokeAndWait
1311      * @see             Toolkit#getSystemEventQueue
1312      * @see             #isDispatchThread
1313      * @since           1.2
1314      */
1315     public static void invokeLater(Runnable runnable) {
1316         Toolkit.getEventQueue().postEvent(
1317             new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1318     }
1319 
1320     /**
1321      * Causes {@code runnable} to have its {@code run}
1322      * method called in the {@link #isDispatchThread dispatch thread} of
1323      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1324      * This will happen after all pending events are processed.
1325      * The call blocks until this has happened.  This method
1326      * will throw an Error if called from the
1327      * {@link #isDispatchThread event dispatcher thread}.
1328      *
1329      * @param runnable  the {@code Runnable} whose {@code run}
1330      *                  method should be executed
1331      *                  synchronously in the
1332      *                  {@link #isDispatchThread event dispatch thread}
1333      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1334      * @exception       InterruptedException  if any thread has
1335      *                  interrupted this thread
1336      * @exception       InvocationTargetException  if an throwable is thrown
1337      *                  when running {@code runnable}
1338      * @see             #invokeLater
1339      * @see             Toolkit#getSystemEventQueue
1340      * @see             #isDispatchThread
1341      * @since           1.2
1342      */
1343     public static void invokeAndWait(Runnable runnable)
1344         throws InterruptedException, InvocationTargetException
1345     {
1346         invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1347     }
1348 
1349     static void invokeAndWait(Object source, Runnable runnable)
1350         throws InterruptedException, InvocationTargetException
1351     {
1352         if (EventQueue.isDispatchThread()) {
1353             throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1354         }
1355 
1356         class AWTInvocationLock {}
1357         Object lock = new AWTInvocationLock();
1358 
1359         InvocationEvent event =
1360             new InvocationEvent(source, runnable, lock, true);
1361 
1362         synchronized (lock) {
1363             Toolkit.getEventQueue().postEvent(event);
1364             while (!event.isDispatched()) {
1365                 lock.wait();
1366             }
1367         }
1368 
1369         Throwable eventThrowable = event.getThrowable();
1370         if (eventThrowable != null) {
1371             throw new InvocationTargetException(eventThrowable);
1372         }
1373     }
1374 
1375     /*
1376      * Called from PostEventQueue.postEvent to notify that a new event
1377      * appeared. First it proceeds to the EventQueue on the top of the
1378      * stack, then notifies the associated dispatch thread if it exists
1379      * or starts a new one otherwise.
1380      */
1381     private void wakeup(boolean isShutdown) {
1382         pushPopLock.lock();
1383         try {
1384             if (nextQueue != null) {
1385                 // Forward call to the top of EventQueue stack.
1386                 nextQueue.wakeup(isShutdown);
1387             } else if (dispatchThread != null) {
1388                 pushPopCond.signalAll();
1389             } else if (!isShutdown) {
1390                 initDispatchThread();
1391             }
1392         } finally {
1393             pushPopLock.unlock();
1394         }
1395     }
1396 
1397     // The method is used by AWTAccessor for javafx/AWT single threaded mode.
1398     private void setFwDispatcher(FwDispatcher dispatcher) {
1399         if (nextQueue != null) {
1400             nextQueue.setFwDispatcher(dispatcher);
1401         } else {
1402             fwDispatcher = dispatcher;
1403         }
1404     }
1405 }
1406 
1407 /**
1408  * The Queue object holds pointers to the beginning and end of one internal
1409  * queue. An EventQueue object is composed of multiple internal Queues, one
1410  * for each priority supported by the EventQueue. All Events on a particular
1411  * internal Queue have identical priority.
1412  */
1413 class Queue {
1414     EventQueueItem head;
1415     EventQueueItem tail;
1416 }