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 || getEventQueue().peekEvent() != null) 116 && !isInterrupted() && cond.evaluate()) { 117 pumpOneEventForFilters(id); 118 } 119 removeEventFilter(filter); 120 } 121 122 void addEventFilter(EventFilter filter) { 123 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 124 eventLog.finest("adding the event filter: " + filter); 125 } 126 synchronized (eventFilters) { 127 if (!eventFilters.contains(filter)) { 128 if (filter instanceof ModalEventFilter) { 129 ModalEventFilter newFilter = (ModalEventFilter)filter; 130 int k = 0; 131 for (k = 0; k < eventFilters.size(); k++) { 132 EventFilter f = eventFilters.get(k); 133 if (f instanceof ModalEventFilter) { 134 ModalEventFilter cf = (ModalEventFilter)f; 135 if (cf.compareTo(newFilter) > 0) { 136 break; 137 } 138 } 139 } 140 eventFilters.add(k, filter); 141 } else { 142 eventFilters.add(filter); 143 } 144 } 145 } 146 } 147 148 void removeEventFilter(EventFilter filter) { 149 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 150 eventLog.finest("removing the event filter: " + filter); 151 } 152 synchronized (eventFilters) { 153 eventFilters.remove(filter); 154 } 155 } 156 157 void pumpOneEventForFilters(int id) { 158 AWTEvent event = null; 159 boolean eventOK = false; 160 try { 161 EventQueue eq = null; 162 EventQueueDelegate.Delegate delegate = null; 163 do { 164 // EventQueue may change during the dispatching 165 eq = getEventQueue(); 166 delegate = EventQueueDelegate.getDelegate(); 167 168 if (delegate != null && id == ANY_EVENT) { 169 event = delegate.getNextEvent(eq); 170 } else { 171 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id); 172 } 173 174 eventOK = true; 175 synchronized (eventFilters) { 176 for (int i = eventFilters.size() - 1; i >= 0; i--) { 177 EventFilter f = eventFilters.get(i); 178 EventFilter.FilterAction accept = f.acceptEvent(event); 179 if (accept == EventFilter.FilterAction.REJECT) { 180 eventOK = false; 181 break; 182 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) { 183 break; 184 } 185 } 186 } 187 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event); 188 if (!eventOK) { 189 event.consume(); 190 } 191 } 192 while (eventOK == false); 193 194 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 195 eventLog.finest("Dispatching: " + event); 196 } 197 198 Object handle = null; 199 if (delegate != null) { 200 handle = delegate.beforeDispatch(event); 201 } 202 eq.dispatchEvent(event); 203 if (delegate != null) { 204 delegate.afterDispatch(event, handle); 205 } 206 } 207 catch (ThreadDeath death) { 208 doDispatch = false; 209 throw death; 210 } 211 catch (InterruptedException interruptedException) { 212 doDispatch = false; // AppContext.dispose() interrupts all 213 // Threads in the AppContext 214 } 215 catch (Throwable e) { 216 processException(e); 217 } 218 } 219 220 private void processException(Throwable e) { 221 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 222 eventLog.fine("Processing exception: " + e); 223 } 224 getUncaughtExceptionHandler().uncaughtException(this, e); 225 } 226 227 public synchronized EventQueue getEventQueue() { 228 return theQueue; 229 } 230 public synchronized void setEventQueue(EventQueue eq) { 231 theQueue = eq; 232 } 233 234 private static class HierarchyEventFilter implements EventFilter { 235 private Component modalComponent; 236 public HierarchyEventFilter(Component modalComponent) { 237 this.modalComponent = modalComponent; 238 } 239 public FilterAction acceptEvent(AWTEvent event) { 240 if (modalComponent != null) { 241 int eventID = event.getID(); 242 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) && 243 (eventID <= MouseEvent.MOUSE_LAST); 244 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) && 245 (eventID <= ActionEvent.ACTION_LAST); 246 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING); 247 /* 248 * filter out MouseEvent and ActionEvent that's outside 249 * the modalComponent hierarchy. 250 * KeyEvent is handled by using enqueueKeyEvent 251 * in Dialog.show 252 */ 253 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) { 254 /* 255 * Modal internal frames are handled separately. If event is 256 * for some component from another heavyweight than modalComp, 257 * it is accepted. If heavyweight is the same - we still accept 258 * event and perform further filtering in LightweightDispatcher 259 */ 260 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT; 261 } 262 if (mouseEvent || actionEvent || windowClosingEvent) { 263 Object o = event.getSource(); 264 if (o instanceof sun.awt.ModalExclude) { 265 // Exclude this object from modality and 266 // continue to pump it's events. 267 return FilterAction.ACCEPT; 268 } else if (o instanceof Component) { 269 Component c = (Component) o; 270 // 5.0u3 modal exclusion 271 boolean modalExcluded = false; 272 if (modalComponent instanceof Container) { 273 while (c != modalComponent && c != null) { 274 if ((c instanceof Window) && 275 (sun.awt.SunToolkit.isModalExcluded((Window)c))) { 276 // Exclude this window and all its children from 277 // modality and continue to pump it's events. 278 modalExcluded = true; 279 break; 280 } 281 c = c.getParent(); 282 } 283 } 284 if (!modalExcluded && (c != modalComponent)) { 285 return FilterAction.REJECT; 286 } 287 } 288 } 289 } 290 return FilterAction.ACCEPT; 291 } 292 } 293 }