Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/awt/EventQueue.java
38829 views
/*1* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.awt;2627import java.awt.event.*;2829import java.awt.peer.ComponentPeer;3031import java.lang.ref.WeakReference;32import java.lang.reflect.InvocationTargetException;3334import java.security.AccessController;35import java.security.PrivilegedAction;3637import java.util.EmptyStackException;3839import sun.awt.*;40import sun.awt.dnd.SunDropTargetEvent;41import sun.util.logging.PlatformLogger;4243import java.util.concurrent.locks.Condition;44import java.util.concurrent.locks.Lock;45import java.util.concurrent.atomic.AtomicInteger;4647import java.security.AccessControlContext;4849import sun.misc.SharedSecrets;50import sun.misc.JavaSecurityAccess;5152/**53* <code>EventQueue</code> is a platform-independent class54* that queues events, both from the underlying peer classes55* and from trusted application classes.56* <p>57* It encapsulates asynchronous event dispatch machinery which58* extracts events from the queue and dispatches them by calling59* {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method60* on this <code>EventQueue</code> with the event to be dispatched61* as an argument. The particular behavior of this machinery is62* implementation-dependent. The only requirements are that events63* which were actually enqueued to this queue (note that events64* being posted to the <code>EventQueue</code> can be coalesced)65* are dispatched:66* <dl>67* <dt> Sequentially.68* <dd> That is, it is not permitted that several events from69* this queue are dispatched simultaneously.70* <dt> In the same order as they are enqueued.71* <dd> That is, if <code>AWTEvent</code> A is enqueued72* to the <code>EventQueue</code> before73* <code>AWTEvent</code> B then event B will not be74* dispatched before event A.75* </dl>76* <p>77* Some browsers partition applets in different code bases into78* separate contexts, and establish walls between these contexts.79* In such a scenario, there will be one <code>EventQueue</code>80* per context. Other browsers place all applets into the same81* context, implying that there will be only a single, global82* <code>EventQueue</code> for all applets. This behavior is83* implementation-dependent. Consult your browser's documentation84* for more information.85* <p>86* For information on the threading issues of the event dispatch87* machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"88* >AWT Threading Issues</a>.89*90* @author Thomas Ball91* @author Fred Ecks92* @author David Mendenhall93*94* @since 1.195*/96public class EventQueue {97private static final AtomicInteger threadInitNumber = new AtomicInteger(0);9899private static final int LOW_PRIORITY = 0;100private static final int NORM_PRIORITY = 1;101private static final int HIGH_PRIORITY = 2;102private static final int ULTIMATE_PRIORITY = 3;103104private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;105106/*107* We maintain one Queue for each priority that the EventQueue supports.108* That is, the EventQueue object is actually implemented as109* NUM_PRIORITIES queues and all Events on a particular internal Queue110* have identical priority. Events are pulled off the EventQueue starting111* with the Queue of highest priority. We progress in decreasing order112* across all Queues.113*/114private Queue[] queues = new Queue[NUM_PRIORITIES];115116/*117* The next EventQueue on the stack, or null if this EventQueue is118* on the top of the stack. If nextQueue is non-null, requests to post119* an event are forwarded to nextQueue.120*/121private EventQueue nextQueue;122123/*124* The previous EventQueue on the stack, or null if this is the125* "base" EventQueue.126*/127private EventQueue previousQueue;128129/*130* A single lock to synchronize the push()/pop() and related operations with131* all the EventQueues from the AppContext. Synchronization on any particular132* event queue(s) is not enough: we should lock the whole stack.133*/134private final Lock pushPopLock;135private final Condition pushPopCond;136137/*138* Dummy runnable to wake up EDT from getNextEvent() after139push/pop is performed140*/141private final static Runnable dummyRunnable = new Runnable() {142public void run() {143}144};145146private EventDispatchThread dispatchThread;147148private final ThreadGroup threadGroup =149Thread.currentThread().getThreadGroup();150private final ClassLoader classLoader =151Thread.currentThread().getContextClassLoader();152153/*154* The time stamp of the last dispatched InputEvent or ActionEvent.155*/156private long mostRecentEventTime = System.currentTimeMillis();157158/*159* The time stamp of the last KeyEvent .160*/161private long mostRecentKeyEventTime = System.currentTimeMillis();162163/**164* The modifiers field of the current event, if the current event is an165* InputEvent or ActionEvent.166*/167private WeakReference<AWTEvent> currentEvent;168169/*170* Non-zero if a thread is waiting in getNextEvent(int) for an event of171* a particular ID to be posted to the queue.172*/173private volatile int waitForID;174175/*176* AppContext corresponding to the queue.177*/178private final AppContext appContext;179180private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();181182private FwDispatcher fwDispatcher;183184private static volatile PlatformLogger eventLog;185186private static final PlatformLogger getEventLog() {187if(eventLog == null) {188eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");189}190return eventLog;191}192193static {194AWTAccessor.setEventQueueAccessor(195new AWTAccessor.EventQueueAccessor() {196public Thread getDispatchThread(EventQueue eventQueue) {197return eventQueue.getDispatchThread();198}199public boolean isDispatchThreadImpl(EventQueue eventQueue) {200return eventQueue.isDispatchThreadImpl();201}202public void removeSourceEvents(EventQueue eventQueue,203Object source,204boolean removeAllEvents)205{206eventQueue.removeSourceEvents(source, removeAllEvents);207}208public boolean noEvents(EventQueue eventQueue) {209return eventQueue.noEvents();210}211public void wakeup(EventQueue eventQueue, boolean isShutdown) {212eventQueue.wakeup(isShutdown);213}214public void invokeAndWait(Object source, Runnable r)215throws InterruptedException, InvocationTargetException216{217EventQueue.invokeAndWait(source, r);218}219public void setFwDispatcher(EventQueue eventQueue,220FwDispatcher dispatcher) {221eventQueue.setFwDispatcher(dispatcher);222}223224@Override225public long getMostRecentEventTime(EventQueue eventQueue) {226return eventQueue.getMostRecentEventTimeImpl();227}228});229}230231public EventQueue() {232for (int i = 0; i < NUM_PRIORITIES; i++) {233queues[i] = new Queue();234}235/*236* NOTE: if you ever have to start the associated event dispatch237* thread at this point, be aware of the following problem:238* If this EventQueue instance is created in239* SunToolkit.createNewAppContext() the started dispatch thread240* may call AppContext.getAppContext() before createNewAppContext()241* completes thus causing mess in thread group to appcontext mapping.242*/243244appContext = AppContext.getAppContext();245pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);246pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);247}248249/**250* Posts a 1.1-style event to the <code>EventQueue</code>.251* If there is an existing event on the queue with the same ID252* and event source, the source <code>Component</code>'s253* <code>coalesceEvents</code> method will be called.254*255* @param theEvent an instance of <code>java.awt.AWTEvent</code>,256* or a subclass of it257* @throws NullPointerException if <code>theEvent</code> is <code>null</code>258*/259public void postEvent(AWTEvent theEvent) {260SunToolkit.flushPendingEvents(appContext);261postEventPrivate(theEvent);262}263264/**265* Posts a 1.1-style event to the <code>EventQueue</code>.266* If there is an existing event on the queue with the same ID267* and event source, the source <code>Component</code>'s268* <code>coalesceEvents</code> method will be called.269*270* @param theEvent an instance of <code>java.awt.AWTEvent</code>,271* or a subclass of it272*/273private final void postEventPrivate(AWTEvent theEvent) {274theEvent.isPosted = true;275pushPopLock.lock();276try {277if (nextQueue != null) {278// Forward the event to the top of EventQueue stack279nextQueue.postEventPrivate(theEvent);280return;281}282if (dispatchThread == null) {283if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {284return;285} else {286initDispatchThread();287}288}289postEvent(theEvent, getPriority(theEvent));290} finally {291pushPopLock.unlock();292}293}294295private static int getPriority(AWTEvent theEvent) {296if (theEvent instanceof PeerEvent) {297PeerEvent peerEvent = (PeerEvent)theEvent;298if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {299return ULTIMATE_PRIORITY;300}301if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {302return HIGH_PRIORITY;303}304if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {305return LOW_PRIORITY;306}307}308int id = theEvent.getID();309if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {310return LOW_PRIORITY;311}312return NORM_PRIORITY;313}314315/**316* Posts the event to the internal Queue of specified priority,317* coalescing as appropriate.318*319* @param theEvent an instance of <code>java.awt.AWTEvent</code>,320* or a subclass of it321* @param priority the desired priority of the event322*/323private void postEvent(AWTEvent theEvent, int priority) {324if (coalesceEvent(theEvent, priority)) {325return;326}327328EventQueueItem newItem = new EventQueueItem(theEvent);329330cacheEQItem(newItem);331332boolean notifyID = (theEvent.getID() == this.waitForID);333334if (queues[priority].head == null) {335boolean shouldNotify = noEvents();336queues[priority].head = queues[priority].tail = newItem;337338if (shouldNotify) {339if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {340AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);341}342pushPopCond.signalAll();343} else if (notifyID) {344pushPopCond.signalAll();345}346} else {347// The event was not coalesced or has non-Component source.348// Insert it at the end of the appropriate Queue.349queues[priority].tail.next = newItem;350queues[priority].tail = newItem;351if (notifyID) {352pushPopCond.signalAll();353}354}355}356357private boolean coalescePaintEvent(PaintEvent e) {358ComponentPeer sourcePeer = ((Component)e.getSource()).peer;359if (sourcePeer != null) {360sourcePeer.coalescePaintEvent(e);361}362EventQueueItem[] cache = ((Component)e.getSource()).eventCache;363if (cache == null) {364return false;365}366int index = eventToCacheIndex(e);367368if (index != -1 && cache[index] != null) {369PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);370if (merged != null) {371cache[index].event = merged;372return true;373}374}375return false;376}377378private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {379Rectangle aRect = a.getUpdateRect();380Rectangle bRect = b.getUpdateRect();381if (bRect.contains(aRect)) {382return b;383}384if (aRect.contains(bRect)) {385return a;386}387return null;388}389390private boolean coalesceMouseEvent(MouseEvent e) {391EventQueueItem[] cache = ((Component)e.getSource()).eventCache;392if (cache == null) {393return false;394}395int index = eventToCacheIndex(e);396if (index != -1 && cache[index] != null) {397cache[index].event = e;398return true;399}400return false;401}402403private boolean coalescePeerEvent(PeerEvent e) {404EventQueueItem[] cache = ((Component)e.getSource()).eventCache;405if (cache == null) {406return false;407}408int index = eventToCacheIndex(e);409if (index != -1 && cache[index] != null) {410e = e.coalesceEvents((PeerEvent)cache[index].event);411if (e != null) {412cache[index].event = e;413return true;414} else {415cache[index] = null;416}417}418return false;419}420421/*422* Should avoid of calling this method by any means423* as it's working time is dependant on EQ length.424* In the wors case this method alone can slow down the entire application425* 10 times by stalling the Event processing.426* Only here by backward compatibility reasons.427*/428private boolean coalesceOtherEvent(AWTEvent e, int priority) {429int id = e.getID();430Component source = (Component)e.getSource();431for (EventQueueItem entry = queues[priority].head;432entry != null; entry = entry.next)433{434// Give Component.coalesceEvents a chance435if (entry.event.getSource() == source && entry.event.getID() == id) {436AWTEvent coalescedEvent = source.coalesceEvents(437entry.event, e);438if (coalescedEvent != null) {439entry.event = coalescedEvent;440return true;441}442}443}444return false;445}446447private boolean coalesceEvent(AWTEvent e, int priority) {448if (!(e.getSource() instanceof Component)) {449return false;450}451if (e instanceof PeerEvent) {452return coalescePeerEvent((PeerEvent)e);453}454// The worst case455if (((Component)e.getSource()).isCoalescingEnabled()456&& coalesceOtherEvent(e, priority))457{458return true;459}460if (e instanceof PaintEvent) {461return coalescePaintEvent((PaintEvent)e);462}463if (e instanceof MouseEvent) {464return coalesceMouseEvent((MouseEvent)e);465}466return false;467}468469private void cacheEQItem(EventQueueItem entry) {470int index = eventToCacheIndex(entry.event);471if (index != -1 && entry.event.getSource() instanceof Component) {472Component source = (Component)entry.event.getSource();473if (source.eventCache == null) {474source.eventCache = new EventQueueItem[CACHE_LENGTH];475}476source.eventCache[index] = entry;477}478}479480private void uncacheEQItem(EventQueueItem entry) {481int index = eventToCacheIndex(entry.event);482if (index != -1 && entry.event.getSource() instanceof Component) {483Component source = (Component)entry.event.getSource();484if (source.eventCache == null) {485return;486}487source.eventCache[index] = null;488}489}490491private static final int PAINT = 0;492private static final int UPDATE = 1;493private static final int MOVE = 2;494private static final int DRAG = 3;495private static final int PEER = 4;496private static final int CACHE_LENGTH = 5;497498private static int eventToCacheIndex(AWTEvent e) {499switch(e.getID()) {500case PaintEvent.PAINT:501return PAINT;502case PaintEvent.UPDATE:503return UPDATE;504case MouseEvent.MOUSE_MOVED:505return MOVE;506case MouseEvent.MOUSE_DRAGGED:507// Return -1 for SunDropTargetEvent since they are usually synchronous508// and we don't want to skip them by coalescing with MouseEvent or other drag events509return e instanceof SunDropTargetEvent ? -1 : DRAG;510default:511return e instanceof PeerEvent ? PEER : -1;512}513}514515/**516* Returns whether an event is pending on any of the separate517* Queues.518* @return whether an event is pending on any of the separate Queues519*/520private boolean noEvents() {521for (int i = 0; i < NUM_PRIORITIES; i++) {522if (queues[i].head != null) {523return false;524}525}526527return true;528}529530/**531* Removes an event from the <code>EventQueue</code> and532* returns it. This method will block until an event has533* been posted by another thread.534* @return the next <code>AWTEvent</code>535* @exception InterruptedException536* if any thread has interrupted this thread537*/538public AWTEvent getNextEvent() throws InterruptedException {539do {540/*541* SunToolkit.flushPendingEvents must be called outside542* of the synchronized block to avoid deadlock when543* event queues are nested with push()/pop().544*/545SunToolkit.flushPendingEvents(appContext);546pushPopLock.lock();547try {548AWTEvent event = getNextEventPrivate();549if (event != null) {550return event;551}552AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);553pushPopCond.await();554} finally {555pushPopLock.unlock();556}557} while(true);558}559560/*561* Must be called under the lock. Doesn't call flushPendingEvents()562*/563AWTEvent getNextEventPrivate() throws InterruptedException {564for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {565if (queues[i].head != null) {566EventQueueItem entry = queues[i].head;567queues[i].head = entry.next;568if (entry.next == null) {569queues[i].tail = null;570}571uncacheEQItem(entry);572return entry.event;573}574}575return null;576}577578AWTEvent getNextEvent(int id) throws InterruptedException {579do {580/*581* SunToolkit.flushPendingEvents must be called outside582* of the synchronized block to avoid deadlock when583* event queues are nested with push()/pop().584*/585SunToolkit.flushPendingEvents(appContext);586pushPopLock.lock();587try {588for (int i = 0; i < NUM_PRIORITIES; i++) {589for (EventQueueItem entry = queues[i].head, prev = null;590entry != null; prev = entry, entry = entry.next)591{592if (entry.event.getID() == id) {593if (prev == null) {594queues[i].head = entry.next;595} else {596prev.next = entry.next;597}598if (queues[i].tail == entry) {599queues[i].tail = prev;600}601uncacheEQItem(entry);602return entry.event;603}604}605}606waitForID = id;607pushPopCond.await();608waitForID = 0;609} finally {610pushPopLock.unlock();611}612} while(true);613}614615/**616* Returns the first event on the <code>EventQueue</code>617* without removing it.618* @return the first event619*/620public AWTEvent peekEvent() {621pushPopLock.lock();622try {623for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {624if (queues[i].head != null) {625return queues[i].head.event;626}627}628} finally {629pushPopLock.unlock();630}631632return null;633}634635/**636* Returns the first event with the specified id, if any.637* @param id the id of the type of event desired638* @return the first event of the specified id or <code>null</code>639* if there is no such event640*/641public AWTEvent peekEvent(int id) {642pushPopLock.lock();643try {644for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {645EventQueueItem q = queues[i].head;646for (; q != null; q = q.next) {647if (q.event.getID() == id) {648return q.event;649}650}651}652} finally {653pushPopLock.unlock();654}655656return null;657}658659private static final JavaSecurityAccess javaSecurityAccess =660SharedSecrets.getJavaSecurityAccess();661662/**663* Dispatches an event. The manner in which the event is664* dispatched depends upon the type of the event and the665* type of the event's source object:666*667* <table border=1 summary="Event types, source types, and dispatch methods">668* <tr>669* <th>Event Type</th>670* <th>Source Type</th>671* <th>Dispatched To</th>672* </tr>673* <tr>674* <td>ActiveEvent</td>675* <td>Any</td>676* <td>event.dispatch()</td>677* </tr>678* <tr>679* <td>Other</td>680* <td>Component</td>681* <td>source.dispatchEvent(AWTEvent)</td>682* </tr>683* <tr>684* <td>Other</td>685* <td>MenuComponent</td>686* <td>source.dispatchEvent(AWTEvent)</td>687* </tr>688* <tr>689* <td>Other</td>690* <td>Other</td>691* <td>No action (ignored)</td>692* </tr>693* </table>694* <p>695* @param event an instance of <code>java.awt.AWTEvent</code>,696* or a subclass of it697* @throws NullPointerException if <code>event</code> is <code>null</code>698* @since 1.2699*/700protected void dispatchEvent(final AWTEvent event) {701final Object src = event.getSource();702final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {703public Void run() {704// In case fwDispatcher is installed and we're already on the705// dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),706// dispatch the event straight away.707if (fwDispatcher == null || isDispatchThreadImpl()) {708dispatchEventImpl(event, src);709} else {710fwDispatcher.scheduleDispatch(new Runnable() {711@Override712public void run() {713if (dispatchThread.filterAndCheckEvent(event)) {714dispatchEventImpl(event, src);715}716}717});718}719return null;720}721};722723final AccessControlContext stack = AccessController.getContext();724final AccessControlContext srcAcc = getAccessControlContextFrom(src);725final AccessControlContext eventAcc = event.getAccessControlContext();726if (srcAcc == null) {727javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);728} else {729javaSecurityAccess.doIntersectionPrivilege(730new PrivilegedAction<Void>() {731public Void run() {732javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);733return null;734}735}, stack, srcAcc);736}737}738739private static AccessControlContext getAccessControlContextFrom(Object src) {740return src instanceof Component ?741((Component)src).getAccessControlContext() :742src instanceof MenuComponent ?743((MenuComponent)src).getAccessControlContext() :744src instanceof TrayIcon ?745((TrayIcon)src).getAccessControlContext() :746null;747}748749/**750* Called from dispatchEvent() under a correct AccessControlContext751*/752private void dispatchEventImpl(final AWTEvent event, final Object src) {753event.isPosted = true;754if (event instanceof ActiveEvent) {755// This could become the sole method of dispatching in time.756setCurrentEventAndMostRecentTimeImpl(event);757((ActiveEvent)event).dispatch();758} else if (src instanceof Component) {759((Component)src).dispatchEvent(event);760event.dispatched();761} else if (src instanceof MenuComponent) {762((MenuComponent)src).dispatchEvent(event);763} else if (src instanceof TrayIcon) {764((TrayIcon)src).dispatchEvent(event);765} else if (src instanceof AWTAutoShutdown) {766if (noEvents()) {767dispatchThread.stopDispatching();768}769} else {770if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {771getEventLog().fine("Unable to dispatch event: " + event);772}773}774}775776/**777* Returns the timestamp of the most recent event that had a timestamp, and778* that was dispatched from the <code>EventQueue</code> associated with the779* calling thread. If an event with a timestamp is currently being780* dispatched, its timestamp will be returned. If no events have yet781* been dispatched, the EventQueue's initialization time will be782* returned instead.In the current version of783* the JDK, only <code>InputEvent</code>s,784* <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have785* timestamps; however, future versions of the JDK may add timestamps to786* additional event types. Note that this method should only be invoked787* from an application's {@link #isDispatchThread event dispatching thread}.788* If this method is789* invoked from another thread, the current system time (as reported by790* <code>System.currentTimeMillis()</code>) will be returned instead.791*792* @return the timestamp of the last <code>InputEvent</code>,793* <code>ActionEvent</code>, or <code>InvocationEvent</code> to be794* dispatched, or <code>System.currentTimeMillis()</code> if this795* method is invoked on a thread other than an event dispatching796* thread797* @see java.awt.event.InputEvent#getWhen798* @see java.awt.event.ActionEvent#getWhen799* @see java.awt.event.InvocationEvent#getWhen800* @see #isDispatchThread801*802* @since 1.4803*/804public static long getMostRecentEventTime() {805return Toolkit.getEventQueue().getMostRecentEventTimeImpl();806}807private long getMostRecentEventTimeImpl() {808pushPopLock.lock();809try {810return (Thread.currentThread() == dispatchThread)811? mostRecentEventTime812: System.currentTimeMillis();813} finally {814pushPopLock.unlock();815}816}817818/**819* @return most recent event time on all threads.820*/821long getMostRecentEventTimeEx() {822pushPopLock.lock();823try {824return mostRecentEventTime;825} finally {826pushPopLock.unlock();827}828}829830/**831* Returns the the event currently being dispatched by the832* <code>EventQueue</code> associated with the calling thread. This is833* useful if a method needs access to the event, but was not designed to834* receive a reference to it as an argument. Note that this method should835* only be invoked from an application's event dispatching thread. If this836* method is invoked from another thread, null will be returned.837*838* @return the event currently being dispatched, or null if this method is839* invoked on a thread other than an event dispatching thread840* @since 1.4841*/842public static AWTEvent getCurrentEvent() {843return Toolkit.getEventQueue().getCurrentEventImpl();844}845private AWTEvent getCurrentEventImpl() {846pushPopLock.lock();847try {848return (Thread.currentThread() == dispatchThread)849? currentEvent.get()850: null;851} finally {852pushPopLock.unlock();853}854}855856/**857* Replaces the existing <code>EventQueue</code> with the specified one.858* Any pending events are transferred to the new <code>EventQueue</code>859* for processing by it.860*861* @param newEventQueue an <code>EventQueue</code>862* (or subclass thereof) instance to be use863* @see java.awt.EventQueue#pop864* @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>865* @since 1.2866*/867public void push(EventQueue newEventQueue) {868if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {869getEventLog().fine("EventQueue.push(" + newEventQueue + ")");870}871872pushPopLock.lock();873try {874EventQueue topQueue = this;875while (topQueue.nextQueue != null) {876topQueue = topQueue.nextQueue;877}878if (topQueue.fwDispatcher != null) {879throw new RuntimeException("push() to queue with fwDispatcher");880}881if ((topQueue.dispatchThread != null) &&882(topQueue.dispatchThread.getEventQueue() == this))883{884newEventQueue.dispatchThread = topQueue.dispatchThread;885topQueue.dispatchThread.setEventQueue(newEventQueue);886}887888// Transfer all events forward to new EventQueue.889while (topQueue.peekEvent() != null) {890try {891// Use getNextEventPrivate() as it doesn't call flushPendingEvents()892newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());893} catch (InterruptedException ie) {894if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {895getEventLog().fine("Interrupted push", ie);896}897}898}899900if (topQueue.dispatchThread != null) {901// Wake up EDT waiting in getNextEvent(), so it can902// pick up a new EventQueue. Post the waking event before903// topQueue.nextQueue is assigned, otherwise the event would904// go newEventQueue905topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));906}907908newEventQueue.previousQueue = topQueue;909topQueue.nextQueue = newEventQueue;910911if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {912appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);913}914915pushPopCond.signalAll();916} finally {917pushPopLock.unlock();918}919}920921/**922* Stops dispatching events using this <code>EventQueue</code>.923* Any pending events are transferred to the previous924* <code>EventQueue</code> for processing.925* <p>926* Warning: To avoid deadlock, do not declare this method927* synchronized in a subclass.928*929* @exception EmptyStackException if no previous push was made930* on this <code>EventQueue</code>931* @see java.awt.EventQueue#push932* @since 1.2933*/934protected void pop() throws EmptyStackException {935if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {936getEventLog().fine("EventQueue.pop(" + this + ")");937}938939pushPopLock.lock();940try {941EventQueue topQueue = this;942while (topQueue.nextQueue != null) {943topQueue = topQueue.nextQueue;944}945EventQueue prevQueue = topQueue.previousQueue;946if (prevQueue == null) {947throw new EmptyStackException();948}949950topQueue.previousQueue = null;951prevQueue.nextQueue = null;952953// Transfer all events back to previous EventQueue.954while (topQueue.peekEvent() != null) {955try {956prevQueue.postEventPrivate(topQueue.getNextEventPrivate());957} catch (InterruptedException ie) {958if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {959getEventLog().fine("Interrupted pop", ie);960}961}962}963964if ((topQueue.dispatchThread != null) &&965(topQueue.dispatchThread.getEventQueue() == this))966{967prevQueue.dispatchThread = topQueue.dispatchThread;968topQueue.dispatchThread.setEventQueue(prevQueue);969}970971if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {972appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);973}974975// Wake up EDT waiting in getNextEvent(), so it can976// pick up a new EventQueue977topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));978979pushPopCond.signalAll();980} finally {981pushPopLock.unlock();982}983}984985/**986* Creates a new {@code secondary loop} associated with this987* event queue. Use the {@link SecondaryLoop#enter} and988* {@link SecondaryLoop#exit} methods to start and stop the989* event loop and dispatch the events from this queue.990*991* @return secondaryLoop A new secondary loop object, which can992* be used to launch a new nested event993* loop and dispatch events from this queue994*995* @see SecondaryLoop#enter996* @see SecondaryLoop#exit997*998* @since 1.7999*/1000public SecondaryLoop createSecondaryLoop() {1001return createSecondaryLoop(null, null, 0);1002}10031004private class FwSecondaryLoopWrapper implements SecondaryLoop {1005final private SecondaryLoop loop;1006final private EventFilter filter;10071008public FwSecondaryLoopWrapper(SecondaryLoop loop, EventFilter filter) {1009this.loop = loop;1010this.filter = filter;1011}10121013@Override1014public boolean enter() {1015if (filter != null) {1016dispatchThread.addEventFilter(filter);1017}1018return loop.enter();1019}10201021@Override1022public boolean exit() {1023if (filter != null) {1024dispatchThread.removeEventFilter(filter);1025}1026return loop.exit();1027}1028}10291030SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {1031pushPopLock.lock();1032try {1033if (nextQueue != null) {1034// Forward the request to the top of EventQueue stack1035return nextQueue.createSecondaryLoop(cond, filter, interval);1036}1037if (fwDispatcher != null) {1038return new FwSecondaryLoopWrapper(fwDispatcher.createSecondaryLoop(), filter);1039}1040if (dispatchThread == null) {1041initDispatchThread();1042}1043return new WaitDispatchSupport(dispatchThread, cond, filter, interval);1044} finally {1045pushPopLock.unlock();1046}1047}10481049/**1050* Returns true if the calling thread is1051* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1052* dispatch thread. Use this method to ensure that a particular1053* task is being executed (or not being) there.1054* <p>1055* Note: use the {@link #invokeLater} or {@link #invokeAndWait}1056* methods to execute a task in1057* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1058* dispatch thread.1059* <p>1060*1061* @return true if running in1062* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1063* dispatch thread1064* @see #invokeLater1065* @see #invokeAndWait1066* @see Toolkit#getSystemEventQueue1067* @since 1.21068*/1069public static boolean isDispatchThread() {1070EventQueue eq = Toolkit.getEventQueue();1071return eq.isDispatchThreadImpl();1072}10731074final boolean isDispatchThreadImpl() {1075EventQueue eq = this;1076pushPopLock.lock();1077try {1078EventQueue next = eq.nextQueue;1079while (next != null) {1080eq = next;1081next = eq.nextQueue;1082}1083if (eq.fwDispatcher != null) {1084return eq.fwDispatcher.isDispatchThread();1085}1086return (Thread.currentThread() == eq.dispatchThread);1087} finally {1088pushPopLock.unlock();1089}1090}10911092final void initDispatchThread() {1093pushPopLock.lock();1094try {1095if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {1096dispatchThread = AccessController.doPrivileged(1097new PrivilegedAction<EventDispatchThread>() {1098public EventDispatchThread run() {1099EventDispatchThread t =1100new EventDispatchThread(threadGroup,1101name,1102EventQueue.this);1103t.setContextClassLoader(classLoader);1104t.setPriority(Thread.NORM_PRIORITY + 1);1105t.setDaemon(false);1106AWTAutoShutdown.getInstance().notifyThreadBusy(t);1107return t;1108}1109}1110);1111dispatchThread.start();1112}1113} finally {1114pushPopLock.unlock();1115}1116}11171118final void detachDispatchThread(EventDispatchThread edt) {1119/*1120* Minimize discard possibility for non-posted events1121*/1122SunToolkit.flushPendingEvents(appContext);1123/*1124* This synchronized block is to secure that the event dispatch1125* thread won't die in the middle of posting a new event to the1126* associated event queue. It is important because we notify1127* that the event dispatch thread is busy after posting a new event1128* to its queue, so the EventQueue.dispatchThread reference must1129* be valid at that point.1130*/1131pushPopLock.lock();1132try {1133if (edt == dispatchThread) {1134dispatchThread = null;1135}1136AWTAutoShutdown.getInstance().notifyThreadFree(edt);1137/*1138* Event was posted after EDT events pumping had stopped, so start1139* another EDT to handle this event1140*/1141if (peekEvent() != null) {1142initDispatchThread();1143}1144} finally {1145pushPopLock.unlock();1146}1147}11481149/*1150* Gets the <code>EventDispatchThread</code> for this1151* <code>EventQueue</code>.1152* @return the event dispatch thread associated with this event queue1153* or <code>null</code> if this event queue doesn't have a1154* working thread associated with it1155* @see java.awt.EventQueue#initDispatchThread1156* @see java.awt.EventQueue#detachDispatchThread1157*/1158final EventDispatchThread getDispatchThread() {1159pushPopLock.lock();1160try {1161return dispatchThread;1162} finally {1163pushPopLock.unlock();1164}1165}11661167/*1168* Removes any pending events for the specified source object.1169* If removeAllEvents parameter is <code>true</code> then all1170* events for the specified source object are removed, if it1171* is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,1172* <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,1173* and <code>InputMethodEvent</code> are kept in the queue, but all other1174* events are removed.1175*1176* This method is normally called by the source's1177* <code>removeNotify</code> method.1178*/1179final void removeSourceEvents(Object source, boolean removeAllEvents) {1180SunToolkit.flushPendingEvents(appContext);1181pushPopLock.lock();1182try {1183for (int i = 0; i < NUM_PRIORITIES; i++) {1184EventQueueItem entry = queues[i].head;1185EventQueueItem prev = null;1186while (entry != null) {1187if ((entry.event.getSource() == source)1188&& (removeAllEvents1189|| ! (entry.event instanceof SequencedEvent1190|| entry.event instanceof SentEvent1191|| entry.event instanceof FocusEvent1192|| entry.event instanceof WindowEvent1193|| entry.event instanceof KeyEvent1194|| entry.event instanceof InputMethodEvent)))1195{1196if (entry.event instanceof SequencedEvent) {1197((SequencedEvent)entry.event).dispose();1198}1199if (entry.event instanceof SentEvent) {1200((SentEvent)entry.event).dispose();1201}1202if (entry.event instanceof InvocationEvent) {1203AWTAccessor.getInvocationEventAccessor()1204.dispose((InvocationEvent)entry.event);1205}1206if (prev == null) {1207queues[i].head = entry.next;1208} else {1209prev.next = entry.next;1210}1211uncacheEQItem(entry);1212} else {1213prev = entry;1214}1215entry = entry.next;1216}1217queues[i].tail = prev;1218}1219} finally {1220pushPopLock.unlock();1221}1222}12231224synchronized long getMostRecentKeyEventTime() {1225pushPopLock.lock();1226try {1227return mostRecentKeyEventTime;1228} finally {1229pushPopLock.unlock();1230}1231}12321233static void setCurrentEventAndMostRecentTime(AWTEvent e) {1234Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);1235}1236private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {1237pushPopLock.lock();1238try {1239if (Thread.currentThread() != dispatchThread) {1240return;1241}12421243currentEvent = new WeakReference<>(e);12441245// This series of 'instanceof' checks should be replaced with a1246// polymorphic type (for example, an interface which declares a1247// getWhen() method). However, this would require us to make such1248// a type public, or to place it in sun.awt. Both of these approaches1249// have been frowned upon. So for now, we hack.1250//1251// In tiger, we will probably give timestamps to all events, so this1252// will no longer be an issue.1253long mostRecentEventTime2 = Long.MIN_VALUE;1254if (e instanceof InputEvent) {1255InputEvent ie = (InputEvent)e;1256mostRecentEventTime2 = ie.getWhen();1257if (e instanceof KeyEvent) {1258mostRecentKeyEventTime = ie.getWhen();1259}1260} else if (e instanceof InputMethodEvent) {1261InputMethodEvent ime = (InputMethodEvent)e;1262mostRecentEventTime2 = ime.getWhen();1263} else if (e instanceof ActionEvent) {1264ActionEvent ae = (ActionEvent)e;1265mostRecentEventTime2 = ae.getWhen();1266} else if (e instanceof InvocationEvent) {1267InvocationEvent ie = (InvocationEvent)e;1268mostRecentEventTime2 = ie.getWhen();1269}1270mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);1271} finally {1272pushPopLock.unlock();1273}1274}12751276/**1277* Causes <code>runnable</code> to have its <code>run</code>1278* method called in the {@link #isDispatchThread dispatch thread} of1279* {@link Toolkit#getSystemEventQueue the system EventQueue}.1280* This will happen after all pending events are processed.1281*1282* @param runnable the <code>Runnable</code> whose <code>run</code>1283* method should be executed1284* asynchronously in the1285* {@link #isDispatchThread event dispatch thread}1286* of {@link Toolkit#getSystemEventQueue the system EventQueue}1287* @see #invokeAndWait1288* @see Toolkit#getSystemEventQueue1289* @see #isDispatchThread1290* @since 1.21291*/1292public static void invokeLater(Runnable runnable) {1293Toolkit.getEventQueue().postEvent(1294new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));1295}12961297/**1298* Causes <code>runnable</code> to have its <code>run</code>1299* method called in the {@link #isDispatchThread dispatch thread} of1300* {@link Toolkit#getSystemEventQueue the system EventQueue}.1301* This will happen after all pending events are processed.1302* The call blocks until this has happened. This method1303* will throw an Error if called from the1304* {@link #isDispatchThread event dispatcher thread}.1305*1306* @param runnable the <code>Runnable</code> whose <code>run</code>1307* method should be executed1308* synchronously in the1309* {@link #isDispatchThread event dispatch thread}1310* of {@link Toolkit#getSystemEventQueue the system EventQueue}1311* @exception InterruptedException if any thread has1312* interrupted this thread1313* @exception InvocationTargetException if an throwable is thrown1314* when running <code>runnable</code>1315* @see #invokeLater1316* @see Toolkit#getSystemEventQueue1317* @see #isDispatchThread1318* @since 1.21319*/1320public static void invokeAndWait(Runnable runnable)1321throws InterruptedException, InvocationTargetException1322{1323invokeAndWait(Toolkit.getDefaultToolkit(), runnable);1324}13251326static void invokeAndWait(Object source, Runnable runnable)1327throws InterruptedException, InvocationTargetException1328{1329if (EventQueue.isDispatchThread()) {1330throw new Error("Cannot call invokeAndWait from the event dispatcher thread");1331}13321333class AWTInvocationLock {}1334Object lock = new AWTInvocationLock();13351336InvocationEvent event =1337new InvocationEvent(source, runnable, lock, true);13381339synchronized (lock) {1340Toolkit.getEventQueue().postEvent(event);1341while (!event.isDispatched()) {1342lock.wait();1343}1344}13451346Throwable eventThrowable = event.getThrowable();1347if (eventThrowable != null) {1348throw new InvocationTargetException(eventThrowable);1349}1350}13511352/*1353* Called from PostEventQueue.postEvent to notify that a new event1354* appeared. First it proceeds to the EventQueue on the top of the1355* stack, then notifies the associated dispatch thread if it exists1356* or starts a new one otherwise.1357*/1358private void wakeup(boolean isShutdown) {1359pushPopLock.lock();1360try {1361if (nextQueue != null) {1362// Forward call to the top of EventQueue stack.1363nextQueue.wakeup(isShutdown);1364} else if (dispatchThread != null) {1365pushPopCond.signalAll();1366} else if (!isShutdown) {1367initDispatchThread();1368}1369} finally {1370pushPopLock.unlock();1371}1372}13731374// The method is used by AWTAccessor for javafx/AWT single threaded mode.1375private void setFwDispatcher(FwDispatcher dispatcher) {1376if (nextQueue != null) {1377nextQueue.setFwDispatcher(dispatcher);1378} else {1379fwDispatcher = dispatcher;1380}1381}1382}13831384/**1385* The Queue object holds pointers to the beginning and end of one internal1386* queue. An EventQueue object is composed of multiple internal Queues, one1387* for each priority supported by the EventQueue. All Events on a particular1388* internal Queue have identical priority.1389*/1390class Queue {1391EventQueueItem head;1392EventQueueItem tail;1393}139413951396