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