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