2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import gnu.java.awt.ClasspathToolkit;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.InputEvent;
45 import java.awt.event.InvocationEvent;
46 import java.awt.event.WindowEvent;
47 import java.lang.reflect.InvocationTargetException;
48 import java.util.EmptyStackException;
50 /* Written using on-line Java 2 Platform Standard Edition v1.3 API
51 * Specification, as well as "The Java Class Libraries", 2nd edition
52 * (Addison-Wesley, 1998).
53 * Status: Believed complete, but untested.
57 * This class manages a queue of <code>AWTEvent</code> objects that
58 * are posted to it. The AWT system uses only one event queue for all
61 * @author Bryce McKinlay
62 * @author Aaron M. Renn (arenn@urbanophile.com)
64 public class EventQueue
66 private static final int INITIAL_QUEUE_DEPTH = 8;
67 private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
69 private int next_in = 0; // Index where next event will be added to queue
70 private int next_out = 0; // Index of next event to be removed from queue
72 private EventQueue next;
73 private EventQueue prev;
74 private AWTEvent currentEvent;
75 private long lastWhen = System.currentTimeMillis();
77 private EventDispatchThread dispatchThread = new EventDispatchThread(this);
78 private boolean shutdown = false;
80 private long lastNativeQueueAccess = 0;
81 private long humanLatencyThreshold = 100;
83 synchronized void setShutdown (boolean b)
88 synchronized boolean isShutdown ()
93 // This is the exact self-shutdown condition specified in J2SE:
94 // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
96 if (peekEvent() == null
97 && ((ClasspathToolkit) Toolkit.getDefaultToolkit()).nativeQueueEmpty())
99 Frame[] frames = Frame.getFrames();
100 for (int i = 0; i < frames.length; ++i)
101 if (frames[i].isDisplayable())
109 * Initializes a new instance of <code>EventQueue</code>.
116 * Returns the next event in the queue. This method will block until
117 * an event is available or until the thread is interrupted.
119 * @return The next event in the queue.
121 * @exception InterruptedException If this thread is interrupted while
122 * waiting for an event to be posted to the queue.
124 public synchronized AWTEvent getNextEvent()
125 throws InterruptedException
128 return next.getNextEvent();
130 ClasspathToolkit tk = ((ClasspathToolkit) Toolkit.getDefaultToolkit());
131 long curr = System.currentTimeMillis();
133 if (! tk.nativeQueueEmpty() &&
134 (curr - lastNativeQueueAccess > humanLatencyThreshold))
136 tk.iterateNativeQueue(this, false);
137 lastNativeQueueAccess = curr;
140 while (next_in == next_out)
142 // Only the EventDispatchThread associated with the top of the stack is
143 // allowed to get events from the native source; everyone else just
144 // waits on the head of the queue.
146 if (isDispatchThread())
148 // We are not allowed to return null from this method, yet it
149 // is possible that we actually have run out of native events
150 // in the enclosing while() loop, and none of the native events
151 // happened to cause AWT events. We therefore ought to check
152 // the isShutdown() condition here, before risking a "native
153 // wait". If we check it before entering this function we may
154 // wait forever for events after the shutdown condition has
158 throw new InterruptedException();
160 tk.iterateNativeQueue(this, true);
161 lastNativeQueueAccess = System.currentTimeMillis();
169 catch (InterruptedException ie)
175 AWTEvent res = queue[next_out];
177 if (++next_out == queue.length)
183 * Returns the next event in the queue without removing it from the queue.
184 * This method will block until an event is available or until the thread
187 * @return The next event in the queue.
188 * @specnote Does not block. Returns null if there are no events on the
191 public synchronized AWTEvent peekEvent()
194 return next.peekEvent();
196 if (next_in != next_out)
197 return queue[next_out];
203 * Returns the next event in the queue that has the specified id
204 * without removing it from the queue.
205 * This method will block until an event is available or until the thread
208 * @param id The event id to return.
210 * @return The next event in the queue.
212 * @specnote Does not block. Returns null if there are no matching events
215 public synchronized AWTEvent peekEvent(int id)
218 return next.peekEvent(id);
223 AWTEvent qevt = queue[i];
231 * Posts a new event to the queue.
233 * @param evt The event to post to the queue.
235 * @exception NullPointerException If event is null.
237 public synchronized void postEvent(AWTEvent evt)
240 throw new NullPointerException();
248 /* Check for any events already on the queue with the same source
253 AWTEvent qevt = queue[i];
255 if (qevt.id == evt.id
256 && (src = qevt.getSource()) == evt.getSource()
257 && src instanceof Component)
259 /* If there are, call coalesceEvents on the source component
260 to see if they can be combined. */
261 Component srccmp = (Component) src;
262 AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
263 if (coalesced_evt != null)
265 /* Yes. Replace the existing event with the combined event. */
266 queue[i] = coalesced_evt;
271 if (++i == queue.length)
275 queue[next_in] = evt;
276 if (++next_in == queue.length)
279 if (next_in == next_out)
281 /* Queue is full. Extend it. */
282 AWTEvent[] oldQueue = queue;
283 queue = new AWTEvent[queue.length * 2];
285 int len = oldQueue.length - next_out;
286 System.arraycopy(oldQueue, next_out, queue, 0, len);
288 System.arraycopy(oldQueue, 0, queue, len, next_out);
291 next_in = oldQueue.length;
294 if (dispatchThread == null || !dispatchThread.isAlive())
296 dispatchThread = new EventDispatchThread(this);
297 dispatchThread.start();
300 // Window events might represent the closing of a window, which
301 // might cause the end of the dispatch thread's life, so we'll wake
302 // it up here to give it a chance to check for shutdown.
304 if (!isDispatchThread()
305 || (evt.getID() == WindowEvent.WINDOW_CLOSED)
306 || (evt.getID() == WindowEvent.WINDOW_CLOSING))
307 ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue();
313 * Causes runnable to have its run method called in the dispatch thread of the
314 * EventQueue. This will happen after all pending events are processed. The
315 * call blocks until this has happened. This method will throw an Error if
316 * called from the event dispatcher thread.
318 * @exception InterruptedException If another thread has interrupted
320 * @exception InvocationTargetException If an exception is thrown when running
325 public static void invokeAndWait(Runnable runnable)
326 throws InterruptedException, InvocationTargetException
328 if (isDispatchThread ())
329 throw new Error("Can't call invokeAndWait from event dispatch thread");
331 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
332 Thread current = Thread.currentThread();
335 new InvocationEvent(eq, runnable, current, true);
337 synchronized (current)
345 if ((exception = ie.getException()) != null)
346 throw new InvocationTargetException(exception);
350 * This arranges for runnable to have its run method called in the
351 * dispatch thread of the EventQueue. This will happen after all
352 * pending events are processed.
356 public static void invokeLater(Runnable runnable)
358 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
361 new InvocationEvent(eq, runnable, null, false);
367 * Return true if the current thread is the current AWT event dispatch
370 public static boolean isDispatchThread()
372 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
374 /* Find last EventQueue in chain */
375 while (eq.next != null)
378 return (Thread.currentThread() == eq.dispatchThread);
382 * Return the event currently being dispatched by the event
383 * dispatch thread. If the current thread is not the event
384 * dispatch thread, this method returns null.
388 public static AWTEvent getCurrentEvent()
390 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
391 Thread ct = Thread.currentThread();
393 /* Find out if this thread is the dispatch thread for any of the
394 EventQueues in the chain */
395 while (ct != eq.dispatchThread)
397 // Try next EventQueue, if any
399 return null; // Not an event dispatch thread
403 return eq.currentEvent;
407 * Allows a custom EventQueue implementation to replace this one.
408 * All pending events are transferred to the new queue. Calls to postEvent,
409 * getNextEvent, and peekEvent and others are forwarded to the pushed queue
410 * until it is removed with a pop().
412 * @exception NullPointerException if newEventQueue is null.
414 public synchronized void push(EventQueue newEventQueue)
416 if (newEventQueue == null)
417 throw new NullPointerException ();
419 /* Make sure we are at the top of the stack because callers can
420 only get a reference to the one at the bottom using
421 Toolkit.getDefaultToolkit().getSystemEventQueue() */
424 next.push (newEventQueue);
428 /* Make sure we have a live dispatch thread to drive the queue */
429 if (dispatchThread == null)
430 dispatchThread = new EventDispatchThread(this);
435 newEventQueue.postEvent(queue[i]);
437 if (++i == queue.length)
441 next = newEventQueue;
442 newEventQueue.prev = this;
445 /** Transfer any pending events from this queue back to the parent queue that
446 * was previously push()ed. Event dispatch from this queue is suspended.
448 * @exception EmptyStackException If no previous push was made on this
451 protected void pop() throws EmptyStackException
454 throw new EmptyStackException();
456 /* The order is important here, we must get the prev lock first,
457 or deadlock could occur as callers usually get here following
458 prev's next pointer, and thus obtain prev's lock before trying
471 prev.postEvent(queue[i]);
473 if (++i == queue.length)
476 // Empty the queue so it can be reused
480 ((ClasspathToolkit) Toolkit.getDefaultToolkit()).wakeNativeQueue();
482 dispatchThread = null;
489 * Dispatches an event. The manner in which the event is dispatched depends
490 * upon the type of the event and the type of the event's source object.
492 * @exception NullPointerException If event is null.
494 protected void dispatchEvent(AWTEvent evt)
498 if (evt instanceof InputEvent)
499 lastWhen = ((InputEvent) evt).getWhen();
500 else if (evt instanceof ActionEvent)
501 lastWhen = ((ActionEvent) evt).getWhen();
502 else if (evt instanceof InvocationEvent)
503 lastWhen = ((InvocationEvent) evt).getWhen();
505 if (evt instanceof ActiveEvent)
507 ActiveEvent active_evt = (ActiveEvent) evt;
508 active_evt.dispatch();
512 Object source = evt.getSource();
514 if (source instanceof Component)
516 Component srccmp = (Component) source;
517 srccmp.dispatchEvent(evt);
519 else if (source instanceof MenuComponent)
521 MenuComponent srccmp = (MenuComponent) source;
522 srccmp.dispatchEvent(evt);
528 * Returns the timestamp of the most recent event that had a timestamp, or
529 * the initialization time of the event queue if no events have been fired.
530 * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
531 * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
532 * timestamps, but this may be added to other events in future versions.
533 * If this is called by the event dispatching thread, it can be any
534 * (sequential) value, but to other threads, the safest bet is to return
535 * System.currentTimeMillis().
537 * @return the most recent timestamp
538 * @see InputEvent#getWhen()
539 * @see ActionEvent#getWhen()
540 * @see InvocationEvent#getWhen()
541 * @see InputMethodEvent#getWhen()
544 public static long getMostRecentEventTime()
546 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
547 if (Thread.currentThread() != eq.dispatchThread)
548 return System.currentTimeMillis();