jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java
changeset 25859 3317bb8137f4
parent 25206 f1ed7d27ec7f
child 26749 b6598aa90114
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1996, 2013, 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.MouseEvent;
       
    29 import java.awt.event.ActionEvent;
       
    30 import java.awt.event.WindowEvent;
       
    31 
       
    32 import java.util.ArrayList;
       
    33 import sun.util.logging.PlatformLogger;
       
    34 
       
    35 import sun.awt.dnd.SunDragSourceContextPeer;
       
    36 
       
    37 /**
       
    38  * EventDispatchThread is a package-private AWT class which takes
       
    39  * events off the EventQueue and dispatches them to the appropriate
       
    40  * AWT components.
       
    41  *
       
    42  * The Thread starts a "permanent" event pump with a call to
       
    43  * pumpEvents(Conditional) in its run() method. Event handlers can choose to
       
    44  * block this event pump at any time, but should start a new pump (<b>not</b>
       
    45  * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
       
    46  * secondary event pump will exit automatically as soon as the Condtional
       
    47  * evaluate()s to false and an additional Event is pumped and dispatched.
       
    48  *
       
    49  * @author Tom Ball
       
    50  * @author Amy Fowler
       
    51  * @author Fred Ecks
       
    52  * @author David Mendenhall
       
    53  *
       
    54  * @since 1.1
       
    55  */
       
    56 class EventDispatchThread extends Thread {
       
    57 
       
    58     private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
       
    59 
       
    60     private EventQueue theQueue;
       
    61     private volatile boolean doDispatch = true;
       
    62 
       
    63     private static final int ANY_EVENT = -1;
       
    64 
       
    65     private ArrayList<EventFilter> eventFilters = new ArrayList<EventFilter>();
       
    66 
       
    67     EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
       
    68         super(group, name);
       
    69         setEventQueue(queue);
       
    70     }
       
    71 
       
    72     /*
       
    73      * Must be called on EDT only, that's why no synchronization
       
    74      */
       
    75     public void stopDispatching() {
       
    76         doDispatch = false;
       
    77     }
       
    78 
       
    79     public void run() {
       
    80         try {
       
    81             pumpEvents(new Conditional() {
       
    82                 public boolean evaluate() {
       
    83                     return true;
       
    84                 }
       
    85             });
       
    86         } finally {
       
    87             getEventQueue().detachDispatchThread(this);
       
    88         }
       
    89     }
       
    90 
       
    91     void pumpEvents(Conditional cond) {
       
    92         pumpEvents(ANY_EVENT, cond);
       
    93     }
       
    94 
       
    95     void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
       
    96         pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
       
    97     }
       
    98 
       
    99     void pumpEvents(int id, Conditional cond) {
       
   100         pumpEventsForHierarchy(id, cond, null);
       
   101     }
       
   102 
       
   103     void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
       
   104         pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
       
   105     }
       
   106 
       
   107     void pumpEventsForFilter(Conditional cond, EventFilter filter) {
       
   108         pumpEventsForFilter(ANY_EVENT, cond, filter);
       
   109     }
       
   110 
       
   111     void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
       
   112         addEventFilter(filter);
       
   113         doDispatch = true;
       
   114         while (doDispatch && !isInterrupted() && cond.evaluate()) {
       
   115             pumpOneEventForFilters(id);
       
   116         }
       
   117         removeEventFilter(filter);
       
   118     }
       
   119 
       
   120     void addEventFilter(EventFilter filter) {
       
   121         if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
       
   122             eventLog.finest("adding the event filter: " + filter);
       
   123         }
       
   124         synchronized (eventFilters) {
       
   125             if (!eventFilters.contains(filter)) {
       
   126                 if (filter instanceof ModalEventFilter) {
       
   127                     ModalEventFilter newFilter = (ModalEventFilter)filter;
       
   128                     int k = 0;
       
   129                     for (k = 0; k < eventFilters.size(); k++) {
       
   130                         EventFilter f = eventFilters.get(k);
       
   131                         if (f instanceof ModalEventFilter) {
       
   132                             ModalEventFilter cf = (ModalEventFilter)f;
       
   133                             if (cf.compareTo(newFilter) > 0) {
       
   134                                 break;
       
   135                             }
       
   136                         }
       
   137                     }
       
   138                     eventFilters.add(k, filter);
       
   139                 } else {
       
   140                     eventFilters.add(filter);
       
   141                 }
       
   142             }
       
   143         }
       
   144     }
       
   145 
       
   146     void removeEventFilter(EventFilter filter) {
       
   147         if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
       
   148             eventLog.finest("removing the event filter: " + filter);
       
   149         }
       
   150         synchronized (eventFilters) {
       
   151             eventFilters.remove(filter);
       
   152         }
       
   153     }
       
   154 
       
   155     void pumpOneEventForFilters(int id) {
       
   156         AWTEvent event = null;
       
   157         boolean eventOK = false;
       
   158         try {
       
   159             EventQueue eq = null;
       
   160             do {
       
   161                 // EventQueue may change during the dispatching
       
   162                 eq = getEventQueue();
       
   163 
       
   164                 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
       
   165 
       
   166                 eventOK = true;
       
   167                 synchronized (eventFilters) {
       
   168                     for (int i = eventFilters.size() - 1; i >= 0; i--) {
       
   169                         EventFilter f = eventFilters.get(i);
       
   170                         EventFilter.FilterAction accept = f.acceptEvent(event);
       
   171                         if (accept == EventFilter.FilterAction.REJECT) {
       
   172                             eventOK = false;
       
   173                             break;
       
   174                         } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
       
   175                             break;
       
   176                         }
       
   177                     }
       
   178                 }
       
   179                 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
       
   180                 if (!eventOK) {
       
   181                     event.consume();
       
   182                 }
       
   183             }
       
   184             while (eventOK == false);
       
   185 
       
   186             if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
       
   187                 eventLog.finest("Dispatching: " + event);
       
   188             }
       
   189 
       
   190             eq.dispatchEvent(event);
       
   191         }
       
   192         catch (ThreadDeath death) {
       
   193             doDispatch = false;
       
   194             throw death;
       
   195         }
       
   196         catch (InterruptedException interruptedException) {
       
   197             doDispatch = false; // AppContext.dispose() interrupts all
       
   198                                 // Threads in the AppContext
       
   199         }
       
   200         catch (Throwable e) {
       
   201             processException(e);
       
   202         }
       
   203     }
       
   204 
       
   205     private void processException(Throwable e) {
       
   206         if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
       
   207             eventLog.fine("Processing exception: " + e);
       
   208         }
       
   209         getUncaughtExceptionHandler().uncaughtException(this, e);
       
   210     }
       
   211 
       
   212     public synchronized EventQueue getEventQueue() {
       
   213         return theQueue;
       
   214     }
       
   215     public synchronized void setEventQueue(EventQueue eq) {
       
   216         theQueue = eq;
       
   217     }
       
   218 
       
   219     private static class HierarchyEventFilter implements EventFilter {
       
   220         private Component modalComponent;
       
   221         public HierarchyEventFilter(Component modalComponent) {
       
   222             this.modalComponent = modalComponent;
       
   223         }
       
   224         public FilterAction acceptEvent(AWTEvent event) {
       
   225             if (modalComponent != null) {
       
   226                 int eventID = event.getID();
       
   227                 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
       
   228                                      (eventID <= MouseEvent.MOUSE_LAST);
       
   229                 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
       
   230                                       (eventID <= ActionEvent.ACTION_LAST);
       
   231                 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
       
   232                 /*
       
   233                  * filter out MouseEvent and ActionEvent that's outside
       
   234                  * the modalComponent hierarchy.
       
   235                  * KeyEvent is handled by using enqueueKeyEvent
       
   236                  * in Dialog.show
       
   237                  */
       
   238                 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
       
   239                     /*
       
   240                      * Modal internal frames are handled separately. If event is
       
   241                      * for some component from another heavyweight than modalComp,
       
   242                      * it is accepted. If heavyweight is the same - we still accept
       
   243                      * event and perform further filtering in LightweightDispatcher
       
   244                      */
       
   245                     return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
       
   246                 }
       
   247                 if (mouseEvent || actionEvent || windowClosingEvent) {
       
   248                     Object o = event.getSource();
       
   249                     if (o instanceof sun.awt.ModalExclude) {
       
   250                         // Exclude this object from modality and
       
   251                         // continue to pump it's events.
       
   252                         return FilterAction.ACCEPT;
       
   253                     } else if (o instanceof Component) {
       
   254                         Component c = (Component) o;
       
   255                         // 5.0u3 modal exclusion
       
   256                         boolean modalExcluded = false;
       
   257                         if (modalComponent instanceof Container) {
       
   258                             while (c != modalComponent && c != null) {
       
   259                                 if ((c instanceof Window) &&
       
   260                                     (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
       
   261                                     // Exclude this window and all its children from
       
   262                                     //  modality and continue to pump it's events.
       
   263                                     modalExcluded = true;
       
   264                                     break;
       
   265                                 }
       
   266                                 c = c.getParent();
       
   267                             }
       
   268                         }
       
   269                         if (!modalExcluded && (c != modalComponent)) {
       
   270                             return FilterAction.REJECT;
       
   271                         }
       
   272                     }
       
   273                 }
       
   274             }
       
   275             return FilterAction.ACCEPT;
       
   276         }
       
   277     }
       
   278 }