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