mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
348 lines
13 KiB
Java
348 lines
13 KiB
Java
/*
|
|
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
|
|
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
|
|
*/
|
|
|
|
/*
|
|
* @(#)EventDispatchThread.java 1.46 03/01/23
|
|
*
|
|
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
|
|
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
|
|
package java.awt;
|
|
|
|
import java.awt.event.InputEvent;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.ActionEvent;
|
|
import java.lang.reflect.Method;
|
|
import java.security.AccessController;
|
|
import sun.security.action.GetPropertyAction;
|
|
import sun.awt.DebugHelper;
|
|
import sun.awt.AWTAutoShutdown;
|
|
import sun.awt.SunToolkit;
|
|
|
|
import sun.awt.dnd.SunDragSourceContextPeer;
|
|
|
|
/**
|
|
* EventDispatchThread is a package-private AWT class which takes
|
|
* events off the EventQueue and dispatches them to the appropriate
|
|
* AWT components.
|
|
*
|
|
* The Thread starts a "permanent" event pump with a call to
|
|
* pumpEvents(Conditional) in its run() method. Event handlers can choose to
|
|
* block this event pump at any time, but should start a new pump (<b>not</b>
|
|
* a new EventDispatchThread) by again calling pumpEvents(Conditional). This
|
|
* secondary event pump will exit automatically as soon as the Condtional
|
|
* evaluate()s to false and an additional Event is pumped and dispatched.
|
|
*
|
|
* @author Tom Ball
|
|
* @author Amy Fowler
|
|
* @author Fred Ecks
|
|
* @author David Mendenhall
|
|
*
|
|
* @version 1.46, 01/23/03
|
|
* @since 1.1
|
|
*/
|
|
class EventDispatchThread extends Thread {
|
|
|
|
private EventQueue theQueue;
|
|
private boolean doDispatch = true;
|
|
private static final int ANY_EVENT = -1;
|
|
|
|
EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
|
|
super(group, name);
|
|
theQueue = queue;
|
|
}
|
|
|
|
void stopDispatchingImpl(boolean wait) {
|
|
// Note: We stop dispatching via a flag rather than using
|
|
// Thread.interrupt() because we can't guarantee that the wait()
|
|
// we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
|
|
|
|
doDispatch = false;
|
|
|
|
// wait for the dispatcher to complete
|
|
if (Thread.currentThread() != this) {
|
|
|
|
// fix 4122683, 4128923
|
|
// Post an empty event to ensure getNextEvent is unblocked
|
|
//
|
|
// We have to use postEventPrivate instead of postEvent because
|
|
// EventQueue.pop calls EventDispatchThread.stopDispatching.
|
|
// Calling SunToolkit.flushPendingEvents in this case could
|
|
// lead to deadlock.
|
|
theQueue.postEventPrivate(new EmptyEvent());
|
|
|
|
if (wait) {
|
|
try {
|
|
join();
|
|
} catch(InterruptedException e) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void stopDispatching() {
|
|
stopDispatchingImpl(true);
|
|
}
|
|
|
|
public void stopDispatchingLater() {
|
|
stopDispatchingImpl(false);
|
|
}
|
|
|
|
class EmptyEvent extends AWTEvent implements ActiveEvent {
|
|
public EmptyEvent() {
|
|
super(EventDispatchThread.this,0);
|
|
}
|
|
|
|
public void dispatch() {}
|
|
}
|
|
|
|
public void run() {
|
|
try {
|
|
pumpEvents(new Conditional() {
|
|
public boolean evaluate() {
|
|
return true;
|
|
}
|
|
});
|
|
} finally {
|
|
/*
|
|
* This synchronized block is to secure that the event dispatch
|
|
* thread won't die in the middle of posting a new event to the
|
|
* associated event queue. It is important because we notify
|
|
* that the event dispatch thread is busy after posting a new event
|
|
* to its queue, so the EventQueue.dispatchThread reference must
|
|
* be valid at that point.
|
|
*/
|
|
boolean outOfMem = false;
|
|
synchronized (theQueue) {
|
|
if (theQueue.getDispatchThread() == this) {
|
|
theQueue.detachDispatchThread();
|
|
}
|
|
/*
|
|
* Event dispatch thread dies in case of an uncaught exception.
|
|
* A new event dispatch thread for this queue will be started
|
|
* only if a new event is posted to it. In case if no more
|
|
* events are posted after this thread died all events that
|
|
* currently are in the queue will never be dispatched.
|
|
*/
|
|
/*
|
|
* Fix for 4648733. Check both the associated java event
|
|
* queue and the PostEventQueue.
|
|
*/
|
|
try {
|
|
if (theQueue.peekEvent() != null ||
|
|
!SunToolkit.isPostEventQueueEmpty()) {
|
|
try {
|
|
theQueue.initDispatchThread();
|
|
} catch (OutOfMemoryError e) {
|
|
outOfMem = true;
|
|
}
|
|
}
|
|
} finally {
|
|
AWTAutoShutdown.getInstance().notifyThreadFree(this);
|
|
}
|
|
}
|
|
if (outOfMem) {
|
|
try {
|
|
System.err.println("Error: cannot restart AWT Event" +
|
|
" Dispatcher (out of memory). Exiting...");
|
|
} catch (OutOfMemoryError e) {}
|
|
System.exit(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pumpEvents(Conditional cond) {
|
|
pumpEvents(ANY_EVENT, cond);
|
|
}
|
|
|
|
void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
|
|
pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
|
|
}
|
|
|
|
void pumpEvents(int id, Conditional cond) {
|
|
pumpEventsForHierarchy(id, cond, null);
|
|
}
|
|
|
|
void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent)
|
|
{
|
|
while (doDispatch && cond.evaluate()) {
|
|
if (isInterrupted() || !pumpOneEventForHierarchy(id, modalComponent)) {
|
|
doDispatch = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean pumpOneEventForHierarchy(int id, Component modalComponent) {
|
|
try {
|
|
AWTEvent event;
|
|
boolean eventOK;
|
|
do {
|
|
event = (id == ANY_EVENT)
|
|
? theQueue.getNextEvent()
|
|
: theQueue.getNextEvent(id);
|
|
|
|
eventOK = true;
|
|
if (modalComponent != null) {
|
|
/*
|
|
* filter out MouseEvent and ActionEvent that's outside
|
|
* the modalComponent hierarchy.
|
|
* KeyEvent is handled by using enqueueKeyEvent
|
|
* in Dialog.show
|
|
*/
|
|
int eventID = event.getID();
|
|
if ((eventID >= MouseEvent.MOUSE_FIRST &&
|
|
eventID <= MouseEvent.MOUSE_LAST) ||
|
|
(eventID >= ActionEvent.ACTION_FIRST &&
|
|
eventID <= ActionEvent.ACTION_LAST)) {
|
|
Object o = event.getSource();
|
|
if (o instanceof Component) {
|
|
Component c = (Component) o;
|
|
if (modalComponent instanceof Container) {
|
|
while (c != modalComponent && c != null) {
|
|
c = c.getParent();
|
|
}
|
|
}
|
|
if (c != modalComponent) {
|
|
eventOK = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
|
|
if (!eventOK) {
|
|
event.consume();
|
|
}
|
|
} while (eventOK == false);
|
|
|
|
theQueue.dispatchEvent(event);
|
|
return true;
|
|
} catch (ThreadDeath death) {
|
|
return false;
|
|
|
|
} catch (InterruptedException interruptedException) {
|
|
return false; // AppContext.dispose() interrupts all
|
|
// Threads in the AppContext
|
|
|
|
// Can get and throw only unchecked exceptions
|
|
} catch (RuntimeException e) {
|
|
processException(e, modalComponent != null);
|
|
} catch (Error e) {
|
|
processException(e, modalComponent != null);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void processException(Throwable e, boolean isModal) {
|
|
if (!handleException(e)) {
|
|
// See bug ID 4499199.
|
|
// If we are in a modal dialog, we cannot throw
|
|
// an exception for the ThreadGroup to handle (as added
|
|
// in RFE 4063022). If we did, the message pump of
|
|
// the modal dialog would be interrupted.
|
|
// We instead choose to handle the exception ourselves.
|
|
// It may be useful to add either a runtime flag or API
|
|
// later if someone would like to instead dispose the
|
|
// dialog and allow the thread group to handle it.
|
|
if (isModal) {
|
|
System.err.println(
|
|
"Exception occurred during event dispatching:");
|
|
e.printStackTrace();
|
|
} else if (e instanceof RuntimeException) {
|
|
throw (RuntimeException)e;
|
|
} else if (e instanceof Error) {
|
|
throw (Error)e;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static final String handlerPropName = "sun.awt.exception.handler";
|
|
private static String handlerClassName = null;
|
|
private static String NO_HANDLER = new String();
|
|
|
|
/**
|
|
* Handles an exception thrown in the event-dispatch thread.
|
|
*
|
|
* <p> If the system property "sun.awt.exception.handler" is defined, then
|
|
* when this method is invoked it will attempt to do the following:
|
|
*
|
|
* <ol>
|
|
* <li> Load the class named by the value of that property, using the
|
|
* current thread's context class loader,
|
|
* <li> Instantiate that class using its zero-argument constructor,
|
|
* <li> Find the resulting handler object's <tt>public void handle</tt>
|
|
* method, which should take a single argument of type
|
|
* <tt>Throwable</tt>, and
|
|
* <li> Invoke the handler's <tt>handle</tt> method, passing it the
|
|
* <tt>thrown</tt> argument that was passed to this method.
|
|
* </ol>
|
|
*
|
|
* If any of the first three steps fail then this method will return
|
|
* <tt>false</tt> and all following invocations of this method will return
|
|
* <tt>false</tt> immediately. An exception thrown by the handler object's
|
|
* <tt>handle</tt> will be caught, and will cause this method to return
|
|
* <tt>false</tt>. If the handler's <tt>handle</tt> method is successfully
|
|
* invoked, then this method will return <tt>true</tt>. This method will
|
|
* never throw any sort of exception.
|
|
*
|
|
* <p> <i>Note:</i> This method is a temporary hack to work around the
|
|
* absence of a real API that provides the ability to replace the
|
|
* event-dispatch thread. The magic "sun.awt.exception.handler" property
|
|
* <i>will be removed</i> in a future release.
|
|
*
|
|
* @param thrown The Throwable that was thrown in the event-dispatch
|
|
* thread
|
|
*
|
|
* @return <tt>false</tt> if any of the above steps failed, otherwise
|
|
* <tt>true</tt>
|
|
*/
|
|
private boolean handleException(Throwable thrown) {
|
|
|
|
try {
|
|
|
|
if (handlerClassName == NO_HANDLER) {
|
|
return false; /* Already tried, and failed */
|
|
}
|
|
|
|
/* Look up the class name */
|
|
if (handlerClassName == null) {
|
|
handlerClassName = ((String) AccessController.doPrivileged(
|
|
new GetPropertyAction(handlerPropName)));
|
|
if (handlerClassName == null) {
|
|
handlerClassName = NO_HANDLER; /* Do not try this again */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Load the class, instantiate it, and find its handle method */
|
|
Method m;
|
|
Object h;
|
|
try {
|
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
|
Class c = Class.forName(handlerClassName, true, cl);
|
|
m = c.getMethod("handle", new Class[] { Throwable.class });
|
|
h = c.newInstance();
|
|
} catch (Throwable x) {
|
|
handlerClassName = NO_HANDLER; /* Do not try this again */
|
|
return false;
|
|
}
|
|
|
|
/* Finally, invoke the handler */
|
|
m.invoke(h, new Object[] { thrown });
|
|
|
|
} catch (Throwable x) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
boolean isDispatching(EventQueue eq) {
|
|
return theQueue.equals(eq);
|
|
}
|
|
|
|
EventQueue getEventQueue() { return theQueue; }
|
|
}
|