FileDocCategorySizeDatePackage
EventQueue.javaAPI DocJava SE 5 API32783Fri Aug 26 14:56:44 BST 2005java.awt

EventQueue

public class EventQueue extends Object
EventQueue is a platform-independent class that queues events, both from the underlying peer classes and from trusted application classes.

It encapsulates asynchronous event dispatch machinery which extracts events from the queue and dispatches them by calling {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method on this EventQueue with the event to be dispatched as an argument. The particular behavior of this machinery is implementation-dependent. The only requirements are that events which were actually enqueued to this queue (note that events being posted to the EventQueue can be coalesced) are dispatched:

Sequentially.
That is, it is not permitted that several events from this queue are dispatched simultaneously.
In the same order as they are enqueued.
That is, if AWTEvent A is enqueued to the EventQueue before AWTEvent B then event B will not be dispatched before event A.

Some browsers partition applets in different code bases into separate contexts, and establish walls between these contexts. In such a scenario, there will be one EventQueue per context. Other browsers place all applets into the same context, implying that there will be only a single, global EventQueue for all applets. This behavior is implementation-dependent. Consult your browser's documentation for more information.

For information on the threading issues of the event dispatch machinery, see AWT Threading Issues.

author
Thomas Ball
author
Fred Ecks
author
David Mendenhall
version
1.96, 06/28/04
since
1.1

Fields Summary
private static final sun.awt.DebugHelper
dbg
private static int
threadInitNumber
private static final int
LOW_PRIORITY
private static final int
NORM_PRIORITY
private static final int
HIGH_PRIORITY
private static final int
ULTIMATE_PRIORITY
private static final int
NUM_PRIORITIES
private Queue[]
queues
private EventQueue
nextQueue
private EventQueue
previousQueue
private EventDispatchThread
dispatchThread
private final ThreadGroup
threadGroup
private final ClassLoader
classLoader
private static final boolean
debug
private long
mostRecentEventTime
private WeakReference
currentEvent
The modifiers field of the current event, if the current event is an InputEvent or ActionEvent.
private int
waitForID
private final String
name
Constructors Summary
public EventQueue()


      
        for (int i = 0; i < NUM_PRIORITIES; i++) {
	    queues[i] = new Queue();
	}
        /* 
         * NOTE: if you ever have to start the associated event dispatch 
         * thread at this point, be aware of the following problem:
         * If this EventQueue instance is created in 
         * SunToolkit.createNewAppContext() the started dispatch thread
         * may call AppContext.getAppContext() before createNewAppContext()
         * completes thus causing mess in thread group to appcontext mapping.
         */
    
Methods Summary
final voiddetachDispatchThread()

        dispatchThread = null;
    
protected voiddispatchEvent(java.awt.AWTEvent event)
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:

Event Type Source Type Dispatched To
ActiveEvent Any event.dispatch()
Other Component source.dispatchEvent(AWTEvent)
Other MenuComponent source.dispatchEvent(AWTEvent)
Other Other No action (ignored)

param
event an instance of java.awt.AWTEvent, or a subclass of it
throws
NullPointerException if event is null

        event.isPosted = true;
        Object src = event.getSource();
        if (event instanceof ActiveEvent) {
            // This could become the sole method of dispatching in time.
            setCurrentEventAndMostRecentTimeImpl(event);

            ((ActiveEvent)event).dispatch();
        } else if (src instanceof Component) {
            ((Component)src).dispatchEvent(event);
            event.dispatched();
        } else if (src instanceof MenuComponent) {
            ((MenuComponent)src).dispatchEvent(event);
        } else if (src instanceof AWTAutoShutdown) {
            if (noEvents()) {
                dispatchThread.stopDispatching();
            }
        } else {
            System.err.println("unable to dispatch event: " + event);
        }
    
public static java.awt.AWTEventgetCurrentEvent()
Returns the the event currently being dispatched by the EventQueue associated with the calling thread. This is useful if a method needs access to the event, but was not designed to receive a reference to it as an argument. Note that this method should only be invoked from an application's event dispatching thread. If this method is invoked from another thread, null will be returned.

return
the event currently being dispatched, or null if this method is invoked on a thread other than an event dispatching thread
since
1.4

        return Toolkit.getEventQueue().getCurrentEventImpl();
    
private synchronized java.awt.AWTEventgetCurrentEventImpl()

        return (Thread.currentThread() == dispatchThread)
            ? ((AWTEvent)currentEvent.get())
            : null;
    
final java.awt.EventDispatchThreadgetDispatchThread()

	return dispatchThread;
    
public static longgetMostRecentEventTime()
Returns the timestamp of the most recent event that had a timestamp, and that was dispatched from the EventQueue associated with the calling thread. If an event with a timestamp is currently being dispatched, its timestamp will be returned. If no events have yet been dispatched, the EventQueue's initialization time will be returned instead.In the current version of the JDK, only InputEvents, ActionEvents, and InvocationEvents have timestamps; however, future versions of the JDK may add timestamps to additional event types. Note that this method should only be invoked from an application's event dispatching thread. If this method is invoked from another thread, the current system time (as reported by System.currentTimeMillis()) will be returned instead.

return
the timestamp of the last InputEvent, ActionEvent, or InvocationEvent to be dispatched, or System.currentTimeMillis() if this method is invoked on a thread other than an event dispatching thread
see
java.awt.event.InputEvent#getWhen
see
java.awt.event.ActionEvent#getWhen
see
java.awt.event.InvocationEvent#getWhen
since
1.4

        return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
    
synchronized longgetMostRecentEventTimeEx()

return
most recent event time on all threads.

        return mostRecentEventTime;
    
private synchronized longgetMostRecentEventTimeImpl()

        return (Thread.currentThread() == dispatchThread)
            ? mostRecentEventTime
            : System.currentTimeMillis();
    
public java.awt.AWTEventgetNextEvent()
Removes an event from the EventQueue and returns it. This method will block until an event has been posted by another thread.

return
the next AWTEvent
exception
InterruptedException if another thread has interrupted this thread

        do {
            /*
             * SunToolkit.flushPendingEvents must be called outside
             * of the synchronized block to avoid deadlock when 
             * event queues are nested with push()/pop(). 
             */
            SunToolkit.flushPendingEvents();
            synchronized (this) {
                for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
                    if (queues[i].head != null) {
                        EventQueueItem eqi = queues[i].head;
                        queues[i].head = eqi.next;
                        if (eqi.next == null) {
                            queues[i].tail = null;
                        }
                        return eqi.event;
                    }
                }
                AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
                wait();
            }
        } while(true);
    
