1 /* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation
3 This file is part of GNU Classpath.
5 GNU Classpath is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 GNU Classpath is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU Classpath; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 Linking this library statically or dynamically with other modules is
21 making a combined work based on this library. Thus, the terms and
22 conditions of the GNU General Public License cover the whole
25 As a special exception, the copyright holders of this library give you
26 permission to link this library with independent modules to produce an
27 executable, regardless of the license terms of these independent
28 modules, and to copy and distribute the resulting executable under
29 terms of your choice, provided that you also meet, for each linked
30 independent module, the terms and conditions of the license of that
31 module. An independent module is a module which is not derived from
32 or based on this library. If you modify this library, you may extend
33 this exception to your version of the library, but you are not
34 obligated to do so. If you do not wish to do so, delete this
35 exception statement from your version. */
40 import java.awt.event.ActionEvent;
41 import java.awt.event.InputEvent;
42 import java.awt.event.InvocationEvent;
43 import java.lang.reflect.InvocationTargetException;
44 import java.util.EmptyStackException;
46 /* Written using on-line Java 2 Platform Standard Edition v1.3 API
47 * Specification, as well as "The Java Class Libraries", 2nd edition
48 * (Addison-Wesley, 1998).
49 * Status: Believed complete, but untested.
53 * This class manages a queue of <code>AWTEvent</code> objects that
54 * are posted to it. The AWT system uses only one event queue for all
57 * @author Bryce McKinlay
58 * @author Aaron M. Renn (arenn@urbanophile.com)
60 public class EventQueue
62 private static final int INITIAL_QUEUE_DEPTH = 8;
63 private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
65 private int next_in = 0; // Index where next event will be added to queue
66 private int next_out = 0; // Index of next event to be removed from queue
68 private EventQueue next;
69 private EventQueue prev;
70 private AWTEvent currentEvent;
71 private long lastWhen = System.currentTimeMillis();
73 private EventDispatchThread dispatchThread = new EventDispatchThread(this);
76 * Initializes a new instance of <code>EventQueue</code>.
83 * Returns the next event in the queue. This method will block until
84 * an event is available or until the thread is interrupted.
86 * @return The next event in the queue.
88 * @exception InterruptedException If this thread is interrupted while
89 * waiting for an event to be posted to the queue.
91 public synchronized AWTEvent getNextEvent()
92 throws InterruptedException
95 return next.getNextEvent();
97 while (next_in == next_out)
100 AWTEvent res = queue[next_out];
102 if (++next_out == queue.length)
108 * Returns the next event in the queue without removing it from the queue.
109 * This method will block until an event is available or until the thread
112 * @return The next event in the queue.
113 * @specnote Does not block. Returns null if there are no events on the
116 public synchronized AWTEvent peekEvent()
119 return next.peekEvent();
121 if (next_in != next_out)
122 return queue[next_out];
128 * Returns the next event in the queue that has the specified id
129 * without removing it from the queue.
130 * This method will block until an event is available or until the thread
133 * @param id The event id to return.
135 * @return The next event in the queue.
137 * @specnote Does not block. Returns null if there are no matching events
140 public synchronized AWTEvent peekEvent(int id)
143 return next.peekEvent(id);
148 AWTEvent qevt = queue[i];
156 * Posts a new event to the queue.
158 * @param event The event to post to the queue.
160 * @exception NullPointerException If event is null.
162 public synchronized void postEvent(AWTEvent evt)
170 /* Check for any events already on the queue with the same source
175 AWTEvent qevt = queue[i];
177 if (qevt.id == evt.id
178 && (src = qevt.getSource()) == evt.getSource()
179 && src instanceof Component)
181 /* If there are, call coalesceEvents on the source component
182 to see if they can be combined. */
183 Component srccmp = (Component) src;
184 AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
185 if (coalesced_evt != null)
187 /* Yes. Replace the existing event with the combined event. */
188 queue[i] = coalesced_evt;
193 if (++i == queue.length)
197 queue[next_in] = evt;
198 if (++next_in == queue.length)
201 if (next_in == next_out)
203 /* Queue is full. Extend it. */
204 AWTEvent[] oldQueue = queue;
205 queue = new AWTEvent[queue.length * 2];
207 int len = oldQueue.length - next_out;
208 System.arraycopy(oldQueue, next_out, queue, 0, len);
210 System.arraycopy(oldQueue, 0, queue, len, next_out);
213 next_in = oldQueue.length;
219 * Causes runnable to have its run method called in the dispatch thread of the
220 * EventQueue. This will happen after all pending events are processed. The
221 * call blocks until this has happened. This method will throw an Error if
222 * called from the event dispatcher thread.
224 * @exception InterruptedException If another thread has interrupted
226 * @exception InvocationTargetException If an exception is thrown when running
231 public static void invokeAndWait(Runnable runnable)
232 throws InterruptedException, InvocationTargetException
234 if (isDispatchThread ())
235 throw new Error("Can't call invokeAndWait from event dispatch thread");
237 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
238 Thread current = Thread.currentThread();
241 new InvocationEvent(eq, runnable, current, true);
243 synchronized (current)
251 if ((exception = ie.getException()) != null)
252 throw new InvocationTargetException(exception);
256 * This arranges for runnable to have its run method called in the
257 * dispatch thread of the EventQueue. This will happen after all
258 * pending events are processed.
262 public static void invokeLater(Runnable runnable)
264 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
267 new InvocationEvent(eq, runnable, null, false);
273 * Return true if the current thread is the current AWT event dispatch
276 public static boolean isDispatchThread()
278 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
280 /* Find last EventQueue in chain */
281 while (eq.next != null)
284 return (Thread.currentThread() == eq.dispatchThread);
288 * Return the event currently being dispatched by the event
289 * dispatch thread. If the current thread is not the event
290 * dispatch thread, this method returns null.
294 public static AWTEvent getCurrentEvent()
296 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
297 Thread ct = Thread.currentThread();
299 /* Find out if this thread is the dispatch thread for any of the
300 EventQueues in the chain */
301 while (ct != eq.dispatchThread)
303 // Try next EventQueue, if any
305 return null; // Not an event dispatch thread
309 return eq.currentEvent;
313 * Allows a custom EventQueue implementation to replace this one.
314 * All pending events are transferred to the new queue. Calls to postEvent,
315 * getNextEvent, and peekEvent and others are forwarded to the pushed queue
316 * until it is removed with a pop().
318 * @exception NullPointerException if newEventQueue is null.
320 public synchronized void push(EventQueue newEventQueue)
322 if (newEventQueue == null)
323 throw new NullPointerException ();
325 /* Make sure we are at the top of the stack because callers can
326 only get a reference to the one at the bottom using
327 Toolkit.getDefaultToolkit().getSystemEventQueue() */
330 next.push (newEventQueue);
334 /* Make sure we have a live dispatch thread to drive the queue */
335 if (dispatchThread == null)
336 dispatchThread = new EventDispatchThread(this);
341 newEventQueue.postEvent(queue[i]);
343 if (++i == queue.length)
347 next = newEventQueue;
348 newEventQueue.prev = this;
351 /** Transfer any pending events from this queue back to the parent queue that
352 * was previously push()ed. Event dispatch from this queue is suspended.
354 * @exception EmptyStackException If no previous push was made on this
357 protected void pop() throws EmptyStackException
360 throw new EmptyStackException();
362 /* The order is important here, we must get the prev lock first,
363 or deadlock could occur as callers usually get here following
364 prev's next pointer, and thus obtain prev's lock before trying
377 prev.postEvent(queue[i]);
379 if (++i == queue.length)
382 // Empty the queue so it can be reused
386 // Tell our EventDispatchThread that it can end execution
387 dispatchThread.interrupt ();
388 dispatchThread = null;
394 * Dispatches an event. The manner in which the event is dispatched depends
395 * upon the type of the event and the type of the event's source object.
397 * @exception NullPointerException If event is null.
399 protected void dispatchEvent(AWTEvent evt)
403 if (evt instanceof InputEvent)
404 lastWhen = ((InputEvent) evt).getWhen();
405 else if (evt instanceof ActionEvent)
406 lastWhen = ((ActionEvent) evt).getWhen();
407 else if (evt instanceof InvocationEvent)
408 lastWhen = ((InvocationEvent) evt).getWhen();
410 if (evt instanceof ActiveEvent)
412 ActiveEvent active_evt = (ActiveEvent) evt;
413 active_evt.dispatch();
417 Object source = evt.getSource();
419 if (source instanceof Component)
421 Component srccmp = (Component) source;
422 srccmp.dispatchEvent(evt);
424 else if (source instanceof MenuComponent)
426 MenuComponent srccmp = (MenuComponent) source;
427 srccmp.dispatchEvent(evt);
433 * Returns the timestamp of the most recent event that had a timestamp, or
434 * the initialization time of the event queue if no events have been fired.
435 * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
436 * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
437 * timestamps, but this may be added to other events in future versions.
438 * If this is called by the event dispatching thread, it can be any
439 * (sequential) value, but to other threads, the safest bet is to return
440 * System.currentTimeMillis().
442 * @return the most recent timestamp
443 * @see InputEvent#getWhen()
444 * @see ActionEvent#getWhen()
445 * @see InvocationEvent#getWhen()
446 * @see InputMethodEvent#getWhen()
449 public static long getMostRecentEventTime()
451 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
452 if (Thread.currentThread() != eq.dispatchThread)
453 return System.currentTimeMillis();