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