java.awt.AWTEventgetNextEvent(int id)

	do {
            /*
             * SunToolkit.flushPendingEvents must be called outside
             * of the synchronized block to avoid deadlock when 
             * event queues are nested with push()/pop(). 
             */
            SunToolkit.flushPendingEvents();
            synchronized (this) {
                for (int i = 0; i < NUM_PRIORITIES; i++) {
                    for (EventQueueItem entry = queues[i].head, prev = null;
                         entry != null; prev = entry, entry = entry.next)
                    {
                        if (entry.id == id) {
                            if (prev == null) {
                                queues[i].head = entry.next;
                            } else {
                                prev.next = entry.next;
                            }
                            if (queues[i].tail == entry) {
                                queues[i].tail = prev;
                            }
                            return entry.event;
                        }
                    }
                }
                this.waitForID = id;
                wait();
                this.waitForID = 0;
            }
	} while(true);
    
final voidinitDispatchThread()

 
        synchronized (this) {
            if (dispatchThread == null && !threadGroup.isDestroyed()) {
                dispatchThread = (EventDispatchThread)
                    AccessController.doPrivileged(new PrivilegedAction() {
                        public Object run() {
                            EventDispatchThread t = 
                                new EventDispatchThread(threadGroup, 
                                                        name, 
                                                        EventQueue.this);
                            t.setContextClassLoader(classLoader);
                            t.setPriority(Thread.NORM_PRIORITY + 1);
                            t.setDaemon(false);
                            return t;
                        }
                    });                            
                AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
                dispatchThread.start();
            }
        }
    
public static voidinvokeAndWait(java.lang.Runnable runnable)
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.

