mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			659 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			659 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
/* EventQueue.java --
 | 
						|
   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005  Free Software Foundation
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package java.awt;
 | 
						|
 | 
						|
import gnu.java.awt.LowPriorityEvent;
 | 
						|
import gnu.java.awt.peer.NativeEventLoopRunningEvent;
 | 
						|
 | 
						|
import java.awt.event.ActionEvent;
 | 
						|
import java.awt.event.InputEvent;
 | 
						|
import java.awt.event.InputMethodEvent;
 | 
						|
import java.awt.event.InvocationEvent;
 | 
						|
import java.awt.event.PaintEvent;
 | 
						|
import java.awt.peer.ComponentPeer;
 | 
						|
import java.awt.peer.LightweightPeer;
 | 
						|
import java.lang.reflect.InvocationTargetException;
 | 
						|
import java.util.EmptyStackException;
 | 
						|
 | 
						|
/* Written using on-line Java 2 Platform Standard Edition v1.3 API
 | 
						|
 * Specification, as well as "The Java Class Libraries", 2nd edition
 | 
						|
 * (Addison-Wesley, 1998).
 | 
						|
 * Status:  Believed complete, but untested.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * This class manages a queue of <code>AWTEvent</code> objects that
 | 
						|
 * are posted to it.  The AWT system uses only one event queue for all
 | 
						|
 * events.
 | 
						|
 *
 | 
						|
 * @author Bryce McKinlay
 | 
						|
 * @author Aaron M. Renn (arenn@urbanophile.com)
 | 
						|
 */
 | 
						|
