0N/A/*
3261N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.awt;
0N/A
0N/Aimport java.util.LinkedList;
5484N/Aimport sun.awt.AWTAccessor;
0N/Aimport sun.awt.AppContext;
0N/Aimport sun.awt.SunToolkit;
0N/A
0N/A/**
0N/A * A mechanism for ensuring that a series of AWTEvents are executed in a
0N/A * precise order, even across multiple AppContexts. The nested events will be
0N/A * dispatched in the order in which their wrapping SequencedEvents were
0N/A * constructed. The only exception to this rule is if the peer of the target of
0N/A * the nested event was destroyed (with a call to Component.removeNotify)
0N/A * before the wrapping SequencedEvent was able to be dispatched. In this case,
0N/A * the nested event is never dispatched.
0N/A *
0N/A * @author David Mendenhall
0N/A */
0N/Aclass SequencedEvent extends AWTEvent implements ActiveEvent {
0N/A /*
0N/A * serialVersionUID
0N/A */
0N/A private static final long serialVersionUID = 547742659238625067L;
0N/A
0N/A private static final int ID =
0N/A java.awt.event.FocusEvent.FOCUS_LAST + 1;
0N/A private static final LinkedList list = new LinkedList();
0N/A
0N/A private final AWTEvent nested;
0N/A private AppContext appContext;
0N/A private boolean disposed;
0N/A
5484N/A static {
5484N/A AWTAccessor.setSequencedEventAccessor(new AWTAccessor.SequencedEventAccessor() {
5484N/A public AWTEvent getNested(AWTEvent sequencedEvent) {
5484N/A return ((SequencedEvent)sequencedEvent).nested;
5484N/A }
5484N/A public boolean isSequencedEvent(AWTEvent event) {
5484N/A return event instanceof SequencedEvent;
5484N/A }
5484N/A });
5484N/A }
5484N/A
0N/A /**
0N/A * Constructs a new SequencedEvent which will dispatch the specified
0N/A * nested event.
0N/A *
0N/A * @param nested the AWTEvent which this SequencedEvent's dispatch()
0N/A * method will dispatch
0N/A */
0N/A public SequencedEvent(AWTEvent nested) {
0N/A super(nested.getSource(), ID);
0N/A this.nested = nested;
2860N/A // All AWTEvents that are wrapped in SequencedEvents are (at
2860N/A // least currently) implicitly generated by the system
2860N/A SunToolkit.setSystemGenerated(nested);
0N/A synchronized (SequencedEvent.class) {
0N/A list.add(this);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Dispatches the nested event after all previous nested events have been
0N/A * dispatched or disposed. If this method is invoked before all previous nested events
0N/A * have been dispatched, then this method blocks until such a point is
0N/A * reached.
0N/A * While waiting disposes nested events to disposed AppContext
0N/A *
0N/A * NOTE: Locking protocol. Since dispose() can get EventQueue lock,
0N/A * dispatch() shall never call dispose() while holding the lock on the list,
0N/A * as EventQueue lock is held during dispatching. The locks should be acquired
0N/A * in the same order.
0N/A */
0N/A public final void dispatch() {
0N/A try {
0N/A appContext = AppContext.getAppContext();
0N/A
0N/A if (getFirst() != this) {
0N/A if (EventQueue.isDispatchThread()) {
0N/A EventDispatchThread edt = (EventDispatchThread)
0N/A Thread.currentThread();
0N/A edt.pumpEvents(SentEvent.ID, new Conditional() {
0N/A public boolean evaluate() {
0N/A return !SequencedEvent.this.isFirstOrDisposed();
0N/A }
0N/A });
0N/A } else {
0N/A while(!isFirstOrDisposed()) {
0N/A synchronized (SequencedEvent.class) {
0N/A try {
0N/A SequencedEvent.class.wait(1000);
0N/A } catch (InterruptedException e) {
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (!disposed) {
0N/A KeyboardFocusManager.getCurrentKeyboardFocusManager().
0N/A setCurrentSequencedEvent(this);
0N/A Toolkit.getEventQueue().dispatchEvent(nested);
0N/A }
0N/A } finally {
0N/A dispose();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * true only if event exists and nested source appContext is disposed.
0N/A */
0N/A private final static boolean isOwnerAppContextDisposed(SequencedEvent se) {
0N/A if (se != null) {
0N/A Object target = se.nested.getSource();
0N/A if (target instanceof Component) {
0N/A return ((Component)target).appContext.isDisposed();
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Sequenced events are dispatched in order, so we cannot dispatch
0N/A * until we are the first sequenced event in the queue (i.e. it's our
0N/A * turn). But while we wait for our turn to dispatch, the event
0N/A * could have been disposed for a number of reasons.
0N/A */
0N/A public final boolean isFirstOrDisposed() {
0N/A if (disposed) {
0N/A return true;
0N/A }
0N/A // getFirstWithContext can dispose this
0N/A return this == getFirstWithContext() || disposed;
0N/A }
0N/A
0N/A private final synchronized static SequencedEvent getFirst() {
0N/A return (SequencedEvent)list.getFirst();
0N/A }
0N/A
0N/A /* Disposes all events from disposed AppContext
0N/A * return first valid event
0N/A */
0N/A private final static SequencedEvent getFirstWithContext() {
0N/A SequencedEvent first = getFirst();
0N/A while(isOwnerAppContextDisposed(first)) {
0N/A first.dispose();
0N/A first = getFirst();
0N/A }
0N/A return first;
0N/A }
0N/A
0N/A /**
0N/A * Disposes of this instance. This method is invoked once the nested event
0N/A * has been dispatched and handled, or when the peer of the target of the
0N/A * nested event has been disposed with a call to Component.removeNotify.
0N/A *
0N/A * NOTE: Locking protocol. Since SunToolkit.postEvent can get EventQueue lock,
0N/A * it shall never be called while holding the lock on the list,
0N/A * as EventQueue lock is held during dispatching and dispatch() will get
0N/A * lock on the list. The locks should be acquired in the same order.
0N/A */
0N/A final void dispose() {
0N/A synchronized (SequencedEvent.class) {
0N/A if (disposed) {
0N/A return;
0N/A }
0N/A if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
0N/A getCurrentSequencedEvent() == this) {
0N/A KeyboardFocusManager.getCurrentKeyboardFocusManager().
0N/A setCurrentSequencedEvent(null);
0N/A }
0N/A disposed = true;
0N/A }
0N/A // Wake myself up
0N/A if (appContext != null) {
0N/A SunToolkit.postEvent(appContext, new SentEvent());
0N/A }
0N/A
0N/A SequencedEvent next = null;
0N/A
0N/A synchronized (SequencedEvent.class) {
0N/A SequencedEvent.class.notifyAll();
0N/A
0N/A if (list.getFirst() == this) {
0N/A list.removeFirst();
0N/A
0N/A if (!list.isEmpty()) {
0N/A next = (SequencedEvent)list.getFirst();
0N/A }
0N/A } else {
0N/A list.remove(this);
0N/A }
0N/A }
0N/A // Wake up waiting threads
0N/A if (next != null && next.appContext != null) {
0N/A SunToolkit.postEvent(next.appContext, new SentEvent());
0N/A }
0N/A }
0N/A}