1 /*
2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.awt;
27
28 import java.awt.event.MouseEvent;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.WindowEvent;
31
32 import java.util.ArrayList;
33 import sun.util.logging.PlatformLogger;
34
35 import sun.awt.dnd.SunDragSourceContextPeer;
36 import sun.awt.EventQueueDelegate;
37
38 /**
39 * EventDispatchThread is a package-private AWT class which takes
40 * events off the EventQueue and dispatches them to the appropriate
41 * AWT components.
42 *
43 * The Thread starts a "permanent" event pump with a call to
44 * pumpEvents(Conditional) in its run() method. Event handlers can choose to
45 * block this event pump at any time, but should start a new pump (<b>not</b>
46 * a new EventDispatchThread) by again calling pumpEvents(Conditional). This
47 * secondary event pump will exit automatically as soon as the Condtional
48 * evaluate()s to false and an additional Event is pumped and dispatched.
49 *
50 * @author Tom Ball
51 * @author Amy Fowler
52 * @author Fred Ecks
53 * @author David Mendenhall
54 *
55 * @since 1.1
56 */
57 class EventDispatchThread extends Thread {
58
59 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
60
61 private EventQueue theQueue;
62 private volatile boolean doDispatch = true;
63
64 private static final int ANY_EVENT = -1;
65
66 private ArrayList<EventFilter> eventFilters = new ArrayList<EventFilter>();
67
68 EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
69 super(group, name);
70 setEventQueue(queue);
71 }
72
73 /*
74 * Must be called on EDT only, that's why no synchronization
75 */
76 public void stopDispatching() {
77 doDispatch = false;
78 }
79
80 public void run() {
81 try {
82 pumpEvents(new Conditional() {
83 public boolean evaluate() {
84 return true;
85 }
86 });
87 } finally {
88 getEventQueue().detachDispatchThread(this);
89 }
90 }
91
92 void pumpEvents(Conditional cond) {
93 pumpEvents(ANY_EVENT, cond);
94 }
95
96 void pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
97 pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
98 }
99
100 void pumpEvents(int id, Conditional cond) {
101 pumpEventsForHierarchy(id, cond, null);
102 }
103
104 void pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
105 pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
106 }
107
108 void pumpEventsForFilter(Conditional cond, EventFilter filter) {
109 pumpEventsForFilter(ANY_EVENT, cond, filter);
110 }
111
112 void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
113 addEventFilter(filter);
114 doDispatch = true;
115 while (doDispatch && !isInterrupted() && cond.evaluate()) {
116 pumpOneEventForFilters(id);
117 }
118 removeEventFilter(filter);
119 }
120
121 void addEventFilter(EventFilter filter) {
122 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
123 eventLog.finest("adding the event filter: " + filter);
124 }
125 synchronized (eventFilters) {
126 if (!eventFilters.contains(filter)) {
127 if (filter instanceof ModalEventFilter) {
128 ModalEventFilter newFilter = (ModalEventFilter)filter;
129 int k = 0;
130 for (k = 0; k < eventFilters.size(); k++) {
131 EventFilter f = eventFilters.get(k);
132 if (f instanceof ModalEventFilter) {
133 ModalEventFilter cf = (ModalEventFilter)f;
134 if (cf.compareTo(newFilter) > 0) {
135 break;
136 }
137 }
138 }
139 eventFilters.add(k, filter);
140 } else {
141 eventFilters.add(filter);
142 }
143 }
144 }
145 }
146
147 void removeEventFilter(EventFilter filter) {
148 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
149 eventLog.finest("removing the event filter: " + filter);
150 }
151 synchronized (eventFilters) {
152 eventFilters.remove(filter);
153 }
154 }
155
156 void pumpOneEventForFilters(int id) {
157 AWTEvent event = null;
158 boolean eventOK = false;
159 try {
160 EventQueue eq = null;
161 EventQueueDelegate.Delegate delegate = null;
162 do {
163 // EventQueue may change during the dispatching
164 eq = getEventQueue();
165 delegate = EventQueueDelegate.getDelegate();
166
167 if (delegate != null && id == ANY_EVENT) {
168 event = delegate.getNextEvent(eq);
169 } else {
170 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
171 }
172
173 eventOK = true;
174 synchronized (eventFilters) {
175 for (int i = eventFilters.size() - 1; i >= 0; i--) {
176 EventFilter f = eventFilters.get(i);
177 EventFilter.FilterAction accept = f.acceptEvent(event);
178 if (accept == EventFilter.FilterAction.REJECT) {
179 eventOK = false;
180 break;
181 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
182 break;
183 }
184 }
185 }
186 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
187 if (!eventOK) {
188 event.consume();
189 }
190 }
191 while (eventOK == false);
192
193 if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) {
194 eventLog.finest("Dispatching: " + event);
195 }
196
197 Object handle = null;
198 if (delegate != null) {
199 handle = delegate.beforeDispatch(event);
200 }
201 eq.dispatchEvent(event);
202 if (delegate != null) {
203 delegate.afterDispatch(event, handle);
204 }
205 }
206 catch (ThreadDeath death) {
207 doDispatch = false;
208 throw death;
209 }
210 catch (InterruptedException interruptedException) {
211 doDispatch = false; // AppContext.dispose() interrupts all
212 // Threads in the AppContext
213 }
214 catch (Throwable e) {
215 processException(e);
216 }
217 }
218
219 private void processException(Throwable e) {
220 if (eventLog.isLoggable(PlatformLogger.Level.FINE)) {
221 eventLog.fine("Processing exception: " + e);
222 }
223 getUncaughtExceptionHandler().uncaughtException(this, e);
224 }
225
226 public synchronized EventQueue getEventQueue() {
227 return theQueue;
228 }
229 public synchronized void setEventQueue(EventQueue eq) {
230 theQueue = eq;
231 }
232
233 private static class HierarchyEventFilter implements EventFilter {
234 private Component modalComponent;
235 public HierarchyEventFilter(Component modalComponent) {
236 this.modalComponent = modalComponent;
237 }
238 public FilterAction acceptEvent(AWTEvent event) {
239 if (modalComponent != null) {
240 int eventID = event.getID();
241 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
242 (eventID <= MouseEvent.MOUSE_LAST);
243 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
244 (eventID <= ActionEvent.ACTION_LAST);
245 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
246 /*
247 * filter out MouseEvent and ActionEvent that's outside
248 * the modalComponent hierarchy.
249 * KeyEvent is handled by using enqueueKeyEvent
250 * in Dialog.show
251 */
252 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
253 /*
254 * Modal internal frames are handled separately. If event is
255 * for some component from another heavyweight than modalComp,
256 * it is accepted. If heavyweight is the same - we still accept
257 * event and perform further filtering in LightweightDispatcher
258 */
259 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
260 }
261 if (mouseEvent || actionEvent || windowClosingEvent) {
262 Object o = event.getSource();
263 if (o instanceof sun.awt.ModalExclude) {
264 // Exclude this object from modality and
265 // continue to pump it's events.
266 return FilterAction.ACCEPT;
267 } else if (o instanceof Component) {
268 Component c = (Component) o;
269 // 5.0u3 modal exclusion
270 boolean modalExcluded = false;
271 if (modalComponent instanceof Container) {
272 while (c != modalComponent && c != null) {
273 if ((c instanceof Window) &&
274 (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
275 // Exclude this window and all its children from
276 // modality and continue to pump it's events.
277 modalExcluded = true;
278 break;
279 }
280 c = c.getParent();
281 }
282 }
283 if (!modalExcluded && (c != modalComponent)) {
284 return FilterAction.REJECT;
285 }
286 }
287 }
288 }
289 return FilterAction.ACCEPT;
290 }
291 }
292 }
--- EOF ---