public class EventQueue
 | 
						|
{
 | 
						|
  /**
 | 
						|
   * Indicates events that are processed with normal priority. This is normally
 | 
						|
   * all events except PaintEvents.
 | 
						|
   */
 | 
						|
  private static final int NORM_PRIORITY = 0;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Indicates events that are processed with lowes priority. This is normally
 | 
						|
   * all PaintEvents and LowPriorityEvents.
 | 
						|
   */
 | 
						|
  private static final int LOW_PRIORITY = 1;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Implements the actual queue. EventQueue has 2 internal queues for
 | 
						|
   * different priorities:
 | 
						|
   * 1 PaintEvents are always dispatched with low priority.
 | 
						|
   * 2. All other events are dispatched with normal priority.
 | 
						|
   *
 | 
						|
   * This makes sure that the actual painting (output) is performed _after_ all
 | 
						|
   * available input has been processed and that the paint regions are
 | 
						|
   * coalesced as much as possible.
 | 
						|
   */
 | 
						|
  private class Queue
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * The first item in the queue. This is where events are popped from.
 | 
						|
     */
 | 
						|
    AWTEvent queueHead;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The last item. This is where events are posted to.
 | 
						|
     */
 | 
						|
    AWTEvent queueTail;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The three internal event queues.
 | 
						|
   *
 | 
						|
   * @see Queue
 | 
						|
   */
 | 
						|
  private Queue[] queues;
 | 
						|
 | 
						|
  private EventQueue next;
 | 
						|
  private EventQueue prev;
 | 
						|
  private AWTEvent currentEvent;
 | 
						|
  private long lastWhen = System.currentTimeMillis();
 | 
						|
 | 
						|
  private EventDispatchThread dispatchThread = new EventDispatchThread(this);
 | 
						|
  private boolean nativeLoopRunning = false;
 | 
						|
 | 
						|
  private boolean isShutdown ()
 | 
						|
  {
 | 
						|
    // This is the exact self-shutdown condition specified in J2SE:
 | 
						|
    // http://java.sun.com/j2se/1.4.2/docs/api/java/awt/doc-files/AWTThreadIssues.html
 | 
						|
 | 
						|
    if (nativeLoopRunning)
 | 
						|
      return false;
 | 
						|
 | 
						|
    if (peekEvent() != null)
 | 
						|
      return false;
 | 
						|
 | 
						|
    if (Frame.hasDisplayableFrames())
 | 
						|
      return false;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Initializes a new instance of <code>EventQueue</code>.
 | 
						|
   */
 | 
						|
  public EventQueue()
 | 
						|
  {
 | 
						|
    queues = new Queue[2];
 | 
						|
    queues[NORM_PRIORITY] = new Queue();
 | 
						|
    queues[LOW_PRIORITY] = new Queue();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the next event in the queue.  This method will block until
 | 
						|
   * an event is available or until the thread is interrupted.
 | 
						|
   *
 | 
						|
   * @return The next event in the queue.
 | 
						|
   *
 | 
						|
   * @exception InterruptedException If this thread is interrupted while
 | 
						|
   * waiting for an event to be posted to the queue.
 | 
						|
   */
 | 
						|
  public synchronized AWTEvent getNextEvent()
 | 
						|
    throws InterruptedException
 | 
						|
  {
 | 
						|
    if (next != null)
 | 
						|
      return next.getNextEvent();
 | 
						|
 | 
						|
    AWTEvent res = getNextEventImpl(true);
 | 
						|
 | 
						|
    while (res == null)
 | 
						|
      {
 | 
						|
        if (isShutdown())
 | 
						|
          {
 | 
						|
            // Explicitly set dispathThread to null.  If we don't do
 | 
						|
            // this, there is a race condition where dispatchThread
 | 
						|
            // can be != null even after the event dispatch thread has
 | 
						|
            // stopped running.  If that happens, then the
 | 
						|
            // dispatchThread == null check in postEventImpl will
 | 
						|
            // fail, and a new event dispatch thread will not be
 | 
						|
            // created, leaving invokeAndWaits waiting indefinitely.
 | 
						|
            dispatchThread = null;
 | 
						|
 | 
						|
            // Interrupt the event dispatch thread.
 | 
						|
            throw new InterruptedException();
 | 
						|
          }
 | 
						|
 | 
						|
        wait();
 | 
						|
        res = getNextEventImpl(true);
 | 
						|
      }
 | 
						|
 | 
						|
    return res;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fetches and possibly removes the next event from the internal queues.
 | 
						|
   * This method returns immediately. When all queues are empty, this returns
 | 
						|
   * <code>null</code>:
 | 
						|
   *
 | 
						|
   * @param remove <true> when the event should be removed from the queue,
 | 
						|
   *        <code>false</code> otherwise
 | 
						|
   *
 | 
						|
   * @return the next event or <code>null</code> when all internal queues
 | 
						|
   *         are empty
 | 
						|
   */
 | 
						|
  private AWTEvent getNextEventImpl(boolean remove)
 | 
						|
  {
 | 
						|
    AWTEvent next = null;
 | 
						|
    for (int i = 0; i < queues.length && next == null; i++)
 | 
						|
      {
 | 
						|
        Queue q = queues[i];
 | 
						|
        if (q.queueHead != null)
 | 
						|
          {
 | 
						|
            // Got an event, remove it.
 | 
						|
            next = q.queueHead;
 | 
						|
            if (remove)
 | 
						|
              {
 | 
						|
                // Unlink event from the queue.
 | 
						|
                q.queueHead = next.queueNext;
 | 
						|
                if (q.queueHead == null)
 | 
						|
                  q.queueTail = null;
 | 
						|
                next.queueNext = null;
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return next;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the next event in the queue without removing it from the queue.
 | 
						|
   * This method will block until an event is available or until the thread
 | 
						|
   * is interrupted.
 | 
						|
   *
 | 
						|
   * @return The next event in the queue.
 | 
						|
   * @specnote Does not block. Returns null if there are no events on the
 | 
						|
   *            queue.
 | 
						|
   */
 | 
						|
  public synchronized AWTEvent peekEvent()
 | 
						|
  {
 | 
						|
    if (next != null)
 | 
						|
      return next.peekEvent();
 | 
						|
 | 
						|
    return getNextEventImpl(false);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the next event in the queue that has the specified id
 | 
						|
   * without removing it from the queue.
 | 
						|
   * This method will block until an event is available or until the thread
 | 
						|
   * is interrupted.
 | 
						|
   *
 | 
						|
   * @param id The event id to return.
 | 
						|
   *
 | 
						|
   * @return The next event in the queue.
 | 
						|
   *
 | 
						|
   * @specnote Does not block. Returns null if there are no matching events
 | 
						|
   *            on the queue.
 | 
						|
   */
 | 
						|
  public synchronized AWTEvent peekEvent(int id)
 | 
						|
  {
 | 
						|
    if (next != null)
 | 
						|
      return next.peekEvent(id);
 | 
						|
 | 
						|
    AWTEvent evt = null;
 | 
						|
    for (int i = 0; i < queues.length && evt == null; i++)
 | 
						|
      {
 | 
						|
        Queue q = queues[i];
 | 
						|
        evt = q.queueHead;
 | 
						|
        while (evt != null && evt.id != id)
 | 
						|
          evt = evt.queueNext;
 | 
						|
        // At this point we either have found an event (evt != null -> exit
 | 
						|
        // for loop), or we have found no event (evt == null -> search next
 | 
						|
        // internal queue).
 | 
						|
      }
 | 
						|
    return evt;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Posts a new event to the queue.
 | 
						|
   *
 | 
						|
   * @param evt The event to post to the queue.
 | 
						|
   *
 | 
						|
   * @exception NullPointerException If event is null.
 | 
						|
   */
 | 
						|
  public void postEvent(AWTEvent evt)
 | 
						|
  {
 | 
						|
    postEventImpl(evt);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sorts events to their priority and calls
 | 
						|
   * {@link #postEventImpl(AWTEvent, int)}.
 | 
						|
   *
 | 
						|
   * @param evt the event to post
 | 
						|
   */
 | 
						|
  private synchronized final void postEventImpl(AWTEvent evt)
 | 
						|
  {
 | 
						|
    int priority = NORM_PRIORITY;
 | 
						|
    if (evt instanceof PaintEvent || evt instanceof LowPriorityEvent)
 | 
						|
      priority = LOW_PRIORITY;
 | 
						|
    // TODO: Maybe let Swing RepaintManager events also be processed with
 | 
						|
    // low priority.
 | 
						|
    if (evt instanceof NativeEventLoopRunningEvent)
 | 
						|
      {
 | 
						|
        nativeLoopRunning = ((NativeEventLoopRunningEvent) evt).isRunning();
 | 
						|
        notify();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    postEventImpl(evt, priority);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Actually performs the event posting. This is needed because the
 | 
						|
   * RI doesn't use the public postEvent() method when transferring events
 | 
						|
   * between event queues in push() and pop().
 | 
						|
   *
 | 
						|
   * @param evt the event to post
 | 
						|
   * @param priority the priority of the event
 | 
						|
   */
 | 
						|
  private final void postEventImpl(AWTEvent evt, int priority)
 | 
						|
  {
 | 
						|
    if (evt == null)
 | 
						|
      throw new NullPointerException();
 | 
						|
 | 
						|
    if (next != null)
 | 
						|
      {
 | 
						|
        next.postEvent(evt);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
    Object source = evt.getSource();
 | 
						|
 | 
						|
    Queue q = queues[priority];
 | 
						|
    if (source instanceof Component)
 | 
						|
      {
 | 
						|
        // For PaintEvents, ask the ComponentPeer to coalesce the event
 | 
						|
        // when the component is heavyweight.
 | 
						|
        Component comp = (Component) source;
 | 
						|
        ComponentPeer peer = comp.peer;
 | 
						|
        if (peer != null && evt instanceof PaintEvent
 | 
						|
            && ! (peer instanceof LightweightPeer))
 | 
						|
          peer.coalescePaintEvent((PaintEvent) evt);
 | 
						|
 | 
						|
        // Check for any events already on the queue with the same source
 | 
						|
        // and ID.
 | 
						|
        AWTEvent previous = null;
 | 
						|
        for (AWTEvent qevt = q.queueHead; qevt != null; qevt = qevt.queueNext)
 | 
						|
          {
 | 
						|
            Object src = qevt.getSource();
 | 
						|
            if (qevt.id == evt.id && src == comp)
 | 
						|
              {
 | 
						|
                // If there are, call coalesceEvents on the source component
 | 
						|
                // to see if they can be combined.
 | 
						|
                Component srccmp = (Component) src;
 | 
						|
                AWTEvent coalescedEvt = srccmp.coalesceEvents(qevt, evt);
 | 
						|
                if (coalescedEvt != null)
 | 
						|
                  {
 | 
						|
                    // Yes. Replace the existing event with the combined event.
 | 
						|
                    if (qevt != coalescedEvt)
 | 
						|
                      {
 | 
						|
                        if (previous != null)
 | 
						|
                          {
 | 
						|
                            assert previous.queueNext == qevt;
 | 
						|
                            previous.queueNext = coalescedEvt;
 | 
						|
                          }
 | 
						|
                        else
 | 
						|
                          {
 | 
						|
                            assert q.queueHead == qevt;
 | 
						|
                            q.queueHead = coalescedEvt;
 | 
						|
                          }
 | 
						|
                        coalescedEvt.queueNext = qevt.queueNext;
 | 
						|
                        if (q.queueTail == qevt)
 | 
						|
                          q.queueTail = coalescedEvt;
 | 
						|
                        qevt.queueNext = null;
 | 
						|
                      }
 | 
						|
                    return;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            previous = qevt;
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    if (q.queueHead == null)
 | 
						|
      {
 | 
						|
        // We have an empty queue. Set this event both as head and as tail.
 | 
						|
        q.queueHead = evt;
 | 
						|
        q.queueTail = evt;
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        // Note: queueTail should not be null here.
 | 
						|
        q.queueTail.queueNext = evt;
 | 
						|
        q.queueTail = evt;
 | 
						|
      }
 | 
						|
 | 
						|
    if (dispatchThread == null || !dispatchThread.isAlive())
 | 
						|
      {
 | 
						|
        dispatchThread = new EventDispatchThread(this);
 | 
						|
        dispatchThread.start();
 | 
						|
      }
 | 
						|
 | 
						|
    notify();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Causes runnable to have its run method called in the dispatch thread of the
 | 
						|
   * EventQueue. This will happen after all pending events are processed. The
 | 
						|
   * call blocks until this has happened. This method will throw an Error if
 | 
						|
   * called from the event dispatcher thread.
 | 
						|
   *
 | 
						|
   * @exception InterruptedException If another thread has interrupted
 | 
						|
   * this thread.
 | 
						|
   * @exception InvocationTargetException If an exception is thrown when running
 | 
						|
   * runnable.
 | 
						|
   *
 | 
						|
   * @since 1.2
 | 
						|
   */
 | 
						|
  public static void invokeAndWait(Runnable runnable)
 | 
						|
    throws InterruptedException, InvocationTargetException
 | 
						|
  {
 | 
						|
    if (isDispatchThread ())
 | 
						|
      throw new Error("Can't call invokeAndWait from event dispatch thread");
 | 
						|
 | 
						|
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 | 
						|
    Object notifyObject = new Object();
 | 
						|
 | 
						|
    InvocationEvent ie =
 | 
						|
      new InvocationEvent(eq, runnable, notifyObject, true);
 | 
						|
 | 
						|
    synchronized (notifyObject)
 | 
						|
      {
 | 
						|
        eq.postEvent(ie);
 | 
						|
        notifyObject.wait();
 | 
						|
      }
 | 
						|
 | 
						|
    Exception exception;
 | 
						|
 | 
						|
    if ((exception = ie.getException()) != null)
 | 
						|
      throw new InvocationTargetException(exception);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This arranges for runnable to have its run method called in the
 | 
						|
   * dispatch thread of the EventQueue.  This will happen after all
 | 
						|
   * pending events are processed.
 | 
						|
   *
 | 
						|
   * @since 1.2
 | 
						|
   */
 | 
						|
  public static void invokeLater(Runnable runnable)
 | 
						|
  {
 | 
						|
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 | 
						|
 | 
						|
    InvocationEvent ie =
 | 
						|
      new InvocationEvent(eq, runnable, null, false);
 | 
						|
 | 
						|
    eq.postEvent(ie);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return true if the current thread is the current AWT event dispatch
 | 
						|
   * thread.
 | 
						|
   */
 | 
						|
  public static boolean isDispatchThread()
 | 
						|
  {
 | 
						|
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 | 
						|
 | 
						|
    /* Find last EventQueue in chain */
 | 
						|
    while (eq.next != null)
 | 
						|
      eq = eq.next;
 | 
						|
 | 
						|
    return (Thread.currentThread() == eq.dispatchThread);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return the event currently being dispatched by the event
 | 
						|
   * dispatch thread.  If the current thread is not the event
 | 
						|
   * dispatch thread, this method returns null.
 | 
						|
   *
 | 
						|
   * @since 1.4
 | 
						|
   */
 | 
						|
  public static AWTEvent getCurrentEvent()
 | 
						|
  {
 | 
						|
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 | 
						|
    Thread ct = Thread.currentThread();
 | 
						|
 | 
						|
    /* Find out if this thread is the dispatch thread for any of the
 | 
						|
       EventQueues in the chain */
 | 
						|
    while (ct != eq.dispatchThread)
 | 
						|
      {
 | 
						|
        // Try next EventQueue, if any
 | 
						|
        if (eq.next == null)
 | 
						|
           return null;  // Not an event dispatch thread
 | 
						|
        eq = eq.next;
 | 
						|
      }
 | 
						|
 | 
						|
    return eq.currentEvent;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Allows a custom EventQueue implementation to replace this one.
 | 
						|
   * All pending events are transferred to the new queue. Calls to postEvent,
 | 
						|
   * getNextEvent, and peekEvent and others are forwarded to the pushed queue
 | 
						|
   * until it is removed with a pop().
 | 
						|
   *
 | 
						|
   * @exception NullPointerException if newEventQueue is null.
 | 
						|
   */
 | 
						|
  public synchronized void push(EventQueue newEventQueue)
 | 
						|
  {
 | 
						|
    if (newEventQueue == null)
 | 
						|
      throw new NullPointerException ();
 | 
						|
 | 
						|
    /* Make sure we are at the top of the stack because callers can
 | 
						|
       only get a reference to the one at the bottom using
 | 
						|
       Toolkit.getDefaultToolkit().getSystemEventQueue() */
 | 
						|
    if (next != null)
 | 
						|
      {
 | 
						|
        next.push (newEventQueue);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
    /* Make sure we have a live dispatch thread to drive the queue */
 | 
						|
    if (dispatchThread == null)
 | 
						|
      dispatchThread = new EventDispatchThread(this);
 | 
						|
 | 
						|
    synchronized (newEventQueue)
 | 
						|
      {
 | 
						|
        // The RI transfers the events without calling the new eventqueue's
 | 
						|
        // push(), but using getNextEvent().
 | 
						|
        while (peekEvent() != null)
 | 
						|
          {
 | 
						|
            try
 | 
						|
              {
 | 
						|
                newEventQueue.postEventImpl(getNextEvent());
 | 
						|
              }
 | 
						|
            catch (InterruptedException ex)
 | 
						|
              {
 | 
						|
                // What should we do with this?
 | 
						|
                ex.printStackTrace();
 | 
						|
              }
 | 
						|
          }
 | 
						|
        newEventQueue.prev = this;
 | 
						|
      }
 | 
						|
 | 
						|
    next = newEventQueue;
 | 
						|
  }
 | 
						|
 | 
						|
  /** Transfer any pending events from this queue back to the parent queue that
 | 
						|
    * was previously push()ed. Event dispatch from this queue is suspended.
 | 
						|
    *
 | 
						|
    * @exception EmptyStackException If no previous push was made on this
 | 
						|
    * EventQueue.
 | 
						|
    */
 | 
						|
  protected void pop() throws EmptyStackException
 | 
						|
  {
 | 
						|
    /* The order is important here, we must get the prev lock first,
 | 
						|
       or deadlock could occur as callers usually get here following
 | 
						|
       prev's next pointer, and thus obtain prev's lock before trying
 | 
						|
       to get this lock. */
 | 
						|
    EventQueue previous = prev;
 | 
						|
    if (previous == null)
 | 
						|
      throw new EmptyStackException();
 | 
						|
    synchronized (previous)
 | 
						|
      {
 | 
						|
        synchronized (this)
 | 
						|
          {
 | 
						|
            EventQueue nextQueue = next;
 | 
						|
            if (nextQueue != null)
 | 
						|
              {
 | 
						|
                nextQueue.pop();
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                previous.next = null;
 | 
						|
 | 
						|
                // The RI transfers the events without calling the new eventqueue's
 | 
						|
                // push(), so this should be OK and most effective.
 | 
						|
                while (peekEvent() != null)
 | 
						|
                  {
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        previous.postEventImpl(getNextEvent());
 | 
						|
                      }
 | 
						|
                    catch (InterruptedException ex)
 | 
						|
                      {
 | 
						|
                        // What should we do with this?
 | 
						|
                        ex.printStackTrace();
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                prev = null;
 | 
						|
                // Tell our EventDispatchThread that it can end
 | 
						|
                // execution.
 | 
						|
                if (dispatchThread != null)
 | 
						|
                  {
 | 
						|
                    dispatchThread.interrupt();
 | 
						|
                    dispatchThread = null;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Dispatches an event. The manner in which the event is dispatched depends
 | 
						|
   * upon the type of the event and the type of the event's source object.
 | 
						|
   *
 | 
						|
   * @exception NullPointerException If event is null.
 | 
						|
   */
 | 
						|
  protected void dispatchEvent(AWTEvent evt)
 | 
						|
  {
 | 
						|
    currentEvent = evt;
 | 
						|
 | 
						|
    if (evt instanceof InputEvent)
 | 
						|
      lastWhen = ((InputEvent) evt).getWhen();
 | 
						|
    else if (evt instanceof ActionEvent)
 | 
						|
      lastWhen = ((ActionEvent) evt).getWhen();
 | 
						|
    else if (evt instanceof InvocationEvent)
 | 
						|
      lastWhen = ((InvocationEvent) evt).getWhen();
 | 
						|
 | 
						|
    if (evt instanceof ActiveEvent)
 | 
						|
      {
 | 
						|
        ActiveEvent active_evt = (ActiveEvent) evt;
 | 
						|
        active_evt.dispatch();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        Object source = evt.getSource();
 | 
						|
 | 
						|
        if (source instanceof Component)
 | 
						|
          {
 | 
						|
            Component srccmp = (Component) source;
 | 
						|
            srccmp.dispatchEvent(evt);
 | 
						|
          }
 | 
						|
        else if (source instanceof MenuComponent)
 | 
						|
          {
 | 
						|
            MenuComponent srccmp = (MenuComponent) source;
 | 
						|
            srccmp.dispatchEvent(evt);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the timestamp of the most recent event that had a timestamp, or
 | 
						|
   * the initialization time of the event queue if no events have been fired.
 | 
						|
   * At present, only <code>InputEvent</code>s, <code>ActionEvent</code>s,
 | 
						|
   * <code>InputMethodEvent</code>s, and <code>InvocationEvent</code>s have
 | 
						|
   * timestamps, but this may be added to other events in future versions.
 | 
						|
   * If this is called by the event dispatching thread, it can be any
 | 
						|
   * (sequential) value, but to other threads, the safest bet is to return
 | 
						|
   * System.currentTimeMillis().
 | 
						|
   *
 | 
						|
   * @return the most recent timestamp
 | 
						|
   * @see InputEvent#getWhen()
 | 
						|
   * @see ActionEvent#getWhen()
 | 
						|
   * @see InvocationEvent#getWhen()
 | 
						|
   * @see InputMethodEvent#getWhen()
 | 
						|
   * @since 1.4
 | 
						|
   */
 | 
						|
  public static long getMostRecentEventTime()
 | 
						|
  {
 | 
						|
    EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
 | 
						|
    if (Thread.currentThread() != eq.dispatchThread)
 | 
						|
      return System.currentTimeMillis();
 | 
						|
    return eq.lastWhen;
 | 
						|
  }
 | 
						|
}
 |