param
runnable the Runnable whose run method should be executed synchronously on the EventQueue
exception
InterruptedException if another thread has interrupted this thread
exception
InvocationTargetException if an throwable is thrown when running runnable
see
#invokeLater
since
1.2


        if (EventQueue.isDispatchThread()) {
            throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
        }

	class AWTInvocationLock {}
        Object lock = new AWTInvocationLock();

        InvocationEvent event = 
            new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
				true);

        synchronized (lock) {
            Toolkit.getEventQueue().postEvent(event);
            lock.wait();
        }

        Throwable eventThrowable = event.getThrowable();
        if (eventThrowable != null) {
            throw new InvocationTargetException(eventThrowable);
        }
    
public static voidinvokeLater(java.lang.Runnable runnable)
Causes runnable to have its run method called in the dispatch thread of the EventQueue. This will happen after all pending events are processed.

param
runnable the Runnable whose run method should be executed synchronously on the EventQueue
see
#invokeAndWait
since
1.2

        Toolkit.getEventQueue().postEvent(
            new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
    
public static booleanisDispatchThread()
Returns true if the calling thread is the current AWT EventQueue's dispatch thread. Use this call the ensure that a given task is being executed (or not being) on the current AWT EventDispatchThread.

return
true if running on the current AWT EventQueue's dispatch thread

	EventQueue eq = Toolkit.getEventQueue();
	EventQueue next = eq.nextQueue;
	while (next != null) {
	    eq = next;
	    next = eq.nextQueue;
	}
	return (Thread.currentThread() == eq.dispatchThread);
    
private static synchronized intnextThreadNum()

         
	return threadInitNumber++;
    
private booleannoEvents()
Returns whether an event is pending on any of the separate Queues.

return
whether an event is pending on any of the separate Queues

        for (int i = 0; i < NUM_PRIORITIES; i++) {
	    if (queues[i].head != null) {
	        return false;
	    }
	}

	return true;
    
public synchronized java.awt.AWTEventpeekEvent(int id)
Returns the first event with the specified id, if any.

param
id the id of the type of event desired
return
the first event of the specified id or null if there is no such event

        for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
	    EventQueueItem q = queues[i].head;
	    for (; q != null; q = q.next) {
	        if (q.id == id) {
		    return q.event;
		}
	    }
	}

        return null;
    
public synchronized java.awt.AWTEventpeekEvent()
Returns the first event on the EventQueue without removing it.

return
the first event

        for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
	    if (queues[i].head != null) {
	        return queues[i].head.event;
	    }
	}

	return null;
    
protected voidpop()
Stops dispatching events using this EventQueue. Any pending events are transferred to the previous EventQueue for processing.

Warning: To avoid deadlock, do not declare this method synchronized in a subclass.

exception
EmptyStackException if no previous push was made on this EventQueue
see
java.awt.EventQueue#push

	if (debug) {
	    System.out.println("EventQueue.pop(" + this + ")");
	}

	// To prevent deadlock, we lock on the previous EventQueue before
	// this one.  This uses the same locking order as everything else
	// in EventQueue.java, so deadlock isn't possible.
	EventQueue prev = previousQueue;
	synchronized ((prev != null) ? prev : this) {
	  synchronized(this) {
            if (nextQueue != null) {
                nextQueue.pop();
                return;
            }
            if (previousQueue == null) {
                throw new EmptyStackException();
            }

	    // Transfer all events back to previous EventQueue.
	    previousQueue.nextQueue = null;
	    while (peekEvent() != null) {
		try {
		    previousQueue.postEventPrivate(getNextEvent());
		} catch (InterruptedException ie) {
		    if (debug) {
			System.err.println("interrupted pop:");
			ie.printStackTrace(System.err);
		    }
		}
	    }
            AppContext appContext = AppContext.getAppContext();
            if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
                appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
            }

	    previousQueue = null;
          }
        }

        EventDispatchThread dt = this.dispatchThread;
        if (dt != null) {
            dt.stopDispatching(); // Must be done outside synchronized
                                  // block to avoid possible deadlock
        }
    
public voidpostEvent(java.awt.AWTEvent theEvent)
Posts a 1.1-style event to the EventQueue. If there is an existing event on the queue with the same ID and event source, the source Component's coalesceEvents method will be called.

param
theEvent an instance of java.awt.AWTEvent, or a subclass of it
throws
NullPointerException if theEvent is null

        SunToolkit.flushPendingEvents();
        postEventPrivate(theEvent);
    
