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