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