KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > EventDispatchThread


1 /*
2  * @(#)EventDispatchThread.java 1.54 05/03/03
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt;
9
10 import java.awt.event.InputEvent JavaDoc;
11 import java.awt.event.MouseEvent JavaDoc;
12 import java.awt.event.ActionEvent JavaDoc;
13 import java.awt.event.WindowEvent JavaDoc;
14 import java.lang.reflect.Method JavaDoc;
15 import java.security.AccessController JavaDoc;
16 import sun.security.action.GetPropertyAction;
17 import sun.awt.DebugHelper;
18 import sun.awt.AWTAutoShutdown;
19 import sun.awt.SunToolkit;
20
21 import sun.awt.dnd.SunDragSourceContextPeer;
22
23 /**
24  * EventDispatchThread is a package-private AWT class which takes
25  * events off the EventQueue and dispatches them to the appropriate
26  * AWT components.
27  *
28  * The Thread starts a "permanent" event pump with a call to
29  * pumpEvents(Conditional) in its run() method. Event handlers can choose to
30  * block this event pump at any time, but should start a new pump (<b>not</b>
31  * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
32  * secondary event pump will exit automatically as soon as the Condtional
33  * evaluate()s to false and an additional Event is pumped and dispatched.
34  *
35  * @author Tom Ball
36  * @author Amy Fowler
37  * @author Fred Ecks
38  * @author David Mendenhall
39  *
40  * @version 1.54, 03/03/05
41  * @since 1.1
42  */

