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