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