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

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