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