Home » openjdk-7 » java » awt » [javadoc | source]

    1   /*
    2    * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.awt;
   27   
   28   import java.util.LinkedList;
   29   import sun.awt.AppContext;
   30   import sun.awt.SunToolkit;
   31   
   32   /**
   33    * A mechanism for ensuring that a series of AWTEvents are executed in a
   34    * precise order, even across multiple AppContexts. The nested events will be
   35    * dispatched in the order in which their wrapping SequencedEvents were
   36    * constructed. The only exception to this rule is if the peer of the target of
   37    * the nested event was destroyed (with a call to Component.removeNotify)
   38    * before the wrapping SequencedEvent was able to be dispatched. In this case,
   39    * the nested event is never dispatched.
   40    *
   41    * @author David Mendenhall
   42    */
   43   class SequencedEvent extends AWTEvent implements ActiveEvent {
   44       /*
   45        * serialVersionUID
   46        */
   47       private static final long serialVersionUID = 547742659238625067L;
   48   
   49       private static final int ID =
   50           java.awt.event.FocusEvent.FOCUS_LAST + 1;
   51       private static final LinkedList list = new LinkedList();
   52   
   53       private final AWTEvent nested;
   54       private AppContext appContext;
   55       private boolean disposed;
   56   
   57       /**
   58        * Constructs a new SequencedEvent which will dispatch the specified
   59        * nested event.
   60        *
   61        * @param nested the AWTEvent which this SequencedEvent's dispatch()
   62        *        method will dispatch
   63        */
   64       public SequencedEvent(AWTEvent nested) {
   65           super(nested.getSource(), ID);
   66           this.nested = nested;
   67           // All AWTEvents that are wrapped in SequencedEvents are (at
   68           // least currently) implicitly generated by the system
   69           SunToolkit.setSystemGenerated(nested);
   70           synchronized (SequencedEvent.class) {
   71               list.add(this);
   72           }
   73       }
   74   
   75       /**
   76        * Dispatches the nested event after all previous nested events have been
   77        * dispatched or disposed. If this method is invoked before all previous nested events
   78        * have been dispatched, then this method blocks until such a point is
   79        * reached.
   80        * While waiting disposes nested events to disposed AppContext
   81        *
   82        * NOTE: Locking protocol.  Since dispose() can get EventQueue lock,
   83        * dispatch() shall never call dispose() while holding the lock on the list,
   84        * as EventQueue lock is held during dispatching.  The locks should be acquired
   85        * in the same order.
   86        */
   87       public final void dispatch() {
   88           try {
   89               appContext = AppContext.getAppContext();
   90   
   91               if (getFirst() != this) {
   92                   if (EventQueue.isDispatchThread()) {
   93                       EventDispatchThread edt = (EventDispatchThread)
   94                           Thread.currentThread();
   95                       edt.pumpEvents(SentEvent.ID, new Conditional() {
   96                           public boolean evaluate() {
   97                               return !SequencedEvent.this.isFirstOrDisposed();
   98                           }
   99                       });
  100                   } else {
  101                       while(!isFirstOrDisposed()) {
  102                           synchronized (SequencedEvent.class) {
  103                               try {
  104                                   SequencedEvent.class.wait(1000);
  105                               } catch (InterruptedException e) {
  106                                   break;
  107                               }
  108                           }
  109                       }
  110                   }
  111               }
  112   
  113               if (!disposed) {
  114                   KeyboardFocusManager.getCurrentKeyboardFocusManager().
  115                       setCurrentSequencedEvent(this);
  116                   Toolkit.getEventQueue().dispatchEvent(nested);
  117               }
  118           } finally {
  119               dispose();
  120           }
  121       }
  122   
  123       /**
  124        * true only if event exists and nested source appContext is disposed.
  125        */
  126       private final static boolean isOwnerAppContextDisposed(SequencedEvent se) {
  127           if (se != null) {
  128               Object target = se.nested.getSource();
  129               if (target instanceof Component) {
  130                   return ((Component)target).appContext.isDisposed();
  131               }
  132           }
  133           return false;
  134       }
  135   
  136       /**
  137        * Sequenced events are dispatched in order, so we cannot dispatch
  138        * until we are the first sequenced event in the queue (i.e. it's our
  139        * turn).  But while we wait for our turn to dispatch, the event
  140        * could have been disposed for a number of reasons.
  141        */
  142       public final boolean isFirstOrDisposed() {
  143           if (disposed) {
  144               return true;
  145           }
  146           // getFirstWithContext can dispose this
  147           return this == getFirstWithContext() || disposed;
  148       }
  149   
  150       private final synchronized static SequencedEvent getFirst() {
  151           return (SequencedEvent)list.getFirst();
  152       }
  153   
  154       /* Disposes all events from disposed AppContext
  155        * return first valid event
  156        */
  157       private final static SequencedEvent getFirstWithContext() {
  158           SequencedEvent first = getFirst();
  159           while(isOwnerAppContextDisposed(first)) {
  160               first.dispose();
  161               first = getFirst();
  162           }
  163           return first;
  164       }
  165   
  166       /**
  167        * Disposes of this instance. This method is invoked once the nested event
  168        * has been dispatched and handled, or when the peer of the target of the
  169        * nested event has been disposed with a call to Component.removeNotify.
  170        *
  171        * NOTE: Locking protocol.  Since SunToolkit.postEvent can get EventQueue lock,
  172        * it shall never be called while holding the lock on the list,
  173        * as EventQueue lock is held during dispatching and dispatch() will get
  174        * lock on the list. The locks should be acquired in the same order.
  175        */
  176       final void dispose() {
  177         synchronized (SequencedEvent.class) {
  178               if (disposed) {
  179                   return;
  180               }
  181               if (KeyboardFocusManager.getCurrentKeyboardFocusManager().
  182                       getCurrentSequencedEvent() == this) {
  183                   KeyboardFocusManager.getCurrentKeyboardFocusManager().
  184                       setCurrentSequencedEvent(null);
  185               }
  186               disposed = true;
  187           }
  188           // Wake myself up
  189           if (appContext != null) {
  190               SunToolkit.postEvent(appContext, new SentEvent());
  191           }
  192   
  193           SequencedEvent next = null;
  194   
  195           synchronized (SequencedEvent.class) {
  196             SequencedEvent.class.notifyAll();
  197   
  198             if (list.getFirst() == this) {
  199                 list.removeFirst();
  200   
  201                 if (!list.isEmpty()) {
  202                       next = (SequencedEvent)list.getFirst();
  203                 }
  204             } else {
  205                 list.remove(this);
  206             }
  207         }
  208           // Wake up waiting threads
  209           if (next != null && next.appContext != null) {
  210               SunToolkit.postEvent(next.appContext, new SentEvent());
  211           }
  212       }
  213   }

Home » openjdk-7 » java » awt » [javadoc | source]