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