001 /* EventQueue.java --
002 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package java.awt;
040
041 import gnu.java.awt.LowPriorityEvent;
042 import gnu.java.awt.peer.NativeEventLoopRunningEvent;
043
044 import java.awt.event.ActionEvent;
045 import java.awt.event.InputEvent;
046 import java.awt.event.InputMethodEvent;
047 import java.awt.event.InvocationEvent;
048 import java.awt.event.PaintEvent;
049 import java.awt.peer.ComponentPeer;
050 import java.awt.peer.LightweightPeer;
051 import java.lang.reflect.InvocationTargetException;
052 import java.util.EmptyStackException;
053
054 /* Written using on-line Java 2 Platform Standard Edition v1.3 API
055 * Specification, as well as "The Java Class Libraries", 2nd edition
056 * (Addison-Wesley, 1998).
057 * Status: Believed complete, but untested.
058 */
059
060 /**
061 * This class manages a queue of <code>AWTEvent</code> objects that
062 * are posted to it. The AWT system uses only one event queue for all
063 * events.
064 *
065 * @author Bryce McKinlay
066 * @author Aaron M. Renn (arenn@urbanophile.com)
067 */
068 public class EventQueue
069 {
070 /**
071 * Indicates events that are processed with normal priority. This is normally
072 * all events except PaintEvents.
073 */
074 private static final int NORM_PRIORITY = 0;
075
076 /**
077 * Indicates events that are processed with lowes priority. This is normally
078 * all PaintEvents and LowPriorityEvents.
079 */
080 private static final int LOW_PRIORITY = 1;
081
082 /**
083 * Implements the actual queue. EventQueue has 2 internal queues for
084 * different priorities:
085 * 1 PaintEvents are always dispatched with low priority.
086 * 2. All other events are dispatched with normal priority.
087 *
088 * This makes sure that the actual painting (output) is performed _after_ all
089 * available input has been processed and that the paint regions are
090 * coalesced as much as possible.
091 */
092 private class Queue
093 {
094 /**
095 * The first item in the queue. This is where events are popped from.
096 */
097 AWTEvent queueHead;
098
099 /**
100 * The last item. This is where events are posted to.
101 */
102 AWTEvent queueTail;
103 }
104
105 /**
106 * The three internal event queues.
107 *
108 * @see Queue
109 */
110 private Queue[] queues;
111
112 private EventQueue next;
113 private EventQueue prev;
114 private AWTEvent currentEvent;
115 private long lastWhen = System.currentTimeMillis();
116
117 private EventDispatchThread dispatchThread = new EventDispatchThread(this);
118 private boolean nativeLoopRunning = false;
119
120 private boolean isShutdown ()
121 {
122 // This is the exact self-shutdown condition specified in J2SE:
123 // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
124
125 if (nativeLoopRunning)
126 return false;
127
128 if (peekEvent() != null)
129 return false;
130
131 if (Frame.hasDisplayableFrames())
132 return false;
133
134 return true;
135 }
136
137 /**
138 * Initializes a new instance of <code>EventQueue</code>.
139 */
140 public EventQueue()
141 {
142 queues = new Queue[2];
143 queues[NORM_PRIORITY] = new Queue();
144 queues[LOW_PRIORITY] = new Queue();
145 }
146
147 /**
148 * Returns the next event in the queue. This method will block until
149 * an event is available or until the thread is interrupted.
150 *
151 * @return The next event in the queue.
152 *
153 * @exception InterruptedException If this thread is interrupted while
154 * waiting for an event to be posted to the queue.
155 */
156 public synchronized AWTEvent getNextEvent()
157 throws InterruptedException
158 {
159 if (next != null)
160 return next.getNextEvent();
161
162 AWTEvent res = getNextEventImpl(true);
163
164 while (res == null)
165 {
166 if (isShutdown())
167 {
168 // Explicitly set dispathThread to null. If we don't do
169 // this, there is a race condition where dispatchThread
170 // can be != null even after the event dispatch thread has
171 // stopped running. If that happens, then the
172 // dispatchThread == null check in postEventImpl will
173 // fail, and a new event dispatch thread will not be
174 // created, leaving invokeAndWaits waiting indefinitely.
175 dispatchThread = null;
176
177 // Interrupt the event dispatch thread.
178 throw new InterruptedException();
179 }
180
181 wait();
182 res = getNextEventImpl(true);
183 }
184
185 return res;
186 }
187
188 /**
189 * Fetches and possibly removes the next event from the internal queues.
190 * This method returns immediately. When all queues are empty, this returns
191 * <code>null</code>:
192 *
193 * @param remove <true> when the event should be removed from the queue,
194 * <code>false</code> otherwise
195 *
196 * @return the next event or <code>null</code> when all internal queues
197 * are empty
198 */
199 private AWTEvent getNextEventImpl(boolean remove)
200 {
201 AWTEvent next = null;
202 for (int i = 0; i < queues.length && next == null; i++)
203 {
204 Queue q = queues[i];
205 if (q.queueHead != null)
206 {
207 // Got an event, remove it.
208 next = q.queueHead;
209 if (remove)
210 {
211 // Unlink event from the queue.
212 q.queueHead = next.queueNext;
213 if (q.queueHead == null)
214 q.queueTail = null;
215 next.queueNext = null;
216 }
217 }
218 }
219 return next;
220 }
221
222 /**
223 * Returns the next event in the queue without removing it from the queue.
224 * This method will block until an event is available or until the thread
225 * is interrupted.
226 *
227 * @return The next event in the queue.
228 * @specnote Does not block. Returns null if there are no events on the
229 * queue.
230 */
231 public synchronized AWTEvent peekEvent()
232 {
233 if (next != null)
234 return next.peekEvent();
235
236 return getNextEventImpl(false);
237 }
238
239 /**
240 * Returns the next event in the queue that has the specified id
241 * without removing it from the queue.
242 * This method will block until an event is available or until the thread
243 * is interrupted.
244 *
245 * @param id The event id to return.
246 *
247 * @return The next event in the queue.
248 *
249 * @specnote Does not block. Returns null if there are no matching events
250 * on the queue.
251 */
252 public synchronized AWTEvent peekEvent(int id)
253 {
254 if (next != null)
255 return next.peekEvent(id);
256
257 AWTEvent evt = null;
258 for (int i = 0; i < queues.length && evt == null; i++)
259 {
260 Queue q = queues[i];
261 evt = q.queueHead;
262 while (evt != null && evt.id != id)
263 evt = evt.queueNext;
264 // At this point we either have found an event (evt != null -> exit
265 // for loop), or we have found no event (evt == null -> search next
266 // internal queue).
267 }
268 return evt;
269 }
270
271 /**
272 * Posts a new event to the queue.
273 *
274 * @param evt The event to post to the queue.
275 *
276 * @exception NullPointerException If event is null.
277 */
278 public void postEvent(AWTEvent evt)
279 {
280 postEventImpl(evt);
281 }
282
283 /**
284 * Sorts events to their priority and calls
285 * {@link #postEventImpl(AWTEvent, int)}.
286 *
287 * @param evt the event to post
288 */
289 private synchronized final void postEventImpl(AWTEvent evt)
290 {
291 int priority = NORM_PRIORITY;
292 if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
293 priority = LOW_PRIORITY;
294 // TODO: Maybe let Swing RepaintManager events also be processed with
295 // low priority.
296 if (evt instanceof NativeEventLoopRunningEvent)
297 {
298 nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
299 notify();
300 return;
301 }
302 postEventImpl(evt, priority);
303 }
304
305 /**
306 * Actually performs the event posting. This is needed because the
307 * RI doesn't use the public postEvent() method when transferring events
308 * between event queues in push() and pop().
309 *
310 * @param evt the event to post
311 * @param priority the priority of the event
312 */
313 private final void postEventImpl(AWTEvent evt, int priority)
314 {
315 if (evt == null)
316 throw new NullPointerException();
317
318 if (next != null)
319 {
320 next.postEvent(evt);
321 return;
322 }
323
324 Object source = evt.getSource();
325
326 Queue q = queues[priority];
327 if (source instanceof Component)
328 {
329 // For PaintEvents, ask the ComponentPeer to coalesce the event
330 // when the component is heavyweight.
331 Component comp = (Component) source;
332 ComponentPeer peer = comp.peer;
333 if (peer != null && evt instanceof PaintEvent
334 && ! (peer instanceof LightweightPeer))
335 peer.coalescePaintEvent((PaintEvent) evt);
336
337 // Check for any events already on the queue with the same source
338 // and ID.
339 AWTEvent previous = null;
340 for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
341 {
342 Object src = qevt.getSource();
343 if (qevt.id == evt.id && src == comp)
344 {
345 // If there are, call coalesceEvents on the source component
346 // to see if they can be combined.
347 Component srccmp = (Component) src;
348 AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
349 if (coalescedEvt != null)
350 {
351 // Yes. Replace the existing event with the combined event.
352 if (qevt != coalescedEvt)
353 {
354 if (previous != null)
355 {
356 assert previous.queueNext == qevt;
357 previous.queueNext = coalescedEvt;
358 }
359 else
360 {
361 assert q.queueHead == qevt;
362 q.queueHead = coalescedEvt;
363 }
364 coalescedEvt.queueNext = qevt.queueNext;
365 if (q.queueTail == qevt)
366 q.queueTail = coalescedEvt;
367 qevt.queueNext = null;
368 }
369 return;
370 }
371 }
372 previous = qevt;
373 }
374 }
375
376 if (q.queueHead == null)
377 {
378 // We have an empty queue. Set this event both as head and as tail.
379 q.queueHead = evt;
380 q.queueTail = evt;
381 }
382 else
383 {
384 // Note: queueTail should not be null here.
385 q.queueTail.queueNext = evt;
386 q.queueTail = evt;
387 }
388
389 if (dispatchThread == null || !dispatchThread.isAlive())
390 {
391 dispatchThread = new EventDispatchThread(this);
392 dispatchThread.start();
393 }
394
395 notify();
396 }
397
398 /**
399 * Causes runnable to have its run method called in the dispatch thread of the
400 * EventQueue. This will happen after all pending events are processed. The
401 * call blocks until this has happened. This method will throw an Error if
402 * called from the event dispatcher thread.
403 *
404 * @exception InterruptedException If another thread has interrupted
405 * this thread.
406 * @exception InvocationTargetException If an exception is thrown when running
407 * runnable.
408 *
409 * @since 1.2
410 */
411 public static void invokeAndWait(Runnable runnable)
412 throws InterruptedException, InvocationTargetException
413 {
414 if (isDispatchThread ())
415 throw new Error("Can't call invokeAndWait from event dispatch thread");
416
417 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
418 Object notifyObject = new Object();
419
420 InvocationEvent ie =
421 new InvocationEvent(eq, runnable, notifyObject, true);
422
423 synchronized (notifyObject)
424 {
425 eq.postEvent(ie);
426 notifyObject.wait();
427 }
428
429 Exception exception;
430
431 if ((exception = ie.getException()) != null)
432 throw new InvocationTargetException(exception);
433 }
434
435 /**
436 * This arranges for runnable to have its run method called in the
437 * dispatch thread of the EventQueue. This will happen after all
438 * pending events are processed.
439 *
440 * @since 1.2
441 */
442 public static void invokeLater(Runnable runnable)
443 {
444 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
445
446 InvocationEvent ie =
447 new InvocationEvent(eq, runnable, null, false);
448
449 eq.postEvent(ie);
450 }
451
452 /**
453 * Return true if the current thread is the current AWT event dispatch
454 * thread.
455 */
456 public static boolean isDispatchThread()
457 {
458 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
459
460 /* Find last EventQueue in chain */
461 while (eq.next != null)
462 eq = eq.next;
463
464 return (Thread.currentThread() == eq.dispatchThread);
465 }
466
467 /**
468 * Return the event currently being dispatched by the event
469 * dispatch thread. If the current thread is not the event
470 * dispatch thread, this method returns null.
471 *
472 * @since 1.4
473 */
474 public static AWTEvent getCurrentEvent()
475 {
476 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
477 Thread ct = Thread.currentThread();
478
479 /* Find out if this thread is the dispatch thread for any of the
480 EventQueues in the chain */
481 while (ct != eq.dispatchThread)
482 {
483 // Try next EventQueue, if any
484 if (eq.next == null)
485 return null; // Not an event dispatch thread
486 eq = eq.next;
487 }
488
489 return eq.currentEvent;
490 }
491
492 /**
493 * Allows a custom EventQueue implementation to replace this one.
494 * All pending events are transferred to the new queue. Calls to postEvent,
495 * getNextEvent, and peekEvent and others are forwarded to the pushed queue
496 * until it is removed with a pop().
497 *
498 * @exception NullPointerException if newEventQueue is null.
499 */
500 public synchronized void push(EventQueue newEventQueue)
501 {
502 if (newEventQueue == null)
503 throw new NullPointerException ();
504
505 /* Make sure we are at the top of the stack because callers can
506 only get a reference to the one at the bottom using
507 Toolkit.getDefaultToolkit().getSystemEventQueue() */
508 if (next != null)
509 {
510 next.push (newEventQueue);
511 return;
512 }
513
514 /* Make sure we have a live dispatch thread to drive the queue */
515 if (dispatchThread == null)
516 dispatchThread = new EventDispatchThread(this);
517
518 synchronized (newEventQueue)
519 {
520 // The RI transfers the events without calling the new eventqueue's
521 // push(), but using getNextEvent().
522 while (peekEvent() != null)
523 {
524 try
525 {
526 newEventQueue.postEventImpl(getNextEvent());
527 }
528 catch (InterruptedException ex)
529 {
530 // What should we do with this?
531 ex.printStackTrace();
532 }
533 }
534 newEventQueue.prev = this;
535 }
536
537 next = newEventQueue;
538 }
539
540 /** Transfer any pending events from this queue back to the parent queue that
541 * was previously push()ed. Event dispatch from this queue is suspended.
542 *
543 * @exception EmptyStackException If no previous push was made on this
544 * EventQueue.
545 */
546 protected void pop() throws EmptyStackException
547 {
548 /* The order is important here, we must get the prev lock first,
549 or deadlock could occur as callers usually get here following
550 prev's next pointer, and thus obtain prev's lock before trying
551 to get this lock. */
552 EventQueue previous = prev;
553 if (previous == null)
554 throw new EmptyStackException();
555 synchronized (previous)
556 {
557 synchronized (this)
558 {
559 EventQueue nextQueue = next;
560 if (nextQueue != null)
561 {
562 nextQueue.pop();
563 }
564 else
565 {
566 previous.next = null;
567
568 // The RI transfers the events without calling the new eventqueue's
569 // push(), so this should be OK and most effective.
570 while (peekEvent() != null)
571 {
572 try
573 {
574 previous.postEventImpl(getNextEvent());
575 }
576 catch (InterruptedException ex)
577 {
578 // What should we do with this?
579 ex.printStackTrace();
580 }
581 }
582 prev = null;
583 // Tell our EventDispatchThread that it can end
584 // execution.
585 if (dispatchThread != null)
586 {
587 dispatchThread.interrupt();
588 dispatchThread = null;
589 }
590 }
591 }
592 }
593 }
594
595 /**
596 * Dispatches an event. The manner in which the event is dispatched depends
597 * upon the type of the event and the type of the event's source object.
598 *
599 * @exception NullPointerException If event is null.
600 */
601 protected void dispatchEvent(AWTEvent evt)
602 {
603 currentEvent = evt;
604
605 if (evt instanceof InputEvent)
606 lastWhen = ((InputEvent) evt).getWhen();
607 else if (evt instanceof ActionEvent)
608 lastWhen = ((ActionEvent) evt).getWhen();
609 else if (evt instanceof InvocationEvent)
610 lastWhen = ((InvocationEvent) evt).getWhen();
611
612 if (evt instanceof ActiveEvent)
613 {
614 ActiveEvent active_evt = (ActiveEvent) evt;
615 active_evt.dispatch();
616 }
617 else
618 {
619 Object source = evt.getSource();
620
621 if (source instanceof Component)
622 {
623 Component srccmp = (Component) source;
624 srccmp.dispatchEvent(evt);
625 }
626 else if (source instanceof MenuComponent)
627 {
628 MenuComponent srccmp = (MenuComponent) source;
629 srccmp.dispatchEvent(evt);
630 }
631 }
632 }
633
634 /**
635 * Returns the timestamp of the most recent event that had a timestamp, or
636 * the initialization time of the event queue if no events have been fired.
637 * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
638 * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
639 * timestamps, but this may be added to other events in future versions.
640 * If this is called by the event dispatching thread, it can be any
641 * (sequential) value, but to other threads, the safest bet is to return
642 * System.currentTimeMillis().
643 *
644 * @return the most recent timestamp
645 * @see InputEvent#getWhen()
646 * @see ActionEvent#getWhen()
647 * @see InvocationEvent#getWhen()
648 * @see InputMethodEvent#getWhen()
649 * @since 1.4
650 */
651 public static long getMostRecentEventTime()
652 {
653 EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
654 if (Thread.currentThread() != eq.dispatchThread)
655 return System.currentTimeMillis();
656 return eq.lastWhen;
657 }
658 }