001: /*
002: * @(#)EventDispatchThread.java 1.31 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt;
029:
030: import java.lang.reflect.Method;
031: import java.security.AccessController;
032: import sun.security.action.GetPropertyAction;
033: import java.lang.ref.WeakReference;
034:
035: /**
036: * EventDispatchThread is a package-private AWT class which takes
037: * events off the EventQueue and dispatches them to the appropriate
038: * AWT components.
039: *
040: * The Thread starts a "permanent" event pump with a call to
041: * pumpEvents(Conditional) in its run() method. Event handlers can choose to
042: * block this event pump at any time, but should start a new pump (<b>not</b>
043: * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
044: * secondary event pump will exit automatically as soon as the Condtional
045: * evaluate()s to false and an additional Event is pumped and dispatched.
046: *
047: * @author Tom Ball
048: * @author Amy Fowler
049: * @author Fred Ecks
050: * @author David Mendenhall
051: *
052: * @version 1.34, 02/02/00
053: * @since 1.1
054: */
055: class EventDispatchThread extends Thread {
056: private EventQueueProxy theQueue; // 6261461
057: private boolean doDispatch = true;
058: private static final int ANY_EVENT = -1;
059:
060: EventDispatchThread(String name, EventQueueProxy queue) { // 6261461
061: super (name);
062: theQueue = queue;
063: }
064:
065: public void stopDispatching() {
066: // Note: We stop dispatching via a flag rather than using
067: // Thread.interrupt() because we can't guarantee that the wait()
068: // we interrupt will be EventQueue.getNextEvent()'s. -fredx 8-11-98
069:
070: doDispatch = false;
071: // fix 4122683, 4128923
072: // Post an empty event to ensure getNextEvent is unblocked
073: //
074: // We have to use postEventPrivate instead of postEvent because
075: // EventQueue.pop calls EventDispatchThread.stopDispatching.
076: // Calling SunToolkit.flushPendingEvents in this case could
077: // lead to deadlock.
078: theQueue.postEventPrivate(new EmptyEvent());
079: // wait for the dispatcher to complete
080: if (Thread.currentThread() != this ) {
081: try {
082: join();
083: } catch (InterruptedException e) {
084: }
085: }
086: }
087:
088: class EmptyEvent extends AWTEvent implements ActiveEvent {
089: public EmptyEvent() {
090: super (EventDispatchThread.this , 0);
091: }
092:
093: public void dispatch() {
094: }
095: }
096:
097: public void run() {
098: pumpEvents(new Conditional() {
099: public boolean evaluate() {
100: return true;
101: }
102: });
103: }
104:
105: void pumpEvents(Conditional cond) {
106: pumpEvents(ANY_EVENT, cond);
107: }
108:
109: void pumpEvents(int id, Conditional cond) {
110: while (doDispatch && cond.evaluate()) {
111: if (isInterrupted() || !pumpOneEvent(id)) {
112: doDispatch = false;
113: }
114: }
115: }
116:
117: boolean pumpOneEvent(int id) {
118: try {
119: AWTEvent event = (id == ANY_EVENT) ? theQueue
120: .getNextEvent() : theQueue.getNextEvent(id);
121: theQueue.dispatchEvent(event);
122: return true;
123: } catch (ThreadDeath death) {
124: return false;
125: } catch (InterruptedException interruptedException) {
126: return false; // AppContext.dispose() interrupts all
127: // Threads in the AppContext
128:
129: } catch (Throwable e) {
130: if (!handleException(e)) {
131: System.err
132: .println("Exception occurred during event dispatching:");
133: e.printStackTrace();
134: }
135: return true;
136: }
137: }
138:
139: private static final String handlerPropName = "sun.awt.exception.handler";
140: private static String handlerClassName = null;
141: private static String NO_HANDLER = new String();
142:
143: /**
144: * Handles an exception thrown in the event-dispatch thread.
145: *
146: * <p> If the system property "sun.awt.exception.handler" is defined, then
147: * when this method is invoked it will attempt to do the following:
148: *
149: * <ol>
150: * <li> Load the class named by the value of that property, using the
151: * current thread's context class loader,
152: * <li> Instantiate that class using its zero-argument constructor,
153: * <li> Find the resulting handler object's <tt>public void handle</tt>
154: * method, which should take a single argument of type
155: * <tt>Throwable</tt>, and
156: * <li> Invoke the handler's <tt>handle</tt> method, passing it the
157: * <tt>thrown</tt> argument that was passed to this method.
158: * </ol>
159: *
160: * If any of the first three steps fail then this method will return
161: * <tt>false</tt> and all following invocations of this method will return
162: * <tt>false</tt> immediately. An exception thrown by the handler object's
163: * <tt>handle</tt> will be caught, and will cause this method to return
164: * <tt>false</tt>. If the handler's <tt>handle</tt> method is successfully
165: * invoked, then this method will return <tt>true</tt>. This method will
166: * never throw any sort of exception.
167: *
168: * <p> <i>Note:</i> This method is a temporary fix to work around the
169: * absence of a real API that provides the ability to replace the
170: * event-dispatch thread. The magic "sun.awt.exception.handler" property
171: * <i>will be removed</i> in a future release.
172: *
173: * @param thrown The Throwable that was thrown in the event-dispatch
174: * thread
175: *
176: * @returns <tt>false</tt> if any of the above steps failed, otherwise
177: * <tt>true</tt>.
178: */
179: private boolean handleException(Throwable thrown) {
180: try {
181: if (handlerClassName == NO_HANDLER) {
182: return false; /* Already tried, and failed */
183: }
184: /* Look up the class name */
185: if (handlerClassName == null) {
186: handlerClassName = ((String) AccessController
187: .doPrivileged(new GetPropertyAction(
188: handlerPropName)));
189: if (handlerClassName == null) {
190: handlerClassName = NO_HANDLER; /* Do not try this again */
191: return false;
192: }
193: }
194: /* Load the class, instantiate it, and find its handle method */
195: Method m;
196: Object h;
197: try {
198: ClassLoader cl = Thread.currentThread()
199: .getContextClassLoader();
200: Class c = Class.forName(handlerClassName, true, cl);
201: m = c.getMethod("handle",
202: new Class[] { Throwable.class });
203: h = c.newInstance();
204: } catch (Throwable x) {
205: handlerClassName = NO_HANDLER; /* Do not try this again */
206: return false;
207: }
208: /* Finally, invoke the handler */
209: m.invoke(h, new Object[] { thrown });
210: } catch (Throwable x) {
211: return false;
212: }
213: return true;
214: }
215:
216: boolean isDispatching(EventQueue eq) {
217: // note : getQueue() can return null, hence we changed the order
218: return eq.equals(theQueue.getQueue()); // 6261461
219: }
220:
221: EventQueue getEventQueue() {
222: return theQueue.getQueue(); // 6261461 this can be null
223: }
224: }
225:
226: // 6261461
227: // Ideally EventQueueProxy should be defined in EventQueue class, since it
228: // accesses package protected variables. This is defined here since we
229: // share this file between basis and personal and the implementation of the
230: // methods are identical. This helps us in ease of maintaining the proxy class.
231: /**
232: */
233: class EventQueueProxy {
234: WeakReference eventQueueRef;
235: int waitForID;
236:
237: EventQueueProxy(EventQueue eq) {
238: this .eventQueueRef = new WeakReference(eq);
239: }
240:
241: void postEventPrivate(AWTEvent theEvent) {
242: EventQueue eq = getQueue();
243: if (eq != null)
244: eq.postEventPrivate(theEvent);
245: else {
246: // the event queue must have been collected, so call notify
247: // so that any thread blocked on getNextEvent() can unblock
248: synchronized (this ) {
249: this .notifyAll();
250: }
251: }
252: }
253:
254: public synchronized AWTEvent getNextEvent()
255: throws InterruptedException {
256: do {
257: EventQueue eq = getQueue();
258: if (eq == null)
259: throw new InterruptedException();
260: for (int i = EventQueue.NUM_PRIORITIES - 1; i >= 0; i--) {
261: if (eq.queues[i].head != null) {
262: EventQueueItem eqi = eq.queues[i].head;
263: eq.queues[i].head = eqi.next;
264: if (eqi.next == null) {
265: eq.queues[i].tail = null;
266: }
267: return eqi.event;
268: }
269: }
270: // dont reference event queue since we are going to wait.
271: // this will allow gc on the event queue.
272: eq = null;
273: wait();
274: } while (true);
275: }
276:
277: AWTEvent getNextEvent(int id) throws InterruptedException {
278: do {
279: EventQueue eq = getQueue();
280: if (eq == null)
281: throw new InterruptedException();
282: synchronized (this ) {
283: for (int i = 0; i < EventQueue.NUM_PRIORITIES; i++) {
284: for (EventQueueItem entry = eq.queues[i].head, prev = null; entry != null; prev = entry, entry = entry.next) {
285: if (entry.id == id) {
286: if (prev == null) {
287: eq.queues[i].head = entry.next;
288: } else {
289: prev.next = entry.next;
290: }
291: if (eq.queues[i].tail == entry) {
292: eq.queues[i].tail = prev;
293: }
294: return entry.event;
295: }
296: }
297: }
298: // dont reference event queue since we are going to wait.
299: // this will allow gc on the event queue.
300: eq = null;
301: this .waitForID = id;
302: wait();
303: this .waitForID = 0;
304: }
305: } while (true);
306: }
307:
308: void dispatchEvent(AWTEvent event) {
309: EventQueue eq = getQueue();
310: if (eq != null)
311: eq.dispatchEvent(event);
312: }
313:
314: EventQueue getQueue() {
315: return (EventQueue) (EventQueue) eventQueueRef.get();
316: }
317: }
318: // 6261461
|