1 |
/* EventQueue.java -- Event queuing mechanism |
/* Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation |
|
Copyright (C) 1999 Free Software Foundation, Inc. |
|
2 |
|
|
3 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
4 |
|
|
26 |
|
|
27 |
package java.awt; |
package java.awt; |
28 |
|
|
29 |
/** |
import java.awt.event.*; |
30 |
* This class manages a queue of <code>AWTEvent</code> objects that |
import java.util.EmptyStackException; |
31 |
* are posted to it. The AWT system uses only one event queue for all |
import java.lang.reflect.InvocationTargetException; |
32 |
* events. |
|
33 |
* |
/* Written using on-line Java 2 Platform Standard Edition v1.3 API |
34 |
* @author Aaron M. Renn (arenn@urbanophile.com) |
* Specification, as well as "The Java Class Libraries", 2nd edition |
35 |
*/ |
* (Addison-Wesley, 1998). |
36 |
public class EventQueue |
* Status: Believed complete, but untested. Check FIXME's. |
|
{ |
|
|
|
|
|
/* |
|
|
* Instance Methods |
|
|
*/ |
|
|
|
|
|
// The queue. We added a package protected field to AWTEvent to make it |
|
|
// a convenient linked list. |
|
|
private AWTEvent queue; |
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
/* |
|
|
* Constructors |
|
37 |
*/ |
*/ |
38 |
|
|
39 |
/** |
/** |
40 |
* Initializes a new instance of <code>EventQueue</code>. |
* This class manages a queue of <code>AWTEvent</code> objects that |
41 |
*/ |
* are posted to it. The AWT system uses only one event queue for all |
42 |
public |
* events. |
43 |
EventQueue() |
* |
44 |
|
* @author Bryce McKinlay |
45 |
|
* @author Aaron M. Renn (arenn@urbanophile.com) |
46 |
|
*/ |
47 |
|
public class EventQueue |
48 |
{ |
{ |
49 |
EventDispatcher ed = new EventDispatcher(this); |
private static final int INITIAL_QUEUE_DEPTH = 8; |
50 |
Thread t = new Thread(ed); |
private AWTEvent[] queue = new AWTEvent[INITIAL_QUEUE_DEPTH]; |
|
t.start(); |
|
|
} |
|
51 |
|
|
52 |
/*************************************************************************/ |
private int next_in = 0; // Index where next event will be added to queue |
53 |
|
private int next_out = 0; // Index of next event to be removed from queue |
54 |
|
|
55 |
/* |
private EventQueue next; |
56 |
* Instance Variables |
private EventQueue prev; |
|
*/ |
|
57 |
|
|
58 |
/** |
private EventDispatchThread dispatchThread = new EventDispatchThread(this); |
59 |
* Posts a new event to the queue. |
|
60 |
* |
/** |
61 |
* @param event The event to post to the queue. |
* Initializes a new instance of <code>EventQueue</code>. |
62 |
*/ |
*/ |
63 |
public synchronized void |
public EventQueue() |
64 |
postEvent(AWTEvent event) |
{ |
65 |
{ |
} |
66 |
if (queue == null) |
|
67 |
queue = event; |
/** |
68 |
else |
* Returns the next event in the queue. This method will block until |
69 |
{ |
* an event is available or until the thread is interrupted. |
70 |
AWTEvent end = queue; |
* |
71 |
while (end.next != null) |
* @return The next event in the queue. |
72 |
end = end.next; |
* |
73 |
|
* @exception InterruptedException If this thread is interrupted while |
74 |
end.next = queue; |
* waiting for an event to be posted to the queue. |
75 |
} |
*/ |
76 |
notify(); |
public synchronized AWTEvent getNextEvent() |
77 |
} |
throws InterruptedException |
78 |
|
{ |
79 |
/*************************************************************************/ |
if (next != null) |
80 |
|
return next.getNextEvent(); |
81 |
|
|
82 |
/** |
while (next_in == next_out) |
|
* Returns the next event in the queue. This method will block until |
|
|
* an event is available or until the thread is interrupted. |
|
|
* |
|
|
* @return The next event in the queue. |
|
|
* |
|
|
* @exception InterruptedException If this thread is interrupted while |
|
|
* waiting for an event to be posted to the queue. |
|
|
*/ |
|
|
public synchronized AWTEvent |
|
|
getNextEvent() throws InterruptedException |
|
|
{ |
|
|
for (;;) |
|
|
{ |
|
|
if (queue != null) |
|
|
{ |
|
|
AWTEvent evt = queue; |
|
|
queue = queue.next; |
|
|
evt.next = null; |
|
|
return(evt); |
|
|
} |
|
83 |
wait(); |
wait(); |
|
} |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
84 |
|
|
85 |
/** |
AWTEvent res = queue[next_out]; |
|
* Returns the next event in the queue without removing it from the queue. |
|
|
* This method will block until an event is available or until the thread |
|
|
* is interrupted. |
|
|
* |
|
|
* @return The next event in the queue. |
|
|
*/ |
|
|
public synchronized AWTEvent |
|
|
peekEvent() |
|
|
{ |
|
|
for (;;) |
|
|
{ |
|
|
if (queue != null) |
|
|
{ |
|
|
// We are taking a chance that the user doesn't repost the same |
|
|
// event back to the queue, but AWTEvent isn't cloneable so we |
|
|
// don't have much choice. If this becomes a problem we'll have |
|
|
// to write a wrapper class for enqueuing. |
|
|
return(queue); |
|
|
} |
|
|
|
|
|
try |
|
|
{ |
|
|
wait(); |
|
|
} |
|
|
catch(InterruptedException e) { } |
|
|
} |
|
|
} |
|
|
|
|
|
/*************************************************************************/ |
|
86 |
|
|
87 |
/** |
if (++next_out == queue.length) |
88 |
* Returns the next event in the queue that has the specified id |
next_out = 0; |
89 |
* without removing it from the queue. |
return res; |
90 |
* This method will block until an event is available or until the thread |
} |
91 |
* is interrupted. |
|
92 |
* |
/** |
93 |
* @param id The event id to return. |
* Returns the next event in the queue without removing it from the queue. |
94 |
* |
* This method will block until an event is available or until the thread |
95 |
* @return The next event in the queue. |
* is interrupted. |
96 |
*/ |
* |
97 |
public synchronized AWTEvent |
* @return The next event in the queue. |
98 |
peekEvent(int id) |
* @specnote Does not block. Returns null if there are no events on the |
99 |
{ |
* queue. |
100 |
for(;;) |
*/ |
101 |
{ |
public synchronized AWTEvent peekEvent() |
102 |
if (queue != null) |
{ |
103 |
{ |
if (next != null) |
104 |
AWTEvent evt = queue; |
return next.peekEvent(); |
105 |
while (evt != null) |
|
106 |
{ |
if (next_in != next_out) |
107 |
if (evt.getID() == id) |
return queue[next_out]; |
108 |
return(evt); |
else return null; |
109 |
evt = evt.next; |
} |
110 |
} |
|
111 |
} |
/** |
112 |
|
* Returns the next event in the queue that has the specified id |
113 |
try |
* without removing it from the queue. |
114 |
{ |
* This method will block until an event is available or until the thread |
115 |
wait(); |
* is interrupted. |
116 |
} |
* |
117 |
catch(InterruptedException e) { } |
* @param id The event id to return. |
118 |
} |
* |
119 |
|
* @return The next event in the queue. |
120 |
|
* |
121 |
|
* @specnote Does not block. Returns null if there are no matching events |
122 |
|
* on the queue. |
123 |
|
*/ |
124 |
|
public synchronized AWTEvent peekEvent(int id) |
125 |
|
{ |
126 |
|
if (next != null) |
127 |
|
return next.peekEvent(id); |
128 |
|
|
129 |
|
int i = next_out; |
130 |
|
while (i != next_in) |
131 |
|
{ |
132 |
|
AWTEvent qevt = queue[i]; |
133 |
|
if (qevt.id == id) |
134 |
|
return qevt; |
135 |
|
} |
136 |
|
return null; |
137 |
|
} |
138 |
|
|
139 |
|
/** |
140 |
|
* Posts a new event to the queue. |
141 |
|
* |
142 |
|
* @param event The event to post to the queue. |
143 |
|
*/ |
144 |
|
public synchronized void postEvent(AWTEvent evt) |
145 |
|
{ |
146 |
|
if (next != null) |
147 |
|
{ |
148 |
|
next.postEvent(evt); |
149 |
|
return; |
150 |
|
} |
151 |
|
// FIXME: Security checks? |
152 |
|
|
153 |
|
/* Check for any events already on the queue with the same source |
154 |
|
and ID. */ |
155 |
|
int i = next_out; |
156 |
|
while (i != next_in) |
157 |
|
{ |
158 |
|
AWTEvent qevt = queue[i]; |
159 |
|
Object src; |
160 |
|
if (qevt.id == evt.id |
161 |
|
&& (src = qevt.getSource()) == evt.getSource() |
162 |
|
&& src instanceof Component) |
163 |
|
{ |
164 |
|
/* If there are, call coalesceEvents on the source component |
165 |
|
to see if they can be combined. */ |
166 |
|
Component srccmp = (Component) src; |
167 |
|
AWTEvent coalesced_evt = srccmp.coalesceEvents(qevt, evt); |
168 |
|
if (coalesced_evt != null) |
169 |
|
{ |
170 |
|
/* Yes. Replace the existing event with the combined event. */ |
171 |
|
queue[i] = coalesced_evt; |
172 |
|
return; |
173 |
|
} |
174 |
|
break; |
175 |
|
} |
176 |
|
if (++i == queue.length) |
177 |
|
i = 0; |
178 |
|
} |
179 |
|
|
180 |
|
queue[next_in] = evt; |
181 |
|
if (++next_in == queue.length) |
182 |
|
next_in = 0; |
183 |
|
|
184 |
|
if (next_in == next_out) |
185 |
|
{ |
186 |
|
/* Queue is full. Extend it. */ |
187 |
|
AWTEvent[] oldQueue = queue; |
188 |
|
queue = new AWTEvent[queue.length * 2]; |
189 |
|
|
190 |
|
int len = oldQueue.length - next_out; |
191 |
|
System.arraycopy(oldQueue, next_out, queue, 0, len); |
192 |
|
if (next_out != 0) |
193 |
|
System.arraycopy(oldQueue, 0, queue, len, next_out); |
194 |
|
|
195 |
|
next_out = 0; |
196 |
|
next_in = oldQueue.length; |
197 |
|
} |
198 |
|
notify(); |
199 |
|
} |
200 |
|
|
201 |
|
/** @since JDK1.2 */ |
202 |
|
public static void invokeAndWait(Runnable runnable) |
203 |
|
throws InterruptedException, InvocationTargetException |
204 |
|
{ |
205 |
|
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
206 |
|
Thread current = Thread.currentThread(); |
207 |
|
if (current == eq.dispatchThread) |
208 |
|
throw new Error("Can't call invokeAndWait from event dispatch thread"); |
209 |
|
|
210 |
|
InvocationEvent ie = |
211 |
|
new InvocationEvent(eq, runnable, current, true); |
212 |
|
|
213 |
|
synchronized (current) |
214 |
|
{ |
215 |
|
eq.postEvent(ie); |
216 |
|
current.wait(); |
217 |
|
} |
218 |
|
|
219 |
|
Exception exception; |
220 |
|
|
221 |
|
if ((exception = ie.getException()) != null) |
222 |
|
throw new InvocationTargetException(exception); |
223 |
|
} |
224 |
|
|
225 |
|
/** @since JDK1.2 */ |
226 |
|
public static void invokeLater(Runnable runnable) |
227 |
|
{ |
228 |
|
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
229 |
|
|
230 |
|
InvocationEvent ie = |
231 |
|
new InvocationEvent(eq, runnable, null, false); |
232 |
|
|
233 |
|
eq.postEvent(ie); |
234 |
|
} |
235 |
|
|
236 |
|
public static boolean isDispatchThread() |
237 |
|
{ |
238 |
|
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); |
239 |
|
return (Thread.currentThread() == eq.dispatchThread); |
240 |
|
} |
241 |
|
|
242 |
|
/** Allows a custom EventQueue implementation to replace this one. |
243 |
|
* All pending events are transferred to the new queue. Calls to postEvent, |
244 |
|
* getNextEvent, and peekEvent are forwarded to the pushed queue until it |
245 |
|
* is removed with a pop(). |
246 |
|
*/ |
247 |
|
public synchronized void push(EventQueue newEventQueue) |
248 |
|
{ |
249 |
|
int i = next_out; |
250 |
|
while (i != next_in) |
251 |
|
{ |
252 |
|
newEventQueue.postEvent(queue[i]); |
253 |
|
next_out = i; |
254 |
|
if (++i == queue.length) |
255 |
|
i = 0; |
256 |
|
} |
257 |
|
|
258 |
|
next = newEventQueue; |
259 |
|
newEventQueue.prev = this; |
260 |
|
} |
261 |
|
|
262 |
|
/** Transfer any pending events from this queue back to the parent queue that |
263 |
|
* was previously push()ed. Event dispatch from this queue is suspended. */ |
264 |
|
protected void pop() throws EmptyStackException |
265 |
|
{ |
266 |
|
if (prev == null) |
267 |
|
throw new EmptyStackException(); |
268 |
|
|
269 |
|
// Don't synchronize both this and prev at the same time, or deadlock could |
270 |
|
// occur. |
271 |
|
synchronized (prev) |
272 |
|
{ |
273 |
|
prev.next = null; |
274 |
|
} |
275 |
|
|
276 |
|
synchronized (this) |
277 |
|
{ |
278 |
|
int i = next_out; |
279 |
|
while (i != next_in) |
280 |
|
{ |
281 |
|
prev.postEvent(queue[i]); |
282 |
|
next_out = i; |
283 |
|
if (++i == queue.length) |
284 |
|
i = 0; |
285 |
|
} |
286 |
|
} |
287 |
|
} |
288 |
|
|
289 |
|
protected void dispatchEvent(AWTEvent evt) |
290 |
|
{ |
291 |
|
if (evt instanceof ActiveEvent) |
292 |
|
{ |
293 |
|
ActiveEvent active_evt = (ActiveEvent) evt; |
294 |
|
active_evt.dispatch(); |
295 |
|
} |
296 |
|
else |
297 |
|
{ |
298 |
|
Object source = evt.getSource(); |
299 |
|
|
300 |
|
if (source instanceof Component) |
301 |
|
{ |
302 |
|
Component srccmp = (Component) source; |
303 |
|
srccmp.dispatchEvent(evt); |
304 |
|
} |
305 |
|
else if (source instanceof MenuComponent) |
306 |
|
{ |
307 |
|
MenuComponent srccmp = (MenuComponent) source; |
308 |
|
srccmp.dispatchEvent(evt); |
309 |
|
} |
310 |
|
} |
311 |
|
} |
312 |
} |
} |
|
|
|
|
} // class EventQueue |
|
|
|
|