Merge from mainline.
[official-gcc.git] / libjava / classpath / java / awt / EventQueue.java
blob235ad2ac17caac5ac2d5c564358af462503c9e08
1 /* EventQueue.java --
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)
9 any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
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
24 combination.
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. */
39 package java.awt;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.InputEvent;
43 import java.awt.event.InputMethodEvent;
44 import java.awt.event.InvocationEvent;
45 import java.lang.reflect.InvocationTargetException;
46 import java.util.EmptyStackException;
48 /* Written using on-line Java 2 Platform Standard Edition v1.3 API
49 * Specification, as well as "The Java Class Libraries", 2nd edition
50 * (Addison-Wesley, 1998).
51 * Status: Believed complete, but untested.
54 /**
55 * This class manages a queue of <code>AWTEvent</code> objects that
56 * are posted to it. The AWT system uses only one event queue for all
57 * events.
59 * @author Bryce McKinlay
60 * @author Aaron M. Renn (arenn@urbanophile.com)
62 public class EventQueue
64 private static final int INITIAL_QUEUE_DEPTH = 8;
65 private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH];
67 private int next_in = 0; // Index where next event will be added to queue
68 private int next_out = 0; // Index of next event to be removed from queue
70 private EventQueue next;
71 private EventQueue prev;
72 private AWTEvent currentEvent;
73 private long lastWhen = System.currentTimeMillis();
75 private EventDispatchThread dispatchThread = new EventDispatchThread(this);
76 private boolean shutdown = false;
78 synchronized private void setShutdown (boolean b)
80 shutdown = b;
83 synchronized boolean isShutdown ()
85 if (shutdown)
86 return true;
88 // This is the exact self-shutdown condition specified in J2SE:
89 // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
91 // FIXME: check somewhere that the native queue is empty
92 if (peekEvent() == null)
94 Frame[] frames = Frame.getFrames();
95 for (int i = 0; i < frames.length; ++i)
96 if (frames[i].isDisplayable())
97 return false;
98 return true;
100 return false;
104 * Initializes a new instance of <code>EventQueue</code>.
106 public EventQueue()
111 * Returns the next event in the queue. This method will block until
112 * an event is available or until the thread is interrupted.
114 * @return The next event in the queue.
116 * @exception InterruptedException If this thread is interrupted while
117 * waiting for an event to be posted to the queue.
119 public synchronized AWTEvent getNextEvent()
120 throws InterruptedException
122 if (next != null)
123 return next.getNextEvent();
125 while (next_in == next_out)
127 // We are not allowed to return null from this method, yet it
128 // is possible that we actually have run out of native events
129 // in the enclosing while() loop, and none of the native events
130 // happened to cause AWT events. We therefore ought to check
131 // the isShutdown() condition here, before risking a "native
132 // wait". If we check it before entering this function we may
133 // wait forever for events after the shutdown condition has
134 // arisen.
136 if (isShutdown())
137 throw new InterruptedException();
139 wait();
142 AWTEvent res = queue[next_out];
144 if (++next_out == queue.length)
145 next_out = 0;
146 return res;
150 * Returns the next event in the queue without removing it from the queue.
151 * This method will block until an event is available or until the thread
152 * is interrupted.
154 * @return The next event in the queue.
155 * @specnote Does not block. Returns null if there are no events on the
156 * queue.
158 public synchronized AWTEvent peekEvent()
160 if (next != null)
161 return next.peekEvent();
163 if (next_in != next_out)
164 return queue[next_out];
165 else
166 return null;
170 * Returns the next event in the queue that has the specified id
171 * without removing it from the queue.
172 * This method will block until an event is available or until the thread
173 * is interrupted.
175 * @param id The event id to return.
177 * @return The next event in the queue.
179 * @specnote Does not block. Returns null if there are no matching events
180 * on the queue.
182 public synchronized AWTEvent peekEvent(int id)
184 if (next != null)
185 return next.peekEvent(id);
187 int i = next_out;
188 while (i != next_in)
190 AWTEvent qevt = queue[i];
191 if (qevt.id == id)
192 return qevt;
194 return null;
198 * Posts a new event to the queue.
200 * @param evt The event to post to the queue.
202 * @exception NullPointerException If event is null.
204 public synchronized void postEvent(AWTEvent evt)
206 if (evt == null)
207 throw new NullPointerException();
209 if (next != null)
211 next.postEvent(evt);
212 return;
215 /* Check for any events already on the queue with the same source
216 and ID. */
217 int i = next_out;
218 while (i != next_in)
220 AWTEvent qevt = queue[i];
221 Object src;
222 if (qevt.id == evt.id
223 && (src = qevt.getSource()) == evt.getSource()
224 && src instanceof Component)
226 /* If there are, call coalesceEvents on the source component
227 to see if they can be combined. */
228 Component srccmp = (Component) src;
229 AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt);
230 if (coalesced_evt != null)
232 /* Yes. Replace the existing event with the combined event. */
233 queue[i] = coalesced_evt;
234 return;
236 break;
238 if (++i == queue.length)
239 i = 0;
242 queue[next_in] = evt;
243 if (++next_in == queue.length)
244 next_in = 0;
246 if (next_in == next_out)
248 /* Queue is full. Extend it. */
249 AWTEvent[] oldQueue = queue;
250 queue = new AWTEvent[queue.length * 2];
252 int len = oldQueue.length - next_out;
253 System.arraycopy(oldQueue, next_out, queue, 0, len);
254 if (next_out != 0)
255 System.arraycopy(oldQueue, 0, queue, len, next_out);
257 next_out = 0;
258 next_in = oldQueue.length;
261 if (dispatchThread == null || !dispatchThread.isAlive())
263 dispatchThread = new EventDispatchThread(this);
264 dispatchThread.start();
267 notify();
271 * Causes runnable to have its run method called in the dispatch thread of the
272 * EventQueue. This will happen after all pending events are processed. The
273 * call blocks until this has happened. This method will throw an Error if
274 * called from the event dispatcher thread.
276 * @exception InterruptedException If another thread has interrupted
277 * this thread.
278 * @exception InvocationTargetException If an exception is thrown when running
279 * runnable.
281 * @since 1.2
283 public static void invokeAndWait(Runnable runnable)
284 throws InterruptedException, InvocationTargetException
286 if (isDispatchThread ())
287 throw new Error("Can't call invokeAndWait from event dispatch thread");
289 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
290 Thread current = Thread.currentThread();
292 InvocationEvent ie =
293 new InvocationEvent(eq, runnable, current, true);
295 synchronized (current)
297 eq.postEvent(ie);
298 current.wait();
301 Exception exception;
303 if ((exception = ie.getException()) != null)
304 throw new InvocationTargetException(exception);
308 * This arranges for runnable to have its run method called in the
309 * dispatch thread of the EventQueue. This will happen after all
310 * pending events are processed.
312 * @since 1.2
314 public static void invokeLater(Runnable runnable)
316 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
318 InvocationEvent ie =
319 new InvocationEvent(eq, runnable, null, false);
321 eq.postEvent(ie);
325 * Return true if the current thread is the current AWT event dispatch
326 * thread.
328 public static boolean isDispatchThread()
330 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
332 /* Find last EventQueue in chain */
333 while (eq.next != null)
334 eq = eq.next;
336 return (Thread.currentThread() == eq.dispatchThread);
340 * Return the event currently being dispatched by the event
341 * dispatch thread. If the current thread is not the event
342 * dispatch thread, this method returns null.
344 * @since 1.4
346 public static AWTEvent getCurrentEvent()
348 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
349 Thread ct = Thread.currentThread();
351 /* Find out if this thread is the dispatch thread for any of the
352 EventQueues in the chain */
353 while (ct != eq.dispatchThread)
355 // Try next EventQueue, if any
356 if (eq.next == null)
357 return null; // Not an event dispatch thread
358 eq = eq.next;
361 return eq.currentEvent;
365 * Allows a custom EventQueue implementation to replace this one.
366 * All pending events are transferred to the new queue. Calls to postEvent,
367 * getNextEvent, and peekEvent and others are forwarded to the pushed queue
368 * until it is removed with a pop().
370 * @exception NullPointerException if newEventQueue is null.
372 public synchronized void push(EventQueue newEventQueue)
374 if (newEventQueue == null)
375 throw new NullPointerException ();
377 /* Make sure we are at the top of the stack because callers can
378 only get a reference to the one at the bottom using
379 Toolkit.getDefaultToolkit().getSystemEventQueue() */
380 if (next != null)
382 next.push (newEventQueue);
383 return;
386 /* Make sure we have a live dispatch thread to drive the queue */
387 if (dispatchThread == null)
388 dispatchThread = new EventDispatchThread(this);
390 int i = next_out;
391 while (i != next_in)
393 newEventQueue.postEvent(queue[i]);
394 next_out = i;
395 if (++i == queue.length)
396 i = 0;
399 next = newEventQueue;
400 newEventQueue.prev = this;
403 /** Transfer any pending events from this queue back to the parent queue that
404 * was previously push()ed. Event dispatch from this queue is suspended.
406 * @exception EmptyStackException If no previous push was made on this
407 * EventQueue.
409 protected void pop() throws EmptyStackException
411 if (prev == null)
412 throw new EmptyStackException();
414 /* The order is important here, we must get the prev lock first,
415 or deadlock could occur as callers usually get here following
416 prev's next pointer, and thus obtain prev's lock before trying
417 to get this lock. */
418 synchronized (prev)
420 prev.next = next;
421 if (next != null)
422 next.prev = prev;
424 synchronized (this)
426 int i = next_out;
427 while (i != next_in)
429 prev.postEvent(queue[i]);
430 next_out = i;
431 if (++i == queue.length)
432 i = 0;
434 // Empty the queue so it can be reused
435 next_in = 0;
436 next_out = 0;
438 setShutdown(true);
439 dispatchThread = null;
440 this.notifyAll();
446 * Dispatches an event. The manner in which the event is dispatched depends
447 * upon the type of the event and the type of the event's source object.
449 * @exception NullPointerException If event is null.
451 protected void dispatchEvent(AWTEvent evt)
453 currentEvent = evt;
455 if (evt instanceof InputEvent)
456 lastWhen = ((InputEvent) evt).getWhen();
457 else if (evt instanceof ActionEvent)
458 lastWhen = ((ActionEvent) evt).getWhen();
459 else if (evt instanceof InvocationEvent)
460 lastWhen = ((InvocationEvent) evt).getWhen();
462 if (evt instanceof ActiveEvent)
464 ActiveEvent active_evt = (ActiveEvent) evt;
465 active_evt.dispatch();
467 else
469 Object source = evt.getSource();
471 if (source instanceof Component)
473 Component srccmp = (Component) source;
474 srccmp.dispatchEvent(evt);
476 else if (source instanceof MenuComponent)
478 MenuComponent srccmp = (MenuComponent) source;
479 srccmp.dispatchEvent(evt);
485 * Returns the timestamp of the most recent event that had a timestamp, or
486 * the initialization time of the event queue if no events have been fired.
487 * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
488 * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
489 * timestamps, but this may be added to other events in future versions.
490 * If this is called by the event dispatching thread, it can be any
491 * (sequential) value, but to other threads, the safest bet is to return
492 * System.currentTimeMillis().
494 * @return the most recent timestamp
495 * @see InputEvent#getWhen()
496 * @see ActionEvent#getWhen()
497 * @see InvocationEvent#getWhen()
498 * @see InputMethodEvent#getWhen()
499 * @since 1.4
501 public static long getMostRecentEventTime()
503 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
504 if (Thread.currentThread() != eq.dispatchThread)
505 return System.currentTimeMillis();
506 return eq.lastWhen;