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