Save This Page
Home » openjdk-7 » java » awt » [javadoc | source]
    1   /*
    2    * Copyright 1996-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.awt;
   27   
   28   import java.awt.event;
   29   
   30   import java.awt.peer.ComponentPeer;
   31   
   32   import java.lang.ref.WeakReference;
   33   import java.lang.reflect.InvocationTargetException;
   34   
   35   import java.security.AccessController;
   36   import java.security.PrivilegedAction;
   37   
   38   import java.util.EmptyStackException;
   39   import java.util.logging;
   40   
   41   import sun.awt.AppContext;
   42   import sun.awt.AWTAutoShutdown;
   43   import sun.awt.PeerEvent;
   44   import sun.awt.SunToolkit;
   45   
   46   /**
   47    * <code>EventQueue</code> is a platform-independent class
   48    * that queues events, both from the underlying peer classes
   49    * and from trusted application classes.
   50    * <p>
   51    * It encapsulates asynchronous event dispatch machinery which
   52    * extracts events from the queue and dispatches them by calling
   53    * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
   54    * on this <code>EventQueue</code> with the event to be dispatched
   55    * as an argument.  The particular behavior of this machinery is
   56    * implementation-dependent.  The only requirements are that events
   57    * which were actually enqueued to this queue (note that events
   58    * being posted to the <code>EventQueue</code> can be coalesced)
   59    * are dispatched:
   60    * <dl>
   61    *   <dt> Sequentially.
   62    *   <dd> That is, it is not permitted that several events from
   63    *        this queue are dispatched simultaneously.
   64    *   <dt> In the same order as they are enqueued.
   65    *   <dd> That is, if <code>AWTEvent</code>&nbsp;A is enqueued
   66    *        to the <code>EventQueue</code> before
   67    *        <code>AWTEvent</code>&nbsp;B then event B will not be
   68    *        dispatched before event A.
   69    * </dl>
   70    * <p>
   71    * Some browsers partition applets in different code bases into
   72    * separate contexts, and establish walls between these contexts.
   73    * In such a scenario, there will be one <code>EventQueue</code>
   74    * per context. Other browsers place all applets into the same
   75    * context, implying that there will be only a single, global
   76    * <code>EventQueue</code> for all applets. This behavior is
   77    * implementation-dependent.  Consult your browser's documentation
   78    * for more information.
   79    * <p>
   80    * For information on the threading issues of the event dispatch
   81    * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown"
   82    * >AWT Threading Issues</a>.
   83    *
   84    * @author Thomas Ball
   85    * @author Fred Ecks
   86    * @author David Mendenhall
   87    *
   88    * @since       1.1
   89    */
   90   public class EventQueue {
   91   
   92       // From Thread.java
   93       private static int threadInitNumber;
   94       private static synchronized int nextThreadNum() {
   95           return threadInitNumber++;
   96       }
   97   
   98       private static final int LOW_PRIORITY = 0;
   99       private static final int NORM_PRIORITY = 1;
  100       private static final int HIGH_PRIORITY = 2;
  101       private static final int ULTIMATE_PRIORITY = 3;
  102   
  103       private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
  104   
  105       /*
  106        * We maintain one Queue for each priority that the EventQueue supports.
  107        * That is, the EventQueue object is actually implemented as
  108        * NUM_PRIORITIES queues and all Events on a particular internal Queue
  109        * have identical priority. Events are pulled off the EventQueue starting
  110        * with the Queue of highest priority. We progress in decreasing order
  111        * across all Queues.
  112        */
  113       private Queue[] queues = new Queue[NUM_PRIORITIES];
  114   
  115       /*
  116        * The next EventQueue on the stack, or null if this EventQueue is
  117        * on the top of the stack.  If nextQueue is non-null, requests to post
  118        * an event are forwarded to nextQueue.
  119        */
  120       private EventQueue nextQueue;
  121   
  122       /*
  123        * The previous EventQueue on the stack, or null if this is the
  124        * "base" EventQueue.
  125        */
  126       private EventQueue previousQueue;
  127   
  128       private EventDispatchThread dispatchThread;
  129   
  130       private final ThreadGroup threadGroup =
  131           Thread.currentThread().getThreadGroup();
  132       private final ClassLoader classLoader =
  133           Thread.currentThread().getContextClassLoader();
  134   
  135       /*
  136        * The time stamp of the last dispatched InputEvent or ActionEvent.
  137        */
  138       private long mostRecentEventTime = System.currentTimeMillis();
  139   
  140       /**
  141        * The modifiers field of the current event, if the current event is an
  142        * InputEvent or ActionEvent.
  143        */
  144       private WeakReference currentEvent;
  145   
  146       /*
  147        * Non-zero if a thread is waiting in getNextEvent(int) for an event of
  148        * a particular ID to be posted to the queue.
  149        */
  150       private int waitForID;
  151   
  152       private final String name = "AWT-EventQueue-" + nextThreadNum();
  153   
  154       private static final Logger eventLog = Logger.getLogger("java.awt.event.EventQueue");
  155   
  156       public EventQueue() {
  157           for (int i = 0; i < NUM_PRIORITIES; i++) {
  158               queues[i] = new Queue();
  159           }
  160           /*
  161            * NOTE: if you ever have to start the associated event dispatch
  162            * thread at this point, be aware of the following problem:
  163            * If this EventQueue instance is created in
  164            * SunToolkit.createNewAppContext() the started dispatch thread
  165            * may call AppContext.getAppContext() before createNewAppContext()
  166            * completes thus causing mess in thread group to appcontext mapping.
  167            */
  168       }
  169   
  170       /**
  171        * Posts a 1.1-style event to the <code>EventQueue</code>.
  172        * If there is an existing event on the queue with the same ID
  173        * and event source, the source <code>Component</code>'s
  174        * <code>coalesceEvents</code> method will be called.
  175        *
  176        * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  177        *          or a subclass of it
  178        * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
  179        */
  180       public void postEvent(AWTEvent theEvent) {
  181           SunToolkit.flushPendingEvents();
  182           postEventPrivate(theEvent);
  183       }
  184   
  185       /**
  186        * Posts a 1.1-style event to the <code>EventQueue</code>.
  187        * If there is an existing event on the queue with the same ID
  188        * and event source, the source <code>Component</code>'s
  189        * <code>coalesceEvents</code> method will be called.
  190        *
  191        * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  192        *          or a subclass of it
  193        */
  194       final void postEventPrivate(AWTEvent theEvent) {
  195           theEvent.isPosted = true;
  196           synchronized(this) {
  197               if (dispatchThread == null && nextQueue == null) {
  198                   if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
  199                       return;
  200                   } else {
  201                       initDispatchThread();
  202                   }
  203               }
  204               if (nextQueue != null) {
  205                   // Forward event to top of EventQueue stack.
  206                   nextQueue.postEventPrivate(theEvent);
  207                   return;
  208               }
  209               postEvent(theEvent, getPriority(theEvent));
  210           }
  211       }
  212   
  213       private static int getPriority(AWTEvent theEvent) {
  214           if (theEvent instanceof PeerEvent &&
  215               (((PeerEvent)theEvent).getFlags() &
  216                   PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0)
  217           {
  218               return ULTIMATE_PRIORITY;
  219           }
  220   
  221           if (theEvent instanceof PeerEvent &&
  222               (((PeerEvent)theEvent).getFlags() &
  223                   PeerEvent.PRIORITY_EVENT) != 0)
  224           {
  225               return HIGH_PRIORITY;
  226           }
  227   
  228           if (theEvent instanceof PeerEvent &&
  229               (((PeerEvent)theEvent).getFlags() &
  230                   PeerEvent.LOW_PRIORITY_EVENT) != 0)
  231           {
  232               return LOW_PRIORITY;
  233           }
  234   
  235           int id = theEvent.getID();
  236           if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
  237               return LOW_PRIORITY;
  238           }
  239           return NORM_PRIORITY;
  240       }
  241   
  242       /**
  243        * Posts the event to the internal Queue of specified priority,
  244        * coalescing as appropriate.
  245        *
  246        * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  247        *          or a subclass of it
  248        * @param priority  the desired priority of the event
  249        */
  250       private void postEvent(AWTEvent theEvent, int priority) {
  251           if (coalesceEvent(theEvent, priority)) {
  252               return;
  253           }
  254   
  255           EventQueueItem newItem = new EventQueueItem(theEvent);
  256   
  257           cacheEQItem(newItem);
  258   
  259           boolean notifyID = (theEvent.getID() == this.waitForID);
  260   
  261           if (queues[priority].head == null) {
  262               boolean shouldNotify = noEvents();
  263               queues[priority].head = queues[priority].tail = newItem;
  264   
  265               if (shouldNotify) {
  266                   if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
  267                       AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
  268                   }
  269                   notifyAll();
  270               } else if (notifyID) {
  271                   notifyAll();
  272               }
  273           } else {
  274               // The event was not coalesced or has non-Component source.
  275               // Insert it at the end of the appropriate Queue.
  276               queues[priority].tail.next = newItem;
  277               queues[priority].tail = newItem;
  278               if (notifyID) {
  279                   notifyAll();
  280               }
  281           }
  282       }
  283   
  284       private boolean coalescePaintEvent(PaintEvent e) {
  285           ComponentPeer sourcePeer = ((Component)e.getSource()).peer;
  286           if (sourcePeer != null) {
  287               sourcePeer.coalescePaintEvent(e);
  288           }
  289           EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
  290           if (cache == null) {
  291               return false;
  292           }
  293           int index = eventToCacheIndex(e);
  294   
  295           if (index != -1 && cache[index] != null) {
  296               PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event);
  297               if (merged != null) {
  298                   cache[index].event = merged;
  299                   return true;
  300               }
  301           }
  302           return false;
  303       }
  304   
  305       private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) {
  306           Rectangle aRect = a.getUpdateRect();
  307           Rectangle bRect = b.getUpdateRect();
  308           if (bRect.contains(aRect)) {
  309               return b;
  310           }
  311           if (aRect.contains(bRect)) {
  312               return a;
  313           }
  314           return null;
  315       }
  316   
  317       private boolean coalesceMouseEvent(MouseEvent e) {
  318           EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
  319           if (cache == null) {
  320               return false;
  321           }
  322           int index = eventToCacheIndex(e);
  323           if (index != -1 && cache[index] != null) {
  324               cache[index].event = e;
  325               return true;
  326           }
  327           return false;
  328       }
  329   
  330       private boolean coalescePeerEvent(PeerEvent e) {
  331           EventQueueItem[] cache = ((Component)e.getSource()).eventCache;
  332           if (cache == null) {
  333               return false;
  334           }
  335           int index = eventToCacheIndex(e);
  336           if (index != -1 && cache[index] != null) {
  337               e = e.coalesceEvents((PeerEvent)cache[index].event);
  338               if (e != null) {
  339                   cache[index].event = e;
  340                   return true;
  341               } else {
  342                   cache[index] = null;
  343               }
  344           }
  345           return false;
  346       }
  347   
  348       /*
  349        * Should avoid of calling this method by any means
  350        * as it's working time is dependant on EQ length.
  351        * In the wors case this method alone can slow down the entire application
  352        * 10 times by stalling the Event processing.
  353        * Only here by backward compatibility reasons.
  354        */
  355       private boolean coalesceOtherEvent(AWTEvent e, int priority) {
  356           int id = e.getID();
  357           Component source = (Component)e.getSource();
  358           for (EventQueueItem entry = queues[priority].head;
  359               entry != null; entry = entry.next)
  360           {
  361               // Give Component.coalesceEvents a chance
  362               if (entry.event.getSource() == source && entry.id == id) {
  363                   AWTEvent coalescedEvent = source.coalesceEvents(
  364                       entry.event, e);
  365                   if (coalescedEvent != null) {
  366                       entry.event = coalescedEvent;
  367                       return true;
  368                   }
  369               }
  370           }
  371           return false;
  372       }
  373   
  374       private boolean coalesceEvent(AWTEvent e, int priority) {
  375           if (!(e.getSource() instanceof Component)) {
  376               return false;
  377           }
  378           if (e instanceof PeerEvent) {
  379               return coalescePeerEvent((PeerEvent)e);
  380           }
  381           // The worst case
  382           if (((Component)e.getSource()).isCoalescingEnabled()
  383               && coalesceOtherEvent(e, priority))
  384           {
  385               return true;
  386           }
  387           if (e instanceof PaintEvent) {
  388               return coalescePaintEvent((PaintEvent)e);
  389           }
  390           if (e instanceof MouseEvent) {
  391               return coalesceMouseEvent((MouseEvent)e);
  392           }
  393           return false;
  394       }
  395   
  396       private void cacheEQItem(EventQueueItem entry) {
  397           int index = eventToCacheIndex(entry.event);
  398           if (index != -1 && entry.event.getSource() instanceof Component) {
  399               Component source = (Component)entry.event.getSource();
  400               if (source.eventCache == null) {
  401                   source.eventCache = new EventQueueItem[CACHE_LENGTH];
  402               }
  403               source.eventCache[index] = entry;
  404           }
  405       }
  406   
  407       private void uncacheEQItem(EventQueueItem entry) {
  408           int index = eventToCacheIndex(entry.event);
  409           if (index != -1 && entry.event.getSource() instanceof Component) {
  410               Component source = (Component)entry.event.getSource();
  411               if (source.eventCache == null) {
  412                   return;
  413               }
  414               source.eventCache[index] = null;
  415           }
  416       }
  417   
  418       private static final int PAINT = 0;
  419       private static final int UPDATE = 1;
  420       private static final int MOVE = 2;
  421       private static final int DRAG = 3;
  422       private static final int PEER = 4;
  423       private static final int CACHE_LENGTH = 5;
  424   
  425       private static int eventToCacheIndex(AWTEvent e) {
  426           switch(e.getID()) {
  427           case PaintEvent.PAINT:
  428               return PAINT;
  429           case PaintEvent.UPDATE:
  430               return UPDATE;
  431           case MouseEvent.MOUSE_MOVED:
  432               return MOVE;
  433           case MouseEvent.MOUSE_DRAGGED:
  434               return DRAG;
  435           default:
  436               return e instanceof PeerEvent ? PEER : -1;
  437           }
  438       }
  439   
  440       /**
  441        * Returns whether an event is pending on any of the separate
  442        * Queues.
  443        * @return whether an event is pending on any of the separate Queues
  444        */
  445       private boolean noEvents() {
  446           for (int i = 0; i < NUM_PRIORITIES; i++) {
  447               if (queues[i].head != null) {
  448                   return false;
  449               }
  450           }
  451   
  452           return true;
  453       }
  454   
  455       /**
  456        * Removes an event from the <code>EventQueue</code> and
  457        * returns it.  This method will block until an event has
  458        * been posted by another thread.
  459        * @return the next <code>AWTEvent</code>
  460        * @exception InterruptedException
  461        *            if any thread has interrupted this thread
  462        */
  463       public AWTEvent getNextEvent() throws InterruptedException {
  464           do {
  465               /*
  466                * SunToolkit.flushPendingEvents must be called outside
  467                * of the synchronized block to avoid deadlock when
  468                * event queues are nested with push()/pop().
  469                */
  470               SunToolkit.flushPendingEvents();
  471               synchronized (this) {
  472                   for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  473                       if (queues[i].head != null) {
  474                           EventQueueItem entry = queues[i].head;
  475                           queues[i].head = entry.next;
  476                           if (entry.next == null) {
  477                               queues[i].tail = null;
  478                           }
  479                           uncacheEQItem(entry);
  480                           return entry.event;
  481                       }
  482                   }
  483                   AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
  484                   wait();
  485               }
  486           } while(true);
  487       }
  488   
  489       AWTEvent getNextEvent(int id) throws InterruptedException {
  490           do {
  491               /*
  492                * SunToolkit.flushPendingEvents must be called outside
  493                * of the synchronized block to avoid deadlock when
  494                * event queues are nested with push()/pop().
  495                */
  496               SunToolkit.flushPendingEvents();
  497               synchronized (this) {
  498                   for (int i = 0; i < NUM_PRIORITIES; i++) {
  499                       for (EventQueueItem entry = queues[i].head, prev = null;
  500                            entry != null; prev = entry, entry = entry.next)
  501                       {
  502                           if (entry.id == id) {
  503                               if (prev == null) {
  504                                   queues[i].head = entry.next;
  505                               } else {
  506                                   prev.next = entry.next;
  507                               }
  508                               if (queues[i].tail == entry) {
  509                                   queues[i].tail = prev;
  510                               }
  511                               uncacheEQItem(entry);
  512                               return entry.event;
  513                           }
  514                       }
  515                   }
  516                   this.waitForID = id;
  517                   wait();
  518                   this.waitForID = 0;
  519               }
  520           } while(true);
  521       }
  522   
  523       /**
  524        * Returns the first event on the <code>EventQueue</code>
  525        * without removing it.
  526        * @return the first event
  527        */
  528       public synchronized AWTEvent peekEvent() {
  529           for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  530               if (queues[i].head != null) {
  531                   return queues[i].head.event;
  532               }
  533           }
  534   
  535           return null;
  536       }
  537   
  538       /**
  539        * Returns the first event with the specified id, if any.
  540        * @param id the id of the type of event desired
  541        * @return the first event of the specified id or <code>null</code>
  542        *    if there is no such event
  543        */
  544       public synchronized AWTEvent peekEvent(int id) {
  545           for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  546               EventQueueItem q = queues[i].head;
  547               for (; q != null; q = q.next) {
  548                   if (q.id == id) {
  549                       return q.event;
  550                   }
  551               }
  552           }
  553   
  554           return null;
  555       }
  556   
  557       /**
  558        * Dispatches an event. The manner in which the event is
  559        * dispatched depends upon the type of the event and the
  560        * type of the event's source object:
  561        * <p> </p>
  562        * <table border=1 summary="Event types, source types, and dispatch methods">
  563        * <tr>
  564        *     <th>Event Type</th>
  565        *     <th>Source Type</th>
  566        *     <th>Dispatched To</th>
  567        * </tr>
  568        * <tr>
  569        *     <td>ActiveEvent</td>
  570        *     <td>Any</td>
  571        *     <td>event.dispatch()</td>
  572        * </tr>
  573        * <tr>
  574        *     <td>Other</td>
  575        *     <td>Component</td>
  576        *     <td>source.dispatchEvent(AWTEvent)</td>
  577        * </tr>
  578        * <tr>
  579        *     <td>Other</td>
  580        *     <td>MenuComponent</td>
  581        *     <td>source.dispatchEvent(AWTEvent)</td>
  582        * </tr>
  583        * <tr>
  584        *     <td>Other</td>
  585        *     <td>Other</td>
  586        *     <td>No action (ignored)</td>
  587        * </tr>
  588        * </table>
  589        * <p> </p>
  590        * @param event an instance of <code>java.awt.AWTEvent</code>,
  591        *          or a subclass of it
  592        * @throws NullPointerException if <code>event</code> is <code>null</code>
  593        * @since           1.2
  594        */
  595       protected void dispatchEvent(AWTEvent event) {
  596           event.isPosted = true;
  597           Object src = event.getSource();
  598           if (event instanceof ActiveEvent) {
  599               // This could become the sole method of dispatching in time.
  600               setCurrentEventAndMostRecentTimeImpl(event);
  601   
  602               ((ActiveEvent)event).dispatch();
  603           } else if (src instanceof Component) {
  604               ((Component)src).dispatchEvent(event);
  605               event.dispatched();
  606           } else if (src instanceof MenuComponent) {
  607               ((MenuComponent)src).dispatchEvent(event);
  608           } else if (src instanceof TrayIcon) {
  609               ((TrayIcon)src).dispatchEvent(event);
  610           } else if (src instanceof AWTAutoShutdown) {
  611               if (noEvents()) {
  612                   dispatchThread.stopDispatching();
  613               }
  614           } else {
  615               System.err.println("unable to dispatch event: " + event);
  616           }
  617       }
  618   
  619       /**
  620        * Returns the timestamp of the most recent event that had a timestamp, and
  621        * that was dispatched from the <code>EventQueue</code> associated with the
  622        * calling thread. If an event with a timestamp is currently being
  623        * dispatched, its timestamp will be returned. If no events have yet
  624        * been dispatched, the EventQueue's initialization time will be
  625        * returned instead.In the current version of
  626        * the JDK, only <code>InputEvent</code>s,
  627        * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
  628        * timestamps; however, future versions of the JDK may add timestamps to
  629        * additional event types. Note that this method should only be invoked
  630        * from an application's {@link #isDispatchThread event dispatching thread}.
  631        * If this method is
  632        * invoked from another thread, the current system time (as reported by
  633        * <code>System.currentTimeMillis()</code>) will be returned instead.
  634        *
  635        * @return the timestamp of the last <code>InputEvent</code>,
  636        *         <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
  637        *         dispatched, or <code>System.currentTimeMillis()</code> if this
  638        *         method is invoked on a thread other than an event dispatching
  639        *         thread
  640        * @see java.awt.event.InputEvent#getWhen
  641        * @see java.awt.event.ActionEvent#getWhen
  642        * @see java.awt.event.InvocationEvent#getWhen
  643        * @see #isDispatchThread
  644        *
  645        * @since 1.4
  646        */
  647       public static long getMostRecentEventTime() {
  648           return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
  649       }
  650       private synchronized long getMostRecentEventTimeImpl() {
  651           return (Thread.currentThread() == dispatchThread)
  652               ? mostRecentEventTime
  653               : System.currentTimeMillis();
  654       }
  655   
  656       /**
  657        * @return most recent event time on all threads.
  658        */
  659       synchronized long getMostRecentEventTimeEx() {
  660           return mostRecentEventTime;
  661       }
  662   
  663       /**
  664        * Returns the the event currently being dispatched by the
  665        * <code>EventQueue</code> associated with the calling thread. This is
  666        * useful if a method needs access to the event, but was not designed to
  667        * receive a reference to it as an argument. Note that this method should
  668        * only be invoked from an application's event dispatching thread. If this
  669        * method is invoked from another thread, null will be returned.
  670        *
  671        * @return the event currently being dispatched, or null if this method is
  672        *         invoked on a thread other than an event dispatching thread
  673        * @since 1.4
  674        */
  675       public static AWTEvent getCurrentEvent() {
  676           return Toolkit.getEventQueue().getCurrentEventImpl();
  677       }
  678       private synchronized AWTEvent getCurrentEventImpl() {
  679           return (Thread.currentThread() == dispatchThread)
  680               ? ((AWTEvent)currentEvent.get())
  681               : null;
  682       }
  683   
  684       /**
  685        * Replaces the existing <code>EventQueue</code> with the specified one.
  686        * Any pending events are transferred to the new <code>EventQueue</code>
  687        * for processing by it.
  688        *
  689        * @param newEventQueue an <code>EventQueue</code>
  690        *          (or subclass thereof) instance to be use
  691        * @see      java.awt.EventQueue#pop
  692        * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
  693        * @since           1.2
  694        */
  695       public synchronized void push(EventQueue newEventQueue) {
  696           if (eventLog.isLoggable(Level.FINE)) {
  697               eventLog.log(Level.FINE, "EventQueue.push(" + newEventQueue + ")");
  698           }
  699   
  700           if (nextQueue != null) {
  701               nextQueue.push(newEventQueue);
  702               return;
  703           }
  704   
  705           synchronized (newEventQueue) {
  706               // Transfer all events forward to new EventQueue.
  707               while (peekEvent() != null) {
  708                   try {
  709                       newEventQueue.postEventPrivate(getNextEvent());
  710                   } catch (InterruptedException ie) {
  711                       if (eventLog.isLoggable(Level.FINE)) {
  712                           eventLog.log(Level.FINE, "Interrupted push", ie);
  713                       }
  714                   }
  715               }
  716   
  717               newEventQueue.previousQueue = this;
  718           }
  719           /*
  720            * Stop the event dispatch thread associated with the currently
  721            * active event queue, so that after the new queue is pushed
  722            * on the top this event dispatch thread won't prevent AWT from
  723            * being automatically shut down.
  724            * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
  725            * waits for the dispatch thread to exit, so if the dispatch
  726            * thread attempts to synchronize on this EventQueue object
  727            * it will never exit since we already hold this lock.
  728            */
  729           if (dispatchThread != null) {
  730               dispatchThread.stopDispatchingLater();
  731           }
  732   
  733           nextQueue = newEventQueue;
  734   
  735           AppContext appContext = AppContext.getAppContext();
  736           if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
  737               appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
  738           }
  739       }
  740   
  741       /**
  742        * Stops dispatching events using this <code>EventQueue</code>.
  743        * Any pending events are transferred to the previous
  744        * <code>EventQueue</code> for processing.
  745        * <p>
  746        * Warning: To avoid deadlock, do not declare this method
  747        * synchronized in a subclass.
  748        *
  749        * @exception EmptyStackException if no previous push was made
  750        *  on this <code>EventQueue</code>
  751        * @see      java.awt.EventQueue#push
  752        * @since           1.2
  753        */
  754       protected void pop() throws EmptyStackException {
  755           if (eventLog.isLoggable(Level.FINE)) {
  756               eventLog.log(Level.FINE, "EventQueue.pop(" + this + ")");
  757           }
  758   
  759           // To prevent deadlock, we lock on the previous EventQueue before
  760           // this one.  This uses the same locking order as everything else
  761           // in EventQueue.java, so deadlock isn't possible.
  762           EventQueue prev = previousQueue;
  763           synchronized ((prev != null) ? prev : this) {
  764             synchronized(this) {
  765               if (nextQueue != null) {
  766                   nextQueue.pop();
  767                   return;
  768               }
  769               if (previousQueue == null) {
  770                   throw new EmptyStackException();
  771               }
  772   
  773               // Transfer all events back to previous EventQueue.
  774               previousQueue.nextQueue = null;
  775               while (peekEvent() != null) {
  776                   try {
  777                       previousQueue.postEventPrivate(getNextEvent());
  778                   } catch (InterruptedException ie) {
  779                       if (eventLog.isLoggable(Level.FINE)) {
  780                           eventLog.log(Level.FINE, "Interrupted pop", ie);
  781                       }
  782                   }
  783               }
  784               AppContext appContext = AppContext.getAppContext();
  785               if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
  786                   appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
  787               }
  788   
  789               previousQueue = null;
  790             }
  791           }
  792   
  793           EventDispatchThread dt = this.dispatchThread;
  794           if (dt != null) {
  795               dt.stopDispatching(); // Must be done outside synchronized
  796                                     // block to avoid possible deadlock
  797           }
  798       }
  799   
  800       /**
  801        * Returns true if the calling thread is
  802        * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
  803        * dispatch thread. Use this method to ensure that a particular
  804        * task is being executed (or not being) there.
  805        * <p>
  806        * Note: use the {@link #invokeLater} or {@link #invokeAndWait}
  807        * methods to execute a task in
  808        * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
  809        * dispatch thread.
  810        * <p>
  811        *
  812        * @return true if running in
  813        * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s
  814        * dispatch thread
  815        * @see             #invokeLater
  816        * @see             #invokeAndWait
  817        * @see             Toolkit#getSystemEventQueue
  818        * @since           1.2
  819        */
  820       public static boolean isDispatchThread() {
  821           EventQueue eq = Toolkit.getEventQueue();
  822           EventQueue next = eq.nextQueue;
  823           while (next != null) {
  824               eq = next;
  825               next = eq.nextQueue;
  826           }
  827           return (Thread.currentThread() == eq.dispatchThread);
  828       }
  829   
  830       final void initDispatchThread() {
  831           synchronized (this) {
  832               if (dispatchThread == null && !threadGroup.isDestroyed()) {
  833                   dispatchThread = (EventDispatchThread)
  834                       AccessController.doPrivileged(new PrivilegedAction() {
  835                           public Object run() {
  836                               EventDispatchThread t =
  837                                   new EventDispatchThread(threadGroup,
  838                                                           name,
  839                                                           EventQueue.this);
  840                               t.setContextClassLoader(classLoader);
  841                               t.setPriority(Thread.NORM_PRIORITY + 1);
  842                               t.setDaemon(false);
  843                               return t;
  844                           }
  845                       });
  846                   AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
  847                   dispatchThread.start();
  848               }
  849           }
  850       }
  851   
  852       final void detachDispatchThread() {
  853           dispatchThread = null;
  854       }
  855   
  856       /*
  857        * Gets the <code>EventDispatchThread</code> for this
  858        * <code>EventQueue</code>.
  859        * @return the event dispatch thread associated with this event queue
  860        *         or <code>null</code> if this event queue doesn't have a
  861        *         working thread associated with it
  862        * @see    java.awt.EventQueue#initDispatchThread
  863        * @see    java.awt.EventQueue#detachDispatchThread
  864        */
  865       final EventDispatchThread getDispatchThread() {
  866           return dispatchThread;
  867       }
  868   
  869       /*
  870        * Removes any pending events for the specified source object.
  871        * If removeAllEvents parameter is <code>true</code> then all
  872        * events for the specified source object are removed, if it
  873        * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
  874        * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
  875        * and <code>InputMethodEvent</code> are kept in the queue, but all other
  876        * events are removed.
  877        *
  878        * This method is normally called by the source's
  879        * <code>removeNotify</code> method.
  880        */
  881       final void removeSourceEvents(Object source, boolean removeAllEvents) {
  882           SunToolkit.flushPendingEvents();
  883           synchronized (this) {
  884               for (int i = 0; i < NUM_PRIORITIES; i++) {
  885                   EventQueueItem entry = queues[i].head;
  886                   EventQueueItem prev = null;
  887                   while (entry != null) {
  888                       if ((entry.event.getSource() == source)
  889                           && (removeAllEvents
  890                               || ! (entry.event instanceof SequencedEvent
  891                                     || entry.event instanceof SentEvent
  892                                     || entry.event instanceof FocusEvent
  893                                     || entry.event instanceof WindowEvent
  894                                     || entry.event instanceof KeyEvent
  895                                     || entry.event instanceof InputMethodEvent)))
  896                       {
  897                           if (entry.event instanceof SequencedEvent) {
  898                               ((SequencedEvent)entry.event).dispose();
  899                           }
  900                           if (entry.event instanceof SentEvent) {
  901                               ((SentEvent)entry.event).dispose();
  902                           }
  903                           if (prev == null) {
  904                               queues[i].head = entry.next;
  905                           } else {
  906                               prev.next = entry.next;
  907                           }
  908                           uncacheEQItem(entry);
  909                       } else {
  910                           prev = entry;
  911                       }
  912                       entry = entry.next;
  913                   }
  914                   queues[i].tail = prev;
  915               }
  916           }
  917       }
  918   
  919       static void setCurrentEventAndMostRecentTime(AWTEvent e) {
  920           Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
  921       }
  922       private synchronized void setCurrentEventAndMostRecentTimeImpl(AWTEvent e)
  923       {
  924           if (Thread.currentThread() != dispatchThread) {
  925               return;
  926           }
  927   
  928           currentEvent = new WeakReference(e);
  929   
  930           // This series of 'instanceof' checks should be replaced with a
  931           // polymorphic type (for example, an interface which declares a
  932           // getWhen() method). However, this would require us to make such
  933           // a type public, or to place it in sun.awt. Both of these approaches
  934           // have been frowned upon. So for now, we hack.
  935           //
  936           // In tiger, we will probably give timestamps to all events, so this
  937           // will no longer be an issue.
  938           long mostRecentEventTime2 = Long.MIN_VALUE;
  939           if (e instanceof InputEvent) {
  940               InputEvent ie = (InputEvent)e;
  941               mostRecentEventTime2 = ie.getWhen();
  942           } else if (e instanceof InputMethodEvent) {
  943               InputMethodEvent ime = (InputMethodEvent)e;
  944               mostRecentEventTime2 = ime.getWhen();
  945           } else if (e instanceof ActionEvent) {
  946               ActionEvent ae = (ActionEvent)e;
  947               mostRecentEventTime2 = ae.getWhen();
  948           } else if (e instanceof InvocationEvent) {
  949               InvocationEvent ie = (InvocationEvent)e;
  950               mostRecentEventTime2 = ie.getWhen();
  951           }
  952           mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2);
  953       }
  954   
  955       /**
  956        * Causes <code>runnable</code> to have its <code>run</code>
  957        * method called in the {@link #isDispatchThread dispatch thread} of
  958        * {@link Toolkit#getSystemEventQueue the system EventQueue}.
  959        * This will happen after all pending events are processed.
  960        *
  961        * @param runnable  the <code>Runnable</code> whose <code>run</code>
  962        *                  method should be executed
  963        *                  asynchronously in the
  964        *                  {@link #isDispatchThread event dispatch thread}
  965        *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
  966        * @see             #invokeAndWait
  967        * @see             Toolkit#getSystemEventQueue
  968        * @see             #isDispatchThread
  969        * @since           1.2
  970        */
  971       public static void invokeLater(Runnable runnable) {
  972           Toolkit.getEventQueue().postEvent(
  973               new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
  974       }
  975   
  976       /**
  977        * Causes <code>runnable</code> to have its <code>run</code>
  978        * method called in the {@link #isDispatchThread dispatch thread} of
  979        * {@link Toolkit#getSystemEventQueue the system EventQueue}.
  980        * This will happen after all pending events are processed.
  981        * The call blocks until this has happened.  This method
  982        * will throw an Error if called from the
  983        * {@link #isDispatchThread event dispatcher thread}.
  984        *
  985        * @param runnable  the <code>Runnable</code> whose <code>run</code>
  986        *                  method should be executed
  987        *                  synchronously in the
  988        *                  {@link #isDispatchThread event dispatch thread}
  989        *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
  990        * @exception       InterruptedException  if any thread has
  991        *                  interrupted this thread
  992        * @exception       InvocationTargetException  if an throwable is thrown
  993        *                  when running <code>runnable</code>
  994        * @see             #invokeLater
  995        * @see             Toolkit#getSystemEventQueue
  996        * @see             #isDispatchThread
  997        * @since           1.2
  998        */
  999       public static void invokeAndWait(Runnable runnable)
 1000                throws InterruptedException, InvocationTargetException {
 1001   
 1002           if (EventQueue.isDispatchThread()) {
 1003               throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
 1004           }
 1005   
 1006           class AWTInvocationLock {}
 1007           Object lock = new AWTInvocationLock();
 1008   
 1009           InvocationEvent event =
 1010               new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
 1011                                   true);
 1012   
 1013           synchronized (lock) {
 1014               Toolkit.getEventQueue().postEvent(event);
 1015               lock.wait();
 1016           }
 1017   
 1018           Throwable eventThrowable = event.getThrowable();
 1019           if (eventThrowable != null) {
 1020               throw new InvocationTargetException(eventThrowable);
 1021           }
 1022       }
 1023   
 1024       /*
 1025        * Called from PostEventQueue.postEvent to notify that a new event
 1026        * appeared. First it proceeds to the EventQueue on the top of the
 1027        * stack, then notifies the associated dispatch thread if it exists
 1028        * or starts a new one otherwise.
 1029        */
 1030       private void wakeup(boolean isShutdown) {
 1031           synchronized(this) {
 1032               if (nextQueue != null) {
 1033                   // Forward call to the top of EventQueue stack.
 1034                   nextQueue.wakeup(isShutdown);
 1035               } else if (dispatchThread != null) {
 1036                   notifyAll();
 1037               } else if (!isShutdown) {
 1038                   initDispatchThread();
 1039               }
 1040           }
 1041       }
 1042   }
 1043   
 1044   /**
 1045    * The Queue object holds pointers to the beginning and end of one internal
 1046    * queue. An EventQueue object is composed of multiple internal Queues, one
 1047    * for each priority supported by the EventQueue. All Events on a particular
 1048    * internal Queue have identical priority.
 1049    */
 1050   class Queue {
 1051       EventQueueItem head;
 1052       EventQueueItem tail;
 1053   }
 1054   
 1055   class EventQueueItem {
 1056       AWTEvent event;
 1057       int      id;
 1058       EventQueueItem next;
 1059   
 1060       EventQueueItem(AWTEvent evt) {
 1061           event = evt;
 1062           id = evt.getID();
 1063       }
 1064   }

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