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