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