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