diff options
author | Michael Bien <[email protected]> | 2010-08-22 21:09:25 +0200 |
---|---|---|
committer | Michael Bien <[email protected]> | 2010-08-22 21:09:25 +0200 |
commit | d24cac77e8d7658b32b8bcb654e10a899de59433 (patch) | |
tree | 1ecee6a3bc12a2b71c3454ba4de0efc5e1385684 /src | |
parent | ddb53592e6633ed2b27519790ca15e07221942ff (diff) | |
parent | 8d55c437547a697b7d0bd4dd81b6669209cf912f (diff) |
Merge branch 'master' of github.com:sgothel/jogl
Diffstat (limited to 'src')
-rw-r--r-- | src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java | 2 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/Display.java | 61 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java | 65 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java | 7 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java | 228 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/EDTUtil.java | 202 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/util/MainThread.java | 235 | ||||
-rw-r--r-- | src/newt/native/KDWindow.c | 16 | ||||
-rw-r--r-- | src/newt/native/NewtMacWindow.m | 53 |
9 files changed, 509 insertions, 360 deletions
diff --git a/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java index 3e7228aba..ea31dfc02 100644 --- a/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java +++ b/src/junit/com/jogamp/test/junit/newt/TestGLWindows01NEWT.java @@ -110,7 +110,7 @@ public class TestGLWindows01NEWT { int wait=0; while(wait<10 && glWindow.getTotalFrames()<1) { Thread.sleep(100); wait++; } System.out.println("Frames for initial setVisible(true): "+glWindow.getTotalFrames()); - Assert.assertTrue(0<glWindow.getTotalFrames()); // native expose .. + // FIXME: Assert.assertTrue(0<glWindow.getTotalFrames()); // native expose .. // Assert.assertEquals(width,glWindow.getWidth()); // Assert.assertEquals(height,glWindow.getHeight()); // System.out.println("Created: "+glWindow); diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index deb4c7abe..a8ab8d520 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -39,10 +39,13 @@ import com.jogamp.newt.event.*; import com.jogamp.newt.impl.event.*; import com.jogamp.newt.impl.Debug; import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.util.MainThread; +import com.jogamp.newt.util.DefaultEDTUtil; import java.util.*; public abstract class Display { public static final boolean DEBUG = Debug.debug("Display"); + public static final boolean DEBUG_TEST_EDT_MAINTHREAD = Debug.debug("TestEDTMainThread"); // JAU EDT Test .. private static Class getDisplayClass(String type) throws ClassNotFoundException @@ -181,21 +184,35 @@ public abstract class Display { public boolean runCreateAndDestroyOnEDT() { return true; } + public EDTUtil getEDTUtil() { if( null == edtUtil ) { synchronized (this) { if( null == edtUtil ) { if(NewtFactory.useEDT()) { final Display f_dpy = this; - Thread current = Thread.currentThread(); - edtUtil = new EDTUtil(current.getThreadGroup(), - "Display_"+getFQName(), - new Runnable() { - public void run() { - if(null!=f_dpy.getGraphicsDevice()) { - f_dpy.dispatchMessages(); - } } } ); - edt = edtUtil.start(); + if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { + Thread current = Thread.currentThread(); + edtUtil = new DefaultEDTUtil(current.getThreadGroup(), + "Display_"+getFQName(), + new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } } ); + } else { + // Begin JAU EDT Test .. + MainThread.addPumpMessage(this, + new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } } ); + edtUtil = MainThread.getSingleton(); + System.err.println("Display.getEDTUtil("+getFQName()+") Test EDT MainThread: "+edtUtil.getClass().getName()); + // End JAU EDT Test .. + } + edtUtil.start(); } } } @@ -203,6 +220,16 @@ public abstract class Display { return edtUtil; } + protected void releaseEDTUtil() { + if(null!=edtUtil) { + if ( DEBUG_TEST_EDT_MAINTHREAD ) { + MainThread.removePumpMessage(this); // JAU EDT Test .. + } + edtUtil.waitUntilStopped(); + edtUtil=null; + } + } + public void runOnEDTIfAvail(boolean wait, final Runnable task) { EDTUtil _edtUtil = getEDTUtil(); if(runCreateAndDestroyOnEDT() && null!=_edtUtil) { @@ -223,21 +250,16 @@ public abstract class Display { System.err.println("Display.destroy("+getFQName()+") REMOVE: "+this+" "+getThreadName()); } final Display f_dpy = this; - final EDTUtil f_edt = edtUtil; + final EDTUtil f_edtUtil = edtUtil; runOnEDTIfAvail(true, new Runnable() { public void run() { f_dpy.closeNative(); - if(null!=f_edt) { - f_edt.stop(); + if(null!=f_edtUtil) { + f_edtUtil.stop(); } } } ); - - if(null!=edtUtil) { - edtUtil.waitUntilStopped(); - edtUtil=null; - edt=null; - } + releaseEDTUtil(); aDevice = null; } else { if(DEBUG) { @@ -316,7 +338,7 @@ public abstract class Display { private Object eventsLock = new Object(); private LinkedList/*<NEWTEvent>*/ events = new LinkedList(); - protected void dispatchMessages() { + public void dispatchMessages() { if(0==refCount) return; // in destruction .. LinkedList/*<NEWTEvent>*/ _events = null; @@ -383,7 +405,6 @@ public abstract class Display { } protected EDTUtil edtUtil = null; - protected Thread edt = null; protected String name; protected String type; protected int refCount; diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java index 699b675dd..11f825282 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java @@ -38,6 +38,7 @@ import javax.media.nativewindow.macosx.*; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.newt.*; import com.jogamp.newt.impl.*; +import com.jogamp.newt.util.EDTUtil; import com.jogamp.newt.util.MainThread; public class MacDisplay extends Display { @@ -60,15 +61,8 @@ public class MacDisplay extends Display { public MacDisplay() { } - class DispatchAction implements Runnable { - public void run() { - dispatchMessages0(); - } - } - private DispatchAction dispatchAction = new DispatchAction(); - protected void dispatchMessagesNative() { - runOnMainThread(false, dispatchAction); + dispatchMessages0(); } protected void createNative() { @@ -77,44 +71,33 @@ public class MacDisplay extends Display { protected void closeNative() { } - /*public boolean runCreateAndDestroyOnEDT() { - return false; - } public EDTUtil getEDTUtil() { - return null; - }*/ - - protected static void runOnMainThread(boolean wait, Runnable r) { - if (MainThread.isRunning()) { - MainThread.invoke(wait, r); - } else if(!runOnAWTEDT(wait, r)) { - throw new NativeWindowException("Neither MainThread is running nor AWT EDT available"); + if( null == edtUtil ) { + synchronized (this) { + if( null == edtUtil ) { + if(NewtFactory.useEDT()) { + final Display f_dpy = this; + MainThread.addPumpMessage(this, + new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } } ); + edtUtil = MainThread.getSingleton(); + edtUtil.start(); + } + } + } } + return edtUtil; } - protected static boolean runOnAWTEDT(boolean wait, Runnable r) { - ClassLoader cl = MacDisplay.class.getClassLoader(); - if(ReflectionUtil.isClassAvailable("java.awt.EventQueue", cl)) { - try { - if(wait) { - ReflectionUtil.callStaticMethod( - "java.awt.EventQueue", - "invokeAndWait", - new Class[] { java.lang.Runnable.class }, - new Object[] { r }, cl ); - } else { - ReflectionUtil.callStaticMethod( - "java.awt.EventQueue", - "invokeLater", - new Class[] { java.lang.Runnable.class }, - new Object[] { r }, cl ); - } - } catch (Exception e) { - throw new NativeWindowException(e); - } - return true; + protected void releaseEDTUtil() { + if(null!=edtUtil) { + MainThread.removePumpMessage(this); + edtUtil.waitUntilStopped(); + edtUtil=null; } - return false; } private static native boolean initNSApplication0(); diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java index 8f5041253..a8e6febf5 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java @@ -165,6 +165,7 @@ public class MacWindow extends Window { windowHandle = 0; nsViewLock.unlock(); } + windowDestroyed(); // No OSX hook for DidClose, so do it here } public long getWindowHandle() { @@ -406,8 +407,8 @@ public class MacWindow extends Window { } try { - MacDisplay.runOnMainThread(true, new Runnable() { - public void run() { + //runOnEDTIfAvail(true, new Runnable() { + // public void run() { if(0!=windowHandle) { // save the view .. close the window surfaceHandle = changeContentView0(parentWindowHandle, windowHandle, 0); @@ -433,7 +434,7 @@ public class MacWindow extends Window { setTitle0(windowHandle, getTitle()); // don't make the window visible on window creation // makeKeyAndOrderFront0(windowHandle); - } } ); + // } } ); } catch (Exception ie) { ie.printStackTrace(); } diff --git a/src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java new file mode 100644 index 000000000..87dfdb9d8 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/DefaultEDTUtil.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +package com.jogamp.newt.util; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.newt.Display; +import com.jogamp.newt.impl.Debug; +import java.util.*; + +public class DefaultEDTUtil implements EDTUtil { + public static final boolean DEBUG = Debug.debug("EDT"); + + private ThreadGroup threadGroup; + private volatile boolean shouldStop = false; + private EventDispatchThread edt = null; + private Object edtLock = new Object(); + private ArrayList tasks = new ArrayList(); // one shot tasks + private String name; + private Runnable pumpMessages; + + public DefaultEDTUtil(ThreadGroup tg, String name, Runnable pumpMessages) { + this.threadGroup = tg; + this.name=new String(Thread.currentThread().getName()+"-"+"EDT-"+name); + this.pumpMessages=pumpMessages; + } + + public void start() { + synchronized(edtLock) { + if(null==edt) { + edt = new EventDispatchThread(threadGroup, name); + } + if(!edt.isRunning()) { + shouldStop = false; + edt.start(); + } + edtLock.notifyAll(); + } + } + + public void stop() { + synchronized(edtLock) { + if(null!=edt && edt.isRunning()) { + shouldStop = true; + } + edtLock.notifyAll(); + if(DEBUG) { + System.out.println(Thread.currentThread()+": EDT signal STOP"); + } + } + } + + public boolean isCurrentThreadEDT() { + return null!=edt && edt == Thread.currentThread(); + } + + public boolean isRunning() { + return null!=edt && edt.isRunning() ; + } + + private void invokeLater(Runnable task) { + synchronized(edtLock) { + if(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { + tasks.add(task); + edtLock.notifyAll(); + } else { + // if !running or isEDTThread, do it right away + task.run(); + } + } + } + + public void invoke(boolean wait, Runnable task) { + if(task == null) { + return; + } + boolean doWait = wait && null!=edt && edt.isRunning() && edt != Thread.currentThread(); + Object lock = new Object(); + RunnableTask rTask = new RunnableTask(task, doWait?lock:null, true); + Throwable throwable = null; + synchronized(lock) { + invokeLater(rTask); + if( doWait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throwable = ie; + } + } + } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + + public void waitUntilIdle() { + synchronized(edtLock) { + if(null!=edt && edt.isRunning() && tasks.size()>0 && edt != Thread.currentThread() ) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public void waitUntilStopped() { + synchronized(edtLock) { + while(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + class EventDispatchThread extends Thread { + boolean isRunning = false; + + public EventDispatchThread(ThreadGroup tg, String name) { + super(tg, name); + } + + public synchronized boolean isRunning() { + return isRunning; + } + + public void start() throws IllegalThreadStateException { + synchronized(this) { + isRunning = true; + } + super.start(); + } + + /** + * Utilizing edtLock only for local resources and task execution, + * not for event dispatching. + */ + public void run() { + if(DEBUG) { + System.out.println(Thread.currentThread()+": EDT run() START"); + } + try { + while(!shouldStop) { + // wait for something todo + while(!shouldStop && tasks.size()==0) { + synchronized(edtLock) { + if(!shouldStop && tasks.size()==0) { + try { + edtLock.wait(defaultEDTPollGranularity); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + pumpMessages.run(); // event dispatch + } + if(!shouldStop && tasks.size()>0) { + synchronized(edtLock) { + if(!shouldStop && tasks.size()>0) { + Runnable task = (Runnable) tasks.remove(0); + task.run(); // FIXME: could be run outside of lock + edtLock.notifyAll(); + } + } + pumpMessages.run(); // event dispatch + } + } + } catch (Throwable t) { + // handle errors .. + shouldStop = true; + throw new RuntimeException(t); + } finally { + synchronized(this) { + isRunning = !shouldStop; + } + if(!isRunning) { + synchronized(edtLock) { + edtLock.notifyAll(); + } + } + if(DEBUG) { + System.out.println(Thread.currentThread()+": EDT run() EXIT"); + } + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java index 2e339fd45..1af102f43 100644 --- a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -38,208 +38,24 @@ package com.jogamp.newt.util; import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.Display; -import com.jogamp.newt.impl.Debug; import java.util.*; -public class EDTUtil { - public static final boolean DEBUG = Debug.debug("EDT"); +public interface EDTUtil { - private ThreadGroup threadGroup; - private volatile boolean shouldStop = false; - private EventDispatchThread edt = null; - private Object edtLock = new Object(); - private ArrayList tasks = new ArrayList(); // one shot tasks - private String name; - private Runnable pumpMessages; - private long edtPollGranularity = 10; // 10ms, 1/100s + public static final long defaultEDTPollGranularity = 10; // 10ms, 1/100s - public EDTUtil(ThreadGroup tg, String name, Runnable pumpMessages) { - this.threadGroup = tg; - this.name=new String(Thread.currentThread().getName()+"-"+"EDT-"+name); - this.pumpMessages=pumpMessages; - } + public void start(); - public String getName() { return name; } + public void stop(); - public ThreadGroup getThreadGroup() { return threadGroup; } + public boolean isCurrentThreadEDT(); - /** - * @return The started Runnable, which handles the run-loop. - */ - public Thread start() { - synchronized(edtLock) { - if(null==edt) { - edt = new EventDispatchThread(threadGroup, name); - } - if(!edt.isRunning()) { - shouldStop = false; - edt.start(); - } - edtLock.notifyAll(); - } - return edt; - } + public boolean isRunning(); - public void stop() { - synchronized(edtLock) { - if(null!=edt && edt.isRunning()) { - shouldStop = true; - } - edtLock.notifyAll(); - if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT signal STOP"); - } - } - } + public void invoke(boolean wait, Runnable task); - public Thread getEDT() { - return edt; - } + public void waitUntilIdle(); - public boolean isThreadEDT(Thread thread) { - return null!=edt && edt == thread; - } - - public boolean isCurrentThreadEDT() { - return null!=edt && edt == Thread.currentThread(); - } - - public boolean isRunning() { - return null!=edt && edt.isRunning() ; - } - - private void invokeLater(Runnable task) { - synchronized(edtLock) { - if(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { - tasks.add(task); - edtLock.notifyAll(); - } else { - // if !running or isEDTThread, do it right away - task.run(); - } - } - } - - public void invoke(boolean wait, Runnable task) { - if(task == null) { - return; - } - boolean doWait = wait && null!=edt && edt.isRunning() && edt != Thread.currentThread(); - Object lock = new Object(); - RunnableTask rTask = new RunnableTask(task, doWait?lock:null, true); - Throwable throwable = null; - synchronized(lock) { - invokeLater(rTask); - if( doWait ) { - try { - lock.wait(); - } catch (InterruptedException ie) { - throwable = ie; - } - } - } - if(null==throwable) { - throwable = rTask.getThrowable(); - } - if(null!=throwable) { - throw new RuntimeException(throwable); - } - } - - public void waitUntilIdle() { - synchronized(edtLock) { - if(null!=edt && edt.isRunning() && tasks.size()>0 && edt != Thread.currentThread() ) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - public void waitUntilStopped() { - synchronized(edtLock) { - while(null!=edt && edt.isRunning() && edt != Thread.currentThread() ) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - class EventDispatchThread extends Thread { - boolean isRunning = false; - - public EventDispatchThread(ThreadGroup tg, String name) { - super(tg, name); - } - - public synchronized boolean isRunning() { - return isRunning; - } - - public void start() throws IllegalThreadStateException { - synchronized(this) { - isRunning = true; - } - super.start(); - } - - /** - * Utilizing edtLock only for local resources and task execution, - * not for event dispatching. - */ - public void run() { - if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT run() START"); - } - try { - while(!shouldStop) { - // wait for something todo - while(!shouldStop && tasks.size()==0) { - synchronized(edtLock) { - if(!shouldStop && tasks.size()==0) { - try { - edtLock.wait(edtPollGranularity); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - pumpMessages.run(); // event dispatch - } - if(!shouldStop && tasks.size()>0) { - synchronized(edtLock) { - if(!shouldStop && tasks.size()>0) { - Runnable task = (Runnable) tasks.remove(0); - task.run(); - edtLock.notifyAll(); - } - } - pumpMessages.run(); // event dispatch - } - } - } catch (Throwable t) { - // handle errors .. - shouldStop = true; - throw new RuntimeException(t); - } finally { - synchronized(this) { - isRunning = !shouldStop; - } - if(!isRunning) { - synchronized(edtLock) { - edtLock.notifyAll(); - } - } - if(DEBUG) { - System.out.println(Thread.currentThread()+": EDT run() EXIT"); - } - } - } - } + public void waitUntilStopped(); } diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index cbd520104..ba886ade8 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -46,7 +46,6 @@ import javax.media.nativewindow.*; import com.jogamp.common.util.*; import com.jogamp.newt.*; import com.jogamp.newt.impl.*; -import com.jogamp.newt.impl.macosx.MacDisplay; /** * NEWT Utility class MainThread<P> @@ -81,21 +80,33 @@ import com.jogamp.newt.impl.macosx.MacDisplay; </PRE> * Which starts 4 threads, each with a window and OpenGL rendering.<br> */ -public class MainThread { +public class MainThread implements EDTUtil { private static AccessControlContext localACC = AccessController.getContext(); - public static final boolean USE_MAIN_THREAD = NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false)) || - Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + public static final boolean MAIN_THREAD_CRITERIA = ( !NativeWindowFactory.isAWTAvailable() && + NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false)) + ) || Debug.getBooleanProperty("newt.MainThread.force", true, localACC); protected static final boolean DEBUG = Debug.debug("MainThread"); + private static MainThread singletonMainThread = new MainThread(); // one singleton MainThread + private static boolean isExit=false; private static volatile boolean isRunning=false; private static Object taskWorkerLock=new Object(); private static boolean shouldStop; private static ArrayList tasks; - private static ArrayList tasksBlock; private static Thread mainThread; + private static Timer pumpMessagesTimer=null; + private static TimerTask pumpMessagesTimerTask=null; + private static Map/*<Display, Runnable>*/ pumpMessageDisplayMap = new HashMap(); + + private static boolean useMainThread = false; + private static Class cAWTEventQueue=null; + private static Method mAWTInvokeAndWait=null; + private static Method mAWTInvokeLater=null; + private static Method mAWTIsDispatchThread=null; + static class MainAction extends Thread { private String mainClassName; private String[] mainClassArgs; @@ -109,9 +120,9 @@ public class MainThread { } public void run() { - if ( USE_MAIN_THREAD ) { + if ( useMainThread ) { // we have to start first to provide the service .. - MainThread.waitUntilRunning(); + singletonMainThread.waitUntilRunning(); } // start user app .. @@ -136,9 +147,9 @@ public class MainThread { if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin"); - if ( USE_MAIN_THREAD ) { - MainThread.exit(); - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - exit"); + if ( useMainThread ) { + singletonMainThread.stop(); + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - stop"); System.exit(0); } } @@ -147,7 +158,9 @@ public class MainThread { /** Your new java application main entry, which pipelines your application */ public static void main(String[] args) { - if(DEBUG) System.err.println("MainThread.main(): "+Thread.currentThread().getName()+" USE_MAIN_THREAD "+ USE_MAIN_THREAD ); + useMainThread = MAIN_THREAD_CRITERIA; + + if(DEBUG) System.err.println("MainThread.main(): "+Thread.currentThread().getName()+" useMainThread "+ useMainThread ); if(args.length==0) { return; @@ -161,35 +174,145 @@ public class MainThread { NEWTJNILibLoader.loadNEWT(); - shouldStop = false; - tasks = new ArrayList(); - tasksBlock = new ArrayList(); - mainThread = Thread.currentThread(); - mainAction = new MainAction(mainClassName, mainClassArgs); if(NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false))) { - MacDisplay.initSingleton(); + ReflectionUtil.callStaticMethod("com.jogamp.newt.impl.macosx.MacDisplay", "initSingleton", + null, null, MainThread.class.getClassLoader()); } - if ( USE_MAIN_THREAD ) { + if ( useMainThread ) { + shouldStop = false; + tasks = new ArrayList(); + mainThread = Thread.currentThread(); + // dispatch user's main thread .. mainAction.start(); // do our main thread task scheduling - run(); + singletonMainThread.run(); } else { // run user's main in this thread mainAction.run(); } } + public static final MainThread getSingleton() { + return singletonMainThread; + } + + public static Runnable removePumpMessage(Display dpy) { + synchronized(pumpMessageDisplayMap) { + return (Runnable) pumpMessageDisplayMap.remove(dpy); + } + } + + public static void addPumpMessage(Display dpy, Runnable pumpMessage) { + if ( useMainThread ) { + return; // error ? + } + if(null == pumpMessagesTimer) { + synchronized (MainThread.class) { + if(null == pumpMessagesTimer) { + pumpMessagesTimer = new Timer(); + pumpMessagesTimerTask = new TimerTask() { + public void run() { + synchronized(pumpMessageDisplayMap) { + for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { + ((Runnable) i.next()).run(); + } + } + } + }; + pumpMessagesTimer.scheduleAtFixedRate(pumpMessagesTimerTask, 0, defaultEDTPollGranularity); + } + } + } + synchronized(pumpMessageDisplayMap) { + pumpMessageDisplayMap.put(dpy, pumpMessage); + } + } + + private void initAWTReflection() { + if(null == cAWTEventQueue) { + ClassLoader cl = MainThread.class.getClassLoader(); + cAWTEventQueue = ReflectionUtil.getClass("java.awt.EventQueue", true, cl); + mAWTInvokeAndWait = ReflectionUtil.getMethod(cAWTEventQueue, "invokeAndWait", new Class[] { java.lang.Runnable.class }, cl); + mAWTInvokeLater = ReflectionUtil.getMethod(cAWTEventQueue, "invokeLater", new Class[] { java.lang.Runnable.class }, cl); + mAWTIsDispatchThread = ReflectionUtil.getMethod(cAWTEventQueue, "isDispatchThread", new Class[] { }, cl); + } + } + + public void start() { + // nop + } + + public void stop() { + if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" start"); + synchronized(taskWorkerLock) { + if(isRunning) { + shouldStop = true; + } + taskWorkerLock.notifyAll(); + } + if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" end"); + } + + public boolean isCurrentThreadEDT() { + if(NativeWindowFactory.isAWTAvailable()) { + initAWTReflection(); + return ((Boolean) ReflectionUtil.callMethod(null, mAWTIsDispatchThread, null) ).booleanValue(); + } + return isRunning() && mainThread == Thread.currentThread() ; + } + + public boolean isRunning() { + if( useMainThread ) { + synchronized(taskWorkerLock) { + return isRunning; + } + } + return true; // AWT is always running + } + + private void invokeLater(Runnable task) { + synchronized(taskWorkerLock) { + if(isRunning() && mainThread != Thread.currentThread()) { + tasks.add(task); + taskWorkerLock.notifyAll(); + } else { + // if !running or isEDTThread, do it right away + task.run(); + } + } + } + /** invokes the given Runnable */ - public static void invoke(boolean wait, Runnable r) { + public void invoke(boolean wait, Runnable r) { if(r == null) { return; } + if(NativeWindowFactory.isAWTAvailable()) { + initAWTReflection(); + + // handover to AWT MainThread .. + try { + if ( ((Boolean) ReflectionUtil.callMethod(null, mAWTIsDispatchThread, null) ).booleanValue() ) { + r.run(); + return; + } + if(wait) { + ReflectionUtil.callMethod(null, mAWTInvokeAndWait, new Object[] { r }); + } else { + ReflectionUtil.callMethod(null, mAWTInvokeLater, new Object[] { r }); + } + } catch (Exception e) { + throw new NativeWindowException(e); + } + return; + } + // if this main thread is not being used or // if this is already the main thread .. just execute. if( !isRunning() || mainThread == Thread.currentThread() ) { @@ -197,42 +320,35 @@ public class MainThread { return; } - synchronized(taskWorkerLock) { - tasks.add(r); - if(wait) { - tasksBlock.add(r); - } - taskWorkerLock.notifyAll(); - if(wait) { - while(tasksBlock.size()>0) { - try { - taskWorkerLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } + boolean doWait = wait && isRunning() && mainThread != Thread.currentThread(); + Object lock = new Object(); + RunnableTask rTask = new RunnableTask(r, doWait?lock:null, true); + Throwable throwable = null; + synchronized(lock) { + invokeLater(rTask); + if( doWait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throwable = ie; } } } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } } - public static void exit() { - if(DEBUG) System.err.println("MainThread.exit(): "+Thread.currentThread().getName()+" start"); - synchronized(taskWorkerLock) { - if(isRunning) { - shouldStop = true; - } - taskWorkerLock.notifyAll(); - } - if(DEBUG) System.err.println("MainThread.exit(): "+Thread.currentThread().getName()+" end"); + public void waitUntilIdle() { } - public static boolean isRunning() { - synchronized(taskWorkerLock) { - return isRunning; - } + public void waitUntilStopped() { } - private static void waitUntilRunning() { + private void waitUntilRunning() { synchronized(taskWorkerLock) { if(isExit) return; @@ -246,7 +362,7 @@ public class MainThread { } } - public static void run() { + public void run() { if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()); synchronized(taskWorkerLock) { isRunning = true; @@ -254,8 +370,6 @@ public class MainThread { } while(!shouldStop) { try { - ArrayList localTasks=null; - // wait for something todo .. synchronized(taskWorkerLock) { while(!shouldStop && tasks.size()==0) { @@ -265,29 +379,14 @@ public class MainThread { e.printStackTrace(); } } - // seq. process all tasks until no blocking one exists in the list - for(Iterator i = tasks.iterator(); tasksBlock.size()>0 && i.hasNext(); ) { - Runnable task = (Runnable) i.next(); - task.run(); - i.remove(); - tasksBlock.remove(task); - } // take over the tasks .. - if(tasks.size()>0) { - localTasks = tasks; - tasks = new ArrayList(); + if(!shouldStop && tasks.size()>0) { + Runnable task = (Runnable) tasks.remove(0); + task.run(); // FIXME: could be run outside of lock } taskWorkerLock.notifyAll(); } - - // seq. process all unblocking tasks .. - if(null!=localTasks) { - for(Iterator i = localTasks.iterator(); i.hasNext(); ) { - Runnable task = (Runnable) i.next(); - task.run(); - } - } } catch (Throwable t) { // handle errors .. t.printStackTrace(); diff --git a/src/newt/native/KDWindow.c b/src/newt/native/KDWindow.c index 82f2ba7df..b67b8dbd3 100644 --- a/src/newt/native/KDWindow.c +++ b/src/newt/native/KDWindow.c @@ -96,8 +96,8 @@ static jmethodID windowCreatedID = NULL; static jmethodID sizeChangedID = NULL; static jmethodID windowDestroyNotifyID = NULL; static jmethodID windowDestroyedID = NULL; -static jmethodID enqueueMouseEventID = NULL; -static jmethodID enqueueKeyEventID = NULL; +static jmethodID sendMouseEventID = NULL; +static jmethodID sendKeyEventID = NULL; /** * Display @@ -180,13 +180,13 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_opengl_kd_KDDisplay_DispatchMes // time = ev->timestamp if(KD_INPUT_POINTER_SELECT==ptr->index) { DBG_PRINT( "event mouse click: src: %p, s:%d, (%d,%d)\n", userData, ptr->select, ptr->x, ptr->y); - (*env)->CallVoidMethod(env, javaWindow, enqueueMouseEventID, + (*env)->CallVoidMethod(env, javaWindow, sendMouseEventID, (ptr->select==0) ? (jint) EVENT_MOUSE_RELEASED : (jint) EVENT_MOUSE_PRESSED, (jint) 0, (jint) ptr->x, (jint) ptr->y, 1, 0); } else { DBG_PRINT( "event mouse: src: %d, s:%p, i:0x%X (%d,%d)\n", userData, ptr->select, ptr->index, ptr->x, ptr->y); - (*env)->CallVoidMethod(env, javaWindow, enqueueMouseEventID, (jint) EVENT_MOUSE_MOVED, + (*env)->CallVoidMethod(env, javaWindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, 0, (jint) ptr->x, (jint) ptr->y, 0, 0); } @@ -213,14 +213,14 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_opengl_kd_KDWindow_initIDs sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(II)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowDestroyedID = (*env)->GetMethodID(env, clazz, "windowDestroyed", "()V"); - enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(IIIC)V"); + sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); + sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); if (windowCreatedID == NULL || sizeChangedID == NULL || windowDestroyNotifyID == NULL || windowDestroyedID == NULL || - enqueueMouseEventID == NULL || - enqueueKeyEventID == NULL) { + sendMouseEventID == NULL || + sendKeyEventID == NULL) { DBG_PRINT( "initIDs failed\n" ); return JNI_FALSE; } diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index ae658b908..da31a686e 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -109,8 +109,8 @@ jint GetDeltaY(NSEvent *event, jint javaMods) { @end -static jmethodID enqueueMouseEventID = NULL; -static jmethodID enqueueKeyEventID = NULL; +static jmethodID sendMouseEventID = NULL; +static jmethodID sendKeyEventID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; static jmethodID positionChangedID = NULL; @@ -122,15 +122,15 @@ static jmethodID windowDestroyedID = NULL; + (BOOL) initNatives: (JNIEnv*) env forClass: (jclass) clazz { - enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(IIIC)V"); + sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); + sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(II)V"); insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(IIII)V"); positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(II)V"); focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(Z)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowDestroyedID = (*env)->GetMethodID(env, clazz, "windowDestroyed", "()V"); - if (enqueueMouseEventID && enqueueKeyEventID && sizeChangedID && insetsChangedID && + if (sendMouseEventID && sendKeyEventID && sizeChangedID && insetsChangedID && positionChangedID && focusChangedID && windowDestroyedID && windowDestroyNotifyID) { return YES; @@ -206,7 +206,7 @@ static jint mods2JavaMods(NSUInteger mods) return javaMods; } -- (void) enqueueKeyEvent: (NSEvent*) event eventType: (jint) evType +- (void) sendKeyEvent: (NSEvent*) event eventType: (jint) evType { NSView* nsview = [self contentView]; if( ! [nsview isMemberOfClass:[NewtView class]] ) { @@ -229,23 +229,23 @@ static jint mods2JavaMods(NSUInteger mods) // Note: the key code in the NSEvent does not map to anything we can use jchar keyChar = (jchar) [chars characterAtIndex: i]; - (*env)->CallVoidMethod(env, javaWindowObject, enqueueKeyEventID, + (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID, evType, javaMods, keyCode, keyChar); } } - (void) keyDown: (NSEvent*) theEvent { - [self enqueueKeyEvent: theEvent eventType: EVENT_KEY_PRESSED]; + [self sendKeyEvent: theEvent eventType: EVENT_KEY_PRESSED]; } - (void) keyUp: (NSEvent*) theEvent { - [self enqueueKeyEvent: theEvent eventType: EVENT_KEY_RELEASED]; - [self enqueueKeyEvent: theEvent eventType: EVENT_KEY_TYPED]; + [self sendKeyEvent: theEvent eventType: EVENT_KEY_RELEASED]; + [self sendKeyEvent: theEvent eventType: EVENT_KEY_TYPED]; } -- (void) enqueueMouseEvent: (NSEvent*) event eventType: (jint) evType +- (void) sendMouseEvent: (NSEvent*) event eventType: (jint) evType { NSView* nsview = [self contentView]; if( ! [nsview isMemberOfClass:[NewtView class]] ) { @@ -302,7 +302,7 @@ static jint mods2JavaMods(NSUInteger mods) // ignore 0 increment wheel scroll events return; } - (*env)->CallVoidMethod(env, javaWindowObject, enqueueMouseEventID, + (*env)->CallVoidMethod(env, javaWindowObject, sendMouseEventID, evType, javaMods, (jint) location.x, (jint) (contentRect.size.height - location.y), @@ -311,70 +311,70 @@ static jint mods2JavaMods(NSUInteger mods) - (void) mouseEntered: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_ENTERED]; } - (void) mouseExited: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_EXITED]; } - (void) mouseMoved: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; } - (void) scrollWheel: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_WHEEL_MOVED]; } - (void) mouseDown: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; } - (void) mouseDragged: (NSEvent*) theEvent { // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; } - (void) mouseUp: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; } - (void) rightMouseDown: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; } - (void) rightMouseDragged: (NSEvent*) theEvent { // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; } - (void) rightMouseUp: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; } - (void) otherMouseDown: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_PRESSED]; } - (void) otherMouseDragged: (NSEvent*) theEvent { // Note use of MOUSE_MOVED event type because mouse dragged events are synthesized by Java - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_MOVED]; } - (void) otherMouseUp: (NSEvent*) theEvent { - [self enqueueMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; + [self sendMouseEvent: theEvent eventType: EVENT_MOUSE_RELEASED]; } - (void)windowDidResize: (NSNotification*) notification @@ -442,7 +442,8 @@ static jint mods2JavaMods(NSUInteger mods) } (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyNotifyID); - (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyedID); // No OSX hook for DidClose, so do it here + // Can't issue call here - locked window state, done from Java method + // (*env)->CallVoidMethod(env, javaWindowObject, windowDestroyedID); // No OSX hook for DidClose, so do it here // EOL .. (*env)->DeleteGlobalRef(env, javaWindowObject); |