34
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37
38 import java.util.EmptyStackException;
39
40 import sun.awt.*;
41 import sun.awt.dnd.SunDropTargetEvent;
42 import sun.util.logging.PlatformLogger;
43
44 import java.util.concurrent.locks.Condition;
45 import java.util.concurrent.locks.Lock;
46 import java.util.concurrent.atomic.AtomicInteger;
47
48 import java.security.AccessControlContext;
49
50 import jdk.internal.misc.SharedSecrets;
51 import jdk.internal.misc.JavaSecurityAccess;
52
53 /**
54 * <code>EventQueue</code> is a platform-independent class
55 * that queues events, both from the underlying peer classes
56 * and from trusted application classes.
57 * <p>
58 * It encapsulates asynchronous event dispatch machinery which
59 * extracts events from the queue and dispatches them by calling
60 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
61 * on this <code>EventQueue</code> with the event to be dispatched
62 * as an argument. The particular behavior of this machinery is
63 * implementation-dependent. The only requirements are that events
64 * which were actually enqueued to this queue (note that events
65 * being posted to the <code>EventQueue</code> can be coalesced)
66 * are dispatched:
67 * <dl>
68 * <dt> Sequentially.
69 * <dd> That is, it is not permitted that several events from
70 * this queue are dispatched simultaneously.
71 * <dt> In the same order as they are enqueued.
72 * <dd> That is, if <code>AWTEvent</code> A is enqueued
73 * to the <code>EventQueue</code> before
74 * <code>AWTEvent</code> B then event B will not be
75 * dispatched before event A.
76 * </dl>
77 * <p>
78 * Some browsers partition applets in different code bases into
79 * separate contexts, and establish walls between these contexts.
80 * In such a scenario, there will be one <code>EventQueue</code>
81 * per context. Other browsers place all applets into the same
82 * context, implying that there will be only a single, global
83 * <code>EventQueue</code> for all applets. This behavior is
84 * implementation-dependent. Consult your browser's documentation
85 * for more information.
86 * <p>
87 * For information on the threading issues of the event dispatch
88 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
89 * >AWT Threading Issues</a>.
90 *
91 * @author Thomas Ball
92 * @author Fred Ecks
93 * @author David Mendenhall
94 *
95 * @since 1.1
96 */
97 public class EventQueue {
98 private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
99
100 private static final int LOW_PRIORITY = 0;
101 private static final int NORM_PRIORITY = 1;
102 private static final int HIGH_PRIORITY = 2;
103 private static final int ULTIMATE_PRIORITY = 3;
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</code>.
255 * If there is an existing event on the queue with the same ID
256 * and event source, the source <code>Component</code>'s
257 * <code>coalesceEvents</code> method will be called.
258 *
259 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
260 * or a subclass of it
261 * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
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</code>.
270 * If there is an existing event on the queue with the same ID
271 * and event source, the source <code>Component</code>'s
272 * <code>coalesceEvents</code> method will be called.
273 *
274 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
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 {
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</code>,
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()) {
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</code> and
536 * returns it. This method will block until an event has
537 * been posted by another thread.
538 * @return the next <code>AWTEvent</code>
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 {
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</code>
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</code>
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
679 * <td>Any</td>
680 * <td>event.dispatch()</td>
681 * </tr>
682 * <tr>
683 * <td>Other</td>
684 * <td>Component</td>
685 * <td>source.dispatchEvent(AWTEvent)</td>
686 * </tr>
687 * <tr>
688 * <td>Other</td>
689 * <td>MenuComponent</td>
690 * <td>source.dispatchEvent(AWTEvent)</td>
691 * </tr>
692 * <tr>
693 * <td>Other</td>
694 * <td>Other</td>
695 * <td>No action (ignored)</td>
696 * </tr>
697 * </table>
698 *
699 * @param event an instance of <code>java.awt.AWTEvent</code>,
700 * or a subclass of it
701 * @throws NullPointerException if <code>event</code> is <code>null</code>
702 * @since 1.2
703 */
704 protected void dispatchEvent(final AWTEvent event) {
705 final Object src = event.getSource();
706 final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
707 public Void run() {
708 // In case fwDispatcher is installed and we're already on the
709 // dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
710 // dispatch the event straight away.
711 if (fwDispatcher == null || isDispatchThreadImpl()) {
712 dispatchEventImpl(event, src);
713 } else {
714 fwDispatcher.scheduleDispatch(new Runnable() {
715 @Override
716 public void run() {
717 dispatchEventImpl(event, src);
718 }
719 });
720 }
721 return null;
760 } else if (src instanceof Component) {
761 ((Component)src).dispatchEvent(event);
762 event.dispatched();
763 } else if (src instanceof MenuComponent) {
764 ((MenuComponent)src).dispatchEvent(event);
765 } else if (src instanceof TrayIcon) {
766 ((TrayIcon)src).dispatchEvent(event);
767 } else if (src instanceof AWTAutoShutdown) {
768 if (noEvents()) {
769 dispatchThread.stopDispatching();
770 }
771 } else {
772 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
773 getEventLog().fine("Unable to dispatch event: " + event);
774 }
775 }
776 }
777
778 /**
779 * Returns the timestamp of the most recent event that had a timestamp, and
780 * that was dispatched from the <code>EventQueue</code> associated with the
781 * calling thread. If an event with a timestamp is currently being
782 * dispatched, its timestamp will be returned. If no events have yet
783 * been dispatched, the EventQueue's initialization time will be
784 * returned instead.In the current version of
785 * the JDK, only <code>InputEvent</code>s,
786 * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
787 * timestamps; however, future versions of the JDK may add timestamps to
788 * additional event types. Note that this method should only be invoked
789 * from an application's {@link #isDispatchThread event dispatching thread}.
790 * If this method is
791 * invoked from another thread, the current system time (as reported by
792 * <code>System.currentTimeMillis()</code>) will be returned instead.
793 *
794 * @return the timestamp of the last <code>InputEvent</code>,
795 * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
796 * dispatched, or <code>System.currentTimeMillis()</code> if this
797 * method is invoked on a thread other than an event dispatching
798 * thread
799 * @see java.awt.event.InputEvent#getWhen
800 * @see java.awt.event.ActionEvent#getWhen
801 * @see java.awt.event.InvocationEvent#getWhen
802 * @see #isDispatchThread
803 *
804 * @since 1.4
805 */
806 public static long getMostRecentEventTime() {
807 return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
808 }
809 private long getMostRecentEventTimeImpl() {
810 pushPopLock.lock();
811 try {
812 return (Thread.currentThread() == dispatchThread)
813 ? mostRecentEventTime
814 : System.currentTimeMillis();
815 } finally {
816 pushPopLock.unlock();
817 }
818 }
819
820 /**
821 * @return most recent event time on all threads.
822 */
823 long getMostRecentEventTimeEx() {
824 pushPopLock.lock();
825 try {
826 return mostRecentEventTime;
827 } finally {
828 pushPopLock.unlock();
829 }
830 }
831
832 /**
833 * Returns the event currently being dispatched by the
834 * <code>EventQueue</code> associated with the calling thread. This is
835 * useful if a method needs access to the event, but was not designed to
836 * receive a reference to it as an argument. Note that this method should
837 * only be invoked from an application's event dispatching thread. If this
838 * method is invoked from another thread, null will be returned.
839 *
840 * @return the event currently being dispatched, or null if this method is
841 * invoked on a thread other than an event dispatching thread
842 * @since 1.4
843 */
844 public static AWTEvent getCurrentEvent() {
845 return Toolkit.getEventQueue().getCurrentEventImpl();
846 }
847 private AWTEvent getCurrentEventImpl() {
848 pushPopLock.lock();
849 try {
850 return (Thread.currentThread() == dispatchThread)
851 ? currentEvent.get()
852 : null;
853 } finally {
854 pushPopLock.unlock();
855 }
856 }
857
858 /**
859 * Replaces the existing <code>EventQueue</code> with the specified one.
860 * Any pending events are transferred to the new <code>EventQueue</code>
861 * for processing by it.
862 *
863 * @param newEventQueue an <code>EventQueue</code>
864 * (or subclass thereof) instance to be use
865 * @see java.awt.EventQueue#pop
866 * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
867 * @since 1.2
868 */
869 public void push(EventQueue newEventQueue) {
870 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
871 getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
872 }
873
874 pushPopLock.lock();
875 try {
876 EventQueue topQueue = this;
877 while (topQueue.nextQueue != null) {
878 topQueue = topQueue.nextQueue;
879 }
880 if (topQueue.fwDispatcher != null) {
881 throw new RuntimeException("push() to queue with fwDispatcher");
882 }
883 if ((topQueue.dispatchThread != null) &&
884 (topQueue.dispatchThread.getEventQueue() == this))
885 {
886 newEventQueue.dispatchThread = topQueue.dispatchThread;
904 // pick up a new EventQueue. Post the waking event before
905 // topQueue.nextQueue is assigned, otherwise the event would
906 // go newEventQueue
907 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
908 }
909
910 newEventQueue.previousQueue = topQueue;
911 topQueue.nextQueue = newEventQueue;
912
913 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
914 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
915 }
916
917 pushPopCond.signalAll();
918 } finally {
919 pushPopLock.unlock();
920 }
921 }
922
923 /**
924 * Stops dispatching events using this <code>EventQueue</code>.
925 * Any pending events are transferred to the previous
926 * <code>EventQueue</code> for processing.
927 * <p>
928 * Warning: To avoid deadlock, do not declare this method
929 * synchronized in a subclass.
930 *
931 * @exception EmptyStackException if no previous push was made
932 * on this <code>EventQueue</code>
933 * @see java.awt.EventQueue#push
934 * @since 1.2
935 */
936 protected void pop() throws EmptyStackException {
937 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
938 getEventLog().fine("EventQueue.pop(" + this + ")");
939 }
940
941 pushPopLock.lock();
942 try {
943 EventQueue topQueue = this;
944 while (topQueue.nextQueue != null) {
945 topQueue = topQueue.nextQueue;
946 }
947 EventQueue prevQueue = topQueue.previousQueue;
948 if (prevQueue == null) {
949 throw new EmptyStackException();
950 }
951
952 topQueue.previousQueue = null;
1105 */
1106 pushPopLock.lock();
1107 try {
1108 if (edt == dispatchThread) {
1109 dispatchThread = null;
1110 }
1111 AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1112 /*
1113 * Event was posted after EDT events pumping had stopped, so start
1114 * another EDT to handle this event
1115 */
1116 if (peekEvent() != null) {
1117 initDispatchThread();
1118 }
1119 } finally {
1120 pushPopLock.unlock();
1121 }
1122 }
1123
1124 /*
1125 * Gets the <code>EventDispatchThread</code> for this
1126 * <code>EventQueue</code>.
1127 * @return the event dispatch thread associated with this event queue
1128 * or <code>null</code> if this event queue doesn't have a
1129 * working thread associated with it
1130 * @see java.awt.EventQueue#initDispatchThread
1131 * @see java.awt.EventQueue#detachDispatchThread
1132 */
1133 final EventDispatchThread getDispatchThread() {
1134 pushPopLock.lock();
1135 try {
1136 return dispatchThread;
1137 } finally {
1138 pushPopLock.unlock();
1139 }
1140 }
1141
1142 /*
1143 * Removes any pending events for the specified source object.
1144 * If removeAllEvents parameter is <code>true</code> then all
1145 * events for the specified source object are removed, if it
1146 * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
1147 * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
1148 * and <code>InputMethodEvent</code> are kept in the queue, but all other
1149 * events are removed.
1150 *
1151 * This method is normally called by the source's
1152 * <code>removeNotify</code> method.
1153 */
1154 final void removeSourceEvents(Object source, boolean removeAllEvents) {
1155 SunToolkit.flushPendingEvents(appContext);
1156 pushPopLock.lock();
1157 try {
1158 for (int i = 0; i < NUM_PRIORITIES; i++) {
1159 EventQueueItem entry = queues[i].head;
1160 EventQueueItem prev = null;
1161 while (entry != null) {
1162 if ((entry.event.getSource() == source)
1163 && (removeAllEvents
1164 || ! (entry.event instanceof SequencedEvent
1165 || entry.event instanceof SentEvent
1166 || entry.event instanceof FocusEvent
1167 || entry.event instanceof WindowEvent
1168 || entry.event instanceof KeyEvent
1169 || entry.event instanceof InputMethodEvent)))
1170 {
1171 if (entry.event instanceof SequencedEvent) {
1172 ((SequencedEvent)entry.event).dispose();
1232 if (e instanceof KeyEvent) {
1233 mostRecentKeyEventTime = ie.getWhen();
1234 }
1235 } else if (e instanceof InputMethodEvent) {
1236 InputMethodEvent ime = (InputMethodEvent)e;
1237 mostRecentEventTime2 = ime.getWhen();
1238 } else if (e instanceof ActionEvent) {
1239 ActionEvent ae = (ActionEvent)e;
1240 mostRecentEventTime2 = ae.getWhen();
1241 } else if (e instanceof InvocationEvent) {
1242 InvocationEvent ie = (InvocationEvent)e;
1243 mostRecentEventTime2 = ie.getWhen();
1244 }
1245 mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1246 } finally {
1247 pushPopLock.unlock();
1248 }
1249 }
1250
1251 /**
1252 * Causes <code>runnable</code> to have its <code>run</code>
1253 * method called in the {@link #isDispatchThread dispatch thread} of
1254 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1255 * This will happen after all pending events are processed.
1256 *
1257 * @param runnable the <code>Runnable</code> whose <code>run</code>
1258 * method should be executed
1259 * asynchronously in the
1260 * {@link #isDispatchThread event dispatch thread}
1261 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1262 * @see #invokeAndWait
1263 * @see Toolkit#getSystemEventQueue
1264 * @see #isDispatchThread
1265 * @since 1.2
1266 */
1267 public static void invokeLater(Runnable runnable) {
1268 Toolkit.getEventQueue().postEvent(
1269 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1270 }
1271
1272 /**
1273 * Causes <code>runnable</code> to have its <code>run</code>
1274 * method called in the {@link #isDispatchThread dispatch thread} of
1275 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1276 * This will happen after all pending events are processed.
1277 * The call blocks until this has happened. This method
1278 * will throw an Error if called from the
1279 * {@link #isDispatchThread event dispatcher thread}.
1280 *
1281 * @param runnable the <code>Runnable</code> whose <code>run</code>
1282 * method should be executed
1283 * synchronously in the
1284 * {@link #isDispatchThread event dispatch thread}
1285 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1286 * @exception InterruptedException if any thread has
1287 * interrupted this thread
1288 * @exception InvocationTargetException if an throwable is thrown
1289 * when running <code>runnable</code>
1290 * @see #invokeLater
1291 * @see Toolkit#getSystemEventQueue
1292 * @see #isDispatchThread
1293 * @since 1.2
1294 */
1295 public static void invokeAndWait(Runnable runnable)
1296 throws InterruptedException, InvocationTargetException
1297 {
1298 invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1299 }
1300
1301 static void invokeAndWait(Object source, Runnable runnable)
1302 throws InterruptedException, InvocationTargetException
1303 {
1304 if (EventQueue.isDispatchThread()) {
1305 throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1306 }
1307
1308 class AWTInvocationLock {}
1309 Object lock = new AWTInvocationLock();
|
34
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37
38 import java.util.EmptyStackException;
39
40 import sun.awt.*;
41 import sun.awt.dnd.SunDropTargetEvent;
42 import sun.util.logging.PlatformLogger;
43
44 import java.util.concurrent.locks.Condition;
45 import java.util.concurrent.locks.Lock;
46 import java.util.concurrent.atomic.AtomicInteger;
47
48 import java.security.AccessControlContext;
49
50 import jdk.internal.misc.SharedSecrets;
51 import 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} A is enqueued
73 * to the {@code EventQueue} before
74 * {@code AWTEvent} 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 */
97 public class EventQueue {
98 private static final AtomicInteger threadInitNumber = new AtomicInteger(0);
99
100 private static final int LOW_PRIORITY = 0;
101 private static final int NORM_PRIORITY = 1;
102 private static final int HIGH_PRIORITY = 2;
103 private static final int ULTIMATE_PRIORITY = 3;
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 {
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()) {
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 {
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
679 * <td>Any</td>
680 * <td>event.dispatch()</td>
681 * </tr>
682 * <tr>
683 * <td>Other</td>
684 * <td>Component</td>
685 * <td>source.dispatchEvent(AWTEvent)</td>
686 * </tr>
687 * <tr>
688 * <td>Other</td>
689 * <td>MenuComponent</td>
690 * <td>source.dispatchEvent(AWTEvent)</td>
691 * </tr>
692 * <tr>
693 * <td>Other</td>
694 * <td>Other</td>
695 * <td>No action (ignored)</td>
696 * </tr>
697 * </table>
698 *
699 * @param event an instance of {@code java.awt.AWTEvent},
700 * or a subclass of it
701 * @throws NullPointerException if {@code event} is {@code null}
702 * @since 1.2
703 */
704 protected void dispatchEvent(final AWTEvent event) {
705 final Object src = event.getSource();
706 final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
707 public Void run() {
708 // In case fwDispatcher is installed and we're already on the
709 // dispatch thread (e.g. performing DefaultKeyboardFocusManager.sendMessage),
710 // dispatch the event straight away.
711 if (fwDispatcher == null || isDispatchThreadImpl()) {
712 dispatchEventImpl(event, src);
713 } else {
714 fwDispatcher.scheduleDispatch(new Runnable() {
715 @Override
716 public void run() {
717 dispatchEventImpl(event, src);
718 }
719 });
720 }
721 return null;
760 } else if (src instanceof Component) {
761 ((Component)src).dispatchEvent(event);
762 event.dispatched();
763 } else if (src instanceof MenuComponent) {
764 ((MenuComponent)src).dispatchEvent(event);
765 } else if (src instanceof TrayIcon) {
766 ((TrayIcon)src).dispatchEvent(event);
767 } else if (src instanceof AWTAutoShutdown) {
768 if (noEvents()) {
769 dispatchThread.stopDispatching();
770 }
771 } else {
772 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
773 getEventLog().fine("Unable to dispatch event: " + event);
774 }
775 }
776 }
777
778 /**
779 * Returns the timestamp of the most recent event that had a timestamp, and
780 * that was dispatched from the {@code EventQueue} associated with the
781 * calling thread. If an event with a timestamp is currently being
782 * dispatched, its timestamp will be returned. If no events have yet
783 * been dispatched, the EventQueue's initialization time will be
784 * returned instead.In the current version of
785 * the JDK, only {@code InputEvent}s,
786 * {@code ActionEvent}s, and {@code InvocationEvent}s have
787 * timestamps; however, future versions of the JDK may add timestamps to
788 * additional event types. Note that this method should only be invoked
789 * from an application's {@link #isDispatchThread event dispatching thread}.
790 * If this method is
791 * invoked from another thread, the current system time (as reported by
792 * {@code System.currentTimeMillis()}) will be returned instead.
793 *
794 * @return the timestamp of the last {@code InputEvent},
795 * {@code ActionEvent}, or {@code InvocationEvent} to be
796 * dispatched, or {@code System.currentTimeMillis()} if this
797 * method is invoked on a thread other than an event dispatching
798 * thread
799 * @see java.awt.event.InputEvent#getWhen
800 * @see java.awt.event.ActionEvent#getWhen
801 * @see java.awt.event.InvocationEvent#getWhen
802 * @see #isDispatchThread
803 *
804 * @since 1.4
805 */
806 public static long getMostRecentEventTime() {
807 return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
808 }
809 private long getMostRecentEventTimeImpl() {
810 pushPopLock.lock();
811 try {
812 return (Thread.currentThread() == dispatchThread)
813 ? mostRecentEventTime
814 : System.currentTimeMillis();
815 } finally {
816 pushPopLock.unlock();
817 }
818 }
819
820 /**
821 * @return most recent event time on all threads.
822 */
823 long getMostRecentEventTimeEx() {
824 pushPopLock.lock();
825 try {
826 return mostRecentEventTime;
827 } finally {
828 pushPopLock.unlock();
829 }
830 }
831
832 /**
833 * Returns the event currently being dispatched by the
834 * {@code EventQueue} associated with the calling thread. This is
835 * useful if a method needs access to the event, but was not designed to
836 * receive a reference to it as an argument. Note that this method should
837 * only be invoked from an application's event dispatching thread. If this
838 * method is invoked from another thread, null will be returned.
839 *
840 * @return the event currently being dispatched, or null if this method is
841 * invoked on a thread other than an event dispatching thread
842 * @since 1.4
843 */
844 public static AWTEvent getCurrentEvent() {
845 return Toolkit.getEventQueue().getCurrentEventImpl();
846 }
847 private AWTEvent getCurrentEventImpl() {
848 pushPopLock.lock();
849 try {
850 return (Thread.currentThread() == dispatchThread)
851 ? currentEvent.get()
852 : null;
853 } finally {
854 pushPopLock.unlock();
855 }
856 }
857
858 /**
859 * Replaces the existing {@code EventQueue} with the specified one.
860 * Any pending events are transferred to the new {@code EventQueue}
861 * for processing by it.
862 *
863 * @param newEventQueue an {@code EventQueue}
864 * (or subclass thereof) instance to be use
865 * @see java.awt.EventQueue#pop
866 * @throws NullPointerException if {@code newEventQueue} is {@code null}
867 * @since 1.2
868 */
869 public void push(EventQueue newEventQueue) {
870 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
871 getEventLog().fine("EventQueue.push(" + newEventQueue + ")");
872 }
873
874 pushPopLock.lock();
875 try {
876 EventQueue topQueue = this;
877 while (topQueue.nextQueue != null) {
878 topQueue = topQueue.nextQueue;
879 }
880 if (topQueue.fwDispatcher != null) {
881 throw new RuntimeException("push() to queue with fwDispatcher");
882 }
883 if ((topQueue.dispatchThread != null) &&
884 (topQueue.dispatchThread.getEventQueue() == this))
885 {
886 newEventQueue.dispatchThread = topQueue.dispatchThread;
904 // pick up a new EventQueue. Post the waking event before
905 // topQueue.nextQueue is assigned, otherwise the event would
906 // go newEventQueue
907 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
908 }
909
910 newEventQueue.previousQueue = topQueue;
911 topQueue.nextQueue = newEventQueue;
912
913 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
914 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
915 }
916
917 pushPopCond.signalAll();
918 } finally {
919 pushPopLock.unlock();
920 }
921 }
922
923 /**
924 * Stops dispatching events using this {@code EventQueue}.
925 * Any pending events are transferred to the previous
926 * {@code EventQueue} for processing.
927 * <p>
928 * Warning: To avoid deadlock, do not declare this method
929 * synchronized in a subclass.
930 *
931 * @exception EmptyStackException if no previous push was made
932 * on this {@code EventQueue}
933 * @see java.awt.EventQueue#push
934 * @since 1.2
935 */
936 protected void pop() throws EmptyStackException {
937 if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
938 getEventLog().fine("EventQueue.pop(" + this + ")");
939 }
940
941 pushPopLock.lock();
942 try {
943 EventQueue topQueue = this;
944 while (topQueue.nextQueue != null) {
945 topQueue = topQueue.nextQueue;
946 }
947 EventQueue prevQueue = topQueue.previousQueue;
948 if (prevQueue == null) {
949 throw new EmptyStackException();
950 }
951
952 topQueue.previousQueue = null;
1105 */
1106 pushPopLock.lock();
1107 try {
1108 if (edt == dispatchThread) {
1109 dispatchThread = null;
1110 }
1111 AWTAutoShutdown.getInstance().notifyThreadFree(edt);
1112 /*
1113 * Event was posted after EDT events pumping had stopped, so start
1114 * another EDT to handle this event
1115 */
1116 if (peekEvent() != null) {
1117 initDispatchThread();
1118 }
1119 } finally {
1120 pushPopLock.unlock();
1121 }
1122 }
1123
1124 /*
1125 * Gets the {@code EventDispatchThread} for this
1126 * {@code EventQueue}.
1127 * @return the event dispatch thread associated with this event queue
1128 * or {@code null} if this event queue doesn't have a
1129 * working thread associated with it
1130 * @see java.awt.EventQueue#initDispatchThread
1131 * @see java.awt.EventQueue#detachDispatchThread
1132 */
1133 final EventDispatchThread getDispatchThread() {
1134 pushPopLock.lock();
1135 try {
1136 return dispatchThread;
1137 } finally {
1138 pushPopLock.unlock();
1139 }
1140 }
1141
1142 /*
1143 * Removes any pending events for the specified source object.
1144 * If removeAllEvents parameter is {@code true} then all
1145 * events for the specified source object are removed, if it
1146 * is {@code false} then {@code SequencedEvent}, {@code SentEvent},
1147 * {@code FocusEvent}, {@code WindowEvent}, {@code KeyEvent},
1148 * and {@code InputMethodEvent} are kept in the queue, but all other
1149 * events are removed.
1150 *
1151 * This method is normally called by the source's
1152 * {@code removeNotify} method.
1153 */
1154 final void removeSourceEvents(Object source, boolean removeAllEvents) {
1155 SunToolkit.flushPendingEvents(appContext);
1156 pushPopLock.lock();
1157 try {
1158 for (int i = 0; i < NUM_PRIORITIES; i++) {
1159 EventQueueItem entry = queues[i].head;
1160 EventQueueItem prev = null;
1161 while (entry != null) {
1162 if ((entry.event.getSource() == source)
1163 && (removeAllEvents
1164 || ! (entry.event instanceof SequencedEvent
1165 || entry.event instanceof SentEvent
1166 || entry.event instanceof FocusEvent
1167 || entry.event instanceof WindowEvent
1168 || entry.event instanceof KeyEvent
1169 || entry.event instanceof InputMethodEvent)))
1170 {
1171 if (entry.event instanceof SequencedEvent) {
1172 ((SequencedEvent)entry.event).dispose();
1232 if (e instanceof KeyEvent) {
1233 mostRecentKeyEventTime = ie.getWhen();
1234 }
1235 } else if (e instanceof InputMethodEvent) {
1236 InputMethodEvent ime = (InputMethodEvent)e;
1237 mostRecentEventTime2 = ime.getWhen();
1238 } else if (e instanceof ActionEvent) {
1239 ActionEvent ae = (ActionEvent)e;
1240 mostRecentEventTime2 = ae.getWhen();
1241 } else if (e instanceof InvocationEvent) {
1242 InvocationEvent ie = (InvocationEvent)e;
1243 mostRecentEventTime2 = ie.getWhen();
1244 }
1245 mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
1246 } finally {
1247 pushPopLock.unlock();
1248 }
1249 }
1250
1251 /**
1252 * Causes {@code runnable} to have its {@code run}
1253 * method called in the {@link #isDispatchThread dispatch thread} of
1254 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1255 * This will happen after all pending events are processed.
1256 *
1257 * @param runnable the {@code Runnable} whose {@code run}
1258 * method should be executed
1259 * asynchronously in the
1260 * {@link #isDispatchThread event dispatch thread}
1261 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1262 * @see #invokeAndWait
1263 * @see Toolkit#getSystemEventQueue
1264 * @see #isDispatchThread
1265 * @since 1.2
1266 */
1267 public static void invokeLater(Runnable runnable) {
1268 Toolkit.getEventQueue().postEvent(
1269 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
1270 }
1271
1272 /**
1273 * Causes {@code runnable} to have its {@code run}
1274 * method called in the {@link #isDispatchThread dispatch thread} of
1275 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
1276 * This will happen after all pending events are processed.
1277 * The call blocks until this has happened. This method
1278 * will throw an Error if called from the
1279 * {@link #isDispatchThread event dispatcher thread}.
1280 *
1281 * @param runnable the {@code Runnable} whose {@code run}
1282 * method should be executed
1283 * synchronously in the
1284 * {@link #isDispatchThread event dispatch thread}
1285 * of {@link Toolkit#getSystemEventQueue the system EventQueue}
1286 * @exception InterruptedException if any thread has
1287 * interrupted this thread
1288 * @exception InvocationTargetException if an throwable is thrown
1289 * when running {@code runnable}
1290 * @see #invokeLater
1291 * @see Toolkit#getSystemEventQueue
1292 * @see #isDispatchThread
1293 * @since 1.2
1294 */
1295 public static void invokeAndWait(Runnable runnable)
1296 throws InterruptedException, InvocationTargetException
1297 {
1298 invokeAndWait(Toolkit.getDefaultToolkit(), runnable);
1299 }
1300
1301 static void invokeAndWait(Object source, Runnable runnable)
1302 throws InterruptedException, InvocationTargetException
1303 {
1304 if (EventQueue.isDispatchThread()) {
1305 throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
1306 }
1307
1308 class AWTInvocationLock {}
1309 Object lock = new AWTInvocationLock();
|