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