1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
|
/**
* Copyright 1998-2001 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
*/
package com.sun.speech.engine;
import javax.speech.SpeechEvent;
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.Component;
import java.security.AccessControlException;
/**
* Utilities to help with dispatch JSAPI 1.0 events on the event
* dispatching thread of AWT/Swing. This is needed to help
* applications conform with the Swing Event Thread model. If these
* utilities were not used, then a GUI application would have to
* implement Runnables to handle JSAPI events that result in updates
* to the GUI.
*/
public class SpeechEventUtilities {
/**
* If true, the AWT EventQueue has been set up in the VM. This flag
* is used to determine whether we should use the AWT EventQueue for
* synchronizing SpeechEvents with the AWT EventQueue or not.
*/
protected static boolean awtRunning = false;
/**
* The AWT EventQueue. This is lazily created in postSpeechEvent to
* delay the need to initialize the Toolkit until it is necessary.
*
* @see #postSpeechEvent
*/
protected static EventQueue systemEventQueue = null;
/**
* A target used to process speechAWTEvent objects. This target
* is a component that expresses interest in SpeechAWTEvents. It
* is lazily created along with systemEventQueue in postSpeechEvent.
*
* @see #postSpeechEvent
*/
protected static SpeechAWTEventTarget speechAWTEventTarget = null;
/**
* If true, wait until an event has been dispatched before returning
* from the post method. This is meant to be a global debugging flag.
* If a class calling postSpeechEvent wants to wait until the
* SpeechEvent has been dispatched, it should call the postSpeechEvent
* method that has the waitUntilDispatched parameter.
*
* @see #postSpeechEvent
*/
public static boolean waitUntilDispatched = false;
/**
* Determine if the AWT event queue is running. This method is one big
* hack, and we will be entering a bug against AWT to provide us with
* a real method for determining if AWT is active or not. The problem
* with asking AWT if it is active right now is that it will activate
* it if it isn't already active.
*/
static protected boolean isAWTRunning() {
if (awtRunning) {
return true;
}
try {
ThreadGroup rootGroup;
ThreadGroup parent;
ThreadGroup g = Thread.currentThread().getThreadGroup();
rootGroup = g;
parent = rootGroup.getParent();
while (parent != null) {
rootGroup = parent;
parent = parent.getParent();
}
int activeCount = rootGroup.activeCount();
Thread[] threads = new Thread[activeCount];
rootGroup.enumerate(threads,true);
for (int i = 0; i < threads.length; i++) {
if (threads[i] != null) {
String name = threads[i].getName();
if (name.startsWith("AWT-EventQueue")) {
awtRunning = true;
return true;
}
}
}
} catch (AccessControlException ace) {
// if we receive an access control exception then
// it is likely that we are running in an applet
// in which case AWT is running.
// I'm not sure if this is always true, perhaps
// there is another way to tell if we are running in an
// applet.
return true;
}
return false;
}
/**
* Post a JSAPI SpeechEvent. This is to be used by multiple processes
* to synchronize SpeechEvents. It currently uses the AWT EventQueue
* as a means for doing this, which has the added benefit of causing
* all SpeechEvent notification to be done from the event dispatch
* thread. This is important because the Swing Thread Model requires
* all interaction with Swing components to be done from the event
* dispatch thread.
*
* This method will immediately return once the event has been
* posted if the global waitUntilDispatched flag is set to false.
* Otherwise, it will wait until the event has been dispatched
* before returning.
*
* @param dispatcher the dispatcher that will dispatch the event
* @param event the SpeechEvent to post
*/
static public void postSpeechEvent(SpeechEventDispatcher dispatcher,
SpeechEvent event) {
postSpeechEvent(dispatcher, event, waitUntilDispatched);
}
/**
* Post a JSAPI SpeechEvent. This is to be used by multiple processes
* to synchronize SpeechEvents. It currently uses the AWT EventQueue
* as a means for doing this, which has the added benefit of causing
* all SpeechEvent notification to be done from the event dispatch
* thread. This is important because the Swing Thread Model requires
* all interaction with Swing components to be done from the event
* dispatch thread.
*
* This method will immediately return once the event has been
* posted if the waitUntilDispatched parameter is set to false.
* Otherwise, it will wait until the event has been dispatched
* before returning.
*
* @param dispatcher the dispatcher that will dispatch the event
* @param event the SpeechEvent to post
* @param waitUntilDispatched if true, do not return until the
* event have been dispatched
*/
static public void postSpeechEvent(
SpeechEventDispatcher dispatcher,
SpeechEvent event,
boolean waitUntilDispatched) {
/* Only use the AWT EventQueue if AWT is running. If it isn't
* running, then just call the dispatcher directly. A more formal
* event queue mechanism probably should be added at some point
* so listeners cannot cause a hang in the engine.
*/
if (isAWTRunning()) {
/* Create the event target and event queue references if they
* haven't been created yet. This is done here to delay the
* initialization of the AWT Toolkit until it is absolutely
* necessary. Creating it earlier may cause conflicts with
* applets.
*/
if (speechAWTEventTarget == null) {
speechAWTEventTarget = new SpeechAWTEventTarget();
systemEventQueue =
Toolkit.getDefaultToolkit().getSystemEventQueue();
}
/* Post the event to the AWT EventQueue. When AWT dispatches
* the events on its EventQueue, this event will be sent to
* the speechAWTEventTarget for processing.
*/
if (waitUntilDispatched) {
Object lock = new Object();
synchronized(lock) {
systemEventQueue.postEvent(
new SpeechAWTEvent(speechAWTEventTarget,
dispatcher,
event,
lock));
try {
lock.wait();
} catch (InterruptedException e) {
}
}
} else {
systemEventQueue.postEvent(
new SpeechAWTEvent(speechAWTEventTarget,
dispatcher,
event));
}
} else {
dispatcher.dispatchSpeechEvent(event);
}
}
/**
* Inner class used to handle events as they are dispatched from the
* AWT event queue.
*
* @see #postSpeechEvent
*/
protected static class SpeechAWTEventTarget extends Component {
SpeechAWTEventTarget() {
super();
enableEvents(SpeechAWTEvent.EVENT_ID);
}
protected void processEvent(AWTEvent event) {
if (event instanceof SpeechAWTEvent) {
SpeechAWTEvent sae = (SpeechAWTEvent) event;
sae.dispatcher.dispatchSpeechEvent(sae.event);
if (sae.lock != null) {
synchronized(sae.lock) {
sae.lock.notify();
}
}
}
}
}
/**
* Inner class that defines SpeechAWTEvents. These are created and
* posted to the AWT EventQueue by the postSpeechEvent method.
*
* @see #postSpeechEvent
*/
protected static class SpeechAWTEvent extends AWTEvent {
static final int EVENT_ID = AWTEvent.RESERVED_ID_MAX + 14830;
SpeechEventDispatcher dispatcher = null;
SpeechEvent event = null;
Object lock = null;
SpeechAWTEvent(SpeechAWTEventTarget target,
SpeechEventDispatcher dispatcher,
SpeechEvent event) {
this(target,dispatcher,event,null);
}
SpeechAWTEvent(SpeechAWTEventTarget target,
SpeechEventDispatcher dispatcher,
SpeechEvent event,
Object lock) {
super(target, EVENT_ID);
this.dispatcher = dispatcher;
this.event = event;
this.lock = lock;
}
}
}
|