< prev index next >

src/java.desktop/share/classes/java/awt/EventQueue.java

Print this page




  34 
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 
  38 import java.util.EmptyStackException;
  39 
  40 import sun.awt.*;
  41 import sun.awt.dnd.SunDropTargetEvent;
  42 import sun.util.logging.PlatformLogger;
  43 
  44 import java.util.concurrent.locks.Condition;
  45 import java.util.concurrent.locks.Lock;
  46 import java.util.concurrent.atomic.AtomicInteger;
  47 
  48 import java.security.AccessControlContext;
  49 
  50 import jdk.internal.misc.SharedSecrets;
  51 import jdk.internal.misc.JavaSecurityAccess;
  52 
  53 /**
  54  * <code>EventQueue</code> is a platform-independent class
  55  * that queues events, both from the underlying peer classes
  56  * and from trusted application classes.
  57  * <p>
  58  * It encapsulates asynchronous event dispatch machinery which
  59  * extracts events from the queue and dispatches them by calling
  60  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  61  * on this <code>EventQueue</code> with the event to be dispatched
  62  * as an argument.  The particular behavior of this machinery is
  63  * implementation-dependent.  The only requirements are that events
  64  * which were actually enqueued to this queue (note that events
  65  * being posted to the <code>EventQueue</code> can be coalesced)
  66  * are dispatched:
  67  * <dl>
  68  *   <dt> Sequentially.
  69  *   <dd> That is, it is not permitted that several events from
  70  *        this queue are dispatched simultaneously.
  71  *   <dt> In the same order as they are enqueued.
  72  *   <dd> That is, if <code>AWTEvent</code>&nbsp;A is enqueued
  73  *        to the <code>EventQueue</code> before
  74  *        <code>AWTEvent</code>&nbsp;B then event B will not be
  75  *        dispatched before event A.
  76  * </dl>
  77  * <p>
  78  * Some browsers partition applets in different code bases into
  79  * separate contexts, and establish walls between these contexts.
  80  * In such a scenario, there will be one <code>EventQueue</code>
  81  * per context. Other browsers place all applets into the same
  82  * context, implying that there will be only a single, global
  83  * <code>EventQueue</code> for all applets. This behavior is
  84  * implementation-dependent.  Consult your browser's documentation
  85  * for more information.
  86  * <p>
  87  * For information on the threading issues of the event dispatch
  88  * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
  89  * >AWT Threading Issues</a>.
  90  *
  91  * @author Thomas Ball
  92  * @author Fred Ecks
  93  * @author David Mendenhall
  94  *
  95  * @since       1.1
  96  */
  97 public class EventQueue {
  98     private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
  99 
 100     private static final int LOW_PRIORITY = 0;
 101     private static final int NORM_PRIORITY = 1;
 102     private static final int HIGH_PRIORITY = 2;
 103     private static final int ULTIMATE_PRIORITY = 3;


 234      */
 235     public EventQueue() {
 236         for (int i = 0; i < NUM_PRIORITIES; i++) {
 237             queues[i] = new Queue();
 238         }
 239         /*
 240          * NOTE: if you ever have to start the associated event dispatch
 241          * thread at this point, be aware of the following problem:
 242          * If this EventQueue instance is created in
 243          * SunToolkit.createNewAppContext() the started dispatch thread
 244          * may call AppContext.getAppContext() before createNewAppContext()
 245          * completes thus causing mess in thread group to appcontext mapping.
 246          */
 247 
 248         appContext = AppContext.getAppContext();
 249         pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);
 250         pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);
 251     }
 252 
 253     /**
 254      * Posts a 1.1-style event to the <code>EventQueue</code>.
 255      * If there is an existing event on the queue with the same ID
 256      * and event source, the source <code>Component</code>'s
 257      * <code>coalesceEvents</code> method will be called.
 258      *
 259      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 260      *          or a subclass of it
 261      * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
 262      */
 263     public void postEvent(AWTEvent theEvent) {
 264         SunToolkit.flushPendingEvents(appContext);
 265         postEventPrivate(theEvent);
 266     }
 267 
 268     /**
 269      * Posts a 1.1-style event to the <code>EventQueue</code>.
 270      * If there is an existing event on the queue with the same ID
 271      * and event source, the source <code>Component</code>'s
 272      * <code>coalesceEvents</code> method will be called.
 273      *
 274      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 275      *          or a subclass of it
 276      */
 277     private final void postEventPrivate(AWTEvent theEvent) {
 278         theEvent.isPosted = true;
 279         pushPopLock.lock();
 280         try {
 281             if (nextQueue != null) {
 282                 // Forward the event to the top of EventQueue stack
 283                 nextQueue.postEventPrivate(theEvent);
 284                 return;
 285             }
 286             if (dispatchThread == null) {
 287                 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
 288                     return;
 289                 } else {
 290                     initDispatchThread();
 291                 }
 292             }
 293             postEvent(theEvent, getPriority(theEvent));
 294         } finally {


 303                 return ULTIMATE_PRIORITY;
 304             }
 305             if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
 306                 return HIGH_PRIORITY;
 307             }
 308             if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
 309                 return LOW_PRIORITY;
 310             }
 311         }
 312         int id = theEvent.getID();
 313         if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
 314             return LOW_PRIORITY;
 315         }
 316         return NORM_PRIORITY;
 317     }
 318 
 319     /**
 320      * Posts the event to the internal Queue of specified priority,
 321      * coalescing as appropriate.
 322      *
 323      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 324      *          or a subclass of it
 325      * @param priority  the desired priority of the event
 326      */
 327     private void postEvent(AWTEvent theEvent, int priority) {
 328         if (coalesceEvent(theEvent, priority)) {
 329             return;
 330         }
 331 
 332         EventQueueItem newItem = new EventQueueItem(theEvent);
 333 
 334         cacheEQItem(newItem);
 335 
 336         boolean notifyID = (theEvent.getID() == this.waitForID);
 337 
 338         if (queues[priority].head == null) {
 339             boolean shouldNotify = noEvents();
 340             queues[priority].head = queues[priority].tail = newItem;
 341 
 342             if (shouldNotify) {
 343                 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {


 515             return e instanceof PeerEvent ? PEER : -1;
 516         }
 517     }
 518 
 519     /**
 520      * Returns whether an event is pending on any of the separate
 521      * Queues.
 522      * @return whether an event is pending on any of the separate Queues
 523      */
 524     private boolean noEvents() {
 525         for (int i = 0; i < NUM_PRIORITIES; i++) {
 526             if (queues[i].head != null) {
 527                 return false;
 528             }
 529         }
 530 
 531         return true;
 532     }
 533 
 534     /**
 535      * Removes an event from the <code>EventQueue</code> and
 536      * returns it.  This method will block until an event has
 537      * been posted by another thread.
 538      * @return the next <code>AWTEvent</code>
 539      * @exception InterruptedException
 540      *            if any thread has interrupted this thread
 541      */
 542     public AWTEvent getNextEvent() throws InterruptedException {
 543         do {
 544             /*
 545              * SunToolkit.flushPendingEvents must be called outside
 546              * of the synchronized block to avoid deadlock when
 547              * event queues are nested with push()/pop().
 548              */
 549             SunToolkit.flushPendingEvents(appContext);
 550             pushPopLock.lock();
 551             try {
 552                 AWTEvent event = getNextEventPrivate();
 553                 if (event != null) {
 554                     return event;
 555                 }
 556                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
 557                 pushPopCond.await();
 558             } finally {


 600                                 prev.next = entry.next;
 601                             }
 602                             if (queues[i].tail == entry) {
 603                                 queues[i].tail = prev;
 604                             }
 605                             uncacheEQItem(entry);
 606                             return entry.event;
 607                         }
 608                     }
 609                 }
 610                 waitForID = id;
 611                 pushPopCond.await();
 612                 waitForID = 0;
 613             } finally {
 614                 pushPopLock.unlock();
 615             }
 616         } while(true);
 617     }
 618 
 619     /**
 620      * Returns the first event on the <code>EventQueue</code>
 621      * without removing it.
 622      * @return the first event
 623      */
 624     public AWTEvent peekEvent() {
 625         pushPopLock.lock();
 626         try {
 627             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 628                 if (queues[i].head != null) {
 629                     return queues[i].head.event;
 630                 }
 631             }
 632         } finally {
 633             pushPopLock.unlock();
 634         }
 635 
 636         return null;
 637     }
 638 
 639     /**
 640      * Returns the first event with the specified id, if any.
 641      * @param id the id of the type of event desired
 642      * @return the first event of the specified id or <code>null</code>
 643      *    if there is no such event
 644      */
 645     public AWTEvent peekEvent(int id) {
 646         pushPopLock.lock();
 647         try {
 648             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 649                 EventQueueItem q = queues[i].head;
 650                 for (; q != null; q = q.next) {
 651                     if (q.event.getID() == id) {
 652                         return q.event;
 653                     }
 654                 }
 655             }
 656         } finally {
 657             pushPopLock.unlock();
 658         }
 659 
 660         return null;
 661     }
 662 


 679      *     <td>Any</td>
 680      *     <td>event.dispatch()</td>
 681      * </tr>
 682      * <tr>
 683      *     <td>Other</td>
 684      *     <td>Component</td>
 685      *     <td>source.dispatchEvent(AWTEvent)</td>
 686      * </tr>
 687      * <tr>
 688      *     <td>Other</td>
 689      *     <td>MenuComponent</td>
 690      *     <td>source.dispatchEvent(AWTEvent)</td>
 691      * </tr>
 692      * <tr>
 693      *     <td>Other</td>
 694      *     <td>Other</td>
 695      *     <td>No action (ignored)</td>
 696      * </tr>
 697      * </table>
 698      *
 699      * @param event an instance of <code>java.awt.AWTEvent</code>,
 700      *          or a subclass of it
 701      * @throws NullPointerException if <code>event</code> is <code>null</code>
 702      * @since           1.2
 703      */
 704     protected void dispatchEvent(final AWTEvent event) {
 705         final Object src = event.getSource();
 706         final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
 707             public Void run() {
 708                 // In case fwDispatcher is installed and we're already on the
 709                 // dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
 710                 // dispatch the event straight away.
 711                 if (fwDispatcher == null || isDispatchThreadImpl()) {
 712                     dispatchEventImpl(event, src);
 713                 } else {
 714                     fwDispatcher.scheduleDispatch(new Runnable() {
 715                         @Override
 716                         public void run() {
 717                             dispatchEventImpl(event, src);
 718                         }
 719                     });
 720                 }
 721                 return null;


 760         } else if (src instanceof Component) {
 761             ((Component)src).dispatchEvent(event);
 762             event.dispatched();
 763         } else if (src instanceof MenuComponent) {
 764             ((MenuComponent)src).dispatchEvent(event);
 765         } else if (src instanceof TrayIcon) {
 766             ((TrayIcon)src).dispatchEvent(event);
 767         } else if (src instanceof AWTAutoShutdown) {
 768             if (noEvents()) {
 769                 dispatchThread.stopDispatching();
 770             }
 771         } else {
 772             if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 773                 getEventLog().fine("Unable to dispatch event: " + event);
 774             }
 775         }
 776     }
 777 
 778     /**
 779      * Returns the timestamp of the most recent event that had a timestamp, and
 780      * that was dispatched from the <code>EventQueue</code> associated with the
 781      * calling thread. If an event with a timestamp is currently being
 782      * dispatched, its timestamp will be returned. If no events have yet
 783      * been dispatched, the EventQueue's initialization time will be
 784      * returned instead.In the current version of
 785      * the JDK, only <code>InputEvent</code>s,
 786      * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
 787      * timestamps; however, future versions of the JDK may add timestamps to
 788      * additional event types. Note that this method should only be invoked
 789      * from an application's {@link #isDispatchThread event dispatching thread}.
 790      * If this method is
 791      * invoked from another thread, the current system time (as reported by
 792      * <code>System.currentTimeMillis()</code>) will be returned instead.
 793      *
 794      * @return the timestamp of the last <code>InputEvent</code>,
 795      *         <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
 796      *         dispatched, or <code>System.currentTimeMillis()</code> if this
 797      *         method is invoked on a thread other than an event dispatching
 798      *         thread
 799      * @see java.awt.event.InputEvent#getWhen
 800      * @see java.awt.event.ActionEvent#getWhen
 801      * @see java.awt.event.InvocationEvent#getWhen
 802      * @see #isDispatchThread
 803      *
 804      * @since 1.4
 805      */
 806     public static long getMostRecentEventTime() {
 807         return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
 808     }
 809     private long getMostRecentEventTimeImpl() {
 810         pushPopLock.lock();
 811         try {
 812             return (Thread.currentThread() == dispatchThread)
 813                 ? mostRecentEventTime
 814                 : System.currentTimeMillis();
 815         } finally {
 816             pushPopLock.unlock();
 817         }
 818     }
 819 
 820     /**
 821      * @return most recent event time on all threads.
 822      */
 823     long getMostRecentEventTimeEx() {
 824         pushPopLock.lock();
 825         try {
 826             return mostRecentEventTime;
 827         } finally {
 828             pushPopLock.unlock();
 829         }
 830     }
 831 
 832     /**
 833      * Returns the event currently being dispatched by the
 834      * <code>EventQueue</code> associated with the calling thread. This is
 835      * useful if a method needs access to the event, but was not designed to
 836      * receive a reference to it as an argument. Note that this method should
 837      * only be invoked from an application's event dispatching thread. If this
 838      * method is invoked from another thread, null will be returned.
 839      *
 840      * @return the event currently being dispatched, or null if this method is
 841      *         invoked on a thread other than an event dispatching thread
 842      * @since 1.4
 843      */
 844     public static AWTEvent getCurrentEvent() {
 845         return Toolkit.getEventQueue().getCurrentEventImpl();
 846     }
 847     private AWTEvent getCurrentEventImpl() {
 848         pushPopLock.lock();
 849         try {
 850                 return (Thread.currentThread() == dispatchThread)
 851                 ? currentEvent.get()
 852                 : null;
 853         } finally {
 854             pushPopLock.unlock();
 855         }
 856     }
 857 
 858     /**
 859      * Replaces the existing <code>EventQueue</code> with the specified one.
 860      * Any pending events are transferred to the new <code>EventQueue</code>
 861      * for processing by it.
 862      *
 863      * @param newEventQueue an <code>EventQueue</code>
 864      *          (or subclass thereof) instance to be use
 865      * @see      java.awt.EventQueue#pop
 866      * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
 867      * @since           1.2
 868      */
 869     public void push(EventQueue newEventQueue) {
 870         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 871             getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
 872         }
 873 
 874         pushPopLock.lock();
 875         try {
 876             EventQueue topQueue = this;
 877             while (topQueue.nextQueue != null) {
 878                 topQueue = topQueue.nextQueue;
 879             }
 880             if (topQueue.fwDispatcher != null) {
 881                 throw new RuntimeException("push() to queue with fwDispatcher");
 882             }
 883             if ((topQueue.dispatchThread != null) &&
 884                 (topQueue.dispatchThread.getEventQueue() == this))
 885             {
 886                 newEventQueue.dispatchThread = topQueue.dispatchThread;


 904                 // pick up a new EventQueue. Post the waking event before
 905                 // topQueue.nextQueue is assigned, otherwise the event would
 906                 // go newEventQueue
 907                 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
 908             }
 909 
 910             newEventQueue.previousQueue = topQueue;
 911             topQueue.nextQueue = newEventQueue;
 912 
 913             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
 914                 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
 915             }
 916 
 917             pushPopCond.signalAll();
 918         } finally {
 919             pushPopLock.unlock();
 920         }
 921     }
 922 
 923     /**
 924      * Stops dispatching events using this <code>EventQueue</code>.
 925      * Any pending events are transferred to the previous
 926      * <code>EventQueue</code> for processing.
 927      * <p>
 928      * Warning: To avoid deadlock, do not declare this method
 929      * synchronized in a subclass.
 930      *
 931      * @exception EmptyStackException if no previous push was made
 932      *  on this <code>EventQueue</code>
 933      * @see      java.awt.EventQueue#push
 934      * @since           1.2
 935      */
 936     protected void pop() throws EmptyStackException {
 937         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 938             getEventLog().fine("EventQueue.pop(" + this + ")");
 939         }
 940 
 941         pushPopLock.lock();
 942         try {
 943             EventQueue topQueue = this;
 944             while (topQueue.nextQueue != null) {
 945                 topQueue = topQueue.nextQueue;
 946             }
 947             EventQueue prevQueue = topQueue.previousQueue;
 948             if (prevQueue == null) {
 949                 throw new EmptyStackException();
 950             }
 951 
 952             topQueue.previousQueue = null;


1105          */
1106         pushPopLock.lock();
1107         try {
1108             if (edt == dispatchThread) {
1109                 dispatchThread = null;
1110             }
1111             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1112             /*
1113              * Event was posted after EDT events pumping had stopped, so start
1114              * another EDT to handle this event
1115              */
1116             if (peekEvent() != null) {
1117                 initDispatchThread();
1118             }
1119         } finally {
1120             pushPopLock.unlock();
1121         }
1122     }
1123 
1124     /*
1125      * Gets the <code>EventDispatchThread</code> for this
1126      * <code>EventQueue</code>.
1127      * @return the event dispatch thread associated with this event queue
1128      *         or <code>null</code> if this event queue doesn't have a
1129      *         working thread associated with it
1130      * @see    java.awt.EventQueue#initDispatchThread
1131      * @see    java.awt.EventQueue#detachDispatchThread
1132      */
1133     final EventDispatchThread getDispatchThread() {
1134         pushPopLock.lock();
1135         try {
1136             return dispatchThread;
1137         } finally {
1138             pushPopLock.unlock();
1139         }
1140     }
1141 
1142     /*
1143      * Removes any pending events for the specified source object.
1144      * If removeAllEvents parameter is <code>true</code> then all
1145      * events for the specified source object are removed, if it
1146      * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
1147      * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
1148      * and <code>InputMethodEvent</code> are kept in the queue, but all other
1149      * events are removed.
1150      *
1151      * This method is normally called by the source's
1152      * <code>removeNotify</code> method.
1153      */
1154     final void removeSourceEvents(Object source, boolean removeAllEvents) {
1155         SunToolkit.flushPendingEvents(appContext);
1156         pushPopLock.lock();
1157         try {
1158             for (int i = 0; i < NUM_PRIORITIES; i++) {
1159                 EventQueueItem entry = queues[i].head;
1160                 EventQueueItem prev = null;
1161                 while (entry != null) {
1162                     if ((entry.event.getSource() == source)
1163                         && (removeAllEvents
1164                             || ! (entry.event instanceof SequencedEvent
1165                                   || entry.event instanceof SentEvent
1166                                   || entry.event instanceof FocusEvent
1167                                   || entry.event instanceof WindowEvent
1168                                   || entry.event instanceof KeyEvent
1169                                   || entry.event instanceof InputMethodEvent)))
1170                     {
1171                         if (entry.event instanceof SequencedEvent) {
1172                             ((SequencedEvent)entry.event).dispose();


1232                 if (e instanceof KeyEvent) {
1233                     mostRecentKeyEventTime = ie.getWhen();
1234                 }
1235             } else if (e instanceof InputMethodEvent) {
1236                 InputMethodEvent ime = (InputMethodEvent)e;
1237                 mostRecentEventTime2 = ime.getWhen();
1238             } else if (e instanceof ActionEvent) {
1239                 ActionEvent ae = (ActionEvent)e;
1240                 mostRecentEventTime2 = ae.getWhen();
1241             } else if (e instanceof InvocationEvent) {
1242                 InvocationEvent ie = (InvocationEvent)e;
1243                 mostRecentEventTime2 = ie.getWhen();
1244             }
1245             mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1246         } finally {
1247             pushPopLock.unlock();
1248         }
1249     }
1250 
1251     /**
1252      * Causes <code>runnable</code> to have its <code>run</code>
1253      * method called in the {@link #isDispatchThread dispatch thread} of
1254      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1255      * This will happen after all pending events are processed.
1256      *
1257      * @param runnable  the <code>Runnable</code> whose <code>run</code>
1258      *                  method should be executed
1259      *                  asynchronously in the
1260      *                  {@link #isDispatchThread event dispatch thread}
1261      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1262      * @see             #invokeAndWait
1263      * @see             Toolkit#getSystemEventQueue
1264      * @see             #isDispatchThread
1265      * @since           1.2
1266      */
1267     public static void invokeLater(Runnable runnable) {
1268         Toolkit.getEventQueue().postEvent(
1269             new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1270     }
1271 
1272     /**
1273      * Causes <code>runnable</code> to have its <code>run</code>
1274      * method called in the {@link #isDispatchThread dispatch thread} of
1275      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1276      * This will happen after all pending events are processed.
1277      * The call blocks until this has happened.  This method
1278      * will throw an Error if called from the
1279      * {@link #isDispatchThread event dispatcher thread}.
1280      *
1281      * @param runnable  the <code>Runnable</code> whose <code>run</code>
1282      *                  method should be executed
1283      *                  synchronously in the
1284      *                  {@link #isDispatchThread event dispatch thread}
1285      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1286      * @exception       InterruptedException  if any thread has
1287      *                  interrupted this thread
1288      * @exception       InvocationTargetException  if an throwable is thrown
1289      *                  when running <code>runnable</code>
1290      * @see             #invokeLater
1291      * @see             Toolkit#getSystemEventQueue
1292      * @see             #isDispatchThread
1293      * @since           1.2
1294      */
1295     public static void invokeAndWait(Runnable runnable)
1296         throws InterruptedException, InvocationTargetException
1297     {
1298         invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1299     }
1300 
1301     static void invokeAndWait(Object source, Runnable runnable)
1302         throws InterruptedException, InvocationTargetException
1303     {
1304         if (EventQueue.isDispatchThread()) {
1305             throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1306         }
1307 
1308         class AWTInvocationLock {}
1309         Object lock = new AWTInvocationLock();




  34 
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 
  38 import java.util.EmptyStackException;
  39 
  40 import sun.awt.*;
  41 import sun.awt.dnd.SunDropTargetEvent;
  42 import sun.util.logging.PlatformLogger;
  43 
  44 import java.util.concurrent.locks.Condition;
  45 import java.util.concurrent.locks.Lock;
  46 import java.util.concurrent.atomic.AtomicInteger;
  47 
  48 import java.security.AccessControlContext;
  49 
  50 import jdk.internal.misc.SharedSecrets;
  51 import jdk.internal.misc.JavaSecurityAccess;
  52 
  53 /**
  54  * {@code EventQueue} is a platform-independent class
  55  * that queues events, both from the underlying peer classes
  56  * and from trusted application classes.
  57  * <p>
  58  * It encapsulates asynchronous event dispatch machinery which
  59  * extracts events from the queue and dispatches them by calling
  60  * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  61  * on this {@code EventQueue} with the event to be dispatched
  62  * as an argument.  The particular behavior of this machinery is
  63  * implementation-dependent.  The only requirements are that events
  64  * which were actually enqueued to this queue (note that events
  65  * being posted to the {@code EventQueue} can be coalesced)
  66  * are dispatched:
  67  * <dl>
  68  *   <dt> Sequentially.
  69  *   <dd> That is, it is not permitted that several events from
  70  *        this queue are dispatched simultaneously.
  71  *   <dt> In the same order as they are enqueued.
  72  *   <dd> That is, if {@code AWTEvent}&nbsp;A is enqueued
  73  *        to the {@code EventQueue} before
  74  *        {@code AWTEvent}&nbsp;B then event B will not be
  75  *        dispatched before event A.
  76  * </dl>
  77  * <p>
  78  * Some browsers partition applets in different code bases into
  79  * separate contexts, and establish walls between these contexts.
  80  * In such a scenario, there will be one {@code EventQueue}
  81  * per context. Other browsers place all applets into the same
  82  * context, implying that there will be only a single, global
  83  * {@code EventQueue} for all applets. This behavior is
  84  * implementation-dependent.  Consult your browser's documentation
  85  * for more information.
  86  * <p>
  87  * For information on the threading issues of the event dispatch
  88  * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
  89  * >AWT Threading Issues</a>.
  90  *
  91  * @author Thomas Ball
  92  * @author Fred Ecks
  93  * @author David Mendenhall
  94  *
  95  * @since       1.1
  96  */
  97 public class EventQueue {
  98     private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
  99 
 100     private static final int LOW_PRIORITY = 0;
 101     private static final int NORM_PRIORITY = 1;
 102     private static final int HIGH_PRIORITY = 2;
 103     private static final int ULTIMATE_PRIORITY = 3;


 234      */
 235     public EventQueue() {
 236         for (int i = 0; i < NUM_PRIORITIES; i++) {
 237             queues[i] = new Queue();
 238         }
 239         /*
 240          * NOTE: if you ever have to start the associated event dispatch
 241          * thread at this point, be aware of the following problem:
 242          * If this EventQueue instance is created in
 243          * SunToolkit.createNewAppContext() the started dispatch thread
 244          * may call AppContext.getAppContext() before createNewAppContext()
 245          * completes thus causing mess in thread group to appcontext mapping.
 246          */
 247 
 248         appContext = AppContext.getAppContext();
 249         pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);
 250         pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);
 251     }
 252 
 253     /**
 254      * Posts a 1.1-style event to the {@code EventQueue}.
 255      * If there is an existing event on the queue with the same ID
 256      * and event source, the source {@code Component}'s
 257      * {@code coalesceEvents} method will be called.
 258      *
 259      * @param theEvent an instance of {@code java.awt.AWTEvent},
 260      *          or a subclass of it
 261      * @throws NullPointerException if {@code theEvent} is {@code null}
 262      */
 263     public void postEvent(AWTEvent theEvent) {
 264         SunToolkit.flushPendingEvents(appContext);
 265         postEventPrivate(theEvent);
 266     }
 267 
 268     /**
 269      * Posts a 1.1-style event to the {@code EventQueue}.
 270      * If there is an existing event on the queue with the same ID
 271      * and event source, the source {@code Component}'s
 272      * {@code coalesceEvents} method will be called.
 273      *
 274      * @param theEvent an instance of {@code java.awt.AWTEvent},
 275      *          or a subclass of it
 276      */
 277     private final void postEventPrivate(AWTEvent theEvent) {
 278         theEvent.isPosted = true;
 279         pushPopLock.lock();
 280         try {
 281             if (nextQueue != null) {
 282                 // Forward the event to the top of EventQueue stack
 283                 nextQueue.postEventPrivate(theEvent);
 284                 return;
 285             }
 286             if (dispatchThread == null) {
 287                 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
 288                     return;
 289                 } else {
 290                     initDispatchThread();
 291                 }
 292             }
 293             postEvent(theEvent, getPriority(theEvent));
 294         } finally {


 303                 return ULTIMATE_PRIORITY;
 304             }
 305             if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
 306                 return HIGH_PRIORITY;
 307             }
 308             if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
 309                 return LOW_PRIORITY;
 310             }
 311         }
 312         int id = theEvent.getID();
 313         if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
 314             return LOW_PRIORITY;
 315         }
 316         return NORM_PRIORITY;
 317     }
 318 
 319     /**
 320      * Posts the event to the internal Queue of specified priority,
 321      * coalescing as appropriate.
 322      *
 323      * @param theEvent an instance of {@code java.awt.AWTEvent},
 324      *          or a subclass of it
 325      * @param priority  the desired priority of the event
 326      */
 327     private void postEvent(AWTEvent theEvent, int priority) {
 328         if (coalesceEvent(theEvent, priority)) {
 329             return;
 330         }
 331 
 332         EventQueueItem newItem = new EventQueueItem(theEvent);
 333 
 334         cacheEQItem(newItem);
 335 
 336         boolean notifyID = (theEvent.getID() == this.waitForID);
 337 
 338         if (queues[priority].head == null) {
 339             boolean shouldNotify = noEvents();
 340             queues[priority].head = queues[priority].tail = newItem;
 341 
 342             if (shouldNotify) {
 343                 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {


 515             return e instanceof PeerEvent ? PEER : -1;
 516         }
 517     }
 518 
 519     /**
 520      * Returns whether an event is pending on any of the separate
 521      * Queues.
 522      * @return whether an event is pending on any of the separate Queues
 523      */
 524     private boolean noEvents() {
 525         for (int i = 0; i < NUM_PRIORITIES; i++) {
 526             if (queues[i].head != null) {
 527                 return false;
 528             }
 529         }
 530 
 531         return true;
 532     }
 533 
 534     /**
 535      * Removes an event from the {@code EventQueue} and
 536      * returns it.  This method will block until an event has
 537      * been posted by another thread.
 538      * @return the next {@code AWTEvent}
 539      * @exception InterruptedException
 540      *            if any thread has interrupted this thread
 541      */
 542     public AWTEvent getNextEvent() throws InterruptedException {
 543         do {
 544             /*
 545              * SunToolkit.flushPendingEvents must be called outside
 546              * of the synchronized block to avoid deadlock when
 547              * event queues are nested with push()/pop().
 548              */
 549             SunToolkit.flushPendingEvents(appContext);
 550             pushPopLock.lock();
 551             try {
 552                 AWTEvent event = getNextEventPrivate();
 553                 if (event != null) {
 554                     return event;
 555                 }
 556                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
 557                 pushPopCond.await();
 558             } finally {


 600                                 prev.next = entry.next;
 601                             }
 602                             if (queues[i].tail == entry) {
 603                                 queues[i].tail = prev;
 604                             }
 605                             uncacheEQItem(entry);
 606                             return entry.event;
 607                         }
 608                     }
 609                 }
 610                 waitForID = id;
 611                 pushPopCond.await();
 612                 waitForID = 0;
 613             } finally {
 614                 pushPopLock.unlock();
 615             }
 616         } while(true);
 617     }
 618 
 619     /**
 620      * Returns the first event on the {@code EventQueue}
 621      * without removing it.
 622      * @return the first event
 623      */
 624     public AWTEvent peekEvent() {
 625         pushPopLock.lock();
 626         try {
 627             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 628                 if (queues[i].head != null) {
 629                     return queues[i].head.event;
 630                 }
 631             }
 632         } finally {
 633             pushPopLock.unlock();
 634         }
 635 
 636         return null;
 637     }
 638 
 639     /**
 640      * Returns the first event with the specified id, if any.
 641      * @param id the id of the type of event desired
 642      * @return the first event of the specified id or {@code null}
 643      *    if there is no such event
 644      */
 645     public AWTEvent peekEvent(int id) {
 646         pushPopLock.lock();
 647         try {
 648             for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
 649                 EventQueueItem q = queues[i].head;
 650                 for (; q != null; q = q.next) {
 651                     if (q.event.getID() == id) {
 652                         return q.event;
 653                     }
 654                 }
 655             }
 656         } finally {
 657             pushPopLock.unlock();
 658         }
 659 
 660         return null;
 661     }
 662 


 679      *     <td>Any</td>
 680      *     <td>event.dispatch()</td>
 681      * </tr>
 682      * <tr>
 683      *     <td>Other</td>
 684      *     <td>Component</td>
 685      *     <td>source.dispatchEvent(AWTEvent)</td>
 686      * </tr>
 687      * <tr>
 688      *     <td>Other</td>
 689      *     <td>MenuComponent</td>
 690      *     <td>source.dispatchEvent(AWTEvent)</td>
 691      * </tr>
 692      * <tr>
 693      *     <td>Other</td>
 694      *     <td>Other</td>
 695      *     <td>No action (ignored)</td>
 696      * </tr>
 697      * </table>
 698      *
 699      * @param event an instance of {@code java.awt.AWTEvent},
 700      *          or a subclass of it
 701      * @throws NullPointerException if {@code event} is {@code null}
 702      * @since           1.2
 703      */
 704     protected void dispatchEvent(final AWTEvent event) {
 705         final Object src = event.getSource();
 706         final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
 707             public Void run() {
 708                 // In case fwDispatcher is installed and we're already on the
 709                 // dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
 710                 // dispatch the event straight away.
 711                 if (fwDispatcher == null || isDispatchThreadImpl()) {
 712                     dispatchEventImpl(event, src);
 713                 } else {
 714                     fwDispatcher.scheduleDispatch(new Runnable() {
 715                         @Override
 716                         public void run() {
 717                             dispatchEventImpl(event, src);
 718                         }
 719                     });
 720                 }
 721                 return null;


 760         } else if (src instanceof Component) {
 761             ((Component)src).dispatchEvent(event);
 762             event.dispatched();
 763         } else if (src instanceof MenuComponent) {
 764             ((MenuComponent)src).dispatchEvent(event);
 765         } else if (src instanceof TrayIcon) {
 766             ((TrayIcon)src).dispatchEvent(event);
 767         } else if (src instanceof AWTAutoShutdown) {
 768             if (noEvents()) {
 769                 dispatchThread.stopDispatching();
 770             }
 771         } else {
 772             if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 773                 getEventLog().fine("Unable to dispatch event: " + event);
 774             }
 775         }
 776     }
 777 
 778     /**
 779      * Returns the timestamp of the most recent event that had a timestamp, and
 780      * that was dispatched from the {@code EventQueue} associated with the
 781      * calling thread. If an event with a timestamp is currently being
 782      * dispatched, its timestamp will be returned. If no events have yet
 783      * been dispatched, the EventQueue's initialization time will be
 784      * returned instead.In the current version of
 785      * the JDK, only {@code InputEvent}s,
 786      * {@code ActionEvent}s, and {@code InvocationEvent}s have
 787      * timestamps; however, future versions of the JDK may add timestamps to
 788      * additional event types. Note that this method should only be invoked
 789      * from an application's {@link #isDispatchThread event dispatching thread}.
 790      * If this method is
 791      * invoked from another thread, the current system time (as reported by
 792      * {@code System.currentTimeMillis()}) will be returned instead.
 793      *
 794      * @return the timestamp of the last {@code InputEvent},
 795      *         {@code ActionEvent}, or {@code InvocationEvent} to be
 796      *         dispatched, or {@code System.currentTimeMillis()} if this
 797      *         method is invoked on a thread other than an event dispatching
 798      *         thread
 799      * @see java.awt.event.InputEvent#getWhen
 800      * @see java.awt.event.ActionEvent#getWhen
 801      * @see java.awt.event.InvocationEvent#getWhen
 802      * @see #isDispatchThread
 803      *
 804      * @since 1.4
 805      */
 806     public static long getMostRecentEventTime() {
 807         return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
 808     }
 809     private long getMostRecentEventTimeImpl() {
 810         pushPopLock.lock();
 811         try {
 812             return (Thread.currentThread() == dispatchThread)
 813                 ? mostRecentEventTime
 814                 : System.currentTimeMillis();
 815         } finally {
 816             pushPopLock.unlock();
 817         }
 818     }
 819 
 820     /**
 821      * @return most recent event time on all threads.
 822      */
 823     long getMostRecentEventTimeEx() {
 824         pushPopLock.lock();
 825         try {
 826             return mostRecentEventTime;
 827         } finally {
 828             pushPopLock.unlock();
 829         }
 830     }
 831 
 832     /**
 833      * Returns the event currently being dispatched by the
 834      * {@code EventQueue} associated with the calling thread. This is
 835      * useful if a method needs access to the event, but was not designed to
 836      * receive a reference to it as an argument. Note that this method should
 837      * only be invoked from an application's event dispatching thread. If this
 838      * method is invoked from another thread, null will be returned.
 839      *
 840      * @return the event currently being dispatched, or null if this method is
 841      *         invoked on a thread other than an event dispatching thread
 842      * @since 1.4
 843      */
 844     public static AWTEvent getCurrentEvent() {
 845         return Toolkit.getEventQueue().getCurrentEventImpl();
 846     }
 847     private AWTEvent getCurrentEventImpl() {
 848         pushPopLock.lock();
 849         try {
 850                 return (Thread.currentThread() == dispatchThread)
 851                 ? currentEvent.get()
 852                 : null;
 853         } finally {
 854             pushPopLock.unlock();
 855         }
 856     }
 857 
 858     /**
 859      * Replaces the existing {@code EventQueue} with the specified one.
 860      * Any pending events are transferred to the new {@code EventQueue}
 861      * for processing by it.
 862      *
 863      * @param newEventQueue an {@code EventQueue}
 864      *          (or subclass thereof) instance to be use
 865      * @see      java.awt.EventQueue#pop
 866      * @throws NullPointerException if {@code newEventQueue} is {@code null}
 867      * @since           1.2
 868      */
 869     public void push(EventQueue newEventQueue) {
 870         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 871             getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
 872         }
 873 
 874         pushPopLock.lock();
 875         try {
 876             EventQueue topQueue = this;
 877             while (topQueue.nextQueue != null) {
 878                 topQueue = topQueue.nextQueue;
 879             }
 880             if (topQueue.fwDispatcher != null) {
 881                 throw new RuntimeException("push() to queue with fwDispatcher");
 882             }
 883             if ((topQueue.dispatchThread != null) &&
 884                 (topQueue.dispatchThread.getEventQueue() == this))
 885             {
 886                 newEventQueue.dispatchThread = topQueue.dispatchThread;


 904                 // pick up a new EventQueue. Post the waking event before
 905                 // topQueue.nextQueue is assigned, otherwise the event would
 906                 // go newEventQueue
 907                 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
 908             }
 909 
 910             newEventQueue.previousQueue = topQueue;
 911             topQueue.nextQueue = newEventQueue;
 912 
 913             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
 914                 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
 915             }
 916 
 917             pushPopCond.signalAll();
 918         } finally {
 919             pushPopLock.unlock();
 920         }
 921     }
 922 
 923     /**
 924      * Stops dispatching events using this {@code EventQueue}.
 925      * Any pending events are transferred to the previous
 926      * {@code EventQueue} for processing.
 927      * <p>
 928      * Warning: To avoid deadlock, do not declare this method
 929      * synchronized in a subclass.
 930      *
 931      * @exception EmptyStackException if no previous push was made
 932      *  on this {@code EventQueue}
 933      * @see      java.awt.EventQueue#push
 934      * @since           1.2
 935      */
 936     protected void pop() throws EmptyStackException {
 937         if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
 938             getEventLog().fine("EventQueue.pop(" + this + ")");
 939         }
 940 
 941         pushPopLock.lock();
 942         try {
 943             EventQueue topQueue = this;
 944             while (topQueue.nextQueue != null) {
 945                 topQueue = topQueue.nextQueue;
 946             }
 947             EventQueue prevQueue = topQueue.previousQueue;
 948             if (prevQueue == null) {
 949                 throw new EmptyStackException();
 950             }
 951 
 952             topQueue.previousQueue = null;


1105          */
1106         pushPopLock.lock();
1107         try {
1108             if (edt == dispatchThread) {
1109                 dispatchThread = null;
1110             }
1111             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1112             /*
1113              * Event was posted after EDT events pumping had stopped, so start
1114              * another EDT to handle this event
1115              */
1116             if (peekEvent() != null) {
1117                 initDispatchThread();
1118             }
1119         } finally {
1120             pushPopLock.unlock();
1121         }
1122     }
1123 
1124     /*
1125      * Gets the {@code EventDispatchThread} for this
1126      * {@code EventQueue}.
1127      * @return the event dispatch thread associated with this event queue
1128      *         or {@code null} if this event queue doesn't have a
1129      *         working thread associated with it
1130      * @see    java.awt.EventQueue#initDispatchThread
1131      * @see    java.awt.EventQueue#detachDispatchThread
1132      */
1133     final EventDispatchThread getDispatchThread() {
1134         pushPopLock.lock();
1135         try {
1136             return dispatchThread;
1137         } finally {
1138             pushPopLock.unlock();
1139         }
1140     }
1141 
1142     /*
1143      * Removes any pending events for the specified source object.
1144      * If removeAllEvents parameter is {@code true} then all
1145      * events for the specified source object are removed, if it
1146      * is {@code false} then {@code SequencedEvent}, {@code SentEvent},
1147      * {@code FocusEvent}, {@code WindowEvent}, {@code KeyEvent},
1148      * and {@code InputMethodEvent} are kept in the queue, but all other
1149      * events are removed.
1150      *
1151      * This method is normally called by the source's
1152      * {@code removeNotify} method.
1153      */
1154     final void removeSourceEvents(Object source, boolean removeAllEvents) {
1155         SunToolkit.flushPendingEvents(appContext);
1156         pushPopLock.lock();
1157         try {
1158             for (int i = 0; i < NUM_PRIORITIES; i++) {
1159                 EventQueueItem entry = queues[i].head;
1160                 EventQueueItem prev = null;
1161                 while (entry != null) {
1162                     if ((entry.event.getSource() == source)
1163                         && (removeAllEvents
1164                             || ! (entry.event instanceof SequencedEvent
1165                                   || entry.event instanceof SentEvent
1166                                   || entry.event instanceof FocusEvent
1167                                   || entry.event instanceof WindowEvent
1168                                   || entry.event instanceof KeyEvent
1169                                   || entry.event instanceof InputMethodEvent)))
1170                     {
1171                         if (entry.event instanceof SequencedEvent) {
1172                             ((SequencedEvent)entry.event).dispose();


1232                 if (e instanceof KeyEvent) {
1233                     mostRecentKeyEventTime = ie.getWhen();
1234                 }
1235             } else if (e instanceof InputMethodEvent) {
1236                 InputMethodEvent ime = (InputMethodEvent)e;
1237                 mostRecentEventTime2 = ime.getWhen();
1238             } else if (e instanceof ActionEvent) {
1239                 ActionEvent ae = (ActionEvent)e;
1240                 mostRecentEventTime2 = ae.getWhen();
1241             } else if (e instanceof InvocationEvent) {
1242                 InvocationEvent ie = (InvocationEvent)e;
1243                 mostRecentEventTime2 = ie.getWhen();
1244             }
1245             mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1246         } finally {
1247             pushPopLock.unlock();
1248         }
1249     }
1250 
1251     /**
1252      * Causes {@code runnable} to have its {@code run}
1253      * method called in the {@link #isDispatchThread dispatch thread} of
1254      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1255      * This will happen after all pending events are processed.
1256      *
1257      * @param runnable  the {@code Runnable} whose {@code run}
1258      *                  method should be executed
1259      *                  asynchronously in the
1260      *                  {@link #isDispatchThread event dispatch thread}
1261      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1262      * @see             #invokeAndWait
1263      * @see             Toolkit#getSystemEventQueue
1264      * @see             #isDispatchThread
1265      * @since           1.2
1266      */
1267     public static void invokeLater(Runnable runnable) {
1268         Toolkit.getEventQueue().postEvent(
1269             new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1270     }
1271 
1272     /**
1273      * Causes {@code runnable} to have its {@code run}
1274      * method called in the {@link #isDispatchThread dispatch thread} of
1275      * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1276      * This will happen after all pending events are processed.
1277      * The call blocks until this has happened.  This method
1278      * will throw an Error if called from the
1279      * {@link #isDispatchThread event dispatcher thread}.
1280      *
1281      * @param runnable  the {@code Runnable} whose {@code run}
1282      *                  method should be executed
1283      *                  synchronously in the
1284      *                  {@link #isDispatchThread event dispatch thread}
1285      *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
1286      * @exception       InterruptedException  if any thread has
1287      *                  interrupted this thread
1288      * @exception       InvocationTargetException  if an throwable is thrown
1289      *                  when running {@code runnable}
1290      * @see             #invokeLater
1291      * @see             Toolkit#getSystemEventQueue
1292      * @see             #isDispatchThread
1293      * @since           1.2
1294      */
1295     public static void invokeAndWait(Runnable runnable)
1296         throws InterruptedException, InvocationTargetException
1297     {
1298         invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1299     }
1300 
1301     static void invokeAndWait(Object source, Runnable runnable)
1302         throws InterruptedException, InvocationTargetException
1303     {
1304         if (EventQueue.isDispatchThread()) {
1305             throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1306         }
1307 
1308         class AWTInvocationLock {}
1309         Object lock = new AWTInvocationLock();


< prev index next >