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., 51 Franklin Street, Fifth Floor, 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 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.
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
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
)
83 synchronized boolean isShutdown ()
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())
104 * Initializes a new instance of <code>EventQueue</code>.
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
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
137 throw new InterruptedException();
142 AWTEvent res
= queue
[next_out
];
144 if (++next_out
== queue
.length
)
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
154 * @return The next event in the queue.
155 * @specnote Does not block. Returns null if there are no events on the
158 public synchronized AWTEvent
peekEvent()
161 return next
.peekEvent();
163 if (next_in
!= next_out
)
164 return queue
[next_out
];
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
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
182 public synchronized AWTEvent
peekEvent(int id
)
185 return next
.peekEvent(id
);
190 AWTEvent qevt
= queue
[i
];
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
)
207 throw new NullPointerException();
215 /* Check for any events already on the queue with the same source
220 AWTEvent qevt
= queue
[i
];
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
;
238 if (++i
== queue
.length
)
242 queue
[next_in
] = evt
;
243 if (++next_in
== queue
.length
)
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
);
255 System
.arraycopy(oldQueue
, 0, queue
, len
, next_out
);
258 next_in
= oldQueue
.length
;
261 if (dispatchThread
== null || !dispatchThread
.isAlive())
263 dispatchThread
= new EventDispatchThread(this);
264 dispatchThread
.start();
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
278 * @exception InvocationTargetException If an exception is thrown when running
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();
293 new InvocationEvent(eq
, runnable
, current
, true);
295 synchronized (current
)
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.
314 public static void invokeLater(Runnable runnable
)
316 EventQueue eq
= Toolkit
.getDefaultToolkit().getSystemEventQueue();
319 new InvocationEvent(eq
, runnable
, null, false);
325 * Return true if the current thread is the current AWT event dispatch
328 public static boolean isDispatchThread()
330 EventQueue eq
= Toolkit
.getDefaultToolkit().getSystemEventQueue();
332 /* Find last EventQueue in chain */
333 while (eq
.next
!= null)
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.
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
357 return null; // Not an event dispatch thread
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() */
382 next
.push (newEventQueue
);
386 /* Make sure we have a live dispatch thread to drive the queue */
387 if (dispatchThread
== null)
388 dispatchThread
= new EventDispatchThread(this);
393 newEventQueue
.postEvent(queue
[i
]);
395 if (++i
== queue
.length
)
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
409 protected void pop() throws EmptyStackException
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
429 prev
.postEvent(queue
[i
]);
431 if (++i
== queue
.length
)
434 // Empty the queue so it can be reused
439 dispatchThread
= null;
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
)
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();
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()
501 public static long getMostRecentEventTime()
503 EventQueue eq
= Toolkit
.getDefaultToolkit().getSystemEventQueue();
504 if (Thread
.currentThread() != eq
.dispatchThread
)
505 return System
.currentTimeMillis();