1. /*
  2. * @(#)EventDispatchThread.java 1.34 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.lang.reflect.Method;
  9. import java.security.AccessController;
  10. import sun.security.action.GetPropertyAction;
  11. import java.awt.event.InputEvent;
  12. /**
  13. * EventDispatchThread is a package-private AWT class which takes
  14. * events off the EventQueue and dispatches them to the appropriate
  15. * AWT components.
  16. *
  17. * The Thread starts a "permanent" event pump with a call to
  18. * pumpEvents(Conditional) in its run() method. Event handlers can choose to
  19. * block this event pump at any time, but should start a new pump (<b>not</b>
  20. * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
  21. * secondary event pump will exit automatically as soon as the Condtional
  22. * evaluate()s to false and an additional Event is pumped and dispatched.
  23. *
  24. * @version 1.34 11/29/01
  25. * @author Tom Ball
  26. * @author Amy Fowler
  27. * @author Fred Ecks
  28. * @author David Mendenhall
  29. */
  30. class EventDispatchThread extends Thread {
  31. private EventQueue theQueue;
  32. private boolean doDispatch = true;
  33. EventDispatchThread(String name, EventQueue queue) {
  34. super(name);
  35. theQueue = queue;
  36. }
  37. public void stopDispatching() {
  38. // Note: We stop dispatching via a flag rather than using
  39. // Thread.interrupt() because we can't guarantee that the wait()
  40. // we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
  41. doDispatch = false;
  42. // fix 4122683, 4128923
  43. // Post an empty event to ensure getNextEvent is unblocked
  44. //
  45. // We have to use postEventPrivate instead of postEvent because
  46. // EventQueue.pop calls EventDispatchThread.stopDispatching.
  47. // Calling SunToolkit.flushPendingEvents in this case could
  48. // lead to deadlock.
  49. theQueue.postEventPrivate(new EmptyEvent());
  50. // wait for the dispatcher to complete
  51. if (Thread.currentThread() != this) {
  52. try {
  53. join();
  54. } catch(InterruptedException e) {
  55. }
  56. }
  57. }
  58. class EmptyEvent extends AWTEvent implements ActiveEvent {
  59. public EmptyEvent() {
  60. super(EventDispatchThread.this,0);
  61. }
  62. public void dispatch() {}
  63. }
  64. public void run() {
  65. pumpEvents(new Conditional() {
  66. public boolean evaluate() {
  67. return true;
  68. }
  69. });
  70. }
  71. void pumpEvents(Conditional cond) {
  72. pumpEventsForComponent(cond, null);
  73. }
  74. void pumpEventsForComponent(Conditional cond, Component modalComponent) {
  75. while (doDispatch && cond.evaluate()) {
  76. if (isInterrupted() || !pumpOneEventForComponent(modalComponent)) {
  77. doDispatch = false;
  78. }
  79. }
  80. }
  81. boolean pumpOneEvent() {
  82. return pumpOneEventForComponent(null);
  83. }
  84. boolean pumpOneEventForComponent(Component modalComponent) {
  85. try {
  86. AWTEvent event = theQueue.getNextEvent();
  87. if (modalComponent != null) {
  88. while (event instanceof InputEvent) {
  89. Component c = (Component)event.getSource();
  90. // check if c's modalComponent's child
  91. while (c != modalComponent && c != null)
  92. c = c.getParent();
  93. if (c != modalComponent)
  94. event = theQueue.getNextEvent();
  95. else
  96. break;
  97. }
  98. }
  99. theQueue.dispatchEvent(event);
  100. return true;
  101. } catch (ThreadDeath death) {
  102. return false;
  103. } catch (InterruptedException interruptedException) {
  104. return false; // AppContext.dispose() interrupts all
  105. // Threads in the AppContext
  106. } catch (Throwable e) {
  107. if (!handleException(e)) {
  108. System.err.println(
  109. "Exception occurred during event dispatching:");
  110. e.printStackTrace();
  111. }
  112. return true;
  113. }
  114. }
  115. private static final String handlerPropName = "sun.awt.exception.handler";
  116. private static String handlerClassName = null;
  117. private static String NO_HANDLER = new String();
  118. /**
  119. * Handles an exception thrown in the event-dispatch thread.
  120. *
  121. * <p> If the system property "sun.awt.exception.handler" is defined, then
  122. * when this method is invoked it will attempt to do the following:
  123. *
  124. * <ol>
  125. * <li> Load the class named by the value of that property, using the
  126. * current thread's context class loader,
  127. * <li> Instantiate that class using its zero-argument constructor,
  128. * <li> Find the resulting handler object's <tt>public void handle</tt>
  129. * method, which should take a single argument of type
  130. * <tt>Throwable</tt>, and
  131. * <li> Invoke the handler's <tt>handle</tt> method, passing it the
  132. * <tt>thrown</tt> argument that was passed to this method.
  133. * </ol>
  134. *
  135. * If any of the first three steps fail then this method will return
  136. * <tt>false</tt> and all following invocations of this method will return
  137. * <tt>false</tt> immediately. An exception thrown by the handler object's
  138. * <tt>handle</tt> will be caught, and will cause this method to return
  139. * <tt>false</tt>. If the handler's <tt>handle</tt> method is successfully
  140. * invoked, then this method will return <tt>true</tt>. This method will
  141. * never throw any sort of exception.
  142. *
  143. * <p> <i>Note:</i> This method is a temporary hack to work around the
  144. * absence of a real API that provides the ability to replace the
  145. * event-dispatch thread. The magic "sun.awt.exception.handler" property
  146. * <i>will be removed</i> in a future release.
  147. *
  148. * @param thrown The Throwable that was thrown in the event-dispatch
  149. * thread
  150. *
  151. * @returns <tt>false</tt> if any of the above steps failed, otherwise
  152. * <tt>true</tt>.
  153. */
  154. private boolean handleException(Throwable thrown) {
  155. try {
  156. if (handlerClassName == NO_HANDLER) {
  157. return false; /* Already tried, and failed */
  158. }
  159. /* Look up the class name */
  160. if (handlerClassName == null) {
  161. handlerClassName = ((String) AccessController.doPrivileged(
  162. new GetPropertyAction(handlerPropName)));
  163. if (handlerClassName == null) {
  164. handlerClassName = NO_HANDLER; /* Do not try this again */
  165. return false;
  166. }
  167. }
  168. /* Load the class, instantiate it, and find its handle method */
  169. Method m;
  170. Object h;
  171. try {
  172. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  173. Class c = Class.forName(handlerClassName, true, cl);
  174. m = c.getMethod("handle", new Class[] { Throwable.class });
  175. h = c.newInstance();
  176. } catch (Throwable x) {
  177. handlerClassName = NO_HANDLER; /* Do not try this again */
  178. return false;
  179. }
  180. /* Finally, invoke the handler */
  181. m.invoke(h, new Object[] { thrown });
  182. } catch (Throwable x) {
  183. return false;
  184. }
  185. return true;
  186. }
  187. boolean isDispatching(EventQueue eq) {
  188. return theQueue.equals(eq);
  189. }
  190. EventQueue getEventQueue() { return theQueue; }
  191. }