2 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
28 import java.awt.event.MouseEvent;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.WindowEvent;
31 import java.lang.reflect.Method;
33 import java.util.ArrayList;
34 import java.util.concurrent.BlockingQueue;
35 import java.util.concurrent.Executor;
36 import java.util.concurrent.LinkedBlockingQueue;
37 import sun.util.logging.PlatformLogger;
39 import sun.awt.dnd.SunDragSourceContextPeer;
40 import sun.awt.EventQueueDelegate;
43 * EventDispatchThread is a package-private AWT class which takes
44 * events off the EventQueue and dispatches them to the appropriate
47 * The Thread starts a "permanent" event pump with a call to
48 * pumpEvents(Conditional) in its run() method. Event handlers can choose to
49 * block this event pump at any time, but should start a new pump (<b>not</b>
50 * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
51 * secondary event pump will exit automatically as soon as the Condtional
52 * evaluate()s to false and an additional Event is pumped and dispatched.
57 * @author David Mendenhall
61 final class EventDispatchThread {
63 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
65 private EventQueue theQueue;
66 private boolean doDispatch = true;
67 private volatile boolean shutdown = false;
69 static final int ANY_EVENT = -1;
71 private final Executor executor;
72 private ArrayList<EventFilter> eventFilters = new ArrayList<EventFilter>();
74 EventDispatchThread(ThreadGroup group, String name, EventQueue queue, ClassLoader l) {
75 // right now using simple executor that sort of mimics the old
76 // behavior of the run() method of EventDispatchThread. But when
77 // running together with FX, the executor should dispatch the runnable
78 // using Platform.invokeLater to share the same processing thread
79 executor = defaultThread(group, name, l);
83 private static Executor defaultThread(ThreadGroup group, String name, ClassLoader classLoader) {
84 class ExecRuns implements Executor, Runnable {
85 final BlockingQueue<Runnable> toRun = new LinkedBlockingQueue<>();
87 public void execute(Runnable command) {
97 } catch (InterruptedException ex) {
98 eventLog.severe(ex.getMessage(), ex);
105 ExecRuns er = new ExecRuns();
107 Thread t = new Thread(group, name);
108 t.setContextClassLoader(classLoader);
109 t.setPriority(Thread.NORM_PRIORITY + 1);
116 * Must be called on EDT only, that's why no synchronization
118 public void stopDispatching() {
122 public void interrupt() {
124 //XXX super.interrupt();
127 public void processEvents() {
128 executor.execute(new Runnable() {
132 // XXX: the meaning now should be: the pumpEvents processes
133 // currently pending events, and then it returns without
135 pumpEvents(new Conditional() {
136 public boolean evaluate() {
141 if(getEventQueue().detachDispatchThread(this, shutdown)) {
150 // This was added because this class (and java.awt.Conditional) are package private.
151 // There are certain instances where classes in other packages need to block the
152 // AWTEventQueue while still allowing it to process events. This uses reflection
153 // to call back into the caller in order to remove dependencies.
155 // NOTE: This uses reflection in its implementation, so it is not for performance critical code.
157 // cond is an instance of sun.lwawt.macosx.EventDispatchAccess
159 private Conditional _macosxGetConditional(final Object cond) {
161 return new Conditional() {
162 final Method evaluateMethod = Class.forName("sun.lwawt.macosx.EventDispatchAccess").getMethod("evaluate", null);
163 public boolean evaluate() {
165 return ((Boolean)evaluateMethod.invoke(cond, null)).booleanValue();
166 } catch (Exception e) {
171 } catch (Exception e) {
172 return new Conditional() { public boolean evaluate() { return false; } };
177 void pumpEvents(Conditional cond) {
178 pumpEvents(ANY_EVENT, cond);
181 void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
182 pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
185 void pumpEvents(int id, Conditional cond) {
186 pumpEventsForHierarchy(id, cond, null);
189 void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
190 pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
193 void pumpEventsForFilter(Conditional cond, EventFilter filter) {
194 pumpEventsForFilter(ANY_EVENT, cond, filter);
198 boolean isInterrupted() {
202 void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
203 addEventFilter(filter);
205 shutdown |= isInterrupted();
206 while (doDispatch && !shutdown && cond.evaluate()) {
207 pumpOneEventForFilters(id);
209 removeEventFilter(filter);
212 void addEventFilter(EventFilter filter) {
213 eventLog.finest("adding the event filter: " + filter);
214 synchronized (eventFilters) {
215 if (!eventFilters.contains(filter)) {
216 if (filter instanceof ModalEventFilter) {
217 ModalEventFilter newFilter = (ModalEventFilter)filter;
219 for (k = 0; k < eventFilters.size(); k++) {
220 EventFilter f = eventFilters.get(k);
221 if (f instanceof ModalEventFilter) {
222 ModalEventFilter cf = (ModalEventFilter)f;
223 if (cf.compareTo(newFilter) > 0) {
228 eventFilters.add(k, filter);
230 eventFilters.add(filter);
236 void removeEventFilter(EventFilter filter) {
237 eventLog.finest("removing the event filter: " + filter);
238 synchronized (eventFilters) {
239 eventFilters.remove(filter);
243 boolean blockWhenNoEvent() {
247 void pumpOneEventForFilters(int id) {
248 AWTEvent event = null;
249 boolean eventOK = false;
251 EventQueue eq = null;
252 EventQueueDelegate.Delegate delegate = null;
254 // EventQueue may change during the dispatching
255 eq = getEventQueue();
256 delegate = EventQueueDelegate.getDelegate();
258 if (delegate != null && id == ANY_EVENT) {
259 event = delegate.getNextEvent(eq);
261 event = eq.getNextEvent(id, blockWhenNoEvent());
268 synchronized (eventFilters) {
269 for (int i = eventFilters.size() - 1; i >= 0; i--) {
270 EventFilter f = eventFilters.get(i);
271 EventFilter.FilterAction accept = f.acceptEvent(event);
272 if (accept == EventFilter.FilterAction.REJECT) {
275 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
280 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
285 while (eventOK == false);
287 if (eventLog.isLoggable(PlatformLogger.FINEST)) {
288 eventLog.finest("Dispatching: " + event);
291 Object handle = null;
292 if (delegate != null) {
293 handle = delegate.beforeDispatch(event);
295 eq.dispatchEvent(event);
296 if (delegate != null) {
297 delegate.afterDispatch(event, handle);
300 catch (ThreadDeath death) {
304 catch (InterruptedException interruptedException) {
305 shutdown = true; // AppContext.dispose() interrupts all
306 // Threads in the AppContext
308 catch (Throwable e) {
313 private void processException(Throwable e) {
314 if (eventLog.isLoggable(PlatformLogger.FINE)) {
315 eventLog.fine("Processing exception: " + e);
317 //XXX getUncaughtExceptionHandler().uncaughtException(this, e);
320 public static EventDispatchThread findCurrent() {
321 //XXX return (EventDispatchThread)Thread.currentThread();
325 public synchronized EventQueue getEventQueue() {
328 public synchronized void setEventQueue(EventQueue eq) {
332 private static class HierarchyEventFilter implements EventFilter {
333 private Component modalComponent;
334 public HierarchyEventFilter(Component modalComponent) {
335 this.modalComponent = modalComponent;
337 public FilterAction acceptEvent(AWTEvent event) {
338 if (modalComponent != null) {
339 int eventID = event.getID();
340 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
341 (eventID <= MouseEvent.MOUSE_LAST);
342 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
343 (eventID <= ActionEvent.ACTION_LAST);
344 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
346 * filter out MouseEvent and ActionEvent that's outside
347 * the modalComponent hierarchy.
348 * KeyEvent is handled by using enqueueKeyEvent
351 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
353 * Modal internal frames are handled separately. If event is
354 * for some component from another heavyweight than modalComp,
355 * it is accepted. If heavyweight is the same - we still accept
356 * event and perform further filtering in LightweightDispatcher
358 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
360 if (mouseEvent || actionEvent || windowClosingEvent) {
361 Object o = event.getSource();
362 if (o instanceof sun.awt.ModalExclude) {
363 // Exclude this object from modality and
364 // continue to pump it's events.
365 return FilterAction.ACCEPT;
366 } else if (o instanceof Component) {
367 Component c = (Component) o;
368 // 5.0u3 modal exclusion
369 boolean modalExcluded = false;
370 if (modalComponent instanceof Container) {
371 while (c != modalComponent && c != null) {
372 if ((c instanceof Window) &&
373 (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
374 // Exclude this window and all its children from
375 // modality and continue to pump it's events.
376 modalExcluded = true;
382 if (!modalExcluded && (c != modalComponent)) {
383 return FilterAction.REJECT;
388 return FilterAction.ACCEPT;