Allowing JavaFX to dispatchEvent in its own, dedicated FX dispatch thread javafx tip
authorJaroslav Tulach <jtulach@netbeans.org>
Wed, 23 May 2012 11:51:09 +0200
branchjavafx
changeset 52294ed8674de305
parent 5222 78cea258caab
Allowing JavaFX to dispatchEvent in its own, dedicated FX dispatch thread
src/share/classes/java/awt/Container.java
src/share/classes/java/awt/DefaultKeyboardFocusManager.java
src/share/classes/java/awt/EventDispatchThread.java
src/share/classes/java/awt/EventQueue.java
src/share/classes/java/awt/SequencedEvent.java
     1.1 --- a/src/share/classes/java/awt/Container.java	Thu Mar 29 13:02:24 2012 -0700
     1.2 +++ b/src/share/classes/java/awt/Container.java	Wed May 23 11:51:09 2012 +0200
     1.3 @@ -2887,8 +2887,7 @@
     1.4  
     1.5          Runnable pumpEventsForHierarchy = new Runnable() {
     1.6              public void run() {
     1.7 -                EventDispatchThread dispatchThread =
     1.8 -                    (EventDispatchThread)Thread.currentThread();
     1.9 +                EventDispatchThread dispatchThread = EventDispatchThread.findCurrent();
    1.10                  dispatchThread.pumpEventsForHierarchy(
    1.11                          new Conditional() {
    1.12                          public boolean evaluate() {
     2.1 --- a/src/share/classes/java/awt/DefaultKeyboardFocusManager.java	Thu Mar 29 13:02:24 2012 -0700
     2.2 +++ b/src/share/classes/java/awt/DefaultKeyboardFocusManager.java	Wed May 23 11:51:09 2012 +0200
     2.3 @@ -237,8 +237,7 @@
     2.4              }
     2.5              SunToolkit.postEvent(targetAppContext, se);
     2.6              if (EventQueue.isDispatchThread()) {
     2.7 -                EventDispatchThread edt = (EventDispatchThread)
     2.8 -                    Thread.currentThread();
     2.9 +                EventDispatchThread edt = EventDispatchThread.findCurrent();
    2.10                  edt.pumpEvents(SentEvent.ID, new Conditional() {
    2.11                          public boolean evaluate() {
    2.12                              return !se.dispatched && !targetAppContext.isDisposed();
     3.1 --- a/src/share/classes/java/awt/EventDispatchThread.java	Thu Mar 29 13:02:24 2012 -0700
     3.2 +++ b/src/share/classes/java/awt/EventDispatchThread.java	Wed May 23 11:51:09 2012 +0200
     3.3 @@ -25,19 +25,15 @@
     3.4  
     3.5  package java.awt;
     3.6  
     3.7 -import java.awt.event.InputEvent;
     3.8  import java.awt.event.MouseEvent;
     3.9  import java.awt.event.ActionEvent;
    3.10  import java.awt.event.WindowEvent;
    3.11  import java.lang.reflect.Method;
    3.12 -import java.security.AccessController;
    3.13 -import sun.security.action.GetPropertyAction;
    3.14 -import sun.awt.AWTAutoShutdown;
    3.15 -import sun.awt.SunToolkit;
    3.16 -import sun.awt.AppContext;
    3.17  
    3.18  import java.util.ArrayList;
    3.19 -import java.util.List;
    3.20 +import java.util.concurrent.BlockingQueue;
    3.21 +import java.util.concurrent.Executor;
    3.22 +import java.util.concurrent.LinkedBlockingQueue;
    3.23  import sun.util.logging.PlatformLogger;
    3.24  
    3.25  import sun.awt.dnd.SunDragSourceContextPeer;
    3.26 @@ -62,7 +58,7 @@
    3.27   *
    3.28   * @since 1.1
    3.29   */
    3.30 -class EventDispatchThread extends Thread {
    3.31 +final class EventDispatchThread {
    3.32  
    3.33      private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
    3.34  
    3.35 @@ -70,14 +66,51 @@
    3.36      private boolean doDispatch = true;
    3.37      private volatile boolean shutdown = false;
    3.38  
    3.39 -    private static final int ANY_EVENT = -1;
    3.40 +    static final int ANY_EVENT = -1;
    3.41  
    3.42 +    private final Executor executor;
    3.43      private ArrayList<EventFilter> eventFilters = new ArrayList<EventFilter>();
    3.44  
    3.45 -    EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
    3.46 -        super(group, name);
    3.47 +    EventDispatchThread(ThreadGroup group, String name, EventQueue queue, ClassLoader l) {
    3.48 +        // right now using simple executor that sort of mimics the old
    3.49 +        // behavior of the run() method of EventDispatchThread. But when
    3.50 +        // running together with FX, the executor should dispatch the runnable
    3.51 +        // using Platform.invokeLater to share the same processing thread
    3.52 +        executor = defaultThread(group, name, l);
    3.53          setEventQueue(queue);
    3.54      }
    3.55 +    
    3.56 +    private static Executor defaultThread(ThreadGroup group, String name, ClassLoader classLoader) {
    3.57 +        class ExecRuns implements Executor, Runnable {
    3.58 +            final BlockingQueue<Runnable> toRun = new LinkedBlockingQueue<>();
    3.59 +            @Override
    3.60 +            public void execute(Runnable command) {
    3.61 +                toRun.add(command);
    3.62 +            }
    3.63 +
    3.64 +            @Override
    3.65 +            public void run() {
    3.66 +                while (true) {
    3.67 +                    Runnable r;
    3.68 +                    try {
    3.69 +                        r = toRun.take();
    3.70 +                    } catch (InterruptedException ex) {
    3.71 +                        eventLog.severe(ex.getMessage(), ex);
    3.72 +                        continue;
    3.73 +                    }
    3.74 +                    r.run();
    3.75 +                }
    3.76 +            }
    3.77 +        }
    3.78 +        ExecRuns er = new ExecRuns();
    3.79 +        
    3.80 +        Thread t = new Thread(group, name);
    3.81 +        t.setContextClassLoader(classLoader);
    3.82 +        t.setPriority(Thread.NORM_PRIORITY + 1);
    3.83 +        t.setDaemon(false);
    3.84 +        t.start();
    3.85 +        return er;
    3.86 +    }
    3.87  
    3.88      /*
    3.89       * Must be called on EDT only, that's why no synchronization
    3.90 @@ -88,23 +121,29 @@
    3.91  
    3.92      public void interrupt() {
    3.93          shutdown = true;
    3.94 -        super.interrupt();
    3.95 +//XXX        super.interrupt();
    3.96      }
    3.97  
    3.98 -    public void run() {
    3.99 -        while (true) {
   3.100 -            try {
   3.101 -                pumpEvents(new Conditional() {
   3.102 -                    public boolean evaluate() {
   3.103 -                        return true;
   3.104 +    public void processEvents() {
   3.105 +        executor.execute(new Runnable() {
   3.106 +            @Override
   3.107 +            public void run() {
   3.108 +                try {
   3.109 +                    // XXX: the meaning now should be: the pumpEvents processes
   3.110 +                    // currently pending events, and then it returns without
   3.111 +                    // any blocking
   3.112 +                    pumpEvents(new Conditional() {
   3.113 +                        public boolean evaluate() {
   3.114 +                            return true;
   3.115 +                        }
   3.116 +                    });
   3.117 +                } finally {
   3.118 +                    if(getEventQueue().detachDispatchThread(this, shutdown)) {
   3.119 +                        return;
   3.120                      }
   3.121 -                });
   3.122 -            } finally {
   3.123 -                if(getEventQueue().detachDispatchThread(this, shutdown)) {
   3.124 -                    break;
   3.125                  }
   3.126              }
   3.127 -        }
   3.128 +        });
   3.129      }
   3.130  
   3.131      // MacOSX change:
   3.132 @@ -155,6 +194,11 @@
   3.133          pumpEventsForFilter(ANY_EVENT, cond, filter);
   3.134      }
   3.135  
   3.136 +    //XXX
   3.137 +    boolean isInterrupted() {
   3.138 +        return false;
   3.139 +    }
   3.140 +    
   3.141      void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
   3.142          addEventFilter(filter);
   3.143          doDispatch = true;
   3.144 @@ -195,6 +239,10 @@
   3.145              eventFilters.remove(filter);
   3.146          }
   3.147      }
   3.148 +    
   3.149 +    boolean blockWhenNoEvent() {
   3.150 +        return true;
   3.151 +    }
   3.152  
   3.153      void pumpOneEventForFilters(int id) {
   3.154          AWTEvent event = null;
   3.155 @@ -210,7 +258,10 @@
   3.156                  if (delegate != null && id == ANY_EVENT) {
   3.157                      event = delegate.getNextEvent(eq);
   3.158                  } else {
   3.159 -                    event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
   3.160 +                    event = eq.getNextEvent(id, blockWhenNoEvent());
   3.161 +                }
   3.162 +                if (event == null) {
   3.163 +                    return;
   3.164                  }
   3.165  
   3.166                  eventOK = true;
   3.167 @@ -263,7 +314,12 @@
   3.168          if (eventLog.isLoggable(PlatformLogger.FINE)) {
   3.169              eventLog.fine("Processing exception: " + e);
   3.170          }
   3.171 -        getUncaughtExceptionHandler().uncaughtException(this, e);
   3.172 +//XXX        getUncaughtExceptionHandler().uncaughtException(this, e);
   3.173 +    }
   3.174 +    
   3.175 +    public static EventDispatchThread findCurrent() {
   3.176 +//XXX        return (EventDispatchThread)Thread.currentThread();
   3.177 +        return null;
   3.178      }
   3.179  
   3.180      public synchronized EventQueue getEventQueue() {
     4.1 --- a/src/share/classes/java/awt/EventQueue.java	Thu Mar 29 13:02:24 2012 -0700
     4.2 +++ b/src/share/classes/java/awt/EventQueue.java	Wed May 23 11:51:09 2012 +0200
     4.3 @@ -299,9 +299,9 @@
     4.4                  if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
     4.5                      AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
     4.6                  }
     4.7 -                pushPopCond.signalAll();
     4.8 +                signalAll();
     4.9              } else if (notifyID) {
    4.10 -                pushPopCond.signalAll();
    4.11 +                signalAll();
    4.12              }
    4.13          } else {
    4.14              // The event was not coalesced or has non-Component source.
    4.15 @@ -309,7 +309,7 @@
    4.16              queues[priority].tail.next = newItem;
    4.17              queues[priority].tail = newItem;
    4.18              if (notifyID) {
    4.19 -                pushPopCond.signalAll();
    4.20 +                signalAll();
    4.21              }
    4.22          }
    4.23      }
    4.24 @@ -484,6 +484,31 @@
    4.25  
    4.26          return true;
    4.27      }
    4.28 +    
    4.29 +    final AWTEvent getNextEvent(int id, boolean block) throws InterruptedException {
    4.30 +        if (block) {
    4.31 +            return (id == EventDispatchThread.ANY_EVENT) ? getNextEvent() : getNextEvent(id);
    4.32 +        }
    4.33 +        try {
    4.34 +            pushPopLock.lock();
    4.35 +            if (id == EventDispatchThread.ANY_EVENT) {
    4.36 +                if (noEvents()) {
    4.37 +                    return null;
    4.38 +                }
    4.39 +                // XXX: calls SunToolkit.flushPendingEvents under lock now
    4.40 +                return getNextEvent();
    4.41 +            } else {
    4.42 +                AWTEvent peek = peekEvent(id);
    4.43 +                if (peek == null) {
    4.44 +                    return null;
    4.45 +                }
    4.46 +                // XXX: calls SunToolkit.flushPendingEvents under lock now
    4.47 +                return getNextEvent(id);
    4.48 +            }
    4.49 +        } finally {
    4.50 +            pushPopLock.unlock();
    4.51 +        }
    4.52 +    }
    4.53  
    4.54      /**
    4.55       * Removes an event from the <code>EventQueue</code> and
    4.56 @@ -853,7 +878,7 @@
    4.57                  appContext.put(AppContext.EVENT_QUEUE_KEY, newEventQueue);
    4.58              }
    4.59  
    4.60 -            pushPopCond.signalAll();
    4.61 +            signalAll();
    4.62          } finally {
    4.63              pushPopLock.unlock();
    4.64          }
    4.65 @@ -918,7 +943,7 @@
    4.66              // pick up a new EventQueue
    4.67              topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
    4.68  
    4.69 -            pushPopCond.signalAll();
    4.70 +            signalAll();
    4.71          } finally {
    4.72              pushPopLock.unlock();
    4.73          }
    4.74 @@ -1010,16 +1035,14 @@
    4.75                              EventDispatchThread t =
    4.76                                  new EventDispatchThread(threadGroup,
    4.77                                                          name,
    4.78 -                                                        EventQueue.this);
    4.79 -                            t.setContextClassLoader(classLoader);
    4.80 -                            t.setPriority(Thread.NORM_PRIORITY + 1);
    4.81 -                            t.setDaemon(false);
    4.82 +                                                        EventQueue.this,
    4.83 +                                                        classLoader
    4.84 +                                );
    4.85                              return t;
    4.86                          }
    4.87                      }
    4.88                  );
    4.89                  AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
    4.90 -                dispatchThread.start();
    4.91              }
    4.92          } finally {
    4.93              pushPopLock.unlock();
    4.94 @@ -1252,7 +1275,7 @@
    4.95                  // Forward call to the top of EventQueue stack.
    4.96                  nextQueue.wakeup(isShutdown);
    4.97              } else if (dispatchThread != null) {
    4.98 -                pushPopCond.signalAll();
    4.99 +                signalAll();
   4.100              } else if (!isShutdown) {
   4.101                  initDispatchThread();
   4.102              }
   4.103 @@ -1260,8 +1283,15 @@
   4.104              pushPopLock.unlock();
   4.105          }
   4.106      }
   4.107 +
   4.108 +    private void signalAll() {
   4.109 +        pushPopCond.signalAll();
   4.110 +        
   4.111 +        // new event delivered - requesting new processing
   4.112 +        // of pending events
   4.113 +        dispatchThread.processEvents();
   4.114 +    }
   4.115  }
   4.116 -
   4.117  /**
   4.118   * The Queue object holds pointers to the beginning and end of one internal
   4.119   * queue. An EventQueue object is composed of multiple internal Queues, one
     5.1 --- a/src/share/classes/java/awt/SequencedEvent.java	Thu Mar 29 13:02:24 2012 -0700
     5.2 +++ b/src/share/classes/java/awt/SequencedEvent.java	Wed May 23 11:51:09 2012 +0200
     5.3 @@ -90,8 +90,7 @@
     5.4  
     5.5              if (getFirst() != this) {
     5.6                  if (EventQueue.isDispatchThread()) {
     5.7 -                    EventDispatchThread edt = (EventDispatchThread)
     5.8 -                        Thread.currentThread();
     5.9 +                    EventDispatchThread edt = EventDispatchThread.findCurrent();
    5.10                      edt.pumpEvents(SentEvent.ID, new Conditional() {
    5.11                          public boolean evaluate() {
    5.12                              return !SequencedEvent.this.isFirstOrDisposed();