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