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