EventDispatchThread.java revision 1696
0N/A/*
726N/A * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation. Sun designates this
0N/A * particular file as subject to the "Classpath" exception as provided
0N/A * by Sun in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
0N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0N/A * CA 95054 USA or visit www.sun.com if you need additional information or
0N/A * have any questions.
0N/A */
0N/A
0N/Apackage java.awt;
0N/A
0N/Aimport java.awt.event.InputEvent;
0N/Aimport java.awt.event.MouseEvent;
0N/Aimport java.awt.event.ActionEvent;
0N/Aimport java.awt.event.WindowEvent;
0N/Aimport java.lang.reflect.Method;
0N/Aimport java.security.AccessController;
0N/Aimport sun.security.action.GetPropertyAction;
0N/Aimport sun.awt.AWTAutoShutdown;
0N/Aimport sun.awt.SunToolkit;
0N/A
0N/Aimport java.util.Vector;
1696N/Aimport sun.util.logging.PlatformLogger;
0N/A
0N/Aimport sun.awt.dnd.SunDragSourceContextPeer;
617N/Aimport sun.awt.EventQueueDelegate;
0N/A
0N/A/**
0N/A * EventDispatchThread is a package-private AWT class which takes
0N/A * events off the EventQueue and dispatches them to the appropriate
0N/A * AWT components.
0N/A *
0N/A * The Thread starts a "permanent" event pump with a call to
0N/A * pumpEvents(Conditional) in its run() method. Event handlers can choose to
0N/A * block this event pump at any time, but should start a new pump (<b>not</b>
0N/A * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
0N/A * secondary event pump will exit automatically as soon as the Condtional
0N/A * evaluate()s to false and an additional Event is pumped and dispatched.
0N/A *
0N/A * @author Tom Ball
0N/A * @author Amy Fowler
0N/A * @author Fred Ecks
0N/A * @author David Mendenhall
0N/A *
0N/A * @since 1.1
0N/A */
0N/Aclass EventDispatchThread extends Thread {
1696N/A private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
0N/A
0N/A private EventQueue theQueue;
0N/A private boolean doDispatch = true;
0N/A private static final int ANY_EVENT = -1;
0N/A
0N/A private Vector<EventFilter> eventFilters = new Vector<EventFilter>();
0N/A // used in handleException
0N/A private int modalFiltersCount = 0;
0N/A
0N/A EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
0N/A super(group, name);
0N/A theQueue = queue;
0N/A }
0N/A
0N/A void stopDispatchingImpl(boolean wait) {
0N/A // Note: We stop dispatching via a flag rather than using
0N/A // Thread.interrupt() because we can't guarantee that the wait()
0N/A // we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
0N/A
0N/A StopDispatchEvent stopEvent = new StopDispatchEvent();
0N/A
0N/A // wait for the dispatcher to complete
0N/A if (Thread.currentThread() != this) {
0N/A
0N/A // fix 4122683, 4128923
0N/A // Post an empty event to ensure getNextEvent is unblocked
0N/A //
0N/A // We have to use postEventPrivate instead of postEvent because
0N/A // EventQueue.pop calls EventDispatchThread.stopDispatching.
0N/A // Calling SunToolkit.flushPendingEvents in this case could
0N/A // lead to deadlock.
0N/A theQueue.postEventPrivate(stopEvent);
0N/A
0N/A if (wait) {
0N/A try {
0N/A join();
0N/A } catch(InterruptedException e) {
0N/A }
0N/A }
0N/A } else {
0N/A stopEvent.dispatch();
0N/A }
0N/A synchronized (theQueue) {
0N/A if (theQueue.getDispatchThread() == this) {
0N/A theQueue.detachDispatchThread();
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void stopDispatching() {
0N/A stopDispatchingImpl(true);
0N/A }
0N/A
0N/A public void stopDispatchingLater() {
0N/A stopDispatchingImpl(false);
0N/A }
0N/A
0N/A class StopDispatchEvent extends AWTEvent implements ActiveEvent {
0N/A /*
0N/A * serialVersionUID
0N/A */
0N/A static final long serialVersionUID = -3692158172100730735L;
0N/A
0N/A public StopDispatchEvent() {
0N/A super(EventDispatchThread.this,0);
0N/A }
0N/A
0N/A public void dispatch() {
0N/A doDispatch = false;
0N/A }
0N/A }
0N/A
0N/A public void run() {
0N/A try {
0N/A pumpEvents(new Conditional() {
0N/A public boolean evaluate() {
0N/A return true;
0N/A }
0N/A });
0N/A } finally {
0N/A /*
0N/A * This synchronized block is to secure that the event dispatch
0N/A * thread won't die in the middle of posting a new event to the
0N/A * associated event queue. It is important because we notify
0N/A * that the event dispatch thread is busy after posting a new event
0N/A * to its queue, so the EventQueue.dispatchThread reference must
0N/A * be valid at that point.
0N/A */
0N/A synchronized (theQueue) {
0N/A if (theQueue.getDispatchThread() == this) {
0N/A theQueue.detachDispatchThread();
0N/A }
0N/A /*
0N/A * Event dispatch thread dies in case of an uncaught exception.
0N/A * A new event dispatch thread for this queue will be started
0N/A * only if a new event is posted to it. In case if no more
0N/A * events are posted after this thread died all events that
0N/A * currently are in the queue will never be dispatched.
0N/A */
0N/A /*
0N/A * Fix for 4648733. Check both the associated java event
0N/A * queue and the PostEventQueue.
0N/A */
0N/A if (theQueue.peekEvent() != null ||
0N/A !SunToolkit.isPostEventQueueEmpty()) {
0N/A theQueue.initDispatchThread();
0N/A }
0N/A AWTAutoShutdown.getInstance().notifyThreadFree(this);
0N/A }
0N/A }
0N/A }
0N/A
0N/A void pumpEvents(Conditional cond) {
0N/A pumpEvents(ANY_EVENT, cond);
0N/A }
0N/A
0N/A void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
0N/A pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
0N/A }
0N/A
0N/A void pumpEvents(int id, Conditional cond) {
0N/A pumpEventsForHierarchy(id, cond, null);
0N/A }
0N/A
0N/A void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent)
0N/A {
0N/A pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
0N/A }
0N/A
0N/A void pumpEventsForFilter(Conditional cond, EventFilter filter) {
0N/A pumpEventsForFilter(ANY_EVENT, cond, filter);
0N/A }
0N/A
0N/A void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
0N/A addEventFilter(filter);
0N/A while (doDispatch && cond.evaluate()) {
0N/A if (isInterrupted() || !pumpOneEventForFilters(id)) {
0N/A doDispatch = false;
0N/A }
0N/A }
0N/A removeEventFilter(filter);
0N/A }
0N/A
0N/A void addEventFilter(EventFilter filter) {
0N/A synchronized (eventFilters) {
0N/A if (!eventFilters.contains(filter)) {
0N/A if (filter instanceof ModalEventFilter) {
0N/A ModalEventFilter newFilter = (ModalEventFilter)filter;
0N/A int k = 0;
0N/A for (k = 0; k < eventFilters.size(); k++) {
0N/A EventFilter f = eventFilters.get(k);
0N/A if (f instanceof ModalEventFilter) {
0N/A ModalEventFilter cf = (ModalEventFilter)f;
0N/A if (cf.compareTo(newFilter) > 0) {
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A eventFilters.add(k, filter);
0N/A modalFiltersCount++;
0N/A } else {
0N/A eventFilters.add(filter);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A void removeEventFilter(EventFilter filter) {
0N/A synchronized (eventFilters) {
0N/A if (eventFilters.contains(filter)) {
0N/A if (filter instanceof ModalEventFilter) {
0N/A modalFiltersCount--;
0N/A }
0N/A eventFilters.remove(filter);
0N/A }
0N/A }
0N/A }
0N/A
0N/A boolean pumpOneEventForFilters(int id) {
0N/A try {
0N/A AWTEvent event;
0N/A boolean eventOK;
617N/A EventQueueDelegate.Delegate delegate =
617N/A EventQueueDelegate.getDelegate();
0N/A do {
617N/A if (delegate != null && id == ANY_EVENT) {
617N/A event = delegate.getNextEvent(theQueue);
617N/A } else {
617N/A event = (id == ANY_EVENT)
617N/A ? theQueue.getNextEvent()
617N/A : theQueue.getNextEvent(id);
617N/A }
0N/A
0N/A eventOK = true;
0N/A synchronized (eventFilters) {
0N/A for (int i = eventFilters.size() - 1; i >= 0; i--) {
0N/A EventFilter f = eventFilters.get(i);
0N/A EventFilter.FilterAction accept = f.acceptEvent(event);
0N/A if (accept == EventFilter.FilterAction.REJECT) {
0N/A eventOK = false;
0N/A break;
0N/A } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
0N/A if (!eventOK) {
0N/A event.consume();
0N/A }
0N/A }
0N/A while (eventOK == false);
0N/A
1696N/A if (eventLog.isLoggable(PlatformLogger.FINEST)) {
1696N/A eventLog.finest("Dispatching: " + event);
0N/A }
0N/A
617N/A Object handle = null;
617N/A if (delegate != null) {
617N/A handle = delegate.beforeDispatch(event);
617N/A }
0N/A theQueue.dispatchEvent(event);
617N/A if (delegate != null) {
617N/A delegate.afterDispatch(event, handle);
617N/A }
0N/A return true;
0N/A }
0N/A catch (ThreadDeath death) {
0N/A return false;
0N/A
0N/A }
0N/A catch (InterruptedException interruptedException) {
0N/A return false; // AppContext.dispose() interrupts all
0N/A // Threads in the AppContext
0N/A
0N/A }
0N/A // Can get and throw only unchecked exceptions
0N/A catch (RuntimeException e) {
869N/A processException(e);
0N/A } catch (Error e) {
869N/A processException(e);
0N/A }
0N/A return true;
0N/A }
0N/A
869N/A private void processException(Throwable e) {
1696N/A if (eventLog.isLoggable(PlatformLogger.FINE)) {
1696N/A eventLog.fine("Processing exception: " + e);
0N/A }
869N/A getUncaughtExceptionHandler().uncaughtException(this, e);
869N/A // don't rethrow the exception to avoid EDT recreation
0N/A }
0N/A
0N/A boolean isDispatching(EventQueue eq) {
0N/A return theQueue.equals(eq);
0N/A }
0N/A
0N/A EventQueue getEventQueue() { return theQueue; }
0N/A
0N/A private static class HierarchyEventFilter implements EventFilter {
0N/A private Component modalComponent;
0N/A public HierarchyEventFilter(Component modalComponent) {
0N/A this.modalComponent = modalComponent;
0N/A }
0N/A public FilterAction acceptEvent(AWTEvent event) {
0N/A if (modalComponent != null) {
0N/A int eventID = event.getID();
0N/A boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
0N/A (eventID <= MouseEvent.MOUSE_LAST);
0N/A boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
0N/A (eventID <= ActionEvent.ACTION_LAST);
0N/A boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
0N/A /*
0N/A * filter out MouseEvent and ActionEvent that's outside
0N/A * the modalComponent hierarchy.
0N/A * KeyEvent is handled by using enqueueKeyEvent
0N/A * in Dialog.show
0N/A */
0N/A if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
0N/A /*
0N/A * Modal internal frames are handled separately. If event is
0N/A * for some component from another heavyweight than modalComp,
0N/A * it is accepted. If heavyweight is the same - we still accept
0N/A * event and perform further filtering in LightweightDispatcher
0N/A */
0N/A return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
0N/A }
0N/A if (mouseEvent || actionEvent || windowClosingEvent) {
0N/A Object o = event.getSource();
0N/A if (o instanceof sun.awt.ModalExclude) {
0N/A // Exclude this object from modality and
0N/A // continue to pump it's events.
0N/A return FilterAction.ACCEPT;
0N/A } else if (o instanceof Component) {
0N/A Component c = (Component) o;
0N/A // 5.0u3 modal exclusion
0N/A boolean modalExcluded = false;
0N/A if (modalComponent instanceof Container) {
0N/A while (c != modalComponent && c != null) {
0N/A if ((c instanceof Window) &&
0N/A (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
0N/A // Exclude this window and all its children from
0N/A // modality and continue to pump it's events.
0N/A modalExcluded = true;
0N/A break;
0N/A }
0N/A c = c.getParent();
0N/A }
0N/A }
0N/A if (!modalExcluded && (c != modalComponent)) {
0N/A return FilterAction.REJECT;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return FilterAction.ACCEPT;
0N/A }
0N/A }
0N/A}