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