private voidpostEvent(java.awt.AWTEvent theEvent, int priority)
Posts the event to the internal Queue of specified priority, coalescing as appropriate.

param
theEvent an instance of java.awt.AWTEvent, or a subclass of it
param
priority the desired priority of the event


        if (dispatchThread == null) {
            if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
                return;
            } else {
                initDispatchThread();
            }
        }

	Object source = theEvent.getSource();

	// Expanding RepaintArea
	if (source instanceof Component) {
	    ComponentPeer sourcePeer = ((Component)source).peer;
	    if (sourcePeer != null && theEvent instanceof PaintEvent &&
                !(sourcePeer instanceof LightweightPeer)) { 
		sourcePeer.coalescePaintEvent((PaintEvent)theEvent);
	    }
	}

        EventQueueItem newItem = new EventQueueItem(theEvent);

        boolean notifyID = (theEvent.getID() == this.waitForID);
	
	if (queues[priority].head == null) {
            boolean shouldNotify = noEvents();
	    queues[priority].head = queues[priority].tail = newItem;

	    if (shouldNotify) {
                if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
                    AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
                }
	        notifyAll();
	    } else if (notifyID) {
                notifyAll();
            }
	} else {
	    boolean isPeerEvent = theEvent instanceof PeerEvent;
           
	    // For Component source events, traverse the entire list,
	    // trying to coalesce events
	    if (source instanceof Component) {
                EventQueueItem q = queues[priority].head;

                if (theEvent.id == Event.MOUSE_MOVE ||
                    theEvent.id == Event.MOUSE_DRAG) {
                    EventQueueItem qm;
                    for(qm = q; qm != null; qm = qm.next) {
                        if ((qm.event instanceof MouseEvent) &&
                            qm.id != theEvent.id) {
                            q = qm;
                        }
                    }
                }

		for (; q != null; q = q.next)  {
		    // Give Component.coalesceEvents a chance
		    if (q.event.getSource() == source && q.id == newItem.id) {
			AWTEvent coalescedEvent = ((Component)source).coalesceEvents(q.event, theEvent);
			if (isPeerEvent && coalescedEvent == null && q.event instanceof PeerEvent) {
			    coalescedEvent = ((PeerEvent)q.event).coalesceEvents((PeerEvent)theEvent);
			}
			if (coalescedEvent != null) {
			    // Remove debugging statement because
			    // calling AWTEvent.toString here causes a
			    // deadlock.
			    q.event = coalescedEvent;
			    return;
			}
		    }
		}
	    }
            // The event was not coalesced or has non-Component source.
            // Insert it at the end of the appropriate Queue.
	    queues[priority].tail.next = newItem;
	    queues[priority].tail = newItem;
            if (notifyID) {
                notifyAll();
            }
	}
    
final voidpostEventPrivate(java.awt.AWTEvent theEvent)
Posts a 1.1-style event to the EventQueue. If there is an existing event on the queue with the same ID and event source, the source Component's coalesceEvents method will be called.

