001/* EventQueue.java --
002   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005  Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt;
040
041import gnu.java.awt.LowPriorityEvent;
042import gnu.java.awt.peer.NativeEventLoopRunningEvent;
043
044import java.awt.event.ActionEvent;
045import java.awt.event.InputEvent;
046import java.awt.event.InputMethodEvent;
047import java.awt.event.InvocationEvent;
048import java.awt.event.PaintEvent;
049import java.awt.peer.ComponentPeer;
050import java.awt.peer.LightweightPeer;
051import java.lang.reflect.InvocationTargetException;
052import 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 */
068public 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}