duke@0
|
1 |
/*
|
ohair@3294
|
2 |
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
|
duke@0
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
duke@0
|
4 |
*
|
duke@0
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
duke@0
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
ohair@2395
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
duke@0
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
ohair@2395
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
duke@0
|
10 |
*
|
duke@0
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
duke@0
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
duke@0
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
duke@0
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
duke@0
|
15 |
* accompanied this code).
|
duke@0
|
16 |
*
|
duke@0
|
17 |
* You should have received a copy of the GNU General Public License version
|
duke@0
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
duke@0
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
duke@0
|
20 |
*
|
ohair@2395
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
ohair@2395
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
ohair@2395
|
23 |
* questions.
|
duke@0
|
24 |
*/
|
duke@0
|
25 |
|
duke@0
|
26 |
package java.awt;
|
duke@0
|
27 |
|
duke@0
|
28 |
import java.awt.event.MouseEvent;
|
duke@0
|
29 |
import java.awt.event.ActionEvent;
|
duke@0
|
30 |
import java.awt.event.WindowEvent;
|
duke@0
|
31 |
import java.lang.reflect.Method;
|
duke@0
|
32 |
|
anthony@4611
|
33 |
import java.util.ArrayList;
|
jtulach@5229
|
34 |
import java.util.concurrent.BlockingQueue;
|
jtulach@5229
|
35 |
import java.util.concurrent.Executor;
|
jtulach@5229
|
36 |
import java.util.concurrent.LinkedBlockingQueue;
|
mchung@1729
|
37 |
import sun.util.logging.PlatformLogger;
|
duke@0
|
38 |
|
duke@0
|
39 |
import sun.awt.dnd.SunDragSourceContextPeer;
|
idk@617
|
40 |
import sun.awt.EventQueueDelegate;
|
duke@0
|
41 |
|
duke@0
|
42 |
/**
|
duke@0
|
43 |
* EventDispatchThread is a package-private AWT class which takes
|
duke@0
|
44 |
* events off the EventQueue and dispatches them to the appropriate
|
duke@0
|
45 |
* AWT components.
|
duke@0
|
46 |
*
|
duke@0
|
47 |
* The Thread starts a "permanent" event pump with a call to
|
duke@0
|
48 |
* pumpEvents(Conditional) in its run() method. Event handlers can choose to
|
duke@0
|
49 |
* block this event pump at any time, but should start a new pump (<b>not</b>
|
duke@0
|
50 |
* a new EventDispatchThread) by again calling pumpEvents(Conditional). This
|
duke@0
|
51 |
* secondary event pump will exit automatically as soon as the Condtional
|
duke@0
|
52 |
* evaluate()s to false and an additional Event is pumped and dispatched.
|
duke@0
|
53 |
*
|
duke@0
|
54 |
* @author Tom Ball
|
duke@0
|
55 |
* @author Amy Fowler
|
duke@0
|
56 |
* @author Fred Ecks
|
duke@0
|
57 |
* @author David Mendenhall
|
duke@0
|
58 |
*
|
duke@0
|
59 |
* @since 1.1
|
duke@0
|
60 |
*/
|
jtulach@5229
|
61 |
final class EventDispatchThread {
|
art@2551
|
62 |
|
mchung@1729
|
63 |
private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
|
duke@0
|
64 |
|
duke@0
|
65 |
private EventQueue theQueue;
|
duke@0
|
66 |
private boolean doDispatch = true;
|
anthony@4611
|
67 |
private volatile boolean shutdown = false;
|
art@2551
|
68 |
|
jtulach@5229
|
69 |
static final int ANY_EVENT = -1;
|
duke@0
|
70 |
|
jtulach@5229
|
71 |
private final Executor executor;
|
anthony@4611
|
72 |
private ArrayList<EventFilter> eventFilters = new ArrayList<EventFilter>();
|
duke@0
|
73 |
|
jtulach@5229
|
74 |
EventDispatchThread(ThreadGroup group, String name, EventQueue queue, ClassLoader l) {
|
jtulach@5229
|
75 |
// right now using simple executor that sort of mimics the old
|
jtulach@5229
|
76 |
// behavior of the run() method of EventDispatchThread. But when
|
jtulach@5229
|
77 |
// running together with FX, the executor should dispatch the runnable
|
jtulach@5229
|
78 |
// using Platform.invokeLater to share the same processing thread
|
jtulach@5229
|
79 |
executor = defaultThread(group, name, l);
|
art@2551
|
80 |
setEventQueue(queue);
|
duke@0
|
81 |
}
|
jtulach@5229
|
82 |
|
jtulach@5229
|
83 |
private static Executor defaultThread(ThreadGroup group, String name, ClassLoader classLoader) {
|
jtulach@5229
|
84 |
class ExecRuns implements Executor, Runnable {
|
jtulach@5229
|
85 |
final BlockingQueue<Runnable> toRun = new LinkedBlockingQueue<>();
|
jtulach@5229
|
86 |
@Override
|
jtulach@5229
|
87 |
public void execute(Runnable command) {
|
jtulach@5229
|
88 |
toRun.add(command);
|
jtulach@5229
|
89 |
}
|
jtulach@5229
|
90 |
|
jtulach@5229
|
91 |
@Override
|
jtulach@5229
|
92 |
public void run() {
|
jtulach@5229
|
93 |
while (true) {
|
jtulach@5229
|
94 |
Runnable r;
|
jtulach@5229
|
95 |
try {
|
jtulach@5229
|
96 |
r = toRun.take();
|
jtulach@5229
|
97 |
} catch (InterruptedException ex) {
|
jtulach@5229
|
98 |
eventLog.severe(ex.getMessage(), ex);
|
jtulach@5229
|
99 |
continue;
|
jtulach@5229
|
100 |
}
|
jtulach@5229
|
101 |
r.run();
|
jtulach@5229
|
102 |
}
|
jtulach@5229
|
103 |
}
|
jtulach@5229
|
104 |
}
|
jtulach@5229
|
105 |
ExecRuns er = new ExecRuns();
|
jtulach@5229
|
106 |
|
jtulach@5229
|
107 |
Thread t = new Thread(group, name);
|
jtulach@5229
|
108 |
t.setContextClassLoader(classLoader);
|
jtulach@5229
|
109 |
t.setPriority(Thread.NORM_PRIORITY + 1);
|
jtulach@5229
|
110 |
t.setDaemon(false);
|
jtulach@5229
|
111 |
t.start();
|
jtulach@5229
|
112 |
return er;
|
jtulach@5229
|
113 |
}
|
duke@0
|
114 |
|
art@2551
|
115 |
/*
|
art@2551
|
116 |
* Must be called on EDT only, that's why no synchronization
|
art@2551
|
117 |
*/
|
duke@0
|
118 |
public void stopDispatching() {
|
art@2551
|
119 |
doDispatch = false;
|
duke@0
|
120 |
}
|
duke@0
|
121 |
|
anthony@4611
|
122 |
public void interrupt() {
|
anthony@4611
|
123 |
shutdown = true;
|
jtulach@5229
|
124 |
//XXX super.interrupt();
|
anthony@4611
|
125 |
}
|
anthony@4611
|
126 |
|
jtulach@5229
|
127 |
public void processEvents() {
|
jtulach@5229
|
128 |
executor.execute(new Runnable() {
|
jtulach@5229
|
129 |
@Override
|
jtulach@5229
|
130 |
public void run() {
|
jtulach@5229
|
131 |
try {
|
jtulach@5229
|
132 |
// XXX: the meaning now should be: the pumpEvents processes
|
jtulach@5229
|
133 |
// currently pending events, and then it returns without
|
jtulach@5229
|
134 |
// any blocking
|
jtulach@5229
|
135 |
pumpEvents(new Conditional() {
|
jtulach@5229
|
136 |
public boolean evaluate() {
|
jtulach@5229
|
137 |
return true;
|
jtulach@5229
|
138 |
}
|
jtulach@5229
|
139 |
});
|
jtulach@5229
|
140 |
} finally {
|
jtulach@5229
|
141 |
if(getEventQueue().detachDispatchThread(this, shutdown)) {
|
jtulach@5229
|
142 |
return;
|
art@2551
|
143 |
}
|
duke@0
|
144 |
}
|
art@2551
|
145 |
}
|
jtulach@5229
|
146 |
});
|
duke@0
|
147 |
}
|
duke@0
|
148 |
|
michaelm@5155
|
149 |
// MacOSX change:
|
michaelm@5155
|
150 |
// This was added because this class (and java.awt.Conditional) are package private.
|
michaelm@5155
|
151 |
// There are certain instances where classes in other packages need to block the
|
michaelm@5155
|
152 |
// AWTEventQueue while still allowing it to process events. This uses reflection
|
michaelm@5155
|
153 |
// to call back into the caller in order to remove dependencies.
|
michaelm@5155
|
154 |
//
|
michaelm@5155
|
155 |
// NOTE: This uses reflection in its implementation, so it is not for performance critical code.
|
michaelm@5155
|
156 |
//
|
michaelm@5155
|
157 |
// cond is an instance of sun.lwawt.macosx.EventDispatchAccess
|
michaelm@5155
|
158 |
//
|
michaelm@5155
|
159 |
private Conditional _macosxGetConditional(final Object cond) {
|
michaelm@5155
|
160 |
try {
|
michaelm@5155
|
161 |
return new Conditional() {
|
michaelm@5155
|
162 |
final Method evaluateMethod = Class.forName("sun.lwawt.macosx.EventDispatchAccess").getMethod("evaluate", null);
|
michaelm@5155
|
163 |
public boolean evaluate() {
|
michaelm@5155
|
164 |
try {
|
michaelm@5155
|
165 |
return ((Boolean)evaluateMethod.invoke(cond, null)).booleanValue();
|
michaelm@5155
|
166 |
} catch (Exception e) {
|
michaelm@5155
|
167 |
return false;
|
michaelm@5155
|
168 |
}
|
michaelm@5155
|
169 |
}
|
michaelm@5155
|
170 |
};
|
michaelm@5155
|
171 |
} catch (Exception e) {
|
michaelm@5155
|
172 |
return new Conditional() { public boolean evaluate() { return false; } };
|
michaelm@5155
|
173 |
}
|
michaelm@5155
|
174 |
}
|
michaelm@5155
|
175 |
|
michaelm@5155
|
176 |
|
duke@0
|
177 |
void pumpEvents(Conditional cond) {
|
duke@0
|
178 |
pumpEvents(ANY_EVENT, cond);
|
duke@0
|
179 |
}
|
duke@0
|
180 |
|
duke@0
|
181 |
void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
|
duke@0
|
182 |
pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
|
duke@0
|
183 |
}
|
duke@0
|
184 |
|
duke@0
|
185 |
void pumpEvents(int id, Conditional cond) {
|
duke@0
|
186 |
pumpEventsForHierarchy(id, cond, null);
|
duke@0
|
187 |
}
|
duke@0
|
188 |
|
art@2728
|
189 |
void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
|
duke@0
|
190 |
pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
|
duke@0
|
191 |
}
|
duke@0
|
192 |
|
duke@0
|
193 |
void pumpEventsForFilter(Conditional cond, EventFilter filter) {
|
duke@0
|
194 |
pumpEventsForFilter(ANY_EVENT, cond, filter);
|
duke@0
|
195 |
}
|
duke@0
|
196 |
|
jtulach@5229
|
197 |
//XXX
|
jtulach@5229
|
198 |
boolean isInterrupted() {
|
jtulach@5229
|
199 |
return false;
|
jtulach@5229
|
200 |
}
|
jtulach@5229
|
201 |
|
duke@0
|
202 |
void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
|
duke@0
|
203 |
addEventFilter(filter);
|
art@2728
|
204 |
doDispatch = true;
|
anthony@4611
|
205 |
shutdown |= isInterrupted();
|
anthony@4611
|
206 |
while (doDispatch && !shutdown && cond.evaluate()) {
|
anthony@4611
|
207 |
pumpOneEventForFilters(id);
|
duke@0
|
208 |
}
|
duke@0
|
209 |
removeEventFilter(filter);
|
duke@0
|
210 |
}
|
duke@0
|
211 |
|
duke@0
|
212 |
void addEventFilter(EventFilter filter) {
|
art@2728
|
213 |
eventLog.finest("adding the event filter: " + filter);
|
duke@0
|
214 |
synchronized (eventFilters) {
|
duke@0
|
215 |
if (!eventFilters.contains(filter)) {
|
duke@0
|
216 |
if (filter instanceof ModalEventFilter) {
|
duke@0
|
217 |
ModalEventFilter newFilter = (ModalEventFilter)filter;
|
duke@0
|
218 |
int k = 0;
|
duke@0
|
219 |
for (k = 0; k < eventFilters.size(); k++) {
|
duke@0
|
220 |
EventFilter f = eventFilters.get(k);
|
duke@0
|
221 |
if (f instanceof ModalEventFilter) {
|
duke@0
|
222 |
ModalEventFilter cf = (ModalEventFilter)f;
|
duke@0
|
223 |
if (cf.compareTo(newFilter) > 0) {
|
duke@0
|
224 |
break;
|
duke@0
|
225 |
}
|
duke@0
|
226 |
}
|
duke@0
|
227 |
}
|
duke@0
|
228 |
eventFilters.add(k, filter);
|
duke@0
|
229 |
} else {
|
duke@0
|
230 |
eventFilters.add(filter);
|
duke@0
|
231 |
}
|
duke@0
|
232 |
}
|
duke@0
|
233 |
}
|
duke@0
|
234 |
}
|
duke@0
|
235 |
|
duke@0
|
236 |
void removeEventFilter(EventFilter filter) {
|
art@2728
|
237 |
eventLog.finest("removing the event filter: " + filter);
|
duke@0
|
238 |
synchronized (eventFilters) {
|
art@2551
|
239 |
eventFilters.remove(filter);
|
duke@0
|
240 |
}
|
duke@0
|
241 |
}
|
jtulach@5229
|
242 |
|
jtulach@5229
|
243 |
boolean blockWhenNoEvent() {
|
jtulach@5229
|
244 |
return true;
|
jtulach@5229
|
245 |
}
|
duke@0
|
246 |
|
anthony@4611
|
247 |
void pumpOneEventForFilters(int id) {
|
art@2551
|
248 |
AWTEvent event = null;
|
art@2551
|
249 |
boolean eventOK = false;
|
duke@0
|
250 |
try {
|
art@2551
|
251 |
EventQueue eq = null;
|
art@2551
|
252 |
EventQueueDelegate.Delegate delegate = null;
|
duke@0
|
253 |
do {
|
art@2551
|
254 |
// EventQueue may change during the dispatching
|
art@2551
|
255 |
eq = getEventQueue();
|
art@2551
|
256 |
delegate = EventQueueDelegate.getDelegate();
|
art@2551
|
257 |
|
idk@617
|
258 |
if (delegate != null && id == ANY_EVENT) {
|
art@2551
|
259 |
event = delegate.getNextEvent(eq);
|
idk@617
|
260 |
} else {
|
jtulach@5229
|
261 |
event = eq.getNextEvent(id, blockWhenNoEvent());
|
jtulach@5229
|
262 |
}
|
jtulach@5229
|
263 |
if (event == null) {
|
jtulach@5229
|
264 |
return;
|
idk@617
|
265 |
}
|
duke@0
|
266 |
|
duke@0
|
267 |
eventOK = true;
|
duke@0
|
268 |
synchronized (eventFilters) {
|
duke@0
|
269 |
for (int i = eventFilters.size() - 1; i >= 0; i--) {
|
duke@0
|
270 |
EventFilter f = eventFilters.get(i);
|
duke@0
|
271 |
EventFilter.FilterAction accept = f.acceptEvent(event);
|
duke@0
|
272 |
if (accept == EventFilter.FilterAction.REJECT) {
|
duke@0
|
273 |
eventOK = false;
|
duke@0
|
274 |
break;
|
duke@0
|
275 |
} else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
|
duke@0
|
276 |
break;
|
duke@0
|
277 |
}
|
duke@0
|
278 |
}
|
duke@0
|
279 |
}
|
duke@0
|
280 |
eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
|
duke@0
|
281 |
if (!eventOK) {
|
duke@0
|
282 |
event.consume();
|
duke@0
|
283 |
}
|
duke@0
|
284 |
}
|
duke@0
|
285 |
while (eventOK == false);
|
duke@0
|
286 |
|
mchung@1729
|
287 |
if (eventLog.isLoggable(PlatformLogger.FINEST)) {
|
mchung@1729
|
288 |
eventLog.finest("Dispatching: " + event);
|
duke@0
|
289 |
}
|
duke@0
|
290 |
|
idk@617
|
291 |
Object handle = null;
|
idk@617
|
292 |
if (delegate != null) {
|
idk@617
|
293 |
handle = delegate.beforeDispatch(event);
|
idk@617
|
294 |
}
|
art@2551
|
295 |
eq.dispatchEvent(event);
|
idk@617
|
296 |
if (delegate != null) {
|
idk@617
|
297 |
delegate.afterDispatch(event, handle);
|
idk@617
|
298 |
}
|
duke@0
|
299 |
}
|
duke@0
|
300 |
catch (ThreadDeath death) {
|
anthony@4611
|
301 |
shutdown = true;
|
anthony@4611
|
302 |
throw death;
|
duke@0
|
303 |
}
|
duke@0
|
304 |
catch (InterruptedException interruptedException) {
|
anthony@4611
|
305 |
shutdown = true; // AppContext.dispose() interrupts all
|
anthony@4611
|
306 |
// Threads in the AppContext
|
duke@0
|
307 |
}
|
art@2551
|
308 |
catch (Throwable e) {
|
art@869
|
309 |
processException(e);
|
duke@0
|
310 |
}
|
duke@0
|
311 |
}
|
duke@0
|
312 |
|
art@869
|
313 |
private void processException(Throwable e) {
|
mchung@1729
|
314 |
if (eventLog.isLoggable(PlatformLogger.FINE)) {
|
mchung@1729
|
315 |
eventLog.fine("Processing exception: " + e);
|
duke@0
|
316 |
}
|
jtulach@5229
|
317 |
//XXX getUncaughtExceptionHandler().uncaughtException(this, e);
|
jtulach@5229
|
318 |
}
|
jtulach@5229
|
319 |
|
jtulach@5229
|
320 |
public static EventDispatchThread findCurrent() {
|
jtulach@5229
|
321 |
//XXX return (EventDispatchThread)Thread.currentThread();
|
jtulach@5229
|
322 |
return null;
|
duke@0
|
323 |
}
|
duke@0
|
324 |
|
art@2551
|
325 |
public synchronized EventQueue getEventQueue() {
|
art@2551
|
326 |
return theQueue;
|
duke@0
|
327 |
}
|
art@2551
|
328 |
public synchronized void setEventQueue(EventQueue eq) {
|
art@2551
|
329 |
theQueue = eq;
|
art@2551
|
330 |
}
|
duke@0
|
331 |
|
duke@0
|
332 |
private static class HierarchyEventFilter implements EventFilter {
|
duke@0
|
333 |
private Component modalComponent;
|
duke@0
|
334 |
public HierarchyEventFilter(Component modalComponent) {
|
duke@0
|
335 |
this.modalComponent = modalComponent;
|
duke@0
|
336 |
}
|
duke@0
|
337 |
public FilterAction acceptEvent(AWTEvent event) {
|
duke@0
|
338 |
if (modalComponent != null) {
|
duke@0
|
339 |
int eventID = event.getID();
|
duke@0
|
340 |
boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
|
duke@0
|
341 |
(eventID <= MouseEvent.MOUSE_LAST);
|
duke@0
|
342 |
boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
|
duke@0
|
343 |
(eventID <= ActionEvent.ACTION_LAST);
|
duke@0
|
344 |
boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
|
duke@0
|
345 |
/*
|
duke@0
|
346 |
* filter out MouseEvent and ActionEvent that's outside
|
duke@0
|
347 |
* the modalComponent hierarchy.
|
duke@0
|
348 |
* KeyEvent is handled by using enqueueKeyEvent
|
duke@0
|
349 |
* in Dialog.show
|
duke@0
|
350 |
*/
|
duke@0
|
351 |
if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
|
duke@0
|
352 |
/*
|
duke@0
|
353 |
* Modal internal frames are handled separately. If event is
|
duke@0
|
354 |
* for some component from another heavyweight than modalComp,
|
duke@0
|
355 |
* it is accepted. If heavyweight is the same - we still accept
|
duke@0
|
356 |
* event and perform further filtering in LightweightDispatcher
|
duke@0
|
357 |
*/
|
duke@0
|
358 |
return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
|
duke@0
|
359 |
}
|
duke@0
|
360 |
if (mouseEvent || actionEvent || windowClosingEvent) {
|
duke@0
|
361 |
Object o = event.getSource();
|
duke@0
|
362 |
if (o instanceof sun.awt.ModalExclude) {
|
duke@0
|
363 |
// Exclude this object from modality and
|
duke@0
|
364 |
// continue to pump it's events.
|
duke@0
|
365 |
return FilterAction.ACCEPT;
|
duke@0
|
366 |
} else if (o instanceof Component) {
|
duke@0
|
367 |
Component c = (Component) o;
|
duke@0
|
368 |
// 5.0u3 modal exclusion
|
duke@0
|
369 |
boolean modalExcluded = false;
|
duke@0
|
370 |
if (modalComponent instanceof Container) {
|
duke@0
|
371 |
while (c != modalComponent && c != null) {
|
duke@0
|
372 |
if ((c instanceof Window) &&
|
duke@0
|
373 |
(sun.awt.SunToolkit.isModalExcluded((Window)c))) {
|
duke@0
|
374 |
// Exclude this window and all its children from
|
duke@0
|
375 |
// modality and continue to pump it's events.
|
duke@0
|
376 |
modalExcluded = true;
|
duke@0
|
377 |
break;
|
duke@0
|
378 |
}
|
duke@0
|
379 |
c = c.getParent();
|
duke@0
|
380 |
}
|
duke@0
|
381 |
}
|
duke@0
|
382 |
if (!modalExcluded && (c != modalComponent)) {
|
duke@0
|
383 |
return FilterAction.REJECT;
|
duke@0
|
384 |
}
|
duke@0
|
385 |
}
|
duke@0
|
386 |
}
|
duke@0
|
387 |
}
|
duke@0
|
388 |
return FilterAction.ACCEPT;
|
duke@0
|
389 |
}
|
duke@0
|
390 |
}
|
duke@0
|
391 |
}
|