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