2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
28 import java.awt.event.*;
30 import java.awt.peer.ComponentPeer;
32 import java.lang.ref.WeakReference;
33 import java.lang.reflect.InvocationTargetException;
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
38 import java.util.EmptyStackException;
39 import sun.util.logging.PlatformLogger;
41 import sun.awt.AppContext;
42 import sun.awt.AWTAutoShutdown;
43 import sun.awt.PeerEvent;
44 import sun.awt.SunToolkit;
45 import sun.awt.EventQueueItem;
46 import sun.awt.AWTAccessor;
48 import java.util.concurrent.locks.Condition;
49 import java.util.concurrent.locks.Lock;
50 import java.util.concurrent.atomic.AtomicInteger;
52 import java.security.AccessControlContext;
53 import java.security.ProtectionDomain;
55 import sun.misc.SharedSecrets;
56 import sun.misc.JavaSecurityAccess;
59 * <code>EventQueue</code> is a platform-independent class
60 * that queues events, both from the underlying peer classes
61 * and from trusted application classes.
63 * It encapsulates asynchronous event dispatch machinery which
64 * extracts events from the queue and dispatches them by calling
65 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
66 * on this <code>EventQueue</code> with the event to be dispatched
67 * as an argument. The particular behavior of this machinery is
68 * implementation-dependent. The only requirements are that events
69 * which were actually enqueued to this queue (note that events
70 * being posted to the <code>EventQueue</code> can be coalesced)
74 * <dd> That is, it is not permitted that several events from
75 * this queue are dispatched simultaneously.
76 * <dt> In the same order as they are enqueued.
77 * <dd> That is, if <code>AWTEvent</code> A is enqueued
78 * to the <code>EventQueue</code> before
79 * <code>AWTEvent</code> B then event B will not be
80 * dispatched before event A.
83 * Some browsers partition applets in different code bases into
84 * separate contexts, and establish walls between these contexts.
85 * In such a scenario, there will be one <code>EventQueue</code>
86 * per context. Other browsers place all applets into the same
87 * context, implying that there will be only a single, global
88 * <code>EventQueue</code> for all applets. This behavior is
89 * implementation-dependent. Consult your browser's documentation
90 * for more information.
92 * For information on the threading issues of the event dispatch
93 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
94 * >AWT Threading Issues</a>.
98 * @author David Mendenhall
102 public class EventQueue {
103 private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
105 private static final int LOW_PRIORITY = 0;
106 private static final int NORM_PRIORITY = 1;
107 private static final int HIGH_PRIORITY = 2;
108 private static final int ULTIMATE_PRIORITY = 3;
110 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
113 * We maintain one Queue for each priority that the EventQueue supports.
114 * That is, the EventQueue object is actually implemented as
115 * NUM_PRIORITIES queues and all Events on a particular internal Queue
116 * have identical priority. Events are pulled off the EventQueue starting
117 * with the Queue of highest priority. We progress in decreasing order
120 private Queue[] queues = new Queue[NUM_PRIORITIES];
123 * The next EventQueue on the stack, or null if this EventQueue is
124 * on the top of the stack. If nextQueue is non-null, requests to post
125 * an event are forwarded to nextQueue.
127 private EventQueue nextQueue;
130 * The previous EventQueue on the stack, or null if this is the
133 private EventQueue previousQueue;
136 * A single lock to synchronize the push()/pop() and related operations with
137 * all the EventQueues from the AppContext. Synchronization on any particular
138 * event queue(s) is not enough: we should lock the whole stack.
140 private final Lock pushPopLock;
141 private final Condition pushPopCond;
144 * Dummy runnable to wake up EDT from getNextEvent() after
145 push/pop is performed
147 private final static Runnable dummyRunnable = new Runnable() {
152 private EventDispatchThread dispatchThread;
154 private final ThreadGroup threadGroup =
155 Thread.currentThread().getThreadGroup();
156 private final ClassLoader classLoader =
157 Thread.currentThread().getContextClassLoader();
160 * The time stamp of the last dispatched InputEvent or ActionEvent.
162 private long mostRecentEventTime = System.currentTimeMillis();
165 * The modifiers field of the current event, if the current event is an
166 * InputEvent or ActionEvent.
168 private WeakReference currentEvent;
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.
174 private volatile int waitForID;
176 private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();
178 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");
181 AWTAccessor.setEventQueueAccessor(
182 new AWTAccessor.EventQueueAccessor() {
183 public Thread getDispatchThread(EventQueue eventQueue) {
184 return eventQueue.getDispatchThread();
186 public boolean isDispatchThreadImpl(EventQueue eventQueue) {
187 return eventQueue.isDispatchThreadImpl();
192 public EventQueue() {
193 for (int i = 0; i < NUM_PRIORITIES; i++) {
194 queues[i] = new Queue();
197 * NOTE: if you ever have to start the associated event dispatch
198 * thread at this point, be aware of the following problem:
199 * If this EventQueue instance is created in
200 * SunToolkit.createNewAppContext() the started dispatch thread
201 * may call AppContext.getAppContext() before createNewAppContext()
202 * completes thus causing mess in thread group to appcontext mapping.
205 pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY);
206 pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY);
210 * Posts a 1.1-style event to the <code>EventQueue</code>.
211 * If there is an existing event on the queue with the same ID
212 * and event source, the source <code>Component</code>'s
213 * <code>coalesceEvents</code> method will be called.
215 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
216 * or a subclass of it
217 * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
219 public void postEvent(AWTEvent theEvent) {
220 SunToolkit.flushPendingEvents();
221 postEventPrivate(theEvent);
225 * Posts a 1.1-style event to the <code>EventQueue</code>.
226 * If there is an existing event on the queue with the same ID
227 * and event source, the source <code>Component</code>'s
228 * <code>coalesceEvents</code> method will be called.
230 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
231 * or a subclass of it
233 private final void postEventPrivate(AWTEvent theEvent) {
234 theEvent.isPosted = true;
237 if (nextQueue != null) {
238 // Forward the event to the top of EventQueue stack
239 nextQueue.postEventPrivate(theEvent);
242 if (dispatchThread == null) {
243 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
246 initDispatchThread();
249 postEvent(theEvent, getPriority(theEvent));
251 pushPopLock.unlock();
255 private static int getPriority(AWTEvent theEvent) {
256 if (theEvent instanceof PeerEvent) {
257 PeerEvent peerEvent = (PeerEvent)theEvent;
258 if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
259 return ULTIMATE_PRIORITY;
261 if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
262 return HIGH_PRIORITY;
264 if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
268 int id = theEvent.getID();
269 if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
272 return NORM_PRIORITY;
276 * Posts the event to the internal Queue of specified priority,
277 * coalescing as appropriate.
279 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
280 * or a subclass of it
281 * @param priority the desired priority of the event
283 private void postEvent(AWTEvent theEvent, int priority) {
284 if (coalesceEvent(theEvent, priority)) {
288 EventQueueItem newItem = new EventQueueItem(theEvent);
290 cacheEQItem(newItem);
292 boolean notifyID = (theEvent.getID() == this.waitForID);
294 if (queues[priority].head == null) {
295 boolean shouldNotify = noEvents();
296 queues[priority].head = queues[priority].tail = newItem;
299 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
300 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
303 } else if (notifyID) {
307 // The event was not coalesced or has non-Component source.
308 // Insert it at the end of the appropriate Queue.
309 queues[priority].tail.next = newItem;
310 queues[priority].tail = newItem;
317 private boolean coalescePaintEvent(PaintEvent e) {
318 ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
319 if (sourcePeer != null) {
320 sourcePeer.coalescePaintEvent(e);
322 EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
326 int index = eventToCacheIndex(e);
328 if (index != -1 && cache[index] != null) {
329 PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
330 if (merged != null) {
331 cache[index].event = merged;
338 private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
339 Rectangle aRect = a.getUpdateRect();
340 Rectangle bRect = b.getUpdateRect();
341 if (bRect.contains(aRect)) {
344 if (aRect.contains(bRect)) {
350 private boolean coalesceMouseEvent(MouseEvent e) {
351 EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
355 int index = eventToCacheIndex(e);
356 if (index != -1 && cache[index] != null) {
357 cache[index].event = e;
363 private boolean coalescePeerEvent(PeerEvent e) {
364 EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
368 int index = eventToCacheIndex(e);
369 if (index != -1 && cache[index] != null) {
370 e = e.coalesceEvents((PeerEvent)cache[index].event);
372 cache[index].event = e;
382 * Should avoid of calling this method by any means
383 * as it's working time is dependant on EQ length.
384 * In the wors case this method alone can slow down the entire application
385 * 10 times by stalling the Event processing.
386 * Only here by backward compatibility reasons.
388 private boolean coalesceOtherEvent(AWTEvent e, int priority) {
390 Component source = (Component)e.getSource();
391 for (EventQueueItem entry = queues[priority].head;
392 entry != null; entry = entry.next)
394 // Give Component.coalesceEvents a chance
395 if (entry.event.getSource() == source && entry.event.getID() == id) {
396 AWTEvent coalescedEvent = source.coalesceEvents(
398 if (coalescedEvent != null) {
399 entry.event = coalescedEvent;
407 private boolean coalesceEvent(AWTEvent e, int priority) {
408 if (!(e.getSource() instanceof Component)) {
411 if (e instanceof PeerEvent) {
412 return coalescePeerEvent((PeerEvent)e);
415 if (((Component)e.getSource()).isCoalescingEnabled()
416 && coalesceOtherEvent(e, priority))
420 if (e instanceof PaintEvent) {
421 return coalescePaintEvent((PaintEvent)e);
423 if (e instanceof MouseEvent) {
424 return coalesceMouseEvent((MouseEvent)e);
429 private void cacheEQItem(EventQueueItem entry) {
430 int index = eventToCacheIndex(entry.event);
431 if (index != -1 && entry.event.getSource() instanceof Component) {
432 Component source = (Component)entry.event.getSource();
433 if (source.eventCache == null) {
434 source.eventCache = new EventQueueItem[CACHE_LENGTH];
436 source.eventCache[index] = entry;
440 private void uncacheEQItem(EventQueueItem entry) {
441 int index = eventToCacheIndex(entry.event);
442 if (index != -1 && entry.event.getSource() instanceof Component) {
443 Component source = (Component)entry.event.getSource();
444 if (source.eventCache == null) {
447 source.eventCache[index] = null;
451 private static final int PAINT = 0;
452 private static final int UPDATE = 1;
453 private static final int MOVE = 2;
454 private static final int DRAG = 3;
455 private static final int PEER = 4;
456 private static final int CACHE_LENGTH = 5;
458 private static int eventToCacheIndex(AWTEvent e) {
460 case PaintEvent.PAINT:
462 case PaintEvent.UPDATE:
464 case MouseEvent.MOUSE_MOVED:
466 case MouseEvent.MOUSE_DRAGGED:
469 return e instanceof PeerEvent ? PEER : -1;
474 * Returns whether an event is pending on any of the separate
476 * @return whether an event is pending on any of the separate Queues
478 private boolean noEvents() {
479 for (int i = 0; i < NUM_PRIORITIES; i++) {
480 if (queues[i].head != null) {
488 final AWTEvent getNextEvent(int id, boolean block) throws InterruptedException {
490 return (id == EventDispatchThread.ANY_EVENT) ? getNextEvent() : getNextEvent(id);
494 if (id == EventDispatchThread.ANY_EVENT) {
498 // XXX: calls SunToolkit.flushPendingEvents under lock now
499 return getNextEvent();
501 AWTEvent peek = peekEvent(id);
505 // XXX: calls SunToolkit.flushPendingEvents under lock now
506 return getNextEvent(id);
509 pushPopLock.unlock();
514 * Removes an event from the <code>EventQueue</code> and
515 * returns it. This method will block until an event has
516 * been posted by another thread.
517 * @return the next <code>AWTEvent</code>
518 * @exception InterruptedException
519 * if any thread has interrupted this thread
521 public AWTEvent getNextEvent() throws InterruptedException {
524 * SunToolkit.flushPendingEvents must be called outside
525 * of the synchronized block to avoid deadlock when
526 * event queues are nested with push()/pop().
528 SunToolkit.flushPendingEvents();
531 AWTEvent event = getNextEventPrivate();
535 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
538 pushPopLock.unlock();
544 * Must be called under the lock. Doesn't call flushPendingEvents()
546 AWTEvent getNextEventPrivate() throws InterruptedException {
547 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
548 if (queues[i].head != null) {
549 EventQueueItem entry = queues[i].head;
550 queues[i].head = entry.next;
551 if (entry.next == null) {
552 queues[i].tail = null;
554 uncacheEQItem(entry);
561 AWTEvent getNextEvent(int id) throws InterruptedException {
564 * SunToolkit.flushPendingEvents must be called outside
565 * of the synchronized block to avoid deadlock when
566 * event queues are nested with push()/pop().
568 SunToolkit.flushPendingEvents();
571 for (int i = 0; i < NUM_PRIORITIES; i++) {
572 for (EventQueueItem entry = queues[i].head, prev = null;
573 entry != null; prev = entry, entry = entry.next)
575 if (entry.event.getID() == id) {
577 queues[i].head = entry.next;
579 prev.next = entry.next;
581 if (queues[i].tail == entry) {
582 queues[i].tail = prev;
584 uncacheEQItem(entry);
593 pushPopLock.unlock();
599 * Returns the first event on the <code>EventQueue</code>
600 * without removing it.
601 * @return the first event
603 public AWTEvent peekEvent() {
606 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
607 if (queues[i].head != null) {
608 return queues[i].head.event;
612 pushPopLock.unlock();
619 * Returns the first event with the specified id, if any.
620 * @param id the id of the type of event desired
621 * @return the first event of the specified id or <code>null</code>
622 * if there is no such event
624 public AWTEvent peekEvent(int id) {
627 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
628 EventQueueItem q = queues[i].head;
629 for (; q != null; q = q.next) {
630 if (q.event.getID() == id) {
636 pushPopLock.unlock();
642 private static final JavaSecurityAccess javaSecurityAccess =
643 SharedSecrets.getJavaSecurityAccess();
646 * Dispatches an event. The manner in which the event is
647 * dispatched depends upon the type of the event and the
648 * type of the event's source object:
650 * <table border=1 summary="Event types, source types, and dispatch methods">
652 * <th>Event Type</th>
653 * <th>Source Type</th>
654 * <th>Dispatched To</th>
657 * <td>ActiveEvent</td>
659 * <td>event.dispatch()</td>
664 * <td>source.dispatchEvent(AWTEvent)</td>
668 * <td>MenuComponent</td>
669 * <td>source.dispatchEvent(AWTEvent)</td>
674 * <td>No action (ignored)</td>
678 * @param event an instance of <code>java.awt.AWTEvent</code>,
679 * or a subclass of it
680 * @throws NullPointerException if <code>event</code> is <code>null</code>
683 protected void dispatchEvent(final AWTEvent event) {
684 final Object src = event.getSource();
685 final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
687 dispatchEventImpl(event, src);
692 final AccessControlContext stack = AccessController.getContext();
693 final AccessControlContext srcAcc = getAccessControlContextFrom(src);
694 final AccessControlContext eventAcc = event.getAccessControlContext();
695 if (srcAcc == null) {
696 javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
698 javaSecurityAccess.doIntersectionPrivilege(
699 new PrivilegedAction<Void>() {
701 javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
708 private static AccessControlContext getAccessControlContextFrom(Object src) {
709 return src instanceof Component ?
710 ((Component)src).getAccessControlContext() :
711 src instanceof MenuComponent ?
712 ((MenuComponent)src).getAccessControlContext() :
713 src instanceof TrayIcon ?
714 ((TrayIcon)src).getAccessControlContext() :
719 * Called from dispatchEvent() under a correct AccessControlContext
721 private void dispatchEventImpl(final AWTEvent event, final Object src) {
722 event.isPosted = true;
723 if (event instanceof ActiveEvent) {
724 // This could become the sole method of dispatching in time.
725 setCurrentEventAndMostRecentTimeImpl(event);
726 ((ActiveEvent)event).dispatch();
727 } else if (src instanceof Component) {
728 ((Component)src).dispatchEvent(event);
730 } else if (src instanceof MenuComponent) {
731 ((MenuComponent)src).dispatchEvent(event);
732 } else if (src instanceof TrayIcon) {
733 ((TrayIcon)src).dispatchEvent(event);
734 } else if (src instanceof AWTAutoShutdown) {
736 dispatchThread.stopDispatching();
739 if (eventLog.isLoggable(PlatformLogger.FINE)) {
740 eventLog.fine("Unable to dispatch event: " + event);
746 * Returns the timestamp of the most recent event that had a timestamp, and
747 * that was dispatched from the <code>EventQueue</code> associated with the
748 * calling thread. If an event with a timestamp is currently being
749 * dispatched, its timestamp will be returned. If no events have yet
750 * been dispatched, the EventQueue's initialization time will be
751 * returned instead.In the current version of
752 * the JDK, only <code>InputEvent</code>s,
753 * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
754 * timestamps; however, future versions of the JDK may add timestamps to
755 * additional event types. Note that this method should only be invoked
756 * from an application's {@link #isDispatchThread event dispatching thread}.
758 * invoked from another thread, the current system time (as reported by
759 * <code>System.currentTimeMillis()</code>) will be returned instead.
761 * @return the timestamp of the last <code>InputEvent</code>,
762 * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
763 * dispatched, or <code>System.currentTimeMillis()</code> if this
764 * method is invoked on a thread other than an event dispatching
766 * @see java.awt.event.InputEvent#getWhen
767 * @see java.awt.event.ActionEvent#getWhen
768 * @see java.awt.event.InvocationEvent#getWhen
769 * @see #isDispatchThread
773 public static long getMostRecentEventTime() {
774 return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
776 private long getMostRecentEventTimeImpl() {
779 return (Thread.currentThread() == dispatchThread)
780 ? mostRecentEventTime
781 : System.currentTimeMillis();
783 pushPopLock.unlock();
788 * @return most recent event time on all threads.
790 long getMostRecentEventTimeEx() {
793 return mostRecentEventTime;
795 pushPopLock.unlock();
800 * Returns the the event currently being dispatched by the
801 * <code>EventQueue</code> associated with the calling thread. This is
802 * useful if a method needs access to the event, but was not designed to
803 * receive a reference to it as an argument. Note that this method should
804 * only be invoked from an application's event dispatching thread. If this
805 * method is invoked from another thread, null will be returned.
807 * @return the event currently being dispatched, or null if this method is
808 * invoked on a thread other than an event dispatching thread
811 public static AWTEvent getCurrentEvent() {
812 return Toolkit.getEventQueue().getCurrentEventImpl();
814 private AWTEvent getCurrentEventImpl() {
817 return (Thread.currentThread() == dispatchThread)
818 ? ((AWTEvent)currentEvent.get())
821 pushPopLock.unlock();
826 * Replaces the existing <code>EventQueue</code> with the specified one.
827 * Any pending events are transferred to the new <code>EventQueue</code>
828 * for processing by it.
830 * @param newEventQueue an <code>EventQueue</code>
831 * (or subclass thereof) instance to be use
832 * @see java.awt.EventQueue#pop
833 * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
836 public void push(EventQueue newEventQueue) {
837 if (eventLog.isLoggable(PlatformLogger.FINE)) {
838 eventLog.fine("EventQueue.push(" + newEventQueue + ")");
843 EventQueue topQueue = this;
844 while (topQueue.nextQueue != null) {
845 topQueue = topQueue.nextQueue;
848 if ((topQueue.dispatchThread != null) &&
849 (topQueue.dispatchThread.getEventQueue() == this))
851 newEventQueue.dispatchThread = topQueue.dispatchThread;
852 topQueue.dispatchThread.setEventQueue(newEventQueue);
855 // Transfer all events forward to new EventQueue.
856 while (topQueue.peekEvent() != null) {
858 // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
859 newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
860 } catch (InterruptedException ie) {
861 if (eventLog.isLoggable(PlatformLogger.FINE)) {
862 eventLog.fine("Interrupted push", ie);
867 // Wake up EDT waiting in getNextEvent(), so it can
868 // pick up a new EventQueue. Post the waking event before
869 // topQueue.nextQueue is assigned, otherwise the event would
871 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
873 newEventQueue.previousQueue = topQueue;
874 topQueue.nextQueue = newEventQueue;
876 AppContext appContext = AppContext.getAppContext();
877 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
878 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
883 pushPopLock.unlock();
888 * Stops dispatching events using this <code>EventQueue</code>.
889 * Any pending events are transferred to the previous
890 * <code>EventQueue</code> for processing.
892 * Warning: To avoid deadlock, do not declare this method
893 * synchronized in a subclass.
895 * @exception EmptyStackException if no previous push was made
896 * on this <code>EventQueue</code>
897 * @see java.awt.EventQueue#push
900 protected void pop() throws EmptyStackException {
901 if (eventLog.isLoggable(PlatformLogger.FINE)) {
902 eventLog.fine("EventQueue.pop(" + this + ")");
907 EventQueue topQueue = this;
908 while (topQueue.nextQueue != null) {
909 topQueue = topQueue.nextQueue;
911 EventQueue prevQueue = topQueue.previousQueue;
912 if (prevQueue == null) {
913 throw new EmptyStackException();
916 topQueue.previousQueue = null;
917 prevQueue.nextQueue = null;
919 // Transfer all events back to previous EventQueue.
920 while (topQueue.peekEvent() != null) {
922 prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
923 } catch (InterruptedException ie) {
924 if (eventLog.isLoggable(PlatformLogger.FINE)) {
925 eventLog.fine("Interrupted pop", ie);
930 if ((topQueue.dispatchThread != null) &&
931 (topQueue.dispatchThread.getEventQueue() == this))
933 prevQueue.dispatchThread = topQueue.dispatchThread;
934 topQueue.dispatchThread.setEventQueue(prevQueue);
937 AppContext appContext = AppContext.getAppContext();
938 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
939 appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
942 // Wake up EDT waiting in getNextEvent(), so it can
943 // pick up a new EventQueue
944 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
948 pushPopLock.unlock();
953 * Creates a new {@code secondary loop} associated with this
954 * event queue. Use the {@link SecondaryLoop#enter} and
955 * {@link SecondaryLoop#exit} methods to start and stop the
956 * event loop and dispatch the events from this queue.
958 * @return secondaryLoop A new secondary loop object, which can
959 * be used to launch a new nested event
960 * loop and dispatch events from this queue
962 * @see SecondaryLoop#enter
963 * @see SecondaryLoop#exit
967 public SecondaryLoop createSecondaryLoop() {
968 return createSecondaryLoop(null, null, 0);
971 SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {
974 if (nextQueue != null) {
975 // Forward the request to the top of EventQueue stack
976 return nextQueue.createSecondaryLoop(cond, filter, interval);
978 if (dispatchThread == null) {
979 initDispatchThread();
981 return new WaitDispatchSupport(dispatchThread, cond, filter, interval);
983 pushPopLock.unlock();
988 * Returns true if the calling thread is
989 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
990 * dispatch thread. Use this method to ensure that a particular
991 * task is being executed (or not being) there.
993 * Note: use the {@link #invokeLater} or {@link #invokeAndWait}
994 * methods to execute a task in
995 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
999 * @return true if running in
1000 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
1003 * @see #invokeAndWait
1004 * @see Toolkit#getSystemEventQueue
1007 public static boolean isDispatchThread() {
1008 EventQueue eq = Toolkit.getEventQueue();
1009 return eq.isDispatchThreadImpl();
1012 final boolean isDispatchThreadImpl() {
1013 EventQueue eq = this;
1016 EventQueue next = eq.nextQueue;
1017 while (next != null) {
1019 next = eq.nextQueue;
1021 return (Thread.currentThread() == eq.dispatchThread);
1023 pushPopLock.unlock();
1027 final void initDispatchThread() {
1030 AppContext appContext = AppContext.getAppContext();
1031 if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
1032 dispatchThread = AccessController.doPrivileged(
1033 new PrivilegedAction<EventDispatchThread>() {
1034 public EventDispatchThread run() {
1035 EventDispatchThread t =
1036 new EventDispatchThread(threadGroup,
1045 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
1048 pushPopLock.unlock();
1052 final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) {
1054 * This synchronized block is to secure that the event dispatch
1055 * thread won't die in the middle of posting a new event to the
1056 * associated event queue. It is important because we notify
1057 * that the event dispatch thread is busy after posting a new event
1058 * to its queue, so the EventQueue.dispatchThread reference must
1059 * be valid at that point.
1063 if (edt == dispatchThread) {
1065 * Don't detach the thread if any events are pending. Not
1066 * sure if it's a possible scenario, though.
1068 * Fix for 4648733. Check both the associated java event
1069 * queue and the PostEventQueue.
1071 if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
1074 dispatchThread = null;
1076 AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1079 pushPopLock.unlock();
1084 * Gets the <code>EventDispatchThread</code> for this
1085 * <code>EventQueue</code>.
1086 * @return the event dispatch thread associated with this event queue
1087 * or <code>null</code> if this event queue doesn't have a
1088 * working thread associated with it
1089 * @see java.awt.EventQueue#initDispatchThread
1090 * @see java.awt.EventQueue#detachDispatchThread
1092 final EventDispatchThread getDispatchThread() {
1095 return dispatchThread;
1097 pushPopLock.unlock();
1102 * Removes any pending events for the specified source object.
1103 * If removeAllEvents parameter is <code>true</code> then all
1104 * events for the specified source object are removed, if it
1105 * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
1106 * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
1107 * and <code>InputMethodEvent</code> are kept in the queue, but all other
1108 * events are removed.
1110 * This method is normally called by the source's
1111 * <code>removeNotify</code> method.
1113 final void removeSourceEvents(Object source, boolean removeAllEvents) {
1114 SunToolkit.flushPendingEvents();
1117 for (int i = 0; i < NUM_PRIORITIES; i++) {
1118 EventQueueItem entry = queues[i].head;
1119 EventQueueItem prev = null;
1120 while (entry != null) {
1121 if ((entry.event.getSource() == source)
1123 || ! (entry.event instanceof SequencedEvent
1124 || entry.event instanceof SentEvent
1125 || entry.event instanceof FocusEvent
1126 || entry.event instanceof WindowEvent
1127 || entry.event instanceof KeyEvent
1128 || entry.event instanceof InputMethodEvent)))
1130 if (entry.event instanceof SequencedEvent) {
1131 ((SequencedEvent)entry.event).dispose();
1133 if (entry.event instanceof SentEvent) {
1134 ((SentEvent)entry.event).dispose();
1137 queues[i].head = entry.next;
1139 prev.next = entry.next;
1141 uncacheEQItem(entry);
1147 queues[i].tail = prev;
1150 pushPopLock.unlock();
1154 static void setCurrentEventAndMostRecentTime(AWTEvent e) {
1155 Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
1157 private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {
1160 if (Thread.currentThread() != dispatchThread) {
1164 currentEvent = new WeakReference(e);
1166 // This series of 'instanceof' checks should be replaced with a
1167 // polymorphic type (for example, an interface which declares a
1168 // getWhen() method). However, this would require us to make such
1169 // a type public, or to place it in sun.awt. Both of these approaches
1170 // have been frowned upon. So for now, we hack.
1172 // In tiger, we will probably give timestamps to all events, so this
1173 // will no longer be an issue.
1174 long mostRecentEventTime2 = Long.MIN_VALUE;
1175 if (e instanceof InputEvent) {
1176 InputEvent ie = (InputEvent)e;
1177 mostRecentEventTime2 = ie.getWhen();
1178 } else if (e instanceof InputMethodEvent) {
1179 InputMethodEvent ime = (InputMethodEvent)e;
1180 mostRecentEventTime2 = ime.getWhen();
1181 } else if (e instanceof ActionEvent) {
1182 ActionEvent ae = (ActionEvent)e;
1183 mostRecentEventTime2 = ae.getWhen();
1184 } else if (e instanceof InvocationEvent) {
1185 InvocationEvent ie = (InvocationEvent)e;
1186 mostRecentEventTime2 = ie.getWhen();
1188 mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1190 pushPopLock.unlock();
1195 * Causes <code>runnable</code> to have its <code>run</code>
1196 * method called in the {@link #isDispatchThread dispatch thread} of
1197 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1198 * This will happen after all pending events are processed.
1200 * @param runnable the <code>Runnable</code> whose <code>run</code>
1201 * method should be executed
1202 * asynchronously in the
1203 * {@link #isDispatchThread event dispatch thread}
1204 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1205 * @see #invokeAndWait
1206 * @see Toolkit#getSystemEventQueue
1207 * @see #isDispatchThread
1210 public static void invokeLater(Runnable runnable) {
1211 Toolkit.getEventQueue().postEvent(
1212 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1216 * Causes <code>runnable</code> to have its <code>run</code>
1217 * method called in the {@link #isDispatchThread dispatch thread} of
1218 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1219 * This will happen after all pending events are processed.
1220 * The call blocks until this has happened. This method
1221 * will throw an Error if called from the
1222 * {@link #isDispatchThread event dispatcher thread}.
1224 * @param runnable the <code>Runnable</code> whose <code>run</code>
1225 * method should be executed
1226 * synchronously in the
1227 * {@link #isDispatchThread event dispatch thread}
1228 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1229 * @exception InterruptedException if any thread has
1230 * interrupted this thread
1231 * @exception InvocationTargetException if an throwable is thrown
1232 * when running <code>runnable</code>
1234 * @see Toolkit#getSystemEventQueue
1235 * @see #isDispatchThread
1238 public static void invokeAndWait(Runnable runnable)
1239 throws InterruptedException, InvocationTargetException {
1241 if (EventQueue.isDispatchThread()) {
1242 throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1245 class AWTInvocationLock {}
1246 Object lock = new AWTInvocationLock();
1248 InvocationEvent event =
1249 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
1252 synchronized (lock) {
1253 Toolkit.getEventQueue().postEvent(event);
1254 while (!event.isDispatched()) {
1259 Throwable eventThrowable = event.getThrowable();
1260 if (eventThrowable != null) {
1261 throw new InvocationTargetException(eventThrowable);
1266 * Called from PostEventQueue.postEvent to notify that a new event
1267 * appeared. First it proceeds to the EventQueue on the top of the
1268 * stack, then notifies the associated dispatch thread if it exists
1269 * or starts a new one otherwise.
1271 private void wakeup(boolean isShutdown) {
1274 if (nextQueue != null) {
1275 // Forward call to the top of EventQueue stack.
1276 nextQueue.wakeup(isShutdown);
1277 } else if (dispatchThread != null) {
1279 } else if (!isShutdown) {
1280 initDispatchThread();
1283 pushPopLock.unlock();
1287 private void signalAll() {
1288 pushPopCond.signalAll();
1290 // new event delivered - requesting new processing
1291 // of pending events
1292 dispatchThread.processEvents();
1296 * The Queue object holds pointers to the beginning and end of one internal
1297 * queue. An EventQueue object is composed of multiple internal Queues, one
1298 * for each priority supported by the EventQueue. All Events on a particular
1299 * internal Queue have identical priority.
1302 EventQueueItem head;
1303 EventQueueItem tail;