Path: blob/master/src/java.desktop/share/classes/java/awt/EventQueue.java
41152 views
/*1* Copyright (c) 1996, 2021, 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 jdk.internal.access.SharedSecrets;50import jdk.internal.access.JavaSecurityAccess;5152/**53* {@code EventQueue} 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} 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} 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} A is enqueued72* to the {@code EventQueue} before73* {@code AWTEvent} 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}80* per context. Other browsers place all applets into the same81* context, implying that there will be only a single, global82* {@code EventQueue} 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*/96@SuppressWarnings("removal")97public class EventQueue {98private static final AtomicInteger threadInitNumber = new AtomicInteger();99100private static final int LOW_PRIORITY = 0;101private static final int NORM_PRIORITY = 1;102private static final int HIGH_PRIORITY = 2;103private static final int ULTIMATE_PRIORITY = 3;104105private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;106107/*108* We maintain one Queue for each priority that the EventQueue supports.109* That is, the EventQueue object is actually implemented as110* NUM_PRIORITIES queues and all Events on a particular internal Queue111* have identical priority. Events are pulled off the EventQueue starting112* with the Queue of highest priority. We progress in decreasing order113* across all Queues.114*/115private Queue[] queues = new Queue[NUM_PRIORITIES];116117/*118* The next EventQueue on the stack, or null if this EventQueue is119* on the top of the stack. If nextQueue is non-null, requests to post120* an event are forwarded to nextQueue.121*/122private EventQueue nextQueue;123124/*125* The previous EventQueue on the stack, or null if this is the126* "base" EventQueue.127*/128private EventQueue previousQueue;129130/*131* A single lock to synchronize the push()/pop() and related operations with132* all the EventQueues from the AppContext. Synchronization on any particular133* event queue(s) is not enough: we should lock the whole stack.134*/135private final Lock pushPopLock;136private final Condition pushPopCond;137138/*139* Dummy runnable to wake up EDT from getNextEvent() after140push/pop is performed141*/142private static final Runnable dummyRunnable = new Runnable() {143public void run() {144}145};146147private EventDispatchThread dispatchThread;148149private final ThreadGroup threadGroup =150Thread.currentThread().getThreadGroup();151private final ClassLoader classLoader =152Thread.currentThread().getContextClassLoader();153154/*155* The time stamp of the last dispatched InputEvent or ActionEvent.156*/157private long mostRecentEventTime = System.currentTimeMillis();158159/*160* The time stamp of the last KeyEvent .161*/162private long mostRecentKeyEventTime = System.currentTimeMillis();163164/**165* The modifiers field of the current event, if the current event is an166* InputEvent or ActionEvent.167*/168private WeakReference<AWTEvent> currentEvent;169170/*171* Non-zero if a thread is waiting in getNextEvent(int) for an event of172* a particular ID to be posted to the queue.173*/174private volatile int waitForID;175176/*177* AppContext corresponding to the queue.178*/179private final AppContext appContext;180181private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement();182183private FwDispatcher fwDispatcher;184185private static volatile PlatformLogger eventLog;186187private static final PlatformLogger getEventLog() {188if(eventLog == null) {189eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue");190}191return eventLog;192}193194private static boolean fxAppThreadIsDispatchThread;195196static {197AWTAccessor.setEventQueueAccessor(198new AWTAccessor.EventQueueAccessor() {199public Thread getDispatchThread(EventQueue eventQueue) {200return eventQueue.getDispatchThread();201}202public boolean isDispatchThreadImpl(EventQueue eventQueue) {203return eventQueue.isDispatchThreadImpl();204}205public void removeSourceEvents(EventQueue eventQueue,206Object source,207boolean removeAllEvents)208{209eventQueue.removeSourceEvents(source, removeAllEvents);210}211public boolean noEvents(EventQueue eventQueue) {212return eventQueue.noEvents();213}214public void wakeup(EventQueue eventQueue, boolean isShutdown) {215eventQueue.wakeup(isShutdown);216}217public void invokeAndWait(Object source, Runnable r)218throws InterruptedException, InvocationTargetException219{220EventQueue.invokeAndWait(source, r);221}222public void setFwDispatcher(EventQueue eventQueue,223FwDispatcher dispatcher) {224eventQueue.setFwDispatcher(dispatcher);225}226227@Override228public long getMostRecentEventTime(EventQueue eventQueue) {229return eventQueue.getMostRecentEventTimeImpl();230}231});232AccessController.doPrivileged(new PrivilegedAction<Object>() {233public Object run() {234fxAppThreadIsDispatchThread =235"true".equals(System.getProperty("javafx.embed.singleThread"));236return null;237}238});239}240241/**242* Initializes a new instance of {@code EventQueue}.243*/244public EventQueue() {245for (int i = 0; i < NUM_PRIORITIES; i++) {246queues[i] = new Queue();247}248/*249* NOTE: if you ever have to start the associated event dispatch250* thread at this point, be aware of the following problem:251* If this EventQueue instance is created in252* SunToolkit.createNewAppContext() the started dispatch thread253* may call AppContext.getAppContext() before createNewAppContext()254* completes thus causing mess in thread group to appcontext mapping.255*/256257appContext = AppContext.getAppContext();258pushPopLock = (Lock)appContext.get(AppContext.EVENT_QUEUE_LOCK_KEY);259pushPopCond = (Condition)appContext.get(AppContext.EVENT_QUEUE_COND_KEY);260}261262/**263* Posts a 1.1-style event to the {@code EventQueue}.264* If there is an existing event on the queue with the same ID265* and event source, the source {@code Component}'s266* {@code coalesceEvents} method will be called.267*268* @param theEvent an instance of {@code java.awt.AWTEvent},269* or a subclass of it270* @throws NullPointerException if {@code theEvent} is {@code null}271*/272public void postEvent(AWTEvent theEvent) {273SunToolkit.flushPendingEvents(appContext);274postEventPrivate(theEvent);275}276277/**278* Posts a 1.1-style event to the {@code EventQueue}.279* If there is an existing event on the queue with the same ID280* and event source, the source {@code Component}'s281* {@code coalesceEvents} method will be called.282*283* @param theEvent an instance of {@code java.awt.AWTEvent},284* or a subclass of it285*/286private void postEventPrivate(AWTEvent theEvent) {287theEvent.isPosted = true;288pushPopLock.lock();289try {290if (nextQueue != null) {291// Forward the event to the top of EventQueue stack292nextQueue.postEventPrivate(theEvent);293return;294}295if (dispatchThread == null) {296if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {297return;298} else {299initDispatchThread();300}301}302postEvent(theEvent, getPriority(theEvent));303} finally {304pushPopLock.unlock();305}306}307308private static int getPriority(AWTEvent theEvent) {309if (theEvent instanceof PeerEvent) {310PeerEvent peerEvent = (PeerEvent)theEvent;311if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {312return ULTIMATE_PRIORITY;313}314if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {315return HIGH_PRIORITY;316}317if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {318return LOW_PRIORITY;319}320}321int id = theEvent.getID();322if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {323return LOW_PRIORITY;324}325return NORM_PRIORITY;326}327328/**329* Posts the event to the internal Queue of specified priority,330* coalescing as appropriate.331*332* @param theEvent an instance of {@code java.awt.AWTEvent},333* or a subclass of it334* @param priority the desired priority of the event335*/336private void postEvent(AWTEvent theEvent, int priority) {337if (coalesceEvent(theEvent, priority)) {338return;339}340341EventQueueItem newItem = new EventQueueItem(theEvent);342343cacheEQItem(newItem);344345boolean notifyID = (theEvent.getID() == this.waitForID);346347if (queues[priority].head == null) {348boolean shouldNotify = noEvents();349queues[priority].head = queues[priority].tail = newItem;350351if (shouldNotify) {352if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {353AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);354}355pushPopCond.signalAll();356} else if (notifyID) {357pushPopCond.signalAll();358}359} else {360// The event was not coalesced or has non-Component source.361// Insert it at the end of the appropriate Queue.362queues[priority].tail.next = newItem;363queues[priority].tail = newItem;364if (notifyID) {365pushPopCond.signalAll();366}367}368}369370private boolean coalescePaintEvent(PaintEvent e) {371ComponentPeer sourcePeer = ((Component)e.getSource()).peer;372if (sourcePeer != null) {373sourcePeer.coalescePaintEvent(e);374}375EventQueueItem[] cache = ((Component)e.getSource()).eventCache;376if (cache == null) {377return false;378}379int index = eventToCacheIndex(e);380381if (index != -1 && cache[index] != null) {382PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);383if (merged != null) {384cache[index].event = merged;385return true;386}387}388return false;389}390391private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {392Rectangle aRect = a.getUpdateRect();393Rectangle bRect = b.getUpdateRect();394if (bRect.contains(aRect)) {395return b;396}397if (aRect.contains(bRect)) {398return a;399}400return null;401}402403private boolean coalesceMouseEvent(MouseEvent e) {404EventQueueItem[] cache = ((Component)e.getSource()).eventCache;405if (cache == null) {406return false;407}408int index = eventToCacheIndex(e);409if (index != -1 && cache[index] != null) {410cache[index].event = e;411return true;412}413return false;414}415416private boolean coalescePeerEvent(PeerEvent e) {417EventQueueItem[] cache = ((Component)e.getSource()).eventCache;418if (cache == null) {419return false;420}421int index = eventToCacheIndex(e);422if (index != -1 && cache[index] != null) {423e = e.coalesceEvents((PeerEvent)cache[index].event);424if (e != null) {425cache[index].event = e;426return true;427} else {428cache[index] = null;429}430}431return false;432}433434/*435* Should avoid of calling this method by any means436* as it's working time is dependent on EQ length.437* In the worst case this method alone can slow down the entire application438* 10 times by stalling the Event processing.439* Only here by backward compatibility reasons.440*/441private boolean coalesceOtherEvent(AWTEvent e, int priority) {442int id = e.getID();443Component source = (Component)e.getSource();444for (EventQueueItem entry = queues[priority].head;445entry != null; entry = entry.next)446{447// Give Component.coalesceEvents a chance448if (entry.event.getSource() == source && entry.event.getID() == id) {449AWTEvent coalescedEvent = source.coalesceEvents(450entry.event, e);451if (coalescedEvent != null) {452entry.event = coalescedEvent;453return true;454}455}456}457return false;458}459460private boolean coalesceEvent(AWTEvent e, int priority) {461if (!(e.getSource() instanceof Component)) {462return false;463}464if (e instanceof PeerEvent) {465return coalescePeerEvent((PeerEvent)e);466}467// The worst case468if (((Component)e.getSource()).isCoalescingEnabled()469&& coalesceOtherEvent(e, priority))470{471return true;472}473if (e instanceof PaintEvent) {474return coalescePaintEvent((PaintEvent)e);475}476if (e instanceof MouseEvent) {477return coalesceMouseEvent((MouseEvent)e);478}479return false;480}481482private void cacheEQItem(EventQueueItem entry) {483int index = eventToCacheIndex(entry.event);484if (index != -1 && entry.event.getSource() instanceof Component) {485Component source = (Component)entry.event.getSource();486if (source.eventCache == null) {487source.eventCache = new EventQueueItem[CACHE_LENGTH];488}489source.eventCache[index] = entry;490}491}492493private void uncacheEQItem(EventQueueItem entry) {494int index = eventToCacheIndex(entry.event);495if (index != -1 && entry.event.getSource() instanceof Component) {496Component source = (Component)entry.event.getSource();497if (source.eventCache == null) {498return;499}500source.eventCache[index] = null;501}502}503504private static final int PAINT = 0;505private static final int UPDATE = 1;506private static final int MOVE = 2;507private static final int DRAG = 3;508private static final int PEER = 4;509private static final int CACHE_LENGTH = 5;510511private static int eventToCacheIndex(AWTEvent e) {512switch(e.getID()) {513case PaintEvent.PAINT:514return PAINT;515case PaintEvent.UPDATE:516return UPDATE;517case MouseEvent.MOUSE_MOVED:518return MOVE;519case MouseEvent.MOUSE_DRAGGED:520// Return -1 for SunDropTargetEvent since they are usually synchronous521// and we don't want to skip them by coalescing with MouseEvent or other drag events522return e instanceof SunDropTargetEvent ? -1 : DRAG;523default:524return e instanceof PeerEvent ? PEER : -1;525}526}527528/**529* Returns whether an event is pending on any of the separate530* Queues.531* @return whether an event is pending on any of the separate Queues532*/533private boolean noEvents() {534for (int i = 0; i < NUM_PRIORITIES; i++) {535if (queues[i].head != null) {536return false;537}538}539540return true;541}542543/**544* Removes an event from the {@code EventQueue} and545* returns it. This method will block until an event has546* been posted by another thread.547* @return the next {@code AWTEvent}548* @exception InterruptedException549* if any thread has interrupted this thread550*/551public AWTEvent getNextEvent() throws InterruptedException {552do {553/*554* SunToolkit.flushPendingEvents must be called outside555* of the synchronized block to avoid deadlock when556* event queues are nested with push()/pop().557*/558SunToolkit.flushPendingEvents(appContext);559pushPopLock.lock();560try {561AWTEvent event = getNextEventPrivate();562if (event != null) {563return event;564}565AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);566pushPopCond.await();567} finally {568pushPopLock.unlock();569}570} while(true);571}572573/*574* Must be called under the lock. Doesn't call flushPendingEvents()575*/576AWTEvent getNextEventPrivate() throws InterruptedException {577for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {578if (queues[i].head != null) {579EventQueueItem entry = queues[i].head;580queues[i].head = entry.next;581if (entry.next == null) {582queues[i].tail = null;583}584uncacheEQItem(entry);585return entry.event;586}587}588return null;589}590591AWTEvent getNextEvent(int id) throws InterruptedException {592do {593/*594* SunToolkit.flushPendingEvents must be called outside595* of the synchronized block to avoid deadlock when596* event queues are nested with push()/pop().597*/598SunToolkit.flushPendingEvents(appContext);599pushPopLock.lock();600try {601for (int i = 0; i < NUM_PRIORITIES; i++) {602for (EventQueueItem entry = queues[i].head, prev = null;603entry != null; prev = entry, entry = entry.next)604{605if (entry.event.getID() == id) {606if (prev == null) {607queues[i].head = entry.next;608} else {609prev.next = entry.next;610}611if (queues[i].tail == entry) {612queues[i].tail = prev;613}614uncacheEQItem(entry);615return entry.event;616}617}618}619waitForID = id;620pushPopCond.await();621waitForID = 0;622} finally {623pushPopLock.unlock();624}625} while(true);626}627628/**629* Returns the first event on the {@code EventQueue}630* without removing it.631* @return the first event632*/633public AWTEvent peekEvent() {634pushPopLock.lock();635try {636for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {637if (queues[i].head != null) {638return queues[i].head.event;639}640}641} finally {642pushPopLock.unlock();643}644645return null;646}647648/**649* Returns the first event with the specified id, if any.650* @param id the id of the type of event desired651* @return the first event of the specified id or {@code null}652* if there is no such event653*/654public AWTEvent peekEvent(int id) {655pushPopLock.lock();656try {657for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {658EventQueueItem q = queues[i].head;659for (; q != null; q = q.next) {660if (q.event.getID() == id) {661return q.event;662}663}664}665} finally {666pushPopLock.unlock();667}668669return null;670}671672private static final JavaSecurityAccess javaSecurityAccess =673SharedSecrets.getJavaSecurityAccess();674675/**676* Dispatches an event. The manner in which the event is677* dispatched depends upon the type of the event and the678* type of the event's source object:679*680* <table class="striped">681* <caption>Event types, source types, and dispatch methods</caption>682* <thead>683* <tr>684* <th scope="col">Event Type685* <th scope="col">Source Type686* <th scope="col">Dispatched To687* </thead>688* <tbody>689* <tr>690* <th scope="row">ActiveEvent691* <td>Any692* <td>event.dispatch()693* <tr>694* <th scope="row">Other695* <td>Component696* <td>source.dispatchEvent(AWTEvent)697* <tr>698* <th scope="row">Other699* <td>MenuComponent700* <td>source.dispatchEvent(AWTEvent)701* <tr>702* <th scope="row">Other703* <td>Other704* <td>No action (ignored)705* </tbody>706* </table>707*708* @param event an instance of {@code java.awt.AWTEvent},709* or a subclass of it710* @throws NullPointerException if {@code event} is {@code null}711* @since 1.2712*/713protected void dispatchEvent(final AWTEvent event) {714final Object src = event.getSource();715final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {716public Void run() {717// In case fwDispatcher is installed and we're already on the718// dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),719// dispatch the event straight away.720if (fwDispatcher == null || isDispatchThreadImpl()) {721dispatchEventImpl(event, src);722} else {723fwDispatcher.scheduleDispatch(new Runnable() {724@Override725public void run() {726if (dispatchThread.filterAndCheckEvent(event)) {727dispatchEventImpl(event, src);728}729}730});731}732return null;733}734};735736final AccessControlContext stack = AccessController.getContext();737final AccessControlContext srcAcc = getAccessControlContextFrom(src);738final AccessControlContext eventAcc = event.getAccessControlContext();739if (srcAcc == null) {740javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);741} else {742javaSecurityAccess.doIntersectionPrivilege(743new PrivilegedAction<Void>() {744public Void run() {745javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);746return null;747}748}, stack, srcAcc);749}750}751752private static AccessControlContext getAccessControlContextFrom(Object src) {753return src instanceof Component ?754((Component)src).getAccessControlContext() :755src instanceof MenuComponent ?756((MenuComponent)src).getAccessControlContext() :757src instanceof TrayIcon ?758((TrayIcon)src).getAccessControlContext() :759null;760}761762/**763* Called from dispatchEvent() under a correct AccessControlContext764*/765private void dispatchEventImpl(final AWTEvent event, final Object src) {766event.isPosted = true;767if (event instanceof ActiveEvent) {768// This could become the sole method of dispatching in time.769setCurrentEventAndMostRecentTimeImpl(event);770((ActiveEvent)event).dispatch();771} else if (src instanceof Component) {772((Component)src).dispatchEvent(event);773event.dispatched();774} else if (src instanceof MenuComponent) {775((MenuComponent)src).dispatchEvent(event);776} else if (src instanceof TrayIcon) {777((TrayIcon)src).dispatchEvent(event);778} else if (src instanceof AWTAutoShutdown) {779if (noEvents()) {780dispatchThread.stopDispatching();781}782} else {783if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {784getEventLog().fine("Unable to dispatch event: " + event);785}786}787}788789/**790* Returns the timestamp of the most recent event that had a timestamp, and791* that was dispatched from the {@code EventQueue} associated with the792* calling thread. If an event with a timestamp is currently being793* dispatched, its timestamp will be returned. If no events have yet794* been dispatched, the EventQueue's initialization time will be795* returned instead.In the current version of796* the JDK, only {@code InputEvent}s,797* {@code ActionEvent}s, and {@code InvocationEvent}s have798* timestamps; however, future versions of the JDK may add timestamps to799* additional event types. Note that this method should only be invoked800* from an application's {@link #isDispatchThread event dispatching thread}.801* If this method is802* invoked from another thread, the current system time (as reported by803* {@code System.currentTimeMillis()}) will be returned instead.804*805* @return the timestamp of the last {@code InputEvent},806* {@code ActionEvent}, or {@code InvocationEvent} to be807* dispatched, or {@code System.currentTimeMillis()} if this808* method is invoked on a thread other than an event dispatching809* thread810* @see java.awt.event.InputEvent#getWhen811* @see java.awt.event.ActionEvent#getWhen812* @see java.awt.event.InvocationEvent#getWhen813* @see #isDispatchThread814*815* @since 1.4816*/817public static long getMostRecentEventTime() {818return Toolkit.getEventQueue().getMostRecentEventTimeImpl();819}820private long getMostRecentEventTimeImpl() {821pushPopLock.lock();822try {823return (Thread.currentThread() == dispatchThread)824? mostRecentEventTime825: System.currentTimeMillis();826} finally {827pushPopLock.unlock();828}829}830831/**832* @return most recent event time on all threads.833*/834long getMostRecentEventTimeEx() {835pushPopLock.lock();836try {837return mostRecentEventTime;838} finally {839pushPopLock.unlock();840}841}842843/**844* Returns the event currently being dispatched by the845* {@code EventQueue} associated with the calling thread. This is846* useful if a method needs access to the event, but was not designed to847* receive a reference to it as an argument. Note that this method should848* only be invoked from an application's event dispatching thread. If this849* method is invoked from another thread, null will be returned.850*851* @return the event currently being dispatched, or null if this method is852* invoked on a thread other than an event dispatching thread853* @since 1.4854*/855public static AWTEvent getCurrentEvent() {856return Toolkit.getEventQueue().getCurrentEventImpl();857}858private AWTEvent getCurrentEventImpl() {859pushPopLock.lock();860try {861if (Thread.currentThread() == dispatchThread862|| fxAppThreadIsDispatchThread) {863return (currentEvent != null)864? currentEvent.get()865: null;866}867return null;868} finally {869pushPopLock.unlock();870}871}872873/**874* Replaces the existing {@code EventQueue} with the specified one.875* Any pending events are transferred to the new {@code EventQueue}876* for processing by it.877*878* @param newEventQueue an {@code EventQueue}879* (or subclass thereof) instance to be use880* @see java.awt.EventQueue#pop881* @throws NullPointerException if {@code newEventQueue} is {@code null}882* @since 1.2883*/884public void push(EventQueue newEventQueue) {885if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {886getEventLog().fine("EventQueue.push(" + newEventQueue + ")");887}888889pushPopLock.lock();890try {891EventQueue topQueue = this;892while (topQueue.nextQueue != null) {893topQueue = topQueue.nextQueue;894}895if (topQueue.fwDispatcher != null) {896throw new RuntimeException("push() to queue with fwDispatcher");897}898if ((topQueue.dispatchThread != null) &&899(topQueue.dispatchThread.getEventQueue() == this))900{901newEventQueue.dispatchThread = topQueue.dispatchThread;902topQueue.dispatchThread.setEventQueue(newEventQueue);903}904905// Transfer all events forward to new EventQueue.906while (topQueue.peekEvent() != null) {907try {908// Use getNextEventPrivate() as it doesn't call flushPendingEvents()909newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());910} catch (InterruptedException ie) {911if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {912getEventLog().fine("Interrupted push", ie);913}914}915}916917if (topQueue.dispatchThread != null) {918// Wake up EDT waiting in getNextEvent(), so it can919// pick up a new EventQueue. Post the waking event before920// topQueue.nextQueue is assigned, otherwise the event would921// go newEventQueue922topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));923}924925newEventQueue.previousQueue = topQueue;926topQueue.nextQueue = newEventQueue;927928if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {929appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);930}931932pushPopCond.signalAll();933} finally {934pushPopLock.unlock();935}936}937938/**939* Stops dispatching events using this {@code EventQueue}.940* Any pending events are transferred to the previous941* {@code EventQueue} for processing.942* <p>943* Warning: To avoid deadlock, do not declare this method944* synchronized in a subclass.945*946* @exception EmptyStackException if no previous push was made947* on this {@code EventQueue}948* @see java.awt.EventQueue#push949* @since 1.2950*/951protected void pop() throws EmptyStackException {952if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {953getEventLog().fine("EventQueue.pop(" + this + ")");954}955956pushPopLock.lock();957try {958EventQueue topQueue = this;959while (topQueue.nextQueue != null) {960topQueue = topQueue.nextQueue;961}962EventQueue prevQueue = topQueue.previousQueue;963if (prevQueue == null) {964throw new EmptyStackException();965}966967topQueue.previousQueue = null;968prevQueue.nextQueue = null;969970// Transfer all events back to previous EventQueue.971while (topQueue.peekEvent() != null) {972try {973prevQueue.postEventPrivate(topQueue.getNextEventPrivate());974} catch (InterruptedException ie) {975if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {976getEventLog().fine("Interrupted pop", ie);977}978}979}980981if ((topQueue.dispatchThread != null) &&982(topQueue.dispatchThread.getEventQueue() == this))983{984prevQueue.dispatchThread = topQueue.dispatchThread;985topQueue.dispatchThread.setEventQueue(prevQueue);986}987988if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {989appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);990}991992// Wake up EDT waiting in getNextEvent(), so it can993// pick up a new EventQueue994topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));995996pushPopCond.signalAll();997} finally {998pushPopLock.unlock();999}1000}10011002/**1003* Creates a new {@code secondary loop} associated with this1004* event queue. Use the {@link SecondaryLoop#enter} and1005* {@link SecondaryLoop#exit} methods to start and stop the1006* event loop and dispatch the events from this queue.1007*1008* @return secondaryLoop A new secondary loop object, which can1009* be used to launch a new nested event1010* loop and dispatch events from this queue1011*1012* @see SecondaryLoop#enter1013* @see SecondaryLoop#exit1014*1015* @since 1.71016*/1017public SecondaryLoop createSecondaryLoop() {1018return createSecondaryLoop(null, null, 0);1019}10201021private class FwSecondaryLoopWrapper implements SecondaryLoop {1022private final SecondaryLoop loop;1023private final EventFilter filter;10241025public FwSecondaryLoopWrapper(SecondaryLoop loop, EventFilter filter) {1026this.loop = loop;1027this.filter = filter;1028}10291030@Override1031public boolean enter() {1032if (filter != null) {1033dispatchThread.addEventFilter(filter);1034}1035return loop.enter();1036}10371038@Override1039public boolean exit() {1040if (filter != null) {1041dispatchThread.removeEventFilter(filter);1042}1043return loop.exit();1044}1045}10461047SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) {1048pushPopLock.lock();1049try {1050if (nextQueue != null) {1051// Forward the request to the top of EventQueue stack1052return nextQueue.createSecondaryLoop(cond, filter, interval);1053}1054if (fwDispatcher != null) {1055return new FwSecondaryLoopWrapper(fwDispatcher.createSecondaryLoop(), filter);1056}1057if (dispatchThread == null) {1058initDispatchThread();1059}1060return new WaitDispatchSupport(dispatchThread, cond, filter, interval);1061} finally {1062pushPopLock.unlock();1063}1064}10651066/**1067* Returns true if the calling thread is1068* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1069* dispatch thread. Use this method to ensure that a particular1070* task is being executed (or not being) there.1071* <p>1072* Note: use the {@link #invokeLater} or {@link #invokeAndWait}1073* methods to execute a task in1074* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1075* dispatch thread.1076*1077* @return true if running in1078* {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s1079* dispatch thread1080* @see #invokeLater1081* @see #invokeAndWait1082* @see Toolkit#getSystemEventQueue1083* @since 1.21084*/1085public static boolean isDispatchThread() {1086EventQueue eq = Toolkit.getEventQueue();1087return eq.isDispatchThreadImpl();1088}10891090final boolean isDispatchThreadImpl() {1091EventQueue eq = this;1092pushPopLock.lock();1093try {1094EventQueue next = eq.nextQueue;1095while (next != null) {1096eq = next;1097next = eq.nextQueue;1098}1099if (eq.fwDispatcher != null) {1100return eq.fwDispatcher.isDispatchThread();1101}1102return (Thread.currentThread() == eq.dispatchThread);1103} finally {1104pushPopLock.unlock();1105}1106}11071108@SuppressWarnings({"deprecation", "removal"})1109final void initDispatchThread() {1110pushPopLock.lock();1111try {1112if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {1113dispatchThread = AccessController.doPrivileged(1114new PrivilegedAction<EventDispatchThread>() {1115public EventDispatchThread run() {1116EventDispatchThread t =1117new EventDispatchThread(threadGroup,1118name,1119EventQueue.this);1120t.setContextClassLoader(classLoader);1121t.setPriority(Thread.NORM_PRIORITY + 1);1122t.setDaemon(false);1123AWTAutoShutdown.getInstance().notifyThreadBusy(t);1124return t;1125}1126}1127);1128dispatchThread.start();1129}1130} finally {1131pushPopLock.unlock();1132}1133}11341135final void detachDispatchThread(EventDispatchThread edt) {1136/*1137* Minimize discard possibility for non-posted events1138*/1139SunToolkit.flushPendingEvents(appContext);1140/*1141* This synchronized block is to secure that the event dispatch1142* thread won't die in the middle of posting a new event to the1143* associated event queue. It is important because we notify1144* that the event dispatch thread is busy after posting a new event1145* to its queue, so the EventQueue.dispatchThread reference must1146* be valid at that point.1147*/1148pushPopLock.lock();1149try {1150if (edt == dispatchThread) {1151dispatchThread = null;1152}1153AWTAutoShutdown.getInstance().notifyThreadFree(edt);1154/*1155* Event was posted after EDT events pumping had stopped, so start1156* another EDT to handle this event1157*/1158if (peekEvent() != null) {1159initDispatchThread();1160}1161} finally {1162pushPopLock.unlock();1163}1164}11651166/*1167* Gets the {@code EventDispatchThread} for this1168* {@code EventQueue}.1169* @return the event dispatch thread associated with this event queue1170* or {@code null} if this event queue doesn't have a1171* working thread associated with it1172* @see java.awt.EventQueue#initDispatchThread1173* @see java.awt.EventQueue#detachDispatchThread1174*/1175final EventDispatchThread getDispatchThread() {1176pushPopLock.lock();1177try {1178return dispatchThread;1179} finally {1180pushPopLock.unlock();1181}1182}11831184/*1185* Removes any pending events for the specified source object.1186* If removeAllEvents parameter is {@code true} then all1187* events for the specified source object are removed, if it1188* is {@code false} then {@code SequencedEvent}, {@code SentEvent},1189* {@code FocusEvent}, {@code WindowEvent}, {@code KeyEvent},1190* and {@code InputMethodEvent} are kept in the queue, but all other1191* events are removed.1192*1193* This method is normally called by the source's1194* {@code removeNotify} method.1195*/1196final void removeSourceEvents(Object source, boolean removeAllEvents) {1197SunToolkit.flushPendingEvents(appContext);1198pushPopLock.lock();1199try {1200for (int i = 0; i < NUM_PRIORITIES; i++) {1201EventQueueItem entry = queues[i].head;1202EventQueueItem prev = null;1203while (entry != null) {1204if ((entry.event.getSource() == source)1205&& (removeAllEvents1206|| ! (entry.event instanceof SequencedEvent1207|| entry.event instanceof SentEvent1208|| entry.event instanceof FocusEvent1209|| entry.event instanceof WindowEvent1210|| entry.event instanceof KeyEvent1211|| entry.event instanceof InputMethodEvent)))1212{1213if (entry.event instanceof SequencedEvent) {1214((SequencedEvent)entry.event).dispose();1215}1216if (entry.event instanceof SentEvent) {1217((SentEvent)entry.event).dispose();1218}1219if (entry.event instanceof InvocationEvent) {1220AWTAccessor.getInvocationEventAccessor()1221.dispose((InvocationEvent)entry.event);1222}1223if (entry.event instanceof SunDropTargetEvent) {1224((SunDropTargetEvent)entry.event).dispose();1225}1226if (prev == null) {1227queues[i].head = entry.next;1228} else {1229prev.next = entry.next;1230}1231uncacheEQItem(entry);1232} else {1233prev = entry;1234}1235entry = entry.next;1236}1237queues[i].tail = prev;1238}1239} finally {1240pushPopLock.unlock();1241}1242}12431244synchronized long getMostRecentKeyEventTime() {1245pushPopLock.lock();1246try {1247return mostRecentKeyEventTime;1248} finally {1249pushPopLock.unlock();1250}1251}12521253static void setCurrentEventAndMostRecentTime(AWTEvent e) {1254Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);1255}1256private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) {1257pushPopLock.lock();1258try {1259if (!fxAppThreadIsDispatchThread && Thread.currentThread() != dispatchThread) {1260return;1261}12621263currentEvent = new WeakReference<>(e);12641265// This series of 'instanceof' checks should be replaced with a1266// polymorphic type (for example, an interface which declares a1267// getWhen() method). However, this would require us to make such1268// a type public, or to place it in sun.awt. Both of these approaches1269// have been frowned upon. So for now, we hack.1270//1271// In tiger, we will probably give timestamps to all events, so this1272// will no longer be an issue.1273long mostRecentEventTime2 = Long.MIN_VALUE;1274if (e instanceof InputEvent) {1275InputEvent ie = (InputEvent)e;1276mostRecentEventTime2 = ie.getWhen();1277if (e instanceof KeyEvent) {1278mostRecentKeyEventTime = ie.getWhen();1279}1280} else if (e instanceof InputMethodEvent) {1281InputMethodEvent ime = (InputMethodEvent)e;1282mostRecentEventTime2 = ime.getWhen();1283} else if (e instanceof ActionEvent) {1284ActionEvent ae = (ActionEvent)e;1285mostRecentEventTime2 = ae.getWhen();1286} else if (e instanceof InvocationEvent) {1287InvocationEvent ie = (InvocationEvent)e;1288mostRecentEventTime2 = ie.getWhen();1289}1290mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);1291} finally {1292pushPopLock.unlock();1293}1294}12951296/**1297* Causes {@code runnable} to have its {@code run}1298* method called in the {@link #isDispatchThread dispatch thread} of1299* {@link Toolkit#getSystemEventQueue the system EventQueue}.1300* This will happen after all pending events are processed.1301*1302* @param runnable the {@code Runnable} whose {@code run}1303* method should be executed1304* asynchronously in the1305* {@link #isDispatchThread event dispatch thread}1306* of {@link Toolkit#getSystemEventQueue the system EventQueue}1307* @see #invokeAndWait1308* @see Toolkit#getSystemEventQueue1309* @see #isDispatchThread1310* @since 1.21311*/1312public static void invokeLater(Runnable runnable) {1313Toolkit.getEventQueue().postEvent(1314new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));1315}13161317/**1318* Causes {@code runnable} to have its {@code run}1319* method called in the {@link #isDispatchThread dispatch thread} of1320* {@link Toolkit#getSystemEventQueue the system EventQueue}.1321* This will happen after all pending events are processed.1322* The call blocks until this has happened. This method1323* will throw an Error if called from the1324* {@link #isDispatchThread event dispatcher thread}.1325*1326* @param runnable the {@code Runnable} whose {@code run}1327* method should be executed1328* synchronously in the1329* {@link #isDispatchThread event dispatch thread}1330* of {@link Toolkit#getSystemEventQueue the system EventQueue}1331* @exception InterruptedException if any thread has1332* interrupted this thread1333* @exception InvocationTargetException if an throwable is thrown1334* when running {@code runnable}1335* @see #invokeLater1336* @see Toolkit#getSystemEventQueue1337* @see #isDispatchThread1338* @since 1.21339*/1340public static void invokeAndWait(Runnable runnable)1341throws InterruptedException, InvocationTargetException1342{1343invokeAndWait(Toolkit.getDefaultToolkit(), runnable);1344}13451346static void invokeAndWait(Object source, Runnable runnable)1347throws InterruptedException, InvocationTargetException1348{1349if (EventQueue.isDispatchThread()) {1350throw new Error("Cannot call invokeAndWait from the event dispatcher thread");1351}13521353class AWTInvocationLock {}1354Object lock = new AWTInvocationLock();13551356InvocationEvent event =1357new InvocationEvent(source, runnable, lock, true);13581359synchronized (lock) {1360Toolkit.getEventQueue().postEvent(event);1361while (!event.isDispatched()) {1362lock.wait();1363}1364}13651366Throwable eventThrowable = event.getThrowable();1367if (eventThrowable != null) {1368throw new InvocationTargetException(eventThrowable);1369}1370}13711372/*1373* Called from PostEventQueue.postEvent to notify that a new event1374* appeared. First it proceeds to the EventQueue on the top of the1375* stack, then notifies the associated dispatch thread if it exists1376* or starts a new one otherwise.1377*/1378private void wakeup(boolean isShutdown) {1379pushPopLock.lock();1380try {1381if (nextQueue != null) {1382// Forward call to the top of EventQueue stack.1383nextQueue.wakeup(isShutdown);1384} else if (dispatchThread != null) {1385pushPopCond.signalAll();1386} else if (!isShutdown) {1387initDispatchThread();1388}1389} finally {1390pushPopLock.unlock();1391}1392}13931394// The method is used by AWTAccessor for javafx/AWT single threaded mode.1395private void setFwDispatcher(FwDispatcher dispatcher) {1396if (nextQueue != null) {1397nextQueue.setFwDispatcher(dispatcher);1398} else {1399fwDispatcher = dispatcher;1400}1401}1402}14031404/**1405* The Queue object holds pointers to the beginning and end of one internal1406* queue. An EventQueue object is composed of multiple internal Queues, one1407* for each priority supported by the EventQueue. All Events on a particular1408* internal Queue have identical priority.1409*/1410class Queue {1411EventQueueItem head;1412EventQueueItem tail;1413}141414151416