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 */ EventDispatchThread()72 private EventDispatchThread() { 73 throw new UnsupportedOperationException("Must erase locals"); 74 } 75 EventDispatchThread(ThreadGroup group, String name, EventQueue queue)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 */ stopDispatching()84 public void stopDispatching() { 85 doDispatch = false; 86 } 87 run()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 pumpEvents(Conditional cond)100 void pumpEvents(Conditional cond) { 101 pumpEvents(ANY_EVENT, cond); 102 } 103 pumpEventsForHierarchy(Conditional cond, Component modalComponent)104 void pumpEventsForHierarchy(Conditional cond, Component modalComponent) { 105 pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent); 106 } 107 pumpEvents(int id, Conditional cond)108 void pumpEvents(int id, Conditional cond) { 109 pumpEventsForHierarchy(id, cond, null); 110 } 111 pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent)112 void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) { 113 pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent)); 114 } 115 pumpEventsForFilter(Conditional cond, EventFilter filter)116 void pumpEventsForFilter(Conditional cond, EventFilter filter) { 117 pumpEventsForFilter(ANY_EVENT, cond, filter); 118 } 119 pumpEventsForFilter(int id, Conditional cond, EventFilter filter)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 addEventFilter(EventFilter filter)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 removeEventFilter(EventFilter filter)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 filterAndCheckEvent(AWTEvent event)164 boolean filterAndCheckEvent(AWTEvent event) { 165 boolean eventOK = true; 166 synchronized (eventFilters) { 167 for (int i = eventFilters.size() - 1; i >= 0; i--) { 168 EventFilter f = eventFilters.get(i); 169 EventFilter.FilterAction accept = f.acceptEvent(event); 170 if (accept == EventFilter.FilterAction.REJECT) { 171 eventOK = false; 172 break; 173 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) { 174 break; 175 } 176 } 177 } 178 return eventOK && SunDragSourceContextPeer.checkEvent(event); 179 } 180 pumpOneEventForFilters(int id)181 void pumpOneEventForFilters(int id) { 182 AWTEvent event = null; 183 boolean eventOK = false; 184 try { 185 EventQueue eq = null; 186 do { 187 // EventQueue may change during the dispatching 188 eq = getEventQueue(); 189 190 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id); 191 192 eventOK = filterAndCheckEvent(event); 193 if (!eventOK) { 194 event.consume(); 195 } 196 } 197 while (eventOK == false); 198 199 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { 200 eventLog.finest("Dispatching: " + event); 201 } 202 203 eq.dispatchEvent(event); 204 } 205 catch (ThreadDeath death) { 206 doDispatch = false; 207 throw death; 208 } 209 catch (InterruptedException interruptedException) { 210 doDispatch = false; // AppContext.dispose() interrupts all 211 // Threads in the AppContext 212 } 213 catch (Throwable e) { 214 processException(e); 215 } 216 } 217 processException(Throwable e)218 private void processException(Throwable e) { 219 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { 220 eventLog.fine("Processing exception: " + e); 221 } 222 getUncaughtExceptionHandler().uncaughtException(this, e); 223 } 224 getEventQueue()225 public synchronized EventQueue getEventQueue() { 226 return theQueue; 227 } setEventQueue(EventQueue eq)228 public synchronized void setEventQueue(EventQueue eq) { 229 theQueue = eq; 230 } 231 232 private static class HierarchyEventFilter implements EventFilter { 233 private Component modalComponent; HierarchyEventFilter(Component modalComponent)234 public HierarchyEventFilter(Component modalComponent) { 235 this.modalComponent = modalComponent; 236 } acceptEvent(AWTEvent event)237 public FilterAction acceptEvent(AWTEvent event) { 238 if (modalComponent != null) { 239 int eventID = event.getID(); 240 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) && 241 (eventID <= MouseEvent.MOUSE_LAST); 242 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) && 243 (eventID <= ActionEvent.ACTION_LAST); 244 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING); 245 /* 246 * filter out MouseEvent and ActionEvent that's outside 247 * the modalComponent hierarchy. 248 * KeyEvent is handled by using enqueueKeyEvent 249 * in Dialog.show 250 */ 251 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) { 252 /* 253 * Modal internal frames are handled separately. If event is 254 * for some component from another heavyweight than modalComp, 255 * it is accepted. If heavyweight is the same - we still accept 256 * event and perform further filtering in LightweightDispatcher 257 */ 258 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT; 259 } 260 if (mouseEvent || actionEvent || windowClosingEvent) { 261 Object o = event.getSource(); 262 if (o instanceof sun.awt.ModalExclude) { 263 // Exclude this object from modality and 264 // continue to pump it's events. 265 return FilterAction.ACCEPT; 266 } else if (o instanceof Component) { 267 Component c = (Component) o; 268 // 5.0u3 modal exclusion 269 boolean modalExcluded = false; 270 if (modalComponent instanceof Container) { 271 while (c != modalComponent && c != null) { 272 if ((c instanceof Window) && 273 (sun.awt.SunToolkit.isModalExcluded((Window)c))) { 274 // Exclude this window and all its children from 275 // modality and continue to pump it's events. 276 modalExcluded = true; 277 break; 278 } 279 c = c.getParent(); 280 } 281 } 282 if (!modalExcluded && (c != modalComponent)) { 283 return FilterAction.REJECT; 284 } 285 } 286 } 287 } 288 return FilterAction.ACCEPT; 289 } 290 } 291 } 292