1 /* 2 * Copyright (c) 1996, 2011, 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.*; 29 30 import java.awt.peer.ComponentPeer; 31 32 import java.lang.ref.WeakReference; 33 import java.lang.reflect.InvocationTargetException; 34 35 import java.security.AccessController; 36 import java.security.PrivilegedAction; 37 38 import java.util.EmptyStackException; 39 40 import sun.awt.dnd.SunDropTargetEvent; 41 import sun.util.logging.PlatformLogger; 42 43 import sun.awt.AppContext; 44 import sun.awt.AWTAutoShutdown; 45 import sun.awt.PeerEvent; 46 import sun.awt.SunToolkit; 47 import sun.awt.EventQueueItem; 48 import sun.awt.AWTAccessor; 49 50 import java.util.concurrent.locks.Condition; 51 import java.util.concurrent.locks.Lock; 52 import java.util.concurrent.atomic.AtomicInteger; 53 54 import java.security.AccessControlContext; 55 56 import sun.misc.SharedSecrets; 57 import sun.misc.JavaSecurityAccess; 58 59 /** 60 * <code>EventQueue</code> is a platform-independent class 61 * that queues events, both from the underlying peer classes 62 * and from trusted application classes. 63 * <p> 64 * It encapsulates asynchronous event dispatch machinery which 65 * extracts events from the queue and dispatches them by calling 66 * {@link #dispatchEvent(AWTEvent) dispatchEvent(AWTEvent)} method 67 * on this <code>EventQueue</code> with the event to be dispatched 68 * as an argument. The particular behavior of this machinery is 69 * implementation-dependent. The only requirements are that events 70 * which were actually enqueued to this queue (note that events 71 * being posted to the <code>EventQueue</code> can be coalesced) 72 * are dispatched: 73 * <dl> 74 * <dt> Sequentially. 75 * <dd> That is, it is not permitted that several events from 76 * this queue are dispatched simultaneously. 77 * <dt> In the same order as they are enqueued. 78 * <dd> That is, if <code>AWTEvent</code> A is enqueued 79 * to the <code>EventQueue</code> before 80 * <code>AWTEvent</code> B then event B will not be 81 * dispatched before event A. 82 * </dl> 83 * <p> 84 * Some browsers partition applets in different code bases into 85 * separate contexts, and establish walls between these contexts. 86 * In such a scenario, there will be one <code>EventQueue</code> 87 * per context. Other browsers place all applets into the same 88 * context, implying that there will be only a single, global 89 * <code>EventQueue</code> for all applets. This behavior is 90 * implementation-dependent. Consult your browser's documentation 91 * for more information. 92 * <p> 93 * For information on the threading issues of the event dispatch 94 * machinery, see <a href="doc-files/AWTThreadIssues.html#Autoshutdown" 95 * >AWT Threading Issues</a>. 96 * 97 * @author Thomas Ball 98 * @author Fred Ecks 99 * @author David Mendenhall 100 * 101 * @since 1.1 102 */ 103 public class EventQueue { 104 private static final AtomicInteger threadInitNumber = new AtomicInteger(0); 105 106 private static final int LOW_PRIORITY = 0; 107 private static final int NORM_PRIORITY = 1; 108 private static final int HIGH_PRIORITY = 2; 109 private static final int ULTIMATE_PRIORITY = 3; 110 111 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1; 112 113 /* 114 * We maintain one Queue for each priority that the EventQueue supports. 115 * That is, the EventQueue object is actually implemented as 116 * NUM_PRIORITIES queues and all Events on a particular internal Queue 117 * have identical priority. Events are pulled off the EventQueue starting 118 * with the Queue of highest priority. We progress in decreasing order 119 * across all Queues. 120 */ 121 private Queue[] queues = new Queue[NUM_PRIORITIES]; 122 123 /* 124 * The next EventQueue on the stack, or null if this EventQueue is 125 * on the top of the stack. If nextQueue is non-null, requests to post 126 * an event are forwarded to nextQueue. 127 */ 128 private EventQueue nextQueue; 129 130 /* 131 * The previous EventQueue on the stack, or null if this is the 132 * "base" EventQueue. 133 */ 134 private EventQueue previousQueue; 135 136 /* 137 * A single lock to synchronize the push()/pop() and related operations with 138 * all the EventQueues from the AppContext. Synchronization on any particular 139 * event queue(s) is not enough: we should lock the whole stack. 140 */ 141 private final Lock pushPopLock; 142 private final Condition pushPopCond; 143 144 /* 145 * Dummy runnable to wake up EDT from getNextEvent() after 146 push/pop is performed 147 */ 148 private final static Runnable dummyRunnable = new Runnable() { 149 public void run() { 150 } 151 }; 152 153 private EventDispatchThread dispatchThread; 154 155 private final ThreadGroup threadGroup = 156 Thread.currentThread().getThreadGroup(); 157 private final ClassLoader classLoader = 158 Thread.currentThread().getContextClassLoader(); 159 160 /* 161 * The time stamp of the last dispatched InputEvent or ActionEvent. 162 */ 163 private long mostRecentEventTime = System.currentTimeMillis(); 164 165 /** 166 * The modifiers field of the current event, if the current event is an 167 * InputEvent or ActionEvent. 168 */ 169 private WeakReference currentEvent; 170 171 /* 172 * Non-zero if a thread is waiting in getNextEvent(int) for an event of 173 * a particular ID to be posted to the queue. 174 */ 175 private volatile int waitForID; 176 177 private final String name = "AWT-EventQueue-" + threadInitNumber.getAndIncrement(); 178 179 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventQueue"); 180 181 static { 182 AWTAccessor.setEventQueueAccessor( 183 new AWTAccessor.EventQueueAccessor() { 184 public Thread getDispatchThread(EventQueue eventQueue) { 185 return eventQueue.getDispatchThread(); 186 } 187 public boolean isDispatchThreadImpl(EventQueue eventQueue) { 188 return eventQueue.isDispatchThreadImpl(); 189 } 190 public void removeSourceEvents(EventQueue eventQueue, 191 Object source, 192 boolean removeAllEvents) { 193 eventQueue.removeSourceEvents(source, removeAllEvents); 194 } 195 public boolean noEvents(EventQueue eventQueue) { 196 return eventQueue.noEvents(); 197 } 198 public void wakeup(EventQueue eventQueue, boolean isShutdown) { 199 eventQueue.wakeup(isShutdown); 200 } 201 }); 202 } 203 204 public EventQueue() { 205 for (int i = 0; i < NUM_PRIORITIES; i++) { 206 queues[i] = new Queue(); 207 } 208 /* 209 * NOTE: if you ever have to start the associated event dispatch 210 * thread at this point, be aware of the following problem: 211 * If this EventQueue instance is created in 212 * SunToolkit.createNewAppContext() the started dispatch thread 213 * may call AppContext.getAppContext() before createNewAppContext() 214 * completes thus causing mess in thread group to appcontext mapping. 215 */ 216 217 pushPopLock = (Lock)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_LOCK_KEY); 218 pushPopCond = (Condition)AppContext.getAppContext().get(AppContext.EVENT_QUEUE_COND_KEY); 219 } 220 221 /** 222 * Posts a 1.1-style event to the <code>EventQueue</code>. 223 * If there is an existing event on the queue with the same ID 224 * and event source, the source <code>Component</code>'s 225 * <code>coalesceEvents</code> method will be called. 226 * 227 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 228 * or a subclass of it 229 * @throws NullPointerException if <code>theEvent</code> is <code>null</code> 230 */ 231 public void postEvent(AWTEvent theEvent) { 232 SunToolkit.flushPendingEvents(); 233 postEventPrivate(theEvent); 234 } 235 236 /** 237 * Posts a 1.1-style event to the <code>EventQueue</code>. 238 * If there is an existing event on the queue with the same ID 239 * and event source, the source <code>Component</code>'s 240 * <code>coalesceEvents</code> method will be called. 241 * 242 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 243 * or a subclass of it 244 */ 245 private final void postEventPrivate(AWTEvent theEvent) { 246 theEvent.isPosted = true; 247 pushPopLock.lock(); 248 try { 249 if (nextQueue != null) { 250 // Forward the event to the top of EventQueue stack 251 nextQueue.postEventPrivate(theEvent); 252 return; 253 } 254 if (dispatchThread == null) { 255 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) { 256 return; 257 } else { 258 initDispatchThread(); 259 } 260 } 261 postEvent(theEvent, getPriority(theEvent)); 262 } finally { 263 pushPopLock.unlock(); 264 } 265 } 266 267 private static int getPriority(AWTEvent theEvent) { 268 if (theEvent instanceof PeerEvent) { 269 PeerEvent peerEvent = (PeerEvent)theEvent; 270 if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) { 271 return ULTIMATE_PRIORITY; 272 } 273 if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) { 274 return HIGH_PRIORITY; 275 } 276 if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) { 277 return LOW_PRIORITY; 278 } 279 } 280 int id = theEvent.getID(); 281 if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) { 282 return LOW_PRIORITY; 283 } 284 return NORM_PRIORITY; 285 } 286 287 /** 288 * Posts the event to the internal Queue of specified priority, 289 * coalescing as appropriate. 290 * 291 * @param theEvent an instance of <code>java.awt.AWTEvent</code>, 292 * or a subclass of it 293 * @param priority the desired priority of the event 294 */ 295 private void postEvent(AWTEvent theEvent, int priority) { 296 if (coalesceEvent(theEvent, priority)) { 297 return; 298 } 299 300 EventQueueItem newItem = new EventQueueItem(theEvent); 301 302 cacheEQItem(newItem); 303 304 boolean notifyID = (theEvent.getID() == this.waitForID); 305 306 if (queues[priority].head == null) { 307 boolean shouldNotify = noEvents(); 308 queues[priority].head = queues[priority].tail = newItem; 309 310 if (shouldNotify) { 311 if (theEvent.getSource() != AWTAutoShutdown.getInstance()) { 312 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); 313 } 314 pushPopCond.signalAll(); 315 } else if (notifyID) { 316 pushPopCond.signalAll(); 317 } 318 } else { 319 // The event was not coalesced or has non-Component source. 320 // Insert it at the end of the appropriate Queue. 321 queues[priority].tail.next = newItem; 322 queues[priority].tail = newItem; 323 if (notifyID) { 324 pushPopCond.signalAll(); 325 } 326 } 327 } 328 329 private boolean coalescePaintEvent(PaintEvent e) { 330 ComponentPeer sourcePeer = ((Component)e.getSource()).peer; 331 if (sourcePeer != null) { 332 sourcePeer.coalescePaintEvent(e); 333 } 334 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 335 if (cache == null) { 336 return false; 337 } 338 int index = eventToCacheIndex(e); 339 340 if (index != -1 && cache[index] != null) { 341 PaintEvent merged = mergePaintEvents(e, (PaintEvent)cache[index].event); 342 if (merged != null) { 343 cache[index].event = merged; 344 return true; 345 } 346 } 347 return false; 348 } 349 350 private PaintEvent mergePaintEvents(PaintEvent a, PaintEvent b) { 351 Rectangle aRect = a.getUpdateRect(); 352 Rectangle bRect = b.getUpdateRect(); 353 if (bRect.contains(aRect)) { 354 return b; 355 } 356 if (aRect.contains(bRect)) { 357 return a; 358 } 359 return null; 360 } 361 362 private boolean coalesceMouseEvent(MouseEvent e) { 363 if (e instanceof SunDropTargetEvent) { 364 // SunDropTargetEvent should not coalesce with MouseEvent 365 return false; 366 } 367 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 368 if (cache == null) { 369 return false; 370 } 371 int index = eventToCacheIndex(e); 372 if (index != -1 && cache[index] != null) { 373 cache[index].event = e; 374 return true; 375 } 376 return false; 377 } 378 379 private boolean coalescePeerEvent(PeerEvent e) { 380 EventQueueItem[] cache = ((Component)e.getSource()).eventCache; 381 if (cache == null) { 382 return false; 383 } 384 int index = eventToCacheIndex(e); 385 if (index != -1 && cache[index] != null) { 386 e = e.coalesceEvents((PeerEvent)cache[index].event); 387 if (e != null) { 388 cache[index].event = e; 389 return true; 390 } else { 391 cache[index] = null; 392 } 393 } 394 return false; 395 } 396 397 /* 398 * Should avoid of calling this method by any means 399 * as it's working time is dependant on EQ length. 400 * In the wors case this method alone can slow down the entire application 401 * 10 times by stalling the Event processing. 402 * Only here by backward compatibility reasons. 403 */ 404 private boolean coalesceOtherEvent(AWTEvent e, int priority) { 405 int id = e.getID(); 406 Component source = (Component)e.getSource(); 407 for (EventQueueItem entry = queues[priority].head; 408 entry != null; entry = entry.next) 409 { 410 // Give Component.coalesceEvents a chance 411 if (entry.event.getSource() == source && entry.event.getID() == id) { 412 AWTEvent coalescedEvent = source.coalesceEvents( 413 entry.event, e); 414 if (coalescedEvent != null) { 415 entry.event = coalescedEvent; 416 return true; 417 } 418 } 419 } 420 return false; 421 } 422 423 private boolean coalesceEvent(AWTEvent e, int priority) { 424 if (!(e.getSource() instanceof Component)) { 425 return false; 426 } 427 if (e instanceof PeerEvent) { 428 return coalescePeerEvent((PeerEvent)e); 429 } 430 // The worst case 431 if (((Component)e.getSource()).isCoalescingEnabled() 432 && coalesceOtherEvent(e, priority)) 433 { 434 return true; 435 } 436 if (e instanceof PaintEvent) { 437 return coalescePaintEvent((PaintEvent)e); 438 } 439 if (e instanceof MouseEvent) { 440 return coalesceMouseEvent((MouseEvent)e); 441 } 442 return false; 443 } 444 445 private void cacheEQItem(EventQueueItem entry) { 446 if(entry.event instanceof SunDropTargetEvent) { 447 // Do not cache SunDropTargetEvent, it should not coalesce 448 return; 449 } 450 int index = eventToCacheIndex(entry.event); 451 if (index != -1 && entry.event.getSource() instanceof Component) { 452 Component source = (Component)entry.event.getSource(); 453 if (source.eventCache == null) { 454 source.eventCache = new EventQueueItem[CACHE_LENGTH]; 455 } 456 source.eventCache[index] = entry; 457 } 458 } 459 460 private void uncacheEQItem(EventQueueItem entry) { 461 int index = eventToCacheIndex(entry.event); 462 if (index != -1 && entry.event.getSource() instanceof Component) { 463 Component source = (Component)entry.event.getSource(); 464 if (source.eventCache == null) { 465 return; 466 } 467 source.eventCache[index] = null; 468 } 469 } 470 471 private static final int PAINT = 0; 472 private static final int UPDATE = 1; 473 private static final int MOVE = 2; 474 private static final int DRAG = 3; 475 private static final int PEER = 4; 476 private static final int CACHE_LENGTH = 5; 477 478 private static int eventToCacheIndex(AWTEvent e) { 479 switch(e.getID()) { 480 case PaintEvent.PAINT: 481 return PAINT; 482 case PaintEvent.UPDATE: 483 return UPDATE; 484 case MouseEvent.MOUSE_MOVED: 485 return MOVE; 486 case MouseEvent.MOUSE_DRAGGED: 487 return DRAG; 488 default: 489 return e instanceof PeerEvent ? PEER : -1; 490 } 491 } 492 493 /** 494 * Returns whether an event is pending on any of the separate 495 * Queues. 496 * @return whether an event is pending on any of the separate Queues 497 */ 498 private boolean noEvents() { 499 for (int i = 0; i < NUM_PRIORITIES; i++) { 500 if (queues[i].head != null) { 501 return false; 502 } 503 } 504 505 return true; 506 } 507 508 /** 509 * Removes an event from the <code>EventQueue</code> and 510 * returns it. This method will block until an event has 511 * been posted by another thread. 512 * @return the next <code>AWTEvent</code> 513 * @exception InterruptedException 514 * if any thread has interrupted this thread 515 */ 516 public AWTEvent getNextEvent() throws InterruptedException { 517 do { 518 /* 519 * SunToolkit.flushPendingEvents must be called outside 520 * of the synchronized block to avoid deadlock when 521 * event queues are nested with push()/pop(). 522 */ 523 SunToolkit.flushPendingEvents(); 524 pushPopLock.lock(); 525 try { 526 AWTEvent event = getNextEventPrivate(); 527 if (event != null) { 528 return event; 529 } 530 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread); 531 pushPopCond.await(); 532 } finally { 533 pushPopLock.unlock(); 534 } 535 } while(true); 536 } 537 538 /* 539 * Must be called under the lock. Doesn't call flushPendingEvents() 540 */ 541 AWTEvent getNextEventPrivate() throws InterruptedException { 542 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 543 if (queues[i].head != null) { 544 EventQueueItem entry = queues[i].head; 545 queues[i].head = entry.next; 546 if (entry.next == null) { 547 queues[i].tail = null; 548 } 549 uncacheEQItem(entry); 550 return entry.event; 551 } 552 } 553 return null; 554 } 555 556 AWTEvent getNextEvent(int id) throws InterruptedException { 557 do { 558 /* 559 * SunToolkit.flushPendingEvents must be called outside 560 * of the synchronized block to avoid deadlock when 561 * event queues are nested with push()/pop(). 562 */ 563 SunToolkit.flushPendingEvents(); 564 pushPopLock.lock(); 565 try { 566 for (int i = 0; i < NUM_PRIORITIES; i++) { 567 for (EventQueueItem entry = queues[i].head, prev = null; 568 entry != null; prev = entry, entry = entry.next) 569 { 570 if (entry.event.getID() == id) { 571 if (prev == null) { 572 queues[i].head = entry.next; 573 } else { 574 prev.next = entry.next; 575 } 576 if (queues[i].tail == entry) { 577 queues[i].tail = prev; 578 } 579 uncacheEQItem(entry); 580 return entry.event; 581 } 582 } 583 } 584 waitForID = id; 585 pushPopCond.await(); 586 waitForID = 0; 587 } finally { 588 pushPopLock.unlock(); 589 } 590 } while(true); 591 } 592 593 /** 594 * Returns the first event on the <code>EventQueue</code> 595 * without removing it. 596 * @return the first event 597 */ 598 public AWTEvent peekEvent() { 599 pushPopLock.lock(); 600 try { 601 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 602 if (queues[i].head != null) { 603 return queues[i].head.event; 604 } 605 } 606 } finally { 607 pushPopLock.unlock(); 608 } 609 610 return null; 611 } 612 613 /** 614 * Returns the first event with the specified id, if any. 615 * @param id the id of the type of event desired 616 * @return the first event of the specified id or <code>null</code> 617 * if there is no such event 618 */ 619 public AWTEvent peekEvent(int id) { 620 pushPopLock.lock(); 621 try { 622 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) { 623 EventQueueItem q = queues[i].head; 624 for (; q != null; q = q.next) { 625 if (q.event.getID() == id) { 626 return q.event; 627 } 628 } 629 } 630 } finally { 631 pushPopLock.unlock(); 632 } 633 634 return null; 635 } 636 637 private static final JavaSecurityAccess javaSecurityAccess = 638 SharedSecrets.getJavaSecurityAccess(); 639 640 /** 641 * Dispatches an event. The manner in which the event is 642 * dispatched depends upon the type of the event and the 643 * type of the event's source object: 644 * <p> </p> 645 * <table border=1 summary="Event types, source types, and dispatch methods"> 646 * <tr> 647 * <th>Event Type</th> 648 * <th>Source Type</th> 649 * <th>Dispatched To</th> 650 * </tr> 651 * <tr> 652 * <td>ActiveEvent</td> 653 * <td>Any</td> 654 * <td>event.dispatch()</td> 655 * </tr> 656 * <tr> 657 * <td>Other</td> 658 * <td>Component</td> 659 * <td>source.dispatchEvent(AWTEvent)</td> 660 * </tr> 661 * <tr> 662 * <td>Other</td> 663 * <td>MenuComponent</td> 664 * <td>source.dispatchEvent(AWTEvent)</td> 665 * </tr> 666 * <tr> 667 * <td>Other</td> 668 * <td>Other</td> 669 * <td>No action (ignored)</td> 670 * </tr> 671 * </table> 672 * <p> </p> 673 * @param event an instance of <code>java.awt.AWTEvent</code>, 674 * or a subclass of it 675 * @throws NullPointerException if <code>event</code> is <code>null</code> 676 * @since 1.2 677 */ 678 protected void dispatchEvent(final AWTEvent event) { 679 final Object src = event.getSource(); 680 final PrivilegedAction<Void> action = new PrivilegedAction<Void>() { 681 public Void run() { 682 dispatchEventImpl(event, src); 683 return null; 684 } 685 }; 686 687 final AccessControlContext stack = AccessController.getContext(); 688 final AccessControlContext srcAcc = getAccessControlContextFrom(src); 689 final AccessControlContext eventAcc = event.getAccessControlContext(); 690 if (srcAcc == null) { 691 javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc); 692 } else { 693 javaSecurityAccess.doIntersectionPrivilege( 694 new PrivilegedAction<Void>() { 695 public Void run() { 696 javaSecurityAccess.doIntersectionPrivilege(action, eventAcc); 697 return null; 698 } 699 }, stack, srcAcc); 700 } 701 } 702 703 private static AccessControlContext getAccessControlContextFrom(Object src) { 704 return src instanceof Component ? 705 ((Component)src).getAccessControlContext() : 706 src instanceof MenuComponent ? 707 ((MenuComponent)src).getAccessControlContext() : 708 src instanceof TrayIcon ? 709 ((TrayIcon)src).getAccessControlContext() : 710 null; 711 } 712 713 /** 714 * Called from dispatchEvent() under a correct AccessControlContext 715 */ 716 private void dispatchEventImpl(final AWTEvent event, final Object src) { 717 event.isPosted = true; 718 if (event instanceof ActiveEvent) { 719 // This could become the sole method of dispatching in time. 720 setCurrentEventAndMostRecentTimeImpl(event); 721 ((ActiveEvent)event).dispatch(); 722 } else if (src instanceof Component) { 723 ((Component)src).dispatchEvent(event); 724 event.dispatched(); 725 } else if (src instanceof MenuComponent) { 726 ((MenuComponent)src).dispatchEvent(event); 727 } else if (src instanceof TrayIcon) { 728 ((TrayIcon)src).dispatchEvent(event); 729 } else if (src instanceof AWTAutoShutdown) { 730 if (noEvents()) { 731 dispatchThread.stopDispatching(); 732 } 733 } else { 734 if (eventLog.isLoggable(PlatformLogger.FINE)) { 735 eventLog.fine("Unable to dispatch event: " + event); 736 } 737 } 738 } 739 740 /** 741 * Returns the timestamp of the most recent event that had a timestamp, and 742 * that was dispatched from the <code>EventQueue</code> associated with the 743 * calling thread. If an event with a timestamp is currently being 744 * dispatched, its timestamp will be returned. If no events have yet 745 * been dispatched, the EventQueue's initialization time will be 746 * returned instead.In the current version of 747 * the JDK, only <code>InputEvent</code>s, 748 * <code>ActionEvent</code>s, and <code>InvocationEvent</code>s have 749 * timestamps; however, future versions of the JDK may add timestamps to 750 * additional event types. Note that this method should only be invoked 751 * from an application's {@link #isDispatchThread event dispatching thread}. 752 * If this method is 753 * invoked from another thread, the current system time (as reported by 754 * <code>System.currentTimeMillis()</code>) will be returned instead. 755 * 756 * @return the timestamp of the last <code>InputEvent</code>, 757 * <code>ActionEvent</code>, or <code>InvocationEvent</code> to be 758 * dispatched, or <code>System.currentTimeMillis()</code> if this 759 * method is invoked on a thread other than an event dispatching 760 * thread 761 * @see java.awt.event.InputEvent#getWhen 762 * @see java.awt.event.ActionEvent#getWhen 763 * @see java.awt.event.InvocationEvent#getWhen 764 * @see #isDispatchThread 765 * 766 * @since 1.4 767 */ 768 public static long getMostRecentEventTime() { 769 return Toolkit.getEventQueue().getMostRecentEventTimeImpl(); 770 } 771 private long getMostRecentEventTimeImpl() { 772 pushPopLock.lock(); 773 try { 774 return (Thread.currentThread() == dispatchThread) 775 ? mostRecentEventTime 776 : System.currentTimeMillis(); 777 } finally { 778 pushPopLock.unlock(); 779 } 780 } 781 782 /** 783 * @return most recent event time on all threads. 784 */ 785 long getMostRecentEventTimeEx() { 786 pushPopLock.lock(); 787 try { 788 return mostRecentEventTime; 789 } finally { 790 pushPopLock.unlock(); 791 } 792 } 793 794 /** 795 * Returns the the event currently being dispatched by the 796 * <code>EventQueue</code> associated with the calling thread. This is 797 * useful if a method needs access to the event, but was not designed to 798 * receive a reference to it as an argument. Note that this method should 799 * only be invoked from an application's event dispatching thread. If this 800 * method is invoked from another thread, null will be returned. 801 * 802 * @return the event currently being dispatched, or null if this method is 803 * invoked on a thread other than an event dispatching thread 804 * @since 1.4 805 */ 806 public static AWTEvent getCurrentEvent() { 807 return Toolkit.getEventQueue().getCurrentEventImpl(); 808 } 809 private AWTEvent getCurrentEventImpl() { 810 pushPopLock.lock(); 811 try { 812 return (Thread.currentThread() == dispatchThread) 813 ? ((AWTEvent)currentEvent.get()) 814 : null; 815 } finally { 816 pushPopLock.unlock(); 817 } 818 } 819 820 /** 821 * Replaces the existing <code>EventQueue</code> with the specified one. 822 * Any pending events are transferred to the new <code>EventQueue</code> 823 * for processing by it. 824 * 825 * @param newEventQueue an <code>EventQueue</code> 826 * (or subclass thereof) instance to be use 827 * @see java.awt.EventQueue#pop 828 * @throws NullPointerException if <code>newEventQueue</code> is <code>null</code> 829 * @since 1.2 830 */ 831 public void push(EventQueue newEventQueue) { 832 if (eventLog.isLoggable(PlatformLogger.FINE)) { 833 eventLog.fine("EventQueue.push(" + newEventQueue + ")"); 834 } 835 836 pushPopLock.lock(); 837 try { 838 EventQueue topQueue = this; 839 while (topQueue.nextQueue != null) { 840 topQueue = topQueue.nextQueue; 841 } 842 843 if ((topQueue.dispatchThread != null) && 844 (topQueue.dispatchThread.getEventQueue() == this)) 845 { 846 newEventQueue.dispatchThread = topQueue.dispatchThread; 847 topQueue.dispatchThread.setEventQueue(newEventQueue); 848 } 849 850 // Transfer all events forward to new EventQueue. 851 while (topQueue.peekEvent() != null) { 852 try { 853 // Use getNextEventPrivate() as it doesn't call flushPendingEvents() 854 newEventQueue.postEventPrivate(topQueue.getNextEventPrivate()); 855 } catch (InterruptedException ie) { 856 if (eventLog.isLoggable(PlatformLogger.FINE)) { 857 eventLog.fine("Interrupted push", ie); 858 } 859 } 860 } 861 862 // Wake up EDT waiting in getNextEvent(), so it can 863 // pick up a new EventQueue. Post the waking event before 864 // topQueue.nextQueue is assigned, otherwise the event would 865 // go newEventQueue 866 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); 867 868 newEventQueue.previousQueue = topQueue; 869 topQueue.nextQueue = newEventQueue; 870 871 AppContext appContext = AppContext.getAppContext(); 872 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) { 873 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue); 874 } 875 876 pushPopCond.signalAll(); 877 } finally { 878 pushPopLock.unlock(); 879 } 880 } 881 882 /** 883 * Stops dispatching events using this <code>EventQueue</code>. 884 * Any pending events are transferred to the previous 885 * <code>EventQueue</code> for processing. 886 * <p> 887 * Warning: To avoid deadlock, do not declare this method 888 * synchronized in a subclass. 889 * 890 * @exception EmptyStackException if no previous push was made 891 * on this <code>EventQueue</code> 892 * @see java.awt.EventQueue#push 893 * @since 1.2 894 */ 895 protected void pop() throws EmptyStackException { 896 if (eventLog.isLoggable(PlatformLogger.FINE)) { 897 eventLog.fine("EventQueue.pop(" + this + ")"); 898 } 899 900 pushPopLock.lock(); 901 try { 902 EventQueue topQueue = this; 903 while (topQueue.nextQueue != null) { 904 topQueue = topQueue.nextQueue; 905 } 906 EventQueue prevQueue = topQueue.previousQueue; 907 if (prevQueue == null) { 908 throw new EmptyStackException(); 909 } 910 911 topQueue.previousQueue = null; 912 prevQueue.nextQueue = null; 913 914 // Transfer all events back to previous EventQueue. 915 while (topQueue.peekEvent() != null) { 916 try { 917 prevQueue.postEventPrivate(topQueue.getNextEventPrivate()); 918 } catch (InterruptedException ie) { 919 if (eventLog.isLoggable(PlatformLogger.FINE)) { 920 eventLog.fine("Interrupted pop", ie); 921 } 922 } 923 } 924 925 if ((topQueue.dispatchThread != null) && 926 (topQueue.dispatchThread.getEventQueue() == this)) 927 { 928 prevQueue.dispatchThread = topQueue.dispatchThread; 929 topQueue.dispatchThread.setEventQueue(prevQueue); 930 } 931 932 AppContext appContext = AppContext.getAppContext(); 933 if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) { 934 appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue); 935 } 936 937 // Wake up EDT waiting in getNextEvent(), so it can 938 // pick up a new EventQueue 939 topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable)); 940 941 pushPopCond.signalAll(); 942 } finally { 943 pushPopLock.unlock(); 944 } 945 } 946 947 /** 948 * Creates a new {@code secondary loop} associated with this 949 * event queue. Use the {@link SecondaryLoop#enter} and 950 * {@link SecondaryLoop#exit} methods to start and stop the 951 * event loop and dispatch the events from this queue. 952 * 953 * @return secondaryLoop A new secondary loop object, which can 954 * be used to launch a new nested event 955 * loop and dispatch events from this queue 956 * 957 * @see SecondaryLoop#enter 958 * @see SecondaryLoop#exit 959 * 960 * @since 1.7 961 */ 962 public SecondaryLoop createSecondaryLoop() { 963 return createSecondaryLoop(null, null, 0); 964 } 965 966 SecondaryLoop createSecondaryLoop(Conditional cond, EventFilter filter, long interval) { 967 pushPopLock.lock(); 968 try { 969 if (nextQueue != null) { 970 // Forward the request to the top of EventQueue stack 971 return nextQueue.createSecondaryLoop(cond, filter, interval); 972 } 973 if (dispatchThread == null) { 974 initDispatchThread(); 975 } 976 return new WaitDispatchSupport(dispatchThread, cond, filter, interval); 977 } finally { 978 pushPopLock.unlock(); 979 } 980 } 981 982 /** 983 * Returns true if the calling thread is 984 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 985 * dispatch thread. Use this method to ensure that a particular 986 * task is being executed (or not being) there. 987 * <p> 988 * Note: use the {@link #invokeLater} or {@link #invokeAndWait} 989 * methods to execute a task in 990 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 991 * dispatch thread. 992 * <p> 993 * 994 * @return true if running in 995 * {@link Toolkit#getSystemEventQueue the current AWT EventQueue}'s 996 * dispatch thread 997 * @see #invokeLater 998 * @see #invokeAndWait 999 * @see Toolkit#getSystemEventQueue 1000 * @since 1.2 1001 */ 1002 public static boolean isDispatchThread() { 1003 EventQueue eq = Toolkit.getEventQueue(); 1004 return eq.isDispatchThreadImpl(); 1005 } 1006 1007 final boolean isDispatchThreadImpl() { 1008 EventQueue eq = this; 1009 pushPopLock.lock(); 1010 try { 1011 EventQueue next = eq.nextQueue; 1012 while (next != null) { 1013 eq = next; 1014 next = eq.nextQueue; 1015 } 1016 return (Thread.currentThread() == eq.dispatchThread); 1017 } finally { 1018 pushPopLock.unlock(); 1019 } 1020 } 1021 1022 final void initDispatchThread() { 1023 pushPopLock.lock(); 1024 try { 1025 AppContext appContext = AppContext.getAppContext(); 1026 if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) { 1027 dispatchThread = AccessController.doPrivileged( 1028 new PrivilegedAction<EventDispatchThread>() { 1029 public EventDispatchThread run() { 1030 EventDispatchThread t = 1031 new EventDispatchThread(threadGroup, 1032 name, 1033 EventQueue.this); 1034 t.setContextClassLoader(classLoader); 1035 t.setPriority(Thread.NORM_PRIORITY + 1); 1036 t.setDaemon(false); 1037 return t; 1038 } 1039 } 1040 ); 1041 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); 1042 dispatchThread.start(); 1043 } 1044 } finally { 1045 pushPopLock.unlock(); 1046 } 1047 } 1048 1049 final boolean detachDispatchThread(EventDispatchThread edt, boolean forceDetach) { 1050 /* 1051 * This synchronized block is to secure that the event dispatch 1052 * thread won't die in the middle of posting a new event to the 1053 * associated event queue. It is important because we notify 1054 * that the event dispatch thread is busy after posting a new event 1055 * to its queue, so the EventQueue.dispatchThread reference must 1056 * be valid at that point. 1057 */ 1058 pushPopLock.lock(); 1059 try { 1060 if (edt == dispatchThread) { 1061 /* 1062 * Don't detach the thread if any events are pending. Not 1063 * sure if it's a possible scenario, though. 1064 * 1065 * Fix for 4648733. Check both the associated java event 1066 * queue and the PostEventQueue. 1067 */ 1068 if (!forceDetach && (peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) { 1069 return false; 1070 } 1071 dispatchThread = null; 1072 } 1073 AWTAutoShutdown.getInstance().notifyThreadFree(edt); 1074 return true; 1075 } finally { 1076 pushPopLock.unlock(); 1077 } 1078 } 1079 1080 /* 1081 * Gets the <code>EventDispatchThread</code> for this 1082 * <code>EventQueue</code>. 1083 * @return the event dispatch thread associated with this event queue 1084 * or <code>null</code> if this event queue doesn't have a 1085 * working thread associated with it 1086 * @see java.awt.EventQueue#initDispatchThread 1087 * @see java.awt.EventQueue#detachDispatchThread 1088 */ 1089 final EventDispatchThread getDispatchThread() { 1090 pushPopLock.lock(); 1091 try { 1092 return dispatchThread; 1093 } finally { 1094 pushPopLock.unlock(); 1095 } 1096 } 1097 1098 /* 1099 * Removes any pending events for the specified source object. 1100 * If removeAllEvents parameter is <code>true</code> then all 1101 * events for the specified source object are removed, if it 1102 * is <code>false</code> then <code>SequencedEvent</code>, <code>SentEvent</code>, 1103 * <code>FocusEvent</code>, <code>WindowEvent</code>, <code>KeyEvent</code>, 1104 * and <code>InputMethodEvent</code> are kept in the queue, but all other 1105 * events are removed. 1106 * 1107 * This method is normally called by the source's 1108 * <code>removeNotify</code> method. 1109 */ 1110 final void removeSourceEvents(Object source, boolean removeAllEvents) { 1111 SunToolkit.flushPendingEvents(); 1112 pushPopLock.lock(); 1113 try { 1114 for (int i = 0; i < NUM_PRIORITIES; i++) { 1115 EventQueueItem entry = queues[i].head; 1116 EventQueueItem prev = null; 1117 while (entry != null) { 1118 if ((entry.event.getSource() == source) 1119 && (removeAllEvents 1120 || ! (entry.event instanceof SequencedEvent 1121 || entry.event instanceof SentEvent 1122 || entry.event instanceof FocusEvent 1123 || entry.event instanceof WindowEvent 1124 || entry.event instanceof KeyEvent 1125 || entry.event instanceof InputMethodEvent))) 1126 { 1127 if (entry.event instanceof SequencedEvent) { 1128 ((SequencedEvent)entry.event).dispose(); 1129 } 1130 if (entry.event instanceof SentEvent) { 1131 ((SentEvent)entry.event).dispose(); 1132 } 1133 if (prev == null) { 1134 queues[i].head = entry.next; 1135 } else { 1136 prev.next = entry.next; 1137 } 1138 uncacheEQItem(entry); 1139 } else { 1140 prev = entry; 1141 } 1142 entry = entry.next; 1143 } 1144 queues[i].tail = prev; 1145 } 1146 } finally { 1147 pushPopLock.unlock(); 1148 } 1149 } 1150 1151 static void setCurrentEventAndMostRecentTime(AWTEvent e) { 1152 Toolkit.getEventQueue().setCurrentEventAndMostRecentTimeImpl(e); 1153 } 1154 private void setCurrentEventAndMostRecentTimeImpl(AWTEvent e) { 1155 pushPopLock.lock(); 1156 try { 1157 if (Thread.currentThread() != dispatchThread) { 1158 return; 1159 } 1160 1161 currentEvent = new WeakReference(e); 1162 1163 // This series of 'instanceof' checks should be replaced with a 1164 // polymorphic type (for example, an interface which declares a 1165 // getWhen() method). However, this would require us to make such 1166 // a type public, or to place it in sun.awt. Both of these approaches 1167 // have been frowned upon. So for now, we hack. 1168 // 1169 // In tiger, we will probably give timestamps to all events, so this 1170 // will no longer be an issue. 1171 long mostRecentEventTime2 = Long.MIN_VALUE; 1172 if (e instanceof InputEvent) { 1173 InputEvent ie = (InputEvent)e; 1174 mostRecentEventTime2 = ie.getWhen(); 1175 } else if (e instanceof InputMethodEvent) { 1176 InputMethodEvent ime = (InputMethodEvent)e; 1177 mostRecentEventTime2 = ime.getWhen(); 1178 } else if (e instanceof ActionEvent) { 1179 ActionEvent ae = (ActionEvent)e; 1180 mostRecentEventTime2 = ae.getWhen(); 1181 } else if (e instanceof InvocationEvent) { 1182 InvocationEvent ie = (InvocationEvent)e; 1183 mostRecentEventTime2 = ie.getWhen(); 1184 } 1185 mostRecentEventTime = Math.max(mostRecentEventTime, mostRecentEventTime2); 1186 } finally { 1187 pushPopLock.unlock(); 1188 } 1189 } 1190 1191 /** 1192 * Causes <code>runnable</code> to have its <code>run</code> 1193 * method called in the {@link #isDispatchThread dispatch thread} of 1194 * {@link Toolkit#getSystemEventQueue the system EventQueue}. 1195 * This will happen after all pending events are processed. 1196 * 1197 * @param runnable the <code>Runnable</code> whose <code>run</code> 1198 * method should be executed 1199 * asynchronously in the 1200 * {@link #isDispatchThread event dispatch thread} 1201 * of {@link Toolkit#getSystemEventQueue the system EventQueue} 1202 * @see #invokeAndWait 1203 * @see Toolkit#getSystemEventQueue 1204 * @see #isDispatchThread 1205 * @since 1.2 1206 */ 1207 public static void invokeLater(Runnable runnable) { 1208 Toolkit.getEventQueue().postEvent( 1209 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable)); 1210 } 1211 1212 /** 1213 * Causes <code>runnable</code> to have its <code>run</code> 1214 * method called in the {@link #isDispatchThread dispatch thread} of 1215 * {@link Toolkit#getSystemEventQueue the system EventQueue}. 1216 * This will happen after all pending events are processed. 1217 * The call blocks until this has happened. This method 1218 * will throw an Error if called from the 1219 * {@link #isDispatchThread event dispatcher thread}. 1220 * 1221 * @param runnable the <code>Runnable</code> whose <code>run</code> 1222 * method should be executed 1223 * synchronously in the 1224 * {@link #isDispatchThread event dispatch thread} 1225 * of {@link Toolkit#getSystemEventQueue the system EventQueue} 1226 * @exception InterruptedException if any thread has 1227 * interrupted this thread 1228 * @exception InvocationTargetException if an throwable is thrown 1229 * when running <code>runnable</code> 1230 * @see #invokeLater 1231 * @see Toolkit#getSystemEventQueue 1232 * @see #isDispatchThread 1233 * @since 1.2 1234 */ 1235 public static void invokeAndWait(Runnable runnable) 1236 throws InterruptedException, InvocationTargetException { 1237 1238 if (EventQueue.isDispatchThread()) { 1239 throw new Error("Cannot call invokeAndWait from the event dispatcher thread"); 1240 } 1241 1242 class AWTInvocationLock {} 1243 Object lock = new AWTInvocationLock(); 1244 1245 InvocationEvent event = 1246 new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, 1247 true); 1248 1249 synchronized (lock) { 1250 Toolkit.getEventQueue().postEvent(event); 1251 while (!event.isDispatched()) { 1252 lock.wait(); 1253 } 1254 } 1255 1256 Throwable eventThrowable = event.getThrowable(); 1257 if (eventThrowable != null) { 1258 throw new InvocationTargetException(eventThrowable); 1259 } 1260 } 1261 1262 /* 1263 * Called from PostEventQueue.postEvent to notify that a new event 1264 * appeared. First it proceeds to the EventQueue on the top of the 1265 * stack, then notifies the associated dispatch thread if it exists 1266 * or starts a new one otherwise. 1267 */ 1268 private void wakeup(boolean isShutdown) { 1269 pushPopLock.lock(); 1270 try { 1271 if (nextQueue != null) { 1272 // Forward call to the top of EventQueue stack. 1273 nextQueue.wakeup(isShutdown); 1274 } else if (dispatchThread != null) { 1275 pushPopCond.signalAll(); 1276 } else if (!isShutdown) { 1277 initDispatchThread(); 1278 } 1279 } finally { 1280 pushPopLock.unlock(); 1281 } 1282 } 1283 } 1284 1285 /** 1286 * The Queue object holds pointers to the beginning and end of one internal 1287 * queue. An EventQueue object is composed of multiple internal Queues, one 1288 * for each priority supported by the EventQueue. All Events on a particular 1289 * internal Queue have identical priority. 1290 */ 1291 class Queue { 1292 EventQueueItem head; 1293 EventQueueItem tail; 1294 }