1. /*
  2. * @(#)EventQueue.java 1.96 04/06/28
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.event.ActionEvent;
  9. import java.awt.event.FocusEvent;
  10. import java.awt.event.InputEvent;
  11. import java.awt.event.InputMethodEvent;
  12. import java.awt.event.InvocationEvent;
  13. import java.awt.event.KeyEvent;
  14. import java.awt.event.MouseEvent;
  15. import java.awt.event.PaintEvent;
  16. import java.awt.event.WindowEvent;
  17. import java.awt.ActiveEvent;
  18. import java.awt.peer.ComponentPeer;
  19. import java.awt.peer.LightweightPeer;
  20. import java.util.EmptyStackException;
  21. import java.lang.ref.WeakReference;
  22. import java.lang.reflect.InvocationTargetException;
  23. import java.security.AccessController;
  24. import java.security.PrivilegedAction;
  25. import sun.awt.PeerEvent;
  26. import sun.awt.SunToolkit;
  27. import sun.awt.DebugHelper;
  28. import sun.awt.AWTAutoShutdown;
  29. import sun.awt.AppContext;
  30. /**
  31. * <code>EventQueue</code> is a platform-independent class
  32. * that queues events, both from the underlying peer classes
  33. * and from trusted application classes.
  34. * <p>
  35. * It encapsulates asynchronous event dispatch machinery which
  36. * extracts events from the queue and dispatches them by calling
  37. * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method
  38. * on this <code>EventQueue</code> with the event to be dispatched
  39. * as an argument. The particular behavior of this machinery is
  40. * implementation-dependent. The only requirements are that events
  41. * which were actually enqueued to this queue (note that events
  42. * being posted to the <code>EventQueue</code> can be coalesced)
  43. * are dispatched:
  44. * <dl>
  45. * <dt> Sequentially.
  46. * <dd> That is, it is not permitted that several events from
  47. * this queue are dispatched simultaneously.
  48. * <dt> In the same order as they are enqueued.
  49. * <dd> That is, if <code>AWTEvent</code> A is enqueued
  50. * to the <code>EventQueue</code> before
  51. * <code>AWTEvent</code> B then event B will not be
  52. * dispatched before event A.
  53. * </dl>
  54. * <p>
  55. * Some browsers partition applets in different code bases into
  56. * separate contexts, and establish walls between these contexts.
  57. * In such a scenario, there will be one <code>EventQueue</code>
  58. * per context. Other browsers place all applets into the same
  59. * context, implying that there will be only a single, global
  60. * <code>EventQueue</code> for all applets. This behavior is
  61. * implementation-dependent. Consult your browser's documentation
  62. * for more information.
  63. * <p>
  64. * For information on the threading issues of the event dispatch
  65. * machinery, see <a href="doc-files/AWTThreadIssues.html">AWT Threading
  66. * Issues</a>.
  67. *
  68. * @author Thomas Ball
  69. * @author Fred Ecks
  70. * @author David Mendenhall
  71. *
  72. * @version 1.96, 06/28/04
  73. * @since 1.1
  74. */
  75. public class EventQueue {
  76. private static final DebugHelper dbg = DebugHelper.create(EventQueue.class);
  77. // From Thread.java
  78. private static int threadInitNumber;
  79. private static synchronized int nextThreadNum() {
  80. return threadInitNumber++;
  81. }
  82. private static final int LOW_PRIORITY = 0;
  83. private static final int NORM_PRIORITY = 1;
  84. private static final int HIGH_PRIORITY = 2;
  85. private static final int ULTIMATE_PRIORITY = 3;
  86. private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
  87. /*
  88. * We maintain one Queue for each priority that the EventQueue supports.
  89. * That is, the EventQueue object is actually implemented as
  90. * NUM_PRIORITIES queues and all Events on a particular internal Queue
  91. * have identical priority. Events are pulled off the EventQueue starting
  92. * with the Queue of highest priority. We progress in decreasing order
  93. * across all Queues.
  94. */
  95. private Queue[] queues = new Queue[NUM_PRIORITIES];
  96. /*
  97. * The next EventQueue on the stack, or null if this EventQueue is
  98. * on the top of the stack. If nextQueue is non-null, requests to post
  99. * an event are forwarded to nextQueue.
  100. */
  101. private EventQueue nextQueue;
  102. /*
  103. * The previous EventQueue on the stack, or null if this is the
  104. * "base" EventQueue.
  105. */
  106. private EventQueue previousQueue;
  107. private EventDispatchThread dispatchThread;
  108. private final ThreadGroup threadGroup =
  109. Thread.currentThread().getThreadGroup();
  110. private final ClassLoader classLoader =
  111. Thread.currentThread().getContextClassLoader();
  112. /*
  113. * Debugging flag -- set true and recompile to enable checking.
  114. */
  115. private final static boolean debug = false;
  116. /*
  117. * The time stamp of the last dispatched InputEvent or ActionEvent.
  118. */
  119. private long mostRecentEventTime = System.currentTimeMillis();
  120. /**
  121. * The modifiers field of the current event, if the current event is an
  122. * InputEvent or ActionEvent.
  123. */
  124. private WeakReference currentEvent;
  125. /*
  126. * Non-zero if a thread is waiting in getNextEvent(int) for an event of
  127. * a particular ID to be posted to the queue.
  128. */
  129. private int waitForID;
  130. private final String name = "AWT-EventQueue-" + nextThreadNum();
  131. public EventQueue() {
  132. for (int i = 0; i < NUM_PRIORITIES; i++) {
  133. queues[i] = new Queue();
  134. }
  135. /*
  136. * NOTE: if you ever have to start the associated event dispatch
  137. * thread at this point, be aware of the following problem:
  138. * If this EventQueue instance is created in
  139. * SunToolkit.createNewAppContext() the started dispatch thread
  140. * may call AppContext.getAppContext() before createNewAppContext()
  141. * completes thus causing mess in thread group to appcontext mapping.
  142. */
  143. }
  144. /**
  145. * Posts a 1.1-style event to the <code>EventQueue</code>.
  146. * If there is an existing event on the queue with the same ID
  147. * and event source, the source <code>Component</code>'s
  148. * <code>coalesceEvents</code> method will be called.
  149. *
  150. * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  151. * or a subclass of it
  152. * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
  153. */
  154. public void postEvent(AWTEvent theEvent) {
  155. SunToolkit.flushPendingEvents();
  156. postEventPrivate(theEvent);
  157. }
  158. /**
  159. * Posts a 1.1-style event to the <code>EventQueue</code>.
  160. * If there is an existing event on the queue with the same ID
  161. * and event source, the source <code>Component</code>'s
  162. * <code>coalesceEvents</code> method will be called.
  163. *
  164. * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  165. * or a subclass of it
  166. */
  167. final void postEventPrivate(AWTEvent theEvent) {
  168. theEvent.isPosted = true;
  169. synchronized(this) {
  170. int id = theEvent.getID();
  171. if (nextQueue != null) {
  172. // Forward event to top of EventQueue stack.
  173. nextQueue.postEventPrivate(theEvent);
  174. } else if (theEvent instanceof PeerEvent &&
  175. (((PeerEvent)theEvent).getFlags() &
  176. PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
  177. postEvent(theEvent, ULTIMATE_PRIORITY);
  178. } else if (theEvent instanceof PeerEvent &&
  179. (((PeerEvent)theEvent).getFlags() &
  180. PeerEvent.PRIORITY_EVENT) != 0) {
  181. postEvent(theEvent, HIGH_PRIORITY);
  182. } else if (id == PaintEvent.PAINT ||
  183. id == PaintEvent.UPDATE) {
  184. postEvent(theEvent, LOW_PRIORITY);
  185. } else {
  186. postEvent(theEvent, NORM_PRIORITY);
  187. }
  188. }
  189. }
  190. /**
  191. * Posts the event to the internal Queue of specified priority,
  192. * coalescing as appropriate.
  193. *
  194. * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
  195. * or a subclass of it
  196. * @param priority the desired priority of the event
  197. */
  198. private void postEvent(AWTEvent theEvent, int priority) {
  199. if (dispatchThread == null) {
  200. if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
  201. return;
  202. } else {
  203. initDispatchThread();
  204. }
  205. }
  206. Object source = theEvent.getSource();
  207. // Expanding RepaintArea
  208. if (source instanceof Component) {
  209. ComponentPeer sourcePeer = ((Component)source).peer;
  210. if (sourcePeer != null && theEvent instanceof PaintEvent &&
  211. !(sourcePeer instanceof LightweightPeer)) {
  212. sourcePeer.coalescePaintEvent((PaintEvent)theEvent);
  213. }
  214. }
  215. EventQueueItem newItem = new EventQueueItem(theEvent);
  216. boolean notifyID = (theEvent.getID() == this.waitForID);
  217. if (queues[priority].head == null) {
  218. boolean shouldNotify = noEvents();
  219. queues[priority].head = queues[priority].tail = newItem;
  220. if (shouldNotify) {
  221. if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
  222. AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
  223. }
  224. notifyAll();
  225. } else if (notifyID) {
  226. notifyAll();
  227. }
  228. } else {
  229. boolean isPeerEvent = theEvent instanceof PeerEvent;
  230. // For Component source events, traverse the entire list,
  231. // trying to coalesce events
  232. if (source instanceof Component) {
  233. EventQueueItem q = queues[priority].head;
  234. if (theEvent.id == Event.MOUSE_MOVE ||
  235. theEvent.id == Event.MOUSE_DRAG) {
  236. EventQueueItem qm;
  237. for(qm = q; qm != null; qm = qm.next) {
  238. if ((qm.event instanceof MouseEvent) &&
  239. qm.id != theEvent.id) {
  240. q = qm;
  241. }
  242. }
  243. }
  244. for (; q != null; q = q.next) {
  245. // Give Component.coalesceEvents a chance
  246. if (q.event.getSource() == source && q.id == newItem.id) {
  247. AWTEvent coalescedEvent = ((Component)source).coalesceEvents(q.event, theEvent);
  248. if (isPeerEvent && coalescedEvent == null && q.event instanceof PeerEvent) {
  249. coalescedEvent = ((PeerEvent)q.event).coalesceEvents((PeerEvent)theEvent);
  250. }
  251. if (coalescedEvent != null) {
  252. // Remove debugging statement because
  253. // calling AWTEvent.toString here causes a
  254. // deadlock.
  255. q.event = coalescedEvent;
  256. return;
  257. }
  258. }
  259. }
  260. }
  261. // The event was not coalesced or has non-Component source.
  262. // Insert it at the end of the appropriate Queue.
  263. queues[priority].tail.next = newItem;
  264. queues[priority].tail = newItem;
  265. if (notifyID) {
  266. notifyAll();
  267. }
  268. }
  269. }
  270. /**
  271. * Returns whether an event is pending on any of the separate
  272. * Queues.
  273. * @return whether an event is pending on any of the separate Queues
  274. */
  275. private boolean noEvents() {
  276. for (int i = 0; i < NUM_PRIORITIES; i++) {
  277. if (queues[i].head != null) {
  278. return false;
  279. }
  280. }
  281. return true;
  282. }
  283. /**
  284. * Removes an event from the <code>EventQueue</code> and
  285. * returns it. This method will block until an event has
  286. * been posted by another thread.
  287. * @return the next <code>AWTEvent</code>
  288. * @exception InterruptedException
  289. * if another thread has interrupted this thread
  290. */
  291. public AWTEvent getNextEvent() throws InterruptedException {
  292. do {
  293. /*
  294. * SunToolkit.flushPendingEvents must be called outside
  295. * of the synchronized block to avoid deadlock when
  296. * event queues are nested with push()/pop().
  297. */
  298. SunToolkit.flushPendingEvents();
  299. synchronized (this) {
  300. for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  301. if (queues[i].head != null) {
  302. EventQueueItem eqi = queues[i].head;
  303. queues[i].head = eqi.next;
  304. if (eqi.next == null) {
  305. queues[i].tail = null;
  306. }
  307. return eqi.event;
  308. }
  309. }
  310. AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
  311. wait();
  312. }
  313. } while(true);
  314. }
  315. AWTEvent getNextEvent(int id) throws InterruptedException {
  316. do {
  317. /*
  318. * SunToolkit.flushPendingEvents must be called outside
  319. * of the synchronized block to avoid deadlock when
  320. * event queues are nested with push()/pop().
  321. */
  322. SunToolkit.flushPendingEvents();
  323. synchronized (this) {
  324. for (int i = 0; i < NUM_PRIORITIES; i++) {
  325. for (EventQueueItem entry = queues[i].head, prev = null;
  326. entry != null; prev = entry, entry = entry.next)
  327. {
  328. if (entry.id == id) {
  329. if (prev == null) {
  330. queues[i].head = entry.next;
  331. } else {
  332. prev.next = entry.next;
  333. }
  334. if (queues[i].tail == entry) {
  335. queues[i].tail = prev;
  336. }
  337. return entry.event;
  338. }
  339. }
  340. }
  341. this.waitForID = id;
  342. wait();
  343. this.waitForID = 0;
  344. }
  345. } while(true);
  346. }
  347. /**
  348. * Returns the first event on the <code>EventQueue</code>
  349. * without removing it.
  350. * @return the first event
  351. */
  352. public synchronized AWTEvent peekEvent() {
  353. for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  354. if (queues[i].head != null) {
  355. return queues[i].head.event;
  356. }
  357. }
  358. return null;
  359. }
  360. /**
  361. * Returns the first event with the specified id, if any.
  362. * @param id the id of the type of event desired
  363. * @return the first event of the specified id or <code>null</code>
  364. * if there is no such event
  365. */
  366. public synchronized AWTEvent peekEvent(int id) {
  367. for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
  368. EventQueueItem q = queues[i].head;
  369. for (; q != null; q = q.next) {
  370. if (q.id == id) {
  371. return q.event;
  372. }
  373. }
  374. }
  375. return null;
  376. }
  377. /**
  378. * Dispatches an event. The manner in which the event is
  379. * dispatched depends upon the type of the event and the
  380. * type of the event's source object:
  381. * <p> </p>
  382. * <table border=1 summary="Event types, source types, and dispatch methods">
  383. * <tr>
  384. * <th>Event Type</th>
  385. * <th>Source Type</th>
  386. * <th>Dispatched To</th>
  387. * </tr>
  388. * <tr>
  389. * <td>ActiveEvent</td>
  390. * <td>Any</td>
  391. * <td>event.dispatch()</td>
  392. * </tr>
  393. * <tr>
  394. * <td>Other</td>
  395. * <td>Component</td>
  396. * <td>source.dispatchEvent(AWTEvent)</td>
  397. * </tr>
  398. * <tr>
  399. * <td>Other</td>
  400. * <td>MenuComponent</td>
  401. * <td>source.dispatchEvent(AWTEvent)</td>
  402. * </tr>
  403. * <tr>
  404. * <td>Other</td>
  405. * <td>Other</td>
  406. * <td>No action (ignored)</td>
  407. * </tr>
  408. * </table>
  409. * <p> </p>
  410. * @param event an instance of <code>java.awt.AWTEvent</code>,
  411. * or a subclass of it
  412. * @throws NullPointerException if <code>event</code> is <code>null</code>
  413. */
  414. protected void dispatchEvent(AWTEvent event) {
  415. event.isPosted = true;
  416. Object src = event.getSource();
  417. if (event instanceof ActiveEvent) {
  418. // This could become the sole method of dispatching in time.
  419. setCurrentEventAndMostRecentTimeImpl(event);
  420. ((ActiveEvent)event).dispatch();
  421. } else if (src instanceof Component) {
  422. ((Component)src).dispatchEvent(event);
  423. event.dispatched();
  424. } else if (src instanceof MenuComponent) {
  425. ((MenuComponent)src).dispatchEvent(event);
  426. } else if (src instanceof AWTAutoShutdown) {
  427. if (noEvents()) {
  428. dispatchThread.stopDispatching();
  429. }
  430. } else {
  431. System.err.println("unable to dispatch event: " + event);
  432. }
  433. }
  434. /**
  435. * Returns the timestamp of the most recent event that had a timestamp, and
  436. * that was dispatched from the <code>EventQueue</code> associated with the
  437. * calling thread. If an event with a timestamp is currently being
  438. * dispatched, its timestamp will be returned. If no events have yet
  439. * been dispatched, the EventQueue's initialization time will be
  440. * returned instead.In the current version of
  441. * the JDK, only <code>InputEvent</code>s,
  442. * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have
  443. * timestamps; however, future versions of the JDK may add timestamps to
  444. * additional event types. Note that this method should only be invoked
  445. * from an application's event dispatching thread. If this method is
  446. * invoked from another thread, the current system time (as reported by
  447. * <code>System.currentTimeMillis()</code>) will be returned instead.
  448. *
  449. * @return the timestamp of the last <code>InputEvent</code>,
  450. * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be
  451. * dispatched, or <code>System.currentTimeMillis()</code> if this
  452. * method is invoked on a thread other than an event dispatching
  453. * thread
  454. * @see java.awt.event.InputEvent#getWhen
  455. * @see java.awt.event.ActionEvent#getWhen
  456. * @see java.awt.event.InvocationEvent#getWhen
  457. *
  458. * @since 1.4
  459. */
  460. public static long getMostRecentEventTime() {
  461. return Toolkit.getEventQueue().getMostRecentEventTimeImpl();
  462. }
  463. private synchronized long getMostRecentEventTimeImpl() {
  464. return (Thread.currentThread() == dispatchThread)
  465. ? mostRecentEventTime
  466. : System.currentTimeMillis();
  467. }
  468. /**
  469. * @return most recent event time on all threads.
  470. */
  471. synchronized long getMostRecentEventTimeEx() {
  472. return mostRecentEventTime;
  473. }
  474. /**
  475. * Returns the the event currently being dispatched by the
  476. * <code>EventQueue</code> associated with the calling thread. This is
  477. * useful if a method needs access to the event, but was not designed to
  478. * receive a reference to it as an argument. Note that this method should
  479. * only be invoked from an application's event dispatching thread. If this
  480. * method is invoked from another thread, null will be returned.
  481. *
  482. * @return the event currently being dispatched, or null if this method is
  483. * invoked on a thread other than an event dispatching thread
  484. * @since 1.4
  485. */
  486. public static AWTEvent getCurrentEvent() {
  487. return Toolkit.getEventQueue().getCurrentEventImpl();
  488. }
  489. private synchronized AWTEvent getCurrentEventImpl() {
  490. return (Thread.currentThread() == dispatchThread)
  491. ? ((AWTEvent)currentEvent.get())
  492. : null;
  493. }
  494. /**
  495. * Replaces the existing <code>EventQueue</code> with the specified one.
  496. * Any pending events are transferred to the new <code>EventQueue</code>
  497. * for processing by it.
  498. *
  499. * @param newEventQueue an <code>EventQueue</code>
  500. * (or subclass thereof) instance to be use
  501. * @see java.awt.EventQueue#pop
  502. * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code>
  503. */
  504. public synchronized void push(EventQueue newEventQueue) {
  505. if (debug) {
  506. System.out.println("EventQueue.push(" + newEventQueue + ")");
  507. }
  508. if (nextQueue != null) {
  509. nextQueue.push(newEventQueue);
  510. return;
  511. }
  512. synchronized (newEventQueue) {
  513. // Transfer all events forward to new EventQueue.
  514. while (peekEvent() != null) {
  515. try {
  516. newEventQueue.postEventPrivate(getNextEvent());
  517. } catch (InterruptedException ie) {
  518. if (debug) {
  519. System.err.println("interrupted push:");
  520. ie.printStackTrace(System.err);
  521. }
  522. }
  523. }
  524. newEventQueue.previousQueue = this;
  525. }
  526. /*
  527. * Stop the event dispatch thread associated with the currently
  528. * active event queue, so that after the new queue is pushed
  529. * on the top this event dispatch thread won't prevent AWT from
  530. * being automatically shut down.
  531. * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
  532. * waits for the dispatch thread to exit, so if the dispatch
  533. * thread attempts to synchronize on this EventQueue object
  534. * it will never exit since we already hold this lock.
  535. */
  536. if (dispatchThread != null) {
  537. dispatchThread.stopDispatchingLater();
  538. }
  539. nextQueue = newEventQueue;
  540. AppContext appContext = AppContext.getAppContext();
  541. if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
  542. appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
  543. }
  544. }
  545. /**
  546. * Stops dispatching events using this <code>EventQueue</code>.
  547. * Any pending events are transferred to the previous
  548. * <code>EventQueue</code> for processing.
  549. * <p>
  550. * Warning: To avoid deadlock, do not declare this method
  551. * synchronized in a subclass.
  552. *
  553. * @exception EmptyStackException if no previous push was made
  554. * on this <code>EventQueue</code>
  555. * @see java.awt.EventQueue#push
  556. */
  557. protected void pop() throws EmptyStackException {
  558. if (debug) {
  559. System.out.println("EventQueue.pop(" + this + ")");
  560. }
  561. // To prevent deadlock, we lock on the previous EventQueue before
  562. // this one. This uses the same locking order as everything else
  563. // in EventQueue.java, so deadlock isn't possible.
  564. EventQueue prev = previousQueue;
  565. synchronized ((prev != null) ? prev : this) {
  566. synchronized(this) {
  567. if (nextQueue != null) {
  568. nextQueue.pop();
  569. return;
  570. }
  571. if (previousQueue == null) {
  572. throw new EmptyStackException();
  573. }
  574. // Transfer all events back to previous EventQueue.
  575. previousQueue.nextQueue = null;
  576. while (peekEvent() != null) {
  577. try {
  578. previousQueue.postEventPrivate(getNextEvent());
  579. } catch (InterruptedException ie) {
  580. if (debug) {
  581. System.err.println("interrupted pop:");
  582. ie.printStackTrace(System.err);
  583. }
  584. }
  585. }
  586. AppContext appContext = AppContext.getAppContext();
  587. if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
  588. appContext.put(AppContext.EVENT_QUEUE_KEY, previousQueue);
  589. }
  590. previousQueue = null;
  591. }
  592. }
  593. EventDispatchThread dt = this.dispatchThread;
  594. if (dt != null) {
  595. dt.stopDispatching(); // Must be done outside synchronized
  596. // block to avoid possible deadlock
  597. }
  598. }
  599. /**
  600. * Returns true if the calling thread is the current AWT
  601. * <code>EventQueue</code>'s dispatch thread. Use this
  602. * call the ensure that a given
  603. * task is being executed (or not being) on the current AWT
  604. * <code>EventDispatchThread</code>.
  605. *
  606. * @return true if running on the current AWT
  607. * <code>EventQueue</code>'s dispatch thread
  608. */
  609. public static boolean isDispatchThread() {
  610. EventQueue eq = Toolkit.getEventQueue();
  611. EventQueue next = eq.nextQueue;
  612. while (next != null) {
  613. eq = next;
  614. next = eq.nextQueue;
  615. }
  616. return (Thread.currentThread() == eq.dispatchThread);
  617. }
  618. final void initDispatchThread() {
  619. synchronized (this) {
  620. if (dispatchThread == null && !threadGroup.isDestroyed()) {
  621. dispatchThread = (EventDispatchThread)
  622. AccessController.doPrivileged(new PrivilegedAction() {
  623. public Object run() {
  624. EventDispatchThread t =
  625. new EventDispatchThread(threadGroup,
  626. name,
  627. EventQueue.this);
  628. t.setContextClassLoader(classLoader);
  629. t.setPriority(Thread.NORM_PRIORITY + 1);
  630. t.setDaemon(false);
  631. return t;
  632. }
  633. });
  634. AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
  635. dispatchThread.start();
  636. }
  637. }
  638. }
  639. final void detachDispatchThread() {
  640. dispatchThread = null;
  641. }
  642. /*
  643. * Gets the <code>EventDispatchThread</code> for this
  644. * <code>EventQueue</code>.
  645. * @return the event dispatch thread associated with this event queue
  646. * or <code>null</code> if this event queue doesn't have a
  647. * working thread associated with it
  648. * @see java.awt.EventQueue#initDispatchThread
  649. * @see java.awt.EventQueue#detachDispatchThread
  650. */
  651. final EventDispatchThread getDispatchThread() {
  652. return dispatchThread;
  653. }
  654. /*
  655. * Removes any pending events for the specified source object.
  656. * If removeAllEvents parameter is <code>true</code> then all
  657. * events for the specified source object are removed, if it
  658. * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>,
  659. * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>,
  660. * and <code>InputMethodEvent</code> are kept in the queue, but all other
  661. * events are removed.
  662. *
  663. * This method is normally called by the source's
  664. * <code>removeNotify</code> method.
  665. */
  666. final void removeSourceEvents(Object source, boolean removeAllEvents) {
  667. SunToolkit.flushPendingEvents();
  668. synchronized (this) {
  669. for (int i = 0; i < NUM_PRIORITIES; i++) {
  670. EventQueueItem entry = queues[i].head;
  671. EventQueueItem prev = null;
  672. while (entry != null) {
  673. if ((entry.event.getSource() == source)
  674. && (removeAllEvents
  675. || ! (entry.event instanceof SequencedEvent
  676. || entry.event instanceof SentEvent
  677. || entry.event instanceof FocusEvent
  678. || entry.event instanceof WindowEvent
  679. || entry.event instanceof KeyEvent
  680. || entry.event instanceof InputMethodEvent)))
  681. {
  682. if (entry.event instanceof SequencedEvent) {
  683. ((SequencedEvent)entry.event).dispose();
  684. }
  685. if (entry.event instanceof SentEvent) {
  686. ((SentEvent)entry.event).dispose();
  687. }
  688. if (prev == null) {
  689. queues[i].head = entry.next;
  690. } else {
  691. prev.next = entry.next;
  692. }
  693. } else {
  694. prev = entry;
  695. }
  696. entry = entry.next;
  697. }
  698. queues[i].tail = prev;
  699. }
  700. }
  701. }
  702. static void setCurrentEventAndMostRecentTime(AWTEvent e) {
  703. Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e);
  704. }
  705. private synchronized void setCurrentEventAndMostRecentTimeImpl(AWTEvent e)
  706. {
  707. if (Thread.currentThread() != dispatchThread) {
  708. return;
  709. }
  710. currentEvent = new WeakReference(e);
  711. // This series of 'instanceof' checks should be replaced with a
  712. // polymorphic type (for example, an interface which declares a
  713. // getWhen() method). However, this would require us to make such
  714. // a type public, or to place it in sun.awt. Both of these approaches
  715. // have been frowned upon. So for now, we hack.
  716. //
  717. // In tiger, we will probably give timestamps to all events, so this
  718. // will no longer be an issue.
  719. if (e instanceof InputEvent) {
  720. InputEvent ie = (InputEvent)e;
  721. mostRecentEventTime = ie.getWhen();
  722. } else if (e instanceof InputMethodEvent) {
  723. InputMethodEvent ime = (InputMethodEvent)e;
  724. mostRecentEventTime = ime.getWhen();
  725. } else if (e instanceof ActionEvent) {
  726. ActionEvent ae = (ActionEvent)e;
  727. mostRecentEventTime = ae.getWhen();
  728. } else if (e instanceof InvocationEvent) {
  729. InvocationEvent ie = (InvocationEvent)e;
  730. mostRecentEventTime = ie.getWhen();
  731. }
  732. }
  733. /**
  734. * Causes <code>runnable</code> to have its <code>run</code>
  735. * method called in the dispatch thread of the <code>EventQueue</code>.
  736. * This will happen after all pending events are processed.
  737. *
  738. * @param runnable the <code>Runnable</code> whose <code>run</code>
  739. * method should be executed
  740. * synchronously on the <code>EventQueue</code>
  741. * @see #invokeAndWait
  742. * @since 1.2
  743. */
  744. public static void invokeLater(Runnable runnable) {
  745. Toolkit.getEventQueue().postEvent(
  746. new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
  747. }
  748. /**
  749. * Causes <code>runnable</code> to have its <code>run</code>
  750. * method called in the dispatch thread of the <code>EventQueue</code>.
  751. * This will happen after all pending events are processed.
  752. * The call blocks until this has happened. This method
  753. * will throw an Error if called from the event dispatcher thread.
  754. *
  755. * @param runnable the <code>Runnable</code> whose <code>run</code>
  756. * method should be executed
  757. * synchronously on the <code>EventQueue</code>
  758. * @exception InterruptedException if another thread has
  759. * interrupted this thread
  760. * @exception InvocationTargetException if an throwable is thrown
  761. * when running <code>runnable</code>
  762. * @see #invokeLater
  763. * @since 1.2
  764. */
  765. public static void invokeAndWait(Runnable runnable)
  766. throws InterruptedException, InvocationTargetException {
  767. if (EventQueue.isDispatchThread()) {
  768. throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
  769. }
  770. class AWTInvocationLock {}
  771. Object lock = new AWTInvocationLock();
  772. InvocationEvent event =
  773. new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
  774. true);
  775. synchronized (lock) {
  776. Toolkit.getEventQueue().postEvent(event);
  777. lock.wait();
  778. }
  779. Throwable eventThrowable = event.getThrowable();
  780. if (eventThrowable != null) {
  781. throw new InvocationTargetException(eventThrowable);
  782. }
  783. }
  784. /*
  785. * Called from PostEventQueue.postEvent to notify that a new event
  786. * appeared. First it proceeds to the EventQueue on the top of the
  787. * stack, then notifies the associated dispatch thread if it exists
  788. * or starts a new one otherwise.
  789. */
  790. private void wakeup(boolean isShutdown) {
  791. synchronized(this) {
  792. if (nextQueue != null) {
  793. // Forward call to the top of EventQueue stack.
  794. nextQueue.wakeup(isShutdown);
  795. } else if (dispatchThread != null) {
  796. notifyAll();
  797. } else if (!isShutdown) {
  798. initDispatchThread();
  799. }
  800. }
  801. }
  802. }
  803. /**
  804. * The Queue object holds pointers to the beginning and end of one internal
  805. * queue. An EventQueue object is composed of multiple internal Queues, one
  806. * for each priority supported by the EventQueue. All Events on a particular
  807. * internal Queue have identical priority.
  808. */
  809. class Queue {
  810. EventQueueItem head;
  811. EventQueueItem tail;
  812. }
  813. class EventQueueItem {
  814. AWTEvent event;
  815. int id;
  816. EventQueueItem next;
  817. EventQueueItem(AWTEvent evt) {
  818. event = evt;
  819. id = evt.getID();
  820. }
  821. }