FileDocCategorySizeDatePackage
SequencedEvent.javaAPI DocJava SE 5 API6668Fri Aug 26 14:56:46 BST 2005java.awt

SequencedEvent

public class SequencedEvent extends AWTEvent implements ActiveEvent
A mechanism for ensuring that a series of AWTEvents are executed in a precise order, even across multiple AppContexts. The nested events will be dispatched in the order in which their wrapping SequencedEvents were constructed. The only exception to this rule is if the peer of the target of the nested event was destroyed (with a call to Component.removeNotify) before the wrapping SequencedEvent was able to be dispatched. In this case, the nested event is never dispatched.
version
1.10, 12/19/03
author
David Mendenhall

Fields Summary
private static final int
ID
private static final LinkedList
list
private final AWTEvent
nested
private AppContext
appContext
private boolean
disposed
Constructors Summary
public SequencedEvent(AWTEvent nested)
Constructs a new SequencedEvent which will dispatch the specified nested event.

param
nested the AWTEvent which this SequencedEvent's dispatch() method will dispatch


                                      
       
	super(nested.getSource(), ID);
	this.nested = nested;
	synchronized (SequencedEvent.class) {
	    list.add(this);
	}
    
Methods Summary
public final voiddispatch()
Dispatches the nested event after all previous nested events have been dispatched or disposed. If this method is invoked before all previous nested events have been dispatched, then this method blocks until such a point is reached. While waiting disposes nested events to disposed AppContext NOTE: Locking protocol. Since dispose() can get EventQueue lock, dispatch() shall never call dispose() while holding the lock on the list, as EventQueue lock is held during dispatching. The locks should be acquired in the same order.

        try {
            appContext = AppContext.getAppContext();

            if (getFirst() != this) {
                if (EventQueue.isDispatchThread()) {
                    EventDispatchThread edt = (EventDispatchThread)
                        Thread.currentThread();
                    edt.pumpEvents(SentEvent.ID, new Conditional() {
                        public boolean evaluate() {
                            return !SequencedEvent.this.isFirstOrDisposed();
                        }
                    });
                } else {
                    while(!isFirstOrDisposed()) {
                        synchronized (SequencedEvent.class) {
                            try {                             
                                SequencedEvent.class.wait(1000);
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                    }
                }
            }

            if (!disposed) {
                KeyboardFocusManager.getCurrentKeyboardFocusManager().
                    setCurrentSequencedEvent(this);
                Toolkit.getEventQueue().dispatchEvent(nested);
            }
        } finally {
            dispose();
        }
    
final voiddispose()
Disposes of this instance. This method is invoked once the nested event has been dispatched and handled, or when the peer of the target of the nested event has been disposed with a call to Component.removeNotify. NOTE: Locking protocol. Since SunToolkit.postEvent can get EventQueue lock, it shall never be called while holding the lock on the list, as EventQueue lock is held during dispatching and dispatch() will get lock on the list. The locks should be acquired in the same order.

      synchronized (SequencedEvent.class) {
            if (disposed) {
                return;
            }
            if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
                    getCurrentSequencedEvent() == this) {
                KeyboardFocusManager.getCurrentKeyboardFocusManager().
                    setCurrentSequencedEvent(null);
            }
            disposed = true;
        }
        // Wake myself up
        if (appContext != null) {
            SunToolkit.postEvent(appContext, new SentEvent());
        }
        
        SequencedEvent next = null;
        
        synchronized (SequencedEvent.class) {
          SequencedEvent.class.notifyAll();

          if (list.getFirst() == this) {
              list.removeFirst();

              if (!list.isEmpty()) {
                    next = (SequencedEvent)list.getFirst();
              }
          } else {
              list.remove(this);
          }
      }
        // Wake up waiting threads
        if (next != null && next.appContext != null) {
            SunToolkit.postEvent(next.appContext, new SentEvent());
        }
    
private static final synchronized java.awt.SequencedEventgetFirst()

        return (SequencedEvent)list.getFirst();
    
private static final java.awt.SequencedEventgetFirstWithContext()

        SequencedEvent first = getFirst();
        while(isOwnerAppContextDisposed(first)) {
            first.dispose();
            first = getFirst();
        }        
        return first;
    
public final booleanisFirstOrDisposed()
Sequenced events are dispatched in order, so we cannot dispatch until we are the first sequenced event in the queue (i.e. it's our turn). But while we wait for our turn to dispatch, the event could have been disposed for a number of reasons.

        if (disposed) {
            return true;
        }
        // getFirstWithContext can dispose this
        return this == getFirstWithContext() || disposed;
    
private static final booleanisOwnerAppContextDisposed(java.awt.SequencedEvent se)
true only if event exists and nested source appContext is disposed.

        if (se != null) {
            Object target = se.nested.getSource();
            if (target instanceof Component) {
                return ((Component)target).appContext.isDisposed();
            }
        }
        return false;