param
theEvent an instance of java.awt.AWTEvent, or a subclass of it

        theEvent.isPosted = true;
        synchronized(this) {
            int id = theEvent.getID();
            if (nextQueue != null) {
                // Forward event to top of EventQueue stack.
                nextQueue.postEventPrivate(theEvent);
            } else if (theEvent instanceof PeerEvent &&
                           (((PeerEvent)theEvent).getFlags() & 
                            PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
                postEvent(theEvent, ULTIMATE_PRIORITY);
            } else if (theEvent instanceof PeerEvent &&
                       (((PeerEvent)theEvent).getFlags() & 
                                       PeerEvent.PRIORITY_EVENT) != 0) {
                postEvent(theEvent, HIGH_PRIORITY);
            } else if (id == PaintEvent.PAINT ||
                       id == PaintEvent.UPDATE) {
                postEvent(theEvent, LOW_PRIORITY);
            } else {
                postEvent(theEvent, NORM_PRIORITY);
            }
        }
    
public synchronized voidpush(java.awt.EventQueue newEventQueue)
Replaces the existing EventQueue with the specified one. Any pending events are transferred to the new EventQueue for processing by it.

param
newEventQueue an EventQueue (or subclass thereof) instance to be use
see
java.awt.EventQueue#pop
throws
NullPointerException if newEventQueue is null

	if (debug) {
	    System.out.println("EventQueue.push(" + newEventQueue + ")");
	}

        if (nextQueue != null) {
            nextQueue.push(newEventQueue);
            return;
        }

        synchronized (newEventQueue) {
	    // Transfer all events forward to new EventQueue.
	    while (peekEvent() != null) {
		try {
		    newEventQueue.postEventPrivate(getNextEvent());
		} catch (InterruptedException ie) {
		    if (debug) {
			System.err.println("interrupted push:");
			ie.printStackTrace(System.err);
		    }
		}
	    }

	    newEventQueue.previousQueue = this;
        }
        /* 
         * Stop the event dispatch thread associated with the currently 
         * active event queue, so that after the new queue is pushed
         * on the top this event dispatch thread won't prevent AWT from
         * being automatically shut down.
         * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
         * waits for the dispatch thread to exit, so if the dispatch
         * thread attempts to synchronize on this EventQueue object
         * it will never exit since we already hold this lock.
         */
        if (dispatchThread != null) {
            dispatchThread.stopDispatchingLater();
        }

	nextQueue = newEventQueue;
	
        AppContext appContext = AppContext.getAppContext();
        if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
	    appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
        }
    
final voidremoveSourceEvents(java.lang.Object source, boolean removeAllEvents)

        SunToolkit.flushPendingEvents();
        synchronized (this) {
            for (int i = 0; i < NUM_PRIORITIES; i++) {
                EventQueueItem entry = queues[i].head;
                EventQueueItem prev = null;
                while (entry != null) {
                    if ((entry.event.getSource() == source) 
                        && (removeAllEvents 
                            || ! (entry.event instanceof SequencedEvent 
                                  || entry.event instanceof SentEvent
                                  || entry.event instanceof FocusEvent
                                  || entry.event instanceof WindowEvent
                                  || entry.event instanceof KeyEvent
                                  || entry.event instanceof InputMethodEvent)))
                    {
                        if (entry.event instanceof SequencedEvent) {
                            ((SequencedEvent)entry.event).dispose();
                        }
                        if (entry.event instanceof SentEvent) {
                            ((SentEvent)entry.event).dispose();
                        }
                        if (prev == null) {
                            queues[i].head = entry.next;
                        } else {
                            prev.next = entry.next;
                        }
                    } else {
                        prev = entry;
                    }
                    entry = entry.next;
                }
                queues[i].tail = prev;
            }
        }
    
static voidsetCurrentEventAndMostRecentTime(java.awt.AWTEvent e)

        Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
    
private synchronized voidsetCurrentEventAndMostRecentTimeImpl(java.awt.AWTEvent e)

        if (Thread.currentThread() != dispatchThread) {
            return;
        }

        currentEvent = new WeakReference(e);

        // This series of 'instanceof' checks should be replaced with a
        // polymorphic type (for example, an interface which declares a
        // getWhen() method). However, this would require us to make such
        // a type public, or to place it in sun.awt. Both of these approaches
        // have been frowned upon. So for now, we hack.
        //
        // In tiger, we will probably give timestamps to all events, so this
        // will no longer be an issue.
        if (e instanceof InputEvent) {
            InputEvent ie = (InputEvent)e;
            mostRecentEventTime = ie.getWhen();
        } else if (e instanceof InputMethodEvent) {
            InputMethodEvent ime = (InputMethodEvent)e;
            mostRecentEventTime = ime.getWhen();
        } else if (e instanceof ActionEvent) {
            ActionEvent ae = (ActionEvent)e;
            mostRecentEventTime = ae.getWhen();
        } else if (e instanceof InvocationEvent) {
            InvocationEvent ie = (InvocationEvent)e;
            mostRecentEventTime = ie.getWhen();
        }
    
private voidwakeup(boolean isShutdown)

        synchronized(this) {
            if (nextQueue != null) {
                // Forward call to the top of EventQueue stack.
                nextQueue.wakeup(isShutdown);
            } else if (dispatchThread != null) {
                notifyAll();
            } else if (!isShutdown) {
                initDispatchThread();
            }
        }