jdk/src/share/classes/java/awt/EventQueue.java
changeset 5942 287c421fb9b2
parent 5506 202f599c92aa
child 6484 f5dbd940a640
equal deleted inserted replaced
5941:1a56de1b70b3 5942:287c421fb9b2
   136      * event queue(s) is not enough: we should lock the whole stack.
   136      * event queue(s) is not enough: we should lock the whole stack.
   137      */
   137      */
   138     private final Lock pushPopLock;
   138     private final Lock pushPopLock;
   139     private final Condition pushPopCond;
   139     private final Condition pushPopCond;
   140 
   140 
       
   141     /*
       
   142      * Dummy runnable to wake up EDT from getNextEvent() after
       
   143      push/pop is performed
       
   144      */
       
   145     private final static Runnable dummyRunnable = new Runnable() {
       
   146         public void run() {
       
   147         }
       
   148     };
       
   149 
   141     private EventDispatchThread dispatchThread;
   150     private EventDispatchThread dispatchThread;
   142 
   151 
   143     private final ThreadGroup threadGroup =
   152     private final ThreadGroup threadGroup =
   144         Thread.currentThread().getThreadGroup();
   153         Thread.currentThread().getThreadGroup();
   145     private final ClassLoader classLoader =
   154     private final ClassLoader classLoader =
   217      * <code>coalesceEvents</code> method will be called.
   226      * <code>coalesceEvents</code> method will be called.
   218      *
   227      *
   219      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
   228      * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
   220      *          or a subclass of it
   229      *          or a subclass of it
   221      */
   230      */
   222     final void postEventPrivate(AWTEvent theEvent) {
   231     private final void postEventPrivate(AWTEvent theEvent) {
   223         theEvent.isPosted = true;
   232         theEvent.isPosted = true;
   224         pushPopLock.lock();
   233         pushPopLock.lock();
   225         try {
   234         try {
   226             if (dispatchThread == null && nextQueue == null) {
   235             if (nextQueue != null) {
       
   236                 // Forward the event to the top of EventQueue stack
       
   237                 nextQueue.postEventPrivate(theEvent);
       
   238                 return;
       
   239             }
       
   240             if (dispatchThread == null) {
   227                 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
   241                 if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
   228                     return;
   242                     return;
   229                 } else {
   243                 } else {
   230                     initDispatchThread();
   244                     initDispatchThread();
   231                 }
   245                 }
   232             }
   246             }
   233             if (nextQueue != null) {
       
   234                 // Forward event to top of EventQueue stack.
       
   235                 nextQueue.postEventPrivate(theEvent);
       
   236                 return;
       
   237             }
       
   238             postEvent(theEvent, getPriority(theEvent));
   247             postEvent(theEvent, getPriority(theEvent));
   239         } finally {
   248         } finally {
   240             pushPopLock.unlock();
   249             pushPopLock.unlock();
   241         }
   250         }
   242     }
   251     }
   243 
   252 
   244     private static int getPriority(AWTEvent theEvent) {
   253     private static int getPriority(AWTEvent theEvent) {
   245         if (theEvent instanceof PeerEvent &&
   254         if (theEvent instanceof PeerEvent) {
   246             (((PeerEvent)theEvent).getFlags() &
   255             PeerEvent peerEvent = (PeerEvent)theEvent;
   247                 PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0)
   256             if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
   248         {
   257                 return ULTIMATE_PRIORITY;
   249             return ULTIMATE_PRIORITY;
   258             }
   250         }
   259             if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
   251 
   260                 return HIGH_PRIORITY;
   252         if (theEvent instanceof PeerEvent &&
   261             }
   253             (((PeerEvent)theEvent).getFlags() &
   262             if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
   254                 PeerEvent.PRIORITY_EVENT) != 0)
   263                 return LOW_PRIORITY;
   255         {
   264             }
   256             return HIGH_PRIORITY;
   265         }
   257         }
       
   258 
       
   259         if (theEvent instanceof PeerEvent &&
       
   260             (((PeerEvent)theEvent).getFlags() &
       
   261                 PeerEvent.LOW_PRIORITY_EVENT) != 0)
       
   262         {
       
   263             return LOW_PRIORITY;
       
   264         }
       
   265 
       
   266         int id = theEvent.getID();
   266         int id = theEvent.getID();
   267         if (id == PaintEvent.PAINT || id == PaintEvent.UPDATE) {
   267         if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
   268             return LOW_PRIORITY;
   268             return LOW_PRIORITY;
   269         }
   269         }
   270         return NORM_PRIORITY;
   270         return NORM_PRIORITY;
   271     }
   271     }
   272 
   272 
   499              * event queues are nested with push()/pop().
   499              * event queues are nested with push()/pop().
   500              */
   500              */
   501             SunToolkit.flushPendingEvents();
   501             SunToolkit.flushPendingEvents();
   502             pushPopLock.lock();
   502             pushPopLock.lock();
   503             try {
   503             try {
   504                 for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
   504                 AWTEvent event = getNextEventPrivate();
   505                     if (queues[i].head != null) {
   505                 if (event != null) {
   506                         EventQueueItem entry = queues[i].head;
   506                     return event;
   507                         queues[i].head = entry.next;
       
   508                         if (entry.next == null) {
       
   509                             queues[i].tail = null;
       
   510                         }
       
   511                         uncacheEQItem(entry);
       
   512                         return entry.event;
       
   513                     }
       
   514                 }
   507                 }
   515                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
   508                 AWTAutoShutdown.getInstance().notifyThreadFree(dispatchThread);
   516                 pushPopCond.await();
   509                 pushPopCond.await();
   517             } finally {
   510             } finally {
   518                 pushPopLock.unlock();
   511                 pushPopLock.unlock();
   519             }
   512             }
   520         } while(true);
   513         } while(true);
       
   514     }
       
   515 
       
   516     /*
       
   517      * Must be called under the lock. Doesn't call flushPendingEvents()
       
   518      */
       
   519     AWTEvent getNextEventPrivate() throws InterruptedException {
       
   520         for (int i = NUM_PRIORITIES - 1; i >= 0; i--) {
       
   521             if (queues[i].head != null) {
       
   522                 EventQueueItem entry = queues[i].head;
       
   523                 queues[i].head = entry.next;
       
   524                 if (entry.next == null) {
       
   525                     queues[i].tail = null;
       
   526                 }
       
   527                 uncacheEQItem(entry);
       
   528                 return entry.event;
       
   529             }
       
   530         }
       
   531         return null;
   521     }
   532     }
   522 
   533 
   523     AWTEvent getNextEvent(int id) throws InterruptedException {
   534     AWTEvent getNextEvent(int id) throws InterruptedException {
   524         do {
   535         do {
   525             /*
   536             /*
   657         } else if (src instanceof AWTAutoShutdown) {
   668         } else if (src instanceof AWTAutoShutdown) {
   658             if (noEvents()) {
   669             if (noEvents()) {
   659                 dispatchThread.stopDispatching();
   670                 dispatchThread.stopDispatching();
   660             }
   671             }
   661         } else {
   672         } else {
   662             System.err.println("unable to dispatch event: " + event);
   673             if (eventLog.isLoggable(PlatformLogger.FINE)) {
       
   674                 eventLog.fine("Unable to dispatch event: " + event);
       
   675             }
   663         }
   676         }
   664     }
   677     }
   665 
   678 
   666     /**
   679     /**
   667      * Returns the timestamp of the most recent event that had a timestamp, and
   680      * Returns the timestamp of the most recent event that had a timestamp, and
   759             eventLog.fine("EventQueue.push(" + newEventQueue + ")");
   772             eventLog.fine("EventQueue.push(" + newEventQueue + ")");
   760         }
   773         }
   761 
   774 
   762         pushPopLock.lock();
   775         pushPopLock.lock();
   763         try {
   776         try {
   764             EventQueue toPush = this;
   777             EventQueue topQueue = this;
   765             while (toPush.nextQueue != null) {
   778             while (topQueue.nextQueue != null) {
   766                 toPush = toPush.nextQueue;
   779                 topQueue = topQueue.nextQueue;
       
   780             }
       
   781 
       
   782             if ((topQueue.dispatchThread != null) &&
       
   783                 (topQueue.dispatchThread.getEventQueue() == this))
       
   784             {
       
   785                 newEventQueue.dispatchThread = topQueue.dispatchThread;
       
   786                 topQueue.dispatchThread.setEventQueue(newEventQueue);
   767             }
   787             }
   768 
   788 
   769             // Transfer all events forward to new EventQueue.
   789             // Transfer all events forward to new EventQueue.
   770             while (toPush.peekEvent() != null) {
   790             while (topQueue.peekEvent() != null) {
   771                 try {
   791                 try {
   772                     newEventQueue.postEventPrivate(toPush.getNextEvent());
   792                     // Use getNextEventPrivate() as it doesn't call flushPendingEvents()
       
   793                     newEventQueue.postEventPrivate(topQueue.getNextEventPrivate());
   773                 } catch (InterruptedException ie) {
   794                 } catch (InterruptedException ie) {
   774                     if (eventLog.isLoggable(PlatformLogger.FINE)) {
   795                     if (eventLog.isLoggable(PlatformLogger.FINE)) {
   775                         eventLog.fine("Interrupted push", ie);
   796                         eventLog.fine("Interrupted push", ie);
   776                     }
   797                     }
   777                 }
   798                 }
   778             }
   799             }
   779 
   800 
   780             newEventQueue.previousQueue = toPush;
   801             // Wake up EDT waiting in getNextEvent(), so it can
   781 
   802             // pick up a new EventQueue. Post the waking event before
   782             /*
   803             // topQueue.nextQueue is assigned, otherwise the event would
   783              * Stop the event dispatch thread associated with the currently
   804             // go newEventQueue
   784              * active event queue, so that after the new queue is pushed
   805             topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
   785              * on the top this event dispatch thread won't prevent AWT from
   806 
   786              * being automatically shut down.
   807             newEventQueue.previousQueue = topQueue;
   787              * Use stopDispatchingLater() to avoid deadlock: stopDispatching()
   808             topQueue.nextQueue = newEventQueue;
   788              * waits for the dispatch thread to exit, which in turn waits
       
   789              * for the lock in EQ.detachDispatchThread(), which is hold by
       
   790              * this method.
       
   791              */
       
   792             if (toPush.dispatchThread != null) {
       
   793                 toPush.dispatchThread.stopDispatchingLater();
       
   794             }
       
   795 
       
   796             toPush.nextQueue = newEventQueue;
       
   797 
   809 
   798             AppContext appContext = AppContext.getAppContext();
   810             AppContext appContext = AppContext.getAppContext();
   799             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == toPush) {
   811             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == topQueue) {
   800                 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
   812                 appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
   801             }
   813             }
       
   814 
       
   815             pushPopCond.signalAll();
   802         } finally {
   816         } finally {
   803             pushPopLock.unlock();
   817             pushPopLock.unlock();
   804         }
   818         }
   805     }
   819     }
   806 
   820 
   820     protected void pop() throws EmptyStackException {
   834     protected void pop() throws EmptyStackException {
   821         if (eventLog.isLoggable(PlatformLogger.FINE)) {
   835         if (eventLog.isLoggable(PlatformLogger.FINE)) {
   822             eventLog.fine("EventQueue.pop(" + this + ")");
   836             eventLog.fine("EventQueue.pop(" + this + ")");
   823         }
   837         }
   824 
   838 
   825         EventDispatchThread dt = null;
   839         pushPopLock.lock();
   826         pushPopLock.lock();
   840         try {
   827         try {
   841             EventQueue topQueue = this;
   828             EventQueue toPop = this;
   842             while (topQueue.nextQueue != null) {
   829             while (toPop.nextQueue != null) {
   843                 topQueue = topQueue.nextQueue;
   830                 toPop = toPop.nextQueue;
   844             }
   831             }
   845             EventQueue prevQueue = topQueue.previousQueue;
   832             EventQueue prev = toPop.previousQueue;
   846             if (prevQueue == null) {
   833             if (prev == null) {
       
   834                 throw new EmptyStackException();
   847                 throw new EmptyStackException();
   835             }
   848             }
   836             toPop.previousQueue = null;
   849 
       
   850             topQueue.previousQueue = null;
       
   851             prevQueue.nextQueue = null;
   837 
   852 
   838             // Transfer all events back to previous EventQueue.
   853             // Transfer all events back to previous EventQueue.
   839             prev.nextQueue = null;
   854             while (topQueue.peekEvent() != null) {
   840             while (toPop.peekEvent() != null) {
       
   841                 try {
   855                 try {
   842                     prev.postEventPrivate(toPop.getNextEvent());
   856                     prevQueue.postEventPrivate(topQueue.getNextEventPrivate());
   843                 } catch (InterruptedException ie) {
   857                 } catch (InterruptedException ie) {
   844                     if (eventLog.isLoggable(PlatformLogger.FINE)) {
   858                     if (eventLog.isLoggable(PlatformLogger.FINE)) {
   845                         eventLog.fine("Interrupted pop", ie);
   859                         eventLog.fine("Interrupted pop", ie);
   846                     }
   860                     }
   847                 }
   861                 }
   848             }
   862             }
       
   863 
       
   864             if ((topQueue.dispatchThread != null) &&
       
   865                 (topQueue.dispatchThread.getEventQueue() == this))
       
   866             {
       
   867                 prevQueue.dispatchThread = topQueue.dispatchThread;
       
   868                 topQueue.dispatchThread.setEventQueue(prevQueue);
       
   869             }
       
   870 
   849             AppContext appContext = AppContext.getAppContext();
   871             AppContext appContext = AppContext.getAppContext();
   850             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
   872             if (appContext.get(AppContext.EVENT_QUEUE_KEY) == this) {
   851                 appContext.put(AppContext.EVENT_QUEUE_KEY, prev);
   873                 appContext.put(AppContext.EVENT_QUEUE_KEY, prevQueue);
   852             }
   874             }
   853 
   875 
   854             dt = toPop.dispatchThread;
   876             // Wake up EDT waiting in getNextEvent(), so it can
   855         } finally {
   877             // pick up a new EventQueue
   856             pushPopLock.unlock();
   878             topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
   857         }
   879 
   858 
   880             pushPopCond.signalAll();
   859         if (dt != null) {
   881         } finally {
   860             dt.stopDispatching(); // Must be done outside synchronized
   882             pushPopLock.unlock();
   861                                   // block to avoid possible deadlock
       
   862         }
   883         }
   863     }
   884     }
   864 
   885 
   865     /**
   886     /**
   866      * Returns true if the calling thread is
   887      * Returns true if the calling thread is
   905     final void initDispatchThread() {
   926     final void initDispatchThread() {
   906         pushPopLock.lock();
   927         pushPopLock.lock();
   907         try {
   928         try {
   908             AppContext appContext = AppContext.getAppContext();
   929             AppContext appContext = AppContext.getAppContext();
   909             if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
   930             if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) {
   910                 dispatchThread = (EventDispatchThread)
   931                 dispatchThread = AccessController.doPrivileged(
   911                     AccessController.doPrivileged(new PrivilegedAction() {
   932                     new PrivilegedAction<EventDispatchThread>() {
   912                         public Object run() {
   933                         public EventDispatchThread run() {
   913                             EventDispatchThread t =
   934                             EventDispatchThread t =
   914                                 new EventDispatchThread(threadGroup,
   935                                 new EventDispatchThread(threadGroup,
   915                                                         name,
   936                                                         name,
   916                                                         EventQueue.this);
   937                                                         EventQueue.this);
   917                             t.setContextClassLoader(classLoader);
   938                             t.setContextClassLoader(classLoader);
   918                             t.setPriority(Thread.NORM_PRIORITY + 1);
   939                             t.setPriority(Thread.NORM_PRIORITY + 1);
   919                             t.setDaemon(false);
   940                             t.setDaemon(false);
   920                             return t;
   941                             return t;
   921                         }
   942                         }
   922                     });
   943                     }
       
   944                 );
   923                 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
   945                 AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
   924                 dispatchThread.start();
   946                 dispatchThread.start();
   925             }
   947             }
   926         } finally {
   948         } finally {
   927             pushPopLock.unlock();
   949             pushPopLock.unlock();
   928         }
   950         }
   929     }
   951     }
   930 
   952 
   931     final void detachDispatchThread(EventDispatchThread edt, boolean restart) {
   953     final boolean detachDispatchThread(EventDispatchThread edt) {
   932         /*
   954         /*
   933          * This synchronized block is to secure that the event dispatch
   955          * This synchronized block is to secure that the event dispatch
   934          * thread won't die in the middle of posting a new event to the
   956          * thread won't die in the middle of posting a new event to the
   935          * associated event queue. It is important because we notify
   957          * associated event queue. It is important because we notify
   936          * that the event dispatch thread is busy after posting a new event
   958          * that the event dispatch thread is busy after posting a new event
   937          * to its queue, so the EventQueue.dispatchThread reference must
   959          * to its queue, so the EventQueue.dispatchThread reference must
   938          * be valid at that point.
   960          * be valid at that point.
   939          */
   961          */
   940         pushPopLock.lock();
   962         pushPopLock.lock();
   941         try {
   963         try {
   942             EventDispatchThread oldDispatchThread = dispatchThread;
   964             if (edt == dispatchThread) {
   943             if (dispatchThread == edt) {
       
   944                 dispatchThread = null;
       
   945             }
       
   946             if (restart) {
       
   947                 /*
   965                 /*
   948                  * Event dispatch thread dies in case of an uncaught exception.
   966                  * Don't detach the thread if any events are pending. Not
   949                  * A new event dispatch thread for this queue will be started
   967                  * sure if it's a possible scenario, though.
   950                  * only if a new event is posted to it. In case if no more
       
   951                  * events are posted after this thread died all events that
       
   952                  * currently are in the queue will never be dispatched.
       
   953                  *
   968                  *
   954                  * Fix for 4648733. Check both the associated java event
   969                  * Fix for 4648733. Check both the associated java event
   955                  * queue and the PostEventQueue.
   970                  * queue and the PostEventQueue.
   956                  */
   971                  */
   957                 if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
   972                 if ((peekEvent() != null) || !SunToolkit.isPostEventQueueEmpty()) {
   958                     initDispatchThread();
   973                     return false;
   959                 }
   974                 }
   960                 AWTAutoShutdown.getInstance().notifyThreadFree(oldDispatchThread);
   975                 dispatchThread = null;
   961             }
   976             }
       
   977             AWTAutoShutdown.getInstance().notifyThreadFree(edt);
       
   978             return true;
   962         } finally {
   979         } finally {
   963             pushPopLock.unlock();
   980             pushPopLock.unlock();
   964         }
   981         }
   965     }
   982     }
   966 
   983