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