0001 /*
0002 * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.awt;
0027
0028 import java.awt.event.ActionEvent;
0029 import java.awt.event.FocusEvent;
0030 import java.awt.event.InputEvent;
0031 import java.awt.event.InputMethodEvent;
0032 import java.awt.event.InvocationEvent;
0033 import java.awt.event.KeyEvent;
0034 import java.awt.event.MouseEvent;
0035 import java.awt.event.PaintEvent;
0036 import java.awt.event.WindowEvent;
0037 import java.awt.ActiveEvent;
0038 import java.awt.peer.ComponentPeer;
0039 import java.awt.TrayIcon;
0040 import java.util.EmptyStackException;
0041 import java.lang.ref.WeakReference;
0042 import java.lang.reflect.InvocationTargetException;
0043 import java.security.AccessController;
0044 import java.security.PrivilegedAction;
0045 import sun.awt.PeerEvent;
0046 import sun.awt.SunToolkit;
0047 import sun.awt.AWTAutoShutdown;
0048 import sun.awt.AppContext;
0049
0050 /**
0051 * <code>EventQueue</code> is a platform-independent class
0052 * that queues events, both from the underlying peer classes
0053 * and from trusted application classes.
0054 * <p>
0055 * It encapsulates asynchronous event dispatch machinery which
0056 * extracts events from the queue and dispatches them by calling
0057 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
0058 * on this <code>EventQueue</code> with the event to be dispatched
0059 * as an argument. The particular behavior of this machinery is
0060 * implementation-dependent. The only requirements are that events
0061 * which were actually enqueued to this queue (note that events
0062 * being posted to the <code>EventQueue</code> can be coalesced)
0063 * are dispatched:
0064 * <dl>
0065 * <dt> Sequentially.
0066 * <dd> That is, it is not permitted that several events from
0067 * this queue are dispatched simultaneously.
0068 * <dt> In the same order as they are enqueued.
0069 * <dd> That is, if <code>AWTEvent</code> A is enqueued
0070 * to the <code>EventQueue</code> before
0071 * <code>AWTEvent</code> B then event B will not be
0072 * dispatched before event A.
0073 * </dl>
0074 * <p>
0075 * Some browsers partition applets in different code bases into
0076 * separate contexts, and establish walls between these contexts.
0077 * In such a scenario, there will be one <code>EventQueue</code>
0078 * per context. Other browsers place all applets into the same
0079 * context, implying that there will be only a single, global
0080 * <code>EventQueue</code> for all applets. This behavior is
0081 * implementation-dependent. Consult your browser's documentation
0082 * for more information.
0083 * <p>
0084 * For information on the threading issues of the event dispatch
0085 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
0086 * >AWT Threading Issues</a>.
0087 *
0088 * @author Thomas Ball
0089 * @author Fred Ecks
0090 * @author David Mendenhall
0091 *
0092 * @version 1.114, 06/05/07
0093 * @since 1.1
0094 */
0095 public class EventQueue {
0096
0097 // From Thread.java
0098 private static int threadInitNumber;
0099
0100 private static synchronized int nextThreadNum() {
0101 return threadInitNumber++;
0102 }
0103
0104 private static final int LOW_PRIORITY = 0;
0105 private static final int NORM_PRIORITY = 1;
0106 private static final int HIGH_PRIORITY = 2;
0107 private static final int ULTIMATE_PRIORITY = 3;
0108
0109 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
0110
0111 /*
0112 * We maintain one Queue for each priority that the EventQueue supports.
0113 * That is, the EventQueue object is actually implemented as
0114 * NUM_PRIORITIES queues and all Events on a particular internal Queue
0115 * have identical priority. Events are pulled off the EventQueue starting
0116 * with the Queue of highest priority. We progress in decreasing order
0117 * across all Queues.
0118 */
0119 private Queue[] queues = new Queue[NUM_PRIORITIES];
0120
0121 /*
0122 * The next EventQueue on the stack, or null if this EventQueue is
0123 * on the top of the stack. If nextQueue is non-null, requests to post
0124 * an event are forwarded to nextQueue.
0125 */
0126 private EventQueue nextQueue;
0127
0128 /*
0129 * The previous EventQueue on the stack, or null if this is the
0130 * "base" EventQueue.
0131 */
0132 private EventQueue previousQueue;
0133
0134 private EventDispatchThread dispatchThread;
0135
0136 private final ThreadGroup threadGroup = Thread.currentThread()
0137 .getThreadGroup();
0138 private final ClassLoader classLoader = Thread.currentThread()
0139 .getContextClassLoader();
0140
0141 /*
0142 * Debugging flag -- set true and recompile to enable checking.
0143 */
0144 private final static boolean debug = false;
0145
0146 /*
0147 * The time stamp of the last dispatched InputEvent or ActionEvent.
0148 */
0149 private long mostRecentEventTime = System.currentTimeMillis();
0150
0151 /**
0152 * The modifiers field of the current event, if the current event is an
0153 * InputEvent or ActionEvent.
0154 */
0155 private WeakReference currentEvent;
0156
0157 /*
0158 * Non-zero if a thread is waiting in getNextEvent(int) for an event of
0159 * a particular ID to be posted to the queue.
0160 */
0161 private int waitForID;
0162
0163 private final String name = "AWT-EventQueue-" + nextThreadNum();
0164
0165 public EventQueue() {
0166 for (int i = 0; i < NUM_PRIORITIES; i++) {
0167 queues[i] = new Queue();
0168 }
0169 /*
0170 * NOTE: if you ever have to start the associated event dispatch
0171 * thread at this point, be aware of the following problem:
0172 * If this EventQueue instance is created in
0173 * SunToolkit.createNewAppContext() the started dispatch thread
0174 * may call AppContext.getAppContext() before createNewAppContext()
0175 * completes thus causing mess in thread group to appcontext mapping.
0176 */
0177 }
0178
0179 /**
0180 * Posts a 1.1-style event to the <code>EventQueue</code>.
0181 * If there is an existing event on the queue with the same ID
0182 * and event source, the source <code>Component</code>'s
0183 * <code>coalesceEvents</code> method will be called.
0184 *
0185 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
0186 * or a subclass of it
0187 * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
0188 */
0189 public void postEvent(AWTEvent theEvent) {
0190 SunToolkit.flushPendingEvents();
0191 postEventPrivate(theEvent);
0192 }
0193
0194 /**
0195 * Posts a 1.1-style event to the <code>EventQueue</code>.
0196 * If there is an existing event on the queue with the same ID
0197 * and event source, the source <code>Component</code>'s
0198 * <code>coalesceEvents</code> method will be called.
0199 *
0200 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
0201 * or a subclass of it
0202 */
0203 final void postEventPrivate(AWTEvent theEvent) {
0204 theEvent.isPosted = true;
0205 synchronized (this ) {
0206 if (dispatchThread == null && nextQueue == null) {
0207 if (theEvent.getSource() == AWTAutoShutdown
0208 .getInstance()) {
0209 return;
0210 } else {
0211 initDispatchThread();
0212 }
0213 }
0214 if (nextQueue != null) {
0215 // Forward event to top of EventQueue stack.
0216 nextQueue.postEventPrivate(theEvent);
0217 return;
0218 }
0219 postEvent(theEvent, getPriority(theEvent));
0220 }
0221 }
0222
0223 private static int getPriority(AWTEvent theEvent) {
0224 if (theEvent instanceof PeerEvent
0225 && (((PeerEvent) theEvent).getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
0226 return ULTIMATE_PRIORITY;
0227 }
0228
0229 if (theEvent instanceof PeerEvent
0230 && (((PeerEvent) theEvent).getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
0231 return HIGH_PRIORITY;
0232 }
0233
0234 if (theEvent instanceof PeerEvent
0235 && (((PeerEvent) theEvent).getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
0236 return LOW_PRIORITY;
0237 }
0238
0239 int id = theEvent.getID();
0240 if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
0241 return LOW_PRIORITY;
0242 }
0243 return NORM_PRIORITY;
0244 }
0245
0246 /**
0247 * Posts the event to the internal Queue of specified priority,
0248 * coalescing as appropriate.
0249 *
0250 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
0251 * or a subclass of it
0252 * @param priority the desired priority of the event
0253 */
0254 private void postEvent(AWTEvent theEvent, int priority) {
0255 if (coalesceEvent(theEvent, priority)) {
0256 return;
0257 }
0258
0259 EventQueueItem newItem = new EventQueueItem(theEvent);
0260
0261 cacheEQItem(newItem);
0262
0263 boolean notifyID = (theEvent.getID() == this .waitForID);
0264
0265 if (queues[priority].head == null) {
0266 boolean shouldNotify = noEvents();
0267 queues[priority].head = queues[priority].tail = newItem;
0268
0269 if (shouldNotify) {
0270 if (theEvent.getSource() != AWTAutoShutdown
0271 .getInstance()) {
0272 AWTAutoShutdown.getInstance().notifyThreadBusy(
0273 dispatchThread);
0274 }
0275 notifyAll();
0276 } else if (notifyID) {
0277 notifyAll();
0278 }
0279 } else {
0280 // The event was not coalesced or has non-Component source.
0281 // Insert it at the end of the appropriate Queue.
0282 queues[priority].tail.next = newItem;
0283 queues[priority].tail = newItem;
0284 if (notifyID) {
0285 notifyAll();
0286 }
0287 }
0288 }
0289
0290 private boolean coalescePaintEvent(PaintEvent e) {
0291 ComponentPeer sourcePeer = ((Component) e.getSource()).peer;
0292 if (sourcePeer != null) {
0293 sourcePeer.coalescePaintEvent(e);
0294 }
0295 EventQueueItem[] cache = ((Component) e.getSource()).eventCache;
0296 if (cache == null) {
0297 return false;
0298 }
0299 int index = eventToCacheIndex(e);
0300
0301 if (index != -1 && cache[index] != null) {
0302 PaintEvent merged = mergePaintEvents(e,
0303 (PaintEvent) cache[index].event);
0304 if (merged != null) {
0305 cache[index].event = merged;
0306 return true;
0307 }
0308 }
0309 return false;
0310 }
0311
0312 private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
0313 Rectangle aRect = a.getUpdateRect();
0314 Rectangle bRect = b.getUpdateRect();
0315 if (bRect.contains(aRect)) {
0316 return b;
0317 }
0318 if (aRect.contains(bRect)) {
0319 return a;
0320 }
0321 return null;
0322 }
0323
0324 private boolean coalesceMouseEvent(MouseEvent e) {
0325 EventQueueItem[] cache = ((Component) e.getSource()).eventCache;
0326 if (cache == null) {
0327 return false;
0328 }
0329 int index = eventToCacheIndex(e);
0330 if (index != -1 && cache[index] != null) {
0331 cache[index].event = e;
0332 return true;
0333 }
0334 return false;
0335 }
0336
0337 private boolean coalescePeerEvent(PeerEvent e) {
0338 EventQueueItem[] cache = ((Component) e.getSource()).eventCache;
0339 if (cache == null) {
0340 return false;
0341 }
0342 int index = eventToCacheIndex(e);
0343 if (index != -1 && cache[index] != null) {
0344 e = e.coalesceEvents((PeerEvent) cache[index].event);
0345 if (e != null) {
0346 cache[index].event = e;
0347 return true;
0348 } else {
0349 cache[index] = null;
0350 }
0351 }
0352 return false;
0353 }
0354
0355 /*
0356 * Should avoid of calling this method by any means
0357 * as it's working time is dependant on EQ length.
0358 * In the wors case this method alone can slow down the entire application
0359 * 10 times by stalling the Event processing.
0360 * Only here by backward compatibility reasons.
0361 */
0362 private boolean coalesceOtherEvent(AWTEvent e, int priority) {
0363 int id = e.getID();
0364 Component source = (Component) e.getSource();
0365 for (EventQueueItem entry = queues[priority].head; entry != null; entry = entry.next) {
0366 // Give Component.coalesceEvents a chance
0367 if (entry.event.getSource() == source && entry.id == id) {
0368 AWTEvent coalescedEvent = source.coalesceEvents(
0369 entry.event, e);
0370 if (coalescedEvent != null) {
0371 entry.event = coalescedEvent;
0372 return true;
0373 }
0374 }
0375 }
0376 return false;
0377 }
0378
0379 private boolean coalesceEvent(AWTEvent e, int priority) {
0380 if (!(e.getSource() instanceof Component)) {
0381 return false;
0382 }
0383 if (e instanceof PeerEvent) {
0384 return coalescePeerEvent((PeerEvent) e);
0385 }
0386 // The worst case
0387 if (((Component) e.getSource()).isCoalescingEnabled()
0388 && coalesceOtherEvent(e, priority)) {
0389 return true;
0390 }
0391 if (e instanceof PaintEvent) {
0392 return coalescePaintEvent((PaintEvent) e);
0393 }
0394 if (e instanceof MouseEvent) {
0395 return coalesceMouseEvent((MouseEvent) e);
0396 }
0397 return false;
0398 }
0399
0400 private void cacheEQItem(EventQueueItem entry) {
0401 int index = eventToCacheIndex(entry.event);
0402 if (index != -1 && entry.event.getSource() instanceof Component) {
0403 Component source = (Component) entry.event.getSource();
0404 if (source.eventCache == null) {
0405 source.eventCache = new EventQueueItem[CACHE_LENGTH];
0406 }
0407 source.eventCache[index] = entry;
0408 }
0409 }
0410
0411 private void uncacheEQItem(EventQueueItem entry) {
0412 int index = eventToCacheIndex(entry.event);
0413 if (index != -1 && entry.event.getSource() instanceof Component) {
0414 Component source = (Component) entry.event.getSource();
0415 if (source.eventCache == null) {
0416 return;
0417 }
0418 source.eventCache[index] = null;
0419 }
0420 }
0421
0422 private static final int PAINT = 0;
0423 private static final int UPDATE = 1;
0424 private static final int MOVE = 2;
0425 private static final int DRAG = 3;
0426 private static final int PEER = 4;
0427 private static final int CACHE_LENGTH = 5;
0428
0429 private static int eventToCacheIndex(AWTEvent e) {
0430 switch (e.getID()) {
0431 case PaintEvent.PAINT:
0432 return PAINT;
0433 case PaintEvent.UPDATE:
0434 return UPDATE;
0435 case MouseEvent.MOUSE_MOVED:
0436 return MOVE;
0437 case MouseEvent.MOUSE_DRAGGED:
0438 return DRAG;
0439 default:
0440 return e instanceof PeerEvent ? PEER : -1;
0441 }
0442 }
0443
0444 /**
0445 * Returns whether an event is pending on any of the separate
0446 * Queues.
0447 * @return whether an event is pending on any of the separate Queues
0448 */
0449 private boolean noEvents() {
0450 for (int i = 0; i < NUM_PRIORITIES; i++) {
0451 if (queues[i].head != null) {
0452 return false;
0453 }
0454 }
0455
0456 return true;
0457 }
0458
0459 /**
0460 * Removes an event from the <code>EventQueue</code> and
0461 * returns it. This method will block until an event has
0462 * been posted by another thread.
0463 * @return the next <code>AWTEvent</code>
0464 * @exception InterruptedException
0465 * if any thread has interrupted this thread
0466 */
0467 public AWTEvent getNextEvent() throws InterruptedException {
0468 do {
0469 /*
0470 * SunToolkit.flushPendingEvents must be called outside
0471 * of the synchronized block to avoid deadlock when
0472 * event queues are nested with push()/pop().
0473 */
0474 SunToolkit.flushPendingEvents();
0475 synchronized (this ) {
0476 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
0477 if (queues[i].head != null) {
0478 EventQueueItem entry = queues[i].head;
0479 queues[i].head = entry.next;
0480 if (entry.next == null) {
0481 queues[i].tail = null;
0482 }
0483 uncacheEQItem(entry);
0484 return entry.event;
0485 }
0486 }
0487 AWTAutoShutdown.getInstance().notifyThreadFree(
0488 dispatchThread);
0489 wait();
0490 }
0491 } while (true);
0492 }
0493
0494 AWTEvent getNextEvent(int id) throws InterruptedException {
0495 do {
0496 /*
0497 * SunToolkit.flushPendingEvents must be called outside
0498 * of the synchronized block to avoid deadlock when
0499 * event queues are nested with push()/pop().
0500 */
0501 SunToolkit.flushPendingEvents();
0502 synchronized (this ) {
0503 for (int i = 0; i < NUM_PRIORITIES; i++) {
0504 for (EventQueueItem entry = queues[i].head, prev = null; entry != null; prev = entry, entry = entry.next) {
0505 if (entry.id == id) {
0506 if (prev == null) {
0507 queues[i].head = entry.next;
0508 } else {
0509 prev.next = entry.next;
0510 }
0511 if (queues[i].tail == entry) {
0512 queues[i].tail = prev;
0513 }
0514 uncacheEQItem(entry);
0515 return entry.event;
0516 }
0517 }
0518 }
0519 this .waitForID = id;
0520 wait();
0521 this .waitForID = 0;
0522 }
0523 } while (true);
0524 }
0525
0526 /**
0527 * Returns the first event on the <code>EventQueue</code>
0528 * without removing it.
0529 * @return the first event
0530 */
0531 public synchronized AWTEvent peekEvent() {
0532 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
0533 if (queues[i].head != null) {
0534 return queues[i].head.event;
0535 }
0536 }
0537
0538 return null;
0539 }
0540
0541 /**
0542 * Returns the first event with the specified id, if any.
0543 * @param id the id of the type of event desired
0544 * @return the first event of the specified id or <code>null</code>
0545 * if there is no such event
0546 */
0547 public synchronized AWTEvent peekEvent(int id) {
0548 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
0549 EventQueueItem q = queues[i].head;
0550 for (; q != null; q = q.next) {
0551 if (q.id == id) {
0552 return q.event;
0553 }
0554 }
0555 }
0556
0557 return null;
0558 }
0559
0560 /**
0561 * Dispatches an event. The manner in which the event is
0562 * dispatched depends upon the type of the event and the
0563 * type of the event's source object:
0564 * <p> </p>
0565 * <table border=1 summary="Event types, source types, and dispatch methods">
0566 * <tr>
0567 * <th>Event Type</th>
0568 * <th>Source Type</th>
0569 * <th>Dispatched To</th>
0570 * </tr>
0571 * <tr>
0572 * <td>ActiveEvent</td>
0573 * <td>Any</td>
0574 * <td>event.dispatch()</td>
0575 * </tr>
0576 * <tr>
0577 * <td>Other</td>
0578 * <td>Component</td>
0579 * <td>source.dispatchEvent(AWTEvent)</td>
0580 * </tr>
0581 * <tr>
0582 * <td>Other</td>
0583 * <td>MenuComponent</td>
0584 * <td>source.dispatchEvent(AWTEvent)</td>
0585 * </tr>
0586 * <tr>
0587 * <td>Other</td>
0588 * <td>Other</td>
0589 * <td>No action (ignored)</td>
0590 * </tr>
0591 * </table>
0592 * <p> </p>
0593 * @param event an instance of <code>java.awt.AWTEvent</code>,
0594 * or a subclass of it
0595 * @throws NullPointerException if <code>event</code> is <code>null</code>
0596 * @since 1.2
0597 */
0598 protected void dispatchEvent(AWTEvent event) {
0599 event.isPosted = true;
0600 Object src = event.getSource();
0601 if (event instanceof ActiveEvent) {
0602 // This could become the sole method of dispatching in time.
0603 setCurrentEventAndMostRecentTimeImpl(event);
0604
0605 ((ActiveEvent) event).dispatch();
0606 } else if (src instanceof Component) {
0607 ((Component) src).dispatchEvent(event);
0608 event.dispatched();
0609 } else if (src instanceof MenuComponent) {
0610 ((MenuComponent) src).dispatchEvent(event);
0611 } else if (src instanceof TrayIcon) {
0612 ((TrayIcon) src).dispatchEvent(event);
0613 } else if (src instanceof AWTAutoShutdown) {
0614 if (noEvents()) {
0615 dispatchThread.stopDispatching();
0616 }
0617 } else {
0618 System.err.println("unable to dispatch event: " + event);
0619 }
0620 }
0621
0622 /**
0623 * Returns the timestamp of the most recent event that had a timestamp, and
0624 * that was dispatched from the <code>EventQueue</code> associated with the
0625 * calling thread. If an event with a timestamp is currently being
0626 * dispatched, its timestamp will be returned. If no events have yet
0627 * been dispatched, the EventQueue's initialization time will be
0628 * returned instead.In the current version of
0629 * the JDK, only <code>InputEvent</code>s,
0630 * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
0631 * timestamps; however, future versions of the JDK may add timestamps to
0632 * additional event types. Note that this method should only be invoked
0633 * from an application's event dispatching thread. If this method is
0634 * invoked from another thread, the current system time (as reported by
0635 * <code>System.currentTimeMillis()</code>) will be returned instead.
0636 *
0637 * @return the timestamp of the last <code>InputEvent</code>,
0638 * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
0639 * dispatched, or <code>System.currentTimeMillis()</code> if this
0640 * method is invoked on a thread other than an event dispatching
0641 * thread
0642 * @see java.awt.event.InputEvent#getWhen
0643 * @see java.awt.event.ActionEvent#getWhen
0644 * @see java.awt.event.InvocationEvent#getWhen
0645 *
0646 * @since 1.4
0647 */
0648 public static long getMostRecentEventTime() {
0649 return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
0650 }
0651
0652 private synchronized long getMostRecentEventTimeImpl() {
0653 return (Thread.currentThread() == dispatchThread) ? mostRecentEventTime
0654 : System.currentTimeMillis();
0655 }
0656
0657 /**
0658 * @return most recent event time on all threads.
0659 */
0660 synchronized long getMostRecentEventTimeEx() {
0661 return mostRecentEventTime;
0662 }
0663
0664 /**
0665 * Returns the the event currently being dispatched by the
0666 * <code>EventQueue</code> associated with the calling thread. This is
0667 * useful if a method needs access to the event, but was not designed to
0668 * receive a reference to it as an argument. Note that this method should
0669 * only be invoked from an application's event dispatching thread. If this
0670 * method is invoked from another thread, null will be returned.
0671 *
0672 * @return the event currently being dispatched, or null if this method is
0673 * invoked on a thread other than an event dispatching thread
0674 * @since 1.4
0675 */
0676 public static AWTEvent getCurrentEvent() {
0677 return Toolkit.getEventQueue().getCurrentEventImpl();
0678 }
0679
0680 private synchronized AWTEvent getCurrentEventImpl() {
0681 return (Thread.currentThread() == dispatchThread) ? ((AWTEvent) currentEvent
0682 .get())
0683 : null;
0684 }
0685
0686 /**
0687 * Replaces the existing <code>EventQueue</code> with the specified one.
0688 * Any pending events are transferred to the new <code>EventQueue</code>
0689 * for processing by it.
0690 *
0691 * @param newEventQueue an <code>EventQueue</code>
0692 * (or subclass thereof) instance to be use
0693 * @see java.awt.EventQueue#pop
0694 * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
0695 * @since 1.2
0696 */
0697 public synchronized void push(EventQueue newEventQueue) {
0698 if (debug) {
0699 System.out
0700 .println("EventQueue.push(" + newEventQueue + ")");
0701 }
0702
0703 if (nextQueue != null) {
0704 nextQueue.push(newEventQueue);
0705 return;
0706 }
0707
0708 synchronized (newEventQueue) {
0709 // Transfer all events forward to new EventQueue.
0710 while (peekEvent() != null) {
0711 try {
0712 newEventQueue.postEventPrivate(getNextEvent());
0713 } catch (InterruptedException ie) {
0714 if (debug) {
0715 System.err.println("interrupted push:");
0716 ie.printStackTrace(System.err);
0717 }
0718 }
0719 }
0720
0721 newEventQueue.previousQueue = this ;
0722 }
0723 /*
0724 * Stop the event dispatch thread associated with the currently
0725 * active event queue, so that after the new queue is pushed
0726 * on the top this event dispatch thread won't prevent AWT from
0727 * being automatically shut down.
0728 * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
0729 * waits for the dispatch thread to exit, so if the dispatch
0730 * thread attempts to synchronize on this EventQueue object
0731 * it will never exit since we already hold this lock.
0732 */
0733 if (dispatchThread != null) {
0734 dispatchThread.stopDispatchingLater();
0735 }
0736
0737 nextQueue = newEventQueue;
0738
0739 AppContext appContext = AppContext.getAppContext();
0740 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this ) {
0741 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
0742 }
0743 }
0744
0745 /**
0746 * Stops dispatching events using this <code>EventQueue</code>.
0747 * Any pending events are transferred to the previous
0748 * <code>EventQueue</code> for processing.
0749 * <p>
0750 * Warning: To avoid deadlock, do not declare this method
0751 * synchronized in a subclass.
0752 *
0753 * @exception EmptyStackException if no previous push was made
0754 * on this <code>EventQueue</code>
0755 * @see java.awt.EventQueue#push
0756 * @since 1.2
0757 */
0758 protected void pop() throws EmptyStackException {
0759 if (debug) {
0760 System.out.println("EventQueue.pop(" + this + ")");
0761 }
0762
0763 // To prevent deadlock, we lock on the previous EventQueue before
0764 // this one. This uses the same locking order as everything else
0765 // in EventQueue.java, so deadlock isn't possible.
0766 EventQueue prev = previousQueue;
0767 synchronized ((prev != null) ? prev : this ) {
0768 synchronized (this ) {
0769 if (nextQueue != null) {
0770 nextQueue.pop();
0771 return;
0772 }
0773 if (previousQueue == null) {
0774 throw new EmptyStackException();
0775 }
0776
0777 // Transfer all events back to previous EventQueue.
0778 previousQueue.nextQueue = null;
0779 while (peekEvent() != null) {
0780 try {
0781 previousQueue.postEventPrivate(getNextEvent());
0782 } catch (InterruptedException ie) {
0783 if (debug) {
0784 System.err.println("interrupted pop:");
0785 ie.printStackTrace(System.err);
0786 }
0787 }
0788 }
0789 AppContext appContext = AppContext.getAppContext();
0790 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this ) {
0791 appContext.put(AppContext.EVENT_QUEUE_KEY,
0792 previousQueue);
0793 }
0794
0795 previousQueue = null;
0796 }
0797 }
0798
0799 EventDispatchThread dt = this .dispatchThread;
0800 if (dt != null) {
0801 dt.stopDispatching(); // Must be done outside synchronized
0802 // block to avoid possible deadlock
0803 }
0804 }
0805
0806 /**
0807 * Returns true if the calling thread is the current AWT
0808 * <code>EventQueue</code>'s dispatch thread. Use this
0809 * call the ensure that a given
0810 * task is being executed (or not being) on the current AWT
0811 * <code>EventDispatchThread</code>.
0812 *
0813 * @return true if running on the current AWT
0814 * <code>EventQueue</code>'s dispatch thread
0815 * @since 1.2
0816 */
0817 public static boolean isDispatchThread() {
0818 EventQueue eq = Toolkit.getEventQueue();
0819 EventQueue next = eq.nextQueue;
0820 while (next != null) {
0821 eq = next;
0822 next = eq.nextQueue;
0823 }
0824 return (Thread.currentThread() == eq.dispatchThread);
0825 }
0826
0827 final void initDispatchThread() {
0828 synchronized (this ) {
0829 if (dispatchThread == null && !threadGroup.isDestroyed()) {
0830 dispatchThread = (EventDispatchThread) AccessController
0831 .doPrivileged(new PrivilegedAction() {
0832 public Object run() {
0833 EventDispatchThread t = new EventDispatchThread(
0834 threadGroup, name,
0835 EventQueue.this );
0836 t.setContextClassLoader(classLoader);
0837 t.setPriority(Thread.NORM_PRIORITY + 1);
0838 t.setDaemon(false);
0839 return t;
0840 }
0841 });
0842 AWTAutoShutdown.getInstance().notifyThreadBusy(
0843 dispatchThread);
0844 dispatchThread.start();
0845 }
0846 }
0847 }
0848
0849 final void detachDispatchThread() {
0850 dispatchThread = null;
0851 }
0852
0853 /*
0854 * Gets the <code>EventDispatchThread</code> for this
0855 * <code>EventQueue</code>.
0856 * @return the event dispatch thread associated with this event queue
0857 * or <code>null</code> if this event queue doesn't have a
0858 * working thread associated with it
0859 * @see java.awt.EventQueue#initDispatchThread
0860 * @see java.awt.EventQueue#detachDispatchThread
0861 */
0862 final EventDispatchThread getDispatchThread() {
0863 return dispatchThread;
0864 }
0865
0866 /*
0867 * Removes any pending events for the specified source object.
0868 * If removeAllEvents parameter is <code>true</code> then all
0869 * events for the specified source object are removed, if it
0870 * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
0871 * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
0872 * and <code>InputMethodEvent</code> are kept in the queue, but all other
0873 * events are removed.
0874 *
0875 * This method is normally called by the source's
0876 * <code>removeNotify</code> method.
0877 */
0878 final void removeSourceEvents(Object source, boolean removeAllEvents) {
0879 SunToolkit.flushPendingEvents();
0880 synchronized (this ) {
0881 for (int i = 0; i < NUM_PRIORITIES; i++) {
0882 EventQueueItem entry = queues[i].head;
0883 EventQueueItem prev = null;
0884 while (entry != null) {
0885 if ((entry.event.getSource() == source)
0886 && (removeAllEvents || !(entry.event instanceof SequencedEvent
0887 || entry.event instanceof SentEvent
0888 || entry.event instanceof FocusEvent
0889 || entry.event instanceof WindowEvent
0890 || entry.event instanceof KeyEvent || entry.event instanceof InputMethodEvent))) {
0891 if (entry.event instanceof SequencedEvent) {
0892 ((SequencedEvent) entry.event).dispose();
0893 }
0894 if (entry.event instanceof SentEvent) {
0895 ((SentEvent) entry.event).dispose();
0896 }
0897 if (prev == null) {
0898 queues[i].head = entry.next;
0899 } else {
0900 prev.next = entry.next;
0901 }
0902 uncacheEQItem(entry);
0903 } else {
0904 prev = entry;
0905 }
0906 entry = entry.next;
0907 }
0908 queues[i].tail = prev;
0909 }
0910 }
0911 }
0912
0913 static void setCurrentEventAndMostRecentTime(AWTEvent e) {
0914 Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
0915 }
0916
0917 private synchronized void setCurrentEventAndMostRecentTimeImpl(
0918 AWTEvent e) {
0919 if (Thread.currentThread() != dispatchThread) {
0920 return;
0921 }
0922
0923 currentEvent = new WeakReference(e);
0924
0925 // This series of 'instanceof' checks should be replaced with a
0926 // polymorphic type (for example, an interface which declares a
0927 // getWhen() method). However, this would require us to make such
0928 // a type public, or to place it in sun.awt. Both of these approaches
0929 // have been frowned upon. So for now, we hack.
0930 //
0931 // In tiger, we will probably give timestamps to all events, so this
0932 // will no longer be an issue.
0933 long mostRecentEventTime2 = Long.MIN_VALUE;
0934 if (e instanceof InputEvent) {
0935 InputEvent ie = (InputEvent) e;
0936 mostRecentEventTime2 = ie.getWhen();
0937 } else if (e instanceof InputMethodEvent) {
0938 InputMethodEvent ime = (InputMethodEvent) e;
0939 mostRecentEventTime2 = ime.getWhen();
0940 } else if (e instanceof ActionEvent) {
0941 ActionEvent ae = (ActionEvent) e;
0942 mostRecentEventTime2 = ae.getWhen();
0943 } else if (e instanceof InvocationEvent) {
0944 InvocationEvent ie = (InvocationEvent) e;
0945 mostRecentEventTime2 = ie.getWhen();
0946 }
0947 mostRecentEventTime = Math.max(mostRecentEventTime,
0948 mostRecentEventTime2);
0949 }
0950
0951 /**
0952 * Causes <code>runnable</code> to have its <code>run</code>
0953 * method called in the dispatch thread of
0954 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
0955 * This will happen after all pending events are processed.
0956 *
0957 * @param runnable the <code>Runnable</code> whose <code>run</code>
0958 * method should be executed
0959 * synchronously on the <code>EventQueue</code>
0960 * @see #invokeAndWait
0961 * @since 1.2
0962 */
0963 public static void invokeLater(Runnable runnable) {
0964 Toolkit.getEventQueue().postEvent(
0965 new InvocationEvent(Toolkit.getDefaultToolkit(),
0966 runnable));
0967 }
0968
0969 /**
0970 * Causes <code>runnable</code> to have its <code>run</code>
0971 * method called in the dispatch thread of
0972 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
0973 * This will happen after all pending events are processed.
0974 * The call blocks until this has happened. This method
0975 * will throw an Error if called from the event dispatcher thread.
0976 *
0977 * @param runnable the <code>Runnable</code> whose <code>run</code>
0978 * method should be executed
0979 * synchronously on the <code>EventQueue</code>
0980 * @exception InterruptedException if any thread has
0981 * interrupted this thread
0982 * @exception InvocationTargetException if an throwable is thrown
0983 * when running <code>runnable</code>
0984 * @see #invokeLater
0985 * @since 1.2
0986 */
0987 public static void invokeAndWait(Runnable runnable)
0988 throws InterruptedException, InvocationTargetException {
0989
0990 if (EventQueue.isDispatchThread()) {
0991 throw new Error(
0992 "Cannot call invokeAndWait from the event dispatcher thread");
0993 }
0994
0995 class AWTInvocationLock {
0996 }
0997 Object lock = new AWTInvocationLock();
0998
0999 InvocationEvent event = new InvocationEvent(Toolkit
1000 .getDefaultToolkit(), runnable, lock, true);
1001
1002 synchronized (lock) {
1003 Toolkit.getEventQueue().postEvent(event);
1004 lock.wait();
1005 }
1006
1007 Throwable eventThrowable = event.getThrowable();
1008 if (eventThrowable != null) {
1009 throw new InvocationTargetException(eventThrowable);
1010 }
1011 }
1012
1013 /*
1014 * Called from PostEventQueue.postEvent to notify that a new event
1015 * appeared. First it proceeds to the EventQueue on the top of the
1016 * stack, then notifies the associated dispatch thread if it exists
1017 * or starts a new one otherwise.
1018 */
1019 private void wakeup(boolean isShutdown) {
1020 synchronized (this ) {
1021 if (nextQueue != null) {
1022 // Forward call to the top of EventQueue stack.
1023 nextQueue.wakeup(isShutdown);
1024 } else if (dispatchThread != null) {
1025 notifyAll();
1026 } else if (!isShutdown) {
1027 initDispatchThread();
1028 }
1029 }
1030 }
1031 }
1032
1033 /**
1034 * The Queue object holds pointers to the beginning and end of one internal
1035 * queue. An EventQueue object is composed of multiple internal Queues, one
1036 * for each priority supported by the EventQueue. All Events on a particular
1037 * internal Queue have identical priority.
1038 */
1039 class Queue {
1040 EventQueueItem head;
1041 EventQueueItem tail;
1042 }
1043
1044 class EventQueueItem {
1045 AWTEvent event;
1046 int id;
1047 EventQueueItem next;
1048
1049 EventQueueItem(AWTEvent evt) {
1050 event = evt;
1051 id = evt.getID();
1052 }
1053 }
|