43 class EventDispatchThread extends Thread JavaDoc {
44     private static final DebugHelper dbg = DebugHelper.create(EventDispatchThread JavaDoc.class);
45
46     private EventQueue JavaDoc theQueue;
47     private boolean doDispatch = true;
48     private static final int ANY_EVENT = -1;
49
50     EventDispatchThread(ThreadGroup JavaDoc group, String JavaDoc name, EventQueue JavaDoc queue) {
51         super(group, name);
52         theQueue = queue;
53     }
54
55     void stopDispatchingImpl(boolean wait) {
56         // Note: We stop dispatching via a flag rather than using
57
// Thread.interrupt() because we can't guarantee that the wait()
58
// we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
59

60         StopDispatchEvent stopEvent = new StopDispatchEvent();
61
62         // wait for the dispatcher to complete
63
if (Thread.currentThread() != this) {
64
65             // fix 4122683, 4128923
66
// Post an empty event to ensure getNextEvent is unblocked
67
//
68
// We have to use postEventPrivate instead of postEvent because
69
// EventQueue.pop calls EventDispatchThread.stopDispatching.
70
// Calling SunToolkit.flushPendingEvents in this case could
71
// lead to deadlock.
72
theQueue.postEventPrivate(stopEvent);
73                 
74             if (wait) {
75                 try {
76                     join();
77                 } catch(InterruptedException JavaDoc e) {
78                 }
79             }
80         } else {
81             stopEvent.dispatch();
82         }
83         synchronized (theQueue) {
84             if (theQueue.getDispatchThread() == this) {
85                 theQueue.detachDispatchThread();
86             }
87         }
88     }
89
90     public void stopDispatching() {
91         stopDispatchingImpl(true);
92     }
93
94     public void stopDispatchingLater() {
95         stopDispatchingImpl(false);
96     }
97
98     class StopDispatchEvent extends AWTEvent JavaDoc implements ActiveEvent JavaDoc {
99         public StopDispatchEvent() {
100             super(EventDispatchThread.this,0);
101         }
102
103         public void dispatch() {
104             doDispatch = false;
105         }
106     }
107
108     public void run() {
109     try {
110         pumpEvents(new Conditional JavaDoc() {
111         public boolean evaluate() {
112             return true;
113         }
114         });
115     } finally {
116         /*
117          * This synchronized block is to secure that the event dispatch
118          * thread won't die in the middle of posting a new event to the
119          * associated event queue. It is important because we notify
120          * that the event dispatch thread is busy after posting a new event
121          * to its queue, so the EventQueue.dispatchThread reference must
122          * be valid at that point.
123          */

124         synchronized (theQueue) {
125                 if (theQueue.getDispatchThread() == this) {
126                     theQueue.detachDispatchThread();
127                 }
128                 /*
129                  * Event dispatch thread dies in case of an uncaught exception.
130                  * A new event dispatch thread for this queue will be started
131                  * only if a new event is posted to it. In case if no more
132                  * events are posted after this thread died all events that
133                  * currently are in the queue will never be dispatched.
134                  */

135                 /*
136                  * Fix for 4648733. Check both the associated java event
137                  * queue and the PostEventQueue.
138                  */

139                 if (theQueue.peekEvent() != null ||
140                     !SunToolkit.isPostEventQueueEmpty()) {
141                     theQueue.initDispatchThread();
142                 }
143         AWTAutoShutdown.getInstance().notifyThreadFree(this);
144         }
145     }
146     }
147
148     void pumpEvents(Conditional JavaDoc cond) {
149     pumpEvents(ANY_EVENT, cond);
150     }
151
152     void pumpEventsForHierarchy(Conditional JavaDoc cond, Component JavaDoc modalComponent) {
153         pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
154     }
155
156     void pumpEvents(int id, Conditional JavaDoc cond) {
157         pumpEventsForHierarchy(id, cond, null);
158     }
159
160     void pumpEventsForHierarchy(int id, Conditional JavaDoc cond, Component JavaDoc modalComponent)
161     {
162         while (doDispatch && cond.evaluate()) {
163             if (isInterrupted() || !pumpOneEventForHierarchy(id, modalComponent)) {
164                 doDispatch = false;
165             }
166         }
167     }
168
169     boolean checkMouseEventForModalJInternalFrame(MouseEvent JavaDoc me, Component JavaDoc modalComp) {
170         // Check if the MouseEvent is targeted to the HW parent of the
171
// LW component, if so, then return true. The job of distinguishing
172
// between the LW components is done by the LW dispatcher.
173
if (modalComp instanceof javax.swing.JInternalFrame JavaDoc) {
174             Container JavaDoc c;
175             synchronized (modalComp.getTreeLock()) {
176                 c = ((Container JavaDoc)modalComp).getHeavyweightContainer();
177             }
178             if (me.getSource() == c)
179                 return true;
180         }
181         return false;
182     }
183
184     boolean pumpOneEventForHierarchy(int id, Component JavaDoc modalComponent) {
185         try {
186             AWTEvent JavaDoc event;
187             boolean eventOK;
188             do {
189             event = (id == ANY_EVENT)
190             ? theQueue.getNextEvent()
191             : theQueue.getNextEvent(id);
192
193                 eventOK = true;
194                 if (modalComponent != null) {
195                     /*
196                      * filter out MouseEvent and ActionEvent that's outside
197                      * the modalComponent hierarchy.
198                      * KeyEvent is handled by using enqueueKeyEvent
199                      * in Dialog.show
200                      */

201                     int eventID = event.getID();
202                     if (((eventID >= MouseEvent.MOUSE_FIRST &&
203                             eventID <= MouseEvent.MOUSE_LAST) &&
204                             !(checkMouseEventForModalJInternalFrame((MouseEvent JavaDoc)
205                                 event, modalComponent))) ||
206                             (eventID >= ActionEvent.ACTION_FIRST &&
207                             eventID <= ActionEvent.ACTION_LAST) ||
208                             eventID == WindowEvent.WINDOW_CLOSING) {
209                         Object JavaDoc o = event.getSource();
210                         if (o instanceof sun.awt.ModalExclude) {
211                             // Exclude this object from modality and
212
// continue to pump it's events.
213
} else if (o instanceof Component JavaDoc) {
214                             Component JavaDoc c = (Component JavaDoc) o;
215                             boolean modalExcluded = false;
216                             if (modalComponent instanceof Container JavaDoc) {
217                                 while (c != modalComponent && c != null) {
218                                     if ((c instanceof Window JavaDoc) &&
219                                         (sun.awt.SunToolkit.isModalExcluded((Window JavaDoc)c))) {
220                                             // Exclude this window and all its children from
221
// modality and continue to pump it's events.
222
modalExcluded = true;
223                                         break;
224                                     }
225                                     c = c.getParent();
226                                 }
227                             }
228                             if (!modalExcluded && (c != modalComponent)) {
229                                 eventOK = false;
230                             }
231                         }
232                     }
233                 }
234                 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
235                 if (!eventOK) {
236                     event.consume();
237                 }
238             } while (eventOK == false);
239                       
240         if ( dbg.on ) dbg.println("Dispatching: "+event);
241
242             theQueue.dispatchEvent(event);
243             return true;
244         } catch (ThreadDeath JavaDoc death) {
245             return false;
246
247         } catch (InterruptedException JavaDoc interruptedException) {
248             return false; // AppContext.dispose() interrupts all
249
// Threads in the AppContext
250

251         // Can get and throw only unchecked exceptions
252
} catch (RuntimeException JavaDoc e) {
253             processException(e, modalComponent != null);
254         } catch (Error JavaDoc e) {
255             processException(e, modalComponent != null);
256         }
257         return true;
258     }
259
260     private void processException(Throwable JavaDoc e, boolean isModal) {
261         if (!handleException(e)) {
262             // See bug ID 4499199.
263
// If we are in a modal dialog, we cannot throw
264
// an exception for the ThreadGroup to handle (as added
265
// in RFE 4063022). If we did, the message pump of
266
// the modal dialog would be interrupted.
267
// We instead choose to handle the exception ourselves.
268
// It may be useful to add either a runtime flag or API
269
// later if someone would like to instead dispose the
270
// dialog and allow the thread group to handle it.
271
if (isModal) {
272                 System.err.println(
273                     "Exception occurred during event dispatching:");
274                 e.printStackTrace();
275             } else if (e instanceof RuntimeException JavaDoc) {
276                 throw (RuntimeException JavaDoc)e;
277             } else if (e instanceof Error JavaDoc) {
278                 throw (Error JavaDoc)e;
279             }
280         }
281     }
282
283     private static final String JavaDoc handlerPropName = "sun.awt.exception.handler";
284     private static String JavaDoc handlerClassName = null;
285     private static String JavaDoc NO_HANDLER = new String JavaDoc();
286
287     /**
288      * Handles an exception thrown in the event-dispatch thread.
289      *
290      * <p> If the system property "sun.awt.exception.handler" is defined, then
291      * when this method is invoked it will attempt to do the following:
292      *
293      * <ol>
294      * <li> Load the class named by the value of that property, using the
295      * current thread's context class loader,
296      * <li> Instantiate that class using its zero-argument constructor,
297      * <li> Find the resulting handler object's <tt>public void handle</tt>
298      * method, which should take a single argument of type
299      * <tt>Throwable</tt>, and
300      * <li> Invoke the handler's <tt>handle</tt> method, passing it the
301      * <tt>thrown</tt> argument that was passed to this method.
302      * </ol>
303      *
304      * If any of the first three steps fail then this method will return
305      * <tt>false</tt> and all following invocations of this method will return
306      * <tt>false</tt> immediately. An exception thrown by the handler object's
307      * <tt>handle</tt> will be caught, and will cause this method to return
308      * <tt>false</tt>. If the handler's <tt>handle</tt> method is successfully
309      * invoked, then this method will return <tt>true</tt>. This method will
310      * never throw any sort of exception.
311      *
312      * <p> <i>Note:</i> This method is a temporary hack to work around the
313      * absence of a real API that provides the ability to replace the
314      * event-dispatch thread. The magic "sun.awt.exception.handler" property
315      * <i>will be removed</i> in a future release.
316      *
317      * @param thrown The Throwable that was thrown in the event-dispatch
318      * thread
319      *
320      * @return <tt>false</tt> if any of the above steps failed, otherwise
321      * <tt>true</tt>
322      */

323     private boolean handleException(Throwable JavaDoc thrown) {
324
325         try {
326
327             if (handlerClassName == NO_HANDLER) {
328                 return false; /* Already tried, and failed */
329             }
330
331             /* Look up the class name */
332             if (handlerClassName == null) {
333                 handlerClassName = ((String JavaDoc) AccessController.doPrivileged(
334                     new GetPropertyAction(handlerPropName)));
335                 if (handlerClassName == null) {
336                     handlerClassName = NO_HANDLER; /* Do not try this again */
337                     return false;
338                 }
339             }
340
341             /* Load the class, instantiate it, and find its handle method */
342             Method JavaDoc m;
343             Object JavaDoc h;
344             try {
345                 ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
346                 Class JavaDoc c = Class.forName(handlerClassName, true, cl);
347                 m = c.getMethod("handle", new Class JavaDoc[] { Throwable JavaDoc.class });
348                 h = c.newInstance();
349             } catch (Throwable JavaDoc x) {
350                 handlerClassName = NO_HANDLER; /* Do not try this again */
351                 return false;
352             }
353
354             /* Finally, invoke the handler */
355             m.invoke(h, new Object JavaDoc[] { thrown });
356
357         } catch (Throwable JavaDoc x) {
358             return false;
359         }
360
361         return true;
362     }
363
364     boolean isDispatching(EventQueue JavaDoc eq) {
365     return theQueue.equals(eq);
366     }
367
368     EventQueue JavaDoc getEventQueue() { return theQueue; }
369 }
370
Popular Tags