2 * Copyright 1998-2001 Sun Microsystems, Inc.
4 * See the file "license.terms" for information on usage and
5 * redistribution of this file, and for a DISCLAIMER OF ALL
8 package com.sun.speech.engine;
10 import javax.speech.SpeechEvent;
12 import java.awt.AWTEvent;
13 import java.awt.EventQueue;
14 import java.awt.Toolkit;
15 import java.awt.Component;
16 import java.security.AccessControlException;
19 * Utilities to help with dispatch JSAPI 1.0 events on the event
20 * dispatching thread of AWT/Swing. This is needed to help
21 * applications conform with the Swing Event Thread model. If these
22 * utilities were not used, then a GUI application would have to
23 * implement Runnables to handle JSAPI events that result in updates
26 public class SpeechEventUtilities {
29 * If true, the AWT EventQueue has been set up in the VM. This flag
30 * is used to determine whether we should use the AWT EventQueue for
31 * synchronizing SpeechEvents with the AWT EventQueue or not.
33 protected static boolean awtRunning = false;
36 * The AWT EventQueue. This is lazily created in postSpeechEvent to
37 * delay the need to initialize the Toolkit until it is necessary.
39 * @see #postSpeechEvent
41 protected static EventQueue systemEventQueue = null;
44 * A target used to process speechAWTEvent objects. This target
45 * is a component that expresses interest in SpeechAWTEvents. It
46 * is lazily created along with systemEventQueue in postSpeechEvent.
48 * @see #postSpeechEvent
50 protected static SpeechAWTEventTarget speechAWTEventTarget = null;
53 * If true, wait until an event has been dispatched before returning
54 * from the post method. This is meant to be a global debugging flag.
55 * If a class calling postSpeechEvent wants to wait until the
56 * SpeechEvent has been dispatched, it should call the postSpeechEvent
57 * method that has the waitUntilDispatched parameter.
59 * @see #postSpeechEvent
61 public static boolean waitUntilDispatched = false;
64 * Determine if the AWT event queue is running. This method is one big
65 * hack, and we will be entering a bug against AWT to provide us with
66 * a real method for determining if AWT is active or not. The problem
67 * with asking AWT if it is active right now is that it will activate
68 * it if it isn't already active.
70 static protected boolean isAWTRunning() {
77 ThreadGroup rootGroup;
79 ThreadGroup g = Thread.currentThread().getThreadGroup();
81 parent = rootGroup.getParent();
82 while (parent != null) {
84 parent = parent.getParent();
87 int activeCount = rootGroup.activeCount();
88 Thread[] threads = new Thread[activeCount];
89 rootGroup.enumerate(threads,true);
90 for (int i = 0; i < threads.length; i++) {
91 if (threads[i] != null) {
92 String name = threads[i].getName();
93 if (name.startsWith("AWT-EventQueue")) {
99 } catch (AccessControlException ace) {
100 // if we receive an access control exception then
101 // it is likely that we are running in an applet
102 // in which case AWT is running.
103 // I'm not sure if this is always true, perhaps
104 // there is another way to tell if we are running in an
114 * Post a JSAPI SpeechEvent. This is to be used by multiple processes
115 * to synchronize SpeechEvents. It currently uses the AWT EventQueue
116 * as a means for doing this, which has the added benefit of causing
117 * all SpeechEvent notification to be done from the event dispatch
118 * thread. This is important because the Swing Thread Model requires
119 * all interaction with Swing components to be done from the event
122 * This method will immediately return once the event has been
123 * posted if the global waitUntilDispatched flag is set to false.
124 * Otherwise, it will wait until the event has been dispatched
127 * @param dispatcher the dispatcher that will dispatch the event
128 * @param event the SpeechEvent to post
130 static public void postSpeechEvent(SpeechEventDispatcher dispatcher,
132 postSpeechEvent(dispatcher, event, waitUntilDispatched);
136 * Post a JSAPI SpeechEvent. This is to be used by multiple processes
137 * to synchronize SpeechEvents. It currently uses the AWT EventQueue
138 * as a means for doing this, which has the added benefit of causing
139 * all SpeechEvent notification to be done from the event dispatch
140 * thread. This is important because the Swing Thread Model requires
141 * all interaction with Swing components to be done from the event
144 * This method will immediately return once the event has been
145 * posted if the waitUntilDispatched parameter is set to false.
146 * Otherwise, it will wait until the event has been dispatched
149 * @param dispatcher the dispatcher that will dispatch the event
150 * @param event the SpeechEvent to post
151 * @param waitUntilDispatched if true, do not return until the
152 * event have been dispatched
154 static public void postSpeechEvent(
155 SpeechEventDispatcher dispatcher,
157 boolean waitUntilDispatched) {
159 /* Only use the AWT EventQueue if AWT is running. If it isn't
160 * running, then just call the dispatcher directly. A more formal
161 * event queue mechanism probably should be added at some point
162 * so listeners cannot cause a hang in the engine.
164 if (isAWTRunning()) {
165 /* Create the event target and event queue references if they
166 * haven't been created yet. This is done here to delay the
167 * initialization of the AWT Toolkit until it is absolutely
168 * necessary. Creating it earlier may cause conflicts with
171 if (speechAWTEventTarget == null) {
172 speechAWTEventTarget = new SpeechAWTEventTarget();
174 Toolkit.getDefaultToolkit().getSystemEventQueue();
177 /* Post the event to the AWT EventQueue. When AWT dispatches
178 * the events on its EventQueue, this event will be sent to
179 * the speechAWTEventTarget for processing.
181 if (waitUntilDispatched) {
182 Object lock = new Object();
184 systemEventQueue.postEvent(
185 new SpeechAWTEvent(speechAWTEventTarget,
191 } catch (InterruptedException e) {
195 systemEventQueue.postEvent(
196 new SpeechAWTEvent(speechAWTEventTarget,
201 dispatcher.dispatchSpeechEvent(event);
206 * Inner class used to handle events as they are dispatched from the
209 * @see #postSpeechEvent
211 protected static class SpeechAWTEventTarget extends Component {
212 SpeechAWTEventTarget() {
214 enableEvents(SpeechAWTEvent.EVENT_ID);
216 protected void processEvent(AWTEvent event) {
217 if (event instanceof SpeechAWTEvent) {
218 SpeechAWTEvent sae = (SpeechAWTEvent) event;
219 sae.dispatcher.dispatchSpeechEvent(sae.event);
220 if (sae.lock != null) {
221 synchronized(sae.lock) {
230 * Inner class that defines SpeechAWTEvents. These are created and
231 * posted to the AWT EventQueue by the postSpeechEvent method.
233 * @see #postSpeechEvent
235 protected static class SpeechAWTEvent extends AWTEvent {
236 static final int EVENT_ID = AWTEvent.RESERVED_ID_MAX + 14830;
237 SpeechEventDispatcher dispatcher = null;
238 SpeechEvent event = null;
240 SpeechAWTEvent(SpeechAWTEventTarget target,
241 SpeechEventDispatcher dispatcher,
243 this(target,dispatcher,event,null);
245 SpeechAWTEvent(SpeechAWTEventTarget target,
246 SpeechEventDispatcher dispatcher,
249 super(target, EVENT_ID);
250 this.dispatcher = dispatcher;