1 /* 2 * Copyright (c) 1996, 2015, 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 34 import sun.util.logging.PlatformLogger; 35 36 import sun.awt.dnd.SunDragSourceContextPeer; 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 Conditional 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 /** 69 * Must always call 5 args super-class constructor passing false 70 * to indicate not to inherit locals. 71 */ 72 private EventDispatchThread() { 73 throw new UnsupportedOperationException("Must erase locals"); 74 } 75 76 EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { 77 super(group, null, name, 0, false); 78 setEventQueue(queue); 79 } 80 81 /* 82 * Must be called on EDT only, that's why no synchronization 83 */ 84 public void stopDispatching() { 85 doDispatch = false; 86 } 87 88 public void run() { 89 try { 90 pumpEvents(new Conditional() { 91 public boolean evaluate() { 92 return true; 93 } 94 }); 95 } finally { 96 getEventQueue().detachDispatchThread(this); 97 } 98 } 99 100 void pumpEvents(Conditional cond) { 101 pumpEvents(ANY_EVENT, cond); 102 } 103 104 void pumpEventsForHierarchy(Conditional cond, Component modalComponent) { 105 pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent); 106 } 107 108 void pumpEvents(int id, Conditional cond) { 109 pumpEventsForHierarchy(id, cond, null); 110 } 111 112 void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) { 113 pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent)); 114 } 115 116 void pumpEventsForFilter(Conditional cond, EventFilter filter) { 117 pumpEventsForFilter(ANY_EVENT, cond, filter); 118 } 119 120 void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) { 121 addEventFilter(filter); 122 doDispatch = true; 123 while (doDispatch && !isInterrupted() && cond.evaluate()) { 124 pumpOneEventForFilters(id); 125 } 126 removeEventFilter(filter); 127 } 128 129 void addEventFilter(EventFilter filter) { 130 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 131 eventLog.finest("adding the event filter: " + filter); 132 } 133 synchronized (eventFilters) { 134 if (!eventFilters.contains(filter)) { 135 if (filter instanceof ModalEventFilter) { 136 ModalEventFilter newFilter = (ModalEventFilter)filter; 137 int k = 0; 138 for (k = 0; k < eventFilters.size(); k++) { 139 EventFilter f = eventFilters.get(k); 140 if (f instanceof ModalEventFilter) { 141 ModalEventFilter cf = (ModalEventFilter)f; 142 if (cf.compareTo(newFilter) > 0) { 143 break; 144 } 145 } 146 } 147 eventFilters.add(k, filter); 148 } else { 149 eventFilters.add(filter); 150 } 151 } 152 } 153 } 154 155 void removeEventFilter(EventFilter filter) { 156 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 157 eventLog.finest("removing the event filter: " + filter); 158 } 159 synchronized (eventFilters) { 160 eventFilters.remove(filter); 161 } 162 } 163 164 void pumpOneEventForFilters(int id) { 165 AWTEvent event = null; 166 boolean eventOK = false; 167 try { 168 EventQueue eq = null; 169 do { 170 // EventQueue may change during the dispatching 171 eq = getEventQueue(); 172 173 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id); 174 175 eventOK = true; 176 synchronized (eventFilters) { 177 for (int i = eventFilters.size() - 1; i >= 0; i--) { 178 EventFilter f = eventFilters.get(i); 179 EventFilter.FilterAction accept = f.acceptEvent(event); 180 if (accept == EventFilter.FilterAction.REJECT) { 181 eventOK = false; 182 break; 183 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) { 184 break; 185 } 186 } 187 } 188 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event); 189 if (!eventOK) { 190 event.consume(); 191 } 192 } 193 while (eventOK == false); 194 195 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 196 eventLog.finest("Dispatching: " + event); 197 } 198 199 eq.dispatchEvent(event); 200 } 201 catch (ThreadDeath death) { 202 doDispatch = false; 203 throw death; 204 } 205 catch (InterruptedException interruptedException) { 206 doDispatch = false; // AppContext.dispose() interrupts all 207 // Threads in the AppContext 208 } 209 catch (Throwable e) { 210 processException(e); 211 } 212 } 213 214 private void processException(Throwable e) { 215 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 216 eventLog.fine("Processing exception: " + e); 217 } 218 getUncaughtExceptionHandler().uncaughtException(this, e); 219 } 220 221 public synchronized EventQueue getEventQueue() { 222 return theQueue; 223 } 224 public synchronized void setEventQueue(EventQueue eq) { 225 theQueue = eq; 226 } 227 228 private static class HierarchyEventFilter implements EventFilter { 229 private Component modalComponent; 230 public HierarchyEventFilter(Component modalComponent) { 231 this.modalComponent = modalComponent; 232 } 233 public FilterAction acceptEvent(AWTEvent event) { 234 if (modalComponent != null) { 235 int eventID = event.getID(); 236 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) && 237 (eventID <= MouseEvent.MOUSE_LAST); 238 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) && 239 (eventID <= ActionEvent.ACTION_LAST); 240 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING); 241 /* 242 * filter out MouseEvent and ActionEvent that's outside 243 * the modalComponent hierarchy. 244 * KeyEvent is handled by using enqueueKeyEvent 245 * in Dialog.show 246 */ 247 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) { 248 /* 249 * Modal internal frames are handled separately. If event is 250 * for some component from another heavyweight than modalComp, 251 * it is accepted. If heavyweight is the same - we still accept 252 * event and perform further filtering in LightweightDispatcher 253 */ 254 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT; 255 } 256 if (mouseEvent || actionEvent || windowClosingEvent) { 257 Object o = event.getSource(); 258 if (o instanceof sun.awt.ModalExclude) { 259 // Exclude this object from modality and 260 // continue to pump it's events. 261 return FilterAction.ACCEPT; 262 } else if (o instanceof Component) { 263 Component c = (Component) o; 264 // 5.0u3 modal exclusion 265 boolean modalExcluded = false; 266 if (modalComponent instanceof Container) { 267 while (c != modalComponent && c != null) { 268 if ((c instanceof Window) && 269 (sun.awt.SunToolkit.isModalExcluded((Window)c))) { 270 // Exclude this window and all its children from 271 // modality and continue to pump it's events. 272 modalExcluded = true; 273 break; 274 } 275 c = c.getParent(); 276 } 277 } 278 if (!modalExcluded && (c != modalComponent)) { 279 return FilterAction.REJECT; 280 } 281 } 282 } 283 } 284 return FilterAction.ACCEPT; 285 } 286 } 287 }