diff options
Diffstat (limited to 'src')
299 files changed, 12862 insertions, 5377 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index d162f2bd8..8cb25174c 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -70,7 +70,7 @@ public class JoglVersion extends JogampVersion { public static StringBuilder getGLInfo(GL gl, StringBuilder sb) { AbstractGraphicsDevice device = gl.getContext().getGLDrawable().getNativeSurface() - .getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + .getGraphicsConfiguration().getScreen().getDevice(); if(null==sb) { sb = new StringBuilder(); } diff --git a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java index 9e4d76869..ba159b82c 100644 --- a/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/com/jogamp/opengl/cg/CgDynamicLibraryBundleInfo.java @@ -28,12 +28,30 @@ package com.jogamp.opengl.cg; +import com.jogamp.common.jvm.JNILibLoaderBase; import com.jogamp.common.os.DynamicLibraryBundleInfo; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.cache.TempJarCache; + +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.*; public class CgDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { private static List<String> glueLibNames; static { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + Platform.initSingleton(); + + if(TempJarCache.isInitialized()) { + // Cg class and natives are available in their single atomic JAR files only + JNILibLoaderBase.addNativeJarLibs(CgDynamicLibraryBundleInfo.class, "jogl_cg", null); + } + return null; + } + }); + glueLibNames = new ArrayList<String>(); // glueLibNames.addAll(getGlueLibNamesPreload()); glueLibNames.add("jogl_cg"); diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java index 93b75e70b..26d299663 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java @@ -164,7 +164,7 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { } }; - public boolean skipWaitForCompletion(Thread thread) { - return ((Thread.currentThread() == thread) || EventQueue.isDispatchThread()); + public boolean blockUntilDone(Thread thread) { + return ((Thread.currentThread() != thread) && !EventQueue.isDispatchThread()); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 16aac957a..6d508f227 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -59,7 +59,9 @@ import javax.media.opengl.GLAutoDrawable; */ public class Animator extends AnimatorBase { - + /** timeout in milliseconds, 15 frames @ 60Hz = 240ms, limiting {@link #finishLifecycleAction(Condition)} */ + private static final long TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION = 15*16; + protected ThreadGroup threadGroup; private Runnable runnable; private boolean runAsFastAsPossible; @@ -241,18 +243,24 @@ public class Animator extends AnimatorBase { // dependencies on the Animator's internal thread. Currently we // use a couple of heuristics to determine whether we should do // the blocking wait(). - boolean doWait = !impl.skipWaitForCompletion(animThread); - if (doWait) { - while (condition.result()) { - try { - wait(); - } catch (InterruptedException ie) { } - } + final boolean blocking = impl.blockUntilDone(animThread); + long remaining = blocking ? TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION : 0; + while (remaining>0 && condition.result()) { + long td = System.currentTimeMillis(); + try { + wait(remaining); + } catch (InterruptedException ie) { } + remaining -= (System.currentTimeMillis() - td) ; } if(DEBUG) { - System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished - waited " + doWait + + if(remaining<0) { + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): ++++++ timeout reached ++++++ " + Thread.currentThread().getName()); + } + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished "+ + "- blocking "+blocking+ + ", waited " + (blocking ? ( TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION - remaining ) : 0 ) + "/" + TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION + ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() + - ", paused: " + isPausedImpl() + ", drawables " + drawables.size()); + ", paused: " + isPausedImpl() + ", drawables " + drawables.size() + " - " + Thread.currentThread().getName()); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index e84a9bf78..d65967da1 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -56,7 +56,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { public interface AnimatorImpl { void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions); - boolean skipWaitForCompletion(Thread thread); + boolean blockUntilDone(Thread thread); } protected ArrayList<GLAutoDrawable> drawables = new ArrayList<GLAutoDrawable>(); @@ -92,7 +92,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { public synchronized void add(GLAutoDrawable drawable) { if(DEBUG) { - System.err.println("Animator add: "+drawable.hashCode()+" - "+Thread.currentThread()); + System.err.println("Animator add: "+drawable.hashCode()+" - "+Thread.currentThread().getName()); } boolean paused = pause(); drawables.add(drawable); @@ -101,7 +101,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && !isPaused() && !isAnimating()) { try { wait(); @@ -113,7 +113,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { public synchronized void remove(GLAutoDrawable drawable) { if(DEBUG) { - System.err.println("Animator remove: "+drawable.hashCode()+" - "+Thread.currentThread() + ": "+toString()); + System.err.println("Animator remove: "+drawable.hashCode()+" - "+Thread.currentThread().getName() + ": "+toString()); } boolean paused = pause(); @@ -123,7 +123,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && drawablesEmpty && isAnimating()) { try { wait(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java index bad268f70..23b0845ee 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java @@ -60,7 +60,7 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl { } } - public boolean skipWaitForCompletion(Thread thread) { - return (Thread.currentThread() == thread); + public boolean blockUntilDone(Thread thread) { + return (Thread.currentThread() != thread); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java index f2e742cda..4ab603576 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java @@ -49,9 +49,8 @@ import java.nio.*; /** * Utility routines for dealing with direct buffers. - * @author Kenneth Russel - * @author Sven Gothel - * @author Michael Bien + * + * @author Kenneth Russel, et.al. */ public class GLBuffers extends Buffers { @@ -66,7 +65,8 @@ public class GLBuffers extends Buffers { * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, - * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + * GL_HILO16_NV, GL_SIGNED_HILO16_NV (27) * @return -1 if glType is unhandled, otherwise the actual value > 0 */ public static final int sizeOfGLType(int glType) { @@ -97,6 +97,8 @@ public class GLBuffers extends Buffers { case GL2GL3.GL_UNSIGNED_INT_24_8: case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: + case GL2.GL_HILO16_NV: + case GL2.GL_SIGNED_HILO16_NV: return SIZEOF_INT; case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: @@ -122,7 +124,8 @@ public class GLBuffers extends Buffers { * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, - * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + * GL_HILO16_NV, GL_SIGNED_HILO16_NV (27) * @return null if glType is unhandled, otherwise the new Buffer object */ public static final Buffer newDirectGLBuffer(int glType, int numElements) { @@ -153,6 +156,8 @@ public class GLBuffers extends Buffers { case GL2GL3.GL_UNSIGNED_INT_24_8: case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: + case GL2.GL_HILO16_NV: + case GL2.GL_SIGNED_HILO16_NV: return newDirectIntBuffer(numElements); case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: @@ -178,7 +183,8 @@ public class GLBuffers extends Buffers { * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, - * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + * GL_HILO16_NV, GL_SIGNED_HILO16_NV (27) * @return null if glType is unhandled or parent is null or bufLen is 0, otherwise the new Buffer object */ public static final Buffer sliceGLBuffer(ByteBuffer parent, int bytePos, int byteLen, int glType) { @@ -215,6 +221,8 @@ public class GLBuffers extends Buffers { case GL2GL3.GL_UNSIGNED_INT_24_8: case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: + case GL2.GL_HILO16_NV: + case GL2.GL_SIGNED_HILO16_NV: return parent.asIntBuffer(); case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: @@ -360,7 +368,7 @@ public class GLBuffers extends Buffers { * GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_ABGR_EXT, * GL_RED_INTEGER, GL_GREEN_INTEGER, GL_BLUE_INTEGER, * GL_RG_INTEGER, GL_RGB_INTEGER, GL_BGR_INTEGER, - * GL_RGBA_INTEGER, GL_BGRA_INTEGER (24) + * GL_RGBA_INTEGER, GL_BGRA_INTEGER, GL_HILO_NV, GL_SIGNED_HILO_NV (26) * * @param type must be one of * GL_BITMAP, @@ -373,7 +381,8 @@ public class GLBuffers extends Buffers { * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, - * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (26) + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + * GL_HILO16_NV, GL_SIGNED_HILO16_NV (28) * * @param width in pixels * @param height in pixels @@ -410,6 +419,8 @@ public class GLBuffers extends Buffers { case GL.GL_LUMINANCE_ALPHA: case GL2GL3.GL_RG: case GL2GL3.GL_RG_INTEGER: + case GL2.GL_HILO_NV: + case GL2.GL_SIGNED_HILO_NV: elements = 2; break; case GL.GL_RGB: @@ -470,6 +481,11 @@ public class GLBuffers extends Buffers { esize = 2; elements = 1; break; + case GL2.GL_HILO16_NV: + case GL2.GL_SIGNED_HILO16_NV: + esize = 2; + elements = 2; + break; case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: case GL2GL3.GL_UNSIGNED_INT_10_10_10_2: @@ -491,6 +507,19 @@ public class GLBuffers extends Buffers { return sizeof(gl, tmp, elements * esize, width, height, depth, pack); } + + public static final int getNextPowerOf2(int number) { + if (((number-1) & number) == 0) { + //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 + return number; + } + int power = 0; + while (number > 0) { + number = number>>1; + power++; + } + return (1<<power); + } //---------------------------------------------------------------------- // Conversion routines diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java index b6df365ba..7f3aa8a39 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java @@ -1055,9 +1055,7 @@ public class Texture { // Helper routines for disabling certain codepaths private static boolean haveNPOT(GL gl) { - return (!disableNPOT && - ( gl.isGLES2() || - gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two") ) ); + return !disableNPOT && gl.isNPOTTextureAvailable(); } private static boolean haveTexRect(GL gl) { diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index f93d443e0..534e449bc 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -294,6 +294,17 @@ public interface GLBase { */ public boolean isExtensionAvailable(String glExtensionName); + /** + * Returns true if the GL context supports non power of two (NPOT) textures, + * otherwise false. + * <p> + * NPOT textures are supported in OpenGL >= 3, GLES2 or if the + * 'GL_ARB_texture_non_power_of_two' extension is available. + * </p> + * @return + */ + public boolean isNPOTTextureAvailable(); + /** Provides a platform-independent way to specify the minimum swap interval for buffer swaps. An argument of 0 disables sync-to-vertical-refresh completely, while an argument of 1 diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 9d99a32ff..8626400f7 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -45,9 +45,12 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.util.HashMap; import java.util.HashSet; + import javax.media.nativewindow.AbstractGraphicsDevice; import com.jogamp.common.util.IntObjectHashMap; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; @@ -65,7 +68,8 @@ import jogamp.opengl.GLContextImpl; abstraction provides a stable object which clients can use to refer to a given context. */ public abstract class GLContext { - + public static final boolean DEBUG = Debug.debug("GLContext"); + /** Reflects property jogl.debug.DebugGL. If true, the debug pipeline is enabled at context creation. */ public final static boolean DEBUG_GL; /** Reflects property jogl.debug.TraceGL. If true, the trace pipeline is enabled at context creation. */ @@ -105,12 +109,15 @@ public abstract class GLContext { protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 0; /** GLContext {@link com.jogamp.gluegen.runtime.ProcAddressTable} caching related: GL hardware implementation */ protected static final int CTX_IMPL_ACCEL_HARD = 1 << 1; - + private static ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>(); private HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>(); private IntObjectHashMap attachedObjectsByInt = new IntObjectHashMap(); + // RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock. + protected RecursiveLock lock = LockFactory.createRecursiveLock(); + /** The underlying native OpenGL context */ protected long contextHandle; @@ -293,8 +300,11 @@ public abstract class GLContext { /** * Destroys this OpenGL context and frees its associated - * resources. The context should have been released before this - * method is called. + * resources. + * <p> + * The context may be current w/o recursion when calling <code>destroy()</code>, + * in which case this method destroys the context and releases the lock. + * </p> */ public abstract void destroy(); @@ -406,6 +416,8 @@ public abstract class GLContext { sb.append(",\n\tDrawable: "); sb.append(getGLDrawable()); } + sb.append(", lock "); + sb.append(lock.toString()); return sb; } @@ -767,12 +779,12 @@ public abstract class GLContext { /** * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) */ - protected static /*final*/ HashMap/*<DeviceVersionAvailableKey, Integer>*/ deviceVersionAvailable = new HashMap(); + protected static /*final*/ HashMap<String, Integer> deviceVersionAvailable = new HashMap<String, Integer>(); /** * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) */ - private static /*final*/ HashSet/*<UniqueDeviceString>*/ deviceVersionsAvailableSet = new HashSet(); + private static /*final*/ HashSet<String> deviceVersionsAvailableSet = new HashSet<String>(); protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { return device.getUniqueID() + "-" + toHexString(compose8bit(major, profile, 0, 0)); @@ -791,16 +803,18 @@ public abstract class GLContext { throw new InternalError("Already set: "+devKey); } deviceVersionsAvailableSet.add(devKey); - if (GLContextImpl.DEBUG) { + if (DEBUG) { System.err.println(getThreadName() + ": !!! createContextARB: SET mappedVersionsAvailableSet "+devKey); // Thread.dumpStack(); } } } + /** clears the device/context mappings as well as the GL/GLX proc address tables. */ protected static void shutdown() { deviceVersionAvailable.clear(); - deviceVersionsAvailableSet.clear(); + deviceVersionsAvailableSet.clear(); + GLContextImpl.shutdownImpl(); // well .. } /** @@ -824,7 +838,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val = new Integer(compose8bit(resMajor, resMinor, resCtp, 0)); synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.put( key, val ); + val = deviceVersionAvailable.put( key, val ); } return val; } @@ -833,7 +847,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val; synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.get( key ); + val = deviceVersionAvailable.get( key ); } return val; } @@ -875,29 +889,29 @@ public abstract class GLContext { return null != getAvailableGLVersion(device, major, profile); } - public static boolean isGLES1Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); + } - public static boolean isGLES2Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); + } - public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); - } + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); + } - public static boolean isGL4Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); - } + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); + } - public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); - } + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); + } - public static boolean isGL3Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); - } + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); + } public static boolean isGL2Available(AbstractGraphicsDevice device) { return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT); @@ -941,6 +955,10 @@ public abstract class GLContext { return sb.toString(); } + // + // internal string utils + // + protected static String toString(int val, boolean hex) { if(hex) { return "0x" + Integer.toHexString(val); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java index f4cd77059..2b86a04ba 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -158,6 +158,12 @@ public interface GLDrawable { */ public GLProfile getGLProfile(); + /** + * Returns the underlying native surface which surface handle + * represents this OpenGL drawable's native resource. + * + * @see #getHandle() + */ public NativeSurface getNativeSurface(); /** diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index 1282eb168..3f9700436 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -47,12 +47,14 @@ import java.util.List; import com.jogamp.common.JogampRuntimeException; import jogamp.common.Debug; + import com.jogamp.common.util.ReflectionUtil; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; +import javax.media.opengl.GLProfile.ShutdownType; /** <P> Provides a virtual machine- and operating system-independent mechanism for creating {@link GLDrawable}s. </P> @@ -87,14 +89,12 @@ import javax.media.nativewindow.ProxySurface; property <code>opengl.factory.class.name</code> to the fully-qualified name of the desired class. </P> */ - public abstract class GLDrawableFactory { - private static final String nativeOSType; static final String macosxFactoryClassNameCGL = "jogamp.opengl.macosx.cgl.MacOSXCGLDrawableFactory"; static final String macosxFactoryClassNameAWTCGL = "jogamp.opengl.macosx.cgl.awt.MacOSXAWTCGLDrawableFactory"; - private static volatile boolean initialized = false; + private static volatile boolean isInit = false; private static GLDrawableFactory eglFactory; private static GLDrawableFactory nativeOSFactory; @@ -107,16 +107,20 @@ public abstract class GLDrawableFactory { /** * Instantiate singleton factories if available, EGLES1, EGLES2 and the OS native ones. */ - static { - nativeOSType = NativeWindowFactory.getNativeWindowType(true); - } - - protected static final void initialize() { - if(initialized) { return; } - initialized = true; - + public static final void initSingleton() { + if (!isInit) { // volatile: ok + synchronized (GLDrawableFactory.class) { + if (!isInit) { + isInit=true; + initSingletonImpl(); + } + } + } + } + private static final void initSingletonImpl() { registerFactoryShutdownHook(); + final String nativeOSType = NativeWindowFactory.getNativeWindowType(true); GLDrawableFactory tmp = null; String factoryClassName = Debug.getProperty("jogl.gldrawablefactory.class.name", true, AccessController.getContext()); ClassLoader cl = GLDrawableFactory.class.getClassLoader(); @@ -165,16 +169,40 @@ public abstract class GLDrawableFactory { eglFactory = tmp; } + protected static void shutdown(ShutdownType shutdownType) { + if (isInit) { // volatile: ok + synchronized (GLDrawableFactory.class) { + if (isInit) { + isInit=false; + unregisterFactoryShutdownHook(); + shutdownImpl(shutdownType); + } + } + } + } + private static void shutdownImpl(ShutdownType shutdownType) { + synchronized(glDrawableFactories) { + for(int i=0; i<glDrawableFactories.size(); i++) { + glDrawableFactories.get(i).destroy(shutdownType); + } + glDrawableFactories.clear(); + + // both were members of glDrawableFactories and are shutdown already + nativeOSFactory = null; + eglFactory = null; + } + } + private static synchronized void registerFactoryShutdownHook() { if (factoryShutdownHookRegistered) { return; } factoryShutdownHook = new Thread(new Runnable() { public void run() { - GLDrawableFactory.shutdownImpl(); + GLDrawableFactory.shutdownImpl(GLProfile.ShutdownType.COMPLETE); } }); - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { Runtime.getRuntime().addShutdownHook(factoryShutdownHook); return null; @@ -187,7 +215,7 @@ public abstract class GLDrawableFactory { if (!factoryShutdownHookRegistered) { return; } - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { Runtime.getRuntime().removeShutdownHook(factoryShutdownHook); return null; @@ -196,23 +224,6 @@ public abstract class GLDrawableFactory { factoryShutdownHookRegistered = false; } - private static void shutdownImpl() { - synchronized(glDrawableFactories) { - for(int i=0; i<glDrawableFactories.size(); i++) { - GLDrawableFactory factory = glDrawableFactories.get(i); - factory.shutdownInstance(); - } - glDrawableFactories.clear(); - } - } - - protected static void shutdown() { - unregisterFactoryShutdownHook(); - shutdownImpl(); - eglFactory = null; - nativeOSFactory = null; - initialized = false; - } protected GLDrawableFactory() { synchronized(glDrawableFactories) { @@ -223,7 +234,7 @@ public abstract class GLDrawableFactory { protected void enterThreadCriticalZone() {}; protected void leaveThreadCriticalZone() {}; - protected abstract void shutdownInstance(); + protected abstract void destroy(ShutdownType shutdownType); /** * Retrieve the default <code>device</code> {@link AbstractGraphicsDevice#getConnection() connection}, @@ -258,34 +269,31 @@ public abstract class GLDrawableFactory { } /** - * Returns true if a shared context could be created while initialization - * of shared resources for <code>device</code> {@link AbstractGraphicsDevice#getConnection()}.<br> - * This does not imply a shared context is mapped, but was available<br>. - * - * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * Validate and start the shared resource runner thread if necessary and + * if the implementation uses it. + * + * @return the shared resource runner thread, if implementation uses it. */ - public abstract boolean getWasSharedContextCreated(AbstractGraphicsDevice device); - + protected abstract Thread getSharedResourceThread(); + /** - * Returns the shared context mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, - * either a pre-existing or newly created, or <code>null</code> if creation failed or not supported.<br> - * Creation of the shared context is tried only once. + * Create the shared resource used internally as a reference for capabilities etc. + * <p> + * Returns true if a shared resource could be created + * for the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}.<br> + * This does not imply a shared resource is mapped (ie. made persistent), but is available in general<br>. + * </p> * * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @return true if a shared resource could been created, otherwise false. */ - public final GLContext getOrCreateSharedContext(AbstractGraphicsDevice device) { - device = validateDevice(device); - if(null!=device) { - return getOrCreateSharedContextImpl(device); - } - return null; - } - protected abstract GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device); - + protected abstract boolean createSharedResource(AbstractGraphicsDevice device); + /** * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null */ public static GLDrawableFactory getDesktopFactory() { + GLProfile.initSingleton(); return nativeOSFactory; } @@ -293,6 +301,7 @@ public abstract class GLDrawableFactory { * Returns the sole GLDrawableFactory instance for EGL if exist or null */ public static GLDrawableFactory getEGLFactory() { + GLProfile.initSingleton(); return eglFactory; } diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java index 20e2f2a33..6b39fe765 100644 --- a/src/jogl/classes/javax/media/opengl/GLProfile.java +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -48,6 +48,8 @@ import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.VersionUtil; import com.jogamp.common.util.cache.TempJarCache; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveThreadGroupLock; import com.jogamp.nativewindow.NativeWindowVersion; import com.jogamp.opengl.JoglVersion; @@ -74,56 +76,80 @@ public class GLProfile { public static final boolean DEBUG = Debug.debug("GLProfile"); + static { + // Also initializes TempJarCache if shall be used. + Platform.initSingleton(); + } + /** - * Static one time initialization of JOGL. + * Static initialization of JOGL. * <p> * The parameter <code>firstUIActionOnProcess</code> has an impact on concurrent locking,<br> * see {@link javax.media.nativewindow.NativeWindowFactory#initSingleton(boolean) NativeWindowFactory.initSingleton(firstUIActionOnProcess)}. * </p> * <p> - * Applications shall call this methods <b>ASAP</b>, before any other UI invocation.<br> - * You may issue the call in your <code>main class</code> static block, which is the earliest point in your application/applet lifecycle, - * or within the <code>main function</code>.<br> - * In case applications are able to initialize JOGL before any other UI action,<br> - * they shall invoke this method with <code>firstUIActionOnProcess=true</code> and benefit from fast native multithreading support on all platforms if possible.</P> - * <P> - * RCP Application (Applet's, Webstart, Netbeans, ..) using JOGL may not be able to initialize JOGL - * before the first UI action.<br> - * In such case you shall invoke this method with <code>firstUIActionOnProcess=false</code>.<br> - * On some platforms, notably X11 with AWT usage, JOGL will utilize special locking mechanisms which may slow down your - * application.</P> + * Applications using this method may place it's call before any other UI invocation + * in the <code>main class</code>'s static block or within the <code>main function</code>. + * In such case, applications may pass <code>firstUIActionOnProcess=true</code> to use native toolkit locking.</P> * <P> - * Remark: NEWT is currently not affected by this behavior, ie always uses native multithreading.</P> + * RCP Application (Applet's, Webstart, Netbeans, ..) using JOGL are not be able to initialize JOGL + * before the first UI action. + * In such case you shall pass <code>firstUIActionOnProcess=false</code>.</P> * <P> - * However, in case this method is not invoked, hence GLProfile is not initialized explicitly by the user,<br> - * the first call to {@link #getDefault()}, {@link #get(java.lang.String)}, etc, will initialize with <code>firstUIActionOnProcess=false</code>,<br> - * hence without the possibility to enable native multithreading.<br> - * This is not the recommended way, since it may has a performance impact, but it allows you to run code without explicit initialization.</P> + * In case this method is not invoked, GLProfile is initialized implicit by + * the first call to {@link #getDefault()}, {@link #get(java.lang.String)} passing <code>firstUIActionOnProcess=false</code>. * <P> * * @param firstUIActionOnProcess Should be <code>true</code> if called before the first UI action of the running program, * otherwise <code>false</code>. + * + * @deprecated This method shall not need to be called for other reasons than having a defined initialization sequence. + * To ensure homogeneous behavior with application not calling this method, you shall pass <code>firstUIActionOnProcess=false</code>. + * This method is subject to be removed in future versions of JOGL. */ - public static synchronized void initSingleton(final boolean firstUIActionOnProcess) { - if(!initialized) { - initialized = true; - // run the whole static initialization privileged to speed up, - // since this skips checking further access - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - if(TempJarCache.isInitialized()) { - String[] atomicNativeJarBaseNames = new String[] { "nativewindow", "jogl", null }; - if( ReflectionUtil.isClassAvailable("com.jogamp.newt.NewtFactory", GLProfile.class.getClassLoader()) ) { - atomicNativeJarBaseNames[2] = "newt"; - } - JNILibLoaderBase.addNativeJarLibs(GLProfile.class, "jogl.all", "jogl-all", atomicNativeJarBaseNames); - } - initProfilesForDefaultDevices(firstUIActionOnProcess); - return null; + public static void initSingleton(final boolean firstUIActionOnProcess) { + initLock.lock(); + try { + if(!initialized) { // volatile: ok + initialized = true; + if(DEBUG) { + System.err.println("GLProfile.initSingleton(firstUIActionOnProcess: "+firstUIActionOnProcess+") - thread "+Thread.currentThread().getName()); + Thread.dumpStack(); } - }); + + // run the whole static initialization privileged to speed up, + // since this skips checking further access + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + Platform.initSingleton(); + + if(TempJarCache.isInitialized()) { + String[] atomicNativeJarBaseNames = new String[] { "nativewindow", "jogl", null }; + if( ReflectionUtil.isClassAvailable("com.jogamp.newt.NewtFactory", GLProfile.class.getClassLoader()) ) { + atomicNativeJarBaseNames[2] = "newt"; + } + JNILibLoaderBase.addNativeJarLibs(GLProfile.class, "jogl-all", atomicNativeJarBaseNames); + } + initProfilesForDefaultDevices(firstUIActionOnProcess); + return null; + } + }); + } + } finally { + initLock.unlock(); } } + + /** + * Static initialization of JOGL. + * + * <p> + * This method shall not need to be called for other reasons than having a defined initialization sequence. + * </p> + */ + public static void initSingleton() { + GLProfile.initSingleton(false); + } /** * Trigger eager initialization of GLProfiles for the given device, @@ -132,21 +158,50 @@ public class GLProfile { * @throws GLException if no profile for the given device is available. */ public static void initProfiles(AbstractGraphicsDevice device) throws GLException { - getProfileMap(device); + getProfileMap(device, true); } + /** + * Shutdown type for {@link GLProfile#shutdown(ShutdownType)}. + * <p> + * {@link #SHARED_ONLY} For thread based resources only, suitable for eg. {@link java.applet.Applet Applet} restart.<br> + * {@link #COMPLETE} Everything.<br> + * </p> + */ + public enum ShutdownType { + /* Shared thread based resources only, eg. for Applets */ + SHARED_ONLY, + /* Everything */ + COMPLETE; + } + /** * Manual shutdown method, may be called after your last JOGL use * within the running JVM.<br> * It releases all temporary created resources, ie issues {@link javax.media.opengl.GLDrawableFactory#shutdown()}.<br> - * The shutdown implementation is called via the JVM shutdown hook, if not manually invoked here.<br> - * Invoke <code>shutdown()</code> manually is recommended, due to the unreliable JVM state within the shutdown hook.<br> + * The shutdown implementation is called via the JVM shutdown hook, if not manually invoked.<br> + * <p> + * This method shall not need to be called for other reasons than issuing a proper shutdown of resources. + * </p> + * @param type the shutdown type, see {@link ShutdownType}. */ - public static synchronized void shutdown() { - if(initialized) { - initialized = false; - GLDrawableFactory.shutdown(); - GLContext.shutdown(); + public static void shutdown(ShutdownType type) { + initLock.lock(); + try { + if(initialized) { // volatile: ok + initialized = false; + if(DEBUG) { + System.err.println("GLProfile.shutdown(type: "+type+") - thread "+Thread.currentThread().getName()); + Thread.dumpStack(); + } + GLDrawableFactory.shutdown(type); + if(ShutdownType.COMPLETE == type) { + GLContext.shutdown(); + } + NativeWindowFactory.shutdown(); + } + } finally { + initLock.unlock(); } } @@ -163,12 +218,13 @@ public class GLProfile { * @return true if the profile is available for the device, otherwise false. */ public static boolean isAvailable(AbstractGraphicsDevice device, String profile) { - try { - return null != getProfileMap(device).get(profile); - } catch (GLException gle) { /* profiles for device n/a */ } - return false; + initSingleton(); + return isAvailableImpl(getProfileMap(device, false), profile); } - + private static boolean isAvailableImpl(HashMap<String /*GLProfile_name*/, GLProfile> map, String profile) { + return null != map && null != map.get(profile); + } + /** * Returns the availability of a profile on the default device. * @@ -193,74 +249,71 @@ public class GLProfile { boolean avail; StringBuffer sb = new StringBuffer(); - validateInitialization(); - + initSingleton(); + if(null==device) { device = defaultDevice; } - + final HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, false); + sb.append("GLAvailability[Native[GL4bc "); - avail=isAvailable(device, GL4bc); + avail=isAvailableImpl(map, GL4bc); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL4 "); - avail=isAvailable(device, GL4); + avail=isAvailableImpl(map, GL4); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_CORE); } sb.append(", GL3bc "); - avail=isAvailable(device, GL3bc); + avail=isAvailableImpl(map, GL3bc); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL3 "); - avail=isAvailable(device, GL3); + avail=isAvailableImpl(map, GL3); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_CORE); } sb.append(", GL2 "); - avail=isAvailable(device, GL2); + avail=isAvailableImpl(map, GL2); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL2ES1 "); - sb.append(isAvailable(device, GL2ES1)); + sb.append(isAvailableImpl(map, GL2ES1)); sb.append(", GLES1 "); - avail=isAvailable(device, GLES1); + avail=isAvailableImpl(map, GLES1); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 1, GLContext.CTX_PROFILE_ES); } sb.append(", GL2ES2 "); - sb.append(isAvailable(device, GL2ES2)); + sb.append(isAvailableImpl(map, GL2ES2)); sb.append(", GLES2 "); - avail=isAvailable(device, GLES2); + avail=isAvailableImpl(map, GLES2); sb.append(avail); if(avail) { glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_ES); } sb.append("], Profiles["); - HashMap<String /*GLProfile_name*/, GLProfile> profileMap = null; - try { - profileMap = getProfileMap(device); - } catch (GLException gle) { /* profiles for device n/a */ } - if(null != profileMap) { - for(Iterator<GLProfile> i=profileMap.values().iterator(); i.hasNext(); ) { + if(null != map) { + for(Iterator<GLProfile> i=map.values().iterator(); i.hasNext(); ) { sb.append(i.next().toString()); sb.append(", "); } @@ -275,7 +328,7 @@ public class GLProfile { return sb.toString(); } - + /** Uses the default device */ public static String glAvailabilityToString() { return glAvailabilityToString(null); @@ -596,7 +649,7 @@ public class GLProfile { if(null==profile || profile.equals("GL")) { profile = GL_DEFAULT; } - final HashMap<String /*GLProfile_name*/, GLProfile> glpMap = getProfileMap(device); + final HashMap<String /*GLProfile_name*/, GLProfile> glpMap = getProfileMap(device, true); final GLProfile glp = glpMap.get(profile); if(null == glp) { throw new GLException("Profile "+profile+" is not available on "+device+", but: "+glpMap.values()); @@ -626,7 +679,7 @@ public class GLProfile { public static GLProfile get(AbstractGraphicsDevice device, String[] profiles) throws GLException { - HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device); + HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, true); for(int i=0; i<profiles.length; i++) { String profile = profiles[i]; GLProfile glProfile = map.get(profile); @@ -1137,10 +1190,6 @@ public class GLProfile { return "GLProfile[" + getName() + "/" + getImplName() + "]"; } - static { - Platform.initSingleton(); - } - private static /*final*/ boolean isAWTAvailable; private static /*final*/ boolean hasDesktopGLFactory; @@ -1155,7 +1204,8 @@ public class GLProfile { private static /*final*/ AbstractGraphicsDevice defaultDesktopDevice; private static /*final*/ AbstractGraphicsDevice defaultEGLDevice; - static boolean initialized = false; + private static volatile boolean initialized = false; + private static RecursiveThreadGroupLock initLock = LockFactory.createRecursiveThreadGroupLock(); /** * Tries the profiles implementation and native libraries. @@ -1191,7 +1241,7 @@ public class GLProfile { // - Instantiate GLDrawableFactory incl its shared dummy drawable/context, // which will register at GLContext .. // - GLDrawableFactory.initialize(); + GLDrawableFactory.initSingleton(); Throwable t=null; // if successfull it has a shared dummy drawable and context created @@ -1295,19 +1345,24 @@ public class GLProfile { * @param device the device for which profiles shall be initialized * @return true if any profile for the device exists, otherwise false */ - private static synchronized boolean initProfilesForDevice(AbstractGraphicsDevice device) { + private static boolean initProfilesForDevice(AbstractGraphicsDevice device) { if(null == device) { return false; } - GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device); - factory.enterThreadCriticalZone(); + initLock.lock(); try { - return initProfilesForDeviceCritical(device); + GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device); + factory.enterThreadCriticalZone(); + try { + return initProfilesForDeviceCritical(device); + } finally { + factory.leaveThreadCriticalZone(); + } } finally { - factory.leaveThreadCriticalZone(); + initLock.unlock(); } } - private static synchronized boolean initProfilesForDeviceCritical(AbstractGraphicsDevice device) { + private static boolean initProfilesForDeviceCritical(AbstractGraphicsDevice device) { boolean isSet = GLContext.getAvailableGLVersionsSet(device); if(DEBUG) { @@ -1331,11 +1386,21 @@ public class GLProfile { // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles - boolean desktopSharedCtxAvail = desktopFactory.getWasSharedContextCreated(device); + final Thread sharedResourceThread = desktopFactory.getSharedResourceThread(); + if(null != sharedResourceThread) { + initLock.addOwner(sharedResourceThread); + } + boolean desktopSharedCtxAvail = desktopFactory.createSharedResource(device); + if(null != sharedResourceThread) { + initLock.removeOwner(sharedResourceThread); + } + if(!desktopSharedCtxAvail) { + hasDesktopGLFactory = false; + } if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail); } - if( null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_COMPAT) ) { + if( hasDesktopGLFactory && null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_COMPAT) ) { // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, // so we have to add the usual suspect GLContext.mapAvailableGLVersion(device, @@ -1350,7 +1415,22 @@ public class GLProfile { // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles - boolean eglSharedCtxAvail = eglFactory.getWasSharedContextCreated(device); + final Thread sharedResourceThread = eglFactory.getSharedResourceThread(); + if(null != sharedResourceThread) { + initLock.addOwner(sharedResourceThread); + } + boolean eglSharedCtxAvail = eglFactory.createSharedResource(device); + if(null != sharedResourceThread) { + initLock.removeOwner(sharedResourceThread); + } + if(!eglSharedCtxAvail) { + // Remark: On Windows there is a libEGL.dll delivered w/ Chrome 15.0.874.121m and Firefox 8.0.1 + // but it seems even EGL.eglInitialize(eglDisplay, null, null) + // fails in some scenarios (eg VirtualBox 4.1.6) w/ EGL error 0x3001 (EGL_NOT_INITIALIZED). + hasEGLFactory = false; + hasGLES2Impl = false; + hasGLES1Impl = false; + } if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail); } @@ -1423,30 +1503,20 @@ public class GLProfile { } public static AbstractGraphicsDevice getDefaultDevice() { - validateInitialization(); + initSingleton(); return defaultDevice; } public static AbstractGraphicsDevice getDefaultDesktopDevice() { - validateInitialization(); + initSingleton(); return defaultDesktopDevice; } public static AbstractGraphicsDevice getDefaultEGLDevice() { - validateInitialization(); + initSingleton(); return defaultEGLDevice; } - private static void validateInitialization() { - if(!initialized) { - synchronized(GLProfile.class) { - if(!initialized) { - initSingleton(false); - } - } - } - } - private static String array2String(String[] list) { StringBuffer msg = new StringBuffer(); msg.append("["); @@ -1608,29 +1678,38 @@ public class GLProfile { * - initialization<br< * * @param device the key 'device -> GLProfiles-Map' + * @param throwExceptionOnZeroProfile true if <code>GLException</code> shall be thrown in case of no mapped profile, otherwise false. * @return the GLProfile HashMap if exists, otherwise null * @throws GLException if no profile for the given device is available. */ - private static HashMap<String /*GLProfile_name*/, GLProfile> getProfileMap(AbstractGraphicsDevice device) throws GLException { - validateInitialization(); + private static HashMap<String /*GLProfile_name*/, GLProfile> getProfileMap(AbstractGraphicsDevice device, boolean throwExceptionOnZeroProfile) + throws GLException + { + initSingleton(); + if(null==device) { device = defaultDevice; } String deviceKey = device.getUniqueID(); HashMap<String /*GLProfile_name*/, GLProfile> map = deviceConn2ProfileMap.get(deviceKey); - if( null == map ) { - if( !initProfilesForDevice(device) ) { + if( null != map ) { + return map; + } + if( !initProfilesForDevice(device) ) { + if( throwExceptionOnZeroProfile ) { throw new GLException("No Profile available for "+device); + } else { + return null; } - if( null == deviceConn2ProfileMap.get(deviceKey) ) { - throw new InternalError("initProfilesForDevice(..) didn't issue setProfileMap(..) on "+device); - } + } + map = deviceConn2ProfileMap.get(deviceKey); + if( null == map && throwExceptionOnZeroProfile ) { + throw new InternalError("initProfilesForDevice(..) didn't setProfileMap(..) for "+device); } return map; } private static void setProfileMap(AbstractGraphicsDevice device, HashMap<String /*GLProfile_name*/, GLProfile> mappedProfiles) { - validateInitialization(); synchronized ( deviceConn2ProfileMap ) { deviceConn2ProfileMap.put(device.getUniqueID(), mappedProfiles); } diff --git a/src/jogl/classes/javax/media/opengl/GLUniformData.java b/src/jogl/classes/javax/media/opengl/GLUniformData.java index 5c9388be2..475ff4546 100644 --- a/src/jogl/classes/javax/media/opengl/GLUniformData.java +++ b/src/jogl/classes/javax/media/opengl/GLUniformData.java @@ -107,10 +107,10 @@ public class GLUniformData { if(data instanceof Buffer) { final int sz = rows*columns; final Buffer buffer = (Buffer)data; - if(buffer.limit()<sz || 0!=buffer.limit()%sz) { - throw new GLException("data buffer size invalid: new buffer limit: "+buffer.limit()+"\n\t"+this); + if(buffer.remaining()<sz || 0!=buffer.remaining()%sz) { + throw new GLException("remaining data buffer size invalid: buffer: "+buffer.toString()+"\n\t"+this); } - this.count=buffer.limit()/(rows*columns); + this.count=buffer.remaining()/(rows*columns); } else { if(isMatrix) { throw new GLException("Atom type not allowed for matrix : "+this); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index ada9f5222..cd341593e 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -59,8 +59,9 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.GraphicsConfigurationFactory; @@ -92,6 +93,8 @@ import com.jogamp.opengl.JoglVersion; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; + +import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableHelper; @@ -136,7 +139,7 @@ import jogamp.opengl.ThreadingImpl; */ @SuppressWarnings("serial") -public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol { +public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol, OffscreenLayerOption { private static final boolean DEBUG; @@ -156,6 +159,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private GLContext shareWith; private int additionalCtxCreationFlags = 0; private GraphicsDevice device; + private boolean shallUseOffscreenLayer = false; private AWTWindowClosingProtocol awtWindowClosingProtocol = new AWTWindowClosingProtocol(this, new Runnable() { @@ -250,6 +254,22 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing this.device = device; } + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + public final boolean isOffscreenLayerSurfaceEnabled() { + if(null != drawable) { + return ((JAWTWindow)drawable.getNativeSurface()).isOffscreenLayerSurfaceEnabled(); + } + return false; + } + + /** * Overridden to choose a GraphicsConfiguration on a parent container's * GraphicsDevice because both devices @@ -279,7 +299,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing * otherwise it is from an ancestor component that this Canvas is being * added to, and we go into this block. */ - GraphicsConfiguration chosen = awtConfig.getGraphicsConfiguration(); + GraphicsConfiguration chosen = awtConfig.getAWTGraphicsConfiguration(); if (gc != null && chosen != null && !chosen.equals(gc)) { /* @@ -308,7 +328,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(), (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(), chooser, gc.getDevice()); - final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null; + final GraphicsConfiguration compatible = (null!=config)?config.getAWTGraphicsConfiguration():null; boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()); if(DEBUG) { Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName()); @@ -406,15 +426,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing private void dispose(boolean regenerate) { drawableSync.lock(); try { + final GLAnimatorControl animator = getAnimator(); if(DEBUG) { - Exception ex1 = new Exception("Info: dispose("+regenerate+") - start, hasContext " + - (null!=context) + ", hasDrawable " + (null!=drawable)); + Exception ex1 = new Exception("Info: dispose("+regenerate+") - START, hasContext " + + (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator); ex1.printStackTrace(); } if(null!=context) { boolean animatorPaused = false; - GLAnimatorControl animator = getAnimator(); if(null!=animator) { // can't remove us from animator for recreational addNotify() animatorPaused = animator.pause(); @@ -422,37 +442,38 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing disposeRegenerate=regenerate; - if (Threading.isSingleThreaded() && - !Threading.isOpenGLThread()) { - // Workaround for termination issues with applets -- - // sun.applet.AppletPanel should probably be performing the - // remove() call on the EDT rather than on its own thread - // Hint: User should run remove from EDT. - if (ThreadingImpl.isAWTMode() && - Thread.holdsLock(getTreeLock())) { - // The user really should not be invoking remove() from this - // thread -- but since he/she is, we can not go over to the - // EDT at this point. Try to destroy the context from here. - if(context.isCreated()) { - drawableHelper.invokeGL(drawable, context, disposeAction, null); + if(context.isCreated()) { + if (Threading.isSingleThreaded() && + !Threading.isOpenGLThread()) { + // Workaround for termination issues with applets -- + // sun.applet.AppletPanel should probably be performing the + // remove() call on the EDT rather than on its own thread + // Hint: User should run remove from EDT. + if (ThreadingImpl.isAWTMode() && + Thread.holdsLock(getTreeLock())) { + // The user really should not be invoking remove() from this + // thread -- but since he/she is, we can not go over to the + // EDT at this point. Try to destroy the context from here. + drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); + } else { + Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); + } + } else { + drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); } - } else if(context.isCreated()) { - Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); - } - } else if(context.isCreated()) { - drawableHelper.invokeGL(drawable, context, disposeAction, null); } if(animatorPaused) { animator.resume(); } } + if(!regenerate) { disposeAbstractGraphicsDevice(); } if(DEBUG) { - System.err.println("dispose("+regenerate+") - stop"); + System.err.println("dispose("+regenerate+") - END, "+animator); } } finally { drawableSync.unlock(); @@ -532,15 +553,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing throw new GLException("Error: NULL AWTGraphicsConfiguration"); } - if (!Beans.isDesignTime()) { - // no lock required, since this resource ain't available yet - drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()) - .createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig)); - context = (GLContextImpl) drawable.createContext(shareWith); - context.setSynchronized(true); - context.setContextCreationFlags(additionalCtxCreationFlags); - } - // before native peer is valid: X11 disableBackgroundErase(); @@ -550,6 +562,10 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // after native peer is valid: Windows disableBackgroundErase(); + if (!Beans.isDesignTime()) { + createDrawableAndContext(); + } + // init drawable by paint/display makes the init sequence more equal // for all launch flavors (applet/javaws/..) // validateGLDrawable(); @@ -562,6 +578,21 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } + private void createDrawableAndContext() { + // no lock required, since this resource ain't available yet + final JAWTWindow jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); + jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); + jawtWindow.lockSurface(); + try { + drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setSynchronized(true); + context.setContextCreationFlags(additionalCtxCreationFlags); + } finally { + jawtWindow.unlockSurface(); + } + } + private boolean validateGLDrawable() { boolean realized = false; if (!Beans.isDesignTime()) { @@ -636,7 +667,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing @Override public void reshape(int x, int y, int width, int height) { super.reshape(x, y, width, height); - sendReshape = true; + if(null != drawable && drawable.isRealized() && !drawable.getChosenGLCapabilities().isOnscreen()) { + dispose(true); + } else { + sendReshape = true; + } } /** <B>Overrides:</B> @@ -800,63 +835,60 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } } - class DisposeAction implements Runnable { + class PostDisposeAction implements Runnable { public void run() { - drawableHelper.dispose(GLCanvas.this); - - if(null!=context) { - context.makeCurrent(); // implicit wait for lock .. - context.destroy(); - context=null; - } - + context=null; if(null!=drawable) { + final JAWTWindow jawtWindow = (JAWTWindow)drawable.getNativeSurface(); drawable.setRealized(false); drawable=null; + if(null!=jawtWindow) { + jawtWindow.destroy(); + } } - + if(disposeRegenerate) { - // recreate GLDrawable to reflect it's new graphics configuration - drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()) - .createGLDrawable(NativeWindowFactory.getNativeWindow(GLCanvas.this, awtConfig)); + // Similar process as in addNotify()! + + // Recreate GLDrawable/GLContext to reflect it's new graphics configuration + createDrawableAndContext(); + if(DEBUG) { System.err.println("GLCanvas.dispose(true): new drawable: "+drawable); } - drawable.setRealized(true); - context = (GLContextImpl) drawable.createContext(shareWith); - context.setSynchronized(true); - sendReshape=true; // ensure a reshape is being send .. + validateGLDrawable(); // immediate attempt to recreate the drawable } } } private boolean disposeRegenerate; - private DisposeAction disposeAction = new DisposeAction(); + private PostDisposeAction postDisposeAction = new PostDisposeAction(); private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = new DisposeOnEventDispatchThreadAction(); class DisposeOnEventDispatchThreadAction implements Runnable { public void run() { - drawableHelper.invokeGL(drawable, context, disposeAction, null); + drawableHelper.disposeGL(GLCanvas.this, drawable, context, postDisposeAction); } } class DisposeAbstractGraphicsDeviceAction implements Runnable { public void run() { - AbstractGraphicsConfiguration aconfig = (null!=awtConfig) ? awtConfig.getNativeGraphicsConfiguration() : null; - AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; - AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; - if(null!=adevice) { - String adeviceMsg=null; + if(null != awtConfig) { + final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration(); + final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + final String adeviceMsg; if(DEBUG) { adeviceMsg = adevice.toString(); + } else { + adeviceMsg = null; } boolean closed = adevice.close(); if(DEBUG) { System.err.println(Thread.currentThread().getName() + " - GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); } + awtConfig=null; } - awtConfig=null; } } private DisposeAbstractGraphicsDeviceAction disposeAbstractGraphicsDeviceAction = new DisposeAbstractGraphicsDeviceAction(); @@ -1001,7 +1033,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing return null; } - final AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT); + final AbstractGraphicsScreen aScreen = null != device ? + AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT): + AWTGraphicsScreen.createDefault(); AWTGraphicsConfiguration config = null; if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { @@ -1045,7 +1079,6 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing // System.err.println(NativeWindowVersion.getInstance()); System.err.println(JoglVersion.getInstance()); - GLProfile.initSingleton(false); GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); List<GLCapabilitiesImmutable> availCaps = factory.getAvailableCapabilities(null); for(int i=0; i<availCaps.size(); i++) { @@ -1053,9 +1086,9 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing } GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()) ); - Frame frame = new Frame("JOGL AWT Test"); + final Frame frame = new Frame("JOGL AWT Test"); - GLCanvas glCanvas = new GLCanvas(caps); + final GLCanvas glCanvas = new GLCanvas(caps); frame.add(glCanvas); frame.setSize(128, 128); @@ -1064,24 +1097,15 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing GL gl = drawable.getGL(); System.err.println(JoglVersion.getGLInfo(gl, null)); } - - public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { - } - - public void display(GLAutoDrawable drawable) { - } - - public void dispose(GLAutoDrawable drawable) { - } + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } + public void display(GLAutoDrawable drawable) { } + public void dispose(GLAutoDrawable drawable) { } }); - final Frame _frame = frame; - final GLCanvas _glCanvas = glCanvas; - try { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { - _frame.setVisible(true); + frame.setVisible(true); }}); } catch (Throwable t) { t.printStackTrace(); @@ -1090,9 +1114,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosing try { javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { - _frame.setVisible(false); - _frame.remove(_glCanvas); - _frame.dispose(); + frame.dispose(); }}); } catch (Throwable t) { t.printStackTrace(); diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 92be62b4d..7a87882ca 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -82,7 +82,10 @@ import javax.media.opengl.GLPbuffer; import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import javax.media.opengl.Threading; + import com.jogamp.opengl.util.FBObject; +import com.jogamp.opengl.util.GLBuffers; + import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -123,9 +126,9 @@ import jogamp.opengl.awt.Java2DGLContext; * </P> */ +@SuppressWarnings("serial") public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol { private static final boolean DEBUG = Debug.debug("GLJPanel"); - private static final boolean VERBOSE = Debug.verbose(); private GLDrawableHelper drawableHelper = new GLDrawableHelper(); private volatile boolean isInitialized; @@ -268,70 +271,51 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } } - protected void dispose(boolean regenerate) { + protected void dispose() { if(DEBUG) { - Exception ex1 = new Exception("Info: dispose("+regenerate+") - start"); - ex1.printStackTrace(); + System.err.println("Info: dispose() - start - "+Thread.currentThread().getName()); + Thread.dumpStack(); } - if (backend != null) { + if (backend != null && backend.getContext() != null) { boolean animatorPaused = false; GLAnimatorControl animator = getAnimator(); if(null!=animator) { - if(regenerate) { - animatorPaused = animator.pause(); - } - } - - disposeRegenerate=regenerate; - disposeContext=backend.getContext(); - disposeDrawable=backend.getDrawable(); - - if (Threading.isSingleThreaded() && - !Threading.isOpenGLThread()) { - // Workaround for termination issues with applets -- - // sun.applet.AppletPanel should probably be performing the - // remove() call on the EDT rather than on its own thread - if (ThreadingImpl.isAWTMode() && - Thread.holdsLock(getTreeLock())) { - // The user really should not be invoking remove() from this - // thread -- but since he/she is, we can not go over to the - // EDT at this point. Try to destroy the context from here. - if(disposeContext.isCreated()) { - drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); - } - } else if(disposeContext.isCreated()) { - Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); - } - } else if(disposeContext.isCreated()) { - drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); + animatorPaused = animator.pause(); } - if(!regenerate) { - AbstractGraphicsDevice adevice = disposeDrawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); - String adeviceMsg=null; - if(DEBUG) { - adeviceMsg = adevice.toString(); - } - // boolean closed = adevice.close(); - boolean closed = false; - if (DEBUG) { - System.err.println("GLJPanel.dispose(false): closed GraphicsDevice: " + adeviceMsg + ", result: " + closed); + if(backend.getContext().isCreated()) { + if (Threading.isSingleThreaded() && + !Threading.isOpenGLThread()) { + // Workaround for termination issues with applets -- + // sun.applet.AppletPanel should probably be performing the + // remove() call on the EDT rather than on its own thread + if (ThreadingImpl.isAWTMode() && + Thread.holdsLock(getTreeLock())) { + // The user really should not be invoking remove() from this + // thread -- but since he/she is, we can not go over to the + // EDT at this point. Try to destroy the context from here. + drawableHelper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); + } else { + Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); + } + } else { + drawableHelper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); } } - - backend.setContext(disposeContext); - if(null==disposeContext) { - isInitialized = false; + if(null != backend) { + // not yet destroyed due to backend.isUsingOwnThreadManagment() == true + backend.destroy(); + isInitialized = false; } if(animatorPaused) { animator.resume(); - } + } } - + if(DEBUG) { - System.err.println("dispose("+regenerate+") - stop"); + System.err.println("dispose() - stop"); } } @@ -347,8 +331,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing super.paintComponent() in their paintComponent() method in order to function properly. <P> - <B>Overrides:</B> <DL><DD><CODE>paintComponent</CODE> in class <CODE>javax.swing.JComponent</CODE></DD></DL> */ + @Override protected void paintComponent(final Graphics g) { if (Beans.isDesignTime()) { // Make GLJPanel behave better in NetBeans GUI builder @@ -396,8 +380,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing super.addNotify() in their addNotify() method in order to function properly. <P> - <B>Overrides:</B> <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ + @Override public void addNotify() { super.addNotify(); if (DEBUG) { @@ -410,26 +394,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing super.removeNotify() in their removeNotify() method in order to function properly. <P> - <B>Overrides:</B> <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ + @Override public void removeNotify() { - if(DEBUG) { - Exception ex1 = new Exception("Info: removeNotify - start"); - ex1.printStackTrace(); - } - awtWindowClosingProtocol.removeClosingListener(); - dispose(false); - if (backend != null) { - backend.destroy(); - backend = null; - } - isInitialized = false; + dispose(); super.removeNotify(); - if(DEBUG) { - System.err.println("Info: removeNotify - end"); - } } /** Overridden to cause {@link GLDrawableHelper#reshape} to be @@ -437,9 +408,10 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing which override this method must call super.reshape() in their reshape() method in order to function properly. <P> - <B>Overrides:</B> <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ - public void reshape(int x, int y, int width, int height) { + @SuppressWarnings("deprecation") + @Override +public void reshape(int x, int y, int width, int height) { super.reshape(x, y, width, height); // reshapeX = x; @@ -449,6 +421,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing handleReshape = true; } + @Override public void setOpaque(boolean opaque) { if (backend != null) { backend.setOpaque(opaque); @@ -481,7 +454,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } public GLContext createContext(GLContext shareWith) { - return backend.createContext(shareWith); + return (null != backend) ? backend.createContext(shareWith) : null; } public void setRealized(boolean realized) { @@ -690,7 +663,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return; } if (sendReshape) { - if (DEBUG||VERBOSE) { + if (DEBUG) { System.err.println("display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")"); } drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight); @@ -713,42 +686,26 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing return "AWT-GLJPanel[ "+((null!=backend)?backend.getDrawable().getClass().getName():"null-drawable")+"]"; } - private boolean disposeRegenerate; - private GLContext disposeContext; - private GLDrawable disposeDrawable; - private DisposeAction disposeAction = new DisposeAction(); - - class DisposeAction implements Runnable { + class PostDisposeAction implements Runnable { public void run() { - updater.dispose(GLJPanel.this); - - if (null != disposeContext) { - disposeContext.destroy(); - disposeContext = null; - } - if (null != disposeDrawable) { - disposeDrawable.setRealized(false); - } - if (null != disposeDrawable) { - if (disposeRegenerate) { - disposeDrawable.setRealized(true); - disposeContext = (GLContextImpl) disposeDrawable.createContext(shareWith); - disposeContext.setSynchronized(true); - } + if (backend != null && !backend.isUsingOwnThreadManagment()) { + backend.destroy(); + backend = null; + isInitialized = false; } } } + private PostDisposeAction postDisposeAction = new PostDisposeAction(); private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = new DisposeOnEventDispatchThreadAction(); class DisposeOnEventDispatchThreadAction implements Runnable { public void run() { - drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); + drawableHelper.disposeGL(GLJPanel.this, backend.getDrawable(), backend.getContext(), postDisposeAction); } } - - + class InitAction implements Runnable { public void run() { updater.init(GLJPanel.this); @@ -776,17 +733,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (number == 0) { return 2; } - - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); + return GLBuffers.getNextPowerOf2(number); } private int getGLInteger(GL gl, int which) { @@ -803,6 +750,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // software / pixmap rendering, pbuffer-based acceleration, Java 2D // / JOGL bridge static interface Backend { + // Create, Destroy, .. + public boolean isUsingOwnThreadManagment(); + // Called each time the backend needs to initialize itself public void initialize(); @@ -862,7 +812,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing protected int readBackWidthInPixels; protected int readBackHeightInPixels; - private int awtFormat; private int glFormat; private int glType; @@ -1031,7 +980,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private GLDrawableImpl offscreenDrawable; private GLContextImpl offscreenContext; + public boolean isUsingOwnThreadManagment() { return false; } + public void initialize() { + if(DEBUG) { + System.err.println("SoftwareBackend: initialize() - "+Thread.currentThread().getName()); + } // Fall-through path: create an offscreen context instead offscreenDrawable = (GLDrawableImpl) factory.createOffscreenDrawable( null /* default platform device */, @@ -1039,6 +993,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing chooser, Math.max(1, panelWidth), Math.max(1, panelHeight)); + offscreenDrawable.setRealized(true); offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith); offscreenContext.setSynchronized(true); offscreenContext.setContextCreationFlags(additionalCtxCreationFlags); @@ -1047,18 +1002,25 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } public void destroy() { + if(DEBUG) { + System.err.println("SoftwareBackend: destroy() - offscreenContext: "+(null!=offscreenContext)+" - offscreenDrawable: "+(null!=offscreenDrawable)+" - "+Thread.currentThread().getName()); + } if (offscreenContext != null) { offscreenContext.destroy(); offscreenContext = null; } if (offscreenDrawable != null) { + final AbstractGraphicsDevice adevice = offscreenDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); offscreenDrawable.destroy(); offscreenDrawable = null; + if(null != adevice) { + adevice.close(); + } } } public GLContext createContext(GLContext shareWith) { - return offscreenDrawable.createContext(shareWith); + return (null != offscreenDrawable) ? offscreenDrawable.createContext(shareWith) : null; } public void setContext(GLContext ctx) { @@ -1117,10 +1079,15 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private int pbufferWidth = 256; private int pbufferHeight = 256; + public boolean isUsingOwnThreadManagment() { return false; } + public void initialize() { if (pbuffer != null) { throw new InternalError("Creating pbuffer twice without destroying it (memory leak / correctness bug)"); } + if(DEBUG) { + System.err.println("PbufferBackend: initialize() - "+Thread.currentThread().getName()); + } try { pbuffer = factory.createGLPbuffer(null /* default platform device */, offscreenCaps, @@ -1144,6 +1111,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } public void destroy() { + if(DEBUG) { + System.err.println("PbufferBackend: destroy() - pbuffer: "+(null!=pbuffer)+" - "+Thread.currentThread().getName()); + } if (pbuffer != null) { pbuffer.destroy(); pbuffer = null; @@ -1151,7 +1121,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } public GLContext createContext(GLContext shareWith) { - return pbuffer.createContext(shareWith); + return (null != pbuffer) ? pbuffer.createContext(shareWith) : null; } public void setContext(GLContext ctx) { @@ -1265,7 +1235,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private Object j2dSurface; // Graphics object being used during Java2D update action // (absolutely essential to cache this) - private Graphics cached2DGraphics; // No-op context representing the Java2D OpenGL context private GLContext j2dContext; // Context associated with no-op drawable representing the JOGL @@ -1308,7 +1277,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // comment related to Issue 274 below private GraphicsConfiguration workaroundConfig; + public boolean isUsingOwnThreadManagment() { return true; } + public void initialize() { + if(DEBUG) { + System.err.println("J2DOGL: initialize() - "+Thread.currentThread().getName()); + } // No-op in this implementation; everything is done lazily isInitialized = true; } @@ -1316,6 +1290,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing public void destroy() { Java2D.invokeWithOGLContextCurrent(null, new Runnable() { public void run() { + if(DEBUG) { + System.err.println("J2DOGL: destroy() - joglContext: "+(null!=joglContext)+" - joglDrawable: "+(null!=joglDrawable)+" - "+Thread.currentThread().getName()); + } if (joglContext != null) { joglContext.destroy(); joglContext = null; @@ -1334,9 +1311,10 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } public GLContext createContext(GLContext shareWith) { - // FIXME: should implement this, but it was not properly - // implemented before the refactoring anyway - throw new GLException("Not yet implemented"); + if(null != shareWith) { + throw new GLException("J2DOGLBackend cannot create context w/ additional shared context, since it already needs to share the context w/ J2D."); + } + return (null != joglDrawable && null != j2dContext) ? joglDrawable.createContext(j2dContext) : null; } public void setContext(GLContext ctx) { @@ -1372,12 +1350,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing Rectangle r = Java2D.getOGLScissorBox(g); if (r == null) { - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("Java2D.getOGLScissorBox() returned null"); } return false; } - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: gl.glScissor(" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + ")"); } @@ -1418,14 +1396,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Need to do workarounds fbObjectWorkarounds = true; createNewDepthBuffer = true; - if (DEBUG || VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: ERR GL_FRAMEBUFFER_BINDING: Discovered Invalid J2D FBO("+frameBuffer[0]+"): "+FBObject.getStatusString(status) + ", frame_buffer_object workarounds to be necessary"); } } else { // Don't need the frameBufferTexture temporary any more frameBufferTexture = null; - if (DEBUG || VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: OK GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]); } } @@ -1472,7 +1450,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing fboTextureTarget, frameBufferTexture[0], 0); - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: frameBufferDepthBuffer: " + frameBufferDepthBuffer[0]); } gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, @@ -1489,7 +1467,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } } } else { - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: Setting up drawBuffer " + drawBuffer[0] + " and readBuffer " + readBuffer[0]); } @@ -1547,14 +1525,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing Java2D.invokeWithOGLContextCurrent(g, new Runnable() { public void run() { - if (DEBUG && VERBOSE) { - System.err.println("-- In invokeWithOGLContextCurrent"); + if (DEBUG) { + System.err.println("-- In invokeWithOGLContextCurrent - "+Thread.currentThread().getName()); } // Create no-op context representing Java2D context if (j2dContext == null) { j2dContext = factory.createExternalGLContext(); - if (DEBUG||VERBOSE) { + if (DEBUG) { System.err.println("-- Created External Context: "+j2dContext); } if (DEBUG) { @@ -1595,15 +1573,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing backend = null; oglPipelineEnabled = false; handleReshape = true; - j2dContext.release(); j2dContext.destroy(); j2dContext = null; return; } - j2dContext.release(); + } else { + j2dContext.makeCurrent(); } - - j2dContext.makeCurrent(); try { captureJ2DState(j2dContext.getGL(), g); Object curSurface = Java2D.getOGLSurfaceIdentifier(g); @@ -1614,13 +1590,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing joglContext = null; joglDrawable = null; sendReshape = true; - if (DEBUG||VERBOSE) { + if (DEBUG) { System.err.println("Sending reshape because surface changed"); System.err.println("New surface = " + curSurface); } } j2dSurface = curSurface; - if (DEBUG || VERBOSE) { + if (DEBUG) { System.err.print("-- Surface type: "); int surfaceType = Java2D.getOGLSurfaceType(g); if (surfaceType == Java2D.UNDEFINED) { @@ -1641,22 +1617,20 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } } if (joglContext == null) { - AbstractGraphicsDevice device = j2dContext.getGLDrawable().getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + AbstractGraphicsDevice device = j2dContext.getGLDrawable().getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); if (factory.canCreateExternalGLDrawable(device)) { joglDrawable = factory.createExternalGLDrawable(); - // FIXME: Need to share with j2d context, due to FBO resource .. - // - ORIG: joglContext = joglDrawable.createContext(shareWith); joglContext = joglDrawable.createContext(j2dContext); - if (DEBUG||VERBOSE) { + joglContext.setSynchronized(true); + if (DEBUG) { System.err.println("-- Created External Drawable: "+joglDrawable); System.err.println("-- Created Context: "+joglContext); } } else if (factory.canCreateContextOnJava2DSurface(device)) { // Mac OS X code path - // FIXME: Need to share with j2d context, due to FBO resource .. - // - ORIG: joglContext = factory.createContextOnJava2DSurface(g, shareWith); joglContext = factory.createContextOnJava2DSurface(g, j2dContext); - if (DEBUG||VERBOSE) { + joglContext.setSynchronized(true); + if (DEBUG) { System.err.println("-- Created Context: "+joglContext); } } @@ -1694,7 +1668,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing checkedForFBObjectWorkarounds=true; fbObjectWorkarounds = true; createNewDepthBuffer = true; - if (DEBUG || VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: Fetched ERR GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]+" - NOT A FBO"+ ", frame_buffer_object workarounds to be necessary"); } @@ -1713,7 +1687,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing GL.GL_COLOR_ATTACHMENT0, GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, frameBufferTexture, 0); - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("GLJPanel: FBO COLOR_ATTACHMENT0: " + frameBufferTexture[0]); } } diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java index 2fa708404..bc9a93042 100644 --- a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java +++ b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java @@ -79,7 +79,7 @@ public class GlyphString { * @param shape is not null, add all {@link GlyphShape}'s {@link Outline} to this instance. * @param vertexFactory vertex impl factory {@link Factory} * @param font the target {@link Font} - * @param size font size + * @param fontSize font size * @param str string text * @return the created {@link GlyphString} instance */ diff --git a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java index 2d2d1c536..ff49303ca 100644 --- a/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java +++ b/src/jogl/classes/jogamp/opengl/DesktopGLDynamicLookupHelper.java @@ -42,7 +42,7 @@ public class DesktopGLDynamicLookupHelper extends GLDynamicLookupHelper { public synchronized boolean loadGLULibrary() { /** hacky code .. where all platform GLU libs are tried ..*/ if(null==gluLib) { - List/*<String>*/ gluLibNames = new ArrayList(); + List<String> gluLibNames = new ArrayList<String>(); gluLibNames.add("/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib"); // osx gluLibNames.add("libGLU.so"); // unix gluLibNames.add("GLU32"); // windows diff --git a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java index 96d62fbb3..27569d210 100644 --- a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java +++ b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java @@ -28,6 +28,8 @@ package jogamp.opengl; import java.io.PrintStream; +import java.util.concurrent.TimeUnit; + import javax.media.opengl.FPSCounter; /** @@ -55,7 +57,7 @@ public class FPSCounterImpl implements FPSCounter { public final synchronized void tickFPS() { fpsTotalFrames++; if(fpsUpdateFramesInterval>0 && fpsTotalFrames%fpsUpdateFramesInterval == 0) { - final long now = System.currentTimeMillis(); + final long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); fpsLastPeriod = now - fpsLastUpdateTime; fpsLastPeriod = Math.max(fpsLastPeriod, 1); // div 0 fpsLast = ( (float)fpsUpdateFramesInterval * 1000f ) / ( (float) fpsLastPeriod ) ; @@ -96,7 +98,7 @@ public class FPSCounterImpl implements FPSCounter { } public final synchronized void resetFPSCounter() { - fpsStartTime = System.currentTimeMillis(); // overwrite startTime to real init one + fpsStartTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); // overwrite startTime to real init one fpsLastUpdateTime = fpsStartTime; fpsLastPeriod = 0; fpsTotalFrames = 0; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 58f1bf1cd..e87d283eb 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -47,8 +47,6 @@ import java.util.Map; import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; import com.jogamp.gluegen.runtime.FunctionAddressResolver; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLExtensionNames; @@ -69,11 +67,8 @@ import javax.media.opengl.GLPipelineFactory; import javax.media.opengl.GLProfile; public abstract class GLContextImpl extends GLContext { - public static final boolean DEBUG = Debug.debug("GLContext"); - - // RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock. - protected RecursiveLock lock = LockFactory.createRecursiveLock(); - + public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true); + /** * Context full qualified name: display_type + display_connection + major + minor + ctp. * This is the key for all cached GL ProcAddressTables, etc, to support multi display/device setups. @@ -113,6 +108,12 @@ public abstract class GLContextImpl extends GLContext { mappedGLXProcAddress = new HashMap<String, ProcAddressTable>(); } + public static void shutdownImpl() { + mappedExtensionAvailabilityCache.clear(); + mappedGLProcAddress.clear(); + mappedGLXProcAddress.clear(); + } + public GLContextImpl(GLDrawableImpl drawable, GLContext shareWith) { super(); @@ -209,74 +210,94 @@ public abstract class GLContextImpl extends GLContext { */ protected void drawableUpdatedNotify() throws GLException { } - boolean lockFailFast = true; - Object lockFailFastSync = new Object(); + volatile boolean lockFailFast = true; public boolean isSynchronized() { - synchronized (lockFailFastSync) { - return !lockFailFast; - } + return !lockFailFast; // volatile: ok } public void setSynchronized(boolean isSynchronized) { - synchronized (lockFailFastSync) { - lockFailFast = !isSynchronized; - } + lockFailFast = !isSynchronized; // volatile: ok } - private final void lockConsiderFailFast() { - synchronized (lockFailFastSync) { - if(lockFailFast && lock.isLockedByOtherThread()) { - throw new GLException("Error: Attempt to make context current on thread " + Thread.currentThread() + - " which is already current on thread " + lock.getOwner()); + private final void lockConsiderFailFast() { + if( lockFailFast ) { // volatile: ok + try { + if( !lock.tryLock(0) ) { // immediate return w/ false, if lock is already held by other thread + throw new GLException("Error: Attempt to make context current on thread " + Thread.currentThread().getName() + + " which is already current on thread " + lock.getOwner().getName()); + } + } catch (InterruptedException ie) { + throw new GLException(ie); } + } else { + lock.lock(); } - lock.lock(); } public abstract Object getPlatformGLExtensions(); // Note: the surface is locked within [makeCurrent .. swap .. release] public void release() throws GLException { + release(false); + } + private void release(boolean force) throws GLException { if ( !lock.isOwner() ) { throw new GLException("Context not current on current thread"); } - setCurrent(null); + final boolean actualRelease = force || lock.getHoldCount() == 1 ; try { - releaseImpl(); + if( actualRelease ) { + setCurrent(null); + if (contextHandle != 0) { // allow dbl-release + releaseImpl(); + } + } } finally { - if (drawable.isSurfaceLocked()) { - drawable.unlockSurface(); - } + drawable.unlockSurface(); lock.unlock(); + if(TRACE_SWITCH) { + if( actualRelease ) { + System.err.println("GLContext.ContextSwitch: - switch - CONTEXT_RELEASE - "+Thread.currentThread().getName()+" - "+lock); + } else { + System.err.println("GLContext.ContextSwitch: - keep - CONTEXT_RELEASE - "+Thread.currentThread().getName()+" - "+lock); + } + } } } protected abstract void releaseImpl() throws GLException; public final void destroy() { - if ( lock.isOwner() ) { - // release current context - if(null != glDebugHandler) { - glDebugHandler.enable(false); - } - release(); - } - // Must hold the lock around the destroy operation to make sure we // don't destroy the context out from under another thread rendering to it - lockConsiderFailFast(); + lockConsiderFailFast(); // holdCount++ -> 1 or 2 try { + if(lock.getHoldCount() > 2) { + throw new GLException("XXX: "+lock); + } + if (DEBUG || TRACE_SWITCH) { + System.err.println("GLContextImpl.destroy.0: " + toHexString(contextHandle) + + ", isShared "+GLContextShareSet.isShared(this)+" - "+lock); + } if (contextHandle != 0) { int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { // this would be odd .. throw new GLException("Surface not ready to lock: "+drawable); } - try { - if (DEBUG) { - System.err.println("GLContextImpl.destroy: " + toHexString(contextHandle) + - ", isShared "+GLContextShareSet.isShared(this)); + // release current context + if(null != glDebugHandler) { + if(lock.getHoldCount() == 1) { + // needs current context to disable debug handler + makeCurrent(); } + glDebugHandler.enable(false); + } + if(lock.getHoldCount() > 1) { + // pending release() after makeCurrent() + release(true); + } + try { destroyImpl(); contextHandle = 0; glDebugHandler = null; @@ -290,6 +311,10 @@ public abstract class GLContextImpl extends GLContext { } } finally { lock.unlock(); + if (DEBUG || TRACE_SWITCH) { + System.err.println("GLContextImpl.destroy.X: " + toHexString(contextHandle) + + ", isShared "+GLContextShareSet.isShared(this)+" - "+lock); + } } resetStates(); @@ -321,7 +346,10 @@ public abstract class GLContextImpl extends GLContext { // /** - * MakeCurrent functionality, which also issues the creation of the actual OpenGL context.<br> + * {@inheritDoc} + * <p> + * MakeCurrent functionality, which also issues the creation of the actual OpenGL context. + * </p> * The complete callgraph for general OpenGL context creation is:<br> * <ul> * <li> {@link #makeCurrent} <i>GLContextImpl</i></li> @@ -355,55 +383,75 @@ public abstract class GLContextImpl extends GLContext { * @see #destroyContextARBImpl */ public int makeCurrent() throws GLException { - // One context can only be current by one thread, - // and one thread can only have one context current! - GLContext current = getCurrent(); - if (current != null) { - if (current == this) { - // Assume we don't need to make this context current again - // For Mac OS X, however, we need to update the context to track resizes - drawableUpdatedNotify(); - return CONTEXT_CURRENT; - } else { - current.release(); - } - } - - if (GLWorkerThread.isStarted() && - !GLWorkerThread.isWorkerThread()) { - // Kick the GLWorkerThread off its current context - GLWorkerThread.invokeLater(new Runnable() { public void run() {} }); - } - - if (!isCreated()) { - // verify if the drawable has chosen Capabilities - if (null == getGLDrawable().getChosenGLCapabilities()) { - throw new GLException("drawable has no chosen GLCapabilities: "+getGLDrawable()); - } - if(DEBUG_GL) { - // only impacts w/ createContextARB(..) - additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ; - } - } - + boolean unlockContextAndDrawable = false; lockConsiderFailFast(); - int res = 0; + int res = CONTEXT_NOT_CURRENT; try { - res = makeCurrentLocking(); - - /* FIXME: refactor dependence on Java 2D / JOGL bridge - if ((tracker != null) && - (res == CONTEXT_CURRENT_NEW)) { - // Increase reference count of GLObjectTracker - tracker.ref(); - } - */ - } catch (GLException e) { - lock.unlock(); - throw(e); + // Note: the surface is locked within [makeCurrent .. swap .. release] + int lockRes = drawable.lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + return CONTEXT_NOT_CURRENT; + } + try { + if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) { + drawable.updateHandle(); + } + // One context can only be current by one thread, + // and one thread can only have one context current! + final GLContext current = getCurrent(); + if (current != null) { + if (current == this) { + // Assume we don't need to make this context current again + // For Mac OS X, however, we need to update the context to track resizes + drawableUpdatedNotify(); + if(TRACE_SWITCH) { + System.err.println("GLContext.ContextSwitch: - keep - CONTEXT_CURRENT - "+Thread.currentThread().getName()+" - "+lock); + } + return CONTEXT_CURRENT; + } else { + current.release(); + } + } + if (GLWorkerThread.isStarted() && + !GLWorkerThread.isWorkerThread()) { + // Kick the GLWorkerThread off its current context + GLWorkerThread.invokeLater(new Runnable() { public void run() {} }); + } + + if (0 == drawable.getHandle()) { + throw new GLException("drawable has invalid handle: "+drawable); + } + res = makeCurrentWithinLock(lockRes); + unlockContextAndDrawable = CONTEXT_NOT_CURRENT == res; + + /** + * FIXME: refactor dependence on Java 2D / JOGL bridge + if ((tracker != null) && + (res == CONTEXT_CURRENT_NEW)) { + // Increase reference count of GLObjectTracker + tracker.ref(); + } + */ + } catch (RuntimeException e) { + unlockContextAndDrawable = true; + throw e; + } finally { + if (unlockContextAndDrawable) { + drawable.unlockSurface(); + } + } + } catch (RuntimeException e) { + unlockContextAndDrawable = true; + throw e; + } finally { + if (unlockContextAndDrawable) { + lock.unlock(); + } } if (res == CONTEXT_NOT_CURRENT) { - lock.unlock(); + if(TRACE_SWITCH) { + System.err.println("GLContext.ContextSwitch: - switch - CONTEXT_NOT_CURRENT - "+Thread.currentThread().getName()+" - "+lock); + } } else { setCurrent(this); if(res == CONTEXT_CURRENT_NEW) { @@ -422,6 +470,11 @@ public abstract class GLContextImpl extends GLContext { if(TRACE_GL) { gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } + if(TRACE_SWITCH) { + System.err.println("GLContext.ContextSwitch: - switch - CONTEXT_CURRENT_NEW - "+Thread.currentThread().getName()+" - "+lock); + } + } else if(TRACE_SWITCH) { + System.err.println("GLContext.ContextSwitch: - switch - CONTEXT_CURRENT - "+Thread.currentThread().getName()+" - "+lock); } /* FIXME: refactor dependence on Java 2D / JOGL bridge @@ -436,71 +489,76 @@ public abstract class GLContextImpl extends GLContext { return res; } - // Note: the surface is locked within [makeCurrent .. swap .. release] - protected final int makeCurrentLocking() throws GLException { - boolean shallUnlockSurface = false; - int lockRes = drawable.lockSurface(); - try { - if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { - return CONTEXT_NOT_CURRENT; - } - try { - if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) { - drawable.updateHandle(); - } - if (0 == drawable.getHandle()) { - throw new GLException("drawable has invalid handle: "+drawable); - } - boolean newCreated = false; - if (!isCreated()) { - GLProfile.initProfiles( - getGLDrawable().getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice()); - newCreated = createImpl(); // may throws exception if fails! - if (DEBUG) { - if(newCreated) { - System.err.println(getThreadName() + ": !!! Create GL context OK: " + toHexString(contextHandle) + " for " + getClass().getName()); - } else { - System.err.println(getThreadName() + ": !!! Create GL context FAILED for " + getClass().getName()); - } - } - if(!newCreated) { - shallUnlockSurface = true; - return CONTEXT_NOT_CURRENT; + private final int makeCurrentWithinLock(int surfaceLockRes) throws GLException { + if (!isCreated()) { + if(DEBUG_GL) { + // only impacts w/ createContextARB(..) + additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ; + } + + final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getShareContext(this); + if (null != shareWith) { + shareWith.getDrawableImpl().lockSurface(); + } + final boolean created; + try { + created = createImpl(shareWith); // may throws exception if fails! + } finally { + if (null != shareWith) { + shareWith.getDrawableImpl().unlockSurface(); + } + } + if (DEBUG) { + if(created) { + System.err.println(getThreadName() + ": !!! Create GL context OK: " + toHexString(contextHandle) + " for " + getClass().getName()); + } else { + System.err.println(getThreadName() + ": !!! Create GL context FAILED for " + getClass().getName()); } - GLContextShareSet.contextCreated(this); - } - makeCurrentImpl(newCreated); - return newCreated ? CONTEXT_CURRENT_NEW : CONTEXT_CURRENT ; - } catch (RuntimeException e) { - shallUnlockSurface = true; - throw e; - } - } finally { - if (shallUnlockSurface) { - drawable.unlockSurface(); + } + if(!created) { + return CONTEXT_NOT_CURRENT; + } + GLContextShareSet.contextCreated(this); + return CONTEXT_CURRENT_NEW; } - } + makeCurrentImpl(); + return CONTEXT_CURRENT; } - protected abstract void makeCurrentImpl(boolean newCreatedContext) throws GLException; - protected abstract boolean createImpl() throws GLException ; + protected abstract void makeCurrentImpl() throws GLException; + + /** + * Platform dependent entry point for context creation.<br> + * + * This method is called from {@link #makeCurrentWithinLock()} .. {@link #makeCurrent()} .<br> + * + * The implementation shall verify this context with a + * <code>MakeContextCurrent</code> call.<br> + * + * The implementation <b>must</b> leave the context current.<br> + * + * @param share the shared context or null + * @return the valid and current context if successful, or null + * @throws GLException + */ + protected abstract boolean createImpl(GLContextImpl sharedWith) throws GLException ; /** * Platform dependent but harmonized implementation of the <code>ARB_create_context</code> * mechanism to create a context.<br> * - * This method is called from {@link #createContextARB}.<br> + * This method is called from {@link #createContextARB}, {@link #createImpl(GLContextImpl)} .. {@link #makeCurrent()} .<br> * * The implementation shall verify this context with a * <code>MakeContextCurrent</code> call.<br> * - * The implementation shall leave the context current.<br> + * The implementation <b>must</b> leave the context current.<br> * * @param share the shared context or null * @param direct flag if direct is requested * @param ctxOptionFlags <code>ARB_create_context</code> related, see references below * @param major major number * @param minor minor number - * @return the valid context if successfull, or null + * @return the valid and current context if successful, or null * * @see #makeCurrent * @see #CTX_PROFILE_COMPAT @@ -548,7 +606,7 @@ public abstract class GLContextImpl extends GLContext { */ protected final long createContextARB(long share, boolean direct) { - AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); GLProfile glp = glCaps.getGLProfile(); @@ -583,7 +641,7 @@ public abstract class GLContextImpl extends GLContext { _ctp[0] |= additionalCtxCreationFlags; _ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]); if(0!=_ctx) { - setGLFunctionAvailability(true, true, _major[0], _minor[0], _ctp[0]); + setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0]); } } return _ctx; @@ -654,12 +712,11 @@ public abstract class GLContextImpl extends GLContext { } } if(0!=_context) { - AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); if( isExtensionAvailable("GL_ARB_ES2_compatibility") ) { ctp |= CTX_PROFILE_ES2_COMPAT; } GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, major[0], minor[0], ctp); - setGLFunctionAvailability(true, true, major[0], minor[0], ctp); destroyContextARBImpl(_context); if (DEBUG) { System.err.println(getThreadName() + ": !!! createContextARBMapVersionsAvailable HAVE: "+ @@ -677,8 +734,9 @@ public abstract class GLContextImpl extends GLContext { major[0]=majorMax; minor[0]=minorMax; long _context=0; + boolean ok = false; - while ( 0==_context && + while ( !ok && GLContext.isValidGLVersion(major[0], minor[0]) && ( major[0]>majorMin || major[0]==majorMin && minor[0] >=minorMin ) ) { @@ -687,15 +745,20 @@ public abstract class GLContextImpl extends GLContext { } _context = createContextARBImpl(share, direct, ctxOptionFlags, major[0], minor[0]); - boolean ok = 0!=_context; + if(0 != _context) { + ok = true; + setGLFunctionAvailability(true, major[0], minor[0], ctxOptionFlags); + } else { + ok = false; + } if(ok && major[0]>=3) { int[] hasMajor = new int[1]; int[] hasMinor = new int[1]; - setGLFunctionAvailability(true, false, major[0], minor[0], ctxOptionFlags); gl.glGetIntegerv(GL3.GL_MAJOR_VERSION, hasMajor, 0); gl.glGetIntegerv(GL3.GL_MINOR_VERSION, hasMinor, 0); ok = hasMajor[0]>major[0] || ( hasMajor[0]==major[0] && hasMinor[0]>=minor[0] ) ; if(!ok) { + removeCachedVersion(major[0], minor[0], ctxOptionFlags); destroyContextARBImpl(_context); _context = 0; } @@ -703,6 +766,7 @@ public abstract class GLContextImpl extends GLContext { System.err.println(getThreadName() + ": createContextARBVersions: version verification - expected "+major[0]+"."+minor[0]+", has "+hasMajor[0]+"."+hasMinor[0]+" == "+ok); } } + if(!ok) { if(!GLContext.decrementGLVersion(major, minor)) break; } @@ -854,15 +918,15 @@ public abstract class GLContextImpl extends GLContext { * * @param force force the setting, even if is already being set. * This might be useful if you change the OpenGL implementation. - * @param cached whether this version's data shall be cached or not * @param major OpenGL major version * @param minor OpenGL minor version * @param ctxProfileBits OpenGL context profile and option bits, see {@link javax.media.opengl.GLContext#CTX_OPTION_ANY} + * * @see #setContextVersion * @see javax.media.opengl.GLContext#CTX_OPTION_ANY * @see javax.media.opengl.GLContext#CTX_PROFILE_COMPAT */ - protected final void setGLFunctionAvailability(boolean force, boolean cached, int major, int minor, int ctxProfileBits) { + protected final void setGLFunctionAvailability(boolean force, int major, int minor, int ctxProfileBits) { if(null!=this.gl && null!=glProcAddressTable && !force) { return; // already done and not forced } @@ -873,7 +937,7 @@ public abstract class GLContextImpl extends GLContext { updateGLXProcAddressTable(); - AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final int ctxImplBits = drawable.getChosenGLCapabilities().getHardwareAccelerated() ? GLContext.CTX_IMPL_ACCEL_HARD : GLContext.CTX_IMPL_ACCEL_SOFT; contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits, ctxImplBits); @@ -904,12 +968,10 @@ public abstract class GLContextImpl extends GLContext { new Object[] { new GLProcAddressResolver() } ); } resetProcAddressTable(getGLProcAddressTable()); - if(cached) { - synchronized(mappedContextTypeObjectLock) { - mappedGLProcAddress.put(contextFQN, getGLProcAddressTable()); - if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+getGLProcAddressTable().hashCode()); - } + synchronized(mappedContextTypeObjectLock) { + mappedGLProcAddress.put(contextFQN, getGLProcAddressTable()); + if(DEBUG) { + System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+getGLProcAddressTable().hashCode()); } } } @@ -919,34 +981,56 @@ public abstract class GLContextImpl extends GLContext { // setContextVersion(major, minor, ctxProfileBits); - if(cached) { - // - // Update ExtensionAvailabilityCache - // - ExtensionAvailabilityCache eCache; - synchronized(mappedContextTypeObjectLock) { - eCache = mappedExtensionAvailabilityCache.get( contextFQN ); + // + // Update ExtensionAvailabilityCache + // + ExtensionAvailabilityCache eCache; + synchronized(mappedContextTypeObjectLock) { + eCache = mappedExtensionAvailabilityCache.get( contextFQN ); + } + if(null != eCache) { + extensionAvailability = eCache; + if(DEBUG) { + System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+eCache.hashCode()); + } + } else { + if(null==extensionAvailability) { + extensionAvailability = new ExtensionAvailabilityCache(this); } - if(null != eCache) { - extensionAvailability = eCache; + extensionAvailability.reset(); + synchronized(mappedContextTypeObjectLock) { + mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+eCache.hashCode()); - } - } else { - if(null==extensionAvailability) { - extensionAvailability = new ExtensionAvailabilityCache(this); - } - extensionAvailability.reset(); - synchronized(mappedContextTypeObjectLock) { - mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability); - if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+extensionAvailability.hashCode()); - } + System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+extensionAvailability.hashCode()); } } } } + protected final void removeCachedVersion(int major, int minor, int ctxProfileBits) { + AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); + AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + final int ctxImplBits = drawable.getChosenGLCapabilities().getHardwareAccelerated() ? GLContext.CTX_IMPL_ACCEL_HARD : GLContext.CTX_IMPL_ACCEL_SOFT; + contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits, ctxImplBits); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! RM Context FQN: "+contextFQN); + } + + synchronized(mappedContextTypeObjectLock) { + ProcAddressTable table = mappedGLProcAddress.remove( contextFQN ); + if(DEBUG) { + System.err.println(getThreadName() + ": !!! RM GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+table.hashCode()); + } + } + + synchronized(mappedContextTypeObjectLock) { + ExtensionAvailabilityCache eCache = mappedExtensionAvailabilityCache.get( contextFQN ); + if(DEBUG) { + System.err.println(getThreadName() + ": !!! RM GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+eCache.hashCode()); + } + } + } + /** * Updates the platform's 'GLX' function cache */ diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java index 8ca0c016d..b950c2fdf 100644 --- a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -35,6 +35,7 @@ import javax.media.opengl.GLDebugListener; import javax.media.opengl.GLDebugMessage; import javax.media.opengl.GLException; +import com.jogamp.common.os.Platform; import com.jogamp.gluegen.runtime.ProcAddressTable; import jogamp.opengl.gl4.GL4bcProcAddressTable; @@ -122,7 +123,14 @@ public class GLDebugMessageHandler { } return; } - + if(Platform.OS_TYPE == Platform.OSType.WINDOWS && Platform.is32Bit()) { + // Currently buggy, ie. throws an exception after leaving the native callback. + // Probably a 32bit on 64bit JVM / OpenGL-driver issue. + if(DEBUG) { + System.err.println("GLDebugMessageHandler: Windows 32bit currently not supported!"); + } + return; + } if( ctx.isExtensionAvailable(GL_ARB_debug_output) ) { extName = GL_ARB_debug_output; extType = EXT_ARB; @@ -199,7 +207,7 @@ public class GLDebugMessageHandler { */ public final void setSynchronous(boolean synchronous) { this.synchronous = synchronous; - if(isEnabled() && isExtensionARB()) { + if( isEnabled() ) { setSynchronousImpl(); } } @@ -227,9 +235,9 @@ public class GLDebugMessageHandler { enableImpl(enable); } final void enableImpl(boolean enable) throws GLException { - setSynchronousImpl(); if(enable) { if(0 == handle) { + setSynchronousImpl(); handle = register0(glDebugMessageCallbackProcAddress, extType); if(0 == handle) { throw new GLException("Failed to register via \"glDebugMessageCallback*\" using "+extName); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 704f71457..e5f415a87 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -40,11 +40,25 @@ package jogamp.opengl; -import java.nio.*; -import javax.media.nativewindow.*; -import javax.media.opengl.*; - -import com.jogamp.common.util.VersionNumber; +import java.nio.Buffer; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.SurfaceChangeable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.MutableGraphicsConfiguration; /** Extends GLDrawableFactory with a few methods for handling typically software-accelerated offscreen rendering (Device @@ -53,17 +67,28 @@ import com.jogamp.common.util.VersionNumber; they may be instantiated by the GLJPanel implementation. */ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { protected static final boolean DEBUG = GLDrawableImpl.DEBUG; - public static final VersionNumber versionOneZero = new VersionNumber(1, 0, 0); - public static final VersionNumber versionOneOne = new VersionNumber(1, 1, 0); - public static final VersionNumber versionOneTwo = new VersionNumber(1, 2, 0); - public static final VersionNumber versionOneThree = new VersionNumber(1, 3, 0); - public static final VersionNumber versionOneFour = new VersionNumber(1, 4, 0); protected GLDrawableFactoryImpl() { super(); } /** + * Returns the shared context mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, + * either a pre-existing or newly created, or <code>null</code> if creation failed or not supported.<br> + * Creation of the shared context is tried only once. + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + */ + public final GLContext getOrCreateSharedContext(AbstractGraphicsDevice device) { + device = validateDevice(device); + if(null!=device) { + return getOrCreateSharedContextImpl(device); + } + return null; + } + protected abstract GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device); + + /** * Returns the shared device mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, * either a preexisting or newly created, or <code>null</code> if creation failed or not supported.<br> * Creation of the shared context is tried only once. @@ -103,24 +128,40 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); AbstractGraphicsDevice adevice = config.getScreen().getDevice(); GLDrawable result = null; adevice.lock(); try { - if(caps.isOnscreen()) { + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true); + if(null != ols) { + // layered surface -> Offscreen/PBuffer + final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable(); + chosenCapsMod.setOnscreen(false); + chosenCapsMod.setPBuffer(canCreateGLPbuffer(adevice)); + config.setChosenCapabilities(chosenCapsMod); + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target); + } + if( ! ( target instanceof SurfaceChangeable ) ) { + throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); + } + result = createOffscreenDrawableImpl(target); + } else if(chosenCaps.isOnscreen()) { + // onscreen if(DEBUG) { System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); } result = createOnscreenDrawableImpl(target); } else { + // offscreen + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+chosenCaps.isPBuffer()+"): "+target); + } if( ! ( target instanceof SurfaceChangeable ) ) { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target); } - if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+caps.isPBuffer()+"): "+target); - } result = createOffscreenDrawableImpl(target); } } finally { @@ -171,6 +212,9 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { device.lock(); try { drawable = (GLDrawableImpl) createGLDrawable( createOffscreenSurfaceImpl(device, capsChosen, capsRequested, chooser, width, height) ); + if(null != drawable) { + drawable.setRealized(true); + } } finally { device.unlock(); } @@ -287,15 +331,6 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // GLDrawableFactoryImpl details // - protected void maybeDoSingleThreadedWorkaround(Runnable action) { - if (Threading.isSingleThreaded() && - !Threading.isOpenGLThread()) { - Threading.invokeOnOpenGLThread(action); - } else { - action.run(); - } - } - /** * Returns the sole GLDrawableFactoryImpl instance. * diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 151ec2e9c..509839f55 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -40,8 +40,16 @@ package jogamp.opengl; -import java.util.*; -import javax.media.opengl.*; +import java.util.ArrayList; +import java.util.HashSet; + +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLRunnable; import com.jogamp.opengl.util.Animator; @@ -49,6 +57,9 @@ import com.jogamp.opengl.util.Animator; methods to be able to share it between GLCanvas and GLJPanel. */ public class GLDrawableHelper { + /** true if property <code>jogl.debug.GLDrawable.PerfStats</code> is defined. */ + private static final boolean PERF_STATS = Debug.isPropertyDefined("jogl.debug.GLDrawable.PerfStats", true); + protected static final boolean DEBUG = GLDrawableImpl.DEBUG; private Object listenersLock = new Object(); private ArrayList<GLEventListener> listeners; @@ -120,6 +131,10 @@ public class GLDrawableHelper { /** * Issues {@link javax.media.opengl.GLEventListener#dispose(javax.media.opengl.GLAutoDrawable)} * to all listeners. + * <p> + * Please consider using {@link #disposeGL(GLAutoDrawable, GLDrawable, GLContext, Runnable)} + * for correctness! + * </p> * @param drawable */ public final void dispose(GLAutoDrawable drawable) { @@ -129,12 +144,12 @@ public class GLDrawableHelper { } } } - + private boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { if(listenersToBeInit.remove(l)) { l.init(drawable); if(sendReshape) { - reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */); + reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false); } return true; } @@ -177,7 +192,12 @@ public class GLDrawableHelper { } private void reshape(GLEventListener listener, GLAutoDrawable drawable, - int x, int y, int width, int height, boolean setViewport) { + int x, int y, int width, int height, boolean setViewport, boolean checkInit) { + if(checkInit) { + // GLEventListener may need to be init, + // in case this one is added after the realization of the GLAutoDrawable + init( listener, drawable, false ) ; + } if(setViewport) { drawable.getGL().glViewport(x, y, width, height); } @@ -187,7 +207,7 @@ public class GLDrawableHelper { public final void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { synchronized(listenersLock) { for (int i=0; i < listeners.size(); i++) { - reshape((GLEventListener) listeners.get(i), drawable, x, y, width, height, 0==i); + reshape((GLEventListener) listeners.get(i), drawable, x, y, width, height, 0==i, true); } } } @@ -294,6 +314,8 @@ public class GLDrawableHelper { * ie. {@link Animator#getThread()}. * @deprecated this is an experimental feature, * intended for measuring performance in regards to GL context switch + * and only being used if {@link #PERF_STATS} is enabled + * by defining property <code>jogl.debug.GLDrawable.PerfStats</code>. */ public final void setSkipContextReleaseThread(Thread t) { skipContextReleaseThread = t; @@ -305,7 +327,7 @@ public class GLDrawableHelper { public final Thread getSkipContextReleaseThread() { return skipContextReleaseThread; } - + private static final ThreadLocal<Runnable> perThreadInitAction = new ThreadLocal<Runnable>(); /** Principal helper method which runs a Runnable with the context @@ -315,8 +337,6 @@ public class GLDrawableHelper { class helps ensure that we don't inadvertently use private methods of the GLContext or its implementing classes.<br> * <br> - * Remark: In case this method is called to dispose the GLDrawable/GLAutoDrawable, - * <code>initAction</code> shall be <code>null</code> to mark this cause.<br> * * @param drawable * @param context @@ -335,13 +355,112 @@ public class GLDrawableHelper { return; } - if(null==initAction) { - // disposal case - if(!context.isCreated()) { - throw new GLException(Thread.currentThread().getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context is not created: "+context); - } + if(PERF_STATS) { + invokeGLImplStats(drawable, context, runnable, initAction, null); + } else { + invokeGLImpl(drawable, context, runnable, initAction, null); } + } + /** + * Principal helper method which runs {@link #dispose(GLAutoDrawable)} with the context + * made current and destroys the context afterwards while holding the lock. + * + * @param autoDrawable + * @param drawable + * @param context + * @param postAction + */ + public final void disposeGL(GLAutoDrawable autoDrawable, + GLDrawable drawable, + GLContext context, + Runnable postAction) { + if(PERF_STATS) { + invokeGLImplStats(drawable, context, null, null, autoDrawable); + } else { + invokeGLImpl(drawable, context, null, null, autoDrawable); + } + if(null != postAction) { + postAction.run(); + } + } + + private final void invokeGLImpl(GLDrawable drawable, + GLContext context, + Runnable runnable, + Runnable initAction, + GLAutoDrawable disposeAutoDrawable) { + final Thread currentThread = Thread.currentThread(); + + final boolean isDisposeAction = null==initAction ; + + // Support for recursive makeCurrent() calls as well as calling + // other drawables' display() methods from within another one's + GLContext lastContext = GLContext.getCurrent(); + Runnable lastInitAction = null; + if (lastContext != null) { + if (lastContext == context) { + lastContext = null; // utilize recursive locking + } else { + lastInitAction = perThreadInitAction.get(); + lastContext.release(); + } + } + int res = GLContext.CONTEXT_NOT_CURRENT; + + try { + res = context.makeCurrent(); + if (res != GLContext.CONTEXT_NOT_CURRENT) { + if(!isDisposeAction) { + perThreadInitAction.set(initAction); + if (res == GLContext.CONTEXT_CURRENT_NEW) { + if (DEBUG) { + System.err.println("GLDrawableHelper " + this + ".invokeGL(): Running initAction"); + } + initAction.run(); + } + runnable.run(); + if (autoSwapBufferMode) { + drawable.swapBuffers(); + } + } else { + if(res == GLContext.CONTEXT_CURRENT_NEW) { + throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); + } + if(listeners.size()>0) { + dispose(disposeAutoDrawable); + } + } + } + } finally { + try { + if(isDisposeAction) { + context.destroy(); + } else if( res != GLContext.CONTEXT_NOT_CURRENT ) { + context.release(); + } + } catch (Exception e) { + System.err.println("Catched: "+e.getMessage()); + e.printStackTrace(); + } + if (lastContext != null) { + final int res2 = lastContext.makeCurrent(); + if (null != lastInitAction && res2 == GLContext.CONTEXT_CURRENT_NEW) { + lastInitAction.run(); + } + } + } + } + + private final void invokeGLImplStats(GLDrawable drawable, + GLContext context, + Runnable runnable, + Runnable initAction, + GLAutoDrawable disposeAutoDrawable) { + final Thread currentThread = Thread.currentThread(); + + final boolean isDisposeAction = null==initAction ; + // Support for recursive makeCurrent() calls as well as calling // other drawables' display() methods from within another one's int res = GLContext.CONTEXT_NOT_CURRENT; @@ -349,7 +468,9 @@ public class GLDrawableHelper { Runnable lastInitAction = null; if (lastContext != null) { if (lastContext == context) { - res = GLContext.CONTEXT_CURRENT; + if( currentThread == skipContextReleaseThread ) { + res = GLContext.CONTEXT_CURRENT; + } // else: utilize recursive locking lastContext = null; } else { lastInitAction = perThreadInitAction.get(); @@ -357,20 +478,21 @@ public class GLDrawableHelper { } } - /** long t0 = System.currentTimeMillis(); - long td1 = 0; // makeCurrent + long tdA = 0; // makeCurrent long tdR = 0; // render time - long td2 = 0; // swapBuffers - long td3 = 0; // release - boolean scr = true; */ - + long tdS = 0; // swapBuffers + long tdX = 0; // release + boolean ctxClaimed = false; + boolean ctxReleased = false; + boolean ctxDestroyed = false; try { if (res == GLContext.CONTEXT_NOT_CURRENT) { res = context.makeCurrent(); + ctxClaimed = true; } if (res != GLContext.CONTEXT_NOT_CURRENT) { - if(null!=initAction) { + if(!isDisposeAction) { perThreadInitAction.set(initAction); if (res == GLContext.CONTEXT_CURRENT_NEW) { if (DEBUG) { @@ -378,41 +500,50 @@ public class GLDrawableHelper { } initAction.run(); } - } - // tdR = System.currentTimeMillis(); - // td1 = tdR - t0; // makeCurrent - if(null!=runnable) { + tdR = System.currentTimeMillis(); + tdA = tdR - t0; // makeCurrent runnable.run(); - // td2 = System.currentTimeMillis(); - // tdR = td2 - tdR; // render time - if (autoSwapBufferMode && null != initAction) { - if (drawable != null) { + tdS = System.currentTimeMillis(); + tdR = tdS - tdR; // render time + if (autoSwapBufferMode) { drawable.swapBuffers(); - // td3 = System.currentTimeMillis(); - // td2 = td3 - td2; // swapBuffers - } + tdX = System.currentTimeMillis(); + tdS = tdX - tdS; // swapBuffers + } + } else { + if(res == GLContext.CONTEXT_CURRENT_NEW) { + throw new GLException(currentThread.getName()+" GLDrawableHelper " + this + ".invokeGL(): Dispose case (no init action given): Native context was not created (new ctx): "+context); + } + if(listeners.size()>0) { + dispose(disposeAutoDrawable); } } } } finally { - if(res != GLContext.CONTEXT_NOT_CURRENT && - (null == skipContextReleaseThread || Thread.currentThread()!=skipContextReleaseThread) ) { - try { + try { + if(isDisposeAction) { + context.destroy(); + ctxDestroyed = true; + } else if( res != GLContext.CONTEXT_NOT_CURRENT && + (null == skipContextReleaseThread || currentThread != skipContextReleaseThread) ) { context.release(); - // scr = false; - } catch (Exception e) { + ctxReleased = true; } + } catch (Exception e) { + System.err.println("Catched: "+e.getMessage()); + e.printStackTrace(); } - // td3 = System.currentTimeMillis() - td3; // release + + tdX = System.currentTimeMillis() - tdX; // release / destroy if (lastContext != null) { - int res2 = lastContext.makeCurrent(); + final int res2 = lastContext.makeCurrent(); if (null != lastInitAction && res2 == GLContext.CONTEXT_CURRENT_NEW) { lastInitAction.run(); } } } - // long td0 = System.currentTimeMillis() - t0; - // System.err.println("td0 "+td0+"ms, fps "+(1.0/(td0/1000.0))+", td-makeCurrent: "+td1+"ms, td-render "+tdR+"ms, td-swap "+td2+"ms, td-release "+td3+"ms, skip ctx release: "+scr); + long td = System.currentTimeMillis() - t0; + System.err.println("td0 "+td+"ms, fps "+(1.0/(td/1000.0))+", td-makeCurrent: "+tdA+"ms, td-render "+tdR+"ms, td-swap "+tdS+"ms, td-release "+tdX+"ms, ctx claimed: "+ctxClaimed+", ctx release: "+ctxReleased+", ctx destroyed "+ctxDestroyed); } - + } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 58c9aaaa6..b9c216eab 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -40,8 +40,14 @@ package jogamp.opengl; -import javax.media.nativewindow.*; -import javax.media.opengl.*; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; public abstract class GLDrawableImpl implements GLDrawable { protected static final boolean DEBUG = Debug.debug("GLDrawable"); @@ -52,7 +58,7 @@ public abstract class GLDrawableImpl implements GLDrawable { this.factory = factory; this.surface = comp; this.realized = realized; - this.requestedCapabilities = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getNativeGraphicsConfiguration().getRequestedCapabilities(); + this.requestedCapabilities = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getRequestedCapabilities(); } /** @@ -79,7 +85,7 @@ public abstract class GLDrawableImpl implements GLDrawable { } public final void swapBuffers() throws GLException { - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getChosenCapabilities(); if ( caps.getDoubleBuffered() ) { if(!surface.surfaceSwap()) { int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release] @@ -114,7 +120,7 @@ public abstract class GLDrawableImpl implements GLDrawable { } public GLCapabilitiesImmutable getChosenGLCapabilities() { - return (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + return (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); } public GLCapabilitiesImmutable getRequestedGLCapabilities() { @@ -125,7 +131,10 @@ public abstract class GLDrawableImpl implements GLDrawable { return surface; } + /** called with locked surface @ setRealized(false) */ protected void destroyHandle() {} + + /** called with locked surface @ setRealized(true) or @ lockSurface(..) when surface changed */ protected void updateHandle() {} public long getHandle() { diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java index 318d00637..6e2b7b744 100644 --- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java +++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java @@ -29,6 +29,7 @@ package jogamp.opengl; import java.util.ArrayList; + import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; @@ -86,6 +87,7 @@ public class GLGraphicsConfigurationUtil { return getWinAttributeBits(caps.isOnscreen(), caps.isPBuffer()); } + @SuppressWarnings({ "rawtypes", "unchecked" }) public static final boolean addGLCapabilitiesPermutations(ArrayList capsBucket, GLCapabilitiesImmutable temp, int winattrbits) { int preSize = capsBucket.size(); if( 0 != ( WINDOW_BIT & winattrbits ) ) { @@ -138,7 +140,7 @@ public class GLGraphicsConfigurationUtil { if( capsRequested.getDoubleBuffered() || capsRequested.isOnscreen() || !capsRequested.isPBuffer()) { // fix caps .. GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN + caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN - we don't need to be single buffered .. caps2.setOnscreen(false); caps2.setPBuffer(true); return caps2; diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index d667fa53a..10d5a3f27 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -42,6 +42,8 @@ package jogamp.opengl; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; + +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GL; import javax.media.opengl.GLAnimatorControl; @@ -70,7 +72,7 @@ public class GLPbufferImpl implements GLPbuffer { public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext parentContext) { GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) - pbufferDrawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + pbufferDrawable.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities(); if(caps.isOnscreen()) { if(caps.isPBuffer()) { throw new IllegalArgumentException("Error: Given drawable is Onscreen and Pbuffer: "+pbufferDrawable); @@ -97,26 +99,25 @@ public class GLPbufferImpl implements GLPbuffer { return true; } - class DisposeAction implements Runnable { - public void run() { - // Lock: Covered by DestroyAction .. - drawableHelper.dispose(GLPbufferImpl.this); - } - } - DisposeAction disposeAction = new DisposeAction(); - public void destroy() { if(pbufferDrawable.isRealized()) { + final AbstractGraphicsDevice adevice = pbufferDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); + if (null != context && context.isCreated()) { try { - drawableHelper.invokeGL(pbufferDrawable, context, disposeAction, null); + drawableHelper.disposeGL(GLPbufferImpl.this, pbufferDrawable, context, null); } catch (GLException gle) { gle.printStackTrace(); } - context.destroy(); + context = null; // drawableHelper.reset(); } pbufferDrawable.destroy(); + pbufferDrawable = null; + + if(null != adevice) { + adevice.close(); + } } } diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java index 2c396e265..a33e03a1a 100644 --- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java +++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java @@ -44,24 +44,28 @@ public class SharedResourceRunner implements Runnable { } public static interface Implementation { + /** + * @param connection for creation a {@link AbstractGraphicsDevice} instance. + * @return A new shared resource instance + */ Resource createSharedResource(String connection); void releaseSharedResource(Resource shared); void clear(); Resource mapPut(String connection, Resource resource); Resource mapGet(String connection); - Collection/*<Resource>*/ mapValues(); + Collection<Resource> mapValues(); } - Implementation impl = null; + final HashSet<String> devicesTried = new HashSet<String>(); + final Implementation impl; - boolean ready = false; - boolean released = false; - boolean shouldRelease = false; - String initConnection = null; - String releaseConnection = null; - - HashSet devicesTried = new HashSet(); + Thread thread; + boolean ready; + boolean released; + boolean shouldRelease; + String initConnection; + String releaseConnection; private boolean getDeviceTried(String connection) { synchronized (devicesTried) { @@ -81,22 +85,82 @@ public class SharedResourceRunner implements Runnable { public SharedResourceRunner(Implementation impl) { this.impl = impl; + resetState(); + } + + private void resetState() { + devicesTried.clear(); + thread = null; + ready = false; + released = false; + shouldRelease = false; + initConnection = null; + releaseConnection = null; } + /** + * Start the shared resource runner thread, if not running. + * <p> + * Validate the thread upfront and release all related resource if it was killed. + * </p> + * + * @return the shared resource runner thread. + */ + public Thread start() { + if(null != thread && !thread.isAlive()) { + // thread was killed unrecognized .. + if (DEBUG) { + System.err.println("SharedResourceRunner.start() - dead-old-thread cleanup - "+Thread.currentThread().getName()); + } + releaseSharedResources(); + thread = null; + } + if(null == thread) { + if (DEBUG) { + System.err.println("SharedResourceRunner.start() - start new Thread - "+Thread.currentThread().getName()); + } + resetState(); + thread = new Thread(this, Thread.currentThread().getName()+"-SharedResourceRunner"); + thread.setDaemon(true); // Allow JVM to exit, even if this one is running + thread.start(); + } + return thread; + } + + public void stop() { + if(null != thread) { + if (DEBUG) { + System.err.println("SharedResourceRunner.stop() - "+Thread.currentThread().getName()); + } + synchronized (this) { + shouldRelease = true; + this.notifyAll(); + + while (!released) { + try { + this.wait(); + } catch (InterruptedException ex) { + } + } + } + } + } + public SharedResourceRunner.Resource getOrCreateShared(AbstractGraphicsDevice device) { SharedResourceRunner.Resource sr = null; if(null != device) { - String connection = device.getConnection(); + start(); + final String connection = device.getConnection(); sr = impl.mapGet(connection); if (null == sr && !getDeviceTried(connection)) { addDeviceTried(connection); if (DEBUG) { - System.err.println("getOrCreateShared() " + connection + ": trying"); + System.err.println("SharedResourceRunner.getOrCreateShared() " + connection + ": trying - "+Thread.currentThread().getName()); } doAndWait(connection, null); sr = impl.mapGet(connection); if (DEBUG) { - System.err.println("getOrCreateShared() " + connection + ": "+ ( ( null != sr ) ? "success" : "failed" ) ); + System.err.println("SharedResourceRunner.getOrCreateShared() " + connection + ": "+ ( ( null != sr ) ? "success" : "failed" ) +" - "+Thread.currentThread().getName()); } } } @@ -111,11 +175,11 @@ public class SharedResourceRunner implements Runnable { if (null != sr) { removeDeviceTried(connection); if (DEBUG) { - System.err.println("releaseShared() " + connection + ": trying"); + System.err.println("SharedResourceRunner.releaseShared() " + connection + ": trying - "+Thread.currentThread().getName()); } doAndWait(null, connection); if (DEBUG) { - System.err.println("releaseShared() " + connection + ": done"); + System.err.println("SharedResourceRunner.releaseShared() " + connection + ": done - "+Thread.currentThread().getName()); } } } @@ -125,9 +189,9 @@ public class SharedResourceRunner implements Runnable { private final void doAndWait(String initConnection, String releaseConnection) { // wait until thread becomes ready to init new device, // pass the device and release the sync - String threadName = Thread.currentThread().getName(); + final String threadName = Thread.currentThread().getName(); if (DEBUG) { - System.err.println(threadName + " doAndWait START init: " + initConnection + ", release: "+releaseConnection); + System.err.println("SharedResourceRunner.doAndWait() START init: " + initConnection + ", release: "+releaseConnection+" - "+threadName); } synchronized (this) { while (!ready) { @@ -137,7 +201,7 @@ public class SharedResourceRunner implements Runnable { } } if (DEBUG) { - System.err.println(threadName + " initializeAndWait set command init: " + initConnection + ", release: "+releaseConnection); + System.err.println("SharedResourceRunner.doAndWait() set command: " + initConnection + ", release: "+releaseConnection+" - "+threadName); } this.initConnection = initConnection; this.releaseConnection = releaseConnection; @@ -151,31 +215,17 @@ public class SharedResourceRunner implements Runnable { } } if (DEBUG) { - System.err.println(threadName + " initializeAndWait END init: " + initConnection + ", release: "+releaseConnection); + System.err.println("SharedResourceRunner.initializeAndWait END init: " + initConnection + ", release: "+releaseConnection+" - "+threadName); } } // done } - public final void releaseAndWait() { - synchronized (this) { - shouldRelease = true; - this.notifyAll(); - - while (!released) { - try { - this.wait(); - } catch (InterruptedException ex) { - } - } - } - } - public final void run() { - String threadName = Thread.currentThread().getName(); + final String threadName = Thread.currentThread().getName(); if (DEBUG) { - System.err.println(threadName + " STARTED"); + System.err.println("SharedResourceRunner.run(): STARTED - " + threadName); } synchronized (this) { @@ -184,21 +234,27 @@ public class SharedResourceRunner implements Runnable { // wait for stop or init ready = true; if (DEBUG) { - System.err.println(threadName + " -> ready"); + System.err.println("SharedResourceRunner.run(): READY - " + threadName); } notifyAll(); this.wait(); - } catch (InterruptedException ex) { } + } catch (InterruptedException ex) { + shouldRelease = true; + if(DEBUG) { + System.err.println("SharedResourceRunner.run(): INTERRUPTED - "+Thread.currentThread().getName()); + ex.printStackTrace(); + } + } ready = false; if (!shouldRelease) { if (DEBUG) { - System.err.println(threadName + " woke up for device connection init: " + initConnection + - ", release: " + releaseConnection); + System.err.println("SharedResourceRunner.run(): WOKE UP for device connection init: " + initConnection + + ", release: " + releaseConnection + " - " + threadName); } if(null != initConnection) { if (DEBUG) { - System.err.println(threadName + " create Shared for: " + initConnection); + System.err.println("SharedResourceRunner.run(): create Shared for: " + initConnection + " - " + threadName); } Resource sr = null; try { @@ -212,7 +268,7 @@ public class SharedResourceRunner implements Runnable { } if(null != releaseConnection) { if (DEBUG) { - System.err.println(threadName + " release Shared for: " + releaseConnection); + System.err.println("SharedResourceRunner.run(): release Shared for: " + releaseConnection + " - " + threadName); } Resource sr = impl.mapGet(releaseConnection); if (null != sr) { @@ -230,26 +286,34 @@ public class SharedResourceRunner implements Runnable { } if (DEBUG) { - System.err.println(threadName + " release START"); + System.err.println("SharedResourceRunner.run(): RELEASE START - " + threadName); } releaseSharedResources(); if (DEBUG) { - System.err.println(threadName + " release END"); + System.err.println("SharedResourceRunner.run(): RELEASE END - " + threadName); } + shouldRelease = false; released = true; - ready = false; + thread = null; notifyAll(); } } private void releaseSharedResources() { - Collection/*<Resource>*/ sharedResources = impl.mapValues(); - for (Iterator iter = sharedResources.iterator(); iter.hasNext();) { - Resource sr = (Resource) iter.next(); - impl.releaseSharedResource(sr); + synchronized (devicesTried) { + devicesTried.clear(); + } + Collection<Resource> sharedResources = impl.mapValues(); + for (Iterator<Resource> iter = sharedResources.iterator(); iter.hasNext();) { + try { + impl.releaseSharedResource(iter.next()); + } catch (Throwable t) { + System.err.println("Catched Exception: "+t.getStackTrace()+" - "+Thread.currentThread().getName()); + t.printStackTrace(); + } } impl.clear(); } diff --git a/src/jogl/classes/jogamp/opengl/awt/Java2D.java b/src/jogl/classes/jogamp/opengl/awt/Java2D.java index e240169e1..3e4a6a147 100644 --- a/src/jogl/classes/jogamp/opengl/awt/Java2D.java +++ b/src/jogl/classes/jogamp/opengl/awt/Java2D.java @@ -39,23 +39,32 @@ package jogamp.opengl.awt; -import jogamp.opengl.*; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Rectangle; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.opengl.Debug; -import java.awt.*; -import java.awt.image.*; -import java.lang.reflect.*; -import java.security.*; - -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import javax.media.nativewindow.awt.*; /** Defines integration with the Java2D OpenGL pipeline. This integration is only supported in 1.6 and is highly experimental. */ public class Java2D { private static boolean DEBUG = Debug.debug("Java2D"); - private static boolean VERBOSE = Debug.verbose(); private static boolean isHeadless; private static boolean isOGLPipelineActive; private static Method invokeWithOGLContextCurrentMethod; @@ -103,9 +112,9 @@ public class Java2D { private static Method destroyOGLContextMethod; static { - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("Checking for Java2D/OpenGL support"); } try { @@ -119,7 +128,7 @@ public class Java2D { // If we get here, we aren't running in headless mode isHeadless = false; String name = cfg.getClass().getName(); - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("Java2D support: default GraphicsConfiguration = " + name); } isOGLPipelineActive = (name.startsWith("sun.java2d.opengl")); @@ -127,7 +136,7 @@ public class Java2D { if (isOGLPipelineActive) { try { // Try to get methods we need to integrate - Class utils = Class.forName("sun.java2d.opengl.OGLUtilities"); + Class<?> utils = Class.forName("sun.java2d.opengl.OGLUtilities"); invokeWithOGLContextCurrentMethod = utils.getDeclaredMethod("invokeWithOGLContextCurrent", new Class[] { Graphics.class, @@ -176,7 +185,7 @@ public class Java2D { getOGLSurfaceTypeMethod.setAccessible(true); } catch (Exception e) { fbObjectSupportInitialized = false; - if (DEBUG && VERBOSE) { + if (DEBUG) { e.printStackTrace(); System.err.println("Info: Disabling Java2D/JOGL FBO support"); } @@ -190,7 +199,7 @@ public class Java2D { }); getOGLTextureTypeMethod.setAccessible(true); } catch (Exception e) { - if (DEBUG && VERBOSE) { + if (DEBUG) { e.printStackTrace(); System.err.println("Info: GL_ARB_texture_rectangle FBO support disabled"); } @@ -199,11 +208,11 @@ public class Java2D { // Try to set up APIs for enabling the bridge on OS X, // where it isn't possible to create generalized // external GLDrawables - Class cglSurfaceData = null; + Class<?> cglSurfaceData = null; try { cglSurfaceData = Class.forName("sun.java2d.opengl.CGLSurfaceData"); } catch (Exception e) { - if (DEBUG && VERBOSE) { + if (DEBUG) { e.printStackTrace(); System.err.println("Info: Unable to find class sun.java2d.opengl.CGLSurfaceData for OS X"); } @@ -234,7 +243,7 @@ public class Java2D { destroyOGLContextMethod.setAccessible(true); } } catch (Exception e) { - if (DEBUG && VERBOSE) { + if (DEBUG) { e.printStackTrace(); System.err.println("Info: Disabling Java2D/JOGL integration"); } @@ -513,15 +522,15 @@ public class Java2D { } private static int getOGLUtilitiesIntField(final String name) { - Integer i = (Integer) AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + Integer i = AccessController.doPrivileged(new PrivilegedAction<Integer>() { + public Integer run() { try { - Class utils = Class.forName("sun.java2d.opengl.OGLUtilities"); + Class<?> utils = Class.forName("sun.java2d.opengl.OGLUtilities"); Field f = utils.getField(name); f.setAccessible(true); - return f.get(null); + return (Integer) f.get(null); } catch (Exception e) { - if (DEBUG && VERBOSE) { + if (DEBUG) { e.printStackTrace(); } return null; @@ -530,7 +539,7 @@ public class Java2D { }); if (i == null) return 0; - if (DEBUG && VERBOSE) { + if (DEBUG) { System.err.println("OGLUtilities." + name + " = " + i.intValue()); } return i.intValue(); diff --git a/src/jogl/classes/jogamp/opengl/awt/VersionApplet.java b/src/jogl/classes/jogamp/opengl/awt/VersionApplet.java index 5856bf3a0..55fb3f9a2 100644 --- a/src/jogl/classes/jogamp/opengl/awt/VersionApplet.java +++ b/src/jogl/classes/jogamp/opengl/awt/VersionApplet.java @@ -67,6 +67,8 @@ public class VersionApplet extends Applet { private synchronized void my_init() { if(null != canvas) { return; } + setEnabled(true); + GLProfile glp = GLProfile.getDefault(); GLCapabilities glcaps = new GLCapabilities(glp); @@ -120,8 +122,10 @@ public class VersionApplet extends Applet { remove(canvas); canvas.destroy(); canvas = null; - remove(tareaVersion); - tareaVersion=null; + remove(tareaVersion.getParent()); // remove the grid + tareaVersion = null; + tareaCaps = null; + setEnabled(false); } } @@ -133,11 +137,13 @@ public class VersionApplet extends Applet { public void start() { System.err.println("VersionApplet: start() - begin"); + canvas.setVisible(true); System.err.println("VersionApplet: start() - end"); } public void stop() { System.err.println("VersionApplet: stop() - begin"); + canvas.setVisible(false); System.err.println("VersionApplet: stop() - end"); } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index 0ec913e31..62ee20f92 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -35,17 +35,20 @@ package jogamp.opengl.egl; -import javax.media.opengl.*; +import java.nio.ByteBuffer; +import java.util.Map; -import jogamp.opengl.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableImpl; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; -import java.nio.*; -import java.util.*; - -import javax.media.nativewindow.AbstractGraphicsConfiguration; -import javax.media.nativewindow.AbstractGraphicsDevice; public abstract class EGLContext extends GLContextImpl { private boolean eglQueryStringInitialized; @@ -95,7 +98,7 @@ public abstract class EGLContext extends GLContextImpl { return true; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { if(EGL.EGL_NO_DISPLAY==((EGLDrawable)drawable).getDisplay() ) { throw new GLException("drawable not properly initialized, NO DISPLAY: "+drawable); } @@ -135,12 +138,12 @@ public abstract class EGLContext extends GLContextImpl { // FIXME } - protected boolean createImpl() throws GLException { + protected boolean createImpl(GLContextImpl shareWith) throws GLException { long eglDisplay = ((EGLDrawable)drawable).getDisplay(); EGLGraphicsConfiguration config = ((EGLDrawable)drawable).getGraphicsConfiguration(); GLProfile glProfile = drawable.getGLProfile(); long eglConfig = config.getNativeConfig(); - long shareWith = EGL.EGL_NO_CONTEXT; + long shareWithHandle = EGL.EGL_NO_CONTEXT; if (eglDisplay == 0) { throw new GLException("Error: attempted to create an OpenGL context without a display connection"); @@ -160,10 +163,9 @@ public abstract class EGLContext extends GLContextImpl { } } - EGLContext other = (EGLContext) GLContextShareSet.getShareContext(this); - if (other != null) { - shareWith = other.getHandle(); - if (shareWith == 0) { + if (shareWith != null) { + shareWithHandle = shareWith.getHandle(); + if (shareWithHandle == 0) { throw new GLException("GLContextShareSet returned an invalid OpenGL context"); } } @@ -179,10 +181,10 @@ public abstract class EGLContext extends GLContextImpl { } else { throw new GLException("Error creating OpenGL context - invalid GLProfile: "+glProfile); } - contextHandle = EGL.eglCreateContext(eglDisplay, eglConfig, shareWith, contextAttrs, 0); + contextHandle = EGL.eglCreateContext(eglDisplay, eglConfig, shareWithHandle, contextAttrs, 0); if (contextHandle == 0) { throw new GLException("Error creating OpenGL context: eglDisplay "+toHexString(eglDisplay)+ - ", eglConfig "+config+", "+glProfile+", shareWith "+toHexString(shareWith)+", error "+toHexString(EGL.eglGetError())); + ", eglConfig "+config+", "+glProfile+", shareWith "+toHexString(shareWithHandle)+", error "+toHexString(EGL.eglGetError())); } if (DEBUG) { System.err.println(getThreadName() + ": !!! Created OpenGL context 0x" + @@ -190,7 +192,7 @@ public abstract class EGLContext extends GLContextImpl { ",\n\twrite surface 0x" + Long.toHexString(drawable.getHandle()) + ",\n\tread surface 0x" + Long.toHexString(drawableRead.getHandle())+ ",\n\t"+this+ - ",\n\tsharing with 0x" + Long.toHexString(shareWith)); + ",\n\tsharing with 0x" + Long.toHexString(shareWithHandle)); } if (!EGL.eglMakeCurrent(((EGLDrawable)drawable).getDisplay(), drawable.getHandle(), @@ -207,12 +209,12 @@ public abstract class EGLContext extends GLContextImpl { } else { major = 1; } - setGLFunctionAvailability(true, true, major, 0, ctp); + setGLFunctionAvailability(true, major, 0, ctp); return true; } protected final void updateGLXProcAddressTable() { - final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "EGL-"+adevice.getUniqueID(); if (DEBUG) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index a9cc40335..14a0a40cd 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -99,7 +99,7 @@ public abstract class EGLDrawable extends GLDrawableImpl { protected void setRealizedImpl() { if (realized) { - AbstractGraphicsConfiguration aConfig = surface.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration aConfig = surface.getGraphicsConfiguration(); AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); if(aDevice instanceof EGLGraphicsDevice) { if(DEBUG) { @@ -197,6 +197,16 @@ public abstract class EGLDrawable extends GLDrawableImpl { } } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { + if(DEBUG) { + System.err.println("eglSwapBuffers failed:"); + Thread.dumpStack(); + } + } + } + public int getWidth() { int[] tmp = new int[1]; if (!EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_WIDTH, tmp, 0)) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 79d96bdb6..cd6d61a22 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -39,6 +39,7 @@ package jogamp.opengl.egl; import javax.media.nativewindow.*; import javax.media.nativewindow.egl.EGLGraphicsDevice; import javax.media.opengl.*; +import javax.media.opengl.GLProfile.ShutdownType; import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.*; @@ -50,13 +51,15 @@ import java.util.HashMap; import java.util.List; public class EGLDrawableFactory extends GLDrawableFactoryImpl { - private static final GLDynamicLookupHelper eglES1DynamicLookupHelper; - private static final GLDynamicLookupHelper eglES2DynamicLookupHelper; - - static { + private static GLDynamicLookupHelper eglES1DynamicLookupHelper = null; + private static GLDynamicLookupHelper eglES2DynamicLookupHelper = null; + + public EGLDrawableFactory() { + super(); + // Register our GraphicsConfigurationFactory implementations // The act of constructing them causes them to be registered - new EGLGraphicsConfigurationFactory(); + EGLGraphicsConfigurationFactory.registerFactory(); // Check for other underlying stuff .. if(NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { @@ -69,38 +72,69 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { // to a dynamic one, where there can be 2 instances // for each ES profile with their own ProcAddressTable. - GLDynamicLookupHelper tmp=null; - try { - tmp = new GLDynamicLookupHelper(new EGLES1DynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + synchronized(EGLDrawableFactory.class) { + if(null==eglES1DynamicLookupHelper) { + GLDynamicLookupHelper tmp=null; + try { + tmp = new GLDynamicLookupHelper(new EGLES1DynamicLibraryBundleInfo()); + } catch (GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + eglES1DynamicLookupHelper = tmp; + if(null!=eglES1DynamicLookupHelper && eglES1DynamicLookupHelper.isLibComplete()) { + EGL.resetProcAddressTable(eglES1DynamicLookupHelper); + } } } - eglES1DynamicLookupHelper = tmp; - if(null!=eglES1DynamicLookupHelper && eglES1DynamicLookupHelper.isLibComplete()) { - EGL.resetProcAddressTable(eglES1DynamicLookupHelper); - } - tmp=null; - try { - tmp = new GLDynamicLookupHelper(new EGLES2DynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + synchronized(EGLDrawableFactory.class) { + if(null==eglES2DynamicLookupHelper) { + GLDynamicLookupHelper tmp=null; + try { + tmp = new GLDynamicLookupHelper(new EGLES2DynamicLibraryBundleInfo()); + } catch (GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + eglES2DynamicLookupHelper = tmp; + if(null!=eglES2DynamicLookupHelper && eglES2DynamicLookupHelper.isLibComplete()) { + EGL.resetProcAddressTable(eglES2DynamicLookupHelper); + } } } - eglES2DynamicLookupHelper = tmp; - if(null!=eglES2DynamicLookupHelper && eglES2DynamicLookupHelper.isLibComplete()) { - EGL.resetProcAddressTable(eglES2DynamicLookupHelper); + if(null != eglES1DynamicLookupHelper || null != eglES2DynamicLookupHelper) { + defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + sharedMap = new HashMap(); } } - public EGLDrawableFactory() { - super(); - defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + protected final void destroy(ShutdownType shutdownType) { + if(null != sharedMap) { + sharedMap.clear(); + sharedMap = null; + } + defaultDevice = null; + /** + * Pulling away the native library may cause havoc .. + * + if(ShutdownType.COMPLETE == shutdownType) { + if(null != eglES1DynamicLookupHelper) { + eglES1DynamicLookupHelper.destroy(); + eglES1DynamicLookupHelper = null; + } + if(null != eglES2DynamicLookupHelper) { + eglES2DynamicLookupHelper.destroy(); + eglES2DynamicLookupHelper = null; + } + } */ } + private HashMap/*<connection, SharedResource>*/ sharedMap; + private EGLGraphicsDevice defaultDevice; + static class SharedResource { private EGLGraphicsDevice device; // private EGLDrawable drawable; @@ -125,8 +159,6 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final boolean wasES1ContextAvailable() { return wasES1ContextCreated; } final boolean wasES2ContextAvailable() { return wasES2ContextCreated; } } - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); - EGLGraphicsDevice defaultDevice; public final AbstractGraphicsDevice getDefaultDevice() { return defaultDevice; @@ -200,10 +232,21 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return sr; } - public final boolean getWasSharedContextCreated(AbstractGraphicsDevice device) { - SharedResource sr = getOrCreateEGLSharedResource(device); - if(null!=sr) { - return sr.wasES1ContextAvailable() || sr.wasES2ContextAvailable(); + protected final Thread getSharedResourceThread() { + return null; + } + + protected final boolean createSharedResource(AbstractGraphicsDevice device) { + try { + SharedResource sr = getOrCreateEGLSharedResource(device); + if(null!=sr) { + return sr.wasES1ContextAvailable() || sr.wasES2ContextAvailable(); + } + } catch (GLException gle) { + if(DEBUG) { + System.err.println("Catched Exception while EGL Shared Resource initialization"); + gle.printStackTrace(); + } } return false; } @@ -236,8 +279,6 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } } - protected final void shutdownInstance() {} - protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(AbstractGraphicsDevice device) { return EGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); } @@ -253,7 +294,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!caps.isPBuffer()) { throw new GLException("Non pbuffer not yet implemented"); @@ -268,7 +309,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { WrappedSurface ns = new WrappedSurface(EGLGraphicsConfigurationFactory.createOffscreenGraphicsConfiguration(device, capsChosen, capsRequested, chooser)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java index 33154b089..1f9254b49 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java @@ -29,18 +29,11 @@ package jogamp.opengl.egl; import com.jogamp.common.os.AndroidVersion; -import com.jogamp.common.os.DynamicLookupHelper; -import com.jogamp.common.os.NativeLibrary; -import com.jogamp.common.os.Platform; import java.util.*; -import javax.media.nativewindow.*; -import javax.media.opengl.*; import jogamp.opengl.*; -import java.security.*; - /** * Abstract implementation of the DynamicLookupHelper for EGL, * which decouples it's dependencies to EGLDrawable. diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java index 3b0fc5957..63109f445 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java @@ -30,10 +30,6 @@ package jogamp.opengl.egl; import java.util.*; -import com.jogamp.common.os.Platform; - -import jogamp.opengl.*; - public class EGLES1DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { protected EGLES1DynamicLibraryBundleInfo() { super(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java index 28c480b0c..b0748ad10 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java @@ -30,10 +30,6 @@ package jogamp.opengl.egl; import java.util.*; -import com.jogamp.common.os.Platform; - -import jogamp.opengl.*; - public class EGLES2DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { protected EGLES2DynamicLibraryBundleInfo() { super(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java index 389daa7ca..796a4311b 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java @@ -45,7 +45,7 @@ public class EGLExternalContext extends EGLContext { public EGLExternalContext(AbstractGraphicsScreen screen) { super(null, null); GLContextShareSet.contextCreated(this); - setGLFunctionAvailability(false, true, 0, 0, CTX_IS_ARB_CREATED|CTX_PROFILE_ES|CTX_OPTION_ANY); + setGLFunctionAvailability(false, 0, 0, CTX_IS_ARB_CREATED|CTX_PROFILE_ES|CTX_OPTION_ANY); getGLStateTracker().setEnabled(false); // external context usage can't track state in Java } @@ -66,7 +66,7 @@ public class EGLExternalContext extends EGLContext { lastContext = null; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { } protected void releaseImpl() throws GLException { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 4fb3dca78..ea625fb27 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -38,15 +38,25 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; import java.util.ArrayList; -import javax.media.nativewindow.*; -import javax.media.nativewindow.egl.*; -import javax.media.opengl.*; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.egl.EGLGraphicsDevice; +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.MutableGraphicsConfiguration; +import jogamp.opengl.Debug; +import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; -import jogamp.opengl.*; -public class EGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); public final long getNativeConfig() { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java index 74f7d884b..ceeebe60b 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java @@ -69,9 +69,11 @@ import java.nio.IntBuffer; public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { static EGLGLCapabilities.EglCfgIDComparator EglCfgIDComparator = new EGLGLCapabilities.EglCfgIDComparator(); - EGLGraphicsConfigurationFactory() { + static void registerFactory() { // become the selector for KD/EGL .. - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.egl.EGLGraphicsDevice.class, this); + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.egl.EGLGraphicsDevice.class, new EGLGraphicsConfigurationFactory()); + } + private EGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl ( diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java index 7d5e0448d..42f067b29 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java @@ -55,15 +55,5 @@ public class EGLOnscreenDrawable extends EGLDrawable { protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { return EGL.eglCreateWindowSurface(eglDpy, eglNativeCfg, surfaceHandle, null); } - - protected void swapBuffersImpl() { - if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { - if(DEBUG) { - System.err.println("eglSwapBuffers failed:"); - Thread.dumpStack(); - } - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index 5fb32e6cd..28a23d294 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -40,48 +40,39 @@ package jogamp.opengl.egl; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.SurfaceChangeable; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; -import jogamp.opengl.x11.glx.GLX; - public class EGLPbufferDrawable extends EGLDrawable { private int texFormat; protected static final boolean useTexture = false; // No yet .. protected EGLPbufferDrawable(EGLDrawableFactory factory, NativeSurface target) { super(factory, target); + } - // get choosen ones .. - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) - getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + protected void destroyImpl() { + setRealized(false); + } + + protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { + final AbstractGraphicsConfiguration config = getNativeSurface().getGraphicsConfiguration(); + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(useTexture) { - this.texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; + texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; } else { - this.texFormat = EGL.EGL_NO_TEXTURE; + texFormat = EGL.EGL_NO_TEXTURE; } if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - setRealized(true); - - if (DEBUG) { - System.out.println("Created pbuffer: " + this); + System.out.println("Pbuffer config: " + config); } - } - - protected void destroyImpl() { - setRealized(false); - } - - protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { NativeSurface nw = getNativeSurface(); int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(nw.getWidth(), nw.getHeight(), texFormat); long surf = EGL.eglCreatePbufferSurface(eglDpy, eglNativeCfg, attrs, 0); @@ -97,11 +88,5 @@ public class EGLPbufferDrawable extends EGLDrawable { public GLContext createContext(GLContext shareWith) { return new EGLPbufferContext(this, shareWith); } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 1fe47f60b..0dd1a460e 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -45,14 +45,15 @@ import java.util.Map; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.DefaultGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import jogamp.opengl.GLContextImpl; -import jogamp.opengl.GLContextShareSet; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -63,7 +64,6 @@ import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; - public abstract class MacOSXCGLContext extends GLContextImpl { // Abstract interface for implementation of this context (either @@ -76,7 +76,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl boolean makeCurrent(long ctx); boolean release(long ctx); boolean setSwapInterval(int interval); - boolean swapBuffers(boolean isOnscreen); + boolean swapBuffers(); } /* package */ static final boolean isTigerOrLater; @@ -95,7 +95,12 @@ public abstract class MacOSXCGLContext extends GLContextImpl // We exclude 3.0, since we would map it's core to GL2. Hence we force mapping 2.1 to GL2 if(3==major && 1<=minor && minor<=2) { // [3.1..3.2] -> GL3* + if(!isLionOrLater) { + // no GL3* on pre lion + return false; + } if(ctBwdCompat) { + // no compatibility profile on OS X return false; } return ctCore; @@ -203,44 +208,43 @@ public abstract class MacOSXCGLContext extends GLContextImpl return false; } - protected long createImplPreset() throws GLException { - MacOSXCGLContext other = (MacOSXCGLContext) GLContextShareSet.getShareContext(this); + protected long createImplPreset(GLContextImpl shareWith) throws GLException { long share = 0; - if (other != null) { + if (shareWith != null) { // Change our OpenGL mode to match that of any share context before we create ourselves - setOpenGLMode(other.getOpenGLMode()); - share = other.getHandle(); + setOpenGLMode(((MacOSXCGLContext)shareWith).getOpenGLMode()); + share = shareWith.getHandle(); if (share == 0) { throw new GLException("GLContextShareSet returned a NULL OpenGL context"); } } - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + + MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); GLCapabilitiesImmutable capabilitiesChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - if (capabilitiesChosen.getPbufferFloatingPointBuffers() && - !isTigerOrLater) { + if (capabilitiesChosen.getPbufferFloatingPointBuffers() && !isTigerOrLater) { throw new GLException("Floating-point pbuffers supported only on OS X 10.4 or later"); } GLProfile glp = capabilitiesChosen.getGLProfile(); if(glp.isGLES1() || glp.isGLES2() || glp.isGL4() || glp.isGL3() && !isLionOrLater) { throw new GLException("OpenGL profile not supported on MacOSX "+Platform.getOSVersionNumber()+": "+glp); } + if (DEBUG) { System.err.println("!!! Share context is " + toHexString(share) + " for " + this); } - return share; + return share; } - - protected boolean createImpl() throws GLException { - long share = createImplPreset(); + + protected boolean createImpl(GLContextImpl shareWith) throws GLException { + long share = createImplPreset(shareWith); contextHandle = createContextARB(share, true); return 0 != contextHandle; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { if (getOpenGLMode() != ((MacOSXCGLDrawable)drawable).getOpenGLMode()) { setOpenGLMode(((MacOSXCGLDrawable)drawable).getOpenGLMode()); } - if (!impl.makeCurrent(contextHandle)) { throw new GLException("Error making Context current: "+this); } @@ -268,9 +272,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl } protected void swapBuffers() { - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - if(!impl.swapBuffers(caps.isOnscreen())) { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!impl.swapBuffers()) { throw new GLException("Error swapping buffers: "+this); } } @@ -282,12 +285,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(!impl.setSwapInterval(interval)) { throw new GLException("Error set swap-interval: "+this); } - if ( isNSContext() ) { - CGL.setSwapInterval(contextHandle, interval); - } else { - int[] lval = new int[] { (int) interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - } currentSwapInterval = interval ; } @@ -297,7 +294,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl } protected final void updateGLXProcAddressTable() { - final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "MacOSX-"+adevice.getUniqueID(); if (DEBUG) { @@ -403,31 +400,44 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { + long nsOpenGLLayer = 0; + long nsOpenGLLayerPFmt = 0; + public boolean isNSContext() { return true; } public long create(long share, int ctp, int major, int minor) { long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) MacOSXCGLContext.this.drawable; + final NativeSurface surface = drawable.getNativeSurface(); + final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration(); + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); if (pixelFormat == 0) { throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } config.setChosenPixelFormat(pixelFormat); + if(DEBUG) { + System.err.println("NS create OSX>=lion "+isLionOrLater); + System.err.println("NS create backingLayerHost: "+backingLayerHost); + System.err.println("NS create share: "+share); + System.err.println("NS create chosenCaps: "+chosenCaps); + System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); + System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); + System.err.println("NS create drawable NSView-handle: "+toHexString(drawable.getNSViewHandle())); + // Thread.dumpStack(); + } try { int[] viewNotReady = new int[1]; // Try to allocate a context with this ctx = CGL.createContext(share, - drawable.getHandle(), + drawable.getNSViewHandle(), null!=backingLayerHost, pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady, 0); if (0 == ctx) { - if (viewNotReady[0] == 1) { - if (DEBUG) { - System.err.println("!!! View not ready for " + getClass().getName()); - } - // View not ready at the window system level + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); } return 0; } @@ -439,22 +449,66 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(DEBUG) { GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(null, pixelFormat); - System.err.println("NS created(>=lion "+isLionOrLater+"): "+caps0); + System.err.println("NS create pixelformat2GLCaps: "+caps0); } - GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); - caps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(caps, chosenCaps.isBackgroundOpaque()); - config.setChosenCapabilities(caps); - if(caps.isPBuffer()) { + GLCapabilitiesImmutable fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("NS create fixedCaps: "+fixedCaps); + } + if(fixedCaps.isPBuffer()) { // Must now associate the pbuffer with our newly-created context CGL.setContextPBuffer(ctx, drawable.getHandle()); - } + } + // + // handled layered surface + // + if(null != backingLayerHost) { + nsOpenGLLayerPFmt = pixelFormat; + pixelFormat = 0; + final int texWidth, texHeight; + if(drawable instanceof MacOSXPbufferCGLDrawable) { + final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; + texWidth = osxPDrawable.getTextureWidth(); + texHeight = osxPDrawable.getTextureHeight(); + } else { + texWidth = drawable.getWidth(); + texHeight = drawable.getHeight(); + } + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight); + if(0>=texWidth || 0>=texHeight || !drawable.isRealized()) { + throw new GLException("Drawable not realized yet or invalid texture size, texSize "+texWidth+"x"+texHeight+", "+drawable); + } + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", texSize "+texWidth+"x"+texHeight+", "+drawable); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + } } finally { - CGL.deletePixelFormat(pixelFormat); + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + } } return ctx; } public boolean destroy(long ctx) { + if(0 != nsOpenGLLayer) { + final NativeSurface surface = drawable.getNativeSurface(); + if (DEBUG) { + System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)); + } + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + if(null == ols) { + throw new InternalError("XXX: "+ols); + } + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); + ols.detachSurfaceLayer(nsOpenGLLayer); + CGL.deletePixelFormat(nsOpenGLLayerPFmt); + nsOpenGLLayerPFmt = 0; + nsOpenGLLayer = 0; + } return CGL.deleteContext(ctx, true); } @@ -464,22 +518,54 @@ public abstract class MacOSXCGLContext extends GLContextImpl } public boolean makeCurrent(long ctx) { - return CGL.makeCurrentContext(ctx); + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + int err = CGL.CGLLockContext(cglCtx); + if(CGL.kCGLNoError == err) { + return CGL.makeCurrentContext(ctx); + } else if(DEBUG) { + System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return false; } public boolean release(long ctx) { - return CGL.clearCurrentContext(ctx); + gl.glFinish(); // w/o glFinish() OSX < 10.7 (NVidia driver) may freeze + final boolean res = CGL.clearCurrentContext(ctx); + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + final int err = CGL.CGLUnlockContext(cglCtx); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return res && CGL.kCGLNoError == err; } public boolean setSwapInterval(int interval) { - CGL.setSwapInterval(contextHandle, interval); + if(0 != nsOpenGLLayer) { + CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + } + CGL.setSwapInterval(contextHandle, interval); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.flushBuffer(contextHandle); - } - return true; + + public boolean swapBuffers() { + if(0 != nsOpenGLLayer) { + // sync w/ CALayer renderer - wait until next frame is required (v-sync) + CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, 16); // timeout 16ms -> 60Hz + } + if(CGL.flushBuffer(contextHandle)) { + if(0 != nsOpenGLLayer) { + // trigger CALayer to update + CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer); + } + return true; + } + return false; } } @@ -488,7 +574,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl public long create(long share, int ctp, int major, int minor) { long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor); if (pixelFormat == 0) { @@ -535,11 +621,31 @@ public abstract class MacOSXCGLContext extends GLContextImpl } public boolean makeCurrent(long ctx) { - return CGL.CGLSetCurrentContext(ctx) == CGL.kCGLNoError; + int err = CGL.CGLLockContext(ctx); + if(CGL.kCGLNoError == err) { + err = CGL.CGLSetCurrentContext(ctx); + if(CGL.kCGLNoError == err) { + return true; + } else if(DEBUG) { + System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this); + } + } else if(DEBUG) { + System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return false; } public boolean release(long ctx) { - return (CGL.CGLSetCurrentContext(0) == CGL.kCGLNoError); + gl.glFinish(); // w/o glFinish() OSX < 10.7 (NVidia driver) may freeze + int err = CGL.CGLSetCurrentContext(0); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this); + } + int err2 = CGL.CGLUnlockContext(ctx); + if(DEBUG && CGL.kCGLNoError != err2) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this); + } + return CGL.kCGLNoError == err && CGL.kCGLNoError == err2; } public boolean setSwapInterval(int interval) { @@ -547,11 +653,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); - } - return true; + public boolean swapBuffers() { + return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index 5a35f661d..12d480fd1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -40,6 +40,11 @@ package jogamp.opengl.macosx.cgl; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -87,18 +92,46 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { this.id = id; } } - + private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); + private boolean haveSetOpenGLMode = false; private GLBackendType openGLMode = GLBackendType.NSOPENGL; public MacOSXCGLDrawable(GLDrawableFactory factory, NativeSurface comp, boolean realized) { super(factory, comp, realized); - initOpenGLImpl(getOpenGLMode()); - } - + initOpenGLImpl(getOpenGLMode()); + } + protected void setRealizedImpl() { } + protected long getNSViewHandle() { + return GLBackendType.NSOPENGL == openGLMode ? getHandle() : null; + } + + protected void registerContext(MacOSXCGLContext ctx) { + // NOTE: we need to keep track of the created contexts in order to + // implement swapBuffers() because of how Mac OS X implements its + // OpenGL window interface + synchronized (createdContexts) { + createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); + } + } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + synchronized (createdContexts) { + for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { + WeakReference<MacOSXCGLContext> ref = iter.next(); + MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.swapBuffers(); + } else { + iter.remove(); + } + } + } + } + public GLDynamicLookupHelper getGLDynamicLookupHelper() { return getFactoryImpl().getGLDynamicLookupHelper(0); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 5c726bc54..3dd7a7f08 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -42,6 +42,7 @@ package jogamp.opengl.macosx.cgl; import java.nio.Buffer; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import javax.media.nativewindow.AbstractGraphicsConfiguration; @@ -52,6 +53,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.macosx.MacOSXGraphicsDevice; +import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; @@ -59,6 +61,7 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import javax.media.opengl.GLProfile.ShutdownType; import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.DesktopGLDynamicLookupHelper; @@ -70,62 +73,93 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.ReflectionUtil; public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { - private static final DesktopGLDynamicLookupHelper macOSXCGLDynamicLookupHelper; - - static { - DesktopGLDynamicLookupHelper tmp = null; - try { - tmp = new DesktopGLDynamicLookupHelper(new MacOSXCGLDynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + private static DesktopGLDynamicLookupHelper macOSXCGLDynamicLookupHelper = null; + + public MacOSXCGLDrawableFactory() { + super(); + + synchronized(MacOSXCGLDrawableFactory.class) { + if(null==macOSXCGLDynamicLookupHelper) { + DesktopGLDynamicLookupHelper tmp = null; + try { + tmp = new DesktopGLDynamicLookupHelper(new MacOSXCGLDynamicLibraryBundleInfo()); + } catch (GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } } + macOSXCGLDynamicLookupHelper = tmp; + /** FIXME ?? + if(null!=macOSXCGLDynamicLookupHelper) { + CGL.getCGLProcAddressTable().reset(macOSXCGLDynamicLookupHelper); + } */ + } + } + + if(null!=macOSXCGLDynamicLookupHelper) { + // Register our GraphicsConfigurationFactory implementations + // The act of constructing them causes them to be registered + MacOSXCGLGraphicsConfigurationFactory.registerFactory(); + if(GLProfile.isAWTAvailable()) { + try { + ReflectionUtil.callStaticMethod("jogamp.opengl.macosx.cgl.awt.MacOSXAWTCGLGraphicsConfigurationFactory", + "registerFactory", null, null, getClass().getClassLoader()); + } catch (JogampRuntimeException jre) { /* n/a .. */ } } - macOSXCGLDynamicLookupHelper = tmp; - /** FIXME ?? - if(null!=macOSXCGLDynamicLookupHelper) { - CGL.getCGLProcAddressTable().reset(macOSXCGLDynamicLookupHelper); - } */ + + defaultDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + sharedMap = new HashMap<String, SharedResource>(); + } + } + + protected final void destroy(ShutdownType shutdownType) { + if(null != sharedMap) { + sharedMap.clear(); + sharedMap = null; + } + defaultDevice = null; + /** + * Pulling away the native library may cause havoc .. + * + if(ShutdownType.COMPLETE == shutdownType && null != macOSXCGLDynamicLookupHelper) { + macOSXCGLDynamicLookupHelper.destroy(); + macOSXCGLDynamicLookupHelper = null; + } */ } public GLDynamicLookupHelper getGLDynamicLookupHelper(int profile) { return macOSXCGLDynamicLookupHelper; } - public MacOSXCGLDrawableFactory() { - super(); - - // Register our GraphicsConfigurationFactory implementations - // The act of constructing them causes them to be registered - new MacOSXCGLGraphicsConfigurationFactory(); - if(GLProfile.isAWTAvailable()) { - try { - ReflectionUtil.createInstance("jogamp.opengl.macosx.cgl.awt.MacOSXAWTCGLGraphicsConfigurationFactory", - null, getClass().getClassLoader()); - } catch (JogampRuntimeException jre) { /* n/a .. */ } - } - - defaultDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); - } + private HashMap<String, SharedResource> sharedMap = new HashMap<String, SharedResource>(); + private MacOSXGraphicsDevice defaultDevice; static class SharedResource { // private MacOSXCGLDrawable drawable; // private MacOSXCGLContext context; MacOSXGraphicsDevice device; boolean wasContextCreated; + boolean hasNPOTTextures; + boolean hasRECTTextures; + boolean hasAppletFloatPixels; - SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated + SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated, + boolean hasNPOTTextures, boolean hasRECTTextures, boolean hasAppletFloatPixels /* MacOSXCGLDrawable draw, MacOSXCGLContext ctx */) { // drawable = draw; // context = ctx; this.device = device; this.wasContextCreated = wasContextCreated; + this.hasNPOTTextures = hasNPOTTextures; + this.hasRECTTextures = hasRECTTextures; + this.hasAppletFloatPixels = hasAppletFloatPixels; } final MacOSXGraphicsDevice getDevice() { return device; } final boolean wasContextAvailable() { return wasContextCreated; } + final boolean isNPOTTextureAvailable() { return hasNPOTTextures; } + final boolean isRECTTextureAvailable() { return hasRECTTextures; } + final boolean isAppletFloatPixelsAvailable() { return hasAppletFloatPixels; } } - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); - MacOSXGraphicsDevice defaultDevice; public final AbstractGraphicsDevice getDefaultDevice() { return defaultDevice; @@ -138,52 +172,79 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return false; } - private boolean isOSXContextAvailable(AbstractGraphicsDevice sharedDevice) { - boolean madeCurrent = false; - GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); - if (null == glp) { - throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); - } - final GLCapabilities caps = new GLCapabilities(glp); - caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); - caps.setDoubleBuffered(false); - caps.setOnscreen(false); - caps.setPBuffer(true); - final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); - if(null!=drawable) { - final GLContext context = drawable.createContext(null); - if (null != context) { - context.setSynchronized(true); - try { - context.makeCurrent(); // could cause exception - madeCurrent = context.isCurrent(); - } catch (GLException gle) { - if (DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); - gle.printStackTrace(); - } - } finally { - context.destroy(); - } - } - drawable.destroy(); - } - return madeCurrent; + private HashSet<String> devicesTried = new HashSet<String>(); + + private boolean getDeviceTried(String connection) { + synchronized (devicesTried) { + return devicesTried.contains(connection); + } + } + private void addDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.add(connection); + } + } + private void removeDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.remove(connection); + } } /* package */ SharedResource getOrCreateOSXSharedResource(AbstractGraphicsDevice adevice) { - String connection = adevice.getConnection(); + final String connection = adevice.getConnection(); SharedResource sr; synchronized(sharedMap) { - sr = (SharedResource) sharedMap.get(connection); + sr = sharedMap.get(connection); } - if(null==sr) { + if(null==sr && !getDeviceTried(connection)) { + addDeviceTried(connection); final MacOSXGraphicsDevice sharedDevice = new MacOSXGraphicsDevice(adevice.getUnitID()); - final boolean madeCurrent = isOSXContextAvailable(sharedDevice); - sr = new SharedResource(sharedDevice, madeCurrent); + boolean madeCurrent = false; + boolean hasNPOTTextures = false; + boolean hasRECTTextures = false; + boolean hasAppletFloatPixels = false; + { + GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); + if (null == glp) { + throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); + } + final GLCapabilities caps = new GLCapabilities(glp); + caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); + caps.setDoubleBuffered(false); + caps.setOnscreen(false); + caps.setPBuffer(true); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); + if(null!=drawable) { + drawable.setRealized(true); + final GLContext context = drawable.createContext(null); + if (null != context) { + context.setSynchronized(true); + try { + context.makeCurrent(); // could cause exception + madeCurrent = context.isCurrent(); + if(madeCurrent) { + GL gl = context.getGL(); + hasNPOTTextures = gl.isNPOTTextureAvailable(); + hasRECTTextures = gl.isExtensionAvailable("GL_EXT_texture_rectangle"); + hasAppletFloatPixels = gl.isExtensionAvailable("GL_APPLE_float_pixels"); + } + } catch (GLException gle) { + if (DEBUG) { + System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); + gle.printStackTrace(); + } + } finally { + context.destroy(); + } + } + drawable.destroy(); + } + } + sr = new SharedResource(sharedDevice, madeCurrent, hasNPOTTextures, hasRECTTextures, hasAppletFloatPixels); synchronized(sharedMap) { sharedMap.put(connection, sr); } + removeDeviceTried(connection); if (DEBUG) { System.err.println("MacOSXCGLDrawableFactory.createShared: device: " + sharedDevice); System.err.println("MacOSXCGLDrawableFactory.createShared: context: " + madeCurrent); @@ -191,11 +252,22 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } return sr; } - - public final boolean getWasSharedContextCreated(AbstractGraphicsDevice device) { - SharedResource sr = getOrCreateOSXSharedResource(device); - if(null!=sr) { - return sr.wasContextAvailable(); + + protected final Thread getSharedResourceThread() { + return null; + } + + protected final boolean createSharedResource(AbstractGraphicsDevice device) { + try { + SharedResource sr = getOrCreateOSXSharedResource(device); + if(null!=sr) { + return sr.wasContextAvailable(); + } + } catch (GLException gle) { + if(DEBUG) { + System.err.println("Catched Exception while MaxOSXCGL Shared Resource initialization"); + gle.printStackTrace(); + } } return false; } @@ -213,8 +285,6 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return null; } - protected final void shutdownInstance() {} - protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(AbstractGraphicsDevice device) { return MacOSXCGLGraphicsConfiguration.getAvailableCapabilities(this, device); } @@ -227,26 +297,11 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } protected GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) { - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!caps.isPBuffer()) { return new MacOSXOffscreenCGLDrawable(this, target); } - - // PBuffer GLDrawable Creation - /** - * FIXME: Think about this .. - * should not be necessary ? .. - final List returnList = new ArrayList(); - final GLDrawableFactory factory = this; - Runnable r = new Runnable() { - public void run() { - returnList.add(new MacOSXPbufferCGLDrawable(factory, target)); - } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); - */ return new MacOSXPbufferCGLDrawable(this, target); } @@ -257,7 +312,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device,GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX); WrappedSurface ns = new WrappedSurface(MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, true)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java index a429720db..f552ab3dd 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java @@ -41,15 +41,16 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; + import com.jogamp.common.nio.PointerBuffer; -public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { long pixelformat; MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen, @@ -67,10 +68,6 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration this.pixelformat=pixelformat; } - void setChosenCapabilities(GLCapabilitiesImmutable caps) { - super.setChosenCapabilities(caps); - } - protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) { MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device); if(null == sharedResource) { @@ -83,6 +80,8 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration static final int[] cglInternalAttributeToken = new int[] { CGL.kCGLPFAOpenGLProfile, CGL.kCGLPFAColorFloat, + CGL.NSOpenGLPFANoRecovery, + CGL.NSOpenGLPFAAccelerated, CGL.NSOpenGLPFAPixelBuffer, CGL.NSOpenGLPFADoubleBuffer, CGL.NSOpenGLPFAStereo, @@ -114,6 +113,13 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0; break; + case CGL.NSOpenGLPFANoRecovery: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAAccelerated: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAPixelBuffer: ivalues[idx] = caps.isPBuffer() ? 1 : 0; break; @@ -222,7 +228,7 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration // Use attribute array to select pixel format PointerBuffer fmt = PointerBuffer.allocateDirect(1); - long[] numScreens = new long[1]; + int[] numScreens = new int[1]; int res = CGL.CGLChoosePixelFormat(attrs, 0, fmt, numScreens, 0); if (res != CGL.kCGLNoError) { throw new GLException("Error code " + res + " while choosing pixel format"); @@ -285,6 +291,10 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration caps.setPbufferFloatingPointBuffers(ivalues[i] != 0); break; + case CGL.NSOpenGLPFAAccelerated: + caps.setHardwareAccelerated(ivalues[i] != 0); + break; + case CGL.NSOpenGLPFAPixelBuffer: caps.setPBuffer(ivalues[i] != 0); break; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java index d4526f04e..0de290c6b 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java @@ -51,8 +51,10 @@ import javax.media.opengl.GLCapabilitiesImmutable; public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); - MacOSXCGLGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.macosx.MacOSXGraphicsDevice.class, this); + static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.macosx.MacOSXGraphicsDevice.class, new MacOSXCGLGraphicsConfigurationFactory()); + } + private MacOSXCGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java index 08a531200..6ce2d7ba7 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java @@ -48,9 +48,9 @@ import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; -import javax.media.opengl.GLProfile; import jogamp.nativewindow.WrappedSurface; +import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLContextShareSet; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -61,10 +61,10 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) { super(drawable, null); setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL ); - drawable.setExternalCGLContext(this); + drawable.registerContext(this); this.contextHandle = handle; GLContextShareSet.contextCreated(this); - setGLFunctionAvailability(false, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); + setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); getGLStateTracker().setEnabled(false); // external context usage can't track state in Java } @@ -118,7 +118,7 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { return new MacOSXExternalCGLContext(new Drawable(factory, ns), isNSContext, contextHandle); } - protected boolean createImpl() throws GLException { + protected boolean createImpl(GLContextImpl shareWith) throws GLException { return true; } @@ -139,7 +139,7 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { lastContext = null; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { } protected void releaseImpl() throws GLException { @@ -150,16 +150,10 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { // Need to provide the display connection to extension querying APIs static class Drawable extends MacOSXCGLDrawable { - MacOSXExternalCGLContext extCtx; - Drawable(GLDrawableFactory factory, NativeSurface comp) { super(factory, comp, true); } - void setExternalCGLContext(MacOSXExternalCGLContext externalContext) { - extCtx = externalContext; - } - public GLContext createContext(GLContext shareWith) { throw new GLException("Should not call this"); } @@ -175,11 +169,5 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { public void setSize(int width, int height) { throw new GLException("Should not call this"); } - - protected void swapBuffersImpl() { - if (extCtx != null) { - extCtx.swapBuffers(); - } - } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java index bec4cf32a..f81cd725e 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java @@ -40,9 +40,9 @@ package jogamp.opengl.macosx.cgl; -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import jogamp.opengl.*; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; public class MacOSXOffscreenCGLDrawable extends MacOSXPbufferCGLDrawable { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java index 97d198c92..9e051311c 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java @@ -42,6 +42,8 @@ package jogamp.opengl.macosx.cgl; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; +import jogamp.opengl.GLContextImpl; + public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { public MacOSXOnscreenCGLContext(MacOSXOnscreenCGLDrawable drawable, @@ -50,14 +52,20 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { } @Override - protected void makeCurrentImpl(boolean newCreated) throws GLException { - super.makeCurrentImpl(newCreated); + protected void makeCurrentImpl() throws GLException { + super.makeCurrentImpl(); drawableUpdatedNotify(); } @Override protected void drawableUpdatedNotify() throws GLException { - if(0==updateHandle || CGL.updateContextNeedsUpdate(updateHandle)) { + final int w = drawable.getWidth(); + final int h = drawable.getHeight(); + final boolean updateContext = ( 0!=updateHandle && CGL.updateContextNeedsUpdate(updateHandle) ) || + w != lastWidth || h != lastHeight; + if(updateContext) { + lastWidth = w; + lastHeight = h; if (contextHandle == 0) { throw new GLException("Context not created"); } @@ -65,11 +73,11 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { } } - protected long updateHandle = 0; - @Override - protected boolean createImpl() { - boolean res = super.createImpl(); + protected boolean createImpl(GLContextImpl sharedWith) { + boolean res = super.createImpl(sharedWith); + lastWidth = -1; + lastHeight = -1; if(res && isNSContext()) { if(0 != updateHandle) { throw new InternalError("XXX1"); @@ -89,5 +97,8 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { updateHandle = 0; } super.destroyImpl(); - } + } + + private long updateHandle = 0; + private int lastWidth, lastHeight; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java index 24276c39e..80c54042f 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java @@ -40,44 +40,20 @@ package jogamp.opengl.macosx.cgl; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable { - private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); - + protected MacOSXOnscreenCGLDrawable(GLDrawableFactory factory, NativeSurface component) { super(factory, component, false); } public GLContext createContext(GLContext shareWith) { - MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); - // NOTE: we need to keep track of the created contexts in order to - // implement swapBuffers() because of how Mac OS X implements its - // OpenGL window interface - synchronized (createdContexts) { - createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); - } + final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); + registerContext(ctx); return ctx; } - protected void swapBuffersImpl() { - synchronized (createdContexts) { - for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { - WeakReference<MacOSXCGLContext> ref = iter.next(); - MacOSXCGLContext ctx = ref.get(); - if (ctx != null) { - ctx.swapBuffers(); - } else { - iter.remove(); - } - } - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java index c5743b923..7ba7d2d5a 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java @@ -33,19 +33,16 @@ package jogamp.opengl.macosx.cgl; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; +import jogamp.opengl.GLContextImpl; public class MacOSXPbufferCGLContext extends MacOSXCGLContext { // State for render-to-texture and render-to-texture-rectangle support - private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV private int texture; // actual texture object public MacOSXPbufferCGLContext(MacOSXPbufferCGLDrawable drawable, @@ -55,7 +52,7 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { public void bindPbufferToTexture() { GL gl = getGL(); - gl.glBindTexture(textureTarget, texture); + gl.glBindTexture(((MacOSXPbufferCGLDrawable)drawable).getTextureTarget(), texture); // FIXME: not clear whether this is really necessary, but since // the API docs seem to imply it is and since it doesn't seem to // impact performance, leaving it in @@ -65,23 +62,14 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { public void releasePbufferFromTexture() { } - protected void makeCurrentImpl(boolean newCreated) throws GLException { - super.makeCurrentImpl(newCreated); - - if (newCreated) { + protected boolean createImpl(GLContextImpl shareWith) { + boolean res = super.createImpl(shareWith); + if(res) { // Initialize render-to-texture support if requested - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GL gl = getGL(); - boolean rect = gl.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle(); - if (rect) { - if (!gl.isExtensionAvailable("GL_EXT_texture_rectangle")) { - System.err.println("MacOSXPbufferCGLContext: WARNING: GL_EXT_texture_rectangle extension not " + - "supported; skipping requested render_to_texture_rectangle support for pbuffer"); - rect = false; - } - } - textureTarget = (rect ? GL2.GL_TEXTURE_RECTANGLE : GL.GL_TEXTURE_2D); + final GL gl = getGL(); + final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; + final int textureTarget = osxPDrawable.getTextureTarget(); + int[] tmp = new int[1]; gl.glGenTextures(1, tmp, 0); texture = tmp[0]; @@ -90,8 +78,11 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, drawable.getWidth(), drawable.getHeight(), 0); + gl.glTexImage2D(textureTarget, 0, GL.GL_RGB, osxPDrawable.getTextureWidth(), osxPDrawable.getTextureHeight(), + 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, null); + gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, drawable.getWidth(), drawable.getHeight()); } + return res; } public int getFloatingPointMode() { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index fdbfaf6d6..e02c3efec 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -51,14 +51,10 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import jogamp.opengl.Debug; - import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.opengl.util.GLBuffers; - -public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { - private static final boolean DEBUG = Debug.debug("MacOSXPbufferCGLDrawable"); - +public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // Abstract interface for implementation of this drawable (either // NSOpenGL-based or CGL-based) interface GLBackendImpl { @@ -76,34 +72,46 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // Note that we can not store this in the NativeSurface because the // semantic is that contains an NSView protected long pBuffer; + protected int pBufferTexTarget, pBufferTexWidth, pBufferTexHeight; public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); - - if (DEBUG) { - System.err.println("Created pbuffer " + this); - } + super(factory, target, false); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } public GLContext createContext(GLContext shareWith) { - return new MacOSXPbufferCGLContext(this, shareWith); + final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith); + registerContext(ctx); + return ctx; } - protected void destroyImpl() { + @Override + protected long getNSViewHandle() { + // pbuffer handle is NSOpenGLPixelBuffer + return 0; + } + + @Override + public long getHandle() { + return pBuffer; + } + + protected int getTextureTarget() { return pBufferTexTarget; } + protected int getTextureWidth() { return pBufferTexWidth; } + protected int getTextureHeight() { return pBufferTexHeight; } + + protected void destroyPbuffer() { if (this.pBuffer != 0) { NativeSurface ns = getNativeSurface(); impl.destroy(pBuffer); @@ -112,73 +120,56 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } } - public long getHandle() { - return pBuffer; - } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); + private void createPbuffer() { + final NativeSurface ns = getNativeSurface(); + final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration(); + final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + final GLProfile glProfile = capabilities.getGLProfile(); + MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice()); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); } - } - private void createPbuffer() { - NativeSurface ns = getNativeSurface(); - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GLProfile glProfile = capabilities.getGLProfile(); - int renderTarget; - if (glProfile.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle()) { - renderTarget = GL2.GL_TEXTURE_RECTANGLE; + if ( capabilities.getPbufferRenderToTextureRectangle() && null!=sr && sr.isRECTTextureAvailable() ) { + pBufferTexTarget = GL2.GL_TEXTURE_RECTANGLE; } else { - int w = getNextPowerOf2(getWidth()); - int h = getNextPowerOf2(getHeight()); - ((SurfaceChangeable)ns).setSize(w, h); - renderTarget = GL.GL_TEXTURE_2D; + pBufferTexTarget = GL.GL_TEXTURE_2D; + } + if ( GL2.GL_TEXTURE_RECTANGLE == pBufferTexTarget || ( null!=sr && sr.isNPOTTextureAvailable() ) ) { + pBufferTexWidth = getWidth(); + pBufferTexHeight = getHeight(); + } else { + pBufferTexWidth = GLBuffers.getNextPowerOf2(getWidth()); + pBufferTexHeight = GLBuffers.getNextPowerOf2(getHeight()); } int internalFormat = GL.GL_RGBA; if (capabilities.getPbufferFloatingPointBuffers()) { - // FIXME: want to check availability of GL_APPLE_float_pixels - // extension, but need valid OpenGL context in order to do so -- - // in worst case would need to create dummy window / GLCanvas - // (undesirable) -- could maybe also do this with pbuffers - /* - if (!gl.isExtensionAvailable("GL_APPLE_float_pixels")) { - throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); - } - */ - if(glProfile.isGL2GL3()) { - switch (capabilities.getRedBits()) { + if(!glProfile.isGL2GL3() || null==sr || sr.isAppletFloatPixelsAvailable()) { + throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); + } + switch (capabilities.getRedBits()) { case 16: internalFormat = GL2.GL_RGBA_FLOAT16_APPLE; break; case 32: internalFormat = GL2.GL_RGBA_FLOAT32_APPLE; break; default: throw new GLException("Invalid floating-point bit depth (only 16 and 32 supported)"); - } - } else { - internalFormat = GL.GL_RGBA; } } - - pBuffer = impl.create(renderTarget, internalFormat, getWidth(), getHeight()); + + pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); + if(DEBUG) { + System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+ + ", pbufferSize "+getWidth()+"x"+getHeight()+ + ", texSize "+pBufferTexWidth+"x"+pBufferTexHeight+ + ", internal-fmt "+toHexString(internalFormat)); + System.err.println("MacOSXPbufferCGLDrawable pBuffer: "+toHexString(pBuffer)); + // Thread.dumpStack(); + } if (pBuffer == 0) { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } ((SurfaceChangeable)ns).setSurfaceHandle(pBuffer); - - } - - private int getNextPowerOf2(int number) { - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); } public void setOpenGLMode(GLBackendType mode) { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java index 68e82dc19..a8c04eee4 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXAWTCGLGraphicsConfigurationFactory.java @@ -58,8 +58,10 @@ import jogamp.opengl.macosx.cgl.MacOSXCGLGraphicsConfiguration; public class MacOSXAWTCGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); - public MacOSXAWTCGLGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, this); + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, new MacOSXAWTCGLGraphicsConfigurationFactory()); + } + private MacOSXAWTCGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( @@ -72,7 +74,7 @@ public class MacOSXAWTCGLGraphicsConfigurationFactory extends GLGraphicsConfigur } if(null==absScreen) { - absScreen = AWTGraphicsScreen.createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); + absScreen = AWTGraphicsScreen.createDefault(); } AWTGraphicsScreen awtScreen = (AWTGraphicsScreen) absScreen; device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXJava2DCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXJava2DCGLContext.java index ae58f6811..70416d1f4 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXJava2DCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/awt/MacOSXJava2DCGLContext.java @@ -44,6 +44,7 @@ import java.awt.Graphics; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; +import jogamp.opengl.GLContextImpl; import jogamp.opengl.awt.Java2D; import jogamp.opengl.awt.Java2DGLContext; import jogamp.opengl.macosx.cgl.MacOSXCGLContext; @@ -73,20 +74,30 @@ public class MacOSXJava2DCGLContext extends MacOSXCGLContext implements Java2DGL this.graphics = g; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { if (!Java2D.makeOGLContextCurrentOnSurface(graphics, contextHandle)) { throw new GLException("Error making context current"); } } - protected boolean createImpl() { - long share = createImplPreset(); + protected boolean createImpl(GLContextImpl shareWith) { + long share = createImplPreset(shareWith); long ctx = Java2D.createOGLContextOnSurface(graphics, share); if (ctx == 0) { + if(DEBUG) { + System.err.println("Error creating current: "+this); + } return false; } - setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + if (!Java2D.makeOGLContextCurrentOnSurface(graphics, contextHandle)) { + Java2D.destroyOGLContext(ctx); + if(DEBUG) { + System.err.println("Error making created context current: "+this); + } + return false; + } + setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION contextHandle = ctx; return true; } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java new file mode 100644 index 000000000..845d749ba --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WGLUtil.java @@ -0,0 +1,95 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl.windows.wgl; + +import java.security.AccessController; + +import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; +import jogamp.opengl.Debug; + +public class WGLUtil { + /** + * Switch to use the <code>wgl</code> variants of {@link jogamp.opengl.windows.wgl.WGL} + * to replace the following 5 GDI based functions (see below). + * <p> + * Disabled per default. + * </p> + * <p> + * You can enable it by defining the property <code>jogl.windows.useWGLVersionOf5WGLGDIFuncSet</code>. + * </p> + * + * @see jogamp.nativewindow.windows.GDI#ChoosePixelFormat(long, PIXELFORMATDESCRIPTOR) + * @see jogamp.nativewindow.windows.GDI#DescribePixelFormat(long, int, int, PIXELFORMATDESCRIPTOR) + * @see jogamp.nativewindow.windows.GDI#GetPixelFormat(long) + * @see jogamp.nativewindow.windows.GDI#SetPixelFormat(long, int, PIXELFORMATDESCRIPTOR) + * @see jogamp.nativewindow.windows.GDI#SwapBuffers(long) + */ + public static final boolean USE_WGLVersion_Of_5WGLGDIFuncSet; + + static { + USE_WGLVersion_Of_5WGLGDIFuncSet = Debug.isPropertyDefined("jogl.windows.useWGLVersionOf5WGLGDIFuncSet", true, AccessController.getContext()); + System.err.println("USE_WGLVersion_Of_5WGLGDIFuncSet: "+USE_WGLVersion_Of_5WGLGDIFuncSet); + } + + public static int ChoosePixelFormat(long hdc, PIXELFORMATDESCRIPTOR pfd) { + if(USE_WGLVersion_Of_5WGLGDIFuncSet) { + return WGL.wglChoosePixelFormat(hdc, pfd); + } else { + return GDI.ChoosePixelFormat(hdc, pfd); + } + } + public static int DescribePixelFormat(long hdc, int pfdid, int pfdSize, PIXELFORMATDESCRIPTOR pfd) { + if(USE_WGLVersion_Of_5WGLGDIFuncSet) { + return WGL.wglDescribePixelFormat(hdc, pfdid, pfdSize, pfd); + } else { + return GDI.DescribePixelFormat(hdc, pfdid, pfdSize, pfd); + } + } + public static int GetPixelFormat(long hdc) { + if(USE_WGLVersion_Of_5WGLGDIFuncSet) { + return WGL.wglGetPixelFormat(hdc); + } else { + return GDI.GetPixelFormat(hdc); + } + } + public static boolean SetPixelFormat(long hdc, int pfdid, PIXELFORMATDESCRIPTOR pfd) { + if(USE_WGLVersion_Of_5WGLGDIFuncSet) { + return WGL.wglSetPixelFormat(hdc, pfdid, pfd); + } else { + return GDI.SetPixelFormat(hdc, pfdid, pfd); + } + } + public static boolean SwapBuffers(long hdc) { + if(USE_WGLVersion_Of_5WGLGDIFuncSet) { + return WGL.wglSwapBuffers(hdc); + } else { + return GDI.SwapBuffers(hdc); + } + } +} diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java index b2c95de39..574226570 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java @@ -57,15 +57,18 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { private long hbitmap; protected WindowsBitmapWGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createBitmap(); } else { - destroyImpl(); + destroyBitmap(); } } @@ -73,13 +76,13 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { return new WindowsBitmapWGLContext(this, shareWith); } - private void create() { + private void createBitmap() { int werr; NativeSurface ns = getNativeSurface(); if(DEBUG) { System.err.println("WindowsBitmapWGLDrawable (1): "+ns); } - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration(); GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getRequestedCapabilities(); int width = getWidth(); int height = getHeight(); @@ -153,7 +156,7 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { config.updateGraphicsConfiguration(getFactory(), ns, null); } - protected void destroyImpl() { + protected void destroyBitmap() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { // Must destroy bitmap and device context @@ -165,11 +168,4 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { ((SurfaceChangeable)ns).setSurfaceHandle(0); } } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java index 3d0cce725..0bd83b923 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java @@ -46,6 +46,8 @@ import javax.media.opengl.GLProfile; import javax.media.nativewindow.AbstractGraphicsScreen; import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLException; @@ -63,7 +65,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { throw new GLException("WindowsDummyWGLDrawable: surface not ready (lockSurface)"); } try { - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration(); config.updateGraphicsConfiguration(factory, ns, null); if (DEBUG) { System.err.println("!!! WindowsDummyWGLDrawable: "+config); @@ -84,7 +86,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { GLCapabilities caps = new GLCapabilities(glp); WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.createDefaultGraphicsConfiguration(caps, absScreen); GDISurface ns = new GDISurface(cfg, windowHandle); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return new WindowsDummyWGLDrawable(factory, ns, handleWindowLifecycle); } @@ -96,7 +98,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { protected void destroyImpl() { if (handleHwndLifecycle && hwnd != 0) { GDI.ShowWindow(hwnd, GDI.SW_HIDE); - GDI.DestroyDummyWindow(hwnd); + GDIUtil.DestroyDummyWindow(hwnd); hwnd = 0; } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java index c3588fd48..b183ad59f 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java @@ -65,7 +65,7 @@ public class WindowsExternalWGLContext extends WindowsWGLContext { System.err.println(getThreadName() + ": !!! Created external OpenGL context " + toHexString(ctx) + " for " + this); } GLContextShareSet.contextCreated(this); - setGLFunctionAvailability(false, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION getGLStateTracker().setEnabled(false); // external context usage can't track state in Java } @@ -85,7 +85,7 @@ public class WindowsExternalWGLContext extends WindowsWGLContext { } AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); WindowsWGLGraphicsConfiguration cfg; - final int pfdID = GDI.GetPixelFormat(hdc); + final int pfdID = WGLUtil.GetPixelFormat(hdc); if (0 == pfdID) { // This could have happened if the HDC was released right after the GL ctx made current (SWT), // WinXP-32bit will not be able to use this HDC afterwards. @@ -122,7 +122,7 @@ public class WindowsExternalWGLContext extends WindowsWGLContext { lastContext = null; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { } protected void releaseImpl() throws GLException { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java index ede504735..1e5991821 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java @@ -63,7 +63,7 @@ public class WindowsExternalWGLDrawable extends WindowsWGLDrawable { if (0==hdc) { throw new GLException("Error: attempted to make an external GLDrawable without a drawable current, werr " + GDI.GetLastError()); } - int pfdID = GDI.GetPixelFormat(hdc); + int pfdID = WGLUtil.GetPixelFormat(hdc); if (pfdID == 0) { throw new GLException("Error: attempted to make an external GLContext without a valid pixelformat, werr " + GDI.GetLastError()); } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsOnscreenWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsOnscreenWGLDrawable.java index 4f34c946a..6ad330ccc 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsOnscreenWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsOnscreenWGLDrawable.java @@ -42,7 +42,6 @@ package jogamp.opengl.windows.wgl; import javax.media.nativewindow.*; import javax.media.opengl.*; -import jogamp.opengl.*; public class WindowsOnscreenWGLDrawable extends WindowsWGLDrawable { protected WindowsOnscreenWGLDrawable(GLDrawableFactory factory, NativeSurface component) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLContext.java index 97c63ea52..0f610495d 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLContext.java @@ -42,6 +42,8 @@ package jogamp.opengl.windows.wgl; import javax.media.opengl.*; +import jogamp.opengl.GLContextImpl; + public class WindowsPbufferWGLContext extends WindowsWGLContext { // State for render-to-texture and render-to-texture-rectangle support private boolean rtt; // render-to-texture? @@ -86,9 +88,9 @@ public class WindowsPbufferWGLContext extends WindowsWGLContext { } } - protected void makeCurrentImpl(boolean newCreated) throws GLException { - super.makeCurrentImpl(newCreated); - if (newCreated) { + protected boolean createImpl(GLContextImpl shareWith) { + boolean res = super.createImpl(shareWith); + if(res) { GLCapabilitiesImmutable capabilities = drawable.getChosenGLCapabilities(); // Initialize render-to-texture support if requested @@ -135,6 +137,7 @@ public class WindowsPbufferWGLContext extends WindowsWGLContext { } } } + return res; } public int getFloatingPointMode() { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java index 7be2c1ac7..0988f3eca 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java @@ -41,6 +41,7 @@ package jogamp.opengl.windows.wgl; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.SurfaceChangeable; import javax.media.opengl.GL; import javax.media.opengl.GLContext; @@ -51,6 +52,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory.SharedResource; import javax.media.opengl.GLCapabilitiesImmutable; @@ -60,27 +62,20 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { private long buffer; // pbuffer handle private int floatMode; - - protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target, - WindowsWGLDrawableFactory.SharedResource sharedResource) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(sharedResource); - - if (DEBUG) { - System.err.println("Created pbuffer " + this); - } + + protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target) { + super(factory, target, false); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - throw new GLException("Recreation via setRealized not supported."); + createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -88,7 +83,7 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return new WindowsPbufferWGLContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if(0!=buffer) { WGLExt wglExt = cachedWGLExt; @@ -120,147 +115,154 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return floatMode; } - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); + private void createPbuffer() { + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration(); + SharedResource sharedResource = ((WindowsWGLDrawableFactory)factory).getOrCreateSharedResource(config.getScreen().getDevice()); + NativeSurface sharedSurface = sharedResource.getDrawable().getNativeSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= sharedSurface.lockSurface()) { + throw new NativeWindowException("Could not lock (sharedSurface): "+this); } - } - - private void createPbuffer(WindowsWGLDrawableFactory.SharedResource sharedResource) { - long parentHdc = sharedResource.getDrawable().getNativeSurface().getSurfaceHandle(); - WGLExt wglExt = sharedResource.getContext().getWGLExt(); + try { + long sharedHdc = sharedSurface.getSurfaceHandle(); + WGLExt wglExt = sharedResource.getContext().getWGLExt(); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } - int[] iattributes = new int [2*WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; - float[] fattributes = new float[1]; - int[] floatModeTmp = new int[1]; - int niattribs = 0; - int width, height; - - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GLProfile glProfile = chosenCaps.getGLProfile(); - - if (DEBUG) { - System.out.println("Pbuffer parentHdc = " + toHexString(parentHdc)); - System.out.println("Pbuffer chosenCaps: " + chosenCaps); - } - - if(!WindowsWGLGraphicsConfiguration.GLCapabilities2AttribList(chosenCaps, - iattributes, sharedResource, -1, floatModeTmp)){ - throw new GLException("Pbuffer-related extensions not supported"); - } - - floatMode = floatModeTmp[0]; - boolean rtt = chosenCaps.getPbufferRenderToTexture(); - boolean rect = chosenCaps.getPbufferRenderToTextureRectangle(); - boolean useFloat = chosenCaps.getPbufferFloatingPointBuffers(); - // boolean ati = false; - - /** - if (useFloat) { - ati = (floatMode == GLPbuffer.ATI_FLOAT); - } */ - - int[] pformats = new int[WindowsWGLGraphicsConfiguration.MAX_PFORMATS]; - int nformats; - int[] nformatsTmp = new int[1]; - if (!wglExt.wglChoosePixelFormatARB(parentHdc, - iattributes, 0, - fattributes, 0, - WindowsWGLGraphicsConfiguration.MAX_PFORMATS, - pformats, 0, - nformatsTmp, 0)) { - throw new GLException("pbuffer creation error: wglChoosePixelFormat() failed"); - } - nformats = nformatsTmp[0]; - if (nformats <= 0) { - throw new GLException("pbuffer creation error: Couldn't find a suitable pixel format"); - } - - if (DEBUG) { - System.err.println("" + nformats + " suitable pixel formats found"); - for (int i = 0; i < nformats; i++) { - WGLGLCapabilities dbgCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, parentHdc, pformats[i], glProfile, false, true); - System.err.println("pixel format " + pformats[i] + " (index " + i + "): " + dbgCaps); - } - } - - int pfdid = 0; - long tmpBuffer = 0; - { - int whichFormat; - // Loop is a workaround for bugs in NVidia's recent drivers - for (whichFormat = 0; whichFormat < nformats; whichFormat++) { - int format = pformats[whichFormat]; - - // Create the p-buffer. - niattribs = 0; - - if (rtt) { - iattributes[niattribs++] = WGLExt.WGL_TEXTURE_FORMAT_ARB; - if (useFloat) { - iattributes[niattribs++] = WGLExt.WGL_TEXTURE_FLOAT_RGB_NV; - } else { - iattributes[niattribs++] = WGLExt.WGL_TEXTURE_RGBA_ARB; + int[] iattributes = new int [2*WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; + float[] fattributes = new float[1]; + int[] floatModeTmp = new int[1]; + int niattribs = 0; + int width, height; + + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + GLProfile glProfile = chosenCaps.getGLProfile(); + + if (DEBUG) { + System.out.println("Pbuffer parentHdc = " + toHexString(sharedHdc)); + System.out.println("Pbuffer chosenCaps: " + chosenCaps); + } + + if(!WindowsWGLGraphicsConfiguration.GLCapabilities2AttribList(chosenCaps, + iattributes, sharedResource, -1, floatModeTmp)){ + throw new GLException("Pbuffer-related extensions not supported"); + } + + floatMode = floatModeTmp[0]; + boolean rtt = chosenCaps.getPbufferRenderToTexture(); + boolean rect = chosenCaps.getPbufferRenderToTextureRectangle(); + boolean useFloat = chosenCaps.getPbufferFloatingPointBuffers(); + // boolean ati = false; + + /** + if (useFloat) { + ati = (floatMode == GLPbuffer.ATI_FLOAT); + } */ + + int[] pformats = new int[WindowsWGLGraphicsConfiguration.MAX_PFORMATS]; + int nformats; + int[] nformatsTmp = new int[1]; + if (!wglExt.wglChoosePixelFormatARB(sharedHdc, + iattributes, 0, + fattributes, 0, + WindowsWGLGraphicsConfiguration.MAX_PFORMATS, + pformats, 0, + nformatsTmp, 0)) { + throw new GLException("pbuffer creation error: wglChoosePixelFormat() failed"); + } + nformats = nformatsTmp[0]; + if (nformats <= 0) { + throw new GLException("pbuffer creation error: Couldn't find a suitable pixel format"); + } + + if (DEBUG) { + System.err.println("" + nformats + " suitable pixel formats found"); + for (int i = 0; i < nformats; i++) { + WGLGLCapabilities dbgCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, sharedHdc, pformats[i], glProfile, false, true); + System.err.println("pixel format " + pformats[i] + " (index " + i + "): " + dbgCaps); + } + } + + int pfdid = 0; + long tmpBuffer = 0; + { + int whichFormat; + // Loop is a workaround for bugs in NVidia's recent drivers + for (whichFormat = 0; whichFormat < nformats; whichFormat++) { + int format = pformats[whichFormat]; + + // Create the p-buffer. + niattribs = 0; + + if (rtt) { + iattributes[niattribs++] = WGLExt.WGL_TEXTURE_FORMAT_ARB; + if (useFloat) { + iattributes[niattribs++] = WGLExt.WGL_TEXTURE_FLOAT_RGB_NV; + } else { + iattributes[niattribs++] = WGLExt.WGL_TEXTURE_RGBA_ARB; + } + + iattributes[niattribs++] = WGLExt.WGL_TEXTURE_TARGET_ARB; + iattributes[niattribs++] = rect ? WGLExt.WGL_TEXTURE_RECTANGLE_NV : WGLExt.WGL_TEXTURE_2D_ARB; + + iattributes[niattribs++] = WGLExt.WGL_MIPMAP_TEXTURE_ARB; + iattributes[niattribs++] = GL.GL_FALSE; + + iattributes[niattribs++] = WGLExt.WGL_PBUFFER_LARGEST_ARB; + iattributes[niattribs++] = GL.GL_FALSE; + } + + iattributes[niattribs++] = 0; + + tmpBuffer = wglExt.wglCreatePbufferARB(sharedHdc, format, getWidth(), getHeight(), iattributes, 0); + if (tmpBuffer != 0) { + // Done + break; + } } - - iattributes[niattribs++] = WGLExt.WGL_TEXTURE_TARGET_ARB; - iattributes[niattribs++] = rect ? WGLExt.WGL_TEXTURE_RECTANGLE_NV : WGLExt.WGL_TEXTURE_2D_ARB; - - iattributes[niattribs++] = WGLExt.WGL_MIPMAP_TEXTURE_ARB; - iattributes[niattribs++] = GL.GL_FALSE; - - iattributes[niattribs++] = WGLExt.WGL_PBUFFER_LARGEST_ARB; - iattributes[niattribs++] = GL.GL_FALSE; + + if (0 == tmpBuffer) { + throw new GLException("pbuffer creation error: wglCreatePbuffer() failed: tried " + nformats + + " pixel formats, last error was: " + wglGetLastError()); + } + pfdid = pformats[whichFormat]; + } + + // Get the device context. + long tmpHdc = wglExt.wglGetPbufferDCARB(tmpBuffer); + if (tmpHdc == 0) { + throw new GLException("pbuffer creation error: wglGetPbufferDC() failed"); + } + + NativeSurface ns = getNativeSurface(); + // Set up instance variables + buffer = tmpBuffer; + ((SurfaceChangeable)ns).setSurfaceHandle(tmpHdc); + cachedWGLExt = wglExt; + + // Re-query chosen pixel format + { + WGLGLCapabilities newCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, sharedHdc, pfdid, glProfile, false, true); + if(null == newCaps) { + throw new GLException("pbuffer creation error: unable to re-query chosen PFD ID: " + pfdid + ", hdc " + GLDrawableImpl.toHexString(tmpHdc)); } - - iattributes[niattribs++] = 0; - - tmpBuffer = wglExt.wglCreatePbufferARB(parentHdc, format, getWidth(), getHeight(), iattributes, 0); - if (tmpBuffer != 0) { - // Done - break; + if(newCaps.isOnscreen() || !newCaps.isPBuffer()) { + throw new GLException("Error: Selected Onscreen Caps for PBuffer: "+newCaps); } + config.setCapsPFD(newCaps); } - - if (0 == tmpBuffer) { - throw new GLException("pbuffer creation error: wglCreatePbuffer() failed: tried " + nformats + - " pixel formats, last error was: " + wglGetLastError()); - } - pfdid = pformats[whichFormat]; - } - - // Get the device context. - long tmpHdc = wglExt.wglGetPbufferDCARB(tmpBuffer); - if (tmpHdc == 0) { - throw new GLException("pbuffer creation error: wglGetPbufferDC() failed"); - } - - NativeSurface ns = getNativeSurface(); - // Set up instance variables - buffer = tmpBuffer; - ((SurfaceChangeable)ns).setSurfaceHandle(tmpHdc); - cachedWGLExt = wglExt; - - // Re-query chosen pixel format - { - WGLGLCapabilities newCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, parentHdc, pfdid, glProfile, false, true); - if(null == newCaps) { - throw new GLException("pbuffer creation error: unable to re-query chosen PFD ID: " + pfdid + ", hdc " + GLDrawableImpl.toHexString(tmpHdc)); - } - if(newCaps.isOnscreen() || !newCaps.isPBuffer()) { - throw new GLException("Error: Selected Onscreen Caps for PBuffer: "+newCaps); - } - config.setCapsPFD(newCaps); + + // Determine the actual width and height we were able to create. + int[] tmp = new int[1]; + wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_WIDTH_ARB, tmp, 0 ); + width = tmp[0]; + wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); + height = tmp[0]; + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); + } finally { + sharedSurface.unlockSurface(); } - - // Determine the actual width and height we were able to create. - int[] tmp = new int[1]; - wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_WIDTH_ARB, tmp, 0 ); - width = tmp[0]; - wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); - height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); } private static String wglGetLastError() { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index 8f2ec74af..ff59e1518 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -55,7 +55,6 @@ import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLContextImpl; -import jogamp.opengl.GLContextShareSet; import jogamp.opengl.GLDrawableImpl; public class WindowsWGLContext extends GLContextImpl { @@ -118,7 +117,7 @@ public class WindowsWGLContext extends GLContextImpl { public final boolean isGLReadDrawableAvailable() { if(!wglGLReadDrawableAvailableSet && null != getWGLExtProcAddressTable()) { WindowsWGLDrawableFactory factory = (WindowsWGLDrawableFactory)drawable.getFactoryImpl(); - AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); switch( factory.isReadDrawableAvailable(device) ) { case 1: @@ -257,20 +256,19 @@ public class WindowsWGLContext extends GLContextImpl { * Creates and initializes an appropriate OpenGL context. Should only be * called by {@link #makeCurrentImpl()}. */ - protected boolean createImpl() { - WindowsWGLDrawableFactory factory = (WindowsWGLDrawableFactory)drawable.getFactoryImpl(); - AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + protected boolean createImpl(GLContextImpl shareWith) { + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); + WindowsWGLDrawableFactory factory = (WindowsWGLDrawableFactory)drawable.getFactoryImpl(); WindowsWGLContext sharedContext = (WindowsWGLContext) factory.getOrCreateSharedContextImpl(device); GLCapabilitiesImmutable glCaps = drawable.getChosenGLCapabilities(); isGLReadDrawableAvailable(); // trigger setup wglGLReadDrawableAvailable // Windows can set up sharing of display lists after creation time - WindowsWGLContext other = (WindowsWGLContext) GLContextShareSet.getShareContext(this); long share = 0; - if (other != null) { - share = other.getHandle(); + if (null != shareWith) { + share = shareWith.getHandle(); if (share == 0) { throw new GLException("GLContextShareSet returned an invalid OpenGL context"); } @@ -298,7 +296,7 @@ public class WindowsWGLContext extends GLContextImpl { if (!WGL.wglMakeCurrent(drawable.getHandle(), temp_ctx)) { throw new GLException("Error making temp context current: 0x" + toHexString(temp_ctx) + ", werr: "+GDI.GetLastError()); } - setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION boolean isCreateContextAttribsARBAvailable = isFunctionAvailable("wglCreateContextAttribsARB"); WGL.wglMakeCurrent(0, 0); // release temp context @@ -334,7 +332,7 @@ public class WindowsWGLContext extends GLContextImpl { if(glCaps.getGLProfile().isGL3()) { WGL.wglMakeCurrent(0, 0); WGL.wglDeleteContext(temp_ctx); - throw new GLException("WindowsWGLContext.createContext failed, but context > GL2 requested "+getGLVersion()+", "); + throw new GLException("WindowsWGLContext.createContext ctx !ARB, context > GL2 requested "+getGLVersion()); } if(DEBUG) { System.err.println("WindowsWGLContext.createContext failed, fall back to !ARB context "+getGLVersion()); @@ -347,29 +345,26 @@ public class WindowsWGLContext extends GLContextImpl { WGL.wglDeleteContext(contextHandle); throw new GLException("Error making old context current: 0x" + toHexString(contextHandle) + ", werr: " + GDI.GetLastError()); } + if(0!=share) { + // Only utilize the classic GDI 'wglShareLists' shared context method + // for traditional non ARB context. + if (!WGL.wglShareLists(share, contextHandle)) { + throw new GLException("wglShareLists(" + toHexString(share) + + ", " + toHexString(contextHandle) + ") failed: werr " + GDI.GetLastError()); + } + } if (DEBUG) { System.err.println(getThreadName() + ": createImpl: OK (old) share "+share); } } - if(0!=share) { - if (!WGL.wglShareLists(share, contextHandle)) { - throw new GLException("wglShareLists(" + toHexString(share) + - ", " + toHexString(contextHandle) + ") failed: werr " + GDI.GetLastError()); - } - } return true; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { if (WGL.wglGetCurrentContext() != contextHandle) { if (!wglMakeContextCurrent(drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { throw new GLException("Error making context current: 0x" + toHexString(contextHandle) + ", werr: " + GDI.GetLastError() + ", " + this); - } else { - if (DEBUG && newCreated) { - System.err.println(getThreadName() + ": wglMakeCurrent(hdc " + toHexString(drawable.getHandle()) + - ", contextHandle " + toHexString(contextHandle) + ") succeeded"); - } } } } @@ -394,7 +389,7 @@ public class WindowsWGLContext extends GLContextImpl { } protected final void updateGLXProcAddressTable() { - final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "WGL-"+adevice.getUniqueID(); if (DEBUG) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index 4ed9a00c3..b96e0cd9b 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -41,6 +41,7 @@ package jogamp.opengl.windows.wgl; import java.security.AccessController; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -67,30 +68,31 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl { } NativeSurface ns = getNativeSurface(); - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration)ns.getGraphicsConfiguration(); config.updateGraphicsConfiguration(getFactory(), ns, null); if (DEBUG) { System.err.println("!!! WindowsWGLDrawable.setRealized(true): "+config); } } - protected void swapBuffersImpl() { - long startTime = 0; + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + final long t0; if (PROFILING) { - startTime = System.currentTimeMillis(); + t0 = System.currentTimeMillis(); + } else { + t0 = 0; } - if (!GDI.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) { + if (!WGLUtil.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) { throw new GLException("Error swapping buffers"); } if (PROFILING) { - long endTime = System.currentTimeMillis(); - profilingSwapBuffersTime += (endTime - startTime); - int ticks = PROFILING_TICKS; - if (++profilingSwapBuffersTicks == ticks) { - System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + ticks + " calls (" + - ((float) profilingSwapBuffersTime / (float) ticks) + " ms/call)"); + profilingSwapBuffersTime += System.currentTimeMillis() - t0; + if (++profilingSwapBuffersTicks == PROFILING_TICKS) { + System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + PROFILING_TICKS + " calls (" + + ((float) profilingSwapBuffersTime / (float) PROFILING_TICKS) + " ms/call)"); profilingSwapBuffersTime = 0; profilingSwapBuffersTicks = 0; } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index cd22127a3..43c16240d 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -42,7 +42,6 @@ package jogamp.opengl.windows.wgl; import java.nio.Buffer; import java.nio.ShortBuffer; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -62,6 +61,7 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import javax.media.opengl.GLProfile.ShutdownType; import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.nio.PointerBuffer; @@ -71,6 +71,7 @@ import com.jogamp.common.util.VersionNumber; import jogamp.nativewindow.WrappedSurface; import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.windows.GDISurface; import jogamp.nativewindow.windows.RegisteredClassFactory; import jogamp.opengl.DesktopGLDynamicLookupHelper; @@ -80,60 +81,81 @@ import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.SharedResourceRunner; public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { - private static final DesktopGLDynamicLookupHelper windowsWGLDynamicLookupHelper; + private static DesktopGLDynamicLookupHelper windowsWGLDynamicLookupHelper = null; + + public WindowsWGLDrawableFactory() { + super(); - static { - DesktopGLDynamicLookupHelper tmp = null; - try { - tmp = new DesktopGLDynamicLookupHelper(new WindowsWGLDynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + synchronized(WindowsWGLDrawableFactory.class) { + if(null==windowsWGLDynamicLookupHelper) { + DesktopGLDynamicLookupHelper tmp = null; + try { + tmp = new DesktopGLDynamicLookupHelper(new WindowsWGLDynamicLibraryBundleInfo()); + } catch (GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + windowsWGLDynamicLookupHelper = tmp; + if(null!=windowsWGLDynamicLookupHelper) { + WGL.getWGLProcAddressTable().reset(windowsWGLDynamicLookupHelper); + } } } - windowsWGLDynamicLookupHelper = tmp; + if(null!=windowsWGLDynamicLookupHelper) { - WGL.getWGLProcAddressTable().reset(windowsWGLDynamicLookupHelper); + // Register our GraphicsConfigurationFactory implementations + // The act of constructing them causes them to be registered + WindowsWGLGraphicsConfigurationFactory.registerFactory(); + if(GLProfile.isAWTAvailable()) { + try { + ReflectionUtil.callStaticMethod("jogamp.opengl.windows.wgl.awt.WindowsAWTWGLGraphicsConfigurationFactory", + "registerFactory", null, null, getClass().getClassLoader()); + } catch (JogampRuntimeException jre) { /* n/a .. */ } + } + + defaultDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); + sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); + + // Init shared resources off thread + // Will be released via ShutdownHook + sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceRunner.start(); } } - public GLDynamicLookupHelper getGLDynamicLookupHelper(int profile) { - return windowsWGLDynamicLookupHelper; - } - - public WindowsWGLDrawableFactory() { - super(); - - // Register our GraphicsConfigurationFactory implementations - // The act of constructing them causes them to be registered - new WindowsWGLGraphicsConfigurationFactory(); - if(GLProfile.isAWTAvailable()) { - try { - ReflectionUtil.createInstance("jogamp.opengl.windows.wgl.awt.WindowsAWTWGLGraphicsConfigurationFactory", - null, getClass().getClassLoader()); - } catch (JogampRuntimeException jre) { /* n/a .. */ } + protected final void destroy(ShutdownType shutdownType) { + if(null != sharedResourceRunner) { + sharedResourceRunner.stop(); + sharedResourceRunner = null; } + if(null != sharedMap) { + sharedMap.clear(); + sharedMap = null; + } + defaultDevice = null; + /** + * Pulling away the native library may cause havoc .. + * + if(ShutdownType.COMPLETE == shutdownType && null != windowsWGLDynamicLookupHelper) { + windowsWGLDynamicLookupHelper.destroy(); + windowsWGLDynamicLookupHelper = null; + } */ + + RegisteredClassFactory.shutdownSharedClasses(); + } - defaultDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_UNIT); - - // Init shared resources off thread - // Will be released via ShutdownHook - sharedResourceImpl = new SharedResourceImplementation(); - sharedResourceRunner = new SharedResourceRunner(sharedResourceImpl); - sharedResourceThread = new Thread(sharedResourceRunner, Thread.currentThread().getName()+"-SharedResourceRunner"); - sharedResourceThread.setDaemon(true); // Allow JVM to exit, even if this one is running - sharedResourceThread.start(); + public GLDynamicLookupHelper getGLDynamicLookupHelper(int profile) { + return windowsWGLDynamicLookupHelper; } - WindowsGraphicsDevice defaultDevice; - SharedResourceImplementation sharedResourceImpl; - SharedResourceRunner sharedResourceRunner; - Thread sharedResourceThread; - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + private WindowsGraphicsDevice defaultDevice; + private SharedResourceRunner sharedResourceRunner; + private HashMap<String /*connection*/, SharedResourceRunner.Resource> sharedMap; - long processAffinityChanges = 0; - PointerBuffer procMask = PointerBuffer.allocateDirect(1); - PointerBuffer sysMask = PointerBuffer.allocateDirect(1); + private long processAffinityChanges = 0; + private PointerBuffer procMask = PointerBuffer.allocateDirect(1); + private PointerBuffer sysMask = PointerBuffer.allocateDirect(1); protected void enterThreadCriticalZone() { synchronized (sysMask) { @@ -251,15 +273,15 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } public SharedResourceRunner.Resource mapPut(String connection, SharedResourceRunner.Resource resource) { synchronized(sharedMap) { - return (SharedResourceRunner.Resource) sharedMap.put(connection, resource); + return sharedMap.put(connection, resource); } } public SharedResourceRunner.Resource mapGet(String connection) { synchronized(sharedMap) { - return (SharedResourceRunner.Resource) sharedMap.get(connection); + return sharedMap.get(connection); } } - public Collection/*<Resource>*/ mapValues() { + public Collection<SharedResourceRunner.Resource> mapValues() { synchronized(sharedMap) { return sharedMap.values(); } @@ -270,15 +292,12 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { sharedDevice.lock(); try { AbstractGraphicsScreen absScreen = new DefaultGraphicsScreen(sharedDevice, 0); - if (null == absScreen) { - throw new GLException("Couldn't create shared screen for device: "+sharedDevice+", idx 0"); - } GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); if (null == glp) { throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); } final int f_dim = 64; - long hwnd = GDI.CreateDummyWindow(0, 0, f_dim, f_dim); + long hwnd = GDIUtil.CreateDummyWindow(0, 0, f_dim, f_dim); WindowsDummyWGLDrawable sharedDrawable = WindowsDummyWGLDrawable.create(WindowsWGLDrawableFactory.this, glp, absScreen, hwnd, f_dim, f_dim, true); if (null == sharedDrawable) { throw new GLException("Couldn't create shared drawable for screen: "+absScreen+", "+glp); @@ -373,10 +392,21 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { final static String WGL_ARB_make_current_read = "WGL_ARB_make_current_read"; final static String wglMakeContextCurrent = "wglMakeContextCurrent"; - public final boolean getWasSharedContextCreated(AbstractGraphicsDevice device) { - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - return null != sr.getContext(); + protected final Thread getSharedResourceThread() { + return sharedResourceRunner.start(); + } + + protected final boolean createSharedResource(AbstractGraphicsDevice device) { + try { + SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); + if(null!=sr) { + return null != sr.getContext(); + } + } catch (GLException gle) { + if(DEBUG) { + System.err.println("Catched Exception while WindowsWGL Shared Resource initialization"); + gle.printStackTrace(); + } } return false; } @@ -409,11 +439,6 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { return (SharedResource) sharedResourceRunner.getOrCreateShared(device); } - protected final void shutdownInstance() { - sharedResourceRunner.releaseAndWait(); - RegisteredClassFactory.shutdownSharedClasses(); - } - protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(AbstractGraphicsDevice device) { return WindowsWGLGraphicsConfigurationFactory.getAvailableCapabilities(this, device); } @@ -429,40 +454,39 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!chosenCaps.isPBuffer()) { return new WindowsBitmapWGLDrawable(this, target); } // PBuffer GLDrawable Creation + GLDrawableImpl pbufferDrawable; final AbstractGraphicsDevice device = config.getScreen().getDevice(); + /** + * Similar to ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, + * we need to have a context current on the same Display to create a PBuffer. + */ final SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); - if(null==sr) { - throw new IllegalArgumentException("No shared resource for "+device); - } - final List returnList = new ArrayList(); - Runnable r = new Runnable() { - public void run() { - GLContext lastContext = GLContext.getCurrent(); - if (lastContext != null) { + if(null!=sr) { + GLContext lastContext = GLContext.getCurrent(); + if (lastContext != null) { lastContext.release(); - } - sr.context.makeCurrent(); - try { - GLDrawableImpl pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target, sr); - returnList.add(pbufferDrawable); - } finally { + } + sr.context.makeCurrent(); + try { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } finally { sr.context.release(); if (lastContext != null) { lastContext.makeCurrent(); } - } } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); + } else { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } + return pbufferDrawable; } /** @@ -489,7 +513,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); WrappedSurface ns = new WrappedSurface(WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( capsChosen, capsRequested, chooser, screen) ); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 989906514..d6788f1c9 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.List; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GL; @@ -48,13 +47,14 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.windows.DWM_BLURBEHIND; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.MARGINS; import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; import jogamp.opengl.GLGraphicsConfigurationUtil; -public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { // Keep this under the same debug flag as the drawable factory for convenience protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); @@ -149,7 +149,7 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio * @see #isDetermined() */ public final void preselectGraphicsConfiguration(GLDrawableFactory factory, int[] pfdIDs) { - AbstractGraphicsDevice device = getNativeGraphicsConfiguration().getScreen().getDevice(); + AbstractGraphicsDevice device = getScreen().getDevice(); WindowsWGLGraphicsConfigurationFactory.preselectGraphicsConfiguration(chooser, factory, device, this, pfdIDs); } @@ -161,7 +161,7 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio throw new GLException("Error: HDC is null"); } - if (!GDI.SetPixelFormat(hdc, caps.getPFDID(), caps.getPFD())) { + if (!WGLUtil.SetPixelFormat(hdc, caps.getPFDID(), caps.getPFD())) { throw new GLException("Unable to set pixel format " + caps + " for device context " + toHexString(hdc) + ": error code " + GDI.GetLastError()); @@ -610,7 +610,7 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio } PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(); - if (GDI.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { + if (WGLUtil.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { // remove displayable bits, since pfdID is non displayable drawableTypeBits = drawableTypeBits & ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.BITMAP_BIT); if( 0 == drawableTypeBits ) { @@ -629,7 +629,7 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio // static int[] wglAllGDIPFIDs(long hdc) { - int numFormats = GDI.DescribePixelFormat(hdc, 1, 0, null); + int numFormats = WGLUtil.DescribePixelFormat(hdc, 1, 0, null); if (numFormats == 0) { throw new GLException("DescribePixelFormat: No formats - HDC 0x" + Long.toHexString(hdc) + ", LastError: " + GDI.GetLastError()); @@ -733,10 +733,10 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor(long hdc, int pfdID) { PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create(); - pfd.setNSize((short) pfd.size()); + pfd.setNSize((short) PIXELFORMATDESCRIPTOR.size()); pfd.setNVersion((short) 1); if(0 != hdc && 1 <= pfdID) { - if (GDI.DescribePixelFormat(hdc, pfdID, pfd.size(), pfd) == 0) { + if (WGLUtil.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { // Accelerated pixel formats that are non displayable if(DEBUG) { System.err.println("Info: Non displayable pixel format " + pfdID + " of device context: error code " + GDI.GetLastError()); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index a485f8ce8..f02520136 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -67,8 +67,10 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); static WGLGLCapabilities.PfdIDComparator PfdIDComparator = new WGLGLCapabilities.PfdIDComparator(); - WindowsWGLGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.windows.WindowsGraphicsDevice.class, this); + static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.windows.WindowsGraphicsDevice.class, new WindowsWGLGraphicsConfigurationFactory()); + } + private WindowsWGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( @@ -189,7 +191,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if (0 == hdc) { throw new GLException("Error: HDC is null"); } - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) ns.getGraphicsConfiguration(); if( !config.isExternal() ) { if( !config.isDetermined() ) { @@ -198,8 +200,8 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat // set PFD if not set yet int pfdID = -1; boolean set = false; - if ( 1 > ( pfdID = GDI.GetPixelFormat(hdc) ) ) { - if (!GDI.SetPixelFormat(hdc, config.getPixelFormatID(), config.getPixelFormat())) { + if ( 1 > ( pfdID = WGLUtil.GetPixelFormat(hdc) ) ) { + if (!WGLUtil.SetPixelFormat(hdc, config.getPixelFormatID(), config.getPixelFormat())) { throw new GLException("Unable to set pixel format " + config.getPixelFormatID() + " for device context " + toHexString(hdc) + ": error code " + GDI.GetLastError()); @@ -236,7 +238,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } if(NativeSurface.LOCK_SURFACE_NOT_READY >= sharedDrawable.lockSurface()) { - throw new GLException("Surface not ready (lockSurface)"); + throw new GLException("Shared Surface not ready (lockSurface): "+device+" -> "+sharedDrawable); } try { long hdc = sharedDrawable.getHandle(); @@ -309,7 +311,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat WGLGLCapabilities pixelFormatCaps = null; // chosen or preset PFD ID's caps boolean pixelFormatSet = false; // indicates a preset PFD ID [caps] - final int presetPFDID = extHDC ? -1 : GDI.GetPixelFormat(hdc) ; + final int presetPFDID = extHDC ? -1 : WGLUtil.GetPixelFormat(hdc) ; if ( 1 <= presetPFDID ) { // Pixelformat already set by either // - a previous preselectGraphicsConfiguration() call on the same HDC, @@ -431,7 +433,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat WGLGLCapabilities pixelFormatCaps = null; // chosen or preset PFD ID's caps boolean pixelFormatSet = false; // indicates a preset PFD ID [caps] - if ( !extHDC && 1 <= ( pfdID = GDI.GetPixelFormat(hdc) ) ) { + if ( !extHDC && 1 <= ( pfdID = WGLUtil.GetPixelFormat(hdc) ) ) { // Pixelformat already set by either // - a previous preselectGraphicsConfiguration() call on the same HDC, // - the graphics driver, copying the HDC's pixelformat to the new one, @@ -455,7 +457,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice PIXELFORMATDESCRIPTOR pfd = WindowsWGLGraphicsConfiguration.createPixelFormatDescriptor(); pfd = WindowsWGLGraphicsConfiguration.GLCapabilities2PFD(capsChosen, pfd); - pfdID = GDI.ChoosePixelFormat(hdc, pfd); + pfdID = WGLUtil.ChoosePixelFormat(hdc, pfd); int recommendedIndex = -1 ; if( 1 <= pfdID ) { // seek index .. diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java index 1f09180eb..0f9786f1d 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/awt/WindowsAWTWGLGraphicsConfigurationFactory.java @@ -62,8 +62,10 @@ import javax.media.opengl.GLDrawableFactory; public class WindowsAWTWGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); - public WindowsAWTWGLGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, this); + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, new WindowsAWTWGLGraphicsConfigurationFactory()); + } + private WindowsAWTWGLGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( @@ -76,7 +78,7 @@ public class WindowsAWTWGLGraphicsConfigurationFactory extends GLGraphicsConfigu } if(null==absScreen) { - absScreen = AWTGraphicsScreen.createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); + absScreen = AWTGraphicsScreen.createDefault(); if(DEBUG) { System.err.println("WindowsAWTWGLGraphicsConfigurationFactory: creating default device: "+absScreen); } @@ -122,12 +124,17 @@ public class WindowsAWTWGLGraphicsConfigurationFactory extends GLGraphicsConfigu // otherwise no hardware accelerated PFD could be achieved. // - preselect with no constrains // - try to create dedicated GC - winConfig.preselectGraphicsConfiguration(drawableFactory, null); - if ( 1 <= winConfig.getPixelFormatID() ) { - chosenGC = Win32SunJDKReflection.graphicsConfigurationGet(device, winConfig.getPixelFormatID()); - if(DEBUG) { - System.err.println("WindowsAWTWGLGraphicsConfigurationFactory: Found new AWT PFD ID "+winConfig.getPixelFormatID()+" -> "+winConfig); + try { + winConfig.preselectGraphicsConfiguration(drawableFactory, null); + if ( 1 <= winConfig.getPixelFormatID() ) { + chosenGC = Win32SunJDKReflection.graphicsConfigurationGet(device, winConfig.getPixelFormatID()); + if(DEBUG) { + System.err.println("WindowsAWTWGLGraphicsConfigurationFactory: Found new AWT PFD ID "+winConfig.getPixelFormatID()+" -> "+winConfig); + } } + } catch (GLException gle0) { + gle0.printStackTrace(); + // go on .. } if( null == chosenGC ) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/GLXUtil.java b/src/jogl/classes/jogamp/opengl/x11/glx/GLXUtil.java index e95c80205..33e85dd0b 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/GLXUtil.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/GLXUtil.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,14 +33,40 @@ package jogamp.opengl.x11.glx; -import javax.media.opengl.*; +import javax.media.nativewindow.x11.X11GraphicsDevice; +import javax.media.opengl.GLException; +import jogamp.opengl.Debug; + +import com.jogamp.common.util.VersionNumber; public class GLXUtil { - public static String getExtension(long display) { - return GLX.glXGetClientString(display, GLX.GLX_EXTENSIONS); - } + public static final boolean DEBUG = Debug.debug("GLXUtil"); + + public static VersionNumber getGLXServerVersionNumber(long display) { + int[] major = new int[1]; + int[] minor = new int[1]; + + if (!GLX.glXQueryVersion(display, major, 0, minor, 0)) { + throw new GLException("glXQueryVersion failed"); + } + // Work around bugs in ATI's Linux drivers where they report they + // only implement GLX version 1.2 on the server side + if (major[0] == 1 && minor[0] == 2) { + String str = GLX.glXGetClientString(display, GLX.GLX_VERSION); + try { + // e.g. "1.3" + major[0] = Integer.valueOf(str.substring(0, 1)).intValue(); + minor[0] = Integer.valueOf(str.substring(2, 3)).intValue(); + } catch (Exception e) { + major[0] = 1; + minor[0] = 2; + } + } + return new VersionNumber(major[0], minor[0], 0); + } + public static boolean isMultisampleAvailable(String extensions) { if (extensions != null) { return (extensions.indexOf("GLX_ARB_multisample") >= 0); @@ -47,16 +74,6 @@ public class GLXUtil { return false; } - public static boolean isMultisampleAvailable(long display) { - return isMultisampleAvailable(getExtension(display)); - } - - /** Workaround for apparent issue with ATI's proprietary drivers - where direct contexts still send GLX tokens for GL calls */ - public static String getVendorName(long display) { - return GLX.glXGetClientString(display, GLX.GLX_VENDOR); - } - public static boolean isVendorNVIDIA(String vendor) { return vendor != null && vendor.startsWith("NVIDIA") ; } @@ -65,38 +82,48 @@ public class GLXUtil { return vendor != null && vendor.startsWith("ATI") ; } - public static boolean isVendorATI(long display) { - return isVendorATI(getVendorName(display)); + public static boolean isClientMultisampleAvailable() { + return clientMultisampleAvailable; } - - public static boolean isVendorNVIDIA(long display) { - return isVendorNVIDIA(getVendorName(display)); + public static String getClientVendorName() { + return clientVendorName; } - - public static void getGLXVersion(long display, int major[], int minor[]) { - if(0 == display) { - throw new GLException("null display handle"); + public static VersionNumber getClientVersionNumber() { + return clientVersionNumber; + } + public static synchronized boolean initGLXClientDataSingleton(X11GraphicsDevice x11Device) { + if(null != clientVendorName) { + return false; } - if(major.length<1||minor.length<1) { - throw new GLException("passed int arrays size is not >= 1"); + if(DEBUG) { + System.err.println("initGLXClientDataSingleton: "+x11Device); + Thread.dumpStack(); } - - if (!GLX.glXQueryVersion(display, major, 0, minor, 0)) { - throw new GLException("glXQueryVersion failed"); + if(null == x11Device) { + throw new GLException("null X11GraphicsDevice"); } - - // Work around bugs in ATI's Linux drivers where they report they - // only implement GLX version 1.2 on the server side - if (major[0] == 1 && minor[0] == 2) { - String str = GLX.glXGetClientString(display, GLX.GLX_VERSION); - try { + if(0 == x11Device.getHandle()) { + throw new GLException("null X11GraphicsDevice display handle"); + } + + clientMultisampleAvailable = isMultisampleAvailable(GLX.glXGetClientString(x11Device.getHandle(), GLX.GLX_EXTENSIONS)); + clientVendorName = GLX.glXGetClientString(x11Device.getHandle(), GLX.GLX_VENDOR); + + int[] major = new int[1]; + int[] minor = new int[1]; + final String str = GLX.glXGetClientString(x11Device.getHandle(), GLX.GLX_VERSION); + try { // e.g. "1.3" major[0] = Integer.valueOf(str.substring(0, 1)).intValue(); minor[0] = Integer.valueOf(str.substring(2, 3)).intValue(); - } catch (Exception e) { + } catch (Exception e) { major[0] = 1; minor[0] = 2; - } } + clientVersionNumber = new VersionNumber(major[0], minor[0], 0); + return true; } + private static boolean clientMultisampleAvailable = false; + private static String clientVendorName = null; + private static VersionNumber clientVersionNumber = null; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java index 68bdb4ab8..6be74c0e9 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java @@ -50,16 +50,16 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable { this.realized = true; WrappedSurface ns = (WrappedSurface) getNativeSurface(); - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)ns.getGraphicsConfiguration(); X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice(); long dpy = device.getHandle(); int scrn = screen.getIndex(); long visualID = config.getVisualID(); - dummyWindow = X11Util.CreateDummyWindow(dpy, scrn, visualID, f_dim, f_dim); + dummyWindow = X11Lib.CreateDummyWindow(dpy, scrn, visualID, f_dim, f_dim); ns.setSurfaceHandle( dummyWindow ); - ns.setSize(f_dim, f_dim); + ns.surfaceSizeChanged(f_dim, f_dim); updateHandle(); } @@ -83,8 +83,8 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable { protected void destroyImpl() { if(0!=dummyWindow) { destroyHandle(); - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - X11Util.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration(); + X11Lib.DestroyDummyWindow(config.getScreen().getDevice().getHandle(), dummyWindow); } } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java index d0d9929a0..4a949ea74 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java @@ -53,7 +53,7 @@ public class X11ExternalGLXContext extends X11GLXContext { super(drawable, null); this.contextHandle = ctx; GLContextShareSet.contextCreated(this); - setGLFunctionAvailability(false, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); + setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); getGLStateTracker().setEnabled(false); // external context usage can't track state in Java } @@ -72,7 +72,7 @@ public class X11ExternalGLXContext extends X11GLXContext { } int[] val = new int[1]; GLX.glXQueryContext(display, ctx, GLX.GLX_SCREEN, val, 0); - X11GraphicsScreen x11Screen = (X11GraphicsScreen) X11GraphicsScreen.createScreenDevice(display, val[0]); + X11GraphicsScreen x11Screen = (X11GraphicsScreen) X11GraphicsScreen.createScreenDevice(display, val[0], false); GLX.glXQueryContext(display, ctx, GLX.GLX_FBCONFIG_ID, val, 0); X11GLXGraphicsConfiguration cfg = null; @@ -95,7 +95,7 @@ public class X11ExternalGLXContext extends X11GLXContext { return new X11ExternalGLXContext(new Drawable(factory, ns), ctx); } - protected boolean createImpl() { + protected boolean createImpl(GLContextImpl shareWith) { return true; } @@ -116,7 +116,7 @@ public class X11ExternalGLXContext extends X11GLXContext { lastContext = null; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { } protected void releaseImpl() throws GLException { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java index eb286cdf0..ca30fde3b 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java @@ -66,7 +66,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable { } int[] val = new int[1]; GLX.glXQueryContext(display, context, GLX.GLX_SCREEN, val, 0); - X11GraphicsScreen x11Screen = (X11GraphicsScreen) X11GraphicsScreen.createScreenDevice(display, val[0]); + X11GraphicsScreen x11Screen = (X11GraphicsScreen) X11GraphicsScreen.createScreenDevice(display, val[0], false); GLX.glXQueryContext(display, context, GLX.GLX_FBCONFIG_ID, val, 0); X11GLXGraphicsConfiguration cfg = X11GLXGraphicsConfiguration.create(glp, x11Screen, val[0]); @@ -85,7 +85,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable { } WrappedSurface ns = new WrappedSurface(cfg); ns.setSurfaceHandle(drawable); - ns.setSize(w, h); + ns.surfaceSizeChanged(w, h); return new X11ExternalGLXDrawable(factory, ns); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index 904379058..c86001969 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -40,28 +40,33 @@ package jogamp.opengl.x11.glx; -import java.nio.*; -import java.util.*; - -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.X11GraphicsDevice; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; +import java.util.Map; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableImpl; import com.jogamp.common.nio.Buffers; -import com.jogamp.common.util.VersionNumber; -import jogamp.opengl.*; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; -import jogamp.nativewindow.x11.X11Util; public abstract class X11GLXContext extends GLContextImpl { protected static final boolean TRACE_CONTEXT_CURRENT = false; // true; private static final Map<String, String> functionNameMap; private static final Map<String, String> extensionNameMap; - private VersionNumber glXVersion; - private boolean glXVersionOneOneCapable; - private boolean glXVersionOneThreeCapable; private GLXExt _glXExt; // Table that holds the addresses of the native C-language entry points for // GLX extension functions. @@ -91,9 +96,6 @@ public abstract class X11GLXContext extends GLContextImpl { @Override protected void resetStates() { - glXVersion = null; - glXVersionOneOneCapable = false; - glXVersionOneThreeCapable = false; // no inner state _glXExt=null; glXExtProcAddressTable = null; hasSwapIntervalSGI = 0; @@ -125,25 +127,10 @@ public abstract class X11GLXContext extends GLContextImpl { protected Map<String, String> getExtensionNameMap() { return extensionNameMap; } - private final void initGLXVersion() { - if(null == glXVersion) { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - X11GraphicsDevice device = (X11GraphicsDevice) config.getScreen().getDevice(); - - glXVersion = X11GLXDrawableFactory.getGLXVersion(device); - glXVersionOneOneCapable = ( null != glXVersion ) ? glXVersion.compareTo(GLDrawableFactoryImpl.versionOneOne) >= 0 : false ; - glXVersionOneThreeCapable = ( null != glXVersion ) ? glXVersion.compareTo(GLDrawableFactoryImpl.versionOneThree) >= 0 : false ; - } - } - public final boolean isGLXVersionGreaterEqualOneOne() { - initGLXVersion(); - return glXVersionOneOneCapable; - } - public final boolean isGLXVersionGreaterEqualOneThree() { - initGLXVersion(); - return glXVersionOneThreeCapable; + protected final boolean isGLXVersionGreaterEqualOneThree() { + return ((X11GLXDrawableFactory)drawable.getFactoryImpl()).isGLXVersionGreaterEqualOneThree(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice()); } - + public final boolean isGLReadDrawableAvailable() { return isGLXVersionGreaterEqualOneThree(); } @@ -154,10 +141,10 @@ public abstract class X11GLXContext extends GLContextImpl { try { if(TRACE_CONTEXT_CURRENT) { Throwable t = new Throwable(Thread.currentThread()+" - glXMakeContextCurrent("+toHexString(dpy)+", "+ - toHexString(writeDrawable)+", "+toHexString(readDrawable)+", "+toHexString(ctx)+") - GLX >= 1.3 "+ glXVersionOneThreeCapable); + toHexString(writeDrawable)+", "+toHexString(readDrawable)+", "+toHexString(ctx)+") - GLX >= 1.3 "+ isGLXVersionGreaterEqualOneThree()); t.printStackTrace(); } - if ( glXVersionOneThreeCapable ) { + if ( isGLXVersionGreaterEqualOneThree() ) { res = GLX.glXMakeContextCurrent(dpy, writeDrawable, readDrawable, ctx); } else if ( writeDrawable == readDrawable ) { res = GLX.glXMakeCurrent(dpy, writeDrawable, ctx); @@ -179,7 +166,7 @@ public abstract class X11GLXContext extends GLContextImpl { } protected void destroyContextARBImpl(long ctx) { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); long display = config.getScreen().getDevice().getHandle(); glXMakeContextCurrent(display, 0, 0, 0); @@ -239,16 +226,16 @@ public abstract class X11GLXContext extends GLContextImpl { attribs.put(ctx_arb_attribs_idx_flags + 1, flags); } - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); long display = device.getHandle(); try { // critical path, a remote display might not support this command, // hence we need to catch the X11 Error within this block. - X11Util.XSync(display, false); + X11Lib.XSync(display, false); ctx = _glXExt.glXCreateContextAttribsARB(display, config.getFBConfig(), share, direct, attribs); - X11Util.XSync(display, false); + X11Lib.XSync(display, false); } catch (RuntimeException re) { if(DEBUG) { Throwable t = new Throwable("Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); @@ -274,32 +261,29 @@ public abstract class X11GLXContext extends GLContextImpl { return ctx; } - protected boolean createImpl() { + protected boolean createImpl(GLContextImpl shareWith) { // covers the whole context creation loop incl createContextARBImpl and destroyContextARBImpl X11Util.setX11ErrorHandler(true, true); try { - return createImplRaw(); + return createImplRaw(shareWith); } finally { X11Util.setX11ErrorHandler(false, false); } } - private boolean createImplRaw() { + private boolean createImplRaw(GLContextImpl shareWith) { boolean direct = true; // try direct always isDirect = false; // fall back X11GLXDrawableFactory factory = (X11GLXDrawableFactory)drawable.getFactoryImpl(); - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsDevice device = config.getScreen().getDevice(); X11GLXContext sharedContext = (X11GLXContext) factory.getOrCreateSharedContextImpl(device); long display = device.getHandle(); - isGLReadDrawableAvailable(); // trigger setup glXVersionOneThreeCapable - - X11GLXContext other = (X11GLXContext) GLContextShareSet.getShareContext(this); long share = 0; - if (other != null) { - share = other.getHandle(); + if (shareWith != null) { + share = shareWith.getHandle(); if (share == 0) { throw new GLException("GLContextShareSet returned an invalid OpenGL context"); } @@ -321,7 +305,7 @@ public abstract class X11GLXContext extends GLContextImpl { if (!glXMakeContextCurrent(display, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { throw new GLException("Error making temp context(0) current: display "+toHexString(display)+", context "+toHexString(contextHandle)+", drawable "+drawable); } - setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION isDirect = GLX.glXIsDirect(display, contextHandle); if (DEBUG) { System.err.println(getThreadName() + ": createContextImpl: OK (old-1) share "+share+", direct "+isDirect+"/"+direct); @@ -351,7 +335,7 @@ public abstract class X11GLXContext extends GLContextImpl { if (!glXMakeContextCurrent(display, drawable.getHandle(), drawableRead.getHandle(), temp_ctx)) { throw new GLException("Error making temp context(1) current: display "+toHexString(display)+", context "+toHexString(temp_ctx)+", drawable "+drawable); } - setGLFunctionAvailability(true, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION boolean isCreateContextAttribsARBAvailable = isFunctionAvailable("glXCreateContextAttribsARB"); glXMakeContextCurrent(display, 0, 0, 0); // release temp context @@ -386,7 +370,7 @@ public abstract class X11GLXContext extends GLContextImpl { if(glp.isGL3()) { glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, temp_ctx); - throw new GLException("X11GLXContext.createContextImpl failed, but context > GL2 requested - requested: "+glp+", current: "+getGLVersion()+", "); + throw new GLException("X11GLXContext.createContextImpl ctx !ARB, context > GL2 requested - requested: "+glp+", current: "+getGLVersion()+", "); } if(DEBUG) { System.err.println("X11GLXContext.createContextImpl failed, fall back to !ARB context "+getGLVersion()); @@ -410,7 +394,7 @@ public abstract class X11GLXContext extends GLContextImpl { return true; } - protected void makeCurrentImpl(boolean newCreated) throws GLException { + protected void makeCurrentImpl() throws GLException { long dpy = drawable.getNativeSurface().getDisplayHandle(); if (GLX.glXGetCurrentContext() != contextHandle) { @@ -422,13 +406,6 @@ public abstract class X11GLXContext extends GLContextImpl { } finally { X11Util.setX11ErrorHandler(false, false); } - if (DEBUG && newCreated) { - System.err.println(getThreadName() + ": glXMakeCurrent(display " + - toHexString(dpy)+ - ", drawable " + toHexString(drawable.getHandle()) + - ", drawableRead " + toHexString(drawableRead.getHandle()) + - ", context " + toHexString(contextHandle) + ") succeeded"); - } } } @@ -460,7 +437,7 @@ public abstract class X11GLXContext extends GLContextImpl { } protected final void updateGLXProcAddressTable() { - final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final String key = "GLX-"+adevice.getUniqueID(); if (DEBUG) { @@ -493,10 +470,12 @@ public abstract class X11GLXContext extends GLContextImpl { protected final StringBuffer getPlatformExtensionsStringImpl() { StringBuffer sb = new StringBuffer(); if (DEBUG) { - System.err.println("!!! GLX Version "+glXVersion); + System.err.println("!!! GLX Version client version "+ GLXUtil.getClientVersionNumber()+ + ", server: "+ + ((X11GLXDrawableFactory)drawable.getFactoryImpl()).getGLXVersionNumber(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice())); } - if(isGLXVersionGreaterEqualOneOne()) { - final NativeSurface ns = drawable.getNativeSurface(); + final NativeSurface ns = drawable.getNativeSurface(); + if(((X11GLXDrawableFactory)drawable.getFactoryImpl()).isGLXVersionGreaterEqualOneOne(ns.getGraphicsConfiguration().getScreen().getDevice())) { { final String ret = GLX.glXGetClientString(ns.getDisplayHandle(), GLX.GLX_EXTENSIONS); if (DEBUG) { @@ -526,14 +505,14 @@ public abstract class X11GLXContext extends GLContextImpl { if (glExtensionName.equals("GL_ARB_pbuffer") || glExtensionName.equals("GL_ARB_pixel_format")) { return getGLDrawable().getFactory().canCreateGLPbuffer( - drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice() ); + drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice() ); } return super.isExtensionAvailable(glExtensionName); } @Override protected void setSwapIntervalImpl(int interval) { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!glCaps.isOnscreen()) return; diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java index d2ce629df..28c02cd06 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java @@ -42,6 +42,7 @@ package jogamp.opengl.x11.glx; import javax.media.nativewindow.*; import javax.media.opengl.*; + import jogamp.opengl.*; public abstract class X11GLXDrawable extends GLDrawableImpl { @@ -55,7 +56,7 @@ public abstract class X11GLXDrawable extends GLDrawableImpl { protected void setRealizedImpl() { if(realized) { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration(); config.updateGraphicsConfiguration(); if (DEBUG) { @@ -64,9 +65,10 @@ public abstract class X11GLXDrawable extends GLDrawableImpl { } } - protected void swapBuffersImpl() { - GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); - } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); + } //--------------------------------------------------------------------------- // Internals only below this point diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 51316dc77..acced638f 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -37,115 +37,156 @@ package jogamp.opengl.x11.glx; +import java.nio.Buffer; +import java.nio.ShortBuffer; import java.util.Collection; import java.util.HashMap; import java.util.List; -import java.nio.*; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; -import javax.media.opengl.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.x11.X11GraphicsDevice; +import javax.media.nativewindow.x11.X11GraphicsScreen; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLProfile.ShutdownType; -import jogamp.opengl.*; - -import com.jogamp.common.JogampRuntimeException; -import com.jogamp.common.util.*; import jogamp.nativewindow.WrappedSurface; -import jogamp.nativewindow.x11.*; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; +import jogamp.opengl.DesktopGLDynamicLookupHelper; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableFactoryImpl; +import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLDynamicLookupHelper; +import jogamp.opengl.SharedResourceRunner; + +import com.jogamp.common.util.VersionNumber; public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { - private static final DesktopGLDynamicLookupHelper x11GLXDynamicLookupHelper; + public static final VersionNumber versionOneZero = new VersionNumber(1, 0, 0); + public static final VersionNumber versionOneOne = new VersionNumber(1, 1, 0); + public static final VersionNumber versionOneTwo = new VersionNumber(1, 2, 0); + public static final VersionNumber versionOneThree = new VersionNumber(1, 3, 0); + public static final VersionNumber versionOneFour = new VersionNumber(1, 4, 0); - static { - DesktopGLDynamicLookupHelper tmp = null; - try { - tmp = new DesktopGLDynamicLookupHelper(new X11GLXDynamicLibraryBundleInfo()); - } catch (GLException gle) { - if(DEBUG) { - gle.printStackTrace(); + private static DesktopGLDynamicLookupHelper x11GLXDynamicLookupHelper = null; + + public X11GLXDrawableFactory() { + super(); + + synchronized(X11GLXDrawableFactory.class) { + if(null==x11GLXDynamicLookupHelper) { + DesktopGLDynamicLookupHelper tmp = null; + try { + tmp = new DesktopGLDynamicLookupHelper(new X11GLXDynamicLibraryBundleInfo()); + } catch (GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + x11GLXDynamicLookupHelper = tmp; + if(null!=x11GLXDynamicLookupHelper) { + GLX.getGLXProcAddressTable().reset(x11GLXDynamicLookupHelper); + } } } - x11GLXDynamicLookupHelper = tmp; - if(null!=x11GLXDynamicLookupHelper) { - GLX.getGLXProcAddressTable().reset(x11GLXDynamicLookupHelper); + + if(null!=x11GLXDynamicLookupHelper) { + // Register our GraphicsConfigurationFactory implementations + // The act of constructing them causes them to be registered + X11GLXGraphicsConfigurationFactory.registerFactory(); + + defaultDevice = new X11GraphicsDevice(X11Util.getNullDisplayName(), AbstractGraphicsDevice.DEFAULT_UNIT); + sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); + + // Init shared resources off thread + // Will be released via ShutdownHook + sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceRunner.start(); + } + } + + protected final void destroy(ShutdownType shutdownType) { + if(null != sharedResourceRunner) { + sharedResourceRunner.stop(); + sharedResourceRunner = null; } - } + if(null != sharedMap) { + sharedMap.clear(); + sharedMap = null; + } + defaultDevice = null; + /** + * Pulling away the native library may cause havoc .. + * + if(ShutdownType.COMPLETE == shutdownType && null != x11GLXDynamicLookupHelper) { + x11GLXDynamicLookupHelper.destroy(); + x11GLXDynamicLookupHelper = null; + } */ - public static VersionNumber getGLXVersion(X11GraphicsDevice device) { - int[] major = new int[1]; - int[] minor = new int[1]; - GLXUtil.getGLXVersion(device.getHandle(), major, minor); - return new VersionNumber(major[0], minor[0], 0); + // Don't really close pending Display connections, + // since this may trigger a JVM exception + X11Util.shutdown( false, DEBUG ); } public GLDynamicLookupHelper getGLDynamicLookupHelper(int profile) { return x11GLXDynamicLookupHelper; } - public X11GLXDrawableFactory() { - super(); - // Register our GraphicsConfigurationFactory implementations - // The act of constructing them causes them to be registered - new X11GLXGraphicsConfigurationFactory(); - if(GLProfile.isAWTAvailable()) { - try { - ReflectionUtil.createInstance("jogamp.opengl.x11.glx.awt.X11AWTGLXGraphicsConfigurationFactory", - null, getClass().getClassLoader()); - } catch (JogampRuntimeException jre) { /* n/a .. */ } - } - - defaultDevice = new X11GraphicsDevice(X11Util.getNullDisplayName(), AbstractGraphicsDevice.DEFAULT_UNIT); - - // Init shared resources off thread - // Will be released via ShutdownHook - sharedResourceImpl = new SharedResourceImplementation(); - sharedResourceRunner = new SharedResourceRunner(sharedResourceImpl); - sharedResourceThread = new Thread(sharedResourceRunner, Thread.currentThread().getName()+"-SharedResourceRunner"); - sharedResourceThread.setDaemon(true); // Allow JVM to exit, even if this one is running - sharedResourceThread.start(); - } - - X11GraphicsDevice defaultDevice; - SharedResourceImplementation sharedResourceImpl; - SharedResourceRunner sharedResourceRunner; - Thread sharedResourceThread; - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + private X11GraphicsDevice defaultDevice; + private SharedResourceRunner sharedResourceRunner; + private HashMap<String /* connection */, SharedResourceRunner.Resource> sharedMap; static class SharedResource implements SharedResourceRunner.Resource { X11GraphicsDevice device; X11GraphicsScreen screen; X11DummyGLXDrawable drawable; X11GLXContext context; - String glXVendorName; - boolean isGLXVendorATI; - boolean isGLXVendorNVIDIA; - VersionNumber glXVersion; + String glXServerVendorName; + boolean isGLXServerVendorATI; + boolean isGLXServerVendorNVIDIA; + VersionNumber glXServerVersion; + boolean glXServerVersionOneOneCapable; + boolean glXServerVersionOneThreeCapable; + boolean glXMultisampleAvailable; SharedResource(X11GraphicsDevice dev, X11GraphicsScreen scrn, X11DummyGLXDrawable draw, X11GLXContext ctx, - VersionNumber glXVer, String glXVendor) { + VersionNumber glXServerVer, String glXServerVendor, boolean glXServerMultisampleAvail) { device = dev; screen = scrn; drawable = draw; context = ctx; - glXVersion = glXVer; - glXVendorName = glXVendor; - isGLXVendorATI = GLXUtil.isVendorATI(glXVendorName); - isGLXVendorNVIDIA = GLXUtil.isVendorNVIDIA(glXVendorName); + glXServerVersion = glXServerVer; + glXServerVersionOneOneCapable = glXServerVersion.compareTo(versionOneOne) >= 0 ; + glXServerVersionOneThreeCapable = glXServerVersion.compareTo(versionOneThree) >= 0 ; + glXServerVendorName = glXServerVendor; + isGLXServerVendorATI = GLXUtil.isVendorATI(glXServerVendorName); + isGLXServerVendorNVIDIA = GLXUtil.isVendorNVIDIA(glXServerVendorName); + glXMultisampleAvailable = glXServerMultisampleAvail; } final public AbstractGraphicsDevice getDevice() { return device; } final public AbstractGraphicsScreen getScreen() { return screen; } final public GLDrawableImpl getDrawable() { return drawable; } final public GLContextImpl getContext() { return context; } - final String getGLXVendorName() { return glXVendorName; } - final boolean isGLXVendorATI() { return isGLXVendorATI; } - final boolean isGLXVendorNVIDIA() { return isGLXVendorNVIDIA; } - final VersionNumber getGLXVersion() { return glXVersion; } - final boolean isGLXVersionGreaterEqualOneThree() { - return ( null != glXVersion ) ? glXVersion.compareTo(versionOneThree) >= 0 : false ; - } + final String getGLXVendorName() { return glXServerVendorName; } + final boolean isGLXVendorATI() { return isGLXServerVendorATI; } + final boolean isGLXVendorNVIDIA() { return isGLXServerVendorNVIDIA; } + final VersionNumber getGLXVersion() { return glXServerVersion; } + final boolean isGLXVersionGreaterEqualOneOne() { return glXServerVersionOneOneCapable; } + final boolean isGLXVersionGreaterEqualOneThree() { return glXServerVersionOneThreeCapable; } + final boolean isGLXMultisampleAvailable() { return glXMultisampleAvailable; } } class SharedResourceImplementation implements SharedResourceRunner.Implementation { @@ -156,27 +197,33 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } public SharedResourceRunner.Resource mapPut(String connection, SharedResourceRunner.Resource resource) { synchronized(sharedMap) { - return (SharedResourceRunner.Resource) sharedMap.put(connection, resource); + return sharedMap.put(connection, resource); } } public SharedResourceRunner.Resource mapGet(String connection) { synchronized(sharedMap) { - return (SharedResourceRunner.Resource) sharedMap.get(connection); + return sharedMap.get(connection); } } - public Collection/*<Resource>*/ mapValues() { + public Collection<SharedResourceRunner.Resource> mapValues() { synchronized(sharedMap) { return sharedMap.values(); } } public SharedResourceRunner.Resource createSharedResource(String connection) { - X11GraphicsDevice sharedDevice = new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT); - sharedDevice.setCloseDisplay(true); + X11GraphicsDevice sharedDevice = + new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, + true); // own non-shared display connection, no locking + // new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, + // NativeWindowFactory.getNullToolkitLock(), true); // own non-shared display connection, no locking sharedDevice.lock(); try { - String glXVendorName = GLXUtil.getVendorName(sharedDevice.getHandle()); - if(X11Util.ATI_HAS_XCLOSEDISPLAY_BUG && GLXUtil.isVendorATI(glXVendorName)) { + GLXUtil.initGLXClientDataSingleton(sharedDevice); + final String glXServerVendorName = GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_VENDOR); + final VersionNumber glXServerVersion = GLXUtil.getGLXServerVersionNumber(sharedDevice.getHandle()); + final boolean glXServerMultisampleAvailable = GLXUtil.isMultisampleAvailable(GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_EXTENSIONS)); + if(X11Util.ATI_HAS_XCLOSEDISPLAY_BUG && GLXUtil.isVendorATI(glXServerVendorName)) { X11Util.setMarkAllDisplaysUnclosable(true); X11Util.markDisplayUncloseable(sharedDevice.getHandle()); } @@ -195,7 +242,6 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { throw new GLException("Couldn't create shared context for drawable: "+sharedDrawable); } sharedContext.setSynchronized(true); - VersionNumber glXVersion = getGLXVersion(sharedDevice); boolean madeCurrent = false; sharedContext.makeCurrent(); try { @@ -207,11 +253,16 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { System.err.println("!!! SharedDevice: " + sharedDevice); System.err.println("!!! SharedScreen: " + sharedScreen); System.err.println("!!! SharedContext: " + sharedContext + ", madeCurrent " + madeCurrent); - System.err.println("!!! GLX Vendor: " + glXVendorName); - System.err.println("!!! GLX Version: " + glXVersion - + " >= 1.3: " + (glXVersion.compareTo(versionOneThree) >= 0)); + System.err.println("!!! GLX Server Vendor: " + glXServerVendorName); + System.err.println("!!! GLX Server Version: " + glXServerVersion); + System.err.println("!!! GLX Server Multisample: " + glXServerMultisampleAvailable); + System.err.println("!!! GLX Client Vendor: " + GLXUtil.getClientVendorName()); + System.err.println("!!! GLX Client Version: " + GLXUtil.getClientVersionNumber()); + System.err.println("!!! GLX Client Multisample: " + GLXUtil.isClientMultisampleAvailable()); } - return new SharedResource(sharedDevice, sharedScreen, sharedDrawable, sharedContext, glXVersion, glXVendorName); + return new SharedResource(sharedDevice, sharedScreen, sharedDrawable, sharedContext, + glXServerVersion, glXServerVendorName, + glXServerMultisampleAvailable && GLXUtil.isClientMultisampleAvailable()); } catch (Throwable t) { throw new GLException("X11GLXDrawableFactory - Could not initialize shared resources for "+connection, t); } finally { @@ -227,15 +278,18 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { System.err.println("!!! Screen : " + sr.screen); System.err.println("!!! Drawable: " + sr.drawable); System.err.println("!!! CTX : " + sr.context); + Thread.dumpStack(); } if (null != sr.context) { - // may cause JVM SIGSEGV: sharedContext.destroy(); + // may cause JVM SIGSEGV: + sr.context.destroy(); sr.context = null; } if (null != sr.drawable) { - // may cause JVM SIGSEGV: sharedDrawable.destroy(); + // may cause JVM SIGSEGV: + sr.drawable.destroy(); sr.drawable = null; } @@ -244,6 +298,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } if (null != sr.device) { + // may cause JVM SIGSEGV: sr.device.close(); sr.device = null; } @@ -261,10 +316,21 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return false; } - public final boolean getWasSharedContextCreated(AbstractGraphicsDevice device) { - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - return null != sr.getContext(); + protected final Thread getSharedResourceThread() { + return sharedResourceRunner.start(); + } + + protected final boolean createSharedResource(AbstractGraphicsDevice device) { + try { + SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); + if(null!=sr) { + return null != sr.getContext(); + } + } catch (GLException gle) { + if(DEBUG) { + System.err.println("Catched Exception while X11GLX Shared Resource initialization"); + gle.printStackTrace(); + } } return false; } @@ -297,47 +363,6 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return (SharedResource) sharedResourceRunner.getOrCreateShared(device); } - public final String getGLXVendorName(AbstractGraphicsDevice device) { - if(null != device) { - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - return ((SharedResource)sr).getGLXVendorName(); - } - return GLXUtil.getVendorName(device.getHandle()); - } - return null; - } - - public final boolean isGLXVendorATI(AbstractGraphicsDevice device) { - if(null != device) { - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - return ((SharedResource)sr).isGLXVendorATI(); - } - return GLXUtil.isVendorATI(device.getHandle()); - } - return false; - } - - public final boolean isGLXVendorNVIDIA(AbstractGraphicsDevice device) { - if(null != device) { - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - return ((SharedResource)sr).isGLXVendorNVIDIA(); - } - return GLXUtil.isVendorNVIDIA(device.getHandle()); - } - return false; - } - - protected final void shutdownInstance() { - sharedResourceRunner.releaseAndWait(); - - // Don't really close pending Display connections, - // since this may trigger a JVM exception - X11Util.shutdown( false, DEBUG ); - } - protected List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(AbstractGraphicsDevice device) { return X11GLXGraphicsConfigurationFactory.getAvailableCapabilities(this, device); } @@ -353,7 +378,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!caps.isPBuffer()) { return new X11PixmapGLXDrawable(this, target); @@ -383,6 +408,43 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return pbufferDrawable; } + public final boolean isGLXMultisampleAvailable(AbstractGraphicsDevice device) { + if(null != device) { + SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); + if(null!=sr) { + return sr.isGLXMultisampleAvailable(); + } + } + return false; + } + + public final VersionNumber getGLXVersionNumber(AbstractGraphicsDevice device) { + if(null != device) { + SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); + if(null!=sr) { + return sr.getGLXVersion(); + } + if( device instanceof X11GraphicsDevice ) { + return GLXUtil.getGLXServerVersionNumber(device.getHandle()); + } + } + return null; + } + + public final boolean isGLXVersionGreaterEqualOneOne(AbstractGraphicsDevice device) { + if(null != device) { + SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); + if(null!=sr) { + return sr.isGLXVersionGreaterEqualOneOne(); + } + if( device instanceof X11GraphicsDevice ) { + final VersionNumber glXServerVersion = GLXUtil.getGLXServerVersionNumber(device.getHandle()); + return glXServerVersion.compareTo(versionOneOne) >= 0; + } + } + return false; + } + public final boolean isGLXVersionGreaterEqualOneThree(AbstractGraphicsDevice device) { if(null != device) { SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); @@ -390,8 +452,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return sr.isGLXVersionGreaterEqualOneThree(); } if( device instanceof X11GraphicsDevice ) { - VersionNumber v = getGLXVersion( (X11GraphicsDevice) device); - return ( null != v ) ? v.compareTo(versionOneThree) >= 0 : false ; + final VersionNumber glXServerVersion = GLXUtil.getGLXServerVersionNumber(device.getHandle()); + return glXServerVersion.compareTo(versionOneThree) >= 0; } } return false; @@ -407,23 +469,28 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return isGLXVersionGreaterEqualOneThree(device); } - protected final NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device, + protected final NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { - X11GraphicsScreen screen = null; - SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(device); - if(null!=sr) { - screen = (X11GraphicsScreen) sr.getScreen(); + if(null == deviceReq) { + throw new InternalError("deviceReq is null"); } - if(null==screen) { - return null; + final SharedResourceRunner.Resource sr = sharedResourceRunner.getOrCreateShared(deviceReq); + if(null==sr) { + throw new InternalError("No SharedResource for: "+deviceReq); } + final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sr.getScreen(); + final AbstractGraphicsDevice sharedDevice = sharedScreen.getDevice(); // should be same .. + // create screen/device pair - Null X11 locking, due to private non-shared Display handle + final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(sharedDevice.getConnection()), AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock(), true); + final X11GraphicsScreen screen = new X11GraphicsScreen(device, sharedScreen.getIndex()); + WrappedSurface ns = new WrappedSurface( X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen) ); if(ns != null) { - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); } return ns; } @@ -475,8 +542,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } int[] size = new int[1]; - boolean res = X11Util.XF86VidModeGetGammaRampSize(display, - X11Util.DefaultScreen(display), + boolean res = X11Lib.XF86VidModeGetGammaRampSize(display, + X11Lib.DefaultScreen(display), size, 0); if (!res) { return 0; @@ -498,8 +565,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData[i] = (short) (ramp[i] * 65535); } - boolean res = X11Util.XF86VidModeSetGammaRamp(display, - X11Util.DefaultScreen(display), + boolean res = X11Lib.XF86VidModeSetGammaRamp(display, + X11Lib.DefaultScreen(display), rampData.length, rampData, 0, rampData, 0, @@ -525,8 +592,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData.limit(3 * size); ShortBuffer blueRampData = rampData.slice(); - boolean res = X11Util.XF86VidModeGetGammaRamp(display, - X11Util.DefaultScreen(display), + boolean res = X11Lib.XF86VidModeGetGammaRamp(display, + X11Lib.DefaultScreen(display), size, redRampData, greenRampData, @@ -562,8 +629,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData.limit(3 * size); ShortBuffer blueRampData = rampData.slice(); - X11Util.XF86VidModeSetGammaRamp(display, - X11Util.DefaultScreen(display), + X11Lib.XF86VidModeSetGammaRamp(display, + X11Lib.DefaultScreen(display), size, redRampData, greenRampData, diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java index 68b8135d0..4d0c3eeca 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java @@ -35,13 +35,26 @@ package jogamp.opengl.x11.glx; import java.util.ArrayList; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; -import javax.media.opengl.*; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsScreen; +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GL; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.XRenderDirectFormat; +import jogamp.nativewindow.x11.XRenderPictFormat; +import jogamp.nativewindow.x11.XVisualInfo; +import jogamp.opengl.Debug; +import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.PointerBuffer; -import jogamp.opengl.*; -import jogamp.nativewindow.x11.*; public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implements Cloneable { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); @@ -56,19 +69,20 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem } static X11GLXGraphicsConfiguration create(GLProfile glp, X11GraphicsScreen x11Screen, int fbcfgID) { - long display = x11Screen.getDevice().getHandle(); + final long display = x11Screen.getDevice().getHandle(); if(0==display) { throw new GLException("Display null of "+x11Screen); } - int screen = x11Screen.getIndex(); - long fbcfg = glXFBConfigID2FBConfig(display, screen, fbcfgID); + final int screen = x11Screen.getIndex(); + final long fbcfg = glXFBConfigID2FBConfig(display, screen, fbcfgID); if(0==fbcfg) { throw new GLException("FBConfig null of "+toHexString(fbcfgID)); } if(null==glp) { glp = GLProfile.getDefault(x11Screen.getDevice()); } - X11GLCapabilities caps = GLXFBConfig2GLCapabilities(glp, display, fbcfg, true, true, true, GLXUtil.isMultisampleAvailable(display)); + final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); + final X11GLCapabilities caps = GLXFBConfig2GLCapabilities(glp, display, fbcfg, true, true, true, factory.isGLXMultisampleAvailable(x11Screen.getDevice())); if(null==caps) { throw new GLException("GLCapabilities null of "+toHexString(fbcfg)); } @@ -100,10 +114,6 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem } } - private static int nonZeroOrDontCare(int value) { - return value != 0 ? value : (int)GLX.GLX_DONT_CARE ; - } - static int[] GLCapabilities2AttribList(GLCapabilitiesImmutable caps, boolean forFBAttr, boolean isMultisampleAvailable, @@ -367,7 +377,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem int[] count = new int[1]; XVisualInfo template = XVisualInfo.create(); template.setVisualid(visualID); - XVisualInfo[] infos = X11Util.XGetVisualInfo(display, X11Lib.VisualIDMask, template, count, 0); + XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask, template, count, 0); if (infos == null || infos.length == 0) { return null; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java index 0f8b94825..a72de8cd5 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java @@ -51,7 +51,6 @@ import javax.media.opengl.GLProfile; import com.jogamp.common.nio.PointerBuffer; import jogamp.nativewindow.x11.X11Lib; -import jogamp.nativewindow.x11.X11Util; import jogamp.nativewindow.x11.XVisualInfo; import jogamp.opengl.Debug; import jogamp.opengl.GLGraphicsConfigurationFactory; @@ -71,8 +70,10 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); static X11GLCapabilities.XVisualIDComparator XVisualIDComparator = new X11GLCapabilities.XVisualIDComparator(); - X11GLXGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, this); + static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, new X11GLXGraphicsConfigurationFactory()); + } + private X11GLXGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( @@ -101,18 +102,19 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if(null == sharedResource) { throw new GLException("Shared resource for device n/a: "+device); } - X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen(); - X11GLXDrawable sharedDrawable = (X11GLXDrawable) sharedResource.getDrawable(); - GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities(); - GLProfile glp = capsChosen.getGLProfile(); + final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen(); + final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(sharedScreen.getDevice()); + final X11GLXDrawable sharedDrawable = (X11GLXDrawable) sharedResource.getDrawable(); + final GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities(); + final GLProfile glp = capsChosen.getGLProfile(); List<GLCapabilitiesImmutable> availableCaps = null; if( sharedResource.isGLXVersionGreaterEqualOneThree() ) { - availableCaps = getAvailableGLCapabilitiesFBConfig(sharedScreen, glp); + availableCaps = getAvailableGLCapabilitiesFBConfig(sharedScreen, glp, isMultisampleAvailable); } if( null == availableCaps || availableCaps.isEmpty() ) { - availableCaps = getAvailableGLCapabilitiesXVisual(sharedScreen, glp); + availableCaps = getAvailableGLCapabilitiesXVisual(sharedScreen, glp, isMultisampleAvailable); } if( null != availableCaps && availableCaps.size() > 1 ) { Collections.sort(availableCaps, XVisualIDComparator); @@ -120,7 +122,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF return availableCaps; } - static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesFBConfig(X11GraphicsScreen x11Screen, GLProfile glProfile) { + static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesFBConfig(X11GraphicsScreen x11Screen, GLProfile glProfile, boolean isMultisampleAvailable) { PointerBuffer fbcfgsL = null; // Utilizing FBConfig @@ -129,7 +131,6 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); - boolean isMultisampleAvailable = GLXUtil.isMultisampleAvailable(display); int[] count = { -1 }; ArrayList<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); @@ -150,17 +151,16 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF return availableCaps; } - static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesXVisual(X11GraphicsScreen x11Screen, GLProfile glProfile) { + static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesXVisual(X11GraphicsScreen x11Screen, GLProfile glProfile, boolean isMultisampleAvailable) { AbstractGraphicsDevice absDevice = x11Screen.getDevice(); long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); - boolean isMultisampleAvailable = GLXUtil.isMultisampleAvailable(display); int[] count = new int[1]; XVisualInfo template = XVisualInfo.create(); template.setScreen(screen); - XVisualInfo[] infos = X11Util.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0); + XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0); if (infos == null || infos.length<1) { throw new GLException("Error while enumerating available XVisualInfos"); } @@ -213,18 +213,20 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } static X11GLXGraphicsConfiguration fetchGraphicsConfigurationFBConfig(X11GraphicsScreen x11Screen, int fbID, GLProfile glp) { - AbstractGraphicsDevice absDevice = x11Screen.getDevice(); - long display = absDevice.getHandle(); - int screen = x11Screen.getIndex(); + final AbstractGraphicsDevice absDevice = x11Screen.getDevice(); + final long display = absDevice.getHandle(); + final int screen = x11Screen.getIndex(); - long fbcfg = X11GLXGraphicsConfiguration.glXFBConfigID2FBConfig(display, screen, fbID); + final long fbcfg = X11GLXGraphicsConfiguration.glXFBConfigID2FBConfig(display, screen, fbID); if( 0 == fbcfg || !X11GLXGraphicsConfiguration.GLXFBConfigValid( display, fbcfg ) ) { if(DEBUG) { System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: Failed - GLX FBConfig invalid: ("+x11Screen+","+toHexString(fbID)+"): fbcfg: "+toHexString(fbcfg)); } return null; } - X11GLCapabilities caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(glp, display, fbcfg, true, true, true, GLXUtil.isMultisampleAvailable(display)); + final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); + + final X11GLCapabilities caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(glp, display, fbcfg, true, true, true, factory.isGLXMultisampleAvailable(absDevice)); return new X11GLXGraphicsConfiguration(x11Screen, caps, caps, new DefaultGLCapabilitiesChooser()); } @@ -242,9 +244,10 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF // AbstractGraphicsDevice absDevice = x11Screen.getDevice(); long display = absDevice.getHandle(); - int screen = x11Screen.getIndex(); - boolean isMultisampleAvailable = GLXUtil.isMultisampleAvailable(display); + + final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); + final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, true, isMultisampleAvailable, display, screen); int[] count = { -1 }; ArrayList/*<X11GLCapabilities>*/ availableCaps = new ArrayList(); @@ -321,9 +324,10 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF AbstractGraphicsDevice absDevice = x11Screen.getDevice(); long display = absDevice.getHandle(); - int screen = x11Screen.getIndex(); - boolean isMultisampleAvailable = GLXUtil.isMultisampleAvailable(display); + + final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); + final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, false, isMultisampleAvailable, display, screen); // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice @@ -341,7 +345,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF int[] count = new int[1]; XVisualInfo template = XVisualInfo.create(); template.setScreen(screen); - XVisualInfo[] infos = X11Util.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0); + XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0); if (infos == null || infos.length<1) { throw new GLException("Error while enumerating available XVisualInfos"); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java index 8ef642322..333486a5f 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java @@ -56,14 +56,16 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } @SuppressWarnings("unused") + @Override public long getHandle() { if(USE_GLXWINDOW && useGLXWindow) { return glXWindow; } - return getNativeSurface().getSurfaceHandle(); + return super.getHandle(); } @SuppressWarnings("unused") + @Override protected void destroyHandle() { if(USE_GLXWINDOW && 0!=glXWindow) { GLX.glXDestroyWindow(getNativeSurface().getDisplayHandle(), glXWindow); @@ -72,10 +74,10 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } } - /** must be locked already */ + @Override protected void updateHandle() { if(USE_GLXWINDOW) { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration(); if(config.getFBConfig()>=0) { useGLXWindow=true; long dpy = getNativeSurface().getDisplayHandle(); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java index 8ea989267..da7b535cb 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java @@ -48,24 +48,18 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { /* GLCapabilities caps, GLCapabilitiesChooser chooser, int width, int height */ - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); - - if (DEBUG) { - System.err.println("Created pbuffer " + this); - } + super(factory, target, false); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -73,7 +67,7 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { return new X11PbufferGLXContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { GLX.glXDestroyPbuffer(ns.getDisplayHandle(), ns.getSurfaceHandle()); @@ -82,11 +76,14 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { } private void createPbuffer() { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration(); AbstractGraphicsScreen aScreen = config.getScreen(); AbstractGraphicsDevice aDevice = aScreen.getDevice(); long display = aDevice.getHandle(); - int screen = aScreen.getIndex(); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } if (display==0) { throw new GLException("Null display"); @@ -129,17 +126,15 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { int width = tmp[0]; GLX.glXQueryDrawable(display, pbuffer, GLX.GLX_HEIGHT, tmp, 0); int height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); + + if (DEBUG) { + System.err.println("Created pbuffer " + this); + } } public int getFloatingPointMode() { // Floating-point pbuffers currently require NVidia hardware on X11 return GLPbuffer.NV_FLOAT; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXContext.java index ef8007de4..e19dfd1b3 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXContext.java @@ -55,7 +55,7 @@ public class X11PixmapGLXContext extends X11GLXContext { } public int getOffscreenContextReadBuffer() { - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)drawable.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities(); if (caps.getDoubleBuffered()) { return GL.GL_BACK; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java index f5d321561..7dae20f80 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java @@ -48,15 +48,18 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { private long pixmap; protected X11PixmapGLXDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createPixmap(); } else { - destroyImpl(); + destroyPixmap(); } } @@ -64,9 +67,9 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { return new X11PixmapGLXContext(this, shareWith); } - private void create() { + private void createPixmap() { NativeSurface ns = getNativeSurface(); - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ns.getGraphicsConfiguration(); XVisualInfo vis = config.getXVisualInfo(); int bitsPerPixel = vis.getDepth(); AbstractGraphicsScreen aScreen = config.getScreen(); @@ -74,14 +77,14 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { long dpy = aDevice.getHandle(); int screen = aScreen.getIndex(); - pixmap = X11Util.XCreatePixmap(dpy, X11Util.RootWindow(dpy, screen), + pixmap = X11Lib.XCreatePixmap(dpy, X11Lib.RootWindow(dpy, screen), surface.getWidth(), surface.getHeight(), bitsPerPixel); if (pixmap == 0) { throw new GLException("XCreatePixmap failed"); } long drawable = GLX.glXCreateGLXPixmap(dpy, vis, pixmap); if (drawable == 0) { - X11Util.XFreePixmap(dpy, pixmap); + X11Lib.XFreePixmap(dpy, pixmap); pixmap = 0; throw new GLException("glXCreateGLXPixmap failed"); } @@ -93,7 +96,7 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { } } - protected void destroyImpl() { + protected void destroyPixmap() { if (pixmap == 0) return; NativeSurface ns = getNativeSurface(); @@ -122,16 +125,10 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { GLX.glXMakeCurrent(display, 0, 0); GLX.glXDestroyGLXPixmap(display, drawable); - X11Util.XFreePixmap(display, pixmap); + X11Lib.XFreePixmap(display, pixmap); drawable = 0; pixmap = 0; ((SurfaceChangeable)ns).setSurfaceHandle(0); display = 0; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/native/GLDebugMessageHandler.c b/src/jogl/native/GLDebugMessageHandler.c index 509c6f695..fea9d90ce 100644 --- a/src/jogl/native/GLDebugMessageHandler.c +++ b/src/jogl/native/GLDebugMessageHandler.c @@ -35,21 +35,22 @@ typedef void (GLAPIENTRY* _local_GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenu JNIEXPORT jboolean JNICALL Java_jogamp_opengl_GLDebugMessageHandler_initIDs0 (JNIEnv *env, jclass clazz) { + jboolean res; JoglCommon_init(env); glDebugMessageARB = (*env)->GetMethodID(env, clazz, "glDebugMessageARB", "(IIIILjava/lang/String;)V"); glDebugMessageAMD = (*env)->GetMethodID(env, clazz, "glDebugMessageAMD", "(IIILjava/lang/String;)V"); - if ( NULL == glDebugMessageARB || NULL == glDebugMessageAMD ) { - return JNI_FALSE; - } - return JNI_TRUE; + res = ( NULL != glDebugMessageARB && NULL != glDebugMessageAMD ) ? JNI_TRUE : JNI_FALSE ; + + DBG_PRINT("GLDebugMessageHandler.initIDS0: OK: %d, ARB %p, AMD %p\n", res, glDebugMessageARB, glDebugMessageAMD); + + return res; } typedef struct { JavaVM *vm; int version; - JNIEnv *env; jobject obj; int extType; } DebugHandlerType; @@ -65,10 +66,12 @@ static void GLDebugMessageARBCallback(GLenum source, GLenum type, GLuint id, GLe JNIEnv *curEnv = NULL; JNIEnv *newEnv = NULL; int envRes ; - DBG_PRINT("GLDebugMessageARBCallback: 01 - %s\n", message); + DBG_PRINT("GLDebugMessageARBCallback: 00 - %s, vm %p, version 0x%X, jobject %p, extType %d\n", + message, handle->vm, handle->version, (void*)handle->obj, handle->extType); // retrieve this thread's JNIEnv curEnv - or detect it's detached envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; + DBG_PRINT("GLDebugMessageARBCallback: 01 - JVM Env: curEnv %p, res 0x%X\n", curEnv, envRes); if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { @@ -107,9 +110,12 @@ static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severit JNIEnv *curEnv = NULL; JNIEnv *newEnv = NULL; int envRes ; + DBG_PRINT("GLDebugMessageAMDCallback: 00 - %s, vm %p, version 0x%X, jobject %p, extType %d\n", + message, handle->vm, handle->version, (void*)handle->obj, handle->extType); // retrieve this thread's JNIEnv curEnv - or detect it's detached envRes = (*vm)->GetEnv(vm, (void **) &curEnv, version) ; + DBG_PRINT("GLDebugMessageAMDCallback: 01 - JVM Env: curEnv %p, res 0x%X\n", curEnv, envRes); if( JNI_EDETACHED == envRes ) { // detached thread - attach to JVM if( JNI_OK != ( envRes = (*vm)->AttachCurrentThread(vm, (void**) &newEnv, NULL) ) ) { @@ -117,6 +123,7 @@ static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severit return; } curEnv = newEnv; + DBG_PRINT("GLDebugMessageAMDCallback: 02 - attached .. \n"); } else if( JNI_OK != envRes ) { // oops .. fprintf(stderr, "GLDebugMessageAMDCallback: can't GetEnv: %d\n", envRes); @@ -128,7 +135,9 @@ static void GLDebugMessageAMDCallback(GLuint id, GLenum category, GLenum severit if( NULL != newEnv ) { // detached attached thread (*vm)->DetachCurrentThread(vm); + DBG_PRINT("GLDebugMessageAMDCallback: 04 - detached .. \n"); } + DBG_PRINT("GLDebugMessageAMDCallback: 0X\n"); /** * On Java 32bit on 64bit Windows, * the unit test com.jogamp.opengl.test.junit.jogl.acore.TestGLDebug00NEWT crashes after this point. @@ -152,9 +161,10 @@ JNIEXPORT jlong JNICALL Java_jogamp_opengl_GLDebugMessageHandler_register0 } handle->vm = vm; handle->version = (*env)->GetVersion(env); - handle->env = env; handle->obj = (*env)->NewGlobalRef(env, obj); handle->extType = extType; + DBG_PRINT("GLDebugMessageHandler.register0: vm %p, version 0x%X, jobject %p, extType %d\n", + handle->vm, handle->version, (void*)handle->obj, handle->extType); if(jogamp_opengl_GLDebugMessageHandler_EXT_ARB == extType) { _local_PFNGLDEBUGMESSAGECALLBACKARBPROC ptr_glDebugMessageCallbackARB; @@ -181,9 +191,9 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_GLDebugMessageHandler_unregister0 { DebugHandlerType * handle = (DebugHandlerType*) (intptr_t) jhandle; - if(env != handle->env) { - JoglCommon_throwNewRuntimeException(env, "wrong handle (env doesn't match)"); - } + DBG_PRINT("GLDebugMessageHandler.unregister0: vm %p, version 0x%X, jobject %p, extType %d\n", + handle->vm, handle->version, (void*)handle->obj, handle->extType); + if(JNI_FALSE == (*env)->IsSameObject(env, obj, handle->obj)) { JoglCommon_throwNewRuntimeException(env, "wrong handle (obj doesn't match)"); } diff --git a/src/jogl/native/macosx/ContextUpdater.h b/src/jogl/native/macosx/ContextUpdater.h index 3cf7315af..f00b2be57 100644 --- a/src/jogl/native/macosx/ContextUpdater.h +++ b/src/jogl/native/macosx/ContextUpdater.h @@ -25,17 +25,13 @@ This notification is sent whenever an NSView that has an attached NSSurface chan @interface ContextUpdater : NSObject { @protected + pthread_mutex_t resourceLock; NSView * view; NSRect viewRect; NSOpenGLContext *ctx; BOOL viewUpdated; } -- (void) lock; -- (void) lockInFunction:(char *)func atLine:(int)line; -- (void) unlock; -- (void) unlockInFunction:(char *)func atLine:(int)line; - - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView; - (void) update:(NSNotification *)notification; diff --git a/src/jogl/native/macosx/ContextUpdater.m b/src/jogl/native/macosx/ContextUpdater.m index 21f98ad5e..d01eaf967 100644 --- a/src/jogl/native/macosx/ContextUpdater.m +++ b/src/jogl/native/macosx/ContextUpdater.m @@ -1,43 +1,26 @@ #import "ContextUpdater.h" #import <pthread.h> -@implementation ContextUpdater -{ -} - -static pthread_mutex_t resourceLock = PTHREAD_MUTEX_INITIALIZER; - -static void printLockDebugInfo(char *message, char *func, int line) -{ - fprintf(stderr, "%s in function: \"%s\" at line: %d\n", message, func, line); - fflush(NULL); -} - -- (void) lock -{ - pthread_mutex_lock(&resourceLock); -} +// #define VERBOSE_ON 1 -- (void) lockInFunction:(char *)func atLine:(int)line -{ - printLockDebugInfo("locked ", func, line); - [self lock]; -} +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif -- (void) unlock -{ - pthread_mutex_unlock(&resourceLock); -} +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif -- (void) unlockInFunction:(char *)func atLine:(int)line +@implementation ContextUpdater { - printLockDebugInfo("unlocked", func, line); - [self unlock]; } - (void) update:(NSNotification *)notification { - [self lock]; + pthread_mutex_lock(&resourceLock); NSRect r = [view frame]; if(viewRect.origin.x != r.origin.x || @@ -47,41 +30,47 @@ static void printLockDebugInfo(char *message, char *func, int line) viewUpdated = TRUE; viewRect = r; } - - [self unlock]; + + pthread_mutex_unlock(&resourceLock); } - (BOOL) needsUpdate { BOOL r; - [self lock]; + pthread_mutex_lock(&resourceLock); r = viewUpdated; viewUpdated = FALSE; - [self unlock]; + pthread_mutex_unlock(&resourceLock); return r; } - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView { + DBG_PRINT("ContextUpdater::init.0 view %p, ctx %p\n", view, ctx); + pthread_mutex_init(&resourceLock, NULL); // fast non-recursive ctx = context; view = nsView; [ctx retain]; [view retain]; viewRect = [view frame]; - viewUpdated = FALSE; + viewUpdated = TRUE; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(update:) name:NSViewGlobalFrameDidChangeNotification object: view]; + DBG_PRINT("ContextUpdater::init.X\n"); return [super init]; } - (void) dealloc { + DBG_PRINT("ContextUpdater::dealloc.0 view %p, ctx %p\n", view, ctx); [[NSNotificationCenter defaultCenter] removeObserver:self]; [view release]; [ctx release]; + pthread_mutex_destroy(&resourceLock); + DBG_PRINT("ContextUpdater::dealloc.X\n"); [super dealloc]; } diff --git a/src/jogl/native/macosx/MacOSXCustomCGLCode.c b/src/jogl/native/macosx/MacOSXCustomCGLCode.c index c29be889d..f8b7a800f 100644 --- a/src/jogl/native/macosx/MacOSXCustomCGLCode.c +++ b/src/jogl/native/macosx/MacOSXCustomCGLCode.c @@ -5,8 +5,7 @@ #include </usr/include/machine/types.h> #include "macosx-window-system.h" -void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { - CGLPixelFormatObj pix = (CGLPixelFormatObj) pixelFormat; +void CGLQueryPixelFormat(CGLPixelFormatObj fmt, int* iattrs, int niattrs, int* ivalues) { // FIXME: think about how specifying this might affect the API int virtualScreen = 0; @@ -14,7 +13,7 @@ void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalu GLint value; for (i = 0; i < niattrs && iattrs[i]>0; i++) { CGLPixelFormatAttribute attr = (CGLPixelFormatAttribute) iattrs[i]; - if ( kCGLNoError == CGLDescribePixelFormat(pix, virtualScreen, attr, &value) ) { + if ( kCGLNoError == CGLDescribePixelFormat(fmt, virtualScreen, attr, &value) ) { ivalues[i] = value; } else { ivalues[i] = 0; diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m new file mode 100644 index 000000000..7233f40ce --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m @@ -0,0 +1,140 @@ + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLContext* ctxShared; + NSView* view; + NSOpenGLPixelFormat* fmt; +@public + volatile BOOL shallDraw; +} + +- (id) initWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + view: (NSView*) v + opaque: (Bool) opaque; + +@end + +@implementation MyNSOpenGLLayer + +- (id) initWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + view: (NSView*) _view + opaque: (Bool) opaque +{ + self = [super init]; + ctxShared = _ctx; + [ctxShared retain]; + + fmt = _fmt; + [fmt retain]; + + view = _view; + [view retain]; + [self setView: view]; + [view setLayer: self]; + [view setWantsLayer: YES]; + + [self setAsynchronous: NO]; + // [self setAsynchronous: YES]; // FIXME: JAU + [self setNeedsDisplayOnBoundsChange: NO]; + [self setOpaque: opaque ? YES : NO]; + shallDraw = NO; + textureID = 0; + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, view %p, opaque %d\n", self, ctx, fmt, view, opaque); + return self; +} + +- (void)dealloc +{ + [fmt release]; + [ctxShared release]; + [view release]; + DBG_PRINT("MyNSOpenGLLayer::dealloc %p\n", self); + [super dealloc]; +} + +- (void) setOpenGLContext: (NSOpenGLContext*) _ctx +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLContext: %p %p -> %p\n", self, [self openGLContext], _ctx); + [super setOpenGLContext: _ctx]; +} + +- (void) setOpenGLPixelFormat: (NSOpenGLPixelFormat*) _fmt +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLPixelFormat %p %p -> %p\n", self, fmt, _fmt); + [super setOpenGLPixelFormat: fmt]; +} + +- (NSOpenGLPixelFormat *) openGLPixelFormat +{ + return fmt; +} + +- (void) setView: (NSView*) v +{ + DBG_PRINT("MyNSOpenGLLayer::setView %p %p -> %p (ignored/propagated)\n", self, view, v); + [super setView: view]; // propagate +} + +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask +{ + DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask %p %d -> %p\n", self, mask, fmt); + return fmt; +} + +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat +{ + NSOpenGLContext* ctx = NULL; + if(NULL == ctx) { + int viewNotReady[] = { 0 }; + ctx = createContext(ctxShared, view, true, fmt, [self isOpaque], viewNotReady); + } + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat %p, fmt %p/%p, view %p, shared %p -> %p\n", + self, fmt, pixelFormat, view, ctxShared, ctx); + return ctx; +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + DBG_PRINT("MyNSOpenGLLayer::canDrawInOpenGLContext %p: %d\n", self, self->shallDraw); + return self->shallDraw; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + self->shallDraw = NO; + + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p\n", self, context, pixelFormat); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSView* view, Bool opaque) { + return [[MyNSOpenGLLayer alloc] initWithContext:ctx pixelFormat: fmt view: view opaque: opaque]; +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + l->shallDraw = YES; + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:YES]; + // NSView* view = [l view]; + // [view setNeedsDisplay: YES]; // FIXME: JAU + // [view performSelectorOnMainThread:@selector(setNeedsDisplay:) withObject:YES waitUntilDone:YES]; + // [view performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:YES]; + DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [l release]; + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m new file mode 100644 index 000000000..fe896cc53 --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m @@ -0,0 +1,480 @@ +#import "MacOSXWindowSystemInterface.h" +#import <QuartzCore/QuartzCore.h> +#import <pthread.h> +#include "timespec.h" + +// +// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient. +// Use CVDisplayLink otherwise. +// +// #define HAS_CADisplayLink 1 +// + +// lock/sync debug output +// +// #define DBG_SYNC 1 +// +#ifdef DBG_SYNC + // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define SYNC_PRINT(...) +#endif + +// fps debug output +// +// #define DBG_PERF 1 + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLPixelBuffer* pbuffer; + int texWidth; + int texHeight; + GLuint textureID; + GLint swapInterval; +#ifdef HAS_CADisplayLink + CADisplayLink* displayLink; +#else + CVDisplayLinkRef displayLink; +#endif + int tc; + struct timespec t0; +@public + pthread_mutex_t renderLock; + pthread_cond_t renderSignal; + BOOL shallDraw; +} + +- (id) setupWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) texWidth + texHeight: (int) texHeight; + +- (void)deallocTex; +- (void)disableAnimation; +- (void)releaseLayer; +- (void)dealloc; +- (int)getSwapInterval; +- (void)setSwapInterval:(int)interval; +- (void)tick; + +@end + +#ifndef HAS_CADisplayLink + +static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext; + pthread_mutex_lock(&l->renderLock); + #ifdef DBG_PERF + [l tick]; + #endif + pthread_cond_signal(&l->renderSignal); + SYNC_PRINT("-*-"); + pthread_mutex_unlock(&l->renderLock); + [pool release]; + return kCVReturnSuccess; +} + +#endif + +@implementation MyNSOpenGLLayer + +- (id) setupWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) _texWidth + texHeight: (int) _texHeight; +{ + pthread_mutexattr_t renderLockAttr; + pthread_mutexattr_init(&renderLockAttr); + pthread_mutexattr_settype(&renderLockAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&renderLock, &renderLockAttr); // recursive + pthread_cond_init(&renderSignal, NULL); // no attribute + + // no animations for add/remove/swap sublayers etc + [self removeAnimationForKey: kCAOnOrderIn]; + [self removeAnimationForKey: kCAOnOrderOut]; + [self removeAnimationForKey: kCATransition]; + + pbuffer = p; + [pbuffer retain]; + + // instantiate a deactivated displayLink +#ifdef HAS_CADisplayLink + displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain]; + [displayLink setPaused: YES]; +#else + CVReturn cvres; + { + int allDisplaysMask = 0; + int virtualScreen, accelerated, displayMask; + for (virtualScreen = 0; virtualScreen < [_fmt numberOfVirtualScreens]; virtualScreen++) { + [_fmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; + [_fmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen]; + if (accelerated) { + allDisplaysMask |= displayMask; + } + } + cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [_ctx CGLContextObj], [_fmt CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + CVDisplayLinkStop(displayLink); + } +#endif + [self setAsynchronous: YES]; + + [self setNeedsDisplayOnBoundsChange: YES]; // FIXME: learn how to recreate on size change! + [self setOpaque: opaque ? YES : NO]; + texWidth = _texWidth; + texHeight = _texHeight; + textureID = 0; + swapInterval = -1; + shallDraw = NO; + + CGRect lRect = [self frame]; + + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, frame: %lf/%lf %lfx%lf (refcnt %d)\n", + self, _ctx, _fmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); + return self; +} + +- (void)disableAnimation +{ + DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); + pthread_mutex_lock(&renderLock); + [self setAsynchronous: NO]; + if(NULL != displayLink) { +#ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + [displayLink release]; +#else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + } +#endif + displayLink = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)deallocTex +{ + pthread_mutex_lock(&renderLock); + NSOpenGLContext* context = [self openGLContext]; + DBG_PRINT("MyNSOpenGLLayer::deallocTex %p (refcnt %d) - context %p, pbuffer %p\n", self, (int)[self retainCount], context, pbuffer); + if(NULL != pbuffer) { + if(NULL!=context) { + [context makeCurrentContext]; + if(0 != textureID) { + glDeleteTextures(1, &textureID); + textureID = 0; + } + [context clearDrawable]; + } + [pbuffer release]; + pbuffer = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)releaseLayer +{ + DBG_PRINT("MyNSOpenGLLayer::releaseLayer.0: %p (refcnt %d)\n", self, (int)[self retainCount]); + pthread_mutex_lock(&renderLock); + [self disableAnimation]; + [self deallocTex]; + [self release]; + DBG_PRINT("MyNSOpenGLLayer::releaseLayer.X: %p (refcnt %d)\n", self, (int)[self retainCount]); + pthread_mutex_unlock(&renderLock); +} + +- (void)dealloc +{ + DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + // NSLog(@"MyNSOpenGLLayer::dealloc: %@",[NSThread callStackSymbols]); + + [self disableAnimation]; + [self deallocTex]; + pthread_cond_destroy(&renderSignal); + pthread_mutex_destroy(&renderLock); + [super dealloc]; + DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + // assume both methods 'canDrawInOpenGLContext' and 'drawInOpenGLContext' + // are called from the same thread subsequently + pthread_mutex_lock(&renderLock); + Bool res = NULL != pbuffer && YES == shallDraw; + if(!res) { + SYNC_PRINT("<0>"); + pthread_mutex_unlock(&renderLock); + } else { + SYNC_PRINT("<"); + } + return res; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + [context makeCurrentContext]; + + /** + * v-sync doesn't works w/ NSOpenGLLayer's context .. well :( + * Using CVDisplayLink .. see setSwapInterval() below. + * + if(0 <= swapInterval) { + GLint si; + [context getValues: &si forParameter: NSOpenGLCPSwapInterval]; + if(si != swapInterval) { + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval); + [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + } + } */ + GLenum textureTarget = [pbuffer textureTarget]; + GLfloat tWidth, tHeight; + { + GLsizei pwidth = [pbuffer pixelsWide]; + GLsizei pheight = [pbuffer pixelsHigh]; + tWidth = textureTarget == GL_TEXTURE_2D ? (GLfloat)pwidth /(GLfloat)texWidth : pwidth; + tHeight = textureTarget == GL_TEXTURE_2D ? (GLfloat)pheight/(GLfloat)texHeight : pheight; + } + Bool texCreated = 0 == textureID; + + if(texCreated) { + glGenTextures(1, &textureID); + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p tex %dx%d -> %fx%f 0x%X: creating texID 0x%X\n", + self, context, pixelFormat, texWidth, texHeight, tWidth, tHeight, textureTarget, textureID); + + CGRect lRect = [self frame]; + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame0: %lf/%lf %lfx%lf\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + } + + glBindTexture(textureTarget, textureID); + + /** + if(texCreated) { + // proper tex size setup + glTexImage2D(textureTarget, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } */ + + [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT]; + + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glEnable(textureTarget); + + static GLfloat verts[] = { + -1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + 1.0, -1.0 + }; + + GLfloat tex[] = { + 0.0, 0.0, + 0.0, tHeight, + tWidth, tHeight, + tWidth, 0.0 + }; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, verts); + glTexCoordPointer(2, GL_FLOAT, 0, tex); + + glDrawArrays(GL_QUADS, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(textureTarget); + glBindTexture(textureTarget, 0); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; + shallDraw = NO; + if(0 >= swapInterval) { + pthread_cond_signal(&renderSignal); + SYNC_PRINT("*"); + } + SYNC_PRINT("1>"); + pthread_mutex_unlock(&renderLock); +} + +- (int)getSwapInterval +{ + return swapInterval; +} + +- (void)setSwapInterval:(int)interval +{ + DBG_PRINT("MyNSOpenGLLayer::setSwapInterval: %d\n", interval); + swapInterval = interval; + if(0 < swapInterval) { + tc = 0; + timespec_now(&t0); + + [self setAsynchronous: NO]; + #ifdef HAS_CADisplayLink + [displayLink setPaused: NO]; + [displayLink setFrameInterval: interval]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStart(displayLink); + // FIXME: doesn't support interval .. + } + #endif + } else { + #ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + } + #endif + [self setAsynchronous: YES]; + } +} + +-(void)tick +{ + tc++; + if(tc%60==0) { + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &t0); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n", + td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms ); + fflush(NULL); + } +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, Bool opaque, int texWidth, int texHeight) { + // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ? + // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO. + // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; + + return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; +} + +void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + pthread_mutex_lock(&l->renderLock); + [l setSwapInterval: interval]; + pthread_mutex_unlock(&l->renderLock); +} + +void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + BOOL ready = NO; + int wr = 0; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("{"); + do { + if([l getSwapInterval] <= 0) { + ready = !l->shallDraw; + } + if(NO == ready) { + if(0 < to_ms) { + struct timespec to_abs; + timespec_now(&to_abs); + timespec_addms(&to_abs, to_ms); + wr = pthread_cond_timedwait(&l->renderSignal, &l->renderLock, &to_abs); + #ifdef DBG_SYNC + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &to_abs); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "%ld ms", td_ms); + #endif + } else { + pthread_cond_wait (&l->renderSignal, &l->renderLock); + } + ready = !l->shallDraw; + } + } while (NO == ready && 0 == wr) ; + SYNC_PRINT("-%d}", ready); + pthread_mutex_unlock(&l->renderLock); +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + @synchronized(l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("["); + l->shallDraw = YES; + if([l getSwapInterval] > 0) { + // only trigger update if async mode is off (swapInterval>0) + if ( [NSThread isMainThread] == YES ) { + [l setNeedsDisplay]; + } else { + // can't wait, otherwise we may deadlock AWT + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; + } + SYNC_PRINT("1]"); + } else { + SYNC_PRINT("0]"); + } + pthread_mutex_unlock(&l->renderLock); + // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; + } +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p\n", l); + + if ( [NSThread isMainThread] == YES ) { + [l releaseLayer]; + } else { + [l performSelectorOnMainThread:@selector(releaseLayer) withObject:nil waitUntilDone:NO]; + } + + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p\n", l); + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.h b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h new file mode 100644 index 000000000..138accb22 --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h @@ -0,0 +1,20 @@ +#import <Cocoa/Cocoa.h> +#import <OpenGL/gl.h> +#import <OpenGL/CGLTypes.h> +#import <jni.h> + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif + +#import "macosx-window-system.h" + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m index 751fba9c0..b5979d53e 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -14,19 +14,10 @@ #endif */ -#import <Cocoa/Cocoa.h> -#import <OpenGL/gl.h> -#import <OpenGL/CGLTypes.h> -#import <jni.h> - -#ifndef CGL_VERSION_1_3 - #warning this SDK doesn't support OpenGL profile -#endif +#import "MacOSXWindowSystemInterface.h" #import "ContextUpdater.h" -#import "macosx-window-system.h" - // see MacOSXPbufferGLContext.java createPbuffer #define USE_GL_TEXTURE_RECTANGLE_EXT @@ -377,7 +368,7 @@ long validateParameter(NSOpenGLPixelFormatAttribute attribute, long value) return value; } -void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { +NSOpenGLPixelFormat* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; getRendererInfo(); @@ -390,6 +381,18 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { for (i = 0; i < niattrs && iattrs[i]>0; i++) { int attr = iattrs[i]; switch (attr) { + case NSOpenGLPFANoRecovery: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFANoRecovery; + } + break; + + case NSOpenGLPFAAccelerated: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAAccelerated; + } + break; + case NSOpenGLPFAPixelBuffer: if (ivalues[i] != 0) { attribs[idx++] = NSOpenGLPFAPixelBuffer; @@ -451,9 +454,8 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { return fmt; } -void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { +void queryPixelFormat(NSOpenGLPixelFormat* fmt, int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; GLint tmp; // FIXME: think about how specifying this might affect the API GLint virtualScreen = 0; @@ -468,16 +470,43 @@ void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) [pool release]; } -void deletePixelFormat(void* pixelFormat) { +void deletePixelFormat(NSOpenGLPixelFormat* fmt) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; [fmt release]; [pool release]; } -void* createContext(void* shareContext, - void* view, - void* pixelFormat, +NSOpenGLContext* getCurrentContext() { + NSOpenGLContext *ctx = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + ctx = [NSOpenGLContext currentContext]; + [pool release]; + return ctx; +} + +CGLContextObj getCGLContext(NSOpenGLContext* ctx) { + void * cglContext = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + cglContext = [ctx CGLContextObj]; + [pool release]; + return cglContext; +} + +NSView* getNSView(NSOpenGLContext* ctx) { + NSView* view = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + view = [ctx view]; + [pool release]; + return view; +} + +NSOpenGLContext* createContext(NSOpenGLContext* share, + NSView* view, + Bool isBackingLayerView, + NSOpenGLPixelFormat* fmt, Bool opaque, int* viewNotReady) { @@ -485,27 +514,22 @@ void* createContext(void* shareContext, NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSView *nsView = NULL; - NSObject *nsObj = (NSObject*) view; - - if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { - nsView = (NSView*)nsObj; - } - - if (nsView != NULL) - { + if (view != NULL) { Bool viewReady = true; - if ([nsView lockFocusIfCanDraw] == NO) - { - viewReady = false; + if(!isBackingLayerView) { + if ([view lockFocusIfCanDraw] == NO) { + DBG_PRINT("createContext [view lockFocusIfCanDraw] failed\n"); + viewReady = false; + } } - else - { - NSRect frame = [nsView frame]; - if ((frame.size.width == 0) || (frame.size.height == 0)) - { - [nsView unlockFocus]; + if(viewReady) { + NSRect frame = [view frame]; + if ((frame.size.width == 0) || (frame.size.height == 0)) { + if(!isBackingLayerView) { + [view unlockFocus]; + } + DBG_PRINT("createContext view.frame size %dx%d\n", (int)frame.size.width, (int)frame.size.height); viewReady = false; } } @@ -523,126 +547,95 @@ void* createContext(void* shareContext, } } - NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] - initWithFormat: (NSOpenGLPixelFormat*) pixelFormat - shareContext: (NSOpenGLContext*) shareContext]; + NSOpenGLContext* ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share]; - if (nsContext != nil) { - if (nsView != nil) { - if(!opaque) { - GLint zeroOpacity = 0; - [nsContext setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; - } - [nsContext setView:nsView]; - [nsView unlockFocus]; - } + if (ctx != nil) { + if (view != nil) { + if(!opaque) { + GLint zeroOpacity = 0; + [ctx setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; + } + [ctx setView:view]; + if(!isBackingLayerView) { + [view unlockFocus]; } + } + } [pool release]; - return nsContext; -} - -void * getCurrentContext() { - NSOpenGLContext *nsContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - nsContext = [NSOpenGLContext currentContext]; - [pool release]; - return nsContext;; + return ctx; } -void * getCGLContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * cglContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - cglContext = [nsContext CGLContextObj]; - [pool release]; - return cglContext; -} - -void * getNSView(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * view = NULL; - +Bool makeCurrentContext(NSOpenGLContext* ctx) { +#if 0 + // we issue the CGL Lock from Java upfront! NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - view = [nsContext view]; + CGLError cglError = CGLLockContext([ctx CGLContextObj]); + if(0 == cglError) { + [ctx makeCurrentContext]; + } [pool release]; - return view; -} - -Bool makeCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - + return 0 == cglError; +#else NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext makeCurrentContext]; + [ctx makeCurrentContext]; [pool release]; return true; +#endif } -Bool clearCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool clearCurrentContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLContext *currentNSContext = [NSOpenGLContext currentContext]; - if( currentNSContext != nsContext ) { - [nsContext makeCurrentContext]; + if( currentNSContext != ctx ) { + [ctx makeCurrentContext]; } [NSOpenGLContext clearCurrentContext]; +#if 0 + // we issue the CGL Lock from Java upfront! + CGLUnlockContext([ctx CGLContextObj]); +#endif [pool release]; return true; } -Bool deleteContext(void* nsJContext, Bool releaseOnMainThread) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool deleteContext(NSOpenGLContext* ctx, Bool releaseOnMainThread) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext clearDrawable]; + [ctx clearDrawable]; if(releaseOnMainThread && NO == [NSThread isMainThread]) { - [nsContext performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES]; + [ctx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; } else { // would hangs for ~10s for 1 of a shared context set or offscreen context, set releaseOnMainThread=true ! - [nsContext release]; + [ctx release]; } [pool release]; return true; } -Bool flushBuffer(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool flushBuffer(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext flushBuffer]; + [ctx flushBuffer]; [pool release]; return true; } -void setContextOpacity(void* nsJContext, int opacity) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - - [nsContext setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; +void setContextOpacity(NSOpenGLContext* ctx, int opacity) { + [ctx setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; } -void updateContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +void updateContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext update]; + [ctx update]; [pool release]; } -void copyContext(void* destContext, void* srcContext, int mask) { - NSOpenGLContext *src = (NSOpenGLContext*) srcContext; - NSOpenGLContext *dst = (NSOpenGLContext*) destContext; - [dst copyAttributesFromContext: src withMask: mask]; +void copyContext(NSOpenGLContext* dest, NSOpenGLContext* src, int mask) { + [dest copyAttributesFromContext: src withMask: mask]; } -void* updateContextRegister(void* nsJContext, void* nsJView) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSView *nsView = (NSView*)nsJView; - +void* updateContextRegister(NSOpenGLContext* ctx, NSView* view) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: nsContext view: nsView]; + ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: ctx view: view]; [pool release]; return contextUpdater; } @@ -666,7 +659,7 @@ void updateContextUnregister(void* updater) { [pool release]; } -void* createPBuffer(int renderTarget, int internalFormat, int width, int height) { +NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int width, int height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLPixelBuffer* pBuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:renderTarget @@ -678,35 +671,25 @@ void* createPBuffer(int renderTarget, int internalFormat, int width, int height) return pBuffer; } -Bool destroyPBuffer(void* buffer) { - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [pBuffer release]; [pool release]; - return true; } -void setContextPBuffer(void* nsJContext, void* buffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setPixelBuffer: pBuffer + [ctx setPixelBuffer: pBuffer cubeMapFace: 0 mipMapLevel: 0 - currentVirtualScreen: [nsContext currentVirtualScreen]]; + currentVirtualScreen: [ctx currentVirtualScreen]]; [pool release]; } -void setContextTextureImageToPBuffer(void* nsJContext, void* buffer, int colorBuffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setTextureImageToPixelBuffer: pBuffer - colorBuffer: (unsigned long) colorBuffer]; + [ctx setTextureImageToPixelBuffer: pBuffer colorBuffer: colorBuffer]; [pool release]; } @@ -746,10 +729,9 @@ void* getProcAddress(const char *procname) { return NULL; } -void setSwapInterval(void* nsJContext, int interval) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; +void setSwapInterval(NSOpenGLContext* ctx, int interval) { GLint swapInterval = interval; - [nsContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + [ctx setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; } Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp) { diff --git a/src/jogl/native/timespec.c b/src/jogl/native/timespec.c new file mode 100644 index 000000000..74c1a6901 --- /dev/null +++ b/src/jogl/native/timespec.c @@ -0,0 +1,63 @@ +#include "timespec.h" +#include <sys/time.h> + +void timespec_now(struct timespec *ts) +{ + struct timeval tv; + + // not using clock_gettime() [of rt library] due to portability + gettimeofday(&tv, NULL); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec*1000; +} + +void timespec_addms(struct timespec *ts, long ms) +{ + int sec=ms/1000; + ms=ms-sec*1000; + + // perform the addition + ts->tv_nsec+=ms*1000000; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; +} + +void timespec_addns(struct timespec *ts, long ns) +{ + int sec=ns/1000000000; + ns=ns - sec*1000000000; + + // perform the addition + ts->tv_nsec+=ns; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; + +} + +int timespec_compare(struct timespec *a, struct timespec *b) +{ + if (a->tv_sec!=b->tv_sec) + return a->tv_sec-b->tv_sec; + return a->tv_nsec-b->tv_nsec; +} + +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b) +{ + r->tv_sec = a->tv_sec; + r->tv_nsec = a->tv_nsec - b->tv_nsec; + if (r->tv_nsec < 0) { + // borrow. + r->tv_nsec += 1000000000; + r->tv_sec --; + } + r->tv_sec = r->tv_sec - b->tv_sec; +} + +long timespec_milliseconds(struct timespec *a) +{ + return a->tv_sec*1000 + a->tv_nsec/1000000; +} diff --git a/src/jogl/native/timespec.h b/src/jogl/native/timespec.h new file mode 100644 index 000000000..671eb4716 --- /dev/null +++ b/src/jogl/native/timespec.h @@ -0,0 +1,19 @@ +#ifndef _timespec_h +#define _timespec_h + +#include <time.h> + +void timespec_now(struct timespec *ts); +void timespec_addms(struct timespec *ts, long ms); +void timespec_addns(struct timespec *ts, long ns); + +/** returns 0: a==b, >0: a>b, <0: a<b */ +int timespec_compare(struct timespec *a, struct timespec *b); + +/** computes r = a - b */ +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b); + +/** convert the timespec into milliseconds (may overflow) */ +long timespec_milliseconds(struct timespec *a); + +#endif /* _timespec_h */ diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java index 784343c5a..1930bdda3 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsConfiguration.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -50,7 +51,7 @@ public interface AbstractGraphicsConfiguration extends Cloneable { /** * Return the capabilities reflecting this graphics configuration, - * which may differ from the capabilites used to choose this configuration. + * which may differ from the capabilities used to choose this configuration. * * @return An immutable instance of the Capabilities to avoid mutation by * the user. @@ -61,7 +62,7 @@ public interface AbstractGraphicsConfiguration extends Cloneable { * Return the capabilities used to choose this graphics configuration. * * These may be used to reconfigure the NativeWindow in case - * the device changes in a multi screen environment. + * the device changes in a multiple screen environment. * * @return An immutable instance of the Capabilities to avoid mutation by * the user. @@ -69,10 +70,10 @@ public interface AbstractGraphicsConfiguration extends Cloneable { public CapabilitiesImmutable getRequestedCapabilities(); /** - * In case this instance already reflects a native configuration, - * return this one. - * Otherwise return the encapsuled native configuration, - * as it shall be included e.g. in the AWT case. + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration}, + * otherwise this instance. + * @see NativeSurface#getGraphicsConfiguration() */ public AbstractGraphicsConfiguration getNativeGraphicsConfiguration(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java index 83b437612..fa25c214f 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/AbstractGraphicsDevice.java @@ -110,14 +110,15 @@ public interface AbstractGraphicsDevice extends Cloneable { public void unlock(); /** - * Optionally closing the device.<br> - * The default implementation is a NOP operation, returning false.<br> + * Optionally closing the device. + * <p> + * The default implementation is a <code>NOP</code>, just setting the handle to <code>null</code>. + * </p> * The specific implementing, ie {@link javax.media.nativewindow.x11.X11GraphicsDevice}, * shall have a enable/disable like {@link javax.media.nativewindow.x11.X11GraphicsDevice#setCloseDisplay(boolean, boolean)},<br> * which shall be invoked at creation time to determine ownership/role of freeing the resource.<br> * - * @return true if a specialized closing operation was successfully issued, otherwise false, - * ie no native closing operation was issued, which doesn't imply an error at all. + * @return true if the handle was not <code>null</code>, otherwise false. */ public boolean close(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java index ffa8bfae6..3eb7a6c9a 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsConfiguration.java @@ -84,8 +84,6 @@ public class DefaultGraphicsConfiguration implements Cloneable, AbstractGraphics * The use case for setting the Capabilities at a later time is * a change of the graphics device in a multi-screen environment.<br> * - * The objects reference is being used. - * * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ protected void setChosenCapabilities(CapabilitiesImmutable capsChosen) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java index c2aa6fae9..187959a67 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/DefaultGraphicsDevice.java @@ -46,7 +46,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice /** * Create an instance with the system default {@link ToolkitLock}, - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * gathered via {@link NativeWindowFactory#getDefaultToolkitLock(String)}. * @param type */ public DefaultGraphicsDevice(String type, String connection, int unitID) { @@ -55,12 +55,12 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = 0; - setToolkitLock( NativeWindowFactory.getDefaultToolkitLock(type) ); + this.toolkitLock = NativeWindowFactory.getDefaultToolkitLock(type); } /** * Create an instance with the system default {@link ToolkitLock}. - * gathered via {@link NativeWindowFactory#createDefaultToolkitLock()}. + * gathered via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. * @param type * @param handle */ @@ -70,7 +70,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = handle; - setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(type, handle) ); + this.toolkitLock = NativeWindowFactory.createDefaultToolkitLock(type, handle); } /** @@ -85,7 +85,7 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice this.unitID = unitID; this.uniqueID = getUniqueID(type, connection, unitID); this.handle = handle; - setToolkitLock( locker ); + this.toolkitLock = null != locker ? locker : NativeWindowFactoryImpl.getNullToolkitLock(); } @Override @@ -140,6 +140,10 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice } public boolean close() { + if(0 != handle) { + handle = 0; + return true; + } return false; } @@ -152,10 +156,21 @@ public class DefaultGraphicsDevice implements Cloneable, AbstractGraphicsDevice * Set the internal ToolkitLock, which is used within the * {@link #lock()} and {@link #unlock()} implementation. * + * <p> + * The current ToolkitLock is being locked/unlocked while swapping the reference, + * ensuring no concurrent access can occur during the swap. + * </p> + * * @param locker the ToolkitLock, if null, {@link jogamp.nativewindow.NullToolkitLock} is being used */ protected void setToolkitLock(ToolkitLock locker) { - this.toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + final ToolkitLock _toolkitLock = toolkitLock; + _toolkitLock.lock(); + try { + toolkitLock = ( null == locker ) ? NativeWindowFactoryImpl.getNullToolkitLock() : locker ; + } finally { + _toolkitLock.unlock(); + } } /** diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index fa3923dcf..259644467 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -40,7 +40,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; - /** * Provides the mechanism by which the graphics configuration for a * window can be chosen before the window is created. The graphics @@ -60,12 +59,34 @@ import java.util.Map; public abstract class GraphicsConfigurationFactory { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); - private static Map/*<Class, NativeWindowFactory>*/ registeredFactories = - Collections.synchronizedMap(new HashMap()); - private static Class abstractGraphicsDeviceClass; + private static Map<Class<?>, GraphicsConfigurationFactory> registeredFactories = + Collections.synchronizedMap(new HashMap<Class<?>, GraphicsConfigurationFactory>()); + private static Class<?> abstractGraphicsDeviceClass; static { - initialize(); + abstractGraphicsDeviceClass = javax.media.nativewindow.AbstractGraphicsDevice.class; + + // Register the default no-op factory for arbitrary + // AbstractGraphicsDevice implementations, including + // AWTGraphicsDevice instances -- the OpenGL binding will take + // care of handling AWTGraphicsDevices on X11 platforms (as + // well as X11GraphicsDevices in non-AWT situations) + registerFactory(abstractGraphicsDeviceClass, new DefaultGraphicsConfigurationFactoryImpl()); + + if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (Exception e) { + throw new RuntimeException(e); + } + if(NativeWindowFactory.isAWTAvailable()) { + try { + ReflectionUtil.callStaticMethod("jogamp.nativewindow.x11.awt.X11AWTGraphicsConfigurationFactory", + "registerFactory", null, null, GraphicsConfigurationFactory.class.getClassLoader()); + } catch (Exception e) { /* n/a */ } + } + } } protected static String getThreadName() { @@ -85,27 +106,6 @@ public abstract class GraphicsConfigurationFactory { protected GraphicsConfigurationFactory() { } - private static void initialize() { - abstractGraphicsDeviceClass = javax.media.nativewindow.AbstractGraphicsDevice.class; - - if (NativeWindowFactory.TYPE_X11.equals(NativeWindowFactory.getNativeWindowType(true))) { - try { - GraphicsConfigurationFactory factory = (GraphicsConfigurationFactory) - ReflectionUtil.createInstance("jogamp.nativewindow.x11.X11GraphicsConfigurationFactory", null, - GraphicsConfigurationFactory.class.getClassLoader()); - registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, factory); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - // Register the default no-op factory for arbitrary - // AbstractGraphicsDevice implementations, including - // AWTGraphicsDevice instances -- the OpenGL binding will take - // care of handling AWTGraphicsDevices on X11 platforms (as - // well as X11GraphicsDevices in non-AWT situations) - registerFactory(abstractGraphicsDeviceClass, new DefaultGraphicsConfigurationFactoryImpl()); - } - /** Returns the factory for use with the given type of AbstractGraphicsDevice. */ public static GraphicsConfigurationFactory getFactory(AbstractGraphicsDevice device) { @@ -122,7 +122,7 @@ public abstract class GraphicsConfigurationFactory { * * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - public static GraphicsConfigurationFactory getFactory(Class abstractGraphicsDeviceImplementor) + public static GraphicsConfigurationFactory getFactory(Class<?> abstractGraphicsDeviceImplementor) throws IllegalArgumentException, NativeWindowException { if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { @@ -130,10 +130,9 @@ public abstract class GraphicsConfigurationFactory { } GraphicsConfigurationFactory factory = null; - Class clazz = abstractGraphicsDeviceImplementor; + Class<?> clazz = abstractGraphicsDeviceImplementor; while (clazz != null) { - factory = - (GraphicsConfigurationFactory) registeredFactories.get(clazz); + factory = registeredFactories.get(clazz); if (factory != null) { if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() "+abstractGraphicsDeviceImplementor+" -> "+factory); @@ -143,7 +142,7 @@ public abstract class GraphicsConfigurationFactory { clazz = clazz.getSuperclass(); } // Return the default - factory = (GraphicsConfigurationFactory)registeredFactories.get(abstractGraphicsDeviceClass); + factory = registeredFactories.get(abstractGraphicsDeviceClass); if(DEBUG) { System.err.println("GraphicsConfigurationFactory.getFactory() DEFAULT "+abstractGraphicsDeviceClass+" -> "+factory); } @@ -157,7 +156,7 @@ public abstract class GraphicsConfigurationFactory { * * @throws IllegalArgumentException if the given class does not implement AbstractGraphicsDevice */ - protected static void registerFactory(Class abstractGraphicsDeviceImplementor, GraphicsConfigurationFactory factory) + protected static void registerFactory(Class<?> abstractGraphicsDeviceImplementor, GraphicsConfigurationFactory factory) throws IllegalArgumentException { if (!(abstractGraphicsDeviceClass.isAssignableFrom(abstractGraphicsDeviceImplementor))) { diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index e691ba8e6..e255dc051 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java @@ -118,6 +118,24 @@ public interface NativeSurface extends SurfaceUpdatedListener { */ public boolean surfaceSwap(); + /** Appends the given {@link SurfaceUpdatedListener} to the end of the list. */ + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l); + + /** + * Inserts the given {@link SurfaceUpdatedListener} at the + * specified position in the list.<br> + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). + * @param l The listener object to be inserted + * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 + */ + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; + + /** Remove the specified {@link SurfaceUpdatedListener} from the list. */ + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); + /** * Returns the handle to the surface for this NativeSurface. <P> * @@ -149,6 +167,11 @@ public interface NativeSurface extends SurfaceUpdatedListener { /** * Returns the graphics configuration corresponding to this window. + * <p> + * In case the implementation utilizes a delegation pattern to wrap abstract toolkits, + * this method shall return the native {@link AbstractGraphicsConfiguration} via {@link AbstractGraphicsConfiguration#getNativeGraphicsConfiguration()}. + * </p> + * @see AbstractGraphicsConfiguration#getNativeGraphicsConfiguration() * @see javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) */ public AbstractGraphicsConfiguration getGraphicsConfiguration(); diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java index 76ac72953..2bc352116 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindow.java @@ -104,20 +104,26 @@ public interface NativeWindow extends NativeSurface { /** * @return the current x position of the top-left corner - * of the client area, hence excluding insets (window decorations).<br> + * of the client area relative to it's parent. + * Since the position reflects the client area, it does not include the insets. * @see #getInsets() */ public int getX(); /** * @return the current y position of the top-left corner - * of the client area, hence excluding insets (window decorations).<br> + * of the client area relative to it's parent. + * Since the position reflects the client area, it does not include the insets. * @see #getInsets() */ public int getY(); /** - * Returns the current absolute location of this window. + * Returns the current position of the top-left corner + * of the client area in screen coordinates. + * <p> + * Since the position reflects the client area, it does not include the insets. + * </p> * @param point if not null, * {@link javax.media.nativewindow.util.Point#translate(javax.media.nativewindow.util.Point)} * the passed {@link javax.media.nativewindow.util.Point} by this location on the screen and return it. @@ -126,4 +132,7 @@ public interface NativeWindow extends NativeSurface { */ public Point getLocationOnScreen(Point point); + /** Returns true if this native window owns the focus, otherwise false. */ + boolean hasFocus(); + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java index ef8876f50..c69b18b30 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeWindowFactory.java @@ -33,15 +33,20 @@ package javax.media.nativewindow; -import java.security.*; -import java.util.*; - -import com.jogamp.common.util.*; -import com.jogamp.common.os.Platform; - -import jogamp.nativewindow.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NativeWindowFactoryImpl; + +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; /** Provides a pluggable mechanism for arbitrary window toolkits to adapt their components to the {@link NativeWindow} interface, @@ -75,20 +80,25 @@ public abstract class NativeWindowFactory { private static NativeWindowFactory defaultFactory; private static Map<Class<?>, NativeWindowFactory> registeredFactories; + private static Class<?> nativeWindowClass; private static String nativeWindowingTypePure; private static String nativeWindowingTypeCustom; private static boolean isAWTAvailable; - public static final String AWTComponentClassName = "java.awt.Component" ; - public static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; - public static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; - public static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; - public static final String GDIClassName = "jogamp.nativewindow.windows.GDI"; - public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; - public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; + + private static final String JAWTUtilClassName = "jogamp.nativewindow.jawt.JAWTUtil" ; + private static final String X11UtilClassName = "jogamp.nativewindow.x11.X11Util"; + private static final String OSXUtilClassName = "jogamp.nativewindow.macosx.OSXUtil"; + private static final String GDIClassName = "jogamp.nativewindow.windows.GDIUtil"; + private static Class<?> jawtUtilClass; private static Method jawtUtilGetJAWTToolkitMethod; private static Method jawtUtilInitMethod; + + public static final String AWTComponentClassName = "java.awt.Component" ; + public static final String X11JAWTToolkitLockClassName = "jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock" ; + public static final String X11ToolkitLockClassName = "jogamp.nativewindow.x11.X11ToolkitLock" ; + private static Class<?> x11JAWTToolkitLockClass; private static Constructor<?> x11JAWTToolkitLockConstructor; private static Class<?> x11ToolkitLockClass; @@ -132,16 +142,18 @@ public abstract class NativeWindowFactory { static boolean initialized = false; - private static void initNativeImpl(final boolean firstUIActionOnProcess, final ClassLoader cl) { + private static void initSingletonNativeImpl(final boolean firstUIActionOnProcess, final ClassLoader cl) { isFirstUIActionOnProcess = firstUIActionOnProcess; - - String clazzName = null; + + final String clazzName; if( TYPE_X11.equals(nativeWindowingTypePure) ) { clazzName = X11UtilClassName; } else if( TYPE_WINDOWS.equals(nativeWindowingTypePure) ) { clazzName = GDIClassName; } else if( TYPE_MACOSX.equals(nativeWindowingTypePure) ) { clazzName = OSXUtilClassName; + } else { + clazzName = null; } if( null != clazzName ) { ReflectionUtil.callStaticMethod(clazzName, "initSingleton", @@ -152,7 +164,7 @@ public abstract class NativeWindowFactory { requiresToolkitLock = res.booleanValue(); } else { requiresToolkitLock = false; - } + } } /** @@ -178,6 +190,8 @@ public abstract class NativeWindowFactory { System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.initSingleton("+firstUIActionOnProcess+")"); } + final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); + // Gather the windowing OS first AccessControlContext acc = AccessController.getContext(); nativeWindowingTypePure = _getNativeWindowingType(); @@ -188,12 +202,10 @@ public abstract class NativeWindowFactory { nativeWindowingTypeCustom = tmp; } - final ClassLoader cl = NativeWindowFactory.class.getClassLoader(); - if(firstUIActionOnProcess) { // X11 initialization before possible AWT initialization - initNativeImpl(true, cl); - } + initSingletonNativeImpl(true, cl); + } isAWTAvailable = false; // may be set to true below if( !Debug.getBooleanProperty("java.awt.headless", true, acc) && @@ -203,7 +215,7 @@ public abstract class NativeWindowFactory { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { try { - jawtUtilClass = Class.forName(JAWTUtilClassName, false, NativeWindowFactory.class.getClassLoader()); + jawtUtilClass = Class.forName(JAWTUtilClassName, true, NativeWindowFactory.class.getClassLoader()); jawtUtilInitMethod = jawtUtilClass.getDeclaredMethod("initSingleton", (Class[])null); jawtUtilInitMethod.setAccessible(true); jawtUtilGetJAWTToolkitMethod = jawtUtilClass.getDeclaredMethod("getJAWTToolkitLock", new Class[]{}); @@ -227,7 +239,7 @@ public abstract class NativeWindowFactory { } if(!firstUIActionOnProcess) { // X11 initialization after possible AWT initialization - initNativeImpl(false, cl); + initSingletonNativeImpl(false, cl); } registeredFactories = Collections.synchronizedMap(new HashMap<Class<?>, NativeWindowFactory>()); @@ -260,6 +272,21 @@ public abstract class NativeWindowFactory { } } + public static synchronized void shutdown() { + if(initialized) { + initialized = false; + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() START"); + } + registeredFactories.clear(); + registeredFactories = null; + // X11Util.shutdown(..) already called via GLDrawableFactory.shutdown() .. + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - NativeWindowFactory.shutdown() END"); + } + } + } + /** @return true if initialized with <b>{@link #initSingleton(boolean) initSingleton(firstUIActionOnProcess==true)}</b>, otherwise false. */ public static boolean isFirstUIActionOnProcess() { @@ -319,31 +346,30 @@ public abstract class NativeWindowFactory { * <ul> * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> * <ul> - * <li>If native <b>X11 type</b> with or w/o AWT</li> - * <ul> - * <li> If <b>AWT available</b> </li> + * <li>If <b>AWT-type</b> and <b>native-X11-type</b> and <b>AWT-available</b></li> * <ul> * <li> return {@link jogamp.nativewindow.jawt.JAWTToolkitLock} </li> * </ul> - * </ul> * </ul> * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ public static ToolkitLock getDefaultToolkitLock(String type) { if( requiresToolkitLock() ) { - if( TYPE_X11 == type || TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) ) { - if( isAWTAvailable() ) { - return getAWTToolkitLock(); - } + if( TYPE_AWT == type && TYPE_X11 == getNativeWindowType(false) && isAWTAvailable() ) { + return getAWTToolkitLock(); } } return NativeWindowFactoryImpl.getNullToolkitLock(); } - protected static ToolkitLock getAWTToolkitLock() { + private static ToolkitLock getAWTToolkitLock() { Object resO = ReflectionUtil.callMethod(null, jawtUtilGetJAWTToolkitMethod); + if(DEBUG) { + System.err.println("NativeWindowFactory.getAWTToolkitLock()"); + Thread.dumpStack(); + } if(resO instanceof ToolkitLock) { return (ToolkitLock) resO; } else { @@ -363,26 +389,49 @@ public abstract class NativeWindowFactory { * <ul> * <li>If <b>X11 type</b> </li> * <ul> - * <li> If <b>AWT available</b> </li> + * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> + * </ul> + * </ul> + * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> + * </ul> + */ + public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { + if( requiresToolkitLock() ) { + if( TYPE_X11 == type ) { + if( 0== deviceHandle ) { + throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); + } + return createX11ToolkitLock(deviceHandle); + } + } + return NativeWindowFactoryImpl.getNullToolkitLock(); + } + + /** + * Creates the default {@link ToolkitLock} for <code>type</code> and <code>deviceHandle</code>. + * <br> + * <ul> + * <li> If {@link #initSingleton(boolean) initSingleton( <b>firstUIActionOnProcess := false</b> )} </li> + * <ul> + * <li>If <b>X11 type</b> </li> + * <ul> + * <li> If <b>shared-AWT-type</b> and <b>AWT available</b> </li> * <ul> * <li> return {@link jogamp.nativewindow.jawt.x11.X11JAWTToolkitLock} </li> * </ul> - * <li> If <b>AWT not available</b> </li> - * <ul> - * <li> return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> - * </ul> + * <li> else return {@link jogamp.nativewindow.x11.X11ToolkitLock} </li> * </ul> * </ul> * <li> Otherwise return {@link jogamp.nativewindow.NullToolkitLock} </li> * </ul> */ - public static ToolkitLock createDefaultToolkitLock(String type, long deviceHandle) { + public static ToolkitLock createDefaultToolkitLock(String type, String sharedType, long deviceHandle) { if( requiresToolkitLock() ) { if( TYPE_X11 == type ) { if( 0== deviceHandle ) { throw new RuntimeException("JAWTUtil.createDefaultToolkitLock() called with NULL device but on X11"); } - if( isAWTAvailable() ) { + if( TYPE_AWT == sharedType && isAWTAvailable() ) { return createX11AWTToolkitLock(deviceHandle); } return createX11ToolkitLock(deviceHandle); @@ -393,6 +442,10 @@ public abstract class NativeWindowFactory { protected static ToolkitLock createX11AWTToolkitLock(long deviceHandle) { try { + if(DEBUG) { + System.err.println("NativeWindowFactory.createX11AWTToolkitLock(0x"+Long.toHexString(deviceHandle)+")"); + Thread.dumpStack(); + } return (ToolkitLock) x11JAWTToolkitLockConstructor.newInstance(new Object[]{new Long(deviceHandle)}); } catch (Exception ex) { throw new RuntimeException(ex); @@ -470,4 +523,37 @@ public abstract class NativeWindowFactory { NativeWindow. Implementors of concrete NativeWindowFactory subclasses should override this method. */ protected abstract NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException; + + /** + * Returns the {@link OffscreenLayerSurface} instance of this {@link NativeSurface}. + * <p> + * In case this surface is a {@link NativeWindow}, we traverse from the given surface + * up to root until an implementation of {@link OffscreenLayerSurface} is found. + * In case <code>ifEnabled</code> is true, the surface must also implement {@link OffscreenLayerOption} + * where {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()} is <code>true</code>. + * </p> + * + * @param surface The surface to query. + * @param ifEnabled If true, only return the enabled {@link OffscreenLayerSurface}, see {@link OffscreenLayerOption#isOffscreenLayerSurfaceEnabled()}. + * @return + */ + public static OffscreenLayerSurface getOffscreenLayerSurface(NativeSurface surface, boolean ifEnabled) { + if(surface instanceof OffscreenLayerSurface && + ( !ifEnabled || surface instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) surface; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + if(surface instanceof NativeWindow) { + NativeWindow nw = ((NativeWindow) surface).getParent(); + while(null != nw) { + if(nw instanceof OffscreenLayerSurface && + ( !ifEnabled || nw instanceof OffscreenLayerOption ) ) { + final OffscreenLayerSurface ols = (OffscreenLayerSurface) nw; + return ( !ifEnabled || ((OffscreenLayerOption)ols).isOffscreenLayerSurfaceEnabled() ) ? ols : null; + } + nw = nw.getParent(); + } + } + return null; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java new file mode 100644 index 000000000..12d30b3cd --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerOption.java @@ -0,0 +1,61 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.nativewindow; + +/** + * Handling requests for using an {@link OffscreenLayerSurface} + * within the implementation. + */ +public interface OffscreenLayerOption { + /** + * Request an offscreen layer, if supported. + * <p> + * Shall be called before the first {@link NativeWindow#lockSurface()}, + * and hence before realization. + * </p> + * + * @see #getShallUseOffscreenLayer() + * @see #isOffscreenLayerSurfaceEnabled() + */ + public void setShallUseOffscreenLayer(boolean v); + + /** Returns the property set by {@link #setShallUseOffscreenLayer(boolean)}. */ + public boolean getShallUseOffscreenLayer(); + + /** + * Returns true if this instance uses an offscreen layer, otherwise false. + * <p> + * This instance is an offscreen layer, if {@link #setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)} + * has been called before it's realization and first lock and the underlying implementation supports it. + * </p> + * The return value is undefined before issuing the first {@link NativeWindow#lockSurface()}. + * + * @see #setShallUseOffscreenLayer(boolean) + */ + public boolean isOffscreenLayerSurfaceEnabled(); +}
\ No newline at end of file diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java new file mode 100644 index 000000000..dd36509ba --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -0,0 +1,48 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package javax.media.nativewindow; + +/** + * Interface specifying the offscreen layer surface protocol. + */ +public interface OffscreenLayerSurface { + /** + * Attach the offscreen layer to this offscreen layer surface. + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + */ + public void attachSurfaceLayer(final long layerHandle) throws NativeWindowException; + + /** + * Detaches a previously attached offscreen layer from this offscreen layer surface. + * @see #attachSurfaceLayer(long) + * @see #isOffscreenLayerSurfaceEnabled() + * @throws NativeWindowException if {@link #isOffscreenLayerSurfaceEnabled()} == false + */ + public void detachSurfaceLayer(final long layerHandle) throws NativeWindowException; +} diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java index e34476228..9100beac2 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -28,12 +28,15 @@ package javax.media.nativewindow; +import jogamp.nativewindow.SurfaceUpdatedHelper; + import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; public abstract class ProxySurface implements NativeSurface { + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + private AbstractGraphicsConfiguration config; // control access due to delegation protected RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); - protected AbstractGraphicsConfiguration config; protected long displayHandle; protected int height; protected int scrnIndex; @@ -42,7 +45,7 @@ public abstract class ProxySurface implements NativeSurface { public ProxySurface(AbstractGraphicsConfiguration cfg) { invalidate(); config = cfg; - displayHandle=cfg.getScreen().getDevice().getHandle(); + displayHandle=cfg.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); } void invalidate() { @@ -55,12 +58,16 @@ public abstract class ProxySurface implements NativeSurface { return displayHandle; } - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { return config; } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } public final int getScreenIndex() { - return config.getScreen().getIndex(); + return getGraphicsConfiguration().getScreen().getIndex(); } public abstract long getSurfaceHandle(); @@ -73,7 +80,7 @@ public abstract class ProxySurface implements NativeSurface { return height; } - public void setSize(int width, int height) { + public void surfaceSizeChanged(int width, int height) { this.width = width; this.height = height; } @@ -82,16 +89,29 @@ public abstract class ProxySurface implements NativeSurface { return false; } - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } + public int lockSurface() throws NativeWindowException { surfaceLock.lock(); int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { try { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { res = lockSurfaceImpl(); @@ -113,7 +133,7 @@ public abstract class ProxySurface implements NativeSurface { surfaceLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -143,5 +163,5 @@ public abstract class ProxySurface implements NativeSurface { return surfaceLock.getOwner(); } - public abstract String toString(); + public abstract String toString(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java b/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java index fc32b57b3..956e68e61 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java +++ b/src/nativewindow/classes/javax/media/nativewindow/SurfaceChangeable.java @@ -41,8 +41,14 @@ package javax.media.nativewindow; public interface SurfaceChangeable { + /** Sets the surface handle which is created outside of this implementation */ public void setSurfaceHandle(long surfaceHandle); - public void setSize(int width, int height); + + /** + * The surface's size has been determined or changed. + * Implementation shall update the stored surface size with the given ones. + */ + public void surfaceSizeChanged(int width, int height); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java index 88e805d14..0912b5afe 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java +++ b/src/nativewindow/classes/javax/media/nativewindow/SurfaceUpdatedListener.java @@ -34,8 +34,12 @@ package javax.media.nativewindow; +/** + * Clients may add their SurfaceUpdateListener implementation to a {@link javax.media.nativewindow.NativeSurface} + * allowing to get notified after the surface has been updated, eg. after a swap buffer operation. + */ public interface SurfaceUpdatedListener { - /** Notification of a surface update event. + /** Notification of a surface update event, eg. after a swap buffer operation. * * @param updater is the caller object who updated the surface, * e.g. a JOGL GLDrawable. diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java index d83a92a5b..45a3db838 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsConfiguration.java @@ -41,11 +41,13 @@ package javax.media.nativewindow.awt; import javax.media.nativewindow.*; + import java.awt.Component; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.image.ColorModel; import javax.media.nativewindow.AbstractGraphicsConfiguration; + import jogamp.nativewindow.Debug; /** A wrapper for an AWT GraphicsConfiguration allowing it to be @@ -63,56 +65,61 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple this.encapsulated=encapsulated; } - public AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - GraphicsConfiguration config) { + private AWTGraphicsConfiguration(AWTGraphicsScreen screen, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + GraphicsConfiguration config) { super(screen, capsChosen, capsRequested); this.config = config; this.encapsulated=null; } - + /** * @param capsChosen if null, <code>capsRequested</code> is copied and aligned - * with the graphics capabilties of the AWT Component to produce the chosen Capabilties. + * with the graphics Capabilities of the AWT Component to produce the chosen Capabilities. * Otherwise the <code>capsChosen</code> is used. */ - public static AWTGraphicsConfiguration create(Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) - { - AWTGraphicsScreen awtScreen = null; - AWTGraphicsDevice awtDevice = null; - GraphicsDevice awtGraphicsDevice = null; - GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); - if(null!=awtGfxConfig) { - awtGraphicsDevice = awtGfxConfig.getDevice(); - if(null!=awtGraphicsDevice) { - // Create Device/Screen - awtDevice = new AWTGraphicsDevice(awtGraphicsDevice, AbstractGraphicsDevice.DEFAULT_UNIT); - awtScreen = new AWTGraphicsScreen(awtDevice); - } + public static AWTGraphicsConfiguration create(Component awtComp, CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + final GraphicsConfiguration awtGfxConfig = awtComp.getGraphicsConfiguration(); + if(null==awtGfxConfig) { + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsConfiguration @ "+awtComp); } - if(null==awtScreen) { - // use defaults since no native peer is available yet - awtScreen = (AWTGraphicsScreen) AWTGraphicsScreen.createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); - awtDevice = (AWTGraphicsDevice) awtScreen.getDevice(); - awtGraphicsDevice = awtDevice.getGraphicsDevice(); + final GraphicsDevice awtGraphicsDevice = awtGfxConfig.getDevice(); + if(null==awtGraphicsDevice) { + throw new NativeWindowException("AWTGraphicsConfiguration.create: Null AWT GraphicsDevice @ "+awtGfxConfig); } + // Create Device/Screen + final AWTGraphicsDevice awtDevice = new AWTGraphicsDevice(awtGraphicsDevice, AbstractGraphicsDevice.DEFAULT_UNIT); + final AWTGraphicsScreen awtScreen = new AWTGraphicsScreen(awtDevice); + if(null==capsChosen) { GraphicsConfiguration gc = awtGraphicsDevice.getDefaultConfiguration(); - capsChosen = setupCapabilitiesRGBABits(capsChosen, gc); + capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsRequested, gc); + } + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtDevice); + final AbstractGraphicsConfiguration config = factory.chooseGraphicsConfiguration(capsChosen, capsRequested, null, awtScreen); + if(config instanceof AWTGraphicsConfiguration) { + return (AWTGraphicsConfiguration) config; } + // System.err.println("Info: AWTGraphicsConfiguration.create: Expected AWTGraphicsConfiguration got: "+config.getClass()+" w/ factory "+factory.getClass()+" - Unable to encapsulate native GraphicsConfiguration."); return new AWTGraphicsConfiguration(awtScreen, capsChosen, capsRequested, awtGfxConfig); } - @Override + // open access to superclass method + public void setChosenCapabilities(CapabilitiesImmutable capsChosen) { + super.setChosenCapabilities(capsChosen); + } + + @Override public Object clone() { return super.clone(); } - public GraphicsConfiguration getGraphicsConfiguration() { + /** Return the AWT {@link GraphicsConfiguration}. */ + public GraphicsConfiguration getAWTGraphicsConfiguration() { return config; } - @Override + @Override public AbstractGraphicsConfiguration getNativeGraphicsConfiguration() { return (null!=encapsulated)?encapsulated:this; } @@ -156,7 +163,7 @@ public class AWTGraphicsConfiguration extends DefaultGraphicsConfiguration imple return capabilities; } - @Override + @Override public String toString() { return getClass().getSimpleName()+"[" + getScreen() + ",\n\tchosen " + capabilitiesChosen+ diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java index 66a63bfcd..8ebe37626 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsDevice.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -46,26 +47,20 @@ import javax.media.nativewindow.AbstractGraphicsDevice; /** A wrapper for an AWT GraphicsDevice allowing it to be handled in a toolkit-independent manner. */ - public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { private GraphicsDevice device; - private String subType; - protected AWTGraphicsDevice(GraphicsDevice device, int unitID) { + public AWTGraphicsDevice(GraphicsDevice device, int unitID) { super(NativeWindowFactory.TYPE_AWT, device.getIDstring(), unitID); this.device = device; - this.subType = null; } - public static AbstractGraphicsDevice createDevice(GraphicsDevice awtDevice, int unitID) { - if(null==awtDevice) { - awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); - unitID = AbstractGraphicsDevice.DEFAULT_UNIT; - } - return new AWTGraphicsDevice(awtDevice, unitID); + public static AWTGraphicsDevice createDefault() { + GraphicsDevice awtDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + return new AWTGraphicsDevice(awtDevice, AbstractGraphicsDevice.DEFAULT_UNIT); } - @Override + @Override public Object clone() { return super.clone(); } @@ -74,26 +69,9 @@ public class AWTGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl return device; } - /** - * In case the native handle was specified, e.g. using X11, - * we shall be able to mark it.<br> - * This will also set the subType, queried with {@link #getSubType()} - * and reset the ToolkitLock type with {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)} - * and {@link #setToolkitLock(javax.media.nativewindow.ToolkitLock)}. - */ - public void setSubType(String subType, long handle) { - this.handle = handle; - this.subType = subType; - setToolkitLock( NativeWindowFactory.createDefaultToolkitLock(subType, handle) ); - } - - public String getSubType() { - return subType; - } - - @Override + @Override public String toString() { - return getClass().getSimpleName()+"[type "+getType()+"[subType "+getSubType()+"], connection "+getConnection()+", unitID "+getUnitID()+", awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; + return getClass().getSimpleName()+"[type "+getType()+", connection "+getConnection()+", unitID "+getUnitID()+", awtDevice "+device+", handle 0x"+Long.toHexString(getHandle())+"]"; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java index 383dcae80..2978d7868 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/awt/AWTGraphicsScreen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -42,7 +43,6 @@ package javax.media.nativewindow.awt; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import javax.media.nativewindow.*; -import javax.media.nativewindow.AbstractGraphicsDevice; /** A wrapper for an AWT GraphicsDevice (screen) allowing it to be handled in a toolkit-independent manner. */ @@ -74,17 +74,15 @@ public class AWTGraphicsScreen extends DefaultGraphicsScreen implements Cloneabl } public static AbstractGraphicsScreen createScreenDevice(GraphicsDevice awtDevice, int unitID) { - AWTGraphicsDevice device = (AWTGraphicsDevice) AWTGraphicsDevice.createDevice(awtDevice, unitID); - return new AWTGraphicsScreen(device); + return new AWTGraphicsScreen(new AWTGraphicsDevice(awtDevice, unitID)); } public static AbstractGraphicsScreen createScreenDevice(int index, int unitID) { - GraphicsDevice awtDevice = getScreenDevice(index); - return createScreenDevice(awtDevice, unitID); + return createScreenDevice(getScreenDevice(index), unitID); } public static AbstractGraphicsScreen createDefault() { - return createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); + return new AWTGraphicsScreen(AWTGraphicsDevice.createDefault()); } public Object clone() { diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java index 100b6b839..74439336d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsConfiguration.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,8 +33,9 @@ package javax.media.nativewindow.x11; -import javax.media.nativewindow.*; +import javax.media.nativewindow.CapabilitiesImmutable; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.x11.XVisualInfo; /** Encapsulates a graphics configuration, or OpenGL pixel format, on @@ -42,7 +44,7 @@ import jogamp.nativewindow.x11.XVisualInfo; GraphicsConfigurationFactory.chooseGraphicsConfiguration()} on X11 platforms when toolkits other than the AWT are being used. */ -public class X11GraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class X11GraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { private XVisualInfo info; public X11GraphicsConfiguration(X11GraphicsScreen screen, diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java index 48fd63e3c..73c8cfd52 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsDevice.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +34,7 @@ package javax.media.nativewindow.x11; import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import javax.media.nativewindow.DefaultGraphicsDevice; import javax.media.nativewindow.NativeWindowException; @@ -44,49 +46,49 @@ import javax.media.nativewindow.ToolkitLock; public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneable { public static final boolean DEBUG = Debug.debug("GraphicsDevice"); - boolean closeDisplay = false; + final boolean closeDisplay; /** Constructs a new X11GraphicsDevice corresponding to the given connection and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}.<br> + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#getDefaultToolkitLock(String)}.<br> * Note that this is not an open connection, ie no native display handle exist. * This constructor exist to setup a default device connection. + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int) */ public X11GraphicsDevice(String connection, int unitID) { super(NativeWindowFactory.TYPE_X11, connection, unitID); + closeDisplay = false; } /** Constructs a new X11GraphicsDevice corresponding to the given native display handle and default - * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(java.lang.String, long)}. + * {@link javax.media.nativewindow.ToolkitLock} via {@link NativeWindowFactory#createDefaultToolkitLock(String, long)}. + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long) */ - public X11GraphicsDevice(long display, int unitID) { + public X11GraphicsDevice(long display, int unitID, boolean owner) { // FIXME: derive unitID from connection could be buggy, one DISPLAY for all screens for example.. - super(NativeWindowFactory.TYPE_X11, X11Util.XDisplayString(display), unitID, display); + super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display); if(0==display) { throw new NativeWindowException("null display"); } + closeDisplay = owner; } /** * @param display the Display connection * @param locker custom {@link javax.media.nativewindow.ToolkitLock}, eg to force null locking in NEWT + * @see DefaultGraphicsDevice#DefaultGraphicsDevice(String, String, int, long, ToolkitLock) */ - public X11GraphicsDevice(long display, int unitID, ToolkitLock locker) { - super(NativeWindowFactory.TYPE_X11, X11Util.XDisplayString(display), unitID, display, locker); + public X11GraphicsDevice(long display, int unitID, ToolkitLock locker, boolean owner) { + super(NativeWindowFactory.TYPE_X11, X11Lib.XDisplayString(display), unitID, display, locker); if(0==display) { throw new NativeWindowException("null display"); } + closeDisplay = owner; } public Object clone() { return super.clone(); } - public void setCloseDisplay(boolean close) { - closeDisplay = close; - if(DEBUG && close) { - System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.setCloseDisplay(true): "+this); - } - } public boolean close() { // FIXME: shall we respect the unitID ? if(closeDisplay && 0 != handle) { @@ -94,10 +96,8 @@ public class X11GraphicsDevice extends DefaultGraphicsDevice implements Cloneabl System.err.println(Thread.currentThread().getName() + " - X11GraphicsDevice.close(): "+this); } X11Util.closeDisplay(handle); - handle = 0; - return true; } - return false; + return super.close(); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java index ffe84cb6d..6473b9f67 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java +++ b/src/nativewindow/classes/javax/media/nativewindow/x11/X11GraphicsScreen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,6 +34,8 @@ package javax.media.nativewindow.x11; import javax.media.nativewindow.*; + +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; /** Encapsulates a screen index on X11 @@ -48,22 +51,22 @@ public class X11GraphicsScreen extends DefaultGraphicsScreen implements Cloneabl super(device, fetchScreen(device, screen)); } - public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx) { + public static AbstractGraphicsScreen createScreenDevice(long display, int screenIdx, boolean owner) { if(0==display) throw new NativeWindowException("display is null"); - return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT), screenIdx); + return new X11GraphicsScreen(new X11GraphicsDevice(display, AbstractGraphicsDevice.DEFAULT_UNIT, owner), screenIdx); } public long getDefaultVisualID() { // It still could be an AWT hold handle .. long display = getDevice().getHandle(); - int scrnIdx = X11Util.DefaultScreen(display); - return X11Util.DefaultVisualID(display, scrnIdx); + int scrnIdx = X11Lib.DefaultScreen(display); + return X11Lib.DefaultVisualID(display, scrnIdx); } private static int fetchScreen(X11GraphicsDevice device, int screen) { // It still could be an AWT hold handle .. long display = device.getHandle(); - if(X11Util.XineramaEnabled(display)) { + if(X11Lib.XineramaEnabled(display)) { screen = 0; // Xinerama -> 1 screen } return screen; diff --git a/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java new file mode 100644 index 000000000..ee3ab73ba --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/MutableGraphicsConfiguration.java @@ -0,0 +1,43 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.DefaultGraphicsConfiguration; + +public class MutableGraphicsConfiguration extends DefaultGraphicsConfiguration { + public MutableGraphicsConfiguration(AbstractGraphicsScreen screen, + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested) { + super(screen, capsChosen, capsRequested); + } + + public void setChosenCapabilities(CapabilitiesImmutable caps) { + super.setChosenCapabilities(caps); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java index 2b6d3c016..4cf8f448e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NWJNILibLoader.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NWJNILibLoader extends JNILibLoaderBase { @@ -40,9 +41,10 @@ public class NWJNILibLoader extends JNILibLoaderBase { public static void loadNativeWindow(final String ossuffix) { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { + Platform.initSingleton(); final String libName = "nativewindow_"+ossuffix ; if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - addNativeJarLibs(NWJNILibLoader.class, "jogl.all", "jogl-all", new String[] { "nativewindow" } ); + addNativeJarLibs(NWJNILibLoader.class, "jogl-all", new String[] { "nativewindow" } ); } loadLibrary(libName, false); return null; diff --git a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java index d34d4e58f..223078ebf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/NativeWindowFactoryImpl.java @@ -32,11 +32,15 @@ package jogamp.nativewindow; -import com.jogamp.common.os.Platform; -import com.jogamp.common.util.*; -import java.lang.reflect.*; +import java.lang.reflect.Constructor; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; -import javax.media.nativewindow.*; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; public class NativeWindowFactoryImpl extends NativeWindowFactory { private static final ToolkitLock nullToolkitLock = new NullToolkitLock(); @@ -44,13 +48,10 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { public static ToolkitLock getNullToolkitLock() { return nullToolkitLock; } - + // This subclass of NativeWindowFactory handles the case of // NativeWindows being passed in protected NativeWindow getNativeWindowImpl(Object winObj, AbstractGraphicsConfiguration config) throws IllegalArgumentException { - if (null == winObj) { - throw new IllegalArgumentException("winObj is null"); - } if (winObj instanceof NativeWindow) { // Use the NativeWindow directly return (NativeWindow) winObj; @@ -69,7 +70,7 @@ public class NativeWindowFactoryImpl extends NativeWindowFactory { "javax.media.nativewindow.NativeWindow or "+AWTComponentClassName); } - private Constructor nativeWindowConstructor = null; + private Constructor<?> nativeWindowConstructor = null; private NativeWindow getAWTNativeWindow(Object winObj, AbstractGraphicsConfiguration config) { if (nativeWindowConstructor == null) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java new file mode 100644 index 000000000..4877d5c4f --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/SurfaceUpdatedHelper.java @@ -0,0 +1,85 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import java.util.ArrayList; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; + +public class SurfaceUpdatedHelper implements SurfaceUpdatedListener { + private Object surfaceUpdatedListenersLock = new Object(); + private ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); + + // + // Management Utils + // + public int size() { return surfaceUpdatedListeners.size(); } + public SurfaceUpdatedListener get(int i) { return surfaceUpdatedListeners.get(i); } + + // + // Implementation of NativeSurface SurfaceUpdatedListener methods + // + + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + addSurfaceUpdatedListener(-1, l); + } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size(); + } + surfaceUpdatedListeners.add(index, l); + } + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + if (l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners.remove(l); + } + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { + SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); + l.surfaceUpdated(updater, ns, when); + } + } + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index 4c2b1c875..074fab563 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -33,7 +33,7 @@ import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.SurfaceChangeable; -public class WrappedSurface extends ProxySurface implements SurfaceChangeable { +public class WrappedSurface extends ProxySurface implements SurfaceChangeable { protected long surfaceHandle; public WrappedSurface(AbstractGraphicsConfiguration cfg) { @@ -65,6 +65,10 @@ public class WrappedSurface extends ProxySurface implements SurfaceChangeable { } public String toString() { - return "WrappedSurface[config " + config + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + ", size " + getWidth() + "x" + getHeight() + "]"; + return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+ + ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + + ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + + ", size " + getWidth() + "x" + getHeight() + + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java index 2c8538278..354bb83e3 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTJNILibLoader.java @@ -40,14 +40,15 @@ package jogamp.nativewindow.jawt; import javax.media.nativewindow.NativeWindowFactory; + import jogamp.nativewindow.NWJNILibLoader; import java.awt.Toolkit; import java.security.AccessController; import java.security.PrivilegedAction; -public class JAWTJNILibLoader extends NWJNILibLoader { - public static void loadAWTImpl() { +public class JAWTJNILibLoader extends NWJNILibLoader { + static { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { // Make sure that awt.dll is loaded before loading jawt.dll. Otherwise @@ -73,4 +74,9 @@ public class JAWTJNILibLoader extends NWJNILibLoader { } }); } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java index c1c97eece..21e9a3e09 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTUtil.java @@ -37,24 +37,28 @@ package jogamp.nativewindow.jawt; -import jogamp.nativewindow.*; import java.awt.EventQueue; - -import javax.media.nativewindow.*; - - import java.awt.GraphicsEnvironment; import java.awt.Toolkit; -import java.lang.reflect.*; -import java.security.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Map; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.Debug; + +import com.jogamp.common.os.Platform; + public class JAWTUtil { protected static final boolean DEBUG = Debug.debug("JAWT"); // See whether we're running in headless mode private static final boolean headlessMode; + private static final JAWT jawtLockObject; // Java2D magic .. private static final Method isQueueFlusherThread; @@ -75,31 +79,67 @@ public class JAWTUtil { boolean ok; } + /** + * Returns true if this platform's JAWT implementation supports + * or uses offscreen layer. + */ + public static boolean isOffscreenLayerSupported() { + return Platform.OS_TYPE == Platform.OSType.MACOS && + Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0; + } + + /** + * @param useOffscreenLayerIfAvailable + * @return + */ + public static JAWT getJAWT(boolean useOffscreenLayerIfAvailable) { + int jawt_version_flags = JAWTFactory.JAWT_VERSION_1_4; + if(useOffscreenLayerIfAvailable) { + switch(Platform.OS_TYPE) { + case MACOS: + if(Platform.OS_VERSION_NUMBER.compareTo(JAWT.JAWT_MacOSXCALayerMinVersion) >= 0) { + jawt_version_flags |= JAWT.JAWT_MACOSX_USE_CALAYER; + } + } + } + return JAWT.getJAWT(jawt_version_flags); + } + + public static boolean isJAWTUsingOffscreenLayer(JAWT jawt) { + return 0 != ( jawt.getCachedVersion() & JAWT.JAWT_MACOSX_USE_CALAYER ); + } + static { - JAWTJNILibLoader.loadAWTImpl(); + if(DEBUG) { + System.err.println("JAWTUtil initialization (JAWT/JNI/..."); + // Thread.dumpStack(); + } + JAWTJNILibLoader.initSingleton(); JAWTJNILibLoader.loadNativeWindow("awt"); headlessMode = GraphicsEnvironment.isHeadless(); - boolean ok = false; - Class jC = null; + Class<?> jC = null; Method m = null; if (!headlessMode) { + jawtLockObject = getJAWT(false); // don't care for offscreen layer here try { jC = Class.forName("jogamp.opengl.awt.Java2D"); m = jC.getMethod("isQueueFlusherThread", (Class[])null); ok = true; } catch (Exception e) { } + } else { + jawtLockObject = null; // headless ! } isQueueFlusherThread = m; j2dExist = ok; - PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction() { + PrivilegedDataBlob1 pdb1 = (PrivilegedDataBlob1) AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { PrivilegedDataBlob1 d = new PrivilegedDataBlob1(); try { - final Class sunToolkitClass = Class.forName("sun.awt.SunToolkit"); + final Class<?> sunToolkitClass = Class.forName("sun.awt.SunToolkit"); d.sunToolkitAWTLockMethod = sunToolkitClass.getDeclaredMethod("awtLock", new Class[]{}); d.sunToolkitAWTLockMethod.setAccessible(true); d.sunToolkitAWTUnlockMethod = sunToolkitClass.getDeclaredMethod("awtUnlock", new Class[]{}); @@ -129,21 +169,21 @@ public class JAWTUtil { jawtToolkitLock = new JAWTToolkitLock(); // trigger native AWT toolkit / properties initialization - Map desktophints = null; + Map<?,?> desktophints = null; try { if(EventQueue.isDispatchThread()) { - desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); } else { - final ArrayList desktophintsBucket = new ArrayList(1); + final ArrayList<Map<?,?>> desktophintsBucket = new ArrayList<Map<?,?>>(1); EventQueue.invokeAndWait(new Runnable() { public void run() { - Map _desktophints = (Map)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); + Map<?,?> _desktophints = (Map<?,?>)(Toolkit.getDefaultToolkit().getDesktopProperty("awt.font.desktophints")); if(null!=_desktophints) { desktophintsBucket.add(_desktophints); } } }); - desktophints = ( desktophintsBucket.size() > 0 ) ? (Map)desktophintsBucket.get(0) : null ; + desktophints = ( desktophintsBucket.size() > 0 ) ? desktophintsBucket.get(0) : null ; } } catch (InterruptedException ex) { ex.printStackTrace(); @@ -189,7 +229,7 @@ public class JAWTUtil { * JAWT's native Lock() function calls SunToolkit.awtLock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtLock() { + private static void awtLock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTLockMethod.invoke(null, (Object[])null); @@ -197,7 +237,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtLock failed", e); } } else { - JAWT.getJAWT().Lock(); + jawtLockObject.Lock(); } } @@ -207,7 +247,7 @@ public class JAWTUtil { * JAWT's native Unlock() function calls SunToolkit.awtUnlock(), * which just uses AWT's global ReentrantLock.<br> */ - public static void awtUnlock() { + private static void awtUnlock() { if(hasSunToolkitAWTLock) { try { sunToolkitAWTUnlockMethod.invoke(null, (Object[])null); @@ -215,7 +255,7 @@ public class JAWTUtil { throw new NativeWindowException("SunToolkit.awtUnlock failed", e); } } else { - JAWT.getJAWT().Unlock(); + jawtLockObject.Unlock(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java index 2c80392ad..be697b3e0 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/JAWTWindow.java @@ -41,73 +41,190 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; import java.awt.Component; -import java.awt.Window; +import java.awt.Container; +import java.applet.Applet; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.OffscreenLayerOption; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; import javax.media.nativewindow.util.RectangleImmutable; -public abstract class JAWTWindow implements NativeWindow { +import jogamp.nativewindow.SurfaceUpdatedHelper; + +public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, OffscreenLayerOption { protected static final boolean DEBUG = JAWTUtil.DEBUG; + // user properties + protected boolean shallUseOffscreenLayer = false; + // lifetime: forever protected Component component; - protected AbstractGraphicsConfiguration config; + private AWTGraphicsConfiguration config; // control access due to delegation + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - // lifetime: valid after lock, forever until invalidate + // lifetime: valid after lock but may change with each 1st lock, purges after invalidate + private boolean isApplet; + private JAWT jawt; + private boolean isOffscreenLayerSurface; protected long drawable; protected Rectangle bounds; - - public JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { + protected Insets insets; + + /** + * Constructed by {@link jogamp.nativewindow.NativeWindowFactoryImpl#getNativeWindow(Object, AbstractGraphicsConfiguration)} + * via this platform's specialization (X11, OSX, Windows, ..). + * + * @param comp + * @param config + */ + protected JAWTWindow(Object comp, AbstractGraphicsConfiguration config) { if (config == null) { throw new NativeWindowException("Error: AbstractGraphicsConfiguration is null"); } - this.config = config; + if(! ( config instanceof AWTGraphicsConfiguration ) ) { + throw new NativeWindowException("Error: AbstractGraphicsConfiguration is not an AWTGraphicsConfiguration: "+config); + } + this.config = (AWTGraphicsConfiguration) config; init((Component)comp); } private void init(Component windowObject) throws NativeWindowException { invalidate(); this.component = windowObject; - validateNative(); + this.isApplet = false; } - protected abstract void validateNative() throws NativeWindowException; - + + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + protected synchronized void invalidate() { - component = null; + invalidateNative(); + jawt = null; + isOffscreenLayerSurface = false; drawable= 0; bounds = new Rectangle(); + insets = new Insets(); } + protected abstract void invalidateNative(); protected final void updateBounds(JAWT_Rectangle jawtBounds) { bounds.setX(jawtBounds.getX()); bounds.setY(jawtBounds.getY()); bounds.setWidth(jawtBounds.getWidth()); bounds.setHeight(jawtBounds.getHeight()); + + if(component instanceof Container) { + java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.setLeftWidth(contInsets.left); + insets.setRightWidth(contInsets.right); + insets.setTopHeight(contInsets.top); + insets.setBottomHeight(contInsets.bottom); + } } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ public final RectangleImmutable getBounds() { return bounds; } - public final InsetsImmutable getInsets() { return Insets.getZero(); } + public final InsetsImmutable getInsets() { return insets; } public final Component getAWTComponent() { return component; } + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #lockSurface()}. + */ + public final boolean isApplet() { + return isApplet; + } + /** Returns the underlying JAWT instance created @ {@link #lockSurface()}. */ + public final JAWT getJAWT() { + return jawt; + } + + /** + * {@inheritDoc} + */ + public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new NativeWindowException("Not an offscreen layer surface"); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + try { + if(DEBUG) { + System.err.println("JAWTWindow.attachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + attachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void attachSurfaceLayerImpl(final long layerHandle); + + /** + * {@inheritDoc} + */ + public final void detachSurfaceLayer(final long layerHandle) throws NativeWindowException { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("Not an offscreen layer surface"); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock (offscreen layer): "+this); + } + try { + if(DEBUG) { + System.err.println("JAWTWindow.detachSurfaceHandle(): 0x"+Long.toHexString(layerHandle)); + } + detachSurfaceLayerImpl(layerHandle); + } finally { + unlockSurface(); + } + } + protected abstract void detachSurfaceLayerImpl(final long layerHandle); + // // SurfaceUpdateListener // - public final void surfaceUpdated(Object updater, NativeSurface ns, long when) { - // nop + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } // // NativeSurface @@ -115,6 +232,24 @@ public abstract class JAWTWindow implements NativeWindow { private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private void determineIfApplet() { + Component c = component; + while(!isApplet && null != c) { + isApplet = c instanceof Applet; + c = c.getParent(); + } + } + + /** + * If JAWT offscreen layer is supported, + * implementation shall respect {@link #getShallUseOffscreenLayer()} + * and may respect {@link #isApplet()}. + * + * @return The JAWT instance reflecting offscreen layer support, etc. + * + * @throws NativeWindowException + */ + protected abstract JAWT fetchJAWTImpl() throws NativeWindowException; protected abstract int lockSurfaceImpl() throws NativeWindowException; public final int lockSurface() throws NativeWindowException { @@ -122,10 +257,13 @@ public abstract class JAWTWindow implements NativeWindow { int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? if ( LOCK_SURFACE_NOT_READY == res ) { + determineIfApplet(); try { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { + jawt = fetchJAWTImpl(); + isOffscreenLayerSurface = JAWTUtil.isJAWTUsingOffscreenLayer(jawt); res = lockSurfaceImpl(); } finally { if (LOCK_SURFACE_NOT_READY >= res) { @@ -147,7 +285,7 @@ public abstract class JAWTWindow implements NativeWindow { surfaceLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -169,36 +307,35 @@ public abstract class JAWTWindow implements NativeWindow { return surfaceLock.getOwner(); } - public final boolean surfaceSwap() { + public boolean surfaceSwap() { return false; } - public final void surfaceUpdated(Object updater, NativeWindow window, long when) { } - - public final long getSurfaceHandle() { + public long getSurfaceHandle() { return drawable; } - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + + public final AWTGraphicsConfiguration getPrivateGraphicsConfiguration() { return config; } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } public final long getDisplayHandle() { - return config.getScreen().getDevice().getHandle(); + return getGraphicsConfiguration().getScreen().getDevice().getHandle(); } public final int getScreenIndex() { - return config.getScreen().getIndex(); - } - - public final void setSize(int width, int height) { - component.setSize(width, height); + return getGraphicsConfiguration().getScreen().getIndex(); } - public final int getWidth() { + public int getWidth() { return component.getWidth(); } - public final int getHeight() { + public int getHeight() { return component.getHeight(); } @@ -207,12 +344,8 @@ public abstract class JAWTWindow implements NativeWindow { // public synchronized void destroy() { - if(null!=component) { - if(component instanceof Window) { - ((Window)component).dispose(); - } - } - invalidate(); + invalidate(); + component = null; // don't dispose the AWT component, since we are merely an immutable uplink } public final NativeWindow getParent() { @@ -222,7 +355,7 @@ public abstract class JAWTWindow implements NativeWindow { public long getWindowHandle() { return drawable; } - + public final int getX() { return component.getX(); } @@ -230,52 +363,94 @@ public abstract class JAWTWindow implements NativeWindow { public final int getY() { return component.getY(); } - + + /** + * {@inheritDoc} + * + * <p> + * This JAWT default implementation is currently still using + * a blocking implementation. It first attempts to retrieve the location + * via a native implementation. If this fails, it tries the blocking AWT implementation. + * If the latter fails due to an external AWT tree-lock, the non block + * implementation {@link #getLocationOnScreenNonBlocking(Point, Component)} is being used. + * The latter simply traverse up to the AWT component tree and sums the rel. position. + * We have to determine whether the latter is good enough for all cases, + * currently only OS X utilizes the non blocking method per default. + * </p> + */ public Point getLocationOnScreen(Point storage) { + Point los = getLocationOnScreenNative(storage); + if(null == los) { + if(!Thread.holdsLock(component.getTreeLock())) { + // avoid deadlock .. + if(DEBUG) { + System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this); + Thread.dumpStack(); + } + return getLocationOnScreenNonBlocking(storage, component); + } + java.awt.Point awtLOS = component.getLocationOnScreen(); + if(null!=storage) { + los = storage.translate(awtLOS.x, awtLOS.y); + } else { + los = new Point(awtLOS.x, awtLOS.y); + } + } + return los; + } + + protected Point getLocationOnScreenNative(Point storage) { int lockRes = lockSurface(); if(LOCK_SURFACE_NOT_READY == lockRes) { - // FIXME: Shall we deal with already locked or unrealized surfaces ? - System.err.println("Warning: JAWT Lock couldn't be acquired!"); - Thread.dumpStack(); + if(DEBUG) { + System.err.println("Warning: JAWT Lock couldn't be acquired: "+this); + Thread.dumpStack(); + } return null; } try { - Point d = getLocationOnScreenImpl(0, 0); + Point d = getLocationOnScreenNativeImpl(0, 0); if(null!=d) { if(null!=storage) { storage.translate(d.getX(),d.getY()); return storage; } - return d; - } - // fall through intended .. - if(!Thread.holdsLock(component.getTreeLock())) { - // FIXME: Verify if this check is still required! - System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock!"); - Thread.dumpStack(); - return null; // avoid deadlock .. } - java.awt.Point awtLOS = component.getLocationOnScreen(); - int dx = (int) ( awtLOS.getX() + .5 ) ; - int dy = (int) ( awtLOS.getY() + .5 ) ; - if(null!=storage) { - return storage.translate(dx, dy); - } - return new Point(dx, dy); + return d; } finally { unlockSurface(); + } + } + protected abstract Point getLocationOnScreenNativeImpl(int x, int y); + + protected static Point getLocationOnScreenNonBlocking(Point storage, Component comp) { + int x = 0; + int y = 0; + while(null != comp) { + x += comp.getX(); + y += comp.getY(); + comp = comp.getParent(); } + if(null!=storage) { + storage.translate(x, y); + return storage; + } + return new Point(x, y); } - protected abstract Point getLocationOnScreenImpl(int x, int y); - - @Override + + public boolean hasFocus() { + return component.hasFocus(); + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("JAWT-Window["+ "windowHandle 0x"+Long.toHexString(getWindowHandle())+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", bounds "+bounds); + ", bounds "+bounds+", insets "+insets+ + ", shallUseOffscreenLayer "+shallUseOffscreenLayer+", isOffscreenLayerSurface "+isOffscreenLayerSurface); if(null!=component) { sb.append(", pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ ", visible "+component.isVisible()); @@ -283,8 +458,9 @@ public abstract class JAWTWindow implements NativeWindow { sb.append(", component NULL"); } sb.append(", lockedExt "+isSurfaceLockedByOtherThread()+ - ",\n\tconfig "+config+ - ",\n\tawtComponent "+getAWTComponent()+"]"); + ",\n\tconfig "+getPrivateGraphicsConfiguration()+ + ",\n\tawtComponent "+getAWTComponent()+ + ",\n\tsurfaceLock "+surfaceLock+"]"); return sb.toString(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index d4f6a95d4..ab2986fbe 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -40,38 +40,94 @@ package jogamp.nativewindow.jawt.macosx; -import java.awt.Component; +import java.nio.Buffer; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.SurfaceChangeable; import javax.media.nativewindow.util.Point; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -// import jogamp.nativewindow.macosx.OSXUtil; - -public class MacOSXJAWTWindow extends JAWTWindow { +import jogamp.nativewindow.macosx.OSXUtil; +public class MacOSXJAWTWindow extends JAWTWindow implements SurfaceChangeable { public MacOSXJAWTWindow(Object comp, AbstractGraphicsConfiguration config) { super(comp, config); + if(DEBUG) { + dumpInfo(); + } } - protected void validateNative() throws NativeWindowException { + protected void invalidateNative() { + surfaceHandle=0; + if(isOffscreenLayerSurfaceEnabled()) { + if(0 != drawable) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + } + } } + protected void attachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.AddCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + protected void detachSurfaceLayerImpl(final long layerHandle) { + OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); + } + + public long getSurfaceHandle() { + return isOffscreenLayerSurfaceEnabled() ? surfaceHandle : super.getSurfaceHandle() ; + } + + public void setSurfaceHandle(long surfaceHandle) { + if( !isOffscreenLayerSurfaceEnabled() ) { + throw new java.lang.UnsupportedOperationException("Not using CALAYER"); + } + if(DEBUG) { + System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSet &= 0 != surfaceHandle; // reset ssc flag if NULL surfaceHandle, ie. back to JAWT + this.surfaceHandle = surfaceHandle; + } + + public void surfaceSizeChanged(int width, int height) { + sscSet = true; + sscWidth = width; + sscHeight = height; + } + + public int getWidth() { + return sscSet ? sscWidth : super.getWidth(); + } + + public int getHeight() { + return sscSet ? sscHeight: super.getHeight(); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + // use offscreen if supported and [ applet or requested ] + return JAWTUtil.getJAWT(getShallUseOffscreenLayer() || isApplet()); + } protected int lockSurfaceImpl() throws NativeWindowException { - int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); - if (ds == null) { - // Widget not yet realized - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + int ret = NativeWindow.LOCK_SURFACE_NOT_READY; + if(null == ds) { + ds = getJAWT().GetDrawingSurface(component); + if (ds == null) { + // Widget not yet realized + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } } int res = ds.Lock(); dsLocked = ( 0 == ( res & JAWTFactory.JAWT_LOCK_ERROR ) ) ; @@ -87,37 +143,86 @@ public class MacOSXJAWTWindow extends JAWTWindow { if ((res & JAWTFactory.JAWT_LOCK_SURFACE_CHANGED) != 0) { ret = NativeWindow.LOCK_SURFACE_CHANGED; } - if (firstLock) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - public Object run() { - dsi = ds.GetDrawingSurfaceInfo(); - return null; - } - }); - } else { - dsi = ds.GetDrawingSurfaceInfo(); + if(null == dsi) { + if (firstLock) { + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + dsi = ds.GetDrawingSurfaceInfo(); + return null; + } + }); + } else { + dsi = ds.GetDrawingSurfaceInfo(); + } + if (dsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } } - if (dsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + updateBounds(dsi.getBounds()); + if (DEBUG && firstLock ) { + dumpInfo(); } firstLock = false; - macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(); - if (macosxdsi == null) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; - } - drawable = macosxdsi.getCocoaViewRef(); - - if (drawable == 0) { - unlockSurfaceImpl(); - return NativeWindow.LOCK_SURFACE_NOT_READY; + if( !isOffscreenLayerSurfaceEnabled() ) { + macosxdsi = (JAWT_MacOSXDrawingSurfaceInfo) dsi.platformInfo(getJAWT()); + if (macosxdsi == null) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } + drawable = macosxdsi.getCocoaViewRef(); + + if (drawable == 0) { + unlockSurfaceImpl(); + return NativeWindow.LOCK_SURFACE_NOT_READY; + } else { + ret = NativeWindow.LOCK_SUCCESS; + } } else { - updateBounds(dsi.getBounds()); + /** + * Only create a fake invisible NSWindow for the drawable handle + * to please frameworks requiring such (eg. NEWT). + * + * The actual surface/ca-layer shall be created/attached + * by the upper framework (JOGL) since they require more information. + */ + if(0 == drawable) { + drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight()); + if(0 == drawable) { + unlockSurfaceImpl(); + throw new NativeWindowException("Unable to created dummy NSWindow (layered case)"); + } + // fix caps reflecting offscreen! + Capabilities caps = (Capabilities) getPrivateGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + getPrivateGraphicsConfiguration().setChosenCapabilities(caps); + caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + } + if(0 == rootSurfaceLayerHandle) { + rootSurfaceLayerHandle = OSXUtil.CreateCALayer(); + if(0 == rootSurfaceLayerHandle) { + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not create root CALayer: "+this); + } + if(!AttachJAWTSurfaceLayer(dsi, rootSurfaceLayerHandle)) { + OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); + rootSurfaceLayerHandle = 0; + OSXUtil.DestroyNSWindow(drawable); + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException("Could not attach JAWT surfaceLayerHandle: "+this); + } + } + ret = NativeWindow.LOCK_SUCCESS; } + return ret; } - + protected void unlockSurfaceImpl() throws NativeWindowException { if(null!=ds) { if (null!=dsi) { @@ -126,30 +231,65 @@ public class MacOSXJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; - macosxdsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - Component c = component; - while(null != c) { - x += c.getX(); - y += c.getY(); - c = c.getParent(); + private void dumpInfo() { + System.err.println("MaxOSXJAWTWindow: 0x"+Integer.toHexString(this.hashCode())+" - thread: "+Thread.currentThread().getName()); + if(null != getJAWT()) { + System.err.println("JAWT version: 0x"+Integer.toHexString(getJAWT().getCachedVersion())+ + ", CA_LAYER: "+ JAWTUtil.isJAWTUsingOffscreenLayer(getJAWT())+ + ", isLayeredSurface "+isOffscreenLayerSurfaceEnabled()+", bounds "+bounds+", insets "+insets); + } else { + System.err.println("JAWT n/a, bounds "+bounds+", insets "+insets); } - // return OSXUtil.GetLocationOnScreen(getWindowHandle(), x, y); - return new Point(x, y); + // Thread.dumpStack(); } + + /** + * {@inheritDoc} + * <p> + * On OS X locking the surface at this point (ie after creation and for location validation) + * is 'tricky' since the JVM traverses through many threads and crashes at: + * lockSurfaceImpl() { + * .. + * ds = getJAWT().GetDrawingSurface(component); + * due to a SIGSEGV. + * + * Hence we have some threading / sync issues with the native JAWT implementation. + * </p> + */ + @Override + public Point getLocationOnScreen(Point storage) { + return getLocationOnScreenNonBlocking(storage, component); + } + protected Point getLocationOnScreenNativeImpl(final int x0, final int y0) { return null; } + private static boolean AttachJAWTSurfaceLayer(JAWT_DrawingSurfaceInfo dsi, long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + return AttachJAWTSurfaceLayer0(dsi.getBuffer(), caLayer); + } + + private static native boolean AttachJAWTSurfaceLayer0(Buffer jawtDrawingSurfaceInfoBuffer, long caLayer); + // Variables for lockSurface/unlockSurface private JAWT_DrawingSurface ds; private boolean dsLocked; private JAWT_DrawingSurfaceInfo dsi; + private JAWT_MacOSXDrawingSurfaceInfo macosxdsi; - + + private long rootSurfaceLayerHandle = 0; // is autoreleased, once it is attached to the JAWT_SurfaceLayer + + private long surfaceHandle = 0; + private int sscWidth, sscHeight; + private boolean sscSet = false; + // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java index 5ad22807f..bf5c18eaf 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/Win32SunJDKReflection.java @@ -95,7 +95,7 @@ public class Win32SunJDKReflection { public static int graphicsConfigurationGetPixelFormatID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetPixelFormatID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java index 982b94888..786682b17 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/windows/WindowsJAWTWindow.java @@ -47,10 +47,11 @@ import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; public class WindowsJAWTWindow extends JAWTWindow { @@ -58,18 +59,24 @@ public class WindowsJAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - } - - @Override - protected synchronized void invalidate() { - super.invalidate(); + protected void invalidateNative() { windowHandle = 0; } + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + protected void detachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -94,7 +101,8 @@ public class WindowsJAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + win32dsi = (JAWT_Win32DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (win32dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -104,14 +112,12 @@ public class WindowsJAWTWindow extends JAWTWindow { if (windowHandle == 0 || drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } protected void unlockSurfaceImpl() throws NativeWindowException { - long startTime = 0; + drawable = 0; // invalid HDC if(null!=ds) { if (null!=dsi) { ds.FreeDrawingSurfaceInfo(dsi); @@ -119,7 +125,7 @@ public class WindowsJAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; @@ -131,8 +137,8 @@ public class WindowsJAWTWindow extends JAWTWindow { return windowHandle; } - protected Point getLocationOnScreenImpl(int x, int y) { - return GDI.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java index 5d4fa0dad..743d371b7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTToolkitLock.java @@ -28,9 +28,13 @@ package jogamp.nativewindow.jawt.x11; import jogamp.nativewindow.jawt.*; +import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import javax.media.nativewindow.ToolkitLock; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + /** * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} * utilizing JAWT's AWT lock via {@link JAWTUtil#lockToolkit()} and {@link X11Util#XLockDisplay(long)}. @@ -41,20 +45,32 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11JAWTToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11JAWTToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock()"); } + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.lock() - native: "+(null==lock)); } JAWTUtil.lockToolkit(); - X11Util.XLockDisplay(displayHandle); + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11JAWTToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } JAWTUtil.unlockToolkit(); } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java index 2319d6269..35dc2343f 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11JAWTWindow.java @@ -38,20 +38,17 @@ package jogamp.nativewindow.jawt.x11; import javax.media.nativewindow.AbstractGraphicsConfiguration; -import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; -import javax.media.nativewindow.awt.AWTGraphicsDevice; import javax.media.nativewindow.util.Point; import jogamp.nativewindow.jawt.JAWT; import jogamp.nativewindow.jawt.JAWTFactory; +import jogamp.nativewindow.jawt.JAWTUtil; import jogamp.nativewindow.jawt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT_DrawingSurface; import jogamp.nativewindow.jawt.JAWT_DrawingSurfaceInfo; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.x11.X11Lib; public class X11JAWTWindow extends JAWTWindow { @@ -59,36 +56,22 @@ public class X11JAWTWindow extends JAWTWindow { super(comp, config); } - protected void validateNative() throws NativeWindowException { - AWTGraphicsDevice awtDevice = (AWTGraphicsDevice) config.getScreen().getDevice(); + protected void invalidateNative() { } - if(awtDevice.getHandle() != 0) { - // subtype and handle set already, done - return; - } - - long displayHandle = 0; - - // first try a pre-existing attached native configuration, ie native X11GraphicsDevice - AbstractGraphicsConfiguration aconfig = (null!=config) ? config.getNativeGraphicsConfiguration() : null; - AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; - AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; // X11GraphicsDevice - if(null!=adevice) { - displayHandle = adevice.getHandle(); - } - - if(0 == displayHandle) { - displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(awtDevice.getGraphicsDevice()); - } - if(0==displayHandle) { - throw new InternalError("X11JAWTWindow: No X11 Display handle available"); - } - awtDevice.setSubType(NativeWindowFactory.TYPE_X11, displayHandle); + protected void attachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); } - + protected void detachSurfaceLayerImpl(final long layerHandle) { + throw new UnsupportedOperationException("offscreen layer not supported"); + } + + protected JAWT fetchJAWTImpl() throws NativeWindowException { + return JAWTUtil.getJAWT(false); // no offscreen + } + protected int lockSurfaceImpl() throws NativeWindowException { int ret = NativeWindow.LOCK_SUCCESS; - ds = JAWT.getJAWT().GetDrawingSurface(component); + ds = getJAWT().GetDrawingSurface(component); if (ds == null) { // Widget not yet realized unlockSurfaceImpl(); @@ -113,7 +96,8 @@ public class X11JAWTWindow extends JAWTWindow { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; } - x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(); + updateBounds(dsi.getBounds()); + x11dsi = (JAWT_X11DrawingSurfaceInfo) dsi.platformInfo(getJAWT()); if (x11dsi == null) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; @@ -122,8 +106,6 @@ public class X11JAWTWindow extends JAWTWindow { if (drawable == 0) { unlockSurfaceImpl(); return LOCK_SURFACE_NOT_READY; - } else { - updateBounds(dsi.getBounds()); } return ret; } @@ -136,15 +118,15 @@ public class X11JAWTWindow extends JAWTWindow { if (dsLocked) { ds.Unlock(); } - JAWT.getJAWT().FreeDrawingSurface(ds); + getJAWT().FreeDrawingSurface(ds); } ds = null; dsi = null; x11dsi = null; } - protected Point getLocationOnScreenImpl(int x, int y) { - return X11Util.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + protected Point getLocationOnScreenNativeImpl(int x, int y) { + return X11Lib.GetRelativeLocation( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } // Variables for lockSurface/unlockSurface diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java index b576b0c6b..08d471448 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/x11/X11SunJDKReflection.java @@ -55,14 +55,14 @@ import javax.media.nativewindow.awt.AWTGraphicsConfiguration; the purposes of correctly enumerating the available visuals. */ public class X11SunJDKReflection { - private static Class x11GraphicsDeviceClass; - private static Method x11GraphicsDeviceGetDisplayMethod; - private static Class x11GraphicsConfigClass; - private static Method x11GraphicsConfigGetVisualMethod; - private static boolean initted; + private static Class<?> x11GraphicsDeviceClass; + private static Method x11GraphicsDeviceGetDisplayMethod; + private static Class<?> x11GraphicsConfigClass; + private static Method x11GraphicsConfigGetVisualMethod; + private static boolean initialized; static { - AccessController.doPrivileged(new PrivilegedAction() { + AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { try { x11GraphicsDeviceClass = Class.forName("sun.awt.X11GraphicsDevice"); @@ -72,7 +72,7 @@ public class X11SunJDKReflection { x11GraphicsConfigClass = Class.forName("sun.awt.X11GraphicsConfig"); x11GraphicsConfigGetVisualMethod = x11GraphicsConfigClass.getDeclaredMethod("getVisual", new Class[] {}); x11GraphicsConfigGetVisualMethod.setAccessible(true); - initted = true; + initialized = true; } catch (Exception e) { // Either not a Sun JDK or the interfaces have changed since 1.4.2 / 1.5 } @@ -82,7 +82,7 @@ public class X11SunJDKReflection { } public static long graphicsDeviceGetDisplay(GraphicsDevice device) { - if (!initted) { + if (!initialized) { return 0; } @@ -96,7 +96,7 @@ public class X11SunJDKReflection { public static int graphicsConfigurationGetVisualID(AbstractGraphicsConfiguration config) { try { if (config instanceof AWTGraphicsConfiguration) { - return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getGraphicsConfiguration()); + return graphicsConfigurationGetVisualID(((AWTGraphicsConfiguration) config).getAWTGraphicsConfiguration()); } return 0; } catch (Exception e) { @@ -105,7 +105,7 @@ public class X11SunJDKReflection { } public static int graphicsConfigurationGetVisualID(GraphicsConfiguration config) { - if (!initted) { + if (!initialized) { return 0; } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index cd558c05d..5b1e4b0a7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package jogamp.nativewindow.macosx; import javax.media.nativewindow.NativeWindowException; @@ -34,6 +61,42 @@ public class OSXUtil { return (Point) GetLocationOnScreen0(windowOrView, src_x, src_y); } + public static long CreateNSView(int x, int y, int width, int height) { + return CreateNSView0(x, y, width, height); + } + public static void DestroyNSView(long nsView) { + DestroyNSView0(nsView); + } + + public static long CreateNSWindow(int x, int y, int width, int height) { + return CreateNSWindow0(x, y, width, height); + } + public static void DestroyNSWindow(long nsWindow) { + DestroyNSWindow0(nsWindow); + } + + public static long CreateCALayer() { + return CreateCALayer0(); + } + public static void AddCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + AddCASublayer0(rootCALayer, subCALayer); + } + public static void RemoveCASublayer(long rootCALayer, long subCALayer) { + if(0==rootCALayer || 0==subCALayer) { + throw new IllegalArgumentException("rootCALayer 0x"+Long.toHexString(rootCALayer)+", subCALayer 0x"+Long.toHexString(subCALayer)); + } + RemoveCASublayer0(rootCALayer, subCALayer); + } + public static void DestroyCALayer(long caLayer) { + if(0==caLayer) { + throw new IllegalArgumentException("caLayer 0x"+Long.toHexString(caLayer)); + } + DestroyCALayer0(caLayer); + } + public static void RunOnMainThread(boolean waitUntilDone, Runnable runnable) { if(IsMainThread0()) { runnable.run(); // don't leave the JVM @@ -48,6 +111,14 @@ public class OSXUtil { private static native boolean initIDs0(); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); + private static native long CreateNSView0(int x, int y, int width, int height); + private static native void DestroyNSView0(long nsView); + private static native long CreateNSWindow0(int x, int y, int width, int height); + private static native void DestroyNSWindow0(long nsWindow); + private static native long CreateCALayer0(); + private static native void AddCASublayer0(long rootCALayer, long subCALayer); + private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); + private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable); private static native boolean IsMainThread0(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java index 1ad909897..aab1556da 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java +++ b/src/nativewindow/classes/jogamp/nativewindow/swt/SWTAccessor.java @@ -202,7 +202,9 @@ public class SWTAccessor { if( null != OS_gtk_class ) { long widgedHandle = callStaticMethodL2L(OS_GTK_WIDGET_WINDOW, handle); long displayHandle = callStaticMethodL2L(OS_gdk_x11_drawable_get_xdisplay, widgedHandle); - return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT); + // FIXME: May think about creating a private non-shared X11 Display handle, like we use to for AWT + // to avoid locking problems ! + return new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, false); } if( NativeWindowFactory.TYPE_WINDOWS == NativeWindowFactory.getNativeWindowType(false) ) { return new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index 68cf8af45..c8ed8e070 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -61,14 +61,22 @@ public class GDISurface extends ProxySurface { throw new InternalError("surface not released"); } surfaceHandle = GDI.GetDC(windowHandle); + /* + if(0 == surfaceHandle) { + System.err.println("****** DC Acquire: 0x"+Long.toHexString(windowHandle)+", isWindow "+GDI.IsWindow(windowHandle)+", isVisible "+GDI.IsWindowVisible(windowHandle)+", GDI LastError: "+GDI.GetLastError()+", 0x"+Long.toHexString(surfaceHandle)+", GDI LastError: "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); + Thread.dumpStack(); + } + */ return (0 != surfaceHandle) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; } protected void unlockSurfaceImpl() { if (0 == surfaceHandle) { - throw new InternalError("surface not acquired"); + throw new InternalError("surface not acquired: "+this+", thread: "+Thread.currentThread().getName()); + } + if(0 == GDI.ReleaseDC(windowHandle, surfaceHandle)) { + throw new NativeWindowException("DC not released: "+this+", isWindow "+GDI.IsWindow(windowHandle)+", werr "+GDI.GetLastError()+", thread: "+Thread.currentThread().getName()); } - GDI.ReleaseDC(windowHandle, surfaceHandle); surfaceHandle=0; } @@ -77,11 +85,12 @@ public class GDISurface extends ProxySurface { } public String toString() { - return "GDISurface[config "+config+ + return "GDISurface[config "+getPrivateGraphicsConfiguration()+ ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+ ", windowHandle 0x"+Long.toHexString(windowHandle)+ ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", size "+getWidth()+"x"+getHeight()+"]"; + ", size "+getWidth()+"x"+getHeight()+ + ", surfaceLock "+surfaceLock+"]"; } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java new file mode 100644 index 000000000..be531d9ee --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -0,0 +1,101 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.nativewindow.windows; + +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.NativeWindowException; + +import jogamp.nativewindow.NWJNILibLoader; +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.x11.X11Util; + +public class GDIUtil { + private static final boolean DEBUG = Debug.debug("GDIUtil"); + + private static final String dummyWindowClassNameBase = "_dummyWindow_clazz" ; + private static RegisteredClassFactory dummyWindowClassFactory; + private static boolean isInit = false; + + public static synchronized void initSingleton(boolean firstX11ActionOnProcess) { + if(!isInit) { + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("win32"); + + if( !initIDs0() ) { + throw new NativeWindowException("GDI: Could not initialized native stub"); + } + + if(DEBUG) { + System.out.println("GDI.isFirstX11ActionOnProcess: "+firstX11ActionOnProcess); + } + + dummyWindowClassFactory = new RegisteredClassFactory(dummyWindowClassNameBase, getDummyWndProc0()); + } + } + } + } + + public static boolean requiresToolkitLock() { return false; } + + private static RegisteredClass dummyWindowClass = null; + private static Object dummyWindowSync = new Object(); + + public static long CreateDummyWindow(int x, int y, int width, int height) { + synchronized(dummyWindowSync) { + dummyWindowClass = dummyWindowClassFactory.getSharedClass(); + return CreateDummyWindow0(dummyWindowClass.getHandle(), dummyWindowClass.getName(), dummyWindowClass.getName(), x, y, width, height); + } + } + + public static boolean DestroyDummyWindow(long hwnd) { + boolean res; + synchronized(dummyWindowSync) { + if( null == dummyWindowClass ) { + throw new InternalError("GDI Error ("+dummyWindowClassFactory.getSharedRefCount()+"): SharedClass is null"); + } + res = GDI.DestroyWindow(hwnd); + dummyWindowClassFactory.releaseSharedClass(); + } + return res; + } + + public static Point GetRelativeLocation(long src_win, long dest_win, int src_x, int src_y) { + return (Point) GetRelativeLocation0(src_win, dest_win, src_x, src_y); + } + + public static native boolean CreateWindowClass(long hInstance, String clazzName, long wndProc); + public static native boolean DestroyWindowClass(long hInstance, String className); + + private static native boolean initIDs0(); + private static native long getDummyWndProc0(); + private static native Object GetRelativeLocation0(long src_win, long dest_win, int src_x, int src_y); + + static native long CreateDummyWindow0(long hInstance, String className, String windowName, int x, int y, int width, int height); +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java index 15e0a67cb..00bedfc8e 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/RegisteredClassFactory.java @@ -34,34 +34,44 @@ import javax.media.nativewindow.NativeWindowException; public class RegisteredClassFactory { static final boolean DEBUG = Debug.debug("RegisteredClass"); - private static ArrayList sharedClasses = new ArrayList(); + private static ArrayList<RegisteredClassFactory> registeredFactories = new ArrayList<RegisteredClassFactory>(); + private String classBaseName; - long wndProc; + private long wndProc; private RegisteredClass sharedClass = null; private int classIter = 0; private int sharedRefCount = 0; - private Object sync = new Object(); + private final Object sync = new Object(); /** - * Intended for a JVM shutdown hook, hence little synchronization + * Release the {@link RegisteredClass} of all {@link RegisteredClassFactory}. */ public static void shutdownSharedClasses() { - synchronized(sharedClasses) { - for(int i=0; i<sharedClasses.size(); i++) { - RegisteredClass sc = (RegisteredClass) sharedClasses.get(i); - GDI.DestroyWindowClass(sc.getHandle(), sc.getName()); - if(DEBUG) { - System.err.println("RegisteredClassFactory shutdownSharedClasses "+i+"/"+sharedClasses.size()+": "+sc); + synchronized(registeredFactories) { + for(int j=0; j<registeredFactories.size(); j++) { + final RegisteredClassFactory rcf = registeredFactories.get(j); + synchronized(rcf.sync) { + if(null != rcf.sharedClass) { + GDIUtil.DestroyWindowClass(rcf.sharedClass.getHandle(), rcf.sharedClass.getName()); + rcf.sharedClass = null; + rcf.sharedRefCount = 0; + rcf.classIter = 0; + if(DEBUG) { + System.err.println("RegisteredClassFactory #"+j+"/"+registeredFactories.size()+" shutdownSharedClasses : "+rcf.sharedClass); + } + } } } - sharedClasses.clear(); } } public RegisteredClassFactory(String classBaseName, long wndProc) { this.classBaseName = classBaseName; this.wndProc = wndProc; + synchronized(registeredFactories) { + registeredFactories.add(this); + } } public RegisteredClass getSharedClass() throws NativeWindowException { @@ -76,19 +86,17 @@ public class RegisteredClassFactory { } String clazzName = null; boolean registered = false; - while ( !registered && Integer.MAX_VALUE >= classIter ) { + final int classIterMark = classIter - 1; + while ( !registered && classIterMark != classIter ) { // Retry with next clazz name, this could happen if more than one JVM is running clazzName = classBaseName + classIter; classIter++; - registered = GDI.CreateWindowClass(hInstance, clazzName, wndProc); + registered = GDIUtil.CreateWindowClass(hInstance, clazzName, wndProc); } if( !registered ) { throw new NativeWindowException("Error: Could not create WindowClass: "+clazzName); } sharedClass = new RegisteredClass(hInstance, clazzName); - synchronized(sharedClasses) { - sharedClasses.add(sharedClass); - } if(DEBUG) { System.err.println("RegisteredClassFactory getSharedClass ("+sharedRefCount+") initialized: "+sharedClass); } @@ -113,10 +121,7 @@ public class RegisteredClassFactory { throw new InternalError("Error ("+sharedRefCount+"): SharedClass is null"); } if( 0 == sharedRefCount ) { - GDI.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); - synchronized(sharedClasses) { - sharedClasses.remove(sharedClass); - } + GDIUtil.DestroyWindowClass(sharedClass.getHandle(), sharedClass.getName()); if(DEBUG) { System.err.println("RegisteredClassFactory releaseSharedClass ("+sharedRefCount+") released: "+sharedClass); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java index b669bce75..268416266 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11GraphicsConfigurationFactory.java @@ -33,10 +33,22 @@ package jogamp.nativewindow.x11; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsScreen; public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactory { + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.x11.X11GraphicsDevice.class, new X11GraphicsConfigurationFactory()); + } + private X11GraphicsConfigurationFactory() { + } + protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen screen) throws IllegalArgumentException, NativeWindowException { @@ -55,7 +67,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor int num[] = { -1 }; long display = screen.getDevice().getHandle(); - XVisualInfo[] xvis = X11Util.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); + XVisualInfo[] xvis = X11Lib.XGetVisualInfo(display, X11Lib.VisualIDMask|X11Lib.VisualScreenMask, xvi_temp, num, 0); if(xvis==null || num[0]<1) { return null; @@ -81,7 +93,7 @@ public class X11GraphicsConfigurationFactory extends GraphicsConfigurationFactor vinfo_template.setC_class(c_class); long display = screen.getDevice().getHandle(); - XVisualInfo[] vinfos = X11Util.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); + XVisualInfo[] vinfos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, vinfo_template, num, 0); XVisualInfo best=null; int rdepth = capabilities.getRedBits() + capabilities.getGreenBits() + capabilities.getBlueBits() + capabilities.getAlphaBits(); for (int i = 0; vinfos!=null && i < num[0]; i++) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java index fb0aff10d..5166ef577 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11ToolkitLock.java @@ -29,6 +29,9 @@ package jogamp.nativewindow.x11; import javax.media.nativewindow.ToolkitLock; +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + /** * Implementing a recursive {@link javax.media.nativewindow.ToolkitLock} * utilizing {@link X11Util#XLockDisplay(long)}. @@ -38,18 +41,30 @@ import javax.media.nativewindow.ToolkitLock; */ public class X11ToolkitLock implements ToolkitLock { long displayHandle; + RecursiveLock lock; public X11ToolkitLock(long displayHandle) { this.displayHandle = displayHandle; + if(!X11Util.isNativeLockAvailable()) { + lock = LockFactory.createRecursiveLock(); + } } public final void lock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock()"); } - X11Util.XLockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.lock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XLockDisplay(displayHandle); + } else { + lock.lock(); + } } public final void unlock() { - if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock()"); } - X11Util.XUnlockDisplay(displayHandle); + if(TRACE_LOCK) { System.err.println("X11ToolkitLock.unlock() - native: "+(null==lock)); } + if(null == lock) { + X11Lib.XUnlockDisplay(displayHandle); + } else { + lock.unlock(); + } } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 5c1839250..560130dd1 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -33,19 +33,18 @@ package jogamp.nativewindow.x11; -import com.jogamp.common.util.LongObjectHashMap; -import jogamp.nativewindow.Debug; -import jogamp.nativewindow.NWJNILibLoader; - -import javax.media.nativewindow.*; - -import java.nio.Buffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; import java.security.AccessController; import java.util.ArrayList; import java.util.List; -import javax.media.nativewindow.util.Point; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; + +import jogamp.nativewindow.Debug; +import jogamp.nativewindow.NWJNILibLoader; + +import com.jogamp.common.util.LongObjectHashMap; /** * Contains a thread safe X11 utility to retrieve display connections. @@ -53,54 +52,88 @@ import javax.media.nativewindow.util.Point; public class X11Util { /** * See Bug 515 - https://jogamp.org/bugzilla/show_bug.cgi?id=515 - * - * It is observed that ATI X11 drivers, eg. fglrx 8.78.6 and fglrx 11.08/8.881, + * <p> + * It is observed that ATI X11 drivers, eg. + * <ul> + * <li>fglrx 8.78.6,</li> + * <li>fglrx 11.08/8.881 and </li> + * <li>fglrx 11.11/8.911</li> + * </ul> * are quite sensitive to multiple Display connections. - * Here, closing displays shall happen in the same order as - * they were opened, -OR- shall not be closed at all! - * Otherwise some driver related bug appears and brings down the JVM. + * </p> + * <p> + * With the above drivers closing displays shall happen in the same order as + * they were opened, <b>or</b> shall not be closed at all! + * If closed, some driver related bug appears and brings down the JVM. + * </p> + * <p> * You may test this, ie just reverse the destroy order below. * See also native test: jogl/test/native/displayMultiple02.c - * - * Our current 'workaround' is to not close them at all if driver vendor is ATI. + * </p> + * <p> + * Workaround is to not close them at all if driver vendor is ATI. + * </p> */ public static final boolean ATI_HAS_XCLOSEDISPLAY_BUG = true; - - public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; + /** Value is <code>true</code>, best 'stable' results if always using XInitThreads(). */ + public static final boolean XINITTHREADS_ALWAYS_ENABLED = true; + + /** Value is <code>true</code>, best 'stable' results if not using XLockDisplay/XUnlockDisplay at all. */ + public static final boolean HAS_XLOCKDISPLAY_BUG = true; + private static final boolean DEBUG = Debug.debug("X11Util"); private static final boolean TRACE_DISPLAY_LIFECYCLE = Debug.getBooleanProperty("nativewindow.debug.X11Util.TraceDisplayLifecycle", true, AccessController.getContext()); - private static volatile String nullDisplayName = null; - private static boolean requiresX11Lock = false; - private static boolean isInit = false; + private static String nullDisplayName = null; + private static boolean isX11LockAvailable = false; + private static boolean requiresX11Lock = true; + private static volatile boolean isInit = false; private static boolean markAllDisplaysUnclosable = false; // ATI/AMD X11 driver issues private static int setX11ErrorHandlerRecCount = 0; private static Object setX11ErrorHandlerLock = new Object(); - public static synchronized void initSingleton(final boolean firstX11ActionOnProcess) { + @SuppressWarnings("unused") + public static void initSingleton(final boolean firstX11ActionOnProcess) { if(!isInit) { - NWJNILibLoader.loadNativeWindow("x11"); - - /** - * Always issue XInitThreads() since we have independent - * off-thread created Display connections able to utilize multithreading, - * ie NEWT (jogamp.newt.x11.X11Display.createNativeImpl()) !! - */ - initialize0( XINITTHREADS_ALWAYS_ENABLED ? true : firstX11ActionOnProcess ); - - requiresX11Lock = !firstX11ActionOnProcess ; - - if(DEBUG) { - System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ - ", XINITTHREADS_ALWAYS_ENABLED "+XINITTHREADS_ALWAYS_ENABLED+ - ", requiresX11Lock "+requiresX11Lock); + synchronized(X11Util.class) { + if(!isInit) { + isInit = true; + NWJNILibLoader.loadNativeWindow("x11"); + + final boolean callXInitThreads = XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess; + final boolean isXInitThreadsOK = initialize0( XINITTHREADS_ALWAYS_ENABLED || firstX11ActionOnProcess ); + isX11LockAvailable = isXInitThreadsOK && !HAS_XLOCKDISPLAY_BUG ; + + final long dpy = X11Lib.XOpenDisplay(null); + try { + nullDisplayName = X11Lib.XDisplayString(dpy); + } finally { + X11Lib.XCloseDisplay(dpy); + } + + if(DEBUG) { + System.err.println("X11Util firstX11ActionOnProcess: "+firstX11ActionOnProcess+ + ", requiresX11Lock "+requiresX11Lock+ + ", XInitThreads [called "+callXInitThreads+", OK "+isXInitThreadsOK+"]"+ + ", isX11LockAvailable "+isX11LockAvailable+ + ", X11 Display(NULL) <"+nullDisplayName+">"); + // Thread.dumpStack(); + } + } } - isInit = true; } } + + public static synchronized boolean isNativeLockAvailable() { + return isX11LockAvailable; + } + + public static synchronized boolean requiresToolkitLock() { + return requiresX11Lock; + } public static void setX11ErrorHandler(boolean onoff, boolean quiet) { synchronized(setX11ErrorHandlerLock) { @@ -121,42 +154,7 @@ public class X11Util { } } - public static boolean requiresToolkitLock() { - return requiresX11Lock; - } - - public static void lockDefaultToolkit(long dpyHandle) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - if(requiresX11Lock) { - X11Util.XLockDisplay(dpyHandle); - } - } - - public static void unlockDefaultToolkit(long dpyHandle) { - if(requiresX11Lock) { - X11Util.XUnlockDisplay(dpyHandle); - } - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - public static String getNullDisplayName() { - if(null==nullDisplayName) { // volatile: ok - synchronized(X11Util.class) { - if(null==nullDisplayName) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - long dpy = X11Lib.XOpenDisplay(null); - try { - nullDisplayName = X11Lib.XDisplayString(dpy); - } finally { - X11Lib.XCloseDisplay(dpy); - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - if(DEBUG) { - System.out.println("X11 Display(NULL) <"+nullDisplayName+">"); - } - } - } - } return nullDisplayName; } @@ -224,7 +222,6 @@ public class X11Util { public final void setUncloseable(boolean v) { unCloseable = v; } public final boolean isUncloseable() { return unCloseable; } - public final Throwable getCreationStack() { return creationStack; } @Override @@ -238,20 +235,22 @@ public class X11Util { } } - /** Returns the number of unclosed X11 Displays. + /** + * Cleanup resources. + * If <code>realXCloseOpenAndPendingDisplays</code> is <code>false</code>, + * keep alive all references (open display connection) for restart on same ClassLoader. + * + * @return number of unclosed X11 Displays.<br> * @param realXCloseOpenAndPendingDisplays if true, {@link #closePendingDisplayConnections()} is called. - */ + */ public static int shutdown(boolean realXCloseOpenAndPendingDisplays, boolean verbose) { int num=0; if(DEBUG||verbose||pendingDisplayList.size() > 0) { - String msg = "X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ - ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ - ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")" ; + System.err.println("X11Util.Display: Shutdown (close open / pending Displays: "+realXCloseOpenAndPendingDisplays+ + ", open (no close attempt): "+openDisplayMap.size()+"/"+openDisplayList.size()+ + ", pending (not closed, marked uncloseable): "+pendingDisplayList.size()+")"); if(DEBUG) { - Exception e = new Exception(msg); - e.printStackTrace(); - } else { - System.err.println(msg); + Thread.dumpStack(); } if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); @@ -264,10 +263,11 @@ public class X11Util { synchronized(globalLock) { if(realXCloseOpenAndPendingDisplays) { closePendingDisplayConnections(); + openDisplayList.clear(); + pendingDisplayList.clear(); + openDisplayMap.clear(); + shutdown0(); } - openDisplayList.clear(); - pendingDisplayList.clear(); - openDisplayMap.clear(); } return num; } @@ -304,9 +304,9 @@ public class X11Util { public static void dumpOpenDisplayConnections() { synchronized(globalLock) { System.err.println("X11Util: Open X11 Display Connections: "+openDisplayList.size()); - for(int i=0; i<pendingDisplayList.size(); i++) { + for(int i=0; i<openDisplayList.size(); i++) { NamedDisplay ndpy = openDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Open["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -316,7 +316,7 @@ public class X11Util { } } } - + public static int getPendingDisplayConnectionNumber() { synchronized(globalLock) { return pendingDisplayList.size(); @@ -328,7 +328,7 @@ public class X11Util { System.err.println("X11Util: Pending X11 Display Connections: "+pendingDisplayList.size()); for(int i=0; i<pendingDisplayList.size(); i++) { NamedDisplay ndpy = (NamedDisplay) pendingDisplayList.get(i); - System.err.println("X11Util: ["+i+"]: "+ndpy); + System.err.println("X11Util: Pending["+i+"]: "+ndpy); if(null!=ndpy) { Throwable t = ndpy.getCreationStack(); if(null!=t) { @@ -384,8 +384,8 @@ public class X11Util { } } if(DEBUG) { - Exception e = new Exception("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); - e.printStackTrace(); + System.err.println("X11Util.Display: openDisplay [reuse "+reused+"] "+namedDpy+". Thread "+Thread.currentThread().getName()); + // Thread.dumpStack(); } return namedDpy.getHandle(); } @@ -408,10 +408,6 @@ public class X11Util { if(!openDisplayList.remove(namedDpy)) { throw new RuntimeException("Internal: "+namedDpy); } if(!namedDpy.isUncloseable()) { - if(DEBUG) { - System.err.println("X11Util.Display: XCloseDisplay "+namedDpy+". Thread "+Thread.currentThread().getName()); - Thread.dumpStack(); - } XCloseDisplay(namedDpy.getHandle()); } else { // for reuse @@ -439,7 +435,7 @@ public class X11Util { public static String validateDisplayName(String name, long handle) { if( ( null==name || AbstractGraphicsDevice.DEFAULT_CONNECTION.equals(name) ) && 0!=handle) { - name = XDisplayString(handle); + name = X11Lib.XDisplayString(handle); } return validateDisplayName(name); } @@ -455,8 +451,8 @@ public class X11Util { try { long handle = X11Lib.XOpenDisplay(arg0); if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XOpenDisplay("+arg0+") 0x"+Long.toHexString(handle)); + // Thread.dumpStack(); } return handle; } finally { @@ -468,8 +464,8 @@ public class X11Util { NativeWindowFactory.getDefaultToolkitLock().lock(); try { if(TRACE_DISPLAY_LIFECYCLE) { - Throwable t = new Throwable(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); - t.printStackTrace(); + System.err.println(Thread.currentThread()+" - X11Util.XCloseDisplay() 0x"+Long.toHexString(display)); + // Thread.dumpStack(); } int res = -1; X11Util.setX11ErrorHandler(true, DEBUG ? false : true); @@ -487,209 +483,7 @@ public class X11Util { } } - public static int XFree(Buffer arg0) { - NativeWindowFactory.getDefaultToolkitLock().lock(); - try { - return X11Lib.XFree(arg0); - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); - } - } - - public static int XSync(long display, boolean discard) { - lockDefaultToolkit(display); - try { - return X11Lib.XSync(display, discard); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XSynchronize(long display, boolean onoff) { - lockDefaultToolkit(display); - try { - X11Lib.XSynchronize(display, onoff); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XineramaEnabled(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XineramaEnabled(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int DefaultScreen(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultScreen(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long RootWindow(long display, int screen_number) { - lockDefaultToolkit(display); - try { - return X11Lib.RootWindow(display, screen_number); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long XCreatePixmap(long display, long arg1, int arg2, int arg3, int arg4) { - lockDefaultToolkit(display); - try { - return X11Lib.XCreatePixmap(display, arg1, arg2, arg3, arg4); - } finally { - unlockDefaultToolkit(display); - } - } - - public static String XDisplayString(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XDisplayString(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFlush(long display) { - lockDefaultToolkit(display); - try { - return X11Lib.XFlush(display); - } finally { - unlockDefaultToolkit(display); - } - } - - public static int XFreePixmap(long display, long arg1) { - lockDefaultToolkit(display); - try { - return X11Lib.XFreePixmap(display, arg1); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long DefaultVisualID(long display, int screen) { - lockDefaultToolkit(display); - try { - return X11Lib.DefaultVisualID(display, screen); - } finally { - unlockDefaultToolkit(display); - } - } - - public static long CreateDummyWindow(long display, int screen_index, long visualID, int width, int height) { - lockDefaultToolkit(display); - try { - return X11Lib.CreateDummyWindow(display, screen_index, visualID, width, height); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void DestroyDummyWindow(long display, long window) { - lockDefaultToolkit(display); - try { - X11Lib.DestroyDummyWindow(display, window); - } finally { - unlockDefaultToolkit(display); - } - } - - public static Point GetRelativeLocation(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y) { - lockDefaultToolkit(display); - try { - return X11Lib.GetRelativeLocation(display, screen_index, src_win, dest_win, src_x, src_y); - } finally { - unlockDefaultToolkit(display); - } - } - - public static XVisualInfo[] XGetVisualInfo(long display, long arg1, XVisualInfo arg2, int[] arg3, int arg3_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XGetVisualInfo(display, arg1, arg2, arg3, arg3_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, IntBuffer size) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeGetGammaRampSize(long display, int screen, int[] size, int size_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeGetGammaRampSize(display, screen, size, size_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, ShortBuffer red_array, ShortBuffer green_array, ShortBuffer blue_array) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, green_array, blue_array); - } finally { - unlockDefaultToolkit(display); - } - } - - public static boolean XF86VidModeSetGammaRamp(long display, int screen, int size, short[] red_array, int red_array_offset, short[] green_array, int green_array_offset, short[] blue_array, int blue_array_offset) { - lockDefaultToolkit(display); - try { - return X11Lib.XF86VidModeSetGammaRamp(display, screen, size, red_array, red_array_offset, green_array, green_array_offset, blue_array, blue_array_offset); - } finally { - unlockDefaultToolkit(display); - } - } - - public static void XLockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("+++ X11 Display Lock get 0x"+Long.toHexString(handle)); - } - X11Lib.XLockDisplay(handle); - } - - public static void XUnlockDisplay(long handle) { - if(ToolkitLock.TRACE_LOCK) { - System.out.println("--- X11 Display Lock rel 0x"+Long.toHexString(handle)); - } - X11Lib.XUnlockDisplay(handle); - } - - private static native void initialize0(boolean firstUIActionOnProcess); + private static native boolean initialize0(boolean firstUIActionOnProcess); + private static native void shutdown0(); private static native void setX11ErrorHandler0(boolean onoff, boolean quiet); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java index 9ee20d8ea..efaf4728c 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/awt/X11AWTGLXGraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/awt/X11AWTGraphicsConfigurationFactory.java @@ -31,65 +31,69 @@ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ -package jogamp.opengl.x11.glx.awt; +package jogamp.nativewindow.x11.awt; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; -import javax.media.nativewindow.awt.*; -import javax.media.opengl.*; -import jogamp.opengl.*; -import jogamp.nativewindow.jawt.x11.*; -import jogamp.nativewindow.x11.*; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesChooser; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ToolkitLock; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; +import javax.media.nativewindow.awt.AWTGraphicsDevice; +import javax.media.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.x11.X11GraphicsConfiguration; +import javax.media.nativewindow.x11.X11GraphicsDevice; +import javax.media.nativewindow.x11.X11GraphicsScreen; -public class X11AWTGLXGraphicsConfigurationFactory extends GLGraphicsConfigurationFactory { - protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); +import jogamp.nativewindow.jawt.x11.X11SunJDKReflection; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; - public X11AWTGLXGraphicsConfigurationFactory() { - GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, this); +public class X11AWTGraphicsConfigurationFactory extends GraphicsConfigurationFactory { + + public static void registerFactory() { + GraphicsConfigurationFactory.registerFactory(javax.media.nativewindow.awt.AWTGraphicsDevice.class, new X11AWTGraphicsConfigurationFactory()); + } + private X11AWTGraphicsConfigurationFactory() { } protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { - GraphicsDevice device = null; + CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { if (absScreen != null && !(absScreen instanceof AWTGraphicsScreen)) { throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only AWTGraphicsScreen objects"); } - if(null==absScreen) { - absScreen = AWTGraphicsScreen.createScreenDevice(-1, AbstractGraphicsDevice.DEFAULT_UNIT); - } - AWTGraphicsScreen awtScreen = (AWTGraphicsScreen) absScreen; - device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); - - if ( !(capsChosen instanceof GLCapabilitiesImmutable) ) { - throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only GLCapabilities objects - chosen"); - } - - if ( !(capsRequested instanceof GLCapabilitiesImmutable) ) { - throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only GLCapabilities objects - requested"); - } - - if (chooser != null && - !(chooser instanceof GLCapabilitiesChooser)) { - throw new IllegalArgumentException("This GraphicsConfigurationFactory accepts only GLCapabilitiesChooser objects"); + absScreen = AWTGraphicsScreen.createDefault(); } + return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, (AWTGraphicsScreen)absScreen); + } + + public static AWTGraphicsConfiguration chooseGraphicsConfigurationStatic( + CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, + CapabilitiesChooser chooser, AWTGraphicsScreen awtScreen) { if(DEBUG) { - System.err.println("X11AWTGLXGraphicsConfigurationFactory: got "+absScreen); + System.err.println("X11AWTGraphicsConfigurationFactory: got "+awtScreen); } + final GraphicsDevice device = ((AWTGraphicsDevice)awtScreen.getDevice()).getGraphicsDevice(); + long displayHandle = X11SunJDKReflection.graphicsDeviceGetDisplay(device); boolean owner = false; if(0==displayHandle) { displayHandle = X11Util.openDisplay(null); owner = true; if(DEBUG) { - System.err.println(Thread.currentThread().getName() + " - X11AWTGLXGraphicsConfigurationFactory: create local X11 display"); + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create local X11 display"); } } else { /** @@ -98,23 +102,31 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GLGraphicsConfigurati * some work, but some behave erratic. * I.e. hangs in XQueryExtension(..) via X11GraphicsScreen. */ - final String displayName = X11Util.XDisplayString(displayHandle); + final String displayName = X11Lib.XDisplayString(displayHandle); if(DEBUG) { - System.err.println(Thread.currentThread().getName() + " - X11AWTGLXGraphicsConfigurationFactory: create X11 display @ "+displayName+" / 0x"+Long.toHexString(displayHandle)); + System.err.println(Thread.currentThread().getName() + " - X11AWTGraphicsConfigurationFactory: create X11 display @ "+displayName+" / 0x"+Long.toHexString(displayHandle)); } displayHandle = X11Util.openDisplay(displayName); owner = true; } - ((AWTGraphicsDevice)awtScreen.getDevice()).setSubType(NativeWindowFactory.TYPE_X11, displayHandle); - X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT); - x11Device.setCloseDisplay(owner); - X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); + final ToolkitLock lock = owner ? + NativeWindowFactory.getDefaultToolkitLock(NativeWindowFactory.TYPE_AWT) : // own non-shared X11 display connection, no X11 lock + NativeWindowFactory.createDefaultToolkitLock(NativeWindowFactory.TYPE_X11, NativeWindowFactory.TYPE_AWT, displayHandle); + final X11GraphicsDevice x11Device = new X11GraphicsDevice(displayHandle, AbstractGraphicsDevice.DEFAULT_UNIT, lock, owner); + final X11GraphicsScreen x11Screen = new X11GraphicsScreen(x11Device, awtScreen.getIndex()); if(DEBUG) { - System.err.println("X11AWTGLXGraphicsConfigurationFactory: made "+x11Screen); + System.err.println("X11AWTGraphicsConfigurationFactory: made "+x11Screen); } - GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device); - GraphicsConfiguration[] configs = device.getConfigurations(); - + + final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(x11Device); + X11GraphicsConfiguration x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); + if (x11Config == null) { + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + } + if(DEBUG) { + System.err.println("X11AWTGraphicsConfigurationFactory: chosen x11Config: "+x11Config); + } + // // Match the X11/GL Visual with AWT: // - choose a config AWT agnostic and then @@ -122,11 +134,8 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GLGraphicsConfigurati // // The resulting GraphicsConfiguration has to be 'forced' on the AWT native peer, // ie. returned by GLCanvas's getGraphicsConfiguration() befor call by super.addNotify(). - // - X11GraphicsConfiguration x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); - if (x11Config == null) { - throw new GLException("Unable to choose a GraphicsConfiguration (1): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); - } + // + final GraphicsConfiguration[] configs = device.getConfigurations(); long visualID = x11Config.getVisualID(); for (int i = 0; i < configs.length; i++) { GraphicsConfiguration gc = configs[i]; @@ -147,7 +156,7 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GLGraphicsConfigurati capsChosen = AWTGraphicsConfiguration.setupCapabilitiesRGBABits(capsChosen, gc); x11Config = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration(capsChosen, capsRequested, chooser, x11Screen); if (x11Config == null) { - throw new GLException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); + throw new NativeWindowException("Unable to choose a GraphicsConfiguration (2): "+capsChosen+",\n\t"+chooser+"\n\t"+x11Screen); } visualID = x11Config.getVisualID(); for (int i = 0; i < configs.length; i++) { @@ -173,3 +182,4 @@ public class X11AWTGLXGraphicsConfigurationFactory extends GLGraphicsConfigurati return new AWTGraphicsConfiguration(awtScreen, x11Config.getChosenCapabilities(), x11Config.getRequestedCapabilities(), gc, x11Config); } } + diff --git a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c index 470f03a49..2a6651007 100644 --- a/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c +++ b/src/nativewindow/native/JAWT_DrawingSurfaceInfo.c @@ -59,6 +59,13 @@ Java_jogamp_nativewindow_jawt_JAWT_1DrawingSurfaceInfo_platformInfo0(JNIEnv* env return NULL; } if (dsi->platformInfo == NULL) { + (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), + "platformInfo pointer is NULL"); + return NULL; + } + if(0==PLATFORM_DSI_SIZE) { + (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/RuntimeException"), + "platformInfo size is 0"); return NULL; } return (*env)->NewDirectByteBuffer(env, dsi->platformInfo, PLATFORM_DSI_SIZE); diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index e19d5ecf7..d64973b67 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -35,6 +35,19 @@ #include "NativewindowCommon.h" #include "jogamp_nativewindow_macosx_OSXUtil.h" +#include "jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow.h" + +#include <jawt_md.h> +#import <JavaNativeFoundation.h> + +// #define VERBOSE 1 +// +#ifdef VERBOSE + // #define DBG_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif static const char * const ClazzNameRunnable = "java/lang/Runnable"; static jmethodID runnableRunID = NULL; @@ -81,7 +94,7 @@ Java_jogamp_nativewindow_macosx_OSXUtil_initIDs0(JNIEnv *env, jclass _unused) { /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil - * Method: getLocationOnScreenImpl0 + * Method: getLocationOnScreen0 * Signature: (JII)Ljavax/media/nativewindow/util/Point; */ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnScreen0 @@ -97,7 +110,7 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS int dest_x=-1; int dest_y=-1; - NSObject *nsObj = (NSObject*) ((intptr_t) winOrView); + NSObject *nsObj = (NSObject*) (intptr_t) winOrView; NSWindow* win = NULL; NSView* view = NULL; @@ -135,6 +148,189 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetLocationOnS return res; } +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateNSView0 + * Signature: (IIIIZ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSView0 + (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSRect rect = NSMakeRect(x, y, width, height); + NSView * view = [[NSView alloc] initWithFrame: rect] ; + [view setCanDrawConcurrently: YES]; + [pool release]; + + return (jlong) (intptr_t) view; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyNSView0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSView0 + (JNIEnv *env, jclass unused, jlong nsView) +{ + NSView* view = (NSView*) (intptr_t) nsView; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [view release]; + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateNSWindow0 + * Signature: (IIIIZ)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateNSWindow0 + (JNIEnv *env, jclass unused, jint x, jint y, jint width, jint height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSRect rect = NSMakeRect(x, y, width, height); + + // Allocate the window + NSWindow* myWindow = [[NSWindow alloc] initWithContentRect: rect + styleMask: NSBorderlessWindowMask + backing: NSBackingStoreBuffered + defer: YES]; + [myWindow setReleasedWhenClosed: YES]; // default + [myWindow setPreservesContentDuringLiveResize: YES]; + + // invisible .. + [myWindow setOpaque: NO]; + [myWindow setBackgroundColor: [NSColor clearColor]]; + + [pool release]; + + return (jlong) ((intptr_t) myWindow); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyNSWindow0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyNSWindow0 + (JNIEnv *env, jclass unused, jlong nsWindow) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* mWin = (NSWindow*) ((intptr_t) nsWindow); + + [mWin close]; // performs release! + [pool release]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: CreateCALayer0 + * Signature: (V)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_CreateCALayer0 + (JNIEnv *env, jclass unused) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + // CALayer* layer = [[CALayer alloc] init]; + CALayer* layer = [CALayer layer]; + + // no animations for add/remove/swap sublayers etc + [layer removeAnimationForKey: kCAOnOrderIn]; + [layer removeAnimationForKey: kCAOnOrderOut]; + [layer removeAnimationForKey: kCATransition]; + + // initial dummy size ! + CGRect lRect = [layer frame]; + lRect.origin.x = 0; + lRect.origin.y = 0; + lRect.size.width = 32; + lRect.size.height = 32; + [layer setFrame: lRect]; + DBG_PRINT("CALayer::CreateCALayer0: %p %lf/%lf %lfx%lf\n", layer, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + + [pool release]; + + return (jlong) ((intptr_t) layer); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: AddCASublayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_AddCASublayer0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) +{ + JNF_COCOA_ENTER(env); + CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + CGRect lRectRoot = [rootLayer frame]; + DBG_PRINT("CALayer::AddCASublayer0.0: Origin %p frame0: %lf/%lf %lfx%lf\n", + rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + if(lRectRoot.origin.x<0 || lRectRoot.origin.y<0) { + lRectRoot.origin.x = 0; + lRectRoot.origin.y = 0; + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [rootLayer setFrame: lRectRoot]; + }]; + DBG_PRINT("CALayer::AddCASublayer0.1: Origin %p frame*: %lf/%lf %lfx%lf\n", + rootLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height); + } + DBG_PRINT("CALayer::AddCASublayer0.2: %p . %p %lf/%lf %lfx%lf (refcnt %d)\n", + rootLayer, subLayer, lRectRoot.origin.x, lRectRoot.origin.y, lRectRoot.size.width, lRectRoot.size.height, (int)[subLayer retainCount]); + + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + // simple 1:1 layout ! + [subLayer setFrame:lRectRoot]; + [rootLayer addSublayer:subLayer]; + }]; + DBG_PRINT("CALayer::AddCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: RemoveCASublayer0 + * Signature: (JJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RemoveCASublayer0 + (JNIEnv *env, jclass unused, jlong rootCALayer, jlong subCALayer) +{ + JNF_COCOA_ENTER(env); + CALayer* rootLayer = (CALayer*) ((intptr_t) rootCALayer); + CALayer* subLayer = (CALayer*) ((intptr_t) subCALayer); + + (void)rootLayer; // no warnings + + DBG_PRINT("CALayer::RemoveCASublayer0.0: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [subLayer removeFromSuperlayer]; + }]; + DBG_PRINT("CALayer::RemoveCASublayer0.X: %p . %p (refcnt %d)\n", rootLayer, subLayer, (int)[subLayer retainCount]); + JNF_COCOA_EXIT(env); +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: DestroyCALayer0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_DestroyCALayer0 + (JNIEnv *env, jclass unused, jlong caLayer) +{ + JNF_COCOA_ENTER(env); + CALayer* layer = (CALayer*) ((intptr_t) caLayer); + + DBG_PRINT("CALayer::DestroyCALayer0.0: %p (refcnt %d)\n", layer, (int)[layer retainCount]); + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + [layer release]; // performs release! + }]; + DBG_PRINT("CALayer::DestroyCALayer0.X: %p (refcnt %d)\n", layer, (int)[layer retainCount]); + JNF_COCOA_EXIT(env); +} + @interface MainRunnable : NSObject { @@ -212,10 +408,35 @@ JNIEXPORT void JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_RunOnMainThread0 /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: RunOnMainThread0 - * Signature: (ZLjava/lang/Runnable;)V + * Signature: (V)V */ JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_IsMainThread0 (JNIEnv *env, jclass unused) { return ( [NSThread isMainThread] == YES ) ? JNI_TRUE : JNI_FALSE ; } + +/* + * Class: Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow + * Method: AttachJAWTSurfaceLayer + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_jawt_macosx_MacOSXJAWTWindow_AttachJAWTSurfaceLayer0 + (JNIEnv *env, jclass unused, jobject jawtDrawingSurfaceInfoBuffer, jlong caLayer) +{ + JNF_COCOA_ENTER(env); + JAWT_DrawingSurfaceInfo* dsi = (JAWT_DrawingSurfaceInfo*) (*env)->GetDirectBufferAddress(env, jawtDrawingSurfaceInfoBuffer); + if (NULL == dsi) { + NativewindowCommon_throwNewRuntimeException(env, "Argument \"jawtDrawingSurfaceInfoBuffer\" was not a direct buffer"); + return JNI_FALSE; + } + CALayer* layer = (CALayer*) (intptr_t) caLayer; + [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ + id <JAWT_SurfaceLayers> surfaceLayers = (id <JAWT_SurfaceLayers>)dsi->platformInfo; + DBG_PRINT("CALayer::attachJAWTSurfaceLayer: %p -> %p\n", surfaceLayers.layer, layer); + surfaceLayers.layer = [layer autorelease]; + }]; + JNF_COCOA_EXIT(env); + return JNI_TRUE; +} + diff --git a/src/nativewindow/native/windows/GDImisc.c b/src/nativewindow/native/windows/GDImisc.c index e8285008e..3ab7f9859 100644 --- a/src/nativewindow/native/windows/GDImisc.c +++ b/src/nativewindow/native/windows/GDImisc.c @@ -14,7 +14,7 @@ #include <stdio.h> #include "NativewindowCommon.h" -#include "jogamp_nativewindow_windows_GDI.h" +#include "jogamp_nativewindow_windows_GDIUtil.h" // #define VERBOSE_ON 1 @@ -36,12 +36,12 @@ HINSTANCE GetApplicationHandle() { } /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: boolean CreateWindowClass(long hInstance, java.lang.String clazzName, long wndProc) * C function: BOOL CreateWindowClass(HANDLE hInstance, LPCSTR clazzName, HANDLE wndProc); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDI_CreateWindowClass +Java_jogamp_nativewindow_windows_GDIUtil_CreateWindowClass (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName, jlong wndProc) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -85,12 +85,12 @@ Java_jogamp_nativewindow_windows_GDI_CreateWindowClass } /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: boolean DestroyWindowClass(long hInstance, java.lang.String className) * C function: BOOL DestroyWindowClass(HANDLE hInstance, LPCSTR className); */ JNIEXPORT jboolean JNICALL -Java_jogamp_nativewindow_windows_GDI_DestroyWindowClass +Java_jogamp_nativewindow_windows_GDIUtil_DestroyWindowClass (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jClazzName) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -116,12 +116,12 @@ Java_jogamp_nativewindow_windows_GDI_DestroyWindowClass /* Java->C glue code: - * Java package: jogamp.nativewindow.windows.GDI + * Java package: jogamp.nativewindow.windows.GDIUtil * Java method: long CreateDummyWindow0(long hInstance, java.lang.String className, java.lang.String windowName, int x, int y, int width, int height) * C function: HANDLE CreateDummyWindow0(HANDLE hInstance, LPCSTR className, LPCSTR windowName, int x, int y, int width, int height); */ JNIEXPORT jlong JNICALL -Java_jogamp_nativewindow_windows_GDI_CreateDummyWindow0 +Java_jogamp_nativewindow_windows_GDIUtil_CreateDummyWindow0 (JNIEnv *env, jclass _unused, jlong jHInstance, jstring jWndClassName, jstring jWndName, jint x, jint y, jint width, jint height) { HINSTANCE hInstance = (HINSTANCE) (intptr_t) jHInstance; @@ -162,26 +162,26 @@ Java_jogamp_nativewindow_windows_GDI_CreateDummyWindow0 /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: initIDs0 * Signature: ()Z */ -JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDI_initIDs0 +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_windows_GDIUtil_initIDs0 (JNIEnv *env, jclass clazz) { if(NativewindowCommon_init(env)) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't find %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't find %s", ClazzNamePoint); } pointClz = (jclass)(*env)->NewGlobalRef(env, c); (*env)->DeleteLocalRef(env, c); if(NULL==pointClz) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't use %s", ClazzNamePoint); + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't use %s", ClazzNamePoint); } pointCstr = (*env)->GetMethodID(env, pointClz, ClazzAnyCstrName, ClazzNamePointCstrSignature); if(NULL==pointCstr) { - NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDI: can't fetch %s.%s %s", + NativewindowCommon_FatalError(env, "FatalError jogamp_nativewindow_windows_GDIUtil: can't fetch %s.%s %s", ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } } @@ -193,22 +193,22 @@ LRESULT CALLBACK DummyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l } /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: getDummyWndProc0 * Signature: ()J */ -JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDI_getDummyWndProc0 +JNIEXPORT jlong JNICALL Java_jogamp_nativewindow_windows_GDIUtil_getDummyWndProc0 (JNIEnv *env, jclass clazz) { return (jlong) (intptr_t) DummyWndProc; } /* - * Class: jogamp_nativewindow_windows_GDI + * Class: jogamp_nativewindow_windows_GDIUtil * Method: GetRelativeLocation0 * Signature: (JJII)Ljavax/media/nativewindow/util/Point; */ -JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDI_GetRelativeLocation0 +JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_windows_GDIUtil_GetRelativeLocation0 (JNIEnv *env, jclass unused, jlong jsrc_win, jlong jdest_win, jint src_x, jint src_y) { HWND src_win = (HWND) (intptr_t) jsrc_win; diff --git a/src/nativewindow/native/x11/Xmisc.c b/src/nativewindow/native/x11/Xmisc.c index d481343f9..d28891cda 100644 --- a/src/nativewindow/native/x11/Xmisc.c +++ b/src/nativewindow/native/x11/Xmisc.c @@ -293,14 +293,16 @@ static void x11IOErrorHandlerEnable(int onoff, JNIEnv * env) { } static int _initialized=0; +static jboolean _xinitThreadsOK=JNI_FALSE; -JNIEXPORT void JNICALL +JNIEXPORT jboolean JNICALL Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jboolean firstUIActionOnProcess) { if(0==_initialized) { if( JNI_TRUE == firstUIActionOnProcess ) { if( 0 == XInitThreads() ) { fprintf(stderr, "Warning: XInitThreads() failed\n"); } else { + _xinitThreadsOK=JNI_TRUE; fprintf(stderr, "Info: XInitThreads() called for concurrent Thread support\n"); } } else { @@ -311,6 +313,12 @@ Java_jogamp_nativewindow_x11_X11Util_initialize0(JNIEnv *env, jclass _unused, jb x11IOErrorHandlerEnable(1, env); _initialized=1; } + return _xinitThreadsOK; +} + +JNIEXPORT void JNICALL +Java_jogamp_nativewindow_x11_X11Util_shutdown0(JNIEnv *env, jclass _unused) { + x11IOErrorHandlerEnable(0, env); } JNIEXPORT void JNICALL diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 6a0ebe14a..7b6849a30 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -30,7 +30,6 @@ package com.jogamp.newt; import com.jogamp.newt.util.EDTUtil; import jogamp.newt.Debug; -import jogamp.newt.DisplayImpl; import java.util.*; @@ -130,7 +129,10 @@ public abstract class Display { public abstract int getId(); /** - * @return this display instance name as defined at creation time + * @return This display connection name as defined at creation time. + * The display connection name is a technical platform specific detail, see {@link AbstractGraphicsDevice#getConnection()}. + * + * @see AbstractGraphicsDevice#getConnection() */ public abstract String getName(); @@ -198,6 +200,7 @@ public abstract class Display { } /** Returns the global display collection */ + @SuppressWarnings("unchecked") public static Collection<Display> getAllDisplays() { ArrayList<Display> list; synchronized(displayList) { diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index d3be098c0..4e6fa1aa5 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -34,14 +34,19 @@ package com.jogamp.newt; -import javax.media.nativewindow.*; - -import com.jogamp.common.os.Platform; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowFactory; +import jogamp.newt.Debug; import jogamp.newt.DisplayImpl; import jogamp.newt.ScreenImpl; import jogamp.newt.WindowImpl; -import jogamp.newt.Debug; + +import com.jogamp.common.os.Platform; public class NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); @@ -49,7 +54,6 @@ public class NewtFactory { // Work-around for initialization order problems on Mac OS X // between native Newt and (apparently) Fmod static { - Platform.initSingleton(); NativeWindowFactory.initSingleton(false); // last resort .. WindowImpl.init(NativeWindowFactory.getNativeWindowType(true)); } @@ -80,53 +84,124 @@ public class NewtFactory { public static boolean useEDT() { return useEDT; } /** - * Create a Display entity, incl native creation + * Create a Display entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Display#addReference()}. + * </p> + * <p> + * An already existing display connection of the same <code>name</code> will be reused. + * </p> + * @param name the display connection name which is a technical platform specific detail, + * see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default. + * @return the new or reused Display instance */ public static Display createDisplay(String name) { return createDisplay(name, true); } + /** + * Create a Display entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Display#addReference()}. + * </p> + * <p> + * An already existing display connection of the same <code>name</code> will be reused + * <b>if</b> <code>reuse</code> is <code>true</code>, otherwise a new instance is being created. + * </p> + * @param name the display connection name which is a technical platform specific detail, + * see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default. + * @param reuse attempt to reuse an existing Display with same <code>name</code> if set true, otherwise create a new instance. + * @return the new or reused Display instance + */ public static Display createDisplay(String name, boolean reuse) { return DisplayImpl.create(NativeWindowFactory.getNativeWindowType(true), name, 0, reuse); } /** - * Create a Display entity using the given implementation type, incl native creation + * Create a Display entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Display#addReference()}. + * </p> + * <p> + * An already existing display connection of the same <code>name</code> will be reused. + * </p> + * @param type explicit NativeWindow type eg. {@link NativeWindowFactory#TYPE_AWT} + * @param name the display connection name which is a technical platform specific detail, + * see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default. + * @return the new or reused Display instance */ public static Display createDisplay(String type, String name) { return createDisplay(type, name, true); } + /** + * Create a Display entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Display#addReference()}. + * </p> + * <p> + * An already existing display connection of the same <code>name</code> will be reused + * <b>if</b> <code>reuse</code> is <code>true</code>, otherwise a new instance is being created. + * </p> + * @param type explicit NativeWindow type eg. {@link NativeWindowFactory#TYPE_AWT} + * @param name the display connection name which is a technical platform specific detail, + * see {@link AbstractGraphicsDevice#getConnection()}. Use <code>null</code> for default. + * @param reuse attempt to reuse an existing Display with same <code>name</code> if set true, otherwise create a new instance. + * @return the new or reused Display instance + */ public static Display createDisplay(String type, String name, boolean reuse) { return DisplayImpl.create(type, name, 0, reuse); } /** - * Create a Screen entity, incl native creation + * Create a Screen entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Screen#addReference()}. + * </p> + * <p> + * The lifecycle of this Screen's Display is handled via {@link Display#addReference()} + * and {@link Display#removeReference()}. + * </p> */ public static Screen createScreen(Display display, int index) { return ScreenImpl.create(display, index); } /** - * Create a top level Window entity, incl native creation.<br> - * The Display/Screen is created and owned, ie destructed atomatically.<br> - * A new Display is only created if no preexisting one could be found via {@link Display#getLastDisplayOf(java.lang.String, java.lang.String, int)}. + * Create a top level Window entity on the default Display and default Screen. + * <p> + * Native creation is lazily done at usage, ie. {@link Window#setVisible(boolean)}. + * </p> + * <p> + * An already existing default Display will be reused. + * </p> + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> */ public static Window createWindow(CapabilitiesImmutable caps) { return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), caps); } /** - * Create a top level Window entity, incl native creation + * Create a top level Window entity. + * <p> + * Native creation is lazily done at usage, ie. {@link Window#setVisible(boolean)}. + * </p> + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> */ public static Window createWindow(Screen screen, CapabilitiesImmutable caps) { return createWindowImpl(screen, caps); } /** - * Create a child Window entity attached to the given parent, incl native creation.<br> - * The Screen and Display information is regenerated utilizing the parents information.<br> + * Create a child Window entity attached to the given parent.<br> + * The Screen and Display information is regenerated utilizing the parents information, + * while reusing an existing Display.<br> * <p> * In case <code>parentWindowObject</code> is a {@link com.jogamp.newt.Window} instance,<br> * the new window is added to it's list of children.<br> @@ -138,38 +213,41 @@ public class NewtFactory { * In case <code>parentWindowObject</code> is a different {@link javax.media.nativewindow.NativeWindow} implementation,<br> * you have to handle all events appropriate.<br></p> * <p> + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> * * @param parentWindowObject either a NativeWindow instance */ - public static Window createWindow(NativeWindow nParentWindow, CapabilitiesImmutable caps) { + public static Window createWindow(NativeWindow parentWindow, CapabilitiesImmutable caps) { final String type = NativeWindowFactory.getNativeWindowType(true); - Screen screen = null; - Window parentWindow = null; + Window newtParentWindow = null; - if ( nParentWindow instanceof Window ) { + if ( parentWindow instanceof Window ) { // use parent NEWT Windows Display/Screen - parentWindow = (Window) nParentWindow ; - screen = parentWindow.getScreen(); + newtParentWindow = (Window) parentWindow ; + screen = newtParentWindow.getScreen(); } else { // create a Display/Screen compatible to the NativeWindow - AbstractGraphicsConfiguration nParentConfig = nParentWindow.getGraphicsConfiguration(); - if(null!=nParentConfig) { - AbstractGraphicsScreen nParentScreen = nParentConfig.getScreen(); - AbstractGraphicsDevice nParentDevice = nParentScreen.getDevice(); - Display display = NewtFactory.createDisplay(type, nParentDevice.getHandle(), true); - screen = NewtFactory.createScreen(display, nParentScreen.getIndex()); + AbstractGraphicsConfiguration parentConfig = parentWindow.getGraphicsConfiguration(); + if(null!=parentConfig) { + AbstractGraphicsScreen parentScreen = parentConfig.getScreen(); + AbstractGraphicsDevice parentDevice = parentScreen.getDevice(); + Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true); + screen = NewtFactory.createScreen(display, parentScreen.getIndex()); } else { Display display = NewtFactory.createDisplay(type, null, true); // local display screen = NewtFactory.createScreen(display, 0); // screen 0 } } - final Window win = createWindowImpl(nParentWindow, screen, caps); + final Window win = createWindowImpl(parentWindow, screen, caps); - win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); - if ( null != parentWindow ) { - parentWindow.addChild(win); - win.setVisible(parentWindow.isVisible()); + win.setSize(parentWindow.getWidth(), parentWindow.getHeight()); + if ( null != newtParentWindow ) { + newtParentWindow.addChild(win); + win.setVisible(newtParentWindow.isVisible()); } return win; } diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index d25d3e7ac..26f19ad6b 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -120,12 +120,22 @@ public abstract class Screen { public abstract int getIndex(); /** - * @return the current screen width + * @return the x position of the virtual top-left origin. + */ + public abstract int getX(); + + /** + * @return the y position of the virtual top-left origin. + */ + public abstract int getY(); + + /** + * @return the <b>rotated</b> virtual width. */ public abstract int getWidth(); /** - * @return the current screen height + * @return the <b>rotated</b> virtual height. */ public abstract int getHeight(); diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index a78f81668..32024a49a 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -30,12 +30,13 @@ package com.jogamp.newt; import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.MouseListener; import jogamp.newt.Debug; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.WindowClosingProtocol; /** @@ -133,6 +134,11 @@ public interface Window extends NativeWindow, WindowClosingProtocol { boolean isVisible(); + /** + * If the implementation uses delegation, return the delegated {@link Window} instance, + * otherwise return <code>this</code> instance. */ + Window getDelegatedWindow(); + // // Child Window Management // @@ -310,16 +316,46 @@ public interface Window extends NativeWindow, WindowClosingProtocol { } /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * Sets a {@link FocusRunnable}, + * which {@link FocusRunnable#run()} method is executed before the native focus is requested. + * <p> * This allows notifying a covered window toolkit like AWT that the focus is requested, * hence focus traversal can be made transparent. + * </p> */ void setFocusAction(FocusRunnable focusAction); + + /** + * Sets a {@link KeyListener} allowing focus traversal with a covered window toolkit like AWT. + * <p> + * The {@link KeyListener} methods are invoked prior to all other {@link KeyListener}'s + * allowing to suppress the {@link KeyEvent} via the {@link InputEvent#consumedTag}. + * </p> + * @param l + */ + void setKeyboardFocusHandler(KeyListener l); + /** + * Request focus for this native window + * <p> + * The request is handled on this Window EDT and blocked until finished. + * </p> + * + * @see #requestFocus(boolean) + */ void requestFocus(); - boolean hasFocus(); - + /** + * Request focus for this native window + * <p> + * The request is handled on this Window EDT. + * </p> + * + * @param wait true if waiting until the request is executed, otherwise false + * @see #requestFocus() + */ + void requestFocus(boolean wait); + void windowRepaint(int x, int y, int width, int height); void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event); @@ -328,38 +364,6 @@ public interface Window extends NativeWindow, WindowClosingProtocol { // - // SurfaceUpdateListener - // - - /** - * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of - * the list. - */ - void addSurfaceUpdatedListener(SurfaceUpdatedListener l); - - /** - * - * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the - * specified position in the list.<br> - * - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). - * @param l The listener object to be inserted - * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 - */ - void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; - - void removeAllSurfaceUpdatedListener(); - - void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); - - SurfaceUpdatedListener getSurfaceUpdatedListener(int index); - - SurfaceUpdatedListener[] getSurfaceUpdatedListeners(); - - - // // WindowListener // diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index 31d42d21b..a71c6106d 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -29,42 +29,56 @@ package com.jogamp.newt.awt; -import com.jogamp.newt.Display; -import java.lang.reflect.*; -import java.security.*; - +import java.awt.AWTKeyStroke; import java.awt.Canvas; -import java.awt.EventQueue; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.KeyboardFocusManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Set; import javax.media.nativewindow.NativeWindow; -import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.OffscreenLayerOption; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.awt.AWTWindowClosingProtocol; +import javax.swing.MenuSelectionManager; + import jogamp.nativewindow.awt.AWTMisc; +import jogamp.nativewindow.jawt.JAWTWindow; +import jogamp.newt.Debug; +import jogamp.newt.awt.NewtFactoryAWT; +import jogamp.newt.awt.event.AWTParentWindowAdapter; +import jogamp.newt.driver.DriverClearFocus; -import com.jogamp.newt.event.awt.AWTAdapter; -import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.Display; import com.jogamp.newt.Window; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.event.WindowListener; -import jogamp.newt.Debug; -import jogamp.newt.awt.event.AWTParentWindowAdapter; -import jogamp.newt.awt.event.NewtFactoryAWT; - -import javax.swing.MenuSelectionManager; +import com.jogamp.newt.event.awt.AWTAdapter; +import com.jogamp.newt.event.awt.AWTKeyAdapter; +import com.jogamp.newt.event.awt.AWTMouseAdapter; @SuppressWarnings("serial") -public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol { +public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProtocol, OffscreenLayerOption { public static final boolean DEBUG = Debug.debug("Window"); - NativeWindow nativeWindow = null; - Window newtChild = null; - int newtChildCloseOp; - AWTAdapter awtAdapter = null; - + private JAWTWindow jawtWindow = null; + private boolean shallUseOffscreenLayer = false; + private Window newtChild = null; + private boolean isOnscreen = true; + private int newtChildCloseOp; + private AWTAdapter awtAdapter = null; + private AWTAdapter awtMouseAdapter = null; + private AWTAdapter awtKeyAdapter = null; + private AWTWindowClosingProtocol awtWindowClosingProtocol = new AWTWindowClosingProtocol(this, new Runnable() { public void run() { @@ -102,53 +116,136 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto setNEWTChild(child); } + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + public final boolean isOffscreenLayerSurfaceEnabled() { + return jawtWindow.isOffscreenLayerSurfaceEnabled(); + } + + /** + * Returns true if the AWT component is parented to an {@link java.applet.Applet}, + * otherwise false. This information is valid only after {@link #addNotify()} is issued, + * ie. before adding the component to the AWT tree and make it visible. + */ + public boolean isApplet() { + return jawtWindow.isApplet(); + } + class FocusAction implements Window.FocusRunnable { public boolean run() { - if ( EventQueue.isDispatchThread() ) { - focusActionImpl.run(); - } else { - try { - EventQueue.invokeAndWait(focusActionImpl); - } catch (Exception e) { - throw new NativeWindowException(e); - } - /** - // wait for AWT focus ! - for(long sleep = Window.TIMEOUT_NATIVEWINDOW; 0<sleep && !isFocusOwner(); sleep-=10 ) { - try { Thread.sleep(10); } catch (InterruptedException e) { } - } */ + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusAction: "+Display.getThreadName()+", isOnscreen "+isOnscreen+", hasFocus "+hasFocus()); } - return focusActionImpl.result; - } - - class FocusActionImpl implements Runnable { - public final boolean result = false; // NEWT shall always proceed requesting the native focus - public void run() { - if(DEBUG) { - System.err.println("FocusActionImpl.run() "+Display.getThreadName()); - } - NewtCanvasAWT.this.requestFocusAWTParent(); + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + if(!hasFocus()) { + // Acquire the AWT focus 1st for proper AWT traversal + NewtCanvasAWT.super.requestFocus(); + } + if(isOnscreen) { + // Remove the AWT focus in favor of the native NEWT focus KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } + return false; // NEWT shall proceed requesting the native focus } - FocusActionImpl focusActionImpl = new FocusActionImpl(); } - FocusAction focusAction = new FocusAction(); + private FocusAction focusAction = new FocusAction(); WindowListener clearAWTMenusOnNewtFocus = new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent arg0) { - MenuSelectionManager.defaultManager().clearSelectedPath(); + MenuSelectionManager.defaultManager().clearSelectedPath(); } }; - /** sets a new NEWT child, provoking reparenting on the NEWT level. */ - /*package */ NewtCanvasAWT setNEWTChild(Window child) { + class FocusTraversalKeyListener implements KeyListener { + boolean suppress = false; + + public void keyPressed(KeyEvent e) { + handleKey(e, false); + } + public void keyReleased(KeyEvent e) { + handleKey(e, true); + } + public void keyTyped(KeyEvent e) { + if(suppress) { + e.setAttachment(InputEvent.consumedTag); + suppress = false; // reset + } + } + + void handleKey(KeyEvent evt, boolean onRelease) { + if(null == keyboardFocusManager) { + throw new InternalError("XXX"); + } + final AWTKeyStroke ks = AWTKeyStroke.getAWTKeyStroke(evt.getKeyCode(), evt.getModifiers(), onRelease); + if(null != ks) { + final Set<AWTKeyStroke> fwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + final Set<AWTKeyStroke> bwdKeys = keyboardFocusManager.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + if(fwdKeys.contains(ks)) { + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey (fwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); + } + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocus(); + suppress = true; + } else if(bwdKeys.contains(ks)) { + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey (bwd): "+ks+", current focusOwner "+keyboardFocusManager.getFocusOwner()); + } + // Newt-EDT -> AWT-EDT may freeze Window's native peer requestFocus. + NewtCanvasAWT.this.transferFocusBackward(); + suppress = true; + } + } + if(suppress) { + evt.setAttachment(InputEvent.consumedTag); + } + if(DEBUG) { + System.err.println("NewtCanvasAWT.focusKey: XXX: "+ks); + } + } + } + private final FocusTraversalKeyListener newtFocusTraversalKeyListener = new FocusTraversalKeyListener(); + + class FocusPropertyChangeListener implements PropertyChangeListener { + public void propertyChange(PropertyChangeEvent evt) { + final Object oldF = evt.getOldValue(); + final Object newF = evt.getNewValue(); + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: "+evt.getPropertyName()+", src "+evt.getSource()+", "+oldF+" -> "+newF); + } + if(oldF == NewtCanvasAWT.this && newF == null) { + // focus traversal to NEWT - NOP + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: NEWT focus traversal"); + } + } else if(null != newF && newF != NewtCanvasAWT.this) { + // focus traversal to another AWT component + if(DEBUG) { + System.err.println("NewtCanvasAWT.FocusProperty: lost focus - clear focus"); + } + if(newtChild.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)newtChild.getDelegatedWindow()).clearFocus(); + } + } + } + } + private final FocusPropertyChangeListener focusPropertyChangeListener = new FocusPropertyChangeListener(); + private volatile KeyboardFocusManager keyboardFocusManager = null; + + /** sets a new NEWT child, provoking reparenting. */ + private NewtCanvasAWT setNEWTChild(Window child) { if(newtChild!=child) { newtChild = child; - if(null!=nativeWindow) { - java.awt.Container cont = AWTMisc.getContainer(this); + if(isDisplayable()) { // reparent right away, addNotify has been called already + final java.awt.Container cont = AWTMisc.getContainer(this); reparentWindow( (null!=child) ? true : false, cont ); } } @@ -162,8 +259,8 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, * or {@link #addNotify()} hasn't been called yet.*/ - public NativeWindow getNativeWindow() { return nativeWindow; } - + public NativeWindow getNativeWindow() { return jawtWindow; } + public int getDefaultCloseOperation() { return awtWindowClosingProtocol.getDefaultCloseOperation(); } @@ -177,13 +274,41 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto awtAdapter.removeFrom(this); awtAdapter=null; } + if(null!=awtMouseAdapter) { + awtMouseAdapter.removeFrom(this); + awtMouseAdapter = null; + } + if(null!=awtKeyAdapter) { + awtKeyAdapter.removeFrom(this); + awtKeyAdapter = null; + } + newtChild.setKeyboardFocusHandler(null); + if(null != keyboardFocusManager) { + keyboardFocusManager.removePropertyChangeListener("focusOwner", focusPropertyChangeListener); + keyboardFocusManager = null; + } + if( null != newtChild ) { if(attach) { + if(null == jawtWindow.getGraphicsConfiguration()) { + throw new InternalError("XXX"); + } + isOnscreen = jawtWindow.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this); newtChild.addWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(focusAction); // enable AWT focus traversal newtChildCloseOp = newtChild.setDefaultCloseOperation(WindowClosingProtocol.DO_NOTHING_ON_CLOSE); awtWindowClosingProtocol.addClosingListenerOneShot(); + keyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + keyboardFocusManager.addPropertyChangeListener("focusOwner", focusPropertyChangeListener); + if(isOnscreen) { + // onscreen newt child needs to fwd AWT focus + newtChild.setKeyboardFocusHandler(newtFocusTraversalKeyListener); + } else { + // offscreen newt child requires AWT to fwd AWT key/mouse event + awtMouseAdapter = new AWTMouseAdapter(newtChild).addTo(this); + awtKeyAdapter = new AWTKeyAdapter(newtChild).addTo(this); + } } else { newtChild.removeWindowListener(clearAWTMenusOnNewtFocus); newtChild.setFocusAction(null); @@ -232,26 +357,47 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto newtChild.setFocusAction(null); // no AWT focus traversal .. if(add) { - nativeWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); - if(null!=nativeWindow) { - if(DEBUG) { - System.err.println("NewtCanvasAWT.reparentWindow: "+newtChild); - } - final int w = cont.getWidth(); - final int h = cont.getHeight(); - setSize(w, h); - newtChild.setSize(w, h); - newtChild.reparentWindow(nativeWindow); - newtChild.setVisible(true); - configureNewtChild(true); - newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener - newtChild.windowRepaint(0, 0, w, h); + jawtWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); + jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); + if(DEBUG) { + System.err.println("NewtCanvasAWT.reparentWindow: newtChild: "+newtChild); + } + final int w; + final int h; + if(isPreferredSizeSet()) { + java.awt.Dimension d = getPreferredSize(); + w = d.width; + h = d.height; + } else { + final java.awt.Dimension min; + if(this.isMinimumSizeSet()) { + min = getMinimumSize(); + } else { + min = new java.awt.Dimension(0, 0); + } + java.awt.Insets ins = cont.getInsets(); + w = Math.max(min.width, cont.getWidth() - ins.left - ins.right); + h = Math.max(min.height, cont.getHeight() - ins.top - ins.bottom); } + setSize(w, h); + newtChild.setSize(w, h); + newtChild.reparentWindow(jawtWindow); + newtChild.setVisible(true); + configureNewtChild(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + newtChild.windowRepaint(0, 0, w, h); + + // force this AWT Canvas to be focus-able, + // since this it is completely covered by the newtChild (z-order). + setFocusable(true); } else { - configureNewtChild(false); - nativeWindow = null; + configureNewtChild(false); newtChild.setVisible(false); newtChild.reparentWindow(null); + if(null != jawtWindow) { + NewtFactoryAWT.destroyNativeWindow(jawtWindow); + jawtWindow=null; + } } } @@ -273,7 +419,10 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto System.err.println("NewtCanvasAWT.destroy(): "+newtChild+", from "+cont); } configureNewtChild(false); - nativeWindow = null; + if(null!=jawtWindow) { + NewtFactoryAWT.destroyNativeWindow(jawtWindow); + jawtWindow=null; + } newtChild.setVisible(false); newtChild.reparentWindow(null); newtChild.destroy(); @@ -282,7 +431,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto cont.remove(this); } } - } + } @Override public void paint(Graphics g) { @@ -299,14 +448,12 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } } - final void requestFocusAWTParent() { - super.requestFocusInWindow(); - } - - final void requestFocusNEWTChild() { + private final void requestFocusNEWTChild() { if(null!=newtChild) { newtChild.setFocusAction(null); - KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + if(isOnscreen) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + } newtChild.requestFocus(); newtChild.setFocusAction(focusAction); } diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java index 2e86cb512..a052f6f97 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtApplet1Run.java @@ -1,20 +1,48 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package com.jogamp.newt.awt.applet; -import java.applet.*; +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Button; import java.awt.Component; import java.awt.Container; -import java.awt.Label; +import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; -import java.awt.event.KeyListener; -import javax.media.opengl.*; +import javax.media.opengl.FPSCounter; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLProfile; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; -import java.awt.BorderLayout; - -import jogamp.newt.Debug; /** * Simple GLEventListener deployment as an applet using JOGL. This demo must be @@ -62,7 +90,7 @@ import jogamp.newt.Debug; */ @SuppressWarnings("serial") public class JOGLNewtApplet1Run extends Applet { - public static final boolean DEBUG = Debug.debug("Applet"); + public static final boolean DEBUG = JOGLNewtAppletBase.DEBUG; GLWindow glWindow; NewtCanvasAWT newtCanvasAWT; @@ -72,6 +100,9 @@ public class JOGLNewtApplet1Run extends Applet { boolean glStandalone = false; public void init() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.init() START"); + } if(!(this instanceof Container)) { throw new RuntimeException("This Applet is not a AWT Container"); } @@ -88,6 +119,7 @@ public class JOGLNewtApplet1Run extends Applet { int glAlphaBits=0; int glNumMultisampleBuffer=0; boolean glNoDefaultKeyListener = false; + boolean appletDebugTestBorder = false; try { glEventListenerClazzName = getParameter("gl_event_listener_class"); glProfileName = getParameter("gl_profile"); @@ -104,6 +136,7 @@ public class JOGLNewtApplet1Run extends Applet { glWidth = JOGLNewtAppletBase.str2Int(getParameter("gl_width"), glWidth); glHeight = JOGLNewtAppletBase.str2Int(getParameter("gl_height"), glHeight); glNoDefaultKeyListener = JOGLNewtAppletBase.str2Bool(getParameter("gl_nodefaultkeyListener"), glNoDefaultKeyListener); + appletDebugTestBorder = JOGLNewtAppletBase.str2Bool(getParameter("appletDebugTestBorder"), appletDebugTestBorder); } catch (Exception e) { e.printStackTrace(); } @@ -137,7 +170,6 @@ public class JOGLNewtApplet1Run extends Applet { glTrace); try { - GLProfile.initSingleton(false); GLCapabilities caps = new GLCapabilities(GLProfile.get(glProfileName)); caps.setAlphaBits(glAlphaBits); if(0<glNumMultisampleBuffer) { @@ -149,18 +181,12 @@ public class JOGLNewtApplet1Run extends Applet { glWindow.setUpdateFPSFrames(FPSCounter.DEFAULT_FRAMES_PER_INTERVAL, System.err); glWindow.setUndecorated(glUndecorated); glWindow.setAlwaysOnTop(glAlwaysOnTop); - if(glStandalone) { - newtCanvasAWT = null; - } else { - newtCanvasAWT = new NewtCanvasAWT(glWindow); - container.setLayout(new BorderLayout()); - container.add(newtCanvasAWT, BorderLayout.CENTER); - } - if(DEBUG) { - container.add(new Label("North"), BorderLayout.NORTH); - container.add(new Label("South"), BorderLayout.SOUTH); - container.add(new Label("East"), BorderLayout.EAST); - container.add(new Label("West"), BorderLayout.WEST); + container.setLayout(new BorderLayout()); + if(appletDebugTestBorder) { + container.add(new Button("North"), BorderLayout.NORTH); + container.add(new Button("South"), BorderLayout.SOUTH); + container.add(new Button("East"), BorderLayout.EAST); + container.add(new Button("West"), BorderLayout.WEST); } base.init(glWindow); if(base.isValid()) { @@ -176,12 +202,25 @@ public class JOGLNewtApplet1Run extends Applet { addKeyListener((KeyListener)glEventListener); } } + if(glStandalone) { + newtCanvasAWT = null; + } else { + newtCanvasAWT = new NewtCanvasAWT(glWindow); + container.add(newtCanvasAWT, BorderLayout.CENTER); + container.validate(); + } } catch (Throwable t) { throw new RuntimeException(t); } + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.init() END"); + } } public void start() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.start() START"); + } this.validate(); this.setVisible(true); @@ -195,21 +234,35 @@ public class JOGLNewtApplet1Run extends Applet { while (null != topC.getParent()) { topC = topC.getParent(); } + System.err.println("JOGLNewtApplet1Run start:"); System.err.println("TopComponent: "+topC.getLocation()+" rel, "+topC.getLocationOnScreen()+" screen, visible "+topC.isVisible()+", "+topC); System.err.println("Applet Pos: "+this.getLocation()+" rel, "+p0+" screen, visible "+this.isVisible()+", "+this); if(null != newtCanvasAWT) { System.err.println("NewtCanvasAWT Pos: "+newtCanvasAWT.getLocation()+" rel, "+newtCanvasAWT.getLocationOnScreen()+" screen, visible "+newtCanvasAWT.isVisible()+", "+newtCanvasAWT); } System.err.println("GLWindow Pos: "+glWindow.getX()+"/"+glWindow.getY()+" rel, "+glWindow.getLocationOnScreen(null)+" screen"); + System.err.println("GLWindow: "+glWindow); } base.start(); + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.start() END"); + } } public void stop() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.stop() START"); + } base.stop(); + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.stop() END"); + } } public void destroy() { + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.destroy() START"); + } glWindow.setVisible(false); // hide 1st if(!glStandalone) { glWindow.reparentWindow(null); // get out of newtCanvasAWT @@ -217,6 +270,9 @@ public class JOGLNewtApplet1Run extends Applet { } base.destroy(); // destroy glWindow unrecoverable base=null; + if(DEBUG) { + System.err.println("JOGLNewtApplet1Run.destroy() END"); + } } } diff --git a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java index b1061dd14..67da50210 100755 --- a/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java +++ b/src/newt/classes/com/jogamp/newt/awt/applet/JOGLNewtAppletBase.java @@ -1,18 +1,53 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package com.jogamp.newt.awt.applet; -import java.lang.reflect.*; +import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; import javax.media.nativewindow.NativeWindow; -import javax.media.opengl.*; +import javax.media.opengl.FPSCounter; +import javax.media.opengl.GL; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLPipelineFactory; import jogamp.newt.Debug; -import com.jogamp.opengl.util.*; - -import com.jogamp.newt.event.*; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.util.Animator; + /** Shows how to deploy an applet using JOGL. This demo must be referenced from a web page via an <applet> tag. */ @@ -165,6 +200,7 @@ public class JOGLNewtAppletBase implements KeyListener, GLEventListener { public void start() { if(isValid) { glWindow.setVisible(true); + glWindow.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); glAnimator.start(); awtParent = glWindow.getParent(); } diff --git a/src/newt/classes/com/jogamp/newt/event/InputEvent.java b/src/newt/classes/com/jogamp/newt/event/InputEvent.java index 51ceccf31..d8a9235c1 100644 --- a/src/newt/classes/com/jogamp/newt/event/InputEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/InputEvent.java @@ -48,6 +48,11 @@ public abstract class InputEvent extends NEWTEvent public static final int CONFINED_MASK = 1 << 16; public static final int INVISIBLE_MASK = 1 << 17; + /** Object when attached via {@link #setAttachment(Object)} marks the event consumed, + * ie. stops propagating the event any further to the event listener. + */ + public static final Object consumedTag = new Object(); + protected InputEvent(int eventType, Object source, long when, int modifiers) { super(eventType, source, when); this.modifiers=modifiers; diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java index 9e4fe372b..44fcea49c 100644 --- a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java @@ -34,6 +34,7 @@ package com.jogamp.newt.event; +@SuppressWarnings("serial") public class KeyEvent extends InputEvent { public KeyEvent(int eventType, Object source, long when, int modifiers, int keyCode, char keyChar) { @@ -42,9 +43,12 @@ public class KeyEvent extends InputEvent this.keyChar=keyChar; } + /** Only valid if delivered via {@link KeyListener#keyPressed(KeyEvent)} */ public char getKeyChar() { return keyChar; } + + /** Always valid. */ public int getKeyCode() { return keyCode; } diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java index ccc674f1d..9bc3be1e5 100644 --- a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java @@ -139,6 +139,20 @@ public class MouseEvent extends InputEvent return pressure[index]; } + /** + * <i>Usually</i> a wheel rotation of <b>> 0 is up</b>, + * and <b>< 0 is down</b>.<br> + * <i>However</i>, on some OS this might be flipped due to the OS <i>default</i> behavior. + * The latter is true for OS X 10.7 (Lion) for example. + * <p> + * The events will be send usually in steps of one, ie. <i>-1</i> and <i>1</i>. + * Higher values may result due to fast scrolling. + * </p> + * <p> + * The button number refers to the wheel number. + * </p> + * @return + */ public int getWheelRotation() { return wheelRotation; } diff --git a/src/newt/classes/com/jogamp/newt/event/MouseListener.java b/src/newt/classes/com/jogamp/newt/event/MouseListener.java index 5ec086b94..7668b755c 100644 --- a/src/newt/classes/com/jogamp/newt/event/MouseListener.java +++ b/src/newt/classes/com/jogamp/newt/event/MouseListener.java @@ -43,6 +43,8 @@ public interface MouseListener extends NEWTEventListener public void mouseReleased(MouseEvent e); public void mouseMoved(MouseEvent e); public void mouseDragged(MouseEvent e); + + /** See {@link MouseEvent#getWheelRotation() } */ public void mouseWheelMoved(MouseEvent e); } diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java index 50aed2c8e..3f3817b91 100644 --- a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java @@ -46,6 +46,7 @@ package com.jogamp.newt.event; * <li> KeyEvent <code>300..30x</code></li> * </ul><br> */ +@SuppressWarnings("serial") public class NEWTEvent extends java.util.EventObject { private final boolean isSystemEvent; private final int eventType; diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java index ae7474c73..69b0d0482 100644 --- a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java @@ -107,6 +107,9 @@ public class AWTWindowAdapter public void componentResized(java.awt.event.ComponentEvent e) { com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentResized: "+event); + } if(null!=newtListener) { ((com.jogamp.newt.event.WindowListener)newtListener).windowResized(event); } else { @@ -116,6 +119,9 @@ public class AWTWindowAdapter public void componentMoved(java.awt.event.ComponentEvent e) { com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentMoved: "+event); + } if(null!=newtListener) { ((com.jogamp.newt.event.WindowListener)newtListener).windowMoved(event); } else { diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 2cd8c2ced..92f57577d 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -41,6 +41,7 @@ import com.jogamp.common.GlueGenVersion; import com.jogamp.common.util.VersionUtil; import com.jogamp.newt.*; import com.jogamp.newt.event.*; + import jogamp.newt.WindowImpl; import javax.media.nativewindow.*; @@ -54,8 +55,8 @@ import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.util.Animator; /** - * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface, - * using an aggregation of a {@link com.jogamp.newt.Window} implementation. + * An implementation of {@link GLAutoDrawable} and {@link Window} interface, + * using a delegated {@link Window} instance, which may be an aggregation (lifecycle: created and destroyed). * <P> * This implementation does not make the OpenGL context current<br> * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br> @@ -121,12 +122,13 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC } /** - * Creates a new GLWindow attaching a new Window referencing a new Screen - * with the given GLCapabilities. - * <P> - * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed. - * <P> - * The default display connection will be used and reused if already in process. + * Creates a new GLWindow attaching a new Window referencing a + * new default Screen and default Display with the given GLCapabilities. + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> + * The default Display will be reused if already instantiated. */ public static GLWindow create(GLCapabilitiesImmutable caps) { return new GLWindow(NewtFactory.createWindow(caps)); @@ -135,8 +137,10 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC /** * Creates a new GLWindow attaching a new Window referencing the given Screen * with the given GLCapabilities. - * <P> - * The resulting GLWindow owns the Window, ie it will be destructed. + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> */ public static GLWindow create(Screen screen, GLCapabilitiesImmutable caps) { return new GLWindow(NewtFactory.createWindow(screen, caps)); @@ -144,8 +148,10 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC /** * Creates a new GLWindow attaching the given window. - * <P> - * The resulting GLWindow does not own the given Window, ie it will not be destructed. + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> */ public static GLWindow create(Window window) { return new GLWindow(window); @@ -154,11 +160,15 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC /** * Creates a new GLWindow attaching a new child Window * of the given <code>parentNativeWindow</code> with the given GLCapabilities. - * <P> + * <p> * The Display/Screen will be compatible with the <code>parentNativeWindow</code>, * or even identical in case it's a Newt Window. - * <P> - * The resulting GLWindow owns the Window, ie it will be destructed. + * An already instantiated compatible Display will be reused. + * </p> + * <p> + * The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()} + * and {@link Screen#removeReference()}. + * </p> */ public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilitiesImmutable caps) { return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps)); @@ -195,8 +205,8 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC return window.getRequestedCapabilities(); } - public final Window getWindow() { - return window; + public final Window getDelegatedWindow() { + return window.getDelegatedWindow(); } public final NativeWindow getParent() { @@ -254,10 +264,18 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC window.setFocusAction(focusAction); } + public void setKeyboardFocusHandler(KeyListener l) { + window.setKeyboardFocusHandler(l); + } + public final void requestFocus() { window.requestFocus(); } + public final void requestFocus(boolean wait) { + window.requestFocus(wait); + } + public boolean hasFocus() { return window.hasFocus(); } @@ -288,7 +306,7 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC @Override public final String toString() { return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + - ", \n\tContext: " + context + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; + ", \n\tContext: " + context + ", \n\tWindow: "+window+ /** ", \n\tFactory: "+factory+ */ "]"; } public final int reparentWindow(NativeWindow newParent) { @@ -337,14 +355,6 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC // Hide methods here .. protected class GLLifecycleHook implements WindowImpl.LifecycleHook { - private class DisposeAction implements Runnable { - public final void run() { - // Lock: Covered by DestroyAction .. - helper.dispose(GLWindow.this); - } - } - DisposeAction disposeAction = new DisposeAction(); - public synchronized void destroyActionPreLock() { // nop } @@ -362,11 +372,10 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC // Catch dispose GLExceptions by GLEventListener, just 'print' them // so we can continue with the destruction. try { - helper.invokeGL(drawable, context, disposeAction, null); + helper.disposeGL(GLWindow.this, drawable, context, null); } catch (GLException gle) { gle.printStackTrace(); } - context.destroy(); } drawable.setRealized(false); } @@ -399,11 +408,11 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { NativeWindow nw; if (window.getWrappedWindow() != null) { - nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); + nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getPrivateGraphicsConfiguration()); } else { nw = window; } - GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities(); if(null==factory) { factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); } @@ -753,18 +762,6 @@ public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer, FPSC window.runOnEDTIfAvail(wait, task); } - public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - return window.getSurfaceUpdatedListener(index); - } - - public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - return window.getSurfaceUpdatedListeners(); - } - - public final void removeAllSurfaceUpdatedListener() { - window.removeAllSurfaceUpdatedListener(); - } - public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { window.removeSurfaceUpdatedListener(l); } diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java index c7780b0d8..e71ef75ec 100644 --- a/src/newt/classes/com/jogamp/newt/util/MainThread.java +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -93,17 +93,21 @@ import jogamp.newt.NEWTJNILibLoader; */ public class MainThread { private static final String MACOSXDisplayClassName = "jogamp.newt.driver.macosx.MacDisplay"; + private static final Platform.OSType osType; + private static final boolean isMacOSX; + /** if true, use the main thread EDT, otherwise AWT's EDT */ public static final boolean HINT_USE_MAIN_THREAD; static { final AccessControlContext localACC = AccessController.getContext(); - Platform.initSingleton(); NativeWindowFactory.initSingleton(true); NEWTJNILibLoader.loadNEWT(); HINT_USE_MAIN_THREAD = !NativeWindowFactory.isAWTAvailable() || - Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + osType = Platform.getOSType(); + isMacOSX = osType == Platform.OSType.MACOS; } public static boolean useMainThread = false; @@ -132,7 +136,7 @@ public class MainThread { try { Class<?> mainClass = ReflectionUtil.getClass(mainClassName, true, getClass().getClassLoader()); if(null==mainClass) { - throw new RuntimeException(new ClassNotFoundException("MainThread couldn't find main class "+mainClassName)); + throw new RuntimeException(new ClassNotFoundException("MainAction couldn't find main class "+mainClassName)); } try { mainClassMain = mainClass.getDeclaredMethod("main", new Class[] { String[].class }); @@ -151,8 +155,23 @@ public class MainThread { if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin"); if ( useMainThread ) { - if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - stop"); - System.exit(0); + if(isMacOSX) { + try { + if(DEBUG) { + System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.0"); + } + ReflectionUtil.callStaticMethod(MACOSXDisplayClassName, "stopNSApplication", + null, null, MainThread.class.getClassLoader()); + if(DEBUG) { + System.err.println("MainAction.main(): "+Thread.currentThread()+" MainAction fin - stopNSApp.X"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } else { + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainAction fin - System.exit(0)"); + System.exit(0); + } } } } @@ -164,9 +183,6 @@ public class MainThread { useMainThread = HINT_USE_MAIN_THREAD; - final Platform.OSType osType = Platform.getOSType(); - final boolean isMacOSX = osType == Platform.OSType.MACOS; - if(DEBUG) { System.err.println("MainThread.main(): "+cur.getName()+ ", useMainThread "+ useMainThread + diff --git a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java index 5a8bf5bf2..8104f207a 100644 --- a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java +++ b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java @@ -43,8 +43,9 @@ public class MonitorMode { int refreshRate; public MonitorMode(SurfaceSize surfaceSize, DimensionImmutable screenSizeMM, int refreshRate) { - if(null==surfaceSize || refreshRate<=0) { - throw new IllegalArgumentException("surfaceSize must be set and refreshRate greater 0"); + // Don't validate screenSizeMM and refreshRate, since they may not be supported by the OS + if(null==surfaceSize) { + throw new IllegalArgumentException("surfaceSize must be set ("+surfaceSize+")"); } this.surfaceSize=surfaceSize; this.screenSizeMM=screenSizeMM; diff --git a/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java b/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java index 1f5d5dd3d..78707e7cf 100644 --- a/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java +++ b/src/newt/classes/jogamp/newt/NEWTJNILibLoader.java @@ -43,6 +43,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import com.jogamp.common.jvm.JNILibLoaderBase; +import com.jogamp.common.os.Platform; import com.jogamp.common.util.cache.TempJarCache; public class NEWTJNILibLoader extends JNILibLoaderBase { @@ -50,9 +51,10 @@ public class NEWTJNILibLoader extends JNILibLoaderBase { public static void loadNEWT() { AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { + Platform.initSingleton(); final String libName = "newt"; if(TempJarCache.isInitialized() && null == TempJarCache.findLibrary(libName)) { - addNativeJarLibs(NEWTJNILibLoader.class, "jogl.all", "jogl-all", new String[] { "nativewindow", "newt" } ); + addNativeJarLibs(NEWTJNILibLoader.class, "jogl-all", new String[] { "nativewindow", "newt" } ); } loadLibrary(libName, false); return null; diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java index fa7bafe5b..050e24b6c 100644 --- a/src/newt/classes/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java @@ -48,18 +48,16 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { static long nextWindowHandle = 0x100; // start here - a marker protected void createNativeImpl() { - if(0!=getParentWindowHandle()) { - throw new NativeWindowException("OffscreenWindow does not support window parenting"); - } if(capsRequested.isOnscreen()) { throw new NativeWindowException("Capabilities is onscreen"); } - AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); - config = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration( - capsRequested, capsRequested, capabilitiesChooser, aScreen); - if (config == null) { + final AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration( + capsRequested, capsRequested, capabilitiesChooser, aScreen); + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); synchronized(OffscreenWindow.class) { setWindowHandle(nextWindowHandle++); @@ -70,6 +68,10 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { // nop } + public void surfaceSizeChanged(int width, int height) { + sizeChanged(false, width, height, false); + } + @Override public synchronized void destroy() { super.destroy(); @@ -89,29 +91,30 @@ public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { } @Override - public void setSize(int width, int height) { - if(!isVisible()) { - sizeChanged(false, width, height, false); - } - } - @Override public void setPosition(int x, int y) { // nop } + @Override public boolean setFullscreen(boolean fullscreen) { // nop return false; } - + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { sizeChanged(false, width, height, false); - visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); + visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); } else { - shouldNotCallThis(); + /** + * silently ignore: + FLAG_CHANGE_PARENTING + FLAG_CHANGE_DECORATION + FLAG_CHANGE_FULLSCREEN + FLAG_CHANGE_ALWAYSONTOP + */ } - return false; + return true; } @Override diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index 9c51fe973..575de6112 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -34,6 +34,21 @@ package jogamp.newt; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.SurfaceSize; + import com.jogamp.common.util.ArrayHashSet; import com.jogamp.common.util.IntIntHashMap; import com.jogamp.newt.Display; @@ -44,14 +59,6 @@ import com.jogamp.newt.event.ScreenModeListener; import com.jogamp.newt.util.MonitorMode; import com.jogamp.newt.util.ScreenModeUtil; -import javax.media.nativewindow.*; -import javax.media.nativewindow.util.DimensionImmutable; -import javax.media.nativewindow.util.SurfaceSize; - -import java.security.*; -import java.util.ArrayList; -import java.util.List; - public abstract class ScreenImpl extends Screen implements ScreenModeListener { protected static final boolean DEBUG_TEST_SCREENMODE_DISABLED = Debug.isPropertyDefined("newt.test.Screen.disableScreenMode", true); @@ -61,8 +68,10 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { protected int hashCode; protected AbstractGraphicsScreen aScreen; protected int refCount; // number of Screen references by Window - protected int width=-1, height=-1; // detected values: set using setScreenSize - protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight + protected Point vOrigin = new Point(0, 0); // virtual top-left origin + protected Dimension vSize = new Dimension(0, 0); // virtual rotated screen size + protected static Dimension usrSize = null; // property values: newt.ws.swidth and newt.ws.sheight + protected static volatile boolean usrSizeQueried = false; private static AccessControlContext localACC = AccessController.getContext(); private ArrayList<ScreenModeListener> referencedScreenModeListener = new ArrayList<ScreenModeListener>(); long t0; // creationTime @@ -100,32 +109,36 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { return (Class<? extends Screen>)screenClass; } - public static Screen create(Display display, final int idx) { + public static Screen create(Display display, int idx) { try { - if(usrWidth<0 || usrHeight<0) { + if(!usrSizeQueried) { synchronized (Screen.class) { - if(usrWidth<0 || usrHeight<0) { - usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); - usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); - if(usrWidth>0 || usrHeight>0) { - System.err.println("User screen size "+usrWidth+"x"+usrHeight); + if(!usrSizeQueried) { + usrSizeQueried = true; + final int w = Debug.getIntProperty("newt.ws.swidth", true, localACC); + final int h = Debug.getIntProperty("newt.ws.sheight", true, localACC); + if(w>0 && h>0) { + usrSize = new Dimension(w, h); + System.err.println("User screen size "+usrSize); } } } } synchronized(screenList) { + Class<? extends Screen> screenClass = getScreenClass(display.getType()); + ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); + screen.display = (DisplayImpl) display; + idx = screen.validateScreenIndex(idx); { Screen screen0 = ScreenImpl.getLastScreenOf(display, idx, -1); if(null != screen0) { if(DEBUG) { System.err.println("Screen.create() REUSE: "+screen0+" "+Display.getThreadName()); } + screen = null; return screen0; } } - Class<? extends Screen> screenClass = getScreenClass(display.getType()); - ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); - screen.display = (DisplayImpl) display; screen.screen_idx = idx; screen.fqname = (display.getFQName()+idx).intern(); screen.hashCode = screen.fqname.hashCode(); @@ -176,6 +189,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { throw new NativeWindowException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); } initScreenModeStatus(); + updateVirtualScreenOriginAndSize(); if(DEBUG) { System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")"); } @@ -208,6 +222,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public synchronized final int addReference() throws NativeWindowException { if(DEBUG) { System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + // Thread.dumpStack(); } if ( 0 == refCount ) { createNative(); @@ -220,10 +235,8 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public synchronized final int removeReference() { if(DEBUG) { - String msg = "Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1); - // Throwable t = new Throwable(msg); - // t.printStackTrace(); - System.err.println(msg); + System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + // Thread.dumpStack(); } refCount--; // could become < 0, in case of manual destruction without actual creation/addReference if(0>=refCount) { @@ -239,19 +252,37 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { protected abstract void createNativeImpl(); protected abstract void closeNativeImpl(); - + + /** + * Returns the validated screen index, which is either the passed <code>idx</code> + * value or <code>0</code>. + * <p> + * On big-desktops this shall return always 0. + * </p> + */ + protected abstract int validateScreenIndex(int idx); + + /** + * Stores the virtual origin and virtual <b>rotated</b> screen size. + * <p> + * This method is called after the ScreenMode has been set, + * hence you may utilize it. + * </p> + * @param virtualOrigin the store for the virtual origin + * @param virtualSize the store for the virtual rotated size + */ + protected abstract void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize); + public final String getFQName() { return fqname; } /** - * Set the <b>rotated</b> ScreenSize. - * @see com.jogamp.newt.ScreenMode#getRotatedWidth() - * @see com.jogamp.newt.ScreenMode#getRotatedHeight() + * Updates the <b>rotated</b> virtual ScreenSize using the native impl. */ - protected void setScreenSize(int w, int h) { - System.err.println("Detected screen size "+w+"x"+h); - width=w; height=h; + protected void updateVirtualScreenOriginAndSize() { + getVirtualScreenOriginAndSize(vOrigin, vSize); + System.err.println("Detected screen origin "+vOrigin+", size "+vSize); } public final Display getDisplay() { @@ -270,21 +301,15 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { return null != aScreen; } + public int getX() { return vOrigin.getX(); } + public int getY() { return vOrigin.getY(); } - /** - * @return the <b>rotated</b> width. - * @see com.jogamp.newt.ScreenMode#getRotatedWidth() - */ public final int getWidth() { - return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; + return (null != usrSize) ? usrSize.getWidth() : vSize.getWidth(); } - /** - * @return the <b>rotated</b> height - * @see com.jogamp.newt.ScreenMode#getRotatedHeight() - */ public final int getHeight() { - return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; + return (null != usrSize) ? usrSize.getHeight() : vSize.getHeight(); } @Override @@ -347,32 +372,29 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { try { long t0=0, t1=0; if(DEBUG) { - System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.0 "+screenMode); + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.0 "+smU); t0 = System.currentTimeMillis(); } sms.fireScreenModeChangeNotify(smU); if(DEBUG) { - System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.1 "+screenMode); + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.1 "+smU); t1 = System.currentTimeMillis(); } success = setCurrentScreenModeImpl(smU); - if(success) { - setScreenSize(screenMode.getRotatedWidth(), screenMode.getRotatedHeight()); - } if(DEBUG) { t1 = System.currentTimeMillis() - t1; - System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.0 "+screenMode+", success: "+success); + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.0 "+smU+", success: "+success); } sms.fireScreenModeChanged(smU, success); if(DEBUG) { t0 = System.currentTimeMillis() - t0; - System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.X "+screenMode+", success: "+success+ + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.X "+smU+", success: "+success+ " - dt0 "+t0+"ms, dt1 "+t1+"ms"); } } finally { @@ -389,7 +411,7 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { public void screenModeChanged(ScreenMode sm, boolean success) { if(success) { - setScreenSize(sm.getRotatedWidth(), sm.getRotatedHeight()); + updateVirtualScreenOriginAndSize(); } for(int i=0; i<referencedScreenModeListener.size(); i++) { ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChanged(sm, success); @@ -502,11 +524,12 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { } ArrayHashSet<ScreenMode> screenModes = collectNativeScreenModes(screenModesIdx2NativeIdx); - if(screenModes.size()==0) { - if(DEBUG) { - System.err.println("ScreenImpl.initScreenModeStatus: added current (last resort, collect failed): "+currentSM); + screenModes.getOrAdd(currentSM); + if(DEBUG) { + int i=0; + for(Iterator<ScreenMode> iter=screenModes.iterator(); iter.hasNext(); i++) { + System.err.println(i+": "+iter.next()); } - screenModes.getOrAdd(currentSM); } sms = new ScreenModeStatus(screenModes, screenModesIdx2NativeIdx); @@ -550,9 +573,18 @@ public abstract class ScreenImpl extends Screen implements ScreenModeListener { int nativeId = smProps[0]; int screenModeIdx = ScreenModeUtil.streamIn(resolutionPool, surfaceSizePool, screenSizeMMPool, monitorModePool, screenModePool, smProps, 1); + if(DEBUG) { + System.err.println("ScreenImpl.collectNativeScreenModes: #"+num+": idx: "+nativeId+" native -> "+screenModeIdx+" newt"); + } + if(screenModeIdx >= 0) { screenModesIdx2NativeId.put(screenModeIdx, nativeId); } + } else if(DEBUG) { + System.err.println("ScreenImpl.collectNativeScreenModes: #"+num+": smProps: "+(null!=smProps)+ + ", len: "+(null != smProps ? smProps.length : 0)+ + ", bpp: "+(null != smProps && 0 < smProps.length ? smProps[idxBpp] : 0)+ + " - DROPPING"); } num++; } while ( null != smProps && 0 < smProps.length ); diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 7df326e8e..6564857e4 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -72,6 +72,8 @@ import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.Rectangle; +import jogamp.nativewindow.SurfaceUpdatedHelper; + public abstract class WindowImpl implements Window, NEWTEventConsumer { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); @@ -85,12 +87,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private boolean screenReferenceAdded = false; private NativeWindow parentWindow = null; private long parentWindowHandle = 0; - protected AbstractGraphicsConfiguration config = null; + private AbstractGraphicsConfiguration config = null; // control access due to delegation protected CapabilitiesImmutable capsRequested = null; protected CapabilitiesChooser capabilitiesChooser = null; // default null -> default protected boolean fullscreen = false, hasFocus = false; protected int width = 128, height = 128; // client-area size w/o insets, default: may be overwritten by user - protected int x = -1, y = -1; // client-area pos w/o insets, default: undefined (allow WM to choose if not set by user) + protected int x = 64, y = 64; // client-area pos w/o insets + protected boolean autoPosition = true; // default: true (allow WM to choose if not set by user) protected Insets insets = new Insets(); // insets of decoration (if top-level && decorated) protected int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen client-area size/pos w/o insets @@ -108,10 +111,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private RequestFocusAction requestFocusAction = new RequestFocusAction(); private FocusRunnable focusAction = null; + private KeyListener keyboardFocusHandler = null; - private Object surfaceUpdatedListenersLock = new Object(); - private ArrayList<SurfaceUpdatedListener> surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); - + private SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + private Object childWindowsLock = new Object(); private ArrayList<NativeWindow> childWindows = new ArrayList<NativeWindow>(); @@ -213,6 +216,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } + protected final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) { + config = cfg; + } + public static interface LifecycleHook { /** * Reset of internal state counter, ie totalFrames, etc. @@ -270,8 +277,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer NativeSurface.LOCK_SURFACE_NOT_READY >= parentWindow.lockSurface() ) { throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); } - if( ( 0>x || 0>y ) && ( isUndecorated() || null != parentWindow ) ) { - // default child/undecorated window position is 0/0, if not set by user + if( ( 0>x || 0>y ) && null != parentWindow ) { + // min. child window position is 0/0 x = 0; y = 0; } try { @@ -545,7 +552,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if ( LOCK_SURFACE_NOT_READY == res ) { try { if( isNativeValid() ) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); adevice.lock(); try { res = lockSurfaceImpl(); @@ -570,7 +577,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer windowLock.validateLocked(); if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = config.getScreen().getDevice(); + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); try { unlockSurfaceImpl(); } finally { @@ -613,8 +620,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return false; } - public AbstractGraphicsConfiguration getGraphicsConfiguration() { - return config; + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); } public final long getDisplayHandle() { @@ -682,6 +689,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return screen; } + protected final void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible)); + } final void setVisibleActionImpl(boolean visible) { boolean nativeWindowCreated = false; boolean madeVisible = false; @@ -740,8 +750,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( nativeWindowCreated || madeVisible ) { sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener } - } - + } private class VisibleAction implements Runnable { boolean visible; @@ -752,8 +761,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public final void run() { setVisibleActionImpl(visible); } - } - + } public void setVisible(boolean visible) { if(DEBUG_IMPLEMENTATION) { System.err.println("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+(null!=parentWindow)); @@ -762,59 +770,67 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer runOnEDTIfAvail(true, new VisibleAction(visible)); } - protected final void setVisibleImpl(boolean visible, int x, int y, int width, int height) { - reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, visible)); + final void setSizeActionImpl(int width, int height) { + boolean recreate = false; + windowLock.lock(); + try { + int visibleAction = 0; // 1 invisible, 2 visible (create) + if ( !fullscreen && ( width != WindowImpl.this.width || WindowImpl.this.height != height ) ) { + recreate = isNativeValid() && !getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: START "+WindowImpl.this.width+"x"+WindowImpl.this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible+", recreate "+recreate); + } + if(recreate) { + // will trigger visibleAction:=2 -> create if wasVisible + final boolean wasVisible = WindowImpl.this.visible; + screen.addReference(); // retain screen + destroyAction.run(); + WindowImpl.this.visible = wasVisible; + } + if ( isNativeValid() && 0>=width*height && visible ) { + visibleAction=1; // invisible + WindowImpl.this.width = 0; + WindowImpl.this.height = 0; + } else if ( !isNativeValid() && 0<width*height && visible ) { + visibleAction = 2; // visible (create) + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } else if ( isNativeValid() ) { + // this width/height will be set by windowChanged, called by the native implementation + reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(0, isVisible())); + } else { + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: END "+WindowImpl.this.width+"x"+WindowImpl.this.height+", visibleAction "+visibleAction); + } + switch(visibleAction) { + case 1: setVisibleActionImpl(false); break; + case 2: setVisibleActionImpl(true); break; + } + } + } finally { + if(recreate) { + screen.removeReference(); // bring back ref-count + } + windowLock.unlock(); + } } - - private class SetSizeActionImpl implements Runnable { + private class SetSizeAction implements Runnable { int width, height; - private SetSizeActionImpl(int w, int h) { + private SetSizeAction(int w, int h) { width = w; height = h; } public final void run() { - windowLock.lock(); - try { - int visibleAction = 0; // 1 invisible, 2 visible (create) - if ( !fullscreen && ( width != WindowImpl.this.width || WindowImpl.this.height != height ) ) { - if(DEBUG_IMPLEMENTATION) { - String msg = "Window setSize: START "+WindowImpl.this.width+"x"+WindowImpl.this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible; - System.err.println(msg); - } - if ( isNativeValid() && 0>=width*height && visible ) { - visibleAction=1; // invisible - WindowImpl.this.width = 0; - WindowImpl.this.height = 0; - } else if ( !isNativeValid() && 0<width*height && visible ) { - visibleAction = 2; // visible (create) - WindowImpl.this.width = width; - WindowImpl.this.height = height; - } else if ( isNativeValid() ) { - // this width/height will be set by windowChanged, called by the native implementation - reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(0, isVisible())); - } else { - WindowImpl.this.width = width; - WindowImpl.this.height = height; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setSize: END "+WindowImpl.this.width+"x"+WindowImpl.this.height+", visibleAction "+visibleAction); - } - switch(visibleAction) { - case 1: setVisibleActionImpl(false); break; - case 2: setVisibleActionImpl(true); break; - } - } - } finally { - windowLock.unlock(); - } + setSizeActionImpl(width, height); } - } - + } public void setSize(int width, int height) { - runOnEDTIfAvail(true, new SetSizeActionImpl(width, height)); - } - + runOnEDTIfAvail(true, new SetSizeAction(width, height)); + } public void setTopLevelSize(int width, int height) { setSize(width - getInsets().getTotalWidth(), height - getInsets().getTotalHeight()); } @@ -911,6 +927,22 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer runOnEDTIfAvail(true, destroyAction); } + /** + * @param cWin child window, must not be null + * @param pWin parent window, may be null + * @return true if at least one of both window's configurations is offscreen + */ + protected static boolean isOffscreenInstance(NativeWindow cWin, NativeWindow pWin) { + boolean ofs = false; + if( null != cWin.getGraphicsConfiguration() ) { + ofs = !cWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + } + if( !ofs && null != pWin && null != pWin.getGraphicsConfiguration() ) { + ofs |= !pWin.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); + } + return ofs; + } + private class ReparentActionImpl implements Runnable, ReparentAction { NativeWindow newParentWindow; boolean forceDestroyCreate; @@ -918,7 +950,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private ReparentActionImpl(NativeWindow newParentWindow, boolean forceDestroyCreate) { this.newParentWindow = newParentWindow; - this.forceDestroyCreate = forceDestroyCreate; + this.forceDestroyCreate = forceDestroyCreate | DEBUG_TEST_REPARENT_INCOMPATIBLE; this.reparentAction = -1; // ensure it's set } @@ -927,10 +959,10 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } private void setScreen(ScreenImpl newScreen) { // never null ! - WindowImpl.this.removeScreenReference(); + removeScreenReference(); screen = newScreen; } - + public final void run() { boolean animatorPaused = false; if(null!=lifecycleHook) { @@ -952,6 +984,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer windowLock.lock(); try { + if(isNativeValid()) { + // force recreation if offscreen, since it may become onscreen + forceDestroyCreate |= isOffscreenInstance(WindowImpl.this, newParentWindow); + } + wasVisible = isVisible(); Window newParentWindowNEWT = null; @@ -962,7 +999,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer long newParentWindowHandle = 0 ; if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE+" "+x+"/"+y+" "+width+"x"+height); + System.err.println("Window.reparent: START ("+getThreadName()+") valid "+isNativeValid()+", windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", "+x+"/"+y+" "+width+"x"+height); } if(null!=lifecycleHook) { @@ -1013,8 +1050,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else { reparentAction = ACTION_NATIVE_CREATION_PENDING; } - } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate || - !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { + } else if ( forceDestroyCreate || !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { // Destroy this window, may create a new compatible Screen/Display, // and mark it for creation. destroy(); @@ -1045,7 +1081,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if( 0 == parentWindowHandle ) { // Already Top Window reparentAction = ACTION_UNCHANGED; - } else if( !isNativeValid() || DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { + } else if( !isNativeValid() || forceDestroyCreate ) { // Destroy this window and mark it for [pending] creation. destroy(); if( 0<width*height ) { @@ -1138,7 +1174,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer ok = WindowImpl.this.waitForSize(width, height, false, TIMEOUT_NATIVEWINDOW); } if(ok) { - requestFocusImpl(true); + requestFocusInt(true); display.dispatchMessagesNative(); // status up2date } } @@ -1208,7 +1244,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { - ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); + final ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); runOnEDTIfAvail(true, reparentAction); return reparentAction.getStrategy(); } @@ -1220,7 +1256,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public final CapabilitiesImmutable getChosenCapabilities() { - return config.getNativeGraphicsConfiguration().getChosenCapabilities(); + return getGraphicsConfiguration().getChosenCapabilities(); } public final CapabilitiesImmutable getRequestedCapabilities() { @@ -1385,14 +1421,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - public void requestFocus() { - enqueueRequestFocus(true); - } - - public final boolean hasFocus() { - return hasFocus; - } - public final InsetsImmutable getInsets() { if(isUndecorated()) { return Insets.getZero(); @@ -1452,7 +1480,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer public Object getWrappedWindow() { return null; } - + + public final Window getDelegatedWindow() { + return this; + } + /** * If set to true, the default value, this NEWT Window implementation will * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.<br> @@ -1466,6 +1498,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // WindowImpl // + /** + * Returns the non delegated {@link AbstractGraphicsConfiguration}, + * see {@link #getGraphicsConfiguration()}. */ + public final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { + return config; + } + protected final long getParentWindowHandle() { return isFullscreen() ? 0 : parentWindowHandle; } @@ -1487,9 +1526,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer "\n, WrappedWindow "+getWrappedWindow()+ "\n, ChildWindows "+childWindows.size()); - sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); - for (int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { - sb.append(surfaceUpdatedListeners.get(i)+", "); + sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedHelper.size()+" ["); + for (int i = 0; i < surfaceUpdatedHelper.size(); i++ ) { + sb.append(surfaceUpdatedHelper.get(i)+", "); } sb.append("], WindowListeners num "+windowListeners.size()+" ["); for (int i = 0; i < windowListeners.size(); i++ ) { @@ -1503,7 +1542,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer for (int i = 0; i < keyListeners.size(); i++ ) { sb.append(keyListeners.get(i)+", "); } - sb.append("] ]"); + sb.append("], surfaceLock "+surfaceLock); + sb.append(", windowLock "+windowLock+"]"); return sb.toString(); } @@ -1529,21 +1569,32 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } } - protected void enqueueRequestFocus(boolean wait) { - runOnEDTIfAvail(wait, requestFocusAction); + public final boolean hasFocus() { + return hasFocus; } - /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. - * This allows notifying a covered window toolkit like AWT that the focus is requested, - * hence focus traversal can be made transparent. - */ + public void requestFocus() { + requestFocus(true); + } + + public void requestFocus(boolean wait) { + if(isNativeValid() && !focusAction()) { + runOnEDTIfAvail(wait, requestFocusAction); + } + } + + /** Internal request focus on current thread */ + private void requestFocusInt(boolean force) { + if(!focusAction()) { + requestFocusImpl(force); + } + } + public void setFocusAction(FocusRunnable focusAction) { this.focusAction = focusAction; } - - /** Called by native requestFocusImpl() */ - protected boolean focusAction() { + + private boolean focusAction() { if(DEBUG_IMPLEMENTATION) { System.err.println("Window.focusAction() START - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())); } @@ -1558,7 +1609,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } return res; } - + + public void setKeyboardFocusHandler(KeyListener l) { + keyboardFocusHandler = l; + } + private class SetPositionActionImpl implements Runnable { int x, y; @@ -1590,6 +1645,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public void setPosition(int x, int y) { + autoPosition = false; runOnEDTIfAvail(true, new SetPositionActionImpl(x, y)); } @@ -1622,7 +1678,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer nfs_y = WindowImpl.this.y; nfs_width = WindowImpl.this.width; nfs_height = WindowImpl.this.height; - x = 0; y = 0; + x = screen.getX(); + y = screen.getY(); w = screen.getWidth(); h = screen.getHeight(); } else { @@ -1680,7 +1737,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer display.dispatchMessagesNative(); // status up2date WindowImpl.this.waitForSize(w, h, false, TIMEOUT_NATIVEWINDOW); display.dispatchMessagesNative(); // status up2date - requestFocusImpl(true); + requestFocusInt(true); display.dispatchMessagesNative(); // status up2date if(DEBUG_IMPLEMENTATION) { @@ -1800,8 +1857,8 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // queue event in case window is locked, ie in operation if( isWindowLocked() ) { if(DEBUG_IMPLEMENTATION) { - // System.err.println("Window.consumeEvent: queued "+e); - // Thread.dumpStack(); // JAU + System.err.println("Window.consumeEvent: queued "+e); + // Thread.dumpStack(); } return false; } @@ -1824,62 +1881,20 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // // SurfaceUpdatedListener Support // - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - addSurfaceUpdatedListener(-1, l); + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); } - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) - throws IndexOutOfBoundsException - { - if(l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size(); - } - surfaceUpdatedListeners.add(index, l); - } + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); } public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - if (l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); - } - } - - public void removeAllSurfaceUpdatedListener() { - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList<SurfaceUpdatedListener>(); - } - } - - public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size()-1; - } - return surfaceUpdatedListeners.get(index); - } - } - - public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - synchronized(surfaceUpdatedListenersLock) { - return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); - } + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); } public void surfaceUpdated(Object updater, NativeSurface ns, long when) { - synchronized(surfaceUpdatedListenersLock) { - for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { - SurfaceUpdatedListener l = surfaceUpdatedListeners.get(i); - l.surfaceUpdated(updater, ns, when); - } - } + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); } // @@ -1893,8 +1908,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer int x, int y, int button, int rotation) { doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); } - private void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { + + protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { if(eventType == MouseEvent.EVENT_MOUSE_ENTERED || eventType == MouseEvent.EVENT_MOUSE_EXITED) { if(eventType == MouseEvent.EVENT_MOUSE_EXITED && x==-1 && y==-1) { @@ -2026,15 +2042,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public MouseListener[] getMouseListeners() { - return (MouseListener[]) mouseListeners.toArray(); + return mouseListeners.toArray(new MouseListener[mouseListeners.size()]); } protected void consumeMouseEvent(MouseEvent e) { if(DEBUG_MOUSE_EVENT) { System.err.println("consumeMouseEvent: event: "+e); } - - for(int i = 0; i < mouseListeners.size(); i++ ) { + boolean consumed = false; + for(int i = 0; !consumed && i < mouseListeners.size(); i++ ) { MouseListener l = mouseListeners.get(i); switch(e.getEventType()) { case MouseEvent.EVENT_MOUSE_CLICKED: @@ -2064,13 +2080,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer default: throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); } + consumed = InputEvent.consumedTag == e.getAttachment(); } } // // KeyListener/Event Support // - public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); } @@ -2116,29 +2132,42 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public KeyListener[] getKeyListeners() { - return (KeyListener[]) keyListeners.toArray(); + return keyListeners.toArray(new KeyListener[keyListeners.size()]); } - protected void consumeKeyEvent(KeyEvent e) { - if(DEBUG_KEY_EVENT) { - System.err.println("consumeKeyEvent: "+e); + private final boolean propagateKeyEvent(KeyEvent e, KeyListener l) { + switch(e.getEventType()) { + case KeyEvent.EVENT_KEY_PRESSED: + l.keyPressed(e); + break; + case KeyEvent.EVENT_KEY_RELEASED: + l.keyReleased(e); + break; + case KeyEvent.EVENT_KEY_TYPED: + l.keyTyped(e); + break; + default: + throw new NativeWindowException("Unexpected key event type " + e.getEventType()); } - for(int i = 0; i < keyListeners.size(); i++ ) { - KeyListener l = keyListeners.get(i); - switch(e.getEventType()) { - case KeyEvent.EVENT_KEY_PRESSED: - l.keyPressed(e); - break; - case KeyEvent.EVENT_KEY_RELEASED: - l.keyReleased(e); - break; - case KeyEvent.EVENT_KEY_TYPED: - l.keyTyped(e); - break; - default: - throw new NativeWindowException("Unexpected key event type " + e.getEventType()); + return InputEvent.consumedTag == e.getAttachment(); + } + + protected void consumeKeyEvent(KeyEvent e) { + boolean consumed; + if(null != keyboardFocusHandler) { + consumed = propagateKeyEvent(e, keyboardFocusHandler); + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e+", keyboardFocusHandler consumed: "+consumed); + } + } else { + consumed = false; + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e); } } + for(int i = 0; !consumed && i < keyListeners.size(); i++ ) { + consumed = propagateKeyEvent(e, keyListeners.get(i)); + } } // @@ -2191,7 +2220,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public WindowListener[] getWindowListeners() { - return (WindowListener[]) windowListeners.toArray(); + return windowListeners.toArray(new WindowListener[windowListeners.size()]); } protected void consumeWindowEvent(WindowEvent e) { @@ -2324,6 +2353,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer /** Triggered by implementation's WM events to update the position. */ protected void positionChanged(boolean defer, int newX, int newY) { + autoPosition = false; if ( x != newX || y != newY ) { if(DEBUG_IMPLEMENTATION) { System.err.println("Window.positionChanged: ("+getThreadName()+"): (defer: "+defer+") "+x+"/"+y+" -> "+newX+"/"+newY+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); @@ -2389,8 +2419,6 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer * Triggered by implementation's WM events to update the content */ protected void windowRepaint(boolean defer, int x, int y, int width, int height) { - x = ( 0 > x ) ? this.x : x; - y = ( 0 > y ) ? this.y : y; width = ( 0 >= width ) ? this.width : width; height = ( 0 >= height ) ? this.height : height; if(DEBUG_IMPLEMENTATION) { diff --git a/src/newt/classes/jogamp/newt/awt/event/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java index aa98d3a37..2ca3d2cfd 100644 --- a/src/newt/classes/jogamp/newt/awt/event/NewtFactoryAWT.java +++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java @@ -26,15 +26,19 @@ * or implied, of JogAmp Community. */ +package jogamp.newt.awt; -package jogamp.newt.awt.event; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.CapabilitiesImmutable; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; - -import javax.media.nativewindow.*; -import javax.media.nativewindow.awt.*; +import jogamp.nativewindow.jawt.JAWTWindow; +import jogamp.newt.Debug; import com.jogamp.newt.NewtFactory; -import jogamp.newt.Debug; public class NewtFactoryAWT extends NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); @@ -51,7 +55,7 @@ public class NewtFactoryAWT extends NewtFactory { * * @param awtCompObject must be of type java.awt.Component */ - public static NativeWindow getNativeWindow(Object awtCompObject, CapabilitiesImmutable capsRequested) { + public static JAWTWindow getNativeWindow(Object awtCompObject, CapabilitiesImmutable capsRequested) { if(null==awtCompObject) { throw new NativeWindowException("Null AWT Component"); } @@ -61,13 +65,23 @@ public class NewtFactoryAWT extends NewtFactory { return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested ); } - public static NativeWindow getNativeWindow(java.awt.Component awtComp, CapabilitiesImmutable capsRequested) { - DefaultGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, capsRequested, capsRequested); - NativeWindow awtNative = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + public static JAWTWindow getNativeWindow(java.awt.Component awtComp, CapabilitiesImmutable capsRequested) { + AWTGraphicsConfiguration config = AWTGraphicsConfiguration.create(awtComp, null, capsRequested); + NativeWindow nw = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + if(! ( nw instanceof JAWTWindow ) ) { + throw new NativeWindowException("Not an AWT NativeWindow: "+nw); + } if(DEBUG_IMPLEMENTATION) { - System.err.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+awtNative); + System.err.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+nw); } - return awtNative; + return (JAWTWindow)nw; + } + + public static void destroyNativeWindow(JAWTWindow jawtWindow) { + final AbstractGraphicsConfiguration config = jawtWindow.getGraphicsConfiguration(); + jawtWindow.destroy(); + config.getScreen().getDevice().close(); } + } diff --git a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java index 358864547..8e9c028d4 100644 --- a/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java +++ b/src/newt/classes/jogamp/newt/awt/event/AWTParentWindowAdapter.java @@ -28,6 +28,10 @@ package jogamp.newt.awt.event; +import java.awt.KeyboardFocusManager; + +import jogamp.newt.driver.DriverUpdatePosition; + import com.jogamp.newt.event.awt.AWTAdapter; import com.jogamp.newt.event.awt.AWTWindowAdapter; @@ -54,9 +58,16 @@ public class AWTParentWindowAdapter } public void focusGained(java.awt.event.FocusEvent e) { + // forward focus to NEWT child + final com.jogamp.newt.Window newtChild = getNewtWindow(); + final boolean isOnscreen = newtChild.isNativeValid() && newtChild.getGraphicsConfiguration().getChosenCapabilities().isOnscreen(); if(DEBUG_IMPLEMENTATION) { - System.err.println("AWT: focusGained: "+ e); + System.err.println("AWT: focusGained: onscreen "+ isOnscreen+", "+e); + } + if(isOnscreen) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); } + newtChild.requestFocus(false); } public void focusLost(java.awt.event.FocusEvent e) { @@ -90,7 +101,12 @@ public class AWTParentWindowAdapter } public void componentMoved(java.awt.event.ComponentEvent e) { - // no propagation to NEWT child window + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentMoved: "+e); + } + if(getNewtWindow().getDelegatedWindow() instanceof DriverUpdatePosition) { + ((DriverUpdatePosition)getNewtWindow().getDelegatedWindow()).updatePosition(); + } } public void windowActivated(java.awt.event.WindowEvent e) { @@ -104,11 +120,11 @@ public class AWTParentWindowAdapter public void hierarchyChanged(java.awt.event.HierarchyEvent e) { if( null == getNewtEventListener() ) { long bits = e.getChangeFlags(); - final java.awt.Component changed = e.getChanged(); + final java.awt.Component changed = e.getChanged(); if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & bits ) ) { final boolean showing = changed.isShowing(); if(DEBUG_IMPLEMENTATION) { - System.err.println("AWT: hierarchyChanged SHOWING_CHANGED: showing "+showing+", "+changed); + System.err.println("AWT: hierarchyChanged SHOWING_CHANGED: showing "+showing+", "+changed+", source "+e.getComponent()); } getNewtWindow().runOnEDTIfAvail(false, new Runnable() { public void run() { diff --git a/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java new file mode 100644 index 000000000..0a824e83b --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/DriverClearFocus.java @@ -0,0 +1,12 @@ +package jogamp.newt.driver; + +/** + * Interface tagging driver requirement of clearing the focus. + * <p> + * Some drivers require a programmatic {@link #clearFocus()} when traversing the focus. + * </p> + */ +public interface DriverClearFocus { + /** Programmatic clear the focus */ + void clearFocus(); +} diff --git a/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java b/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java new file mode 100644 index 000000000..bb846c081 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/DriverUpdatePosition.java @@ -0,0 +1,9 @@ +package jogamp.newt.driver; + +/** + * Interface tagging driver requirement of absolute positioning, ie. depend on parent position. + */ +public interface DriverUpdatePosition { + /** Programmatic update the position */ + void updatePosition(); +} diff --git a/src/newt/classes/jogamp/newt/driver/android/AndroidScreen.java b/src/newt/classes/jogamp/newt/driver/android/AndroidScreen.java index ce6a9c594..e108ed0bb 100644 --- a/src/newt/classes/jogamp/newt/driver/android/AndroidScreen.java +++ b/src/newt/classes/jogamp/newt/driver/android/AndroidScreen.java @@ -29,6 +29,8 @@ package jogamp.newt.driver.android; import javax.media.nativewindow.*; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; import com.jogamp.newt.ScreenMode; import com.jogamp.newt.util.ScreenModeUtil; @@ -74,6 +76,18 @@ public class AndroidScreen extends jogamp.newt.ScreenImpl { return ScreenModeUtil.streamIn(props, 0); } + protected int validateScreenIndex(int idx) { + return 0; // FIXME: only one screen available ? + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + final ScreenMode sm = getCurrentScreenMode(); + virtualSize.setWidth(sm.getRotatedWidth()); + virtualSize.setHeight(sm.getRotatedHeight()); + } + //---------------------------------------------------------------------- // Internals only // @@ -91,7 +105,7 @@ public class AndroidScreen extends jogamp.newt.ScreenImpl { if (ScreenMode.ROTATE_90 == nrot || ScreenMode.ROTATE_270 == nrot) { props[offset++] = outMetrics.heightPixels; props[offset++] = outMetrics.widthPixels; - } else { + } else { props[offset++] = outMetrics.widthPixels; props[offset++] = outMetrics.heightPixels; } diff --git a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java index 9cefa8163..6348cf19e 100644 --- a/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java +++ b/src/newt/classes/jogamp/newt/driver/android/AndroidWindow.java @@ -239,7 +239,7 @@ public class AndroidWindow extends jogamp.newt.WindowImpl implements Callback2 { } // propagate data .. - config = eglConfig; + setGraphicsConfiguration(eglConfig); setWindowHandle(surfaceHandle); Log.d(MD.TAG, "createNativeImpl X"); } @@ -343,7 +343,9 @@ public class AndroidWindow extends jogamp.newt.WindowImpl implements Callback2 { surfaceHandle = 0; surface=null; } - getScreen().getCurrentScreenMode(); // if ScreenMode changed .. trigger ScreenMode event + if(getScreen().isNativeValid()) { + getScreen().getCurrentScreenMode(); // if ScreenMode changed .. trigger ScreenMode event + } if(0>x || 0>y) { x = 0; diff --git a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java index bb678935a..f7c05cd45 100644 --- a/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java +++ b/src/newt/classes/jogamp/newt/driver/android/NewtBaseActivity.java @@ -27,10 +27,7 @@ */ package jogamp.newt.driver.android; -import javax.media.opengl.GLProfile; - import com.jogamp.newt.Window; -import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.util.Animator; import jogamp.newt.driver.android.AndroidWindow; @@ -63,9 +60,7 @@ public class NewtBaseActivity extends Activity { } public void setContentView(android.view.Window androidWindow, Window newtWindow) { - if(newtWindow instanceof GLWindow) { - newtWindow = ((GLWindow)newtWindow).getWindow(); - } + newtWindow = newtWindow.getDelegatedWindow(); if(newtWindow instanceof AndroidWindow) { this.newtWindow = (AndroidWindow)newtWindow; this.newtWindow.setAndroidWindow(androidWindow); @@ -103,9 +98,6 @@ public class NewtBaseActivity extends Activity { jogamp.common.os.android.StaticContext.setContext(extActivity.getApplicationContext()); } extActivity.getWindow(); - - // init GLProfile - GLProfile.initSingleton(true); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java index 0729f02ab..b63e433f6 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java @@ -99,7 +99,7 @@ public class AWTCanvas extends Canvas { if(null==awtConfig) { throw new NativeWindowException("Error: NULL AWTGraphicsConfiguration"); } - chosen = awtConfig.getGraphicsConfiguration(); + chosen = awtConfig.getAWTGraphicsConfiguration(); // before native peer is valid: X11 disableBackgroundErase(); @@ -192,7 +192,7 @@ public class AWTCanvas extends Canvas { */ AWTGraphicsConfiguration config = chooseGraphicsConfiguration( awtConfig.getChosenCapabilities(), awtConfig.getRequestedCapabilities(), chooser, gc.getDevice()); - final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null; + final GraphicsConfiguration compatible = (null!=config)?config.getAWTGraphicsConfiguration():null; if(Window.DEBUG_IMPLEMENTATION) { Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName()); e.printStackTrace(); @@ -246,7 +246,9 @@ public class AWTCanvas extends Canvas { CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, GraphicsDevice device) { - AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT); + final AbstractGraphicsScreen aScreen = null != device ? + AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT): + AWTGraphicsScreen.createDefault(); AWTGraphicsConfiguration config = (AWTGraphicsConfiguration) GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, capsRequested, diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTDisplay.java b/src/newt/classes/jogamp/newt/driver/awt/AWTDisplay.java index 64c741464..f22ec6fad 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTDisplay.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTDisplay.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,7 +34,6 @@ package jogamp.newt.driver.awt; -import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.newt.NewtFactory; import jogamp.newt.DisplayImpl; @@ -43,7 +43,7 @@ public class AWTDisplay extends DisplayImpl { } protected void createNativeImpl() { - aDevice = (AWTGraphicsDevice) AWTGraphicsDevice.createDevice(null, AbstractGraphicsDevice.DEFAULT_UNIT); // default + aDevice = AWTGraphicsDevice.createDefault(); } protected void setAWTGraphicsDevice(AWTGraphicsDevice d) { diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTScreen.java b/src/newt/classes/jogamp/newt/driver/awt/AWTScreen.java index 644c96391..9eed930b6 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTScreen.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTScreen.java @@ -38,6 +38,8 @@ import java.awt.DisplayMode; import jogamp.newt.ScreenImpl; import javax.media.nativewindow.awt.AWTGraphicsDevice; import javax.media.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; public class AWTScreen extends ScreenImpl { public AWTScreen() { @@ -45,21 +47,34 @@ public class AWTScreen extends ScreenImpl { protected void createNativeImpl() { aScreen = new AWTGraphicsScreen((AWTGraphicsDevice)display.getGraphicsDevice()); - - final DisplayMode mode = ((AWTGraphicsDevice)getDisplay().getGraphicsDevice()).getGraphicsDevice().getDisplayMode(); - if(null != mode) { - setScreenSize(mode.getWidth(), mode.getHeight()); - } } protected void setAWTGraphicsScreen(AWTGraphicsScreen s) { aScreen = s; } - // done by AWTWindow .. - protected void setScreenSize(int w, int h) { - super.setScreenSize(w, h); + /** + * Used by AWTWindow .. + */ + @Override + protected void updateVirtualScreenOriginAndSize() { + super.updateVirtualScreenOriginAndSize(); } protected void closeNativeImpl() { } + + protected int validateScreenIndex(int idx) { + return idx; // pass through ... + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + final DisplayMode mode = ((AWTGraphicsDevice)getDisplay().getGraphicsDevice()).getGraphicsDevice().getDisplayMode(); + if(null != mode) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(mode.getWidth()); + virtualSize.setHeight(mode.getHeight()); + } + } + } diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTWindow.java b/src/newt/classes/jogamp/newt/driver/awt/AWTWindow.java index 9aaa82fec..e9e3ec0ba 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTWindow.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTWindow.java @@ -36,10 +36,11 @@ package jogamp.newt.driver.awt; import java.awt.BorderLayout; import java.awt.Container; -import java.awt.DisplayMode; import java.awt.Frame; import java.awt.Insets; + import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; import javax.media.nativewindow.awt.AWTGraphicsDevice; import javax.media.nativewindow.awt.AWTGraphicsScreen; import javax.media.nativewindow.util.Point; @@ -145,27 +146,21 @@ public class AWTWindow extends WindowImpl { public boolean hasDeviceChanged() { boolean res = canvas.hasDeviceChanged(); if(res) { - config = canvas.getAWTGraphicsConfiguration(); - if (config == null) { + final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration(); + if (null == cfg) { throw new NativeWindowException("Error Device change null GraphicsConfiguration: "+this); } - updateDeviceData(); + setGraphicsConfiguration(cfg); + + // propagate new info .. + ((AWTScreen)getScreen()).setAWTGraphicsScreen((AWTGraphicsScreen)cfg.getScreen()); + ((AWTDisplay)getScreen().getDisplay()).setAWTGraphicsDevice((AWTGraphicsDevice)cfg.getScreen().getDevice()); + + ((AWTScreen)getScreen()).updateVirtualScreenOriginAndSize(); } return res; } - private void updateDeviceData() { - // propagate new info .. - ((AWTScreen)getScreen()).setAWTGraphicsScreen((AWTGraphicsScreen)config.getScreen()); - ((AWTDisplay)getScreen().getDisplay()).setAWTGraphicsDevice((AWTGraphicsDevice)config.getScreen().getDevice()); - - final DisplayMode mode = ((AWTGraphicsDevice)config.getScreen().getDevice()).getGraphicsDevice().getDisplayMode(); - if(null != mode) { - ((AWTScreen)getScreen()).setScreenSize(mode.getWidth(), mode.getHeight()); - } - - } - protected void updateInsetsImpl(javax.media.nativewindow.util.Insets insets) { Insets contInsets = container.getInsets(); insets.setLeftWidth(contInsets.left); @@ -189,11 +184,6 @@ public class AWTWindow extends WindowImpl { container.setVisible(0 != ( FLAG_IS_VISIBLE & flags)); } - x=(x>=0)?x:AWTWindow.this.x; - y=(x>=0)?y:AWTWindow.this.y; - width=(width>0)?width:AWTWindow.this.width; - height=(height>0)?height:AWTWindow.this.height; - container.setLocation(x, y); Insets insets = container.getInsets(); container.setSize(width + insets.left + insets.right, @@ -202,11 +192,12 @@ public class AWTWindow extends WindowImpl { if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { if( 0 != ( FLAG_IS_VISIBLE & flags ) ) { if( !hasDeviceChanged() ) { - // oops ?? - config = canvas.getAWTGraphicsConfiguration(); - if(null == config) { + // oops ?? + final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration(); + if(null == cfg) { throw new NativeWindowException("Error: !hasDeviceChanged && null == GraphicsConfiguration: "+this); } + setGraphicsConfiguration(cfg); } } visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); diff --git a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Screen.java b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Screen.java index 0a8453701..11b8dfcf9 100644 --- a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Screen.java +++ b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Screen.java @@ -34,6 +34,8 @@ package jogamp.newt.driver.broadcom.egl; import javax.media.nativewindow.*; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; public class Screen extends jogamp.newt.ScreenImpl { @@ -47,16 +49,26 @@ public class Screen extends jogamp.newt.ScreenImpl { protected void createNativeImpl() { aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); - setScreenSize(fixedWidth, fixedHeight); } protected void closeNativeImpl() { } + protected int validateScreenIndex(int idx) { + return 0; // only one screen available + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(fixedWidth); // FIXME + virtualSize.setHeight(fixedHeight); // FIXME + } + //---------------------------------------------------------------------- // Internals only // - static final int fixedWidth = 1920; - static final int fixedHeight = 1080; + static final int fixedWidth = 1920; // FIXME + static final int fixedHeight = 1080; // FIXME } diff --git a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java index 7df293c0d..6f66eedd3 100644 --- a/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java +++ b/src/newt/classes/jogamp/newt/driver/broadcom/egl/Window.java @@ -35,6 +35,7 @@ package jogamp.newt.driver.broadcom.egl; import jogamp.opengl.egl.*; import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; import javax.media.opengl.GLCapabilitiesImmutable; @@ -51,13 +52,14 @@ public class Window extends jogamp.newt.WindowImpl { if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported (yet)"); } - // query a good configuration .. even thought we drop this one - // and reuse the EGLUtil choosen one later. - config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( + // query a good configuration, however chose the final one by the native queried egl-cfg-id + // after creation at {@link #windowCreated(int, int, int)}. + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); setSizeImpl(getScreen().getWidth(), getScreen().getHeight()); setWindowHandle(realizeWindow(true, width, height)); @@ -139,7 +141,7 @@ public class Window extends jogamp.newt.WindowImpl { private long realizeWindow(boolean chromaKey, int width, int height) { if(DEBUG_IMPLEMENTATION) { - System.err.println("BCEGL Window.realizeWindow() with: chroma "+chromaKey+", "+width+"x"+height+", "+config); + System.err.println("BCEGL Window.realizeWindow() with: chroma "+chromaKey+", "+width+"x"+height+", "+getGraphicsConfiguration()); } long handle = CreateWindow(getDisplayHandle(), chromaKey, width, height); if (0 == handle) { @@ -152,13 +154,14 @@ public class Window extends jogamp.newt.WindowImpl { private void windowCreated(int cfgID, int width, int height) { this.width = width; this.height = height; - GLCapabilitiesImmutable capsReq = (GLCapabilitiesImmutable) config.getRequestedCapabilities(); - config = EGLGraphicsConfiguration.create(capsReq, getScreen().getGraphicsScreen(), cfgID); - if (config == null) { + GLCapabilitiesImmutable capsReq = (GLCapabilitiesImmutable) getGraphicsConfiguration().getRequestedCapabilities(); + final AbstractGraphicsConfiguration cfg = EGLGraphicsConfiguration.create(capsReq, getScreen().getGraphicsScreen(), cfgID); + if (null == cfg) { throw new NativeWindowException("Error creating EGLGraphicsConfiguration from id: "+cfgID+", "+this); } + setGraphicsConfiguration(cfg); if(DEBUG_IMPLEMENTATION) { - System.err.println("BCEGL Window.windowCreated(): "+toHexString(cfgID)+", "+width+"x"+height+", "+config); + System.err.println("BCEGL Window.windowCreated(): "+toHexString(cfgID)+", "+width+"x"+height+", "+cfg); } } diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/Screen.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/Screen.java index 26b7120a9..66ad1c691 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/Screen.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/Screen.java @@ -33,8 +33,10 @@ package jogamp.newt.driver.intel.gdl; -import jogamp.newt.*; -import javax.media.nativewindow.*; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.DefaultGraphicsScreen; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; public class Screen extends jogamp.newt.ScreenImpl { @@ -53,6 +55,17 @@ public class Screen extends jogamp.newt.ScreenImpl { protected void closeNativeImpl() { } + protected int validateScreenIndex(int idx) { + return 0; // only one screen available + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(cachedWidth); + virtualSize.setHeight(cachedHeight); + } + //---------------------------------------------------------------------- // Internals only // @@ -62,7 +75,11 @@ public class Screen extends jogamp.newt.ScreenImpl { // called by GetScreenInfo() .. private void screenCreated(int width, int height) { - setScreenSize(width, height); + cachedWidth = width; + cachedHeight = height; } + + private static int cachedWidth = 0; + private static int cachedHeight = 0; } diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java index ab3e95e7e..873d0a0c1 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/Window.java @@ -51,14 +51,15 @@ public class Window extends jogamp.newt.WindowImpl { if(0!=getParentWindowHandle()) { throw new NativeWindowException("GDL Window does not support window parenting"); } - AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); - AbstractGraphicsDevice aDevice = getScreen().getDisplay().getGraphicsDevice(); + final AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); + final AbstractGraphicsDevice aDevice = getScreen().getDisplay().getGraphicsDevice(); - config = GraphicsConfigurationFactory.getFactory(aDevice).chooseGraphicsConfiguration( + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(aDevice).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, aScreen); - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); synchronized(Window.class) { setWindowHandle(nextWindowHandle++); // just a marker @@ -83,11 +84,6 @@ public class Window extends jogamp.newt.WindowImpl { protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { Screen screen = (Screen) getScreen(); - x=(x>=0)?x:this.x; - y=(x>=0)?y:this.y; - width=(width>0)?width:this.width; - height=(height>0)?height:this.height; - if(width>screen.getWidth()) { width=screen.getWidth(); } diff --git a/src/newt/classes/jogamp/newt/driver/kd/KDScreen.java b/src/newt/classes/jogamp/newt/driver/kd/KDScreen.java index a11b08b5c..6b6aecb20 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/KDScreen.java +++ b/src/newt/classes/jogamp/newt/driver/kd/KDScreen.java @@ -35,6 +35,8 @@ package jogamp.newt.driver.kd; import jogamp.newt.ScreenImpl; import javax.media.nativewindow.*; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; public class KDScreen extends ScreenImpl { static { @@ -50,8 +52,22 @@ public class KDScreen extends ScreenImpl { protected void closeNativeImpl() { } - // elevate access to this package .. - protected void setScreenSize(int w, int h) { - super.setScreenSize(w, h); + protected int validateScreenIndex(int idx) { + return 0; // only one screen available + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(cachedWidth); + virtualSize.setHeight(cachedHeight); } + + protected void sizeChanged(int w, int h) { + cachedWidth = w; + cachedHeight = h; + } + + private static int cachedWidth = 0; + private static int cachedHeight = 0; } diff --git a/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java b/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java index 10a75a017..92f8251bc 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java +++ b/src/newt/classes/jogamp/newt/driver/kd/KDWindow.java @@ -55,18 +55,19 @@ public class KDWindow extends WindowImpl { if(0!=getParentWindowHandle()) { throw new RuntimeException("Window parenting not supported (yet)"); } - config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); - GLCapabilitiesImmutable eglCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + GLCapabilitiesImmutable eglCaps = (GLCapabilitiesImmutable) cfg.getChosenCapabilities(); int[] eglAttribs = EGLGraphicsConfiguration.GLCapabilities2AttribList(eglCaps); eglWindowHandle = CreateWindow(getDisplayHandle(), eglAttribs); if (eglWindowHandle == 0) { - throw new NativeWindowException("Error creating egl window: "+config); + throw new NativeWindowException("Error creating egl window: "+cfg); } setVisible0(eglWindowHandle, false); setWindowHandle(RealizeWindow(eglWindowHandle)); @@ -145,7 +146,7 @@ public class KDWindow extends WindowImpl { @Override protected void sizeChanged(boolean defer, int newWidth, int newHeight, boolean force) { if(fullscreen) { - ((KDScreen)getScreen()).setScreenSize(width, height); + ((KDScreen)getScreen()).sizeChanged(width, height); } super.sizeChanged(defer, newWidth, newHeight, force); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java b/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java index 527fdac6d..2ac98f255 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacDisplay.java @@ -72,8 +72,12 @@ public class MacDisplay extends DisplayImpl { public static void runNSApplication() { runNSApplication0(); } + public static void stopNSApplication() { + stopNSApplication0(); + } private static native boolean initNSApplication0(); private static native void runNSApplication0(); + private static native void stopNSApplication0(); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java new file mode 100644 index 000000000..46625f7a9 --- /dev/null +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacKeyUtil.java @@ -0,0 +1,262 @@ +package jogamp.newt.driver.macosx; + +import com.jogamp.newt.event.KeyEvent; + +public class MacKeyUtil { + + // KeyCodes (independent) + private static final int kVK_Return = 0x24; + private static final int kVK_Tab = 0x30; + private static final int kVK_Space = 0x31; + private static final int kVK_Delete = 0x33; + private static final int kVK_Escape = 0x35; + private static final int kVK_Command = 0x37; + private static final int kVK_Shift = 0x38; + private static final int kVK_CapsLock = 0x39; + private static final int kVK_Option = 0x3A; + private static final int kVK_Control = 0x3B; + private static final int kVK_RightShift = 0x3C; + private static final int kVK_RightOption = 0x3D; + private static final int kVK_RightControl = 0x3E; + private static final int kVK_Function = 0x3F; + private static final int kVK_F17 = 0x40; + private static final int kVK_VolumeUp = 0x48; + private static final int kVK_VolumeDown = 0x49; + private static final int kVK_Mute = 0x4A; + private static final int kVK_F18 = 0x4F; + private static final int kVK_F19 = 0x50; + private static final int kVK_F20 = 0x5A; + private static final int kVK_F5 = 0x60; + private static final int kVK_F6 = 0x61; + private static final int kVK_F7 = 0x62; + private static final int kVK_F3 = 0x63; + private static final int kVK_F8 = 0x64; + private static final int kVK_F9 = 0x65; + private static final int kVK_F11 = 0x67; + private static final int kVK_F13 = 0x69; + private static final int kVK_F16 = 0x6A; + private static final int kVK_F14 = 0x6B; + private static final int kVK_F10 = 0x6D; + private static final int kVK_F12 = 0x6F; + private static final int kVK_F15 = 0x71; + private static final int kVK_Help = 0x72; + private static final int kVK_Home = 0x73; + private static final int kVK_PageUp = 0x74; + private static final int kVK_ForwardDelete = 0x75; + private static final int kVK_F4 = 0x76; + private static final int kVK_End = 0x77; + private static final int kVK_F2 = 0x78; + private static final int kVK_PageDown = 0x79; + private static final int kVK_F1 = 0x7A; + private static final int kVK_LeftArrow = 0x7B; + private static final int kVK_RightArrow = 0x7C; + private static final int kVK_DownArrow = 0x7D; + private static final int kVK_UpArrow = 0x7E; + + // Key constants handled differently on Mac OS X than other platforms + private static final char NSUpArrowFunctionKey = 0xF700; + private static final char NSDownArrowFunctionKey = 0xF701; + private static final char NSLeftArrowFunctionKey = 0xF702; + private static final char NSRightArrowFunctionKey = 0xF703; + private static final char NSF1FunctionKey = 0xF704; + private static final char NSF2FunctionKey = 0xF705; + private static final char NSF3FunctionKey = 0xF706; + private static final char NSF4FunctionKey = 0xF707; + private static final char NSF5FunctionKey = 0xF708; + private static final char NSF6FunctionKey = 0xF709; + private static final char NSF7FunctionKey = 0xF70A; + private static final char NSF8FunctionKey = 0xF70B; + private static final char NSF9FunctionKey = 0xF70C; + private static final char NSF10FunctionKey = 0xF70D; + private static final char NSF11FunctionKey = 0xF70E; + private static final char NSF12FunctionKey = 0xF70F; + private static final char NSF13FunctionKey = 0xF710; + private static final char NSF14FunctionKey = 0xF711; + private static final char NSF15FunctionKey = 0xF712; + private static final char NSF16FunctionKey = 0xF713; + private static final char NSF17FunctionKey = 0xF714; + private static final char NSF18FunctionKey = 0xF715; + private static final char NSF19FunctionKey = 0xF716; + private static final char NSF20FunctionKey = 0xF717; + private static final char NSF21FunctionKey = 0xF718; + private static final char NSF22FunctionKey = 0xF719; + private static final char NSF23FunctionKey = 0xF71A; + private static final char NSF24FunctionKey = 0xF71B; + private static final char NSF25FunctionKey = 0xF71C; + private static final char NSF26FunctionKey = 0xF71D; + private static final char NSF27FunctionKey = 0xF71E; + private static final char NSF28FunctionKey = 0xF71F; + private static final char NSF29FunctionKey = 0xF720; + private static final char NSF30FunctionKey = 0xF721; + private static final char NSF31FunctionKey = 0xF722; + private static final char NSF32FunctionKey = 0xF723; + private static final char NSF33FunctionKey = 0xF724; + private static final char NSF34FunctionKey = 0xF725; + private static final char NSF35FunctionKey = 0xF726; + private static final char NSInsertFunctionKey = 0xF727; + private static final char NSDeleteFunctionKey = 0xF728; + private static final char NSHomeFunctionKey = 0xF729; + private static final char NSBeginFunctionKey = 0xF72A; + private static final char NSEndFunctionKey = 0xF72B; + private static final char NSPageUpFunctionKey = 0xF72C; + private static final char NSPageDownFunctionKey = 0xF72D; + private static final char NSPrintScreenFunctionKey = 0xF72E; + private static final char NSScrollLockFunctionKey = 0xF72F; + private static final char NSPauseFunctionKey = 0xF730; + private static final char NSSysReqFunctionKey = 0xF731; + private static final char NSBreakFunctionKey = 0xF732; + private static final char NSResetFunctionKey = 0xF733; + private static final char NSStopFunctionKey = 0xF734; + private static final char NSMenuFunctionKey = 0xF735; + private static final char NSUserFunctionKey = 0xF736; + private static final char NSSystemFunctionKey = 0xF737; + private static final char NSPrintFunctionKey = 0xF738; + private static final char NSClearLineFunctionKey = 0xF739; + private static final char NSClearDisplayFunctionKey = 0xF73A; + private static final char NSInsertLineFunctionKey = 0xF73B; + private static final char NSDeleteLineFunctionKey = 0xF73C; + private static final char NSInsertCharFunctionKey = 0xF73D; + private static final char NSDeleteCharFunctionKey = 0xF73E; + private static final char NSPrevFunctionKey = 0xF73F; + private static final char NSNextFunctionKey = 0xF740; + private static final char NSSelectFunctionKey = 0xF741; + private static final char NSExecuteFunctionKey = 0xF742; + private static final char NSUndoFunctionKey = 0xF743; + private static final char NSRedoFunctionKey = 0xF744; + private static final char NSFindFunctionKey = 0xF745; + private static final char NSHelpFunctionKey = 0xF746; + private static final char NSModeSwitchFunctionKey = 0xF747; + + static int validateKeyCode(int keyCode, char keyChar) { + // OS X Virtual Keycodes + switch(keyCode) { + case kVK_Return: return KeyEvent.VK_ENTER; + case kVK_Tab: return KeyEvent.VK_TAB; + case kVK_Space: return KeyEvent.VK_SPACE; + case kVK_Delete: return KeyEvent.VK_BACK_SPACE; + case kVK_Escape: return KeyEvent.VK_ESCAPE; + case kVK_Command: return KeyEvent.VK_ALT; + case kVK_Shift: return KeyEvent.VK_SHIFT; + case kVK_CapsLock: return KeyEvent.VK_CAPS_LOCK; + case kVK_Option: return KeyEvent.VK_WINDOWS; + case kVK_Control: return KeyEvent.VK_CONTROL; + case kVK_RightShift: return KeyEvent.VK_SHIFT; + case kVK_RightOption: return KeyEvent.VK_WINDOWS; + case kVK_RightControl: return KeyEvent.VK_CONTROL; + // case kVK_Function: return KeyEvent.VK_F; + case kVK_F17: return KeyEvent.VK_F17; + // case kVK_VolumeUp: + // case kVK_VolumeDown: + // case kVK_Mute: + case kVK_F18: return KeyEvent.VK_F18; + case kVK_F19: return KeyEvent.VK_F19; + case kVK_F20: return KeyEvent.VK_F20; + case kVK_F5: return KeyEvent.VK_F5; + case kVK_F6: return KeyEvent.VK_F6; + case kVK_F7: return KeyEvent.VK_F7; + case kVK_F3: return KeyEvent.VK_F3; + case kVK_F8: return KeyEvent.VK_F8; + case kVK_F9: return KeyEvent.VK_F9; + case kVK_F11: return KeyEvent.VK_F11; + case kVK_F13: return KeyEvent.VK_F13; + case kVK_F16: return KeyEvent.VK_F16; + case kVK_F14: return KeyEvent.VK_F14; + case kVK_F10: return KeyEvent.VK_F10; + case kVK_F12: return KeyEvent.VK_F12; + case kVK_F15: return KeyEvent.VK_F15; + case kVK_Help: return KeyEvent.VK_HELP; + case kVK_Home: return KeyEvent.VK_HOME; + case kVK_PageUp: return KeyEvent.VK_PAGE_UP; + case kVK_ForwardDelete: return KeyEvent.VK_DELETE; + case kVK_F4: return KeyEvent.VK_F4; + case kVK_End: return KeyEvent.VK_END; + case kVK_F2: return KeyEvent.VK_F2; + case kVK_PageDown: return KeyEvent.VK_PAGE_DOWN; + case kVK_F1: return KeyEvent.VK_F1; + case kVK_LeftArrow: return KeyEvent.VK_LEFT; + case kVK_RightArrow: return KeyEvent.VK_RIGHT; + case kVK_DownArrow: return KeyEvent.VK_DOWN; + case kVK_UpArrow: return KeyEvent.VK_UP; + } + + if (keyChar == '\r') { + // Turn these into \n + return KeyEvent.VK_ENTER; + } + + if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { + switch (keyChar) { + case NSUpArrowFunctionKey: return KeyEvent.VK_UP; + case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; + case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; + case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; + case NSF1FunctionKey: return KeyEvent.VK_F1; + case NSF2FunctionKey: return KeyEvent.VK_F2; + case NSF3FunctionKey: return KeyEvent.VK_F3; + case NSF4FunctionKey: return KeyEvent.VK_F4; + case NSF5FunctionKey: return KeyEvent.VK_F5; + case NSF6FunctionKey: return KeyEvent.VK_F6; + case NSF7FunctionKey: return KeyEvent.VK_F7; + case NSF8FunctionKey: return KeyEvent.VK_F8; + case NSF9FunctionKey: return KeyEvent.VK_F9; + case NSF10FunctionKey: return KeyEvent.VK_F10; + case NSF11FunctionKey: return KeyEvent.VK_F11; + case NSF12FunctionKey: return KeyEvent.VK_F12; + case NSF13FunctionKey: return KeyEvent.VK_F13; + case NSF14FunctionKey: return KeyEvent.VK_F14; + case NSF15FunctionKey: return KeyEvent.VK_F15; + case NSF16FunctionKey: return KeyEvent.VK_F16; + case NSF17FunctionKey: return KeyEvent.VK_F17; + case NSF18FunctionKey: return KeyEvent.VK_F18; + case NSF19FunctionKey: return KeyEvent.VK_F19; + case NSF20FunctionKey: return KeyEvent.VK_F20; + case NSF21FunctionKey: return KeyEvent.VK_F21; + case NSF22FunctionKey: return KeyEvent.VK_F22; + case NSF23FunctionKey: return KeyEvent.VK_F23; + case NSF24FunctionKey: return KeyEvent.VK_F24; + case NSInsertFunctionKey: return KeyEvent.VK_INSERT; + case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; + case NSHomeFunctionKey: return KeyEvent.VK_HOME; + case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; + case NSEndFunctionKey: return KeyEvent.VK_END; + case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; + case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; + case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; + case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; + case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; + // Not handled: + // NSSysReqFunctionKey + // NSBreakFunctionKey + // NSResetFunctionKey + case NSStopFunctionKey: return KeyEvent.VK_STOP; + // Not handled: + // NSMenuFunctionKey + // NSUserFunctionKey + // NSSystemFunctionKey + // NSPrintFunctionKey + // NSClearLineFunctionKey + // NSClearDisplayFunctionKey + // NSInsertLineFunctionKey + // NSDeleteLineFunctionKey + // NSInsertCharFunctionKey + // NSDeleteCharFunctionKey + // NSPrevFunctionKey + // NSNextFunctionKey + // NSSelectFunctionKey + // NSExecuteFunctionKey + // NSUndoFunctionKey + // NSRedoFunctionKey + // NSFindFunctionKey + // NSHelpFunctionKey + // NSModeSwitchFunctionKey + default: break; + } + } + + if ('a' <= keyChar && keyChar <= 'z') { + return KeyEvent.VK_A + ( keyChar - 'a' ) ; + } + + return (int) keyChar; // let's hope for the best (compatibility of keyChar/keyCode's) + } +} diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacScreen.java b/src/newt/classes/jogamp/newt/driver/macosx/MacScreen.java index 67a3f8e92..3204982be 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacScreen.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacScreen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2011 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,9 +34,16 @@ package jogamp.newt.driver.macosx; -import com.jogamp.newt.*; +import java.util.List; + +import javax.media.nativewindow.DefaultGraphicsScreen; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; + import jogamp.newt.ScreenImpl; -import javax.media.nativewindow.*; + +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.util.ScreenModeUtil; public class MacScreen extends ScreenImpl { static { @@ -47,11 +55,69 @@ public class MacScreen extends ScreenImpl { protected void createNativeImpl() { aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); - setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); } protected void closeNativeImpl() { } private static native int getWidthImpl0(int scrn_idx); private static native int getHeightImpl0(int scrn_idx); + + private int[] getScreenModeIdx(int idx) { + int[] modeProps = getScreenMode0(screen_idx, idx); + if (null == modeProps || 0 == modeProps.length) { + return null; + } + if(modeProps.length < ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL) { + throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length); + } + return modeProps; + } + + private int nativeModeIdx; + + protected int[] getScreenModeFirstImpl() { + nativeModeIdx = 0; + return getScreenModeNextImpl(); + } + + protected int[] getScreenModeNextImpl() { + int[] modeProps = getScreenModeIdx(nativeModeIdx); + if (null != modeProps && 0 < modeProps.length) { + nativeModeIdx++; + return modeProps; + } + return null; + } + + protected ScreenMode getCurrentScreenModeImpl() { + int[] modeProps = getScreenModeIdx(-1); + if (null != modeProps && 0 < modeProps.length) { + return ScreenModeUtil.streamIn(modeProps, 0); + } + return null; + } + + protected boolean setCurrentScreenModeImpl(final ScreenMode screenMode) { + final List<ScreenMode> screenModes = this.getScreenModesOrig(); + final int screenModeIdx = screenModes.indexOf(screenMode); + if(0>screenModeIdx) { + throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode); + } + final int nativeModeIdx = getScreenModesIdx2NativeIdx().get(screenModeIdx); + return setScreenMode0(screen_idx, nativeModeIdx); + } + + protected int validateScreenIndex(int idx) { + return idx; + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(getWidthImpl0(screen_idx)); + virtualSize.setHeight(getHeightImpl0(screen_idx)); + } + + private native int[] getScreenMode0(int screen_index, int mode_index); + private native boolean setScreenMode0(int screen_index, int mode_idx); } diff --git a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java index d09ac72ba..75a3cf6d5 100644 --- a/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java +++ b/src/newt/classes/jogamp/newt/driver/macosx/MacWindow.java @@ -34,108 +34,24 @@ package jogamp.newt.driver.macosx; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.SurfaceChangeable; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; import javax.media.nativewindow.util.PointImmutable; import jogamp.newt.WindowImpl; +import jogamp.newt.driver.DriverClearFocus; +import jogamp.newt.driver.DriverUpdatePosition; import com.jogamp.newt.event.KeyEvent; -public class MacWindow extends WindowImpl { +public class MacWindow extends WindowImpl implements SurfaceChangeable, DriverClearFocus, DriverUpdatePosition { - // Window styles - private static final int NSBorderlessWindowMask = 0; - private static final int NSTitledWindowMask = 1 << 0; - private static final int NSClosableWindowMask = 1 << 1; - private static final int NSMiniaturizableWindowMask = 1 << 2; - private static final int NSResizableWindowMask = 1 << 3; - - // Window backing store types - private static final int NSBackingStoreRetained = 0; - private static final int NSBackingStoreNonretained = 1; - private static final int NSBackingStoreBuffered = 2; - - // Key constants handled differently on Mac OS X than other platforms - private static final int NSUpArrowFunctionKey = 0xF700; - private static final int NSDownArrowFunctionKey = 0xF701; - private static final int NSLeftArrowFunctionKey = 0xF702; - private static final int NSRightArrowFunctionKey = 0xF703; - private static final int NSF1FunctionKey = 0xF704; - private static final int NSF2FunctionKey = 0xF705; - private static final int NSF3FunctionKey = 0xF706; - private static final int NSF4FunctionKey = 0xF707; - private static final int NSF5FunctionKey = 0xF708; - private static final int NSF6FunctionKey = 0xF709; - private static final int NSF7FunctionKey = 0xF70A; - private static final int NSF8FunctionKey = 0xF70B; - private static final int NSF9FunctionKey = 0xF70C; - private static final int NSF10FunctionKey = 0xF70D; - private static final int NSF11FunctionKey = 0xF70E; - private static final int NSF12FunctionKey = 0xF70F; - private static final int NSF13FunctionKey = 0xF710; - private static final int NSF14FunctionKey = 0xF711; - private static final int NSF15FunctionKey = 0xF712; - private static final int NSF16FunctionKey = 0xF713; - private static final int NSF17FunctionKey = 0xF714; - private static final int NSF18FunctionKey = 0xF715; - private static final int NSF19FunctionKey = 0xF716; - private static final int NSF20FunctionKey = 0xF717; - private static final int NSF21FunctionKey = 0xF718; - private static final int NSF22FunctionKey = 0xF719; - private static final int NSF23FunctionKey = 0xF71A; - private static final int NSF24FunctionKey = 0xF71B; - private static final int NSF25FunctionKey = 0xF71C; - private static final int NSF26FunctionKey = 0xF71D; - private static final int NSF27FunctionKey = 0xF71E; - private static final int NSF28FunctionKey = 0xF71F; - private static final int NSF29FunctionKey = 0xF720; - private static final int NSF30FunctionKey = 0xF721; - private static final int NSF31FunctionKey = 0xF722; - private static final int NSF32FunctionKey = 0xF723; - private static final int NSF33FunctionKey = 0xF724; - private static final int NSF34FunctionKey = 0xF725; - private static final int NSF35FunctionKey = 0xF726; - private static final int NSInsertFunctionKey = 0xF727; - private static final int NSDeleteFunctionKey = 0xF728; - private static final int NSHomeFunctionKey = 0xF729; - private static final int NSBeginFunctionKey = 0xF72A; - private static final int NSEndFunctionKey = 0xF72B; - private static final int NSPageUpFunctionKey = 0xF72C; - private static final int NSPageDownFunctionKey = 0xF72D; - private static final int NSPrintScreenFunctionKey = 0xF72E; - private static final int NSScrollLockFunctionKey = 0xF72F; - private static final int NSPauseFunctionKey = 0xF730; - private static final int NSSysReqFunctionKey = 0xF731; - private static final int NSBreakFunctionKey = 0xF732; - private static final int NSResetFunctionKey = 0xF733; - private static final int NSStopFunctionKey = 0xF734; - private static final int NSMenuFunctionKey = 0xF735; - private static final int NSUserFunctionKey = 0xF736; - private static final int NSSystemFunctionKey = 0xF737; - private static final int NSPrintFunctionKey = 0xF738; - private static final int NSClearLineFunctionKey = 0xF739; - private static final int NSClearDisplayFunctionKey = 0xF73A; - private static final int NSInsertLineFunctionKey = 0xF73B; - private static final int NSDeleteLineFunctionKey = 0xF73C; - private static final int NSInsertCharFunctionKey = 0xF73D; - private static final int NSDeleteCharFunctionKey = 0xF73E; - private static final int NSPrevFunctionKey = 0xF73F; - private static final int NSNextFunctionKey = 0xF740; - private static final int NSSelectFunctionKey = 0xF741; - private static final int NSExecuteFunctionKey = 0xF742; - private static final int NSUndoFunctionKey = 0xF743; - private static final int NSRedoFunctionKey = 0xF744; - private static final int NSFindFunctionKey = 0xF745; - private static final int NSHelpFunctionKey = 0xF746; - private static final int NSModeSwitchFunctionKey = 0xF747; - - private volatile long surfaceHandle; - static { MacDisplay.initSingleton(); } @@ -143,18 +59,21 @@ public class MacWindow extends WindowImpl { public MacWindow() { } + @Override protected void createNativeImpl() { - config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, getScreen().getGraphicsScreen()); - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); reconfigureWindowImpl(x, y, width, height, getReconfigureFlags(FLAG_CHANGE_VISIBILITY, true)); if (0 == getWindowHandle()) { throw new NativeWindowException("Error creating window"); } } + @Override protected void closeNativeImpl() { try { if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } @@ -168,81 +87,158 @@ public class MacWindow extends WindowImpl { } } finally { setWindowHandle(0); + surfaceHandle = 0; + sscSurfaceHandle = 0; + isOffscreenInstance = false; } } @Override protected int lockSurfaceImpl() { - return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + if(!isOffscreenInstance) { + return lockSurface0(getWindowHandle()) ? LOCK_SUCCESS : LOCK_SURFACE_NOT_READY; + } + return LOCK_SUCCESS; } @Override protected void unlockSurfaceImpl() { - unlockSurface0(getWindowHandle()); + if(!isOffscreenInstance) { + unlockSurface0(getWindowHandle()); + } } @Override public final long getSurfaceHandle() { - return surfaceHandle; + return 0 != sscSurfaceHandle ? sscSurfaceHandle : surfaceHandle; + } + + public void setSurfaceHandle(long surfaceHandle) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); + } + sscSurfaceHandle = surfaceHandle; + if (isNativeValid()) { + if (0 != sscSurfaceHandle) { + orderOut0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } /** this is done by recreation! + else if (isVisible()){ + orderFront0( 0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle() ); + } */ + } } + public void surfaceSizeChanged(int width, int height) { + sizeChanged(false, width, height, false); + } + @Override protected void setTitleImpl(final String title) { setTitle0(getWindowHandle(), title); } protected void requestFocusImpl(boolean force) { - requestFocus0(getWindowHandle(), force); + if(!isOffscreenInstance) { + requestFocus0(getWindowHandle(), force); + } else { + focusChanged(false, true); + } + } + + public final void clearFocus() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: clearFocus() - requestFocusParent, isOffscreenInstance "+isOffscreenInstance); + } + if(!isOffscreenInstance) { + requestFocusParent0(getWindowHandle()); + } else { + focusChanged(false, false); + } + } + + public void updatePosition() { + final Point pS = getTopLevelLocationOnScreen(getX(), getY()); + if(DEBUG_IMPLEMENTATION) { + System.err.println("MacWindow: updatePosition() - isOffscreenInstance "+isOffscreenInstance+", new abs pos: pS "+pS); + } + if( !isOffscreenInstance ) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + } // else no offscreen position + // no native event (fullscreen, some reparenting) + super.positionChanged(true, getX(), getY()); } + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { - final PointImmutable pS = position2TopLevel(new Point(x, y)); + final Point pS = getTopLevelLocationOnScreen(x, y); + isOffscreenInstance = 0 != sscSurfaceHandle || isOffscreenInstance(this, this.getParent()); if(DEBUG_IMPLEMENTATION) { - System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+", "+ - getReconfigureFlagsAsString(null, flags)); + System.err.println("MacWindow reconfig: "+x+"/"+y+" -> "+pS+" - "+width+"x"+height+ + ", offscreenInstance "+isOffscreenInstance+ + ", "+getReconfigureFlagsAsString(null, flags)); } - if( getWindowHandle() == 0 ) { - if( 0 != ( FLAG_IS_VISIBLE & flags) ) { - createWindow(false, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); - // no native event .. - visibleChanged(true, true); - } /* else { ?? } */ - } else { - if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) { + if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 == ( FLAG_IS_VISIBLE & flags) ) { + if ( !isOffscreenInstance ) { orderOut0(getWindowHandle()); - // no native event .. - visibleChanged(true, false); - } - if( 0 != ( FLAG_CHANGE_DECORATION & flags) || - 0 != ( FLAG_CHANGE_PARENTING & flags) || - 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { - createWindow(true, pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); - if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; } - } - if(x>=0 && y>=0) { - setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); - // no native event (fullscreen, some reparenting) - positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation } - if(width>0 && height>0) { + // no native event .. + visibleChanged(true, false); + } + if( 0 == getWindowHandle() && 0 != ( FLAG_IS_VISIBLE & flags) || + 0 != ( FLAG_CHANGE_DECORATION & flags) || + 0 != ( FLAG_CHANGE_PARENTING & flags) || + 0 != ( FLAG_CHANGE_FULLSCREEN & flags) ) { + createWindow(isOffscreenInstance, 0 != getWindowHandle(), pS, width, height, 0 != ( FLAG_IS_FULLSCREEN & flags)); + if(isVisible()) { flags |= FLAG_CHANGE_VISIBILITY; } + } + if(x>=0 && y>=0) { + if( !isOffscreenInstance ) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), pS.getX(), pS.getY()); + } // else no offscreen position + // no native event (fullscreen, some reparenting) + super.positionChanged(true, x, y); + } + if(width>0 && height>0) { + if( !isOffscreenInstance ) { setContentSize0(getWindowHandle(), width, height); - // no native event (fullscreen, some reparenting) - sizeChanged(true, width, height, false); // incl. validation (incl. repositioning) - } - if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 != ( FLAG_IS_VISIBLE & flags) ) { + } // else offscreen size is realized via recreation + // no native event (fullscreen, some reparenting) + sizeChanged(true, width, height, false); // incl. validation (incl. repositioning) + } + if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) && 0 != ( FLAG_IS_VISIBLE & flags) ) { + if( !isOffscreenInstance ) { orderFront0(getWindowHandle()); - // no native event .. - visibleChanged(true, true); - } + } + // no native event .. + visibleChanged(true, true); + } + if( !isOffscreenInstance ) { setAlwaysOnTop0(getWindowHandle(), 0 != ( FLAG_IS_ALWAYSONTOP & flags)); } return true; } protected Point getLocationOnScreenImpl(int x, int y) { - return (Point) getLocationOnScreen0(getWindowHandle(), x, y); + Point p = new Point(x, y); + // min val is 0 + p.setX(Math.max(p.getX(), 0)); + p.setY(Math.max(p.getY(), 0)); + + final NativeWindow parent = getParent(); + if( null != parent && 0 != parent.getWindowHandle() ) { + p.translate(parent.getLocationOnScreen(null)); + } + return p; + } + + private Point getTopLevelLocationOnScreen(int x, int y) { + final InsetsImmutable _insets = getInsets(); // zero if undecorated + // client position -> top-level window position + x -= _insets.getLeftWidth() ; + y -= _insets.getTopHeight() ; + return getLocationOnScreenImpl(x, y); } protected void updateInsetsImpl(Insets insets) { @@ -252,138 +248,76 @@ public class MacWindow extends WindowImpl { @Override protected void sizeChanged(boolean defer, int newWidth, int newHeight, boolean force) { if(width != newWidth || height != newHeight) { - final Point p0S = position2TopLevel(new Point(x, y)); + final Point p0S = getTopLevelLocationOnScreen(x, y); setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), p0S.getX(), p0S.getY()); } super.sizeChanged(defer, newWidth, newHeight, force); } @Override - protected void positionChanged(boolean defer, int newX, int newY) { - positionChanged(defer, new Point(newX, newY)); + protected void positionChanged(boolean defer, int newX, int newY) { + // passed coordinates are in screen position of the client area + if(getWindowHandle()!=0) { + // screen position -> window position + Point absPos = new Point(newX, newY); + final NativeWindow parent = getParent(); + if(null != parent) { + absPos.translate( parent.getLocationOnScreen(null).scale(-1, -1) ); + } + super.positionChanged(defer, absPos.getX(), absPos.getY()); + } } @Override protected boolean setPointerVisibleImpl(final boolean pointerVisible) { - return setPointerVisible0(getWindowHandle(), pointerVisible); + if( !isOffscreenInstance ) { + return setPointerVisible0(getWindowHandle(), pointerVisible); + } // else may need offscreen solution ? FIXME + return false; } @Override protected boolean confinePointerImpl(final boolean confine) { - return confinePointer0(getWindowHandle(), confine); + if( !isOffscreenInstance ) { + return confinePointer0(getWindowHandle(), confine); + } // else may need offscreen solution ? FIXME + return false; } @Override protected void warpPointerImpl(final int x, final int y) { - warpPointer0(getWindowHandle(), x, y); + if( !isOffscreenInstance ) { + warpPointer0(getWindowHandle(), x, y); + } // else may need offscreen solution ? FIXME } @Override public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { - final int key = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()); // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - super.sendKeyEvent(eventType, modifiers, key, keyChar); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.sendKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + // only deliver keyChar on key Typed events, harmonizing platform behavior + keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1; + super.sendKeyEvent(eventType, modifiers, keyCode2, keyChar); } @Override public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { - final int key = convertKeyChar(keyChar); - if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()); // Note that we send the key char for the key code on this // platform -- we do not get any useful key codes out of the system - super.enqueueKeyEvent(wait, eventType, modifiers, key, keyChar); + final int keyCode2 = MacKeyUtil.validateKeyCode(keyCode, keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()+" char: 0x"+Integer.toHexString(keyChar)+", code 0x"+Integer.toHexString(keyCode)+" -> 0x"+Integer.toHexString(keyCode2)); + // only deliver keyChar on key Typed events, harmonizing platform behavior + keyChar = KeyEvent.EVENT_KEY_TYPED == eventType ? keyChar : (char)-1; + super.enqueueKeyEvent(wait, eventType, modifiers, keyCode2, keyChar); } //---------------------------------------------------------------------- // Internals only // - private char convertKeyChar(char keyChar) { - if (keyChar == '\r') { - // Turn these into \n - return '\n'; - } - - if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { - switch (keyChar) { - case NSUpArrowFunctionKey: return KeyEvent.VK_UP; - case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; - case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; - case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; - case NSF1FunctionKey: return KeyEvent.VK_F1; - case NSF2FunctionKey: return KeyEvent.VK_F2; - case NSF3FunctionKey: return KeyEvent.VK_F3; - case NSF4FunctionKey: return KeyEvent.VK_F4; - case NSF5FunctionKey: return KeyEvent.VK_F5; - case NSF6FunctionKey: return KeyEvent.VK_F6; - case NSF7FunctionKey: return KeyEvent.VK_F7; - case NSF8FunctionKey: return KeyEvent.VK_F8; - case NSF9FunctionKey: return KeyEvent.VK_F9; - case NSF10FunctionKey: return KeyEvent.VK_F10; - case NSF11FunctionKey: return KeyEvent.VK_F11; - case NSF12FunctionKey: return KeyEvent.VK_F12; - case NSF13FunctionKey: return KeyEvent.VK_F13; - case NSF14FunctionKey: return KeyEvent.VK_F14; - case NSF15FunctionKey: return KeyEvent.VK_F15; - case NSF16FunctionKey: return KeyEvent.VK_F16; - case NSF17FunctionKey: return KeyEvent.VK_F17; - case NSF18FunctionKey: return KeyEvent.VK_F18; - case NSF19FunctionKey: return KeyEvent.VK_F19; - case NSF20FunctionKey: return KeyEvent.VK_F20; - case NSF21FunctionKey: return KeyEvent.VK_F21; - case NSF22FunctionKey: return KeyEvent.VK_F22; - case NSF23FunctionKey: return KeyEvent.VK_F23; - case NSF24FunctionKey: return KeyEvent.VK_F24; - case NSInsertFunctionKey: return KeyEvent.VK_INSERT; - case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; - case NSHomeFunctionKey: return KeyEvent.VK_HOME; - case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; - case NSEndFunctionKey: return KeyEvent.VK_END; - case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; - case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; - case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; - case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; - case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; - // Not handled: - // NSSysReqFunctionKey - // NSBreakFunctionKey - // NSResetFunctionKey - case NSStopFunctionKey: return KeyEvent.VK_STOP; - // Not handled: - // NSMenuFunctionKey - // NSUserFunctionKey - // NSSystemFunctionKey - // NSPrintFunctionKey - // NSClearLineFunctionKey - // NSClearDisplayFunctionKey - // NSInsertLineFunctionKey - // NSDeleteLineFunctionKey - // NSInsertCharFunctionKey - // NSDeleteCharFunctionKey - // NSPrevFunctionKey - // NSNextFunctionKey - // NSSelectFunctionKey - // NSExecuteFunctionKey - // NSUndoFunctionKey - // NSRedoFunctionKey - // NSFindFunctionKey - // NSHelpFunctionKey - // NSModeSwitchFunctionKey - default: break; - } - } - - // NSEvent's charactersIgnoringModifiers doesn't ignore the shift key - if (keyChar >= 'a' && keyChar <= 'z') { - return Character.toUpperCase(keyChar); - } - - return keyChar; - } - - private void createWindow(final boolean recreate, + private void createWindow(final boolean offscreenInstance, final boolean recreate, final PointImmutable pS, final int width, final int height, final boolean fullscreen) { @@ -406,59 +340,27 @@ public class MacWindow extends WindowImpl { } setWindowHandle(createWindow0(getParentWindowHandle(), pS.getX(), pS.getY(), width, height, - config.getChosenCapabilities().isBackgroundOpaque(), + (getGraphicsConfiguration().getChosenCapabilities().isBackgroundOpaque() && !offscreenInstance), fullscreen, - (isUndecorated() ? - NSBorderlessWindowMask : - NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), + ((isUndecorated() || offscreenInstance) ? + NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), NSBackingStoreBuffered, getScreen().getIndex(), surfaceHandle)); if (getWindowHandle() == 0) { throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); } surfaceHandle = contentView0(getWindowHandle()); - setTitle0(getWindowHandle(), getTitle()); - // need to revalidate real position - positionChanged(true, getLocationOnScreenImpl(0, 0)); // incl. validation + if( offscreenInstance ) { + orderOut0(0!=getParentWindowHandle() ? getParentWindowHandle() : getWindowHandle()); + } else { + setTitle0(getWindowHandle(), getTitle()); + } } catch (Exception ie) { ie.printStackTrace(); } } - private void positionChanged(boolean defer, Point absPos) { - if(getWindowHandle()!=0) { - position2ClientSpace(absPos); - super.positionChanged(defer, absPos.getX(), absPos.getY()); - } - } - - private Point position2ClientSpace(Point absPos) { - final NativeWindow parent = getParent(); - if(null != parent) { - return absPos.translate( parent.getLocationOnScreen(null).scale(-1, -1) ); - } - return absPos; - } - - private Point position2TopLevel(Point clientPos) { - if(0<=clientPos.getX() && 0<=clientPos.getY()) { - final InsetsImmutable _insets = getInsets(); // zero if undecorated - // client position -> top-level window position - clientPos.setX(clientPos.getX() - _insets.getLeftWidth()) ; - clientPos.setY(clientPos.getY() - _insets.getTopHeight()) ; - } - // min val is 0 - clientPos.setX(Math.max(clientPos.getX(), 0)); - clientPos.setY(Math.max(clientPos.getY(), 0)); - // On MacOSX the absolute position is required to position - // a window - even a child window! - final NativeWindow parent = getParent(); - if( null != parent && 0 != parent.getWindowHandle() ) { - clientPos.translate(parent.getLocationOnScreen(null)); - } - return clientPos; - } - protected static native boolean initIDs0(); private native long createWindow0(long parentWindowHandle, int x, int y, int w, int h, boolean opaque, boolean fullscreen, int windowStyle, @@ -467,6 +369,7 @@ public class MacWindow extends WindowImpl { private native boolean lockSurface0(long window); private native void unlockSurface0(long window); private native void requestFocus0(long window, boolean force); + private native void requestFocusParent0(long window); /** in case of a child window, it actually only issues orderBack(..) */ private native void orderOut0(long window); private native void orderFront0(long window); @@ -481,4 +384,21 @@ public class MacWindow extends WindowImpl { private static native boolean setPointerVisible0(long windowHandle, boolean visible); private static native boolean confinePointer0(long windowHandle, boolean confine); private static native void warpPointer0(long windowHandle, int x, int y); + + // Window styles + private static final int NSBorderlessWindowMask = 0; + private static final int NSTitledWindowMask = 1 << 0; + private static final int NSClosableWindowMask = 1 << 1; + private static final int NSMiniaturizableWindowMask = 1 << 2; + private static final int NSResizableWindowMask = 1 << 3; + + // Window backing store types + private static final int NSBackingStoreRetained = 0; + private static final int NSBackingStoreNonretained = 1; + private static final int NSBackingStoreBuffered = 2; + + private volatile long surfaceHandle = 0; + private long sscSurfaceHandle = 0; + private boolean isOffscreenInstance = false; + } diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowsScreen.java b/src/newt/classes/jogamp/newt/driver/windows/WindowsScreen.java index f2e457a0f..f8bce9da3 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowsScreen.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowsScreen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,17 +33,15 @@ */ package jogamp.newt.driver.windows; -import com.jogamp.common.util.ArrayHashSet; -import java.util.ArrayList; +import javax.media.nativewindow.DefaultGraphicsScreen; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; -import com.jogamp.newt.*; import jogamp.newt.ScreenImpl; + import com.jogamp.newt.ScreenMode; -import jogamp.newt.ScreenModeStatus; import com.jogamp.newt.util.ScreenModeUtil; -import javax.media.nativewindow.*; - public class WindowsScreen extends ScreenImpl { static { @@ -54,9 +53,8 @@ public class WindowsScreen extends ScreenImpl { protected void createNativeImpl() { aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); - setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); } - + protected void closeNativeImpl() { } @@ -104,9 +102,21 @@ public class WindowsScreen extends ScreenImpl { sm.getRotation()); } + protected int validateScreenIndex(int idx) { + return 0; // big-desktop, only one screen available + } + + protected void getVirtualScreenOriginAndSize(Point virtualOrigin, Dimension virtualSize) { + virtualOrigin.setX(getOriginX0(screen_idx)); + virtualOrigin.setY(getOriginY0(screen_idx)); + virtualSize.setWidth(getWidthImpl0(screen_idx)); + virtualSize.setHeight(getHeightImpl0(screen_idx)); + } + // Native calls + private native int getOriginX0(int screen_idx); + private native int getOriginY0(int screen_idx); private native int getWidthImpl0(int scrn_idx); - private native int getHeightImpl0(int scrn_idx); private native int[] getScreenMode0(int screen_index, int mode_index); diff --git a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java index cd5909d42..ff3bd5ef6 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java +++ b/src/newt/classes/jogamp/newt/driver/windows/WindowsWindow.java @@ -35,13 +35,17 @@ package jogamp.newt.driver.windows; import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIUtil; import jogamp.newt.WindowImpl; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; @@ -100,17 +104,18 @@ public class WindowsWindow extends WindowImpl { } protected void createNativeImpl() { - WindowsScreen screen = (WindowsScreen) getScreen(); - WindowsDisplay display = (WindowsDisplay) screen.getDisplay(); - config = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()).chooseGraphicsConfiguration( + final WindowsScreen screen = (WindowsScreen) getScreen(); + final WindowsDisplay display = (WindowsDisplay) screen.getDisplay(); + final AbstractGraphicsConfiguration cfg = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()).chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen()); - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } + setGraphicsConfiguration(cfg); final int flags = getReconfigureFlags(0, true) & ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; setWindowHandle(CreateWindow0(display.getHInstance(), display.getWindowClassName(), display.getWindowClassName(), - getParentWindowHandle(), x, y, width, height, flags)); + getParentWindowHandle(), x, y, width, height, autoPosition, flags)); if (getWindowHandle() == 0) { throw new NativeWindowException("Error creating window"); } @@ -169,12 +174,8 @@ public class WindowsWindow extends WindowImpl { final InsetsImmutable i = getInsets(); // client position -> top-level window position - if(0<=x && 0<=y) { - x -= i.getLeftWidth() ; - y -= i.getTopHeight() ; - if( 0 > x ) { x = 0; } - if( 0 > y ) { y = 0; } - } + x -= i.getLeftWidth() ; + y -= i.getTopHeight() ; if(0<width && 0<height) { // client size -> top-level window size @@ -237,13 +238,43 @@ public class WindowsWindow extends WindowImpl { } protected Point getLocationOnScreenImpl(int x, int y) { - return GDI.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); + return GDIUtil.GetRelativeLocation( getWindowHandle(), 0 /*root win*/, x, y); } protected void updateInsetsImpl(Insets insets) { // nop - using event driven insetsChange(..) } + private final int validateKeyCode(int eventType, int keyCode) { + switch(eventType) { + case KeyEvent.EVENT_KEY_PRESSED: + lastPressedKeyCode = keyCode; + break; + case KeyEvent.EVENT_KEY_TYPED: + if(-1==keyCode) { + keyCode = lastPressedKeyCode; + } + lastPressedKeyCode = -1; + break; + } + return keyCode; + } + private int lastPressedKeyCode = 0; + + @Override + public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { + // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform + keyCode = validateKeyCode(eventType, keyCode); + super.sendKeyEvent(eventType, modifiers, keyCode, keyChar); + } + + @Override + public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { + // Note that we have to regenerate the keyCode for EVENT_KEY_TYPED on this platform + keyCode = validateKeyCode(eventType, keyCode); + super.enqueueKeyEvent(wait, eventType, modifiers, keyCode, keyChar); + } + //---------------------------------------------------------------------- // Internals only // @@ -252,7 +283,7 @@ public class WindowsWindow extends WindowImpl { private native long CreateWindow0(long hInstance, String wndClassName, String wndName, long parentWindowHandle, - int x, int y, int width, int height, int flags); + int x, int y, int width, int height, boolean autoPosition, int flags); private native long MonitorFromWindow0(long windowHandle); private native void reconfigureWindow0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, int flags); diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Display.java b/src/newt/classes/jogamp/newt/driver/x11/X11Display.java index b9a32c7de..b3bc6e475 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Display.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Display.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,10 +34,14 @@ package jogamp.newt.driver.x11; -import javax.media.nativewindow.*; -import javax.media.nativewindow.x11.*; -import jogamp.newt.*; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.x11.X11GraphicsDevice; + import jogamp.nativewindow.x11.X11Util; +import jogamp.newt.DisplayImpl; +import jogamp.newt.NEWTJNILibLoader; public class X11Display extends DisplayImpl { @@ -64,6 +69,20 @@ public class X11Display extends DisplayImpl { return X11Util.validateDisplayName(name, handle); } + /** + * {@inheritDoc} + * + * We use a private non-shared X11 Display instance for EDT window operations and one for exposed animation, eg. OpenGL. + * <p> + * In case {@link X11Util#HAS_XLOCKDISPLAY_BUG} and {@link X11Util#XINITTHREADS_ALWAYS_ENABLED}, + * we use null locking. Even though this seems not to be rational, it gives most stable results on all platforms. + * </p> + * <p> + * Otherwise we use basic locking via the constructor {@link X11GraphicsDevice#X11GraphicsDevice(long, int, boolean)}, + * since it is possible to share this device via {@link com.jogamp.newt.NewtFactory#createDisplay(String, boolean)}. + * </p> + */ + @SuppressWarnings("unused") protected void createNativeImpl() { long handle = X11Util.openDisplay(name); if( 0 == handle ) { @@ -85,12 +104,11 @@ public class X11Display extends DisplayImpl { throw e; } - if(X11Util.XINITTHREADS_ALWAYS_ENABLED) { - // Hack: Force non X11Display locking, even w/ AWT and w/o isFirstUIActionOnProcess() - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock()); + // see API doc above! + if(X11Util.XINITTHREADS_ALWAYS_ENABLED && X11Util.HAS_XLOCKDISPLAY_BUG) { + aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, NativeWindowFactory.getNullToolkitLock(), false); } else { - // Proper: Use AWT/X11Display locking w/ AWT and X11Display locking only w/o isFirstUIActionOnProcess() - aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT); + aDevice = new X11GraphicsDevice(handle, AbstractGraphicsDevice.DEFAULT_UNIT, false); } } diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Screen.java b/src/newt/classes/jogamp/newt/driver/x11/X11Screen.java index 5c9c326d7..ed5ebc04e 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Screen.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Screen.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,6 +33,8 @@ */ package jogamp.newt.driver.x11; +import jogamp.nativewindow.x11.X11Lib; +import jogamp.nativewindow.x11.X11Util; import jogamp.newt.DisplayImpl; import jogamp.newt.ScreenImpl; import jogamp.newt.DisplayImpl.DisplayRunnable; @@ -40,6 +43,8 @@ import com.jogamp.newt.ScreenMode; import com.jogamp.newt.util.ScreenModeUtil; import java.util.List; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; import javax.media.nativewindow.x11.*; public class X11Screen extends ScreenImpl { @@ -55,11 +60,7 @@ public class X11Screen extends ScreenImpl { // validate screen index Long handle = display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Long>() { public Long run(long dpy) { - long handle = GetScreen0(dpy, screen_idx); - if(0 != handle) { - setScreenSize(getWidth0(dpy, screen_idx), getHeight0(dpy, screen_idx)); - } - return new Long(handle); + return new Long(GetScreen0(dpy, screen_idx)); } } ); if (handle.longValue() == 0) { throw new RuntimeException("Error creating screen: " + screen_idx); @@ -245,35 +246,64 @@ public class X11Screen extends ScreenImpl { } }).booleanValue(); - if(DEBUG && done) { + if(DEBUG || !done) { System.err.println("X11Screen.setCurrentScreenModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+ - (System.currentTimeMillis()-t0)+"ms"); + (System.currentTimeMillis()-t0)+"ms; Current: "+getCurrentScreenMode()+"; Desired: "+screenMode); } return done; } + private class XineramaEnabledQuery implements DisplayImpl.DisplayRunnable<Boolean> { + public Boolean run(long dpy) { + return new Boolean(X11Lib.XineramaEnabled(dpy)); + } + } + private XineramaEnabledQuery xineramaEnabledQuery = new XineramaEnabledQuery(); + + protected int validateScreenIndex(final int idx) { + if(getDisplay().isNativeValid()) { + return runWithLockedDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + } else { + return runWithTempDisplayHandle( xineramaEnabledQuery ).booleanValue() ? 0 : idx; + } + } + + protected void getVirtualScreenOriginAndSize(final Point virtualOrigin, final Dimension virtualSize) { + display.runWithLockedDisplayHandle( new DisplayImpl.DisplayRunnable<Object>() { + public Object run(long dpy) { + virtualOrigin.setX(0); + virtualOrigin.setY(0); + virtualSize.setWidth(getWidth0(dpy, screen_idx)); + virtualSize.setHeight(getHeight0(dpy, screen_idx)); + return null; + } } ); + } + //---------------------------------------------------------------------- // Internals only // private final <T> T runWithLockedDisplayHandle(DisplayRunnable<T> action) { return display.runWithLockedDisplayHandle(action); // return runWithTempDisplayHandle(action); + // return runWithoutLock(action); } - /** just here for testing some X11 RANDR bugs .. etc .. - private final Object runWithTempDisplayHandle(DisplayRunnable action) { - long dpy = X11Util.openDisplay(null); - if(0 == dpy) { + private final <T> T runWithTempDisplayHandle(DisplayRunnable<T> action) { + final long displayHandle = X11Util.openDisplay(display.getName()); + if(0 == displayHandle) { throw new RuntimeException("null device"); } - Object res; + T res; try { - res = action.run(dpy); + res = action.run(displayHandle); } finally { - X11Util.closeDisplay(dpy); + X11Util.closeDisplay(displayHandle); } return res; - } */ + } + private final <T> T runWithoutLock(DisplayRunnable<T> action) { + return action.run(display.getHandle()); + } private static native long GetScreen0(long dpy, int scrn_idx); diff --git a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java index 2b6bac215..33b541c34 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/X11Window.java +++ b/src/newt/classes/jogamp/newt/driver/x11/X11Window.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,7 +34,7 @@ package jogamp.newt.driver.x11; -import jogamp.nativewindow.x11.X11Util; +import jogamp.nativewindow.x11.X11Lib; import jogamp.newt.DisplayImpl; import jogamp.newt.DisplayImpl.DisplayRunnable; import jogamp.newt.WindowImpl; @@ -43,9 +44,15 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.newt.event.MouseEvent; + public class X11Window extends WindowImpl { private static final String WINDOW_CLASS_NAME = "NewtWindow"; - + private static final int X11_WHEEL_ONE_UP_BUTTON = 4; + private static final int X11_WHEEL_ONE_DOWN_BUTTON = 5; + private static final int X11_WHEEL_TWO_UP_BUTTON = 6; + private static final int X11_WHEEL_TWO_DOWN_BUTTON = 7; + static { X11Display.initSingleton(); } @@ -57,22 +64,22 @@ public class X11Window extends WindowImpl { final X11Screen screen = (X11Screen) getScreen(); final X11Display display = (X11Display) screen.getDisplay(); final GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()); - config = factory.chooseGraphicsConfiguration( + final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) factory.chooseGraphicsConfiguration( capsRequested, capsRequested, capabilitiesChooser, screen.getGraphicsScreen()); if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+config); + System.err.println("X11Window.createNativeImpl() factory: "+factory+", chosen config: "+cfg); } - if (config == null) { + if (null == cfg) { throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); } - X11GraphicsConfiguration x11config = (X11GraphicsConfiguration) config; - final long visualID = x11config.getVisualID(); + setGraphicsConfiguration(cfg); + final long visualID = cfg.getVisualID(); final int flags = getReconfigureFlags(0, true) & ( FLAG_IS_ALWAYSONTOP | FLAG_IS_UNDECORATED ) ; setWindowHandle(CreateWindow0(getParentWindowHandle(), display.getEDTHandle(), screen.getIndex(), visualID, display.getJavaObjectAtom(), display.getWindowDeleteAtom(), - x, y, width, height, flags)); + x, y, width, height, autoPosition, flags)); windowHandleClose = getWindowHandle(); if (0 == windowHandleClose) { throw new NativeWindowException("Error creating window"); @@ -101,14 +108,12 @@ public class X11Window extends WindowImpl { System.err.println("X11Window reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ getReconfigureFlagsAsString(null, flags)); } - if(0 == ( FLAG_IS_UNDECORATED & flags) && 0<=x && 0<=y) { + if(0 == ( FLAG_IS_UNDECORATED & flags)) { final InsetsImmutable i = getInsets(); // client position -> top-level window position x -= i.getLeftWidth() ; y -= i.getTopHeight() ; - if( 0 > x ) { x = 0; } - if( 0 > y ) { y = 0; } } reconfigureWindow0( getDisplayEDTHandle(), getScreenIndex(), getParentWindowHandle(), getWindowHandle(), x, y, width, height, flags); @@ -167,13 +172,55 @@ public class X11Window extends WindowImpl { protected Point getLocationOnScreenImpl(final int x, final int y) { // X11Util.GetRelativeLocation: locks display already ! - return X11Util.GetRelativeLocation( getScreen().getDisplay().getHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + return X11Lib.GetRelativeLocation( getScreen().getDisplay().getHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); } protected void updateInsetsImpl(Insets insets) { // nop - using event driven insetsChange(..) } + protected void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { + switch(eventType) { + case MouseEvent.EVENT_MOUSE_PRESSED: + switch(button) { + case X11_WHEEL_ONE_UP_BUTTON: + case X11_WHEEL_ONE_DOWN_BUTTON: + case X11_WHEEL_TWO_UP_BUTTON: + case X11_WHEEL_TWO_DOWN_BUTTON: + // ignore wheel pressed ! + return; + } + break; + case MouseEvent.EVENT_MOUSE_RELEASED: + switch(button) { + case X11_WHEEL_ONE_UP_BUTTON: + eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; + button = 1; + rotation = 1; + break; + case X11_WHEEL_ONE_DOWN_BUTTON: + eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; + button = 1; + rotation = -1; + break; + case X11_WHEEL_TWO_UP_BUTTON: + eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; + button = 2; + rotation = 1; + break; + case X11_WHEEL_TWO_DOWN_BUTTON: + eventType = MouseEvent.EVENT_MOUSE_WHEEL_MOVED; + button = 2; + rotation = -1; + break; + } + break; + } + super.doMouseEvent(enqueue, wait, eventType, modifiers, x, y, button, rotation); + } + + //---------------------------------------------------------------------- // Internals only // @@ -190,7 +237,7 @@ public class X11Window extends WindowImpl { private native long CreateWindow0(long parentWindowHandle, long display, int screen_index, long visualID, long javaObjectAtom, long windowDeleteAtom, - int x, int y, int width, int height, int flags); + int x, int y, int width, int height, boolean autoPosition, int flags); private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom); private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long windowHandle, int x, int y, int width, int height, int flags); diff --git a/src/newt/native/KDWindow.c b/src/newt/native/KDWindow.c index 5f1affed1..e6bc7952e 100644 --- a/src/newt/native/KDWindow.c +++ b/src/newt/native/KDWindow.c @@ -256,7 +256,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_kd_KDWindow_RealizeWindow jint res = kdRealizeWindow(w, &nativeWindow); if(res) { fprintf(stderr, "[RealizeWindow] failed: 0x%X, 0x%X\n", res, kdGetError()); - nativeWindow = NULL; + nativeWindow = 0; } DBG_PRINT( "[RealizeWindow] ok: %p\n", nativeWindow); return (jlong) (intptr_t) nativeWindow; diff --git a/src/newt/native/KeyEvent.h b/src/newt/native/KeyEvent.h index 1ead0f5e8..0f7b1606b 100644 --- a/src/newt/native/KeyEvent.h +++ b/src/newt/native/KeyEvent.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ #ifndef _KEY_EVENT_H_ #define _KEY_EVENT_H_ diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index a13ffaf31..ddd59f0a1 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -38,6 +38,7 @@ #import "MouseEvent.h" #import "KeyEvent.h" +#import "ScreenMode.h" #import <ApplicationServices/ApplicationServices.h> @@ -48,7 +49,6 @@ static const char * const ClazzAnyCstrName = "<init>"; static const char * const ClazzNamePointCstrSignature = "(II)V"; static jclass pointClz = NULL; static jmethodID pointCstr = NULL; -static jmethodID focusActionID = NULL; static NSString* jstringToNSString(JNIEnv* env, jstring jstr) { @@ -192,13 +192,57 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_initNSAppli JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_runNSApplication0 (JNIEnv *env, jclass clazz) { - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; DBG_PRINT( "\nrunNSApplication0.0\n"); [NSApp run]; DBG_PRINT( "\nrunNSApplication0.X\n"); - // [pool release]; + [pool release]; +} + +/* + * Class: jogamp_newt_driver_macosx_MacDisplay + * Method: stopNSApplication0 + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacDisplay_stopNSApplication0 + (JNIEnv *env, jclass clazz) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT( "\nstopNSApplication0.0 nsApp.running %d\n", (NSApp && [NSApp isRunning])); + + if(NSApp && [NSApp isRunning]) { + [NSApp performSelectorOnMainThread:@selector(stop:) withObject:nil waitUntilDone:YES]; + // [NSApp stop: nil]; + NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined + location: NSMakePoint(0,0) + modifierFlags: 0 + timestamp: 0.0 + windowNumber: 0 + context: nil + subtype: 0 + data1: 0 + data2: 0]; + DBG_PRINT( "\nstopNSApplication0.1\n"); + [NSApp postEvent: event atStart: true]; + } + /** + DBG_PRINT( "\nstopNSApplication0.2\n"); + if(NSApp && [NSApp isRunning]) { + DBG_PRINT( "\nstopNSApplication0.3\n"); + [NSApp terminate:nil]; + } */ + + DBG_PRINT( "\nstopNSApplication0.X\n"); + [pool release]; +} + +static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) { + NSArray *screens = [NSScreen screens]; + if(screen_idx<0) screen_idx=0; + if(screen_idx>=[screens count]) screen_idx=0; + return (NSScreen *) [screens objectAtIndex: screen_idx]; } /* @@ -211,10 +255,7 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getWidthImpl0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); NSRect rect = [screen frame]; [pool release]; @@ -232,10 +273,7 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getHeightImpl0 { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray *screens = [NSScreen screens]; - if(screen_idx<0) screen_idx=0; - if(screen_idx>=[screens count]) screen_idx=0; - NSScreen *screen = (NSScreen *) [screens objectAtIndex: screen_idx]; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)screen_idx); NSRect rect = [screen frame]; [pool release]; @@ -243,6 +281,175 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getHeightImpl0 return (jint) (rect.size.height); } +static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) { + // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! + NSDictionary * dict = [screen deviceDescription]; + NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; + // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size + return (CGDirectDisplayID) [val integerValue]; +} + +/** + * Only in >= 10.6: + * CGDisplayModeGetWidth(mode) + * CGDisplayModeGetRefreshRate(mode) + * CGDisplayModeGetHeight(mode) + */ +static long GetDictionaryLong(CFDictionaryRef theDict, const void* key) +{ + long value = 0; + CFNumberRef numRef; + numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); + if (numRef != NULL) + CFNumberGetValue(numRef, kCFNumberLongType, &value); + return value; +} +#define CGDDGetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth) +#define CGDDGetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight) +#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate) +#define CGDDGetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel) + +// Duplicate each Mode by all possible rotations (4): +// For each real-mode: [mode, 0], [mode, 90], [mode, 180], [mode, 270] +#define ROTMODES_PER_REALMODE 4 + +/* + * Class: jogamp_newt_driver_macosx_MacScreen + * Method: getScreenMode0 + * Signature: (II)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_MacScreen_getScreenMode0 + (JNIEnv *env, jobject obj, jint scrn_idx, jint mode_idx) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + int prop_num = NUM_SCREEN_MODE_PROPERTIES_ALL; + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + + CFArrayRef availableModes = CGDisplayAvailableModes(display); + CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes); + CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; + CFDictionaryRef mode = NULL; + int currentCCWRot = (int)CGDisplayRotation(display); + jint ccwRot = 0; + +#ifdef VERBOSE_ON + if(0 >= mode_idx) { + // only for current mode (-1) and first mode (scanning) + DBG_PRINT( "getScreenMode0: scrn %d (%p, %p), mode %d, avail: %d/%d, current rot %d ccw\n", + (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots, currentCCWRot); + } +#endif + + if(numberOfAvailableModesRots<=mode_idx) { + // n/a - end of modes + DBG_PRINT( "getScreenMode0: end of modes: mode %d, avail: %d/%d\n", + (int)mode_idx, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + [pool release]; + return (*env)->NewIntArray(env, 0); + } else if(-1 < mode_idx) { + // only at initialization time, where index >= 0 + prop_num++; // add 1st extra prop, mode_idx + mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); + ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + } else { + // current mode + mode = CGDisplayCurrentMode(display); + ccwRot = currentCCWRot; + } + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + + CGSize screenDim = CGDisplayScreenSize(display); + int mWidth = CGDDGetModeWidth(mode); + int mHeight = CGDDGetModeHeight(mode); + + // swap width and height, since OSX reflects rotated dimension, we don't + if ( 90 == currentCCWRot || 270 == currentCCWRot ) { + int tempWidth = mWidth; + mWidth = mHeight; + mHeight = tempWidth; + } + + jint prop[ prop_num ]; + int propIndex = 0; + int propIndexRes = 0; + + if( -1 < mode_idx ) { + prop[propIndex++] = mode_idx; + } + prop[propIndex++] = 0; // set later for verification of iterator + propIndexRes = propIndex; + prop[propIndex++] = mWidth; + prop[propIndex++] = mHeight; + prop[propIndex++] = CGDDGetModeBitsPerPixel(mode); + prop[propIndex++] = (jint) screenDim.width; + prop[propIndex++] = (jint) screenDim.height; + prop[propIndex++] = CGDDGetModeRefreshRate(mode); + prop[propIndex++] = ccwRot; + prop[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = ( -1 < mode_idx ) ? propIndex-1 : propIndex ; // count == NUM_SCREEN_MODE_PROPERTIES_ALL + + DBG_PRINT( "getScreenMode0: Mode %d/%d (%d): %dx%d, %d bpp, %dx%d mm, %d Hz, rot %d ccw\n", + (int)mode_idx, (int)numberOfAvailableModesRots, (int)numberOfAvailableModes, + (int)prop[propIndexRes+0], (int)prop[propIndexRes+1], (int)prop[propIndexRes+2], + (int)prop[propIndexRes+3], (int)prop[propIndexRes+4], (int)prop[propIndexRes+5], (int)prop[propIndexRes+6]); + + jintArray properties = (*env)->NewIntArray(env, prop_num); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", prop_num); + } + (*env)->SetIntArrayRegion(env, properties, 0, prop_num, prop); + + // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef + [pool release]; + + return properties; +} + +/* + * Class: jogamp_newt_driver_macosx_MacScreen + * Method: setScreenMode0 + * Signature: (II)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacScreen_setScreenMode0 + (JNIEnv *env, jobject object, jint scrn_idx, jint mode_idx) +{ + jboolean res = JNI_TRUE; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSScreen *screen = NewtScreen_getNSScreenByIndex((int)scrn_idx); + CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen); + + CFArrayRef availableModes = CGDisplayAvailableModes(display); + CFIndex numberOfAvailableModes = CFArrayGetCount(availableModes); + CFIndex numberOfAvailableModesRots = ROTMODES_PER_REALMODE * numberOfAvailableModes; + + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, mode_idx / ROTMODES_PER_REALMODE); + // mode = CGDisplayModeRetain(mode); // 10.6 on CGDisplayModeRef + + int ccwRot = mode_idx % ROTMODES_PER_REALMODE * 90; + DBG_PRINT( "setScreenMode0: scrn %d (%p, %p), mode %d, rot %d ccw, avail: %d/%d\n", + (int)scrn_idx, screen, (void*)(intptr_t)display, (int)mode_idx, ccwRot, (int)numberOfAvailableModes, (int)numberOfAvailableModesRots); + + if(ccwRot!=0) { + // FIXME: How to rotate the display/screen on OSX programmatically ? + DBG_PRINT( "setScreenMode0: Don't know how to rotate screen on OS X: rot %d ccw\n", ccwRot); + res = JNI_FALSE; + } + if(JNI_TRUE == res) { + CGError err = CGDisplaySwitchToMode(display, mode); + if(kCGErrorSuccess != err) { + DBG_PRINT( "setScreenMode0: SetMode failed: %d\n", (int)err); + res = JNI_FALSE; + } + } + + // CGDisplayModeRelease(mode); // 10.6 on CGDisplayModeRef + [pool release]; + + return res; +} + /* * Class: jogamp_newt_driver_macosx_MacWindow * Method: initIDs @@ -272,11 +479,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_macosx_MacWindow_initIDs0 ClazzNamePoint, ClazzAnyCstrName, ClazzNamePointCstrSignature); } - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); - if(NULL==focusActionID) { - NewtCommon_FatalError(env, "FatalError Java_jogamp_newt_driver_macosx_MacWindow_initIDs0: can't fetch method focusAction()Z"); - } - // Need this when debugging, as it is necessary to attach gdb to // the running java process -- "gdb java" doesn't work // printf("Going to sleep for 10 seconds\n"); @@ -449,8 +651,9 @@ NS_DURING if([mView isInFullScreenMode]) { [mView exitFullScreenModeWithOptions: NULL]; } - [mWin setContentView: nil]; - [mView release]; + // Note: mWin's release will also release it's mView! + // [mWin setContentView: nil]; + // [mView release]; } NS_HANDLER NS_ENDHANDLER @@ -463,7 +666,11 @@ NS_ENDHANDLER DBG_PRINT( "windowClose.1 - %p,%d view %p,%d, parent %p\n", mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); - [mWin close]; // performs release! + // '[mWin close]' causes a crash at exit. + // This probably happens b/c it sends events to the main loop + // but our resources are gone ?! + // However, issuing a simple release seems to work quite well. + [mWin release]; DBG_PRINT( "windowClose.X - %p,%d view %p,%d, parent %p\n", mWin, getRetainCount(mWin), mView, getRetainCount(mView), pWin); @@ -510,26 +717,44 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocus0 (JNIEnv *env, jobject window, jlong w, jboolean force) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = (NSWindow*) ((intptr_t) w); + NSWindow* mWin = (NSWindow*) ((intptr_t) w); #ifdef VERBOSE_ON - BOOL hasFocus = [win isKeyWindow]; + BOOL hasFocus = [mWin isKeyWindow]; #endif - DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", win, force, hasFocus); - - // Even if we already own the focus, we need the 'focusAction()' call - // and the other probably redundant NS calls to force proper focus traversal - // of the parent TK (AWT doesn't do it properly on OSX). - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - DBG_PRINT( "makeKeyWindow win %p\n", win); - // [win performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; - // [win performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; - [win orderFrontRegardless]; - [win makeKeyWindow]; - [win makeFirstResponder: nil]; - } + DBG_PRINT( "requestFocus - window: %p, force %d, hasFocus %d (START)\n", mWin, force, hasFocus); + + [mWin makeFirstResponder: nil]; + // [mWin performSelectorOnMainThread:@selector(orderFrontRegardless) withObject:nil waitUntilDone:YES]; + // [mWin performSelectorOnMainThread:@selector(makeKeyWindow) withObject:nil waitUntilDone:YES]; + [mWin orderFrontRegardless]; + [mWin makeKeyWindow]; + + DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", mWin, force); + + [pool release]; +} - DBG_PRINT( "requestFocus - window: %p, force %d (END)\n", win, force); +/* + * Class: jogamp_newt_driver_macosx_MacWindow + * Method: requestFocusParent0 + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_macosx_MacWindow_requestFocusParent0 + (JNIEnv *env, jobject window, jlong w) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* mWin = (NSWindow*) ((intptr_t) w); + NSWindow* pWin = [mWin parentWindow]; +#ifdef VERBOSE_ON + BOOL hasFocus = [mWin isKeyWindow]; +#endif + + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p, hasFocus %d (START)\n", mWin, pWin, hasFocus ); + if(NULL != pWin) { + [pWin makeKeyWindow]; + } + DBG_PRINT( "requestFocusParent0 - window: %p, parent: %p (END)\n", mWin, pWin); [pool release]; } diff --git a/src/newt/native/MouseEvent.h b/src/newt/native/MouseEvent.h index e9c0476ef..59d63cecf 100644 --- a/src/newt/native/MouseEvent.h +++ b/src/newt/native/MouseEvent.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ #ifndef _MOUSE_EVENT_H_ #define _MOUSE_EVENT_H_ diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index 91fceb310..33aba64ae 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ #ifndef NEWT_COMMON_H #define NEWT_COMMON_H 1 diff --git a/src/newt/native/NewtMacWindow.h b/src/newt/native/NewtMacWindow.h index cb256e71f..3ba89de1e 100644 --- a/src/newt/native/NewtMacWindow.h +++ b/src/newt/native/NewtMacWindow.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2011 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -40,7 +41,8 @@ // #define VERBOSE_ON 1 #ifdef VERBOSE_ON - #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) #else #define DBG_PRINT(...) #endif @@ -53,8 +55,8 @@ JavaVM *jvmHandle; int jvmVersion; - BOOL destroyNotifySent; - BOOL softLocked; + volatile BOOL destroyNotifySent; + volatile BOOL softLocked; pthread_mutex_t softLockSync; NSTrackingRectTag ptrTrackingTag; @@ -88,7 +90,7 @@ - (BOOL) needsDisplay; - (void) displayIfNeeded; -- (void) viewWillDraw; +- (void) display; - (void) drawRect:(NSRect)dirtyRect; - (void) viewDidHide; - (void) viewDidUnhide; diff --git a/src/newt/native/NewtMacWindow.m b/src/newt/native/NewtMacWindow.m index 1f74742ec..ce41673c4 100644 --- a/src/newt/native/NewtMacWindow.m +++ b/src/newt/native/NewtMacWindow.m @@ -44,15 +44,17 @@ jint GetDeltaY(NSEvent *event, jint javaMods) { // mouse pad case deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); + // fprintf(stderr, "WHEEL/PAD: %lf\n", (double)deltaY); } else { // traditional mouse wheel case deltaY = [event deltaY]; + // fprintf(stderr, "WHEEL/TRAD: %lf\n", (double)deltaY); if (deltaY == 0.0 && (javaMods & EVENT_SHIFT_MASK) != 0) { // shift+vertical wheel scroll produces horizontal scroll // we convert it to vertical deltaY = [event deltaX]; } - if (deltaY < 1.0 && deltaY > -1.0) { + if (-1.0 < deltaY && deltaY < 1.0) { deltaY *= 10.0; } else { if (deltaY < 0.0) { @@ -62,21 +64,15 @@ jint GetDeltaY(NSEvent *event, jint javaMods) { } } } - - if (deltaY > 0) { - return (NSInteger)deltaY; - } else if (deltaY < 0) { - return -(NSInteger)deltaY; - } - - return 0; + // fprintf(stderr, "WHEEL/res: %d\n", (int)deltaY); + return (jint) deltaY; } static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; @@ -104,7 +100,11 @@ static jmethodID windowRepaintID = NULL; jvmVersion = 0; destroyNotifySent = NO; softLocked = NO; - pthread_mutex_init(&softLockSync, NULL); // fast non-recursive + + pthread_mutexattr_t softLockSyncAttr; + pthread_mutexattr_init(&softLockSyncAttr); + pthread_mutexattr_settype(&softLockSyncAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&softLockSync, &softLockSyncAttr); // recursive ptrTrackingTag = 0; @@ -122,7 +122,7 @@ static jmethodID windowRepaintID = NULL; - (void) dealloc { if(softLocked) { - fprintf(stderr, "*** Warning: softLock still hold @ dealloc!\n"); fflush(NULL); + NSLog(@"NewtView::dealloc: softLock still hold @ dealloc!\n"); } pthread_mutex_destroy(&softLockSync); [super dealloc]; @@ -193,72 +193,61 @@ static jmethodID windowRepaintID = NULL; return destroyNotifySent; } -#define SOFT_LOCK_BLOCKING 1 - - (BOOL) softLock { + // DBG_PRINT("*************** softLock.0: %p\n", (void*)pthread_self()); + // NSLog(@"NewtView::softLock: %@",[NSThread callStackSymbols]); pthread_mutex_lock(&softLockSync); softLocked = YES; -#ifndef SOFT_LOCK_BLOCKING - pthread_mutex_unlock(&softLockSync); -#endif + // DBG_PRINT("*************** softLock.X: %p\n", (void*)pthread_self()); return softLocked; } - (void) softUnlock { -#ifndef SOFT_LOCK_BLOCKING - pthread_mutex_lock(&softLockSync); -#endif + // DBG_PRINT("*************** softUnlock: %p\n", (void*)pthread_self()); softLocked = NO; pthread_mutex_unlock(&softLockSync); } - (BOOL) needsDisplay { -#ifndef SOFT_LOCK_BLOCKING - return NO == softLocked && NO == destroyNotifySent && [super needsDisplay]; -#else return NO == destroyNotifySent && [super needsDisplay]; -#endif } - (void) displayIfNeeded { -#ifndef SOFT_LOCK_BLOCKING - if( NO == softLocked && NO == destroyNotifySent ) { + if( YES == [self needsDisplay] ) { + [self softLock]; [super displayIfNeeded]; + [self softUnlock]; } -#else - [self softLock]; - if( NO == destroyNotifySent ) { - [super displayIfNeeded]; - } - [self softUnlock]; -#endif } -- (void) viewWillDraw +- (void) display { - DBG_PRINT("*************** viewWillDraw: 0x%p\n", javaWindowObject); - [super viewWillDraw]; + if( NO == destroyNotifySent ) { + [self softLock]; + [super display]; + [self softUnlock]; + } } - (void) drawRect:(NSRect)dirtyRect { - DBG_PRINT("*************** dirtyRect: 0x%p %lf/%lf %lfx%lf\n", + DBG_PRINT("*************** dirtyRect: %p %lf/%lf %lfx%lf\n", javaWindowObject, dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } NSRect viewFrame = [self frame]; - (*env)->CallVoidMethod(env, javaWindowObject, windowRepaintID, JNI_FALSE, + (*env)->CallVoidMethod(env, javaWindowObject, windowRepaintID, JNI_TRUE, // defer .. dirtyRect.origin.x, viewFrame.size.height - dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); @@ -272,7 +261,7 @@ static jmethodID windowRepaintID = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } @@ -290,7 +279,7 @@ static jmethodID windowRepaintID = NULL; int shallBeDetached = 0; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); if(NULL==env) { - NSLog(@"viewDidHide: null JNIEnv"); + DBG_PRINT("viewDidHide: null JNIEnv\n"); return; } @@ -325,9 +314,9 @@ static jmethodID windowRepaintID = NULL; focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (enqueueMouseEventID && sendMouseEventID && enqueueKeyEventID && sendKeyEventID && sizeChangedID && visibleChangedID && insetsChangedID && - positionChangedID && focusChangedID && windowDestroyNotifyID && enqueueRequestFocusID && windowRepaintID) + positionChangedID && focusChangedID && windowDestroyNotifyID && requestFocusID && windowRepaintID) { return YES; } @@ -512,14 +501,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"sendKeyEvent: null javaWindowObject"); + DBG_PRINT("sendKeyEvent: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"sendKeyEvent: null JNIEnv"); + DBG_PRINT("sendKeyEvent: null JNIEnv\n"); return; } @@ -533,6 +522,8 @@ 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]; + DBG_PRINT("sendKeyEvent: %d/%d char 0x%X, code 0x%X\n", i, len, (int)keyChar, (int)keyCode); + #ifdef USE_SENDIO_DIRECT (*env)->CallVoidMethod(env, javaWindowObject, sendKeyEventID, evType, javaMods, keyCode, keyChar); @@ -567,14 +558,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"sendMouseEvent: null javaWindowObject"); + DBG_PRINT("sendMouseEvent: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"sendMouseEvent: null JNIEnv"); + DBG_PRINT("sendMouseEvent: null JNIEnv\n"); return; } jint javaMods = mods2JavaMods([event modifierFlags]); @@ -586,6 +577,7 @@ static jint mods2JavaMods(NSUInteger mods) switch ([event type]) { case NSScrollWheel: { scrollDeltaY = GetDeltaY(event, javaMods); + javaButtonNum = 1; break; } case NSLeftMouseDown: @@ -603,9 +595,6 @@ static jint mods2JavaMods(NSUInteger mods) case NSOtherMouseDragged: javaButtonNum = 2; break; - default: - javaButtonNum = 0; - break; } if (evType == EVENT_MOUSE_WHEEL_MOVED && scrollDeltaY == 0) { @@ -613,7 +602,7 @@ static jint mods2JavaMods(NSUInteger mods) return; } if (evType == EVENT_MOUSE_PRESSED) { - (*env)->CallVoidMethod(env, javaWindowObject, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, javaWindowObject, requestFocusID, JNI_FALSE); } NSPoint location = [self screenPos2NewtClientWinPos: [NSEvent mouseLocation]]; @@ -770,14 +759,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"windowDidResize: null javaWindowObject"); + DBG_PRINT("windowDidResize: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowDidResize: null JNIEnv"); + DBG_PRINT("windowDidResize: null JNIEnv\n"); return; } @@ -805,14 +794,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"windowDidMove: null javaWindowObject"); + DBG_PRINT("windowDidMove: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowDidMove: null JNIEnv"); + DBG_PRINT("windowDidMove: null JNIEnv\n"); return; } @@ -839,16 +828,16 @@ static jint mods2JavaMods(NSUInteger mods) if( false == [view getDestroyNotifySent] ) { jobject javaWindowObject = [view getJavaWindowObject]; - DBG_PRINT( "*************** windowWillClose.0: 0x%p\n", (void *)(intptr_t)javaWindowObject); + DBG_PRINT( "*************** windowWillClose.0: %p\n", (void *)(intptr_t)javaWindowObject); if (javaWindowObject == NULL) { - NSLog(@"windowWillClose: null javaWindowObject"); + DBG_PRINT("windowWillClose: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"windowWillClose: null JNIEnv"); + DBG_PRINT("windowWillClose: null JNIEnv\n"); return; } @@ -863,7 +852,7 @@ static jint mods2JavaMods(NSUInteger mods) if (shallBeDetached) { (*jvmHandle)->DetachCurrentThread(jvmHandle); } - DBG_PRINT( "*************** windowWillClose.X: 0x%p\n", (void *)(intptr_t)javaWindowObject); + DBG_PRINT( "*************** windowWillClose.X: %p\n", (void *)(intptr_t)javaWindowObject); } else { DBG_PRINT( "*************** windowWillClose (skip)\n"); } @@ -916,14 +905,14 @@ static jint mods2JavaMods(NSUInteger mods) NewtView* view = (NewtView *) nsview; jobject javaWindowObject = [view getJavaWindowObject]; if (javaWindowObject == NULL) { - NSLog(@"focusChanged: null javaWindowObject"); + DBG_PRINT("focusChanged: null javaWindowObject\n"); return; } int shallBeDetached = 0; JavaVM *jvmHandle = [view getJVMHandle]; JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, [view getJVMVersion], &shallBeDetached); if(NULL==env) { - NSLog(@"focusChanged: null JNIEnv"); + DBG_PRINT("focusChanged: null JNIEnv\n"); return; } diff --git a/src/newt/native/ScreenMode.h b/src/newt/native/ScreenMode.h index 0a760d54a..bb782910e 100644 --- a/src/newt/native/ScreenMode.h +++ b/src/newt/native/ScreenMode.h @@ -1,4 +1,32 @@ /** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +/** * WARNING: must be synced with com.jogamp.newt.util.ScreenModeUtil#streamIn*(int[]) */ diff --git a/src/newt/native/Window.h b/src/newt/native/Window.h index 865746b91..4755c4fc5 100644 --- a/src/newt/native/Window.h +++ b/src/newt/native/Window.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ #ifndef _WINDOW_H_ #define _WINDOW_H_ diff --git a/src/newt/native/WindowEvent.h b/src/newt/native/WindowEvent.h index 05491b43c..3dc6ba97e 100644 --- a/src/newt/native/WindowEvent.h +++ b/src/newt/native/WindowEvent.h @@ -1,3 +1,30 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ #ifndef _WINDOW_EVENT_H_ #define _WINDOW_EVENT_H_ diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index d60c40496..97fe6f28d 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -115,8 +115,7 @@ static jmethodID enqueueMouseEventID = NULL; static jmethodID sendMouseEventID = NULL; static jmethodID enqueueKeyEventID = NULL; static jmethodID sendKeyEventID = NULL; -static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; +static jmethodID requestFocusID = NULL; static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); @@ -602,18 +601,14 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, jb (void*) pHwnd, (void*)hwnd, current==hwnd); if( JNI_TRUE==force || current!=hwnd) { - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); - SetForegroundWindow(hwnd); // Slightly Higher Priority - SetFocus(hwnd);// Sets Keyboard Focus To Window - if(NULL!=pHwnd) { - SetActiveWindow(hwnd); - } - DBG_PRINT("*** WindowsWindow: requestFocus.X1\n"); - } else { - DBG_PRINT("*** WindowsWindow: requestFocus.X0\n"); + UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); + SetForegroundWindow(hwnd); // Slightly Higher Priority + SetFocus(hwnd);// Sets Keyboard Focus To Window + if(NULL!=pHwnd) { + SetActiveWindow(hwnd); } + DBG_PRINT("*** WindowsWindow: requestFocus.X1\n"); } DBG_PRINT("*** WindowsWindow: requestFocus.XX\n"); } @@ -870,11 +865,11 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_LBUTTONDOWN: DBG_PRINT("*** WindowsWindow: LBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 1, (jint) 0); useDefWindowProc = 1; break; @@ -883,18 +878,18 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 1, (jint) 0); useDefWindowProc = 1; break; case WM_MBUTTONDOWN: DBG_PRINT("*** WindowsWindow: MBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 2, (jint) 0); useDefWindowProc = 1; break; @@ -903,18 +898,18 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 2, (jint) 0); useDefWindowProc = 1; break; case WM_RBUTTONDOWN: DBG_PRINT("*** WindowsWindow: RBUTTONDOWN\n"); - (*env)->CallVoidMethod(env, window, enqueueRequestFocusID, JNI_FALSE); + (*env)->CallVoidMethod(env, window, requestFocusID, JNI_FALSE); (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 3, (jint) 0); useDefWindowProc = 1; break; @@ -923,7 +918,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 3, (jint) 0); useDefWindowProc = 1; break; @@ -932,7 +927,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, GetModifiers(), - (jint) LOWORD(lParam), (jint) HIWORD(lParam), + (jint) GET_X_LPARAM(lParam), (jint) GET_Y_LPARAM(lParam), (jint) 0, (jint) 0); useDefWindowProc = 1; break; @@ -958,7 +953,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, (jint) EVENT_MOUSE_WHEEL_MOVED, GetModifiers(), (jint) eventPt.x, (jint) eventPt.y, - (jint) 0, (jint) (GET_WHEEL_DELTA_WPARAM(wParam)/120.0f)); + (jint) 1, (jint) (GET_WHEEL_DELTA_WPARAM(wParam)/120.0f)); useDefWindowProc = 1; break; } @@ -978,8 +973,8 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, break; case WM_MOVE: - DBG_PRINT("*** WindowsWindow: WM_MOVE window %p, %d/%d\n", wnd, (int)LOWORD(lParam), (int)HIWORD(lParam)); - (*env)->CallVoidMethod(env, window, positionChangedID, JNI_FALSE, (jint)LOWORD(lParam), (jint)HIWORD(lParam)); + DBG_PRINT("*** WindowsWindow: WM_MOVE window %p, %d/%d\n", wnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + (*env)->CallVoidMethod(env, window, positionChangedID, JNI_FALSE, (jint)GET_X_LPARAM(lParam), (jint)GET_Y_LPARAM(lParam)); useDefWindowProc = 1; break; @@ -1046,13 +1041,47 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_WindowsDisplay_DispatchMe /* * Class: jogamp_newt_driver_windows_WindowsScreen + * Method: getOriginX0 + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_WindowsScreen_getOriginX0 + (JNIEnv *env, jobject obj, jint scrn_idx) +{ + if( GetSystemMetrics( SM_CMONITORS) > 1) { + return (jint)GetSystemMetrics(SM_XVIRTUALSCREEN); + } else { + return 0; + } +} + +/* + * Class: jogamp_newt_driver_windows_WindowsScreen + * Method: getOriginY0 + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_WindowsScreen_getOriginY0 + (JNIEnv *env, jobject obj, jint scrn_idx) +{ + if( GetSystemMetrics( SM_CMONITORS ) > 1) { + return (jint)GetSystemMetrics(SM_YVIRTUALSCREEN); + } else { + return 0; + } +} + +/* + * Class: jogamp_newt_driver_windows_WindowsScreen * Method: getWidthImpl * Signature: (I)I */ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_WindowsScreen_getWidthImpl0 (JNIEnv *env, jobject obj, jint scrn_idx) { - return (jint)GetSystemMetrics(SM_CXSCREEN); + if( GetSystemMetrics( SM_CMONITORS) > 1) { + return (jint)GetSystemMetrics(SM_CXVIRTUALSCREEN); + } else { + return (jint)GetSystemMetrics(SM_CXSCREEN); + } } /* @@ -1063,7 +1092,11 @@ JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_WindowsScreen_getWidthImp JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_WindowsScreen_getHeightImpl0 (JNIEnv *env, jobject obj, jint scrn_idx) { - return (jint)GetSystemMetrics(SM_CYSCREEN); + if( GetSystemMetrics( SM_CMONITORS ) > 1) { + return (jint)GetSystemMetrics(SM_CYVIRTUALSCREEN); + } else { + return (jint)GetSystemMetrics(SM_CYSCREEN); + } } static int NewtScreen_RotationNativeCCW2NewtCCW(JNIEnv *env, int native) { @@ -1270,8 +1303,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); + requestFocusID = (*env)->GetMethodID(env, clazz, "requestFocus", "(Z)V"); if (insetsChangedID == NULL || sizeChangedID == NULL || @@ -1284,8 +1316,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_initIDs sendMouseEventID == NULL || enqueueKeyEventID == NULL || sendKeyEventID == NULL || - focusActionID == NULL || - enqueueRequestFocusID == NULL) { + requestFocusID == NULL) { return JNI_FALSE; } BuildDynamicKeyMapTable(); @@ -1317,9 +1348,6 @@ static void NewtWindow_setVisiblePosSize(HWND hwnd, BOOL atop, BOOL visible, } else { flags = SWP_NOACTIVATE | SWP_NOZORDER; } - if(0>x || 0>y) { - flags |= SWP_NOMOVE; - } if(0>=width || 0>=height ) { flags |= SWP_NOSIZE; } @@ -1345,7 +1373,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_CreateWind (JNIEnv *env, jobject obj, jlong hInstance, jstring jWndClassName, jstring jWndName, jlong parent, - jint jx, jint jy, jint defaultWidth, jint defaultHeight, jint flags) + jint jx, jint jy, jint defaultWidth, jint defaultHeight, jboolean autoPosition, jint flags) { HWND parentWindow = (HWND) (intptr_t) parent; const TCHAR* wndClassName = NULL; @@ -1374,7 +1402,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_CreateWind windowStyle |= WS_POPUP | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; } else { windowStyle |= WS_OVERLAPPEDWINDOW; - if(0>_x || 0>_y) { + if(JNI_TRUE == autoPosition) { // user didn't requested specific position, use WM default _x = CW_USEDEFAULT; _y = 0; @@ -1387,9 +1415,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_CreateWind (HINSTANCE) (intptr_t) hInstance, NULL); - DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, parent %p, window %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d\n", + DBG_PRINT("*** WindowsWindow: CreateWindow thread 0x%X, parent %p, window %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", (int)GetCurrentThreadId(), parentWindow, window, x, y, width, height, - TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags)); + TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags), autoPosition); if (NULL == window) { int lastError = (int) GetLastError(); @@ -1409,7 +1437,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_CreateWind { RECT rc; RECT * insets; - BOOL userPos = 0<=x && 0<=y ; ShowWindow(window, SW_SHOW); @@ -1417,12 +1444,12 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_windows_WindowsWindow_CreateWind insets = UpdateInsets(env, wud->jinstance, window); (*env)->CallVoidMethod(env, wud->jinstance, visibleChangedID, JNI_FALSE, JNI_TRUE); - if(!userPos) { + if(JNI_TRUE == autoPosition) { GetWindowRect(window, &rc); x = rc.left + insets->left; // client coords y = rc.top + insets->top; // client coords } - DBG_PRINT("*** WindowsWindow: CreateWindow client: %d/%d %dx%d (is user-pos %d)\n", x, y, width, height, userPos); + DBG_PRINT("*** WindowsWindow: CreateWindow client: %d/%d %dx%d (autoPosition %d)\n", x, y, width, height, autoPosition); x -= insets->left; // top-level y -= insets->top; // top-level diff --git a/src/newt/native/X11Common.h b/src/newt/native/X11Common.h new file mode 100644 index 000000000..cefef690f --- /dev/null +++ b/src/newt/native/X11Common.h @@ -0,0 +1,80 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#ifndef _X11COMMON_H_ +#define _X11COMMON_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include <gluegen_stdint.h> + +#include <unistd.h> +#include <errno.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> + +#include <X11/extensions/Xrandr.h> + +#include "jogamp_newt_driver_x11_X11Screen.h" +#include "jogamp_newt_driver_x11_X11Display.h" +#include "jogamp_newt_driver_x11_X11Window.h" + +#include "Window.h" +#include "MouseEvent.h" +#include "InputEvent.h" +#include "KeyEvent.h" +#include "WindowEvent.h" +#include "ScreenMode.h" + +#include "NewtCommon.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +extern jclass X11NewtWindowClazz; +extern jmethodID insetsChangedID; +extern jmethodID visibleChangedID; + +jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning); + +void NewtDisplay_displayDispatchErrorHandlerEnable(int onoff, JNIEnv * env); +Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return); +Status NewtWindows_updateInsets(JNIEnv *env, jobject jwindow, Display *dpy, Window window, int *left, int *right, int *top, int *bottom); + +#endif /* _X11COMMON_H_ */ + diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c new file mode 100644 index 000000000..283636040 --- /dev/null +++ b/src/newt/native/X11Display.c @@ -0,0 +1,660 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Common.h" + +#define USE_SENDIO_DIRECT 1 + +jclass X11NewtWindowClazz = NULL; +jmethodID insetsChangedID = NULL; +jmethodID visibleChangedID = NULL; + +static const char * const ClazzNameX11NewtWindow = "jogamp/newt/driver/x11/X11Window"; + +static jmethodID displayCompletedID = NULL; + +static jmethodID sizeChangedID = NULL; +static jmethodID positionChangedID = NULL; +static jmethodID focusChangedID = NULL; +static jmethodID reparentNotifyID = NULL; +static jmethodID windowDestroyNotifyID = NULL; +static jmethodID windowRepaintID = NULL; +static jmethodID enqueueMouseEventID = NULL; +static jmethodID sendMouseEventID = NULL; +static jmethodID enqueueKeyEventID = NULL; +static jmethodID sendKeyEventID = NULL; +static jmethodID requestFocusID = NULL; + +static JavaVM *jvmHandle = NULL; +static int jvmVersion = 0; + +static void setupJVMVars(JNIEnv * env) { + if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { + jvmHandle = NULL; + } + jvmVersion = (*env)->GetVersion(env); +} + +static XErrorHandler origErrorHandler = NULL ; + +static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) +{ + fprintf(stderr, "Warning: NEWT X11 Error: DisplayDispatch %p, Code 0x%X, errno %s\n", dpy, e->error_code, strerror(errno)); + + if (e->error_code == BadAtom) { + fprintf(stderr, " BadAtom (%p): Atom probably already removed\n", (void*)e->resourceid); + } else if (e->error_code == BadWindow) { + fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid); + } else { + int shallBeDetached = 0; + JNIEnv *jniEnv = NULL; + const char * errStr = strerror(errno); + + fprintf(stderr, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); + + jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL==jniEnv) { + fprintf(stderr, "NEWT X11 Error: null JNIEnv"); + return; + } + + NewtCommon_throwNewRuntimeException(jniEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s", + dpy, e->error_code, errStr); + + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } + } + + return 0; +} + +void NewtDisplay_displayDispatchErrorHandlerEnable(int onoff, JNIEnv * env) { + if(onoff) { + if(NULL==origErrorHandler) { + setupJVMVars(env); + origErrorHandler = XSetErrorHandler(displayDispatchErrorHandler); + } + } else { + if(NULL!=origErrorHandler) { + XSetErrorHandler(origErrorHandler); + origErrorHandler = NULL; + } + } +} + +/** + * Keycode + */ + +#define IS_WITHIN(k,a,b) ((a)<=(k)&&(k)<=(b)) + +static jint X11KeySym2NewtVKey(KeySym keySym) { + if(IS_WITHIN(keySym,XK_F1,XK_F12)) + return (keySym-XK_F1)+J_VK_F1; + if(IS_WITHIN(keySym,XK_KP_0,XK_KP_9)) + return (keySym-XK_KP_0)+J_VK_NUMPAD0; + + switch(keySym) { + case XK_Return: + case XK_KP_Enter: + return J_VK_ENTER; + case XK_BackSpace: + return J_VK_BACK_SPACE; + case XK_Tab: + case XK_KP_Tab: + case XK_ISO_Left_Tab: + return J_VK_TAB; + case XK_Cancel: + return J_VK_CANCEL; + case XK_Clear: + return J_VK_CLEAR; + case XK_Shift_L: + case XK_Shift_R: + return J_VK_SHIFT; + case XK_Control_L: + case XK_Control_R: + return J_VK_CONTROL; + case XK_Alt_L: + case XK_Alt_R: + return J_VK_ALT; + case XK_Pause: + return J_VK_PAUSE; + case XK_Caps_Lock: + return J_VK_CAPS_LOCK; + case XK_Escape: + return J_VK_ESCAPE; + case XK_space: + case XK_KP_Space: + return J_VK_SPACE; + case XK_Page_Up: + case XK_KP_Page_Up: + return J_VK_PAGE_UP; + case XK_Page_Down: + case XK_KP_Page_Down: + return J_VK_PAGE_DOWN; + case XK_End: + case XK_KP_End: + return J_VK_END; + case XK_Home: + case XK_KP_Home: + return J_VK_HOME; + case XK_Left: + case XK_KP_Left: + return J_VK_LEFT; + case XK_Up: + case XK_KP_Up: + return J_VK_UP; + case XK_Right: + case XK_KP_Right: + return J_VK_RIGHT; + case XK_Down: + case XK_KP_Down: + return J_VK_DOWN; + case XK_KP_Multiply: + return J_VK_MULTIPLY; + case XK_KP_Add: + return J_VK_ADD; + case XK_KP_Separator: + return J_VK_SEPARATOR; + case XK_KP_Subtract: + return J_VK_SUBTRACT; + case XK_KP_Decimal: + return J_VK_DECIMAL; + case XK_KP_Divide: + return J_VK_DIVIDE; + case XK_Delete: + case XK_KP_Delete: + return J_VK_DELETE; + case XK_Num_Lock: + return J_VK_NUM_LOCK; + case XK_Scroll_Lock: + return J_VK_SCROLL_LOCK; + case XK_Print: + return J_VK_PRINTSCREEN; + case XK_Insert: + case XK_KP_Insert: + return J_VK_INSERT; + case XK_Help: + return J_VK_HELP; + } + return keySym; +} + +static jint X11InputState2NewtModifiers(unsigned int xstate) { + jint modifiers = 0; + if ((ControlMask & xstate) != 0) { + modifiers |= EVENT_CTRL_MASK; + } + if ((ShiftMask & xstate) != 0) { + modifiers |= EVENT_SHIFT_MASK; + } + if ((Mod1Mask & xstate) != 0) { + modifiers |= EVENT_ALT_MASK; + } + if ((Button1Mask & xstate) != 0) { + modifiers |= EVENT_BUTTON1_MASK; + } + if ((Button2Mask & xstate) != 0) { + modifiers |= EVENT_BUTTON2_MASK; + } + if ((Button3Mask & xstate) != 0) { + modifiers |= EVENT_BUTTON3_MASK; + } + + return modifiers; +} + + +/** + * Keycode + */ + +/* + * Class: jogamp_newt_driver_x11_X11Display + * Method: initIDs + * Signature: (Z)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 + (JNIEnv *env, jclass clazz) +{ + jclass c; + + NewtCommon_init(env); + + if(NULL==X11NewtWindowClazz) { + c = (*env)->FindClass(env, ClazzNameX11NewtWindow); + if(NULL==c) { + NewtCommon_FatalError(env, "NEWT X11Window: can't find %s", ClazzNameX11NewtWindow); + } + X11NewtWindowClazz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==X11NewtWindowClazz) { + NewtCommon_FatalError(env, "NEWT X11Window: can't use %s", ClazzNameX11NewtWindow); + } + } + + displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); + insetsChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "insetsChanged", "(ZIIII)V"); + sizeChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sizeChanged", "(ZIIZ)V"); + positionChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "positionChanged", "(ZII)V"); + focusChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "focusChanged", "(ZZ)V"); + visibleChangedID = (*env)->GetMethodID(env, X11NewtWindowClazz, "visibleChanged", "(ZZ)V"); + reparentNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "reparentNotify", "(J)V"); + windowDestroyNotifyID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowDestroyNotify", "()V"); + windowRepaintID = (*env)->GetMethodID(env, X11NewtWindowClazz, "windowRepaint", "(ZIIII)V"); + enqueueMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "enqueueMouseEvent", "(ZIIIIII)V"); + sendMouseEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendMouseEvent", "(IIIIII)V"); + enqueueKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "enqueueKeyEvent", "(ZIIIC)V"); + sendKeyEventID = (*env)->GetMethodID(env, X11NewtWindowClazz, "sendKeyEvent", "(IIIC)V"); + requestFocusID = (*env)->GetMethodID(env, X11NewtWindowClazz, "requestFocus", "(Z)V"); + + if (displayCompletedID == NULL || + insetsChangedID == NULL || + sizeChangedID == NULL || + positionChangedID == NULL || + focusChangedID == NULL || + visibleChangedID == NULL || + reparentNotifyID == NULL || + windowDestroyNotifyID == NULL || + windowRepaintID == NULL || + enqueueMouseEventID == NULL || + sendMouseEventID == NULL || + enqueueKeyEventID == NULL || + sendKeyEventID == NULL || + requestFocusID == NULL) { + return JNI_FALSE; + } + + + return JNI_TRUE; +} + +/* + * Class: jogamp_newt_driver_x11_X11Display + * Method: CompleteDisplay + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_CompleteDisplay0 + (JNIEnv *env, jobject obj, jlong display) +{ + Display * dpy = (Display *)(intptr_t)display; + jlong javaObjectAtom; + jlong windowDeleteAtom; + + if(dpy==NULL) { + NewtCommon_FatalError(env, "invalid display connection.."); + } + + javaObjectAtom = (jlong) XInternAtom(dpy, "NEWT_JAVA_OBJECT", False); + if(None==javaObjectAtom) { + NewtCommon_throwNewRuntimeException(env, "could not create Atom NEWT_JAVA_OBJECT, bail out!"); + return; + } + + windowDeleteAtom = (jlong) XInternAtom(dpy, "WM_DELETE_WINDOW", False); + if(None==windowDeleteAtom) { + NewtCommon_throwNewRuntimeException(env, "could not create Atom WM_DELETE_WINDOW, bail out!"); + return; + } + + // XSetCloseDownMode(dpy, RetainTemporary); // Just a try .. + + DBG_PRINT("X11: X11Display_completeDisplay dpy %p\n", dpy); + + (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom); +} + +/* + * Class: jogamp_newt_driver_x11_X11Display + * Method: DisplayRelease0 + * Signature: (JJJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DisplayRelease0 + (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) +{ + Display * dpy = (Display *)(intptr_t)display; + Atom wm_javaobject_atom = (Atom)javaObjectAtom; + Atom wm_delete_atom = (Atom)windowDeleteAtom; + + if(dpy==NULL) { + NewtCommon_FatalError(env, "invalid display connection.."); + } + + // nothing to do to free the atoms ! + (void) wm_javaobject_atom; + (void) wm_delete_atom; + + XSync(dpy, True); // discard all pending events + DBG_PRINT("X11: X11Display_DisplayRelease dpy %p\n", dpy); +} + +/* + * Class: jogamp_newt_driver_x11_X11Display + * Method: DispatchMessages + * Signature: (JIJJ)V + */ +JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 + (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) +{ + Display * dpy = (Display *) (intptr_t) display; + Atom wm_delete_atom = (Atom)windowDeleteAtom; + int num_events = 100; + + if ( NULL == dpy ) { + return; + } + + // Periodically take a break + while( num_events > 0 ) { + jobject jwindow = NULL; + XEvent evt; + KeySym keySym = 0; + jint modifiers = 0; + char keyChar = 0; + char text[255]; + + // XEventsQueued(dpy, X): + // QueuedAlready : No I/O Flush or system call doesn't work on some cards (eg ATI) ?) + // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available + // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more .. + if ( 0 >= XPending(dpy) ) { + // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); + return; + } + + XNextEvent(dpy, &evt); + num_events--; + + if( 0==evt.xany.window ) { + NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); + return ; + } + + if(dpy!=evt.xany.display) { + NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); + return ; + } + + // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); + + NewtDisplay_displayDispatchErrorHandlerEnable(1, env); + + jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, + #ifdef VERBOSE_ON + True + #else + False + #endif + ); + + NewtDisplay_displayDispatchErrorHandlerEnable(0, env); + + if(NULL==jwindow) { + fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", + (void*)dpy, evt.type, (void*)evt.xany.window); + continue; + } + + switch(evt.type) { + case KeyRelease: + case KeyPress: + if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { + KeySym lower_return = 0, upper_return = 0; + keyChar=text[0]; + XConvertCase(keySym, &lower_return, &upper_return); + // always return upper case, set modifier masks (SHIFT, ..) + keySym = X11KeySym2NewtVKey(upper_return); + } else { + keyChar=0; + keySym = X11KeySym2NewtVKey(keySym); + } + modifiers = X11InputState2NewtModifiers(evt.xkey.state); + break; + + case ButtonPress: + case ButtonRelease: + case MotionNotify: + modifiers = X11InputState2NewtModifiers(evt.xbutton.state); + break; + + default: + break; + } + + switch(evt.type) { + case ButtonPress: + (*env)->CallVoidMethod(env, jwindow, requestFocusID, JNI_FALSE); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); + #endif + break; + case ButtonRelease: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, + modifiers, + (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); + #endif + break; + case MotionNotify: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, + modifiers, + (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); + #endif + break; + case EnterNotify: + DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_ENTERED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_ENTERED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); + #endif + break; + case LeaveNotify: + DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_EXITED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_EXITED, + modifiers, + (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); + #endif + break; + case KeyPress: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, + modifiers, keySym, (jchar) -1); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, + modifiers, keySym, (jchar) -1); + #endif + + break; + case KeyRelease: + #ifdef USE_SENDIO_DIRECT + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, + modifiers, keySym, (jchar) -1); + + (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, + modifiers, keySym, (jchar) keyChar); + #else + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, + modifiers, keySym, (jchar) -1); + + (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_TYPED, + modifiers, keySym, (jchar) keyChar); + #endif + + break; + case DestroyNotify: + DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", + (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event); + if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) { + // ignore child destroy notification + } + break; + case CreateNotify: + DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n", + (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent); + break; + case ConfigureNotify: + DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n", + (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above, + evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, + evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); + if ( evt.xconfigure.window == evt.xconfigure.event ) { + // ignore child window change notification + { + // update insets + int left, right, top, bottom; + NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); + } + (*env)->CallVoidMethod(env, jwindow, sizeChangedID, JNI_FALSE, + (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); + (*env)->CallVoidMethod(env, jwindow, positionChangedID, JNI_FALSE, + (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); + } + break; + case ClientMessage: + if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom + DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X !!!\n", + (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); + (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID); + // Called by Window.java: CloseWindow(); + num_events = 0; // end loop in case of destroyed display + } + break; + + case FocusIn: + DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_TRUE); + break; + + case FocusOut: + DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); + (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_FALSE); + break; + + case Expose: + DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)evt.xexpose.window, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.count); + + if (evt.xexpose.count == 0 && evt.xexpose.width > 0 && evt.xexpose.height > 0) { + (*env)->CallVoidMethod(env, jwindow, windowRepaintID, JNI_FALSE, + evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); + } + break; + + case MapNotify: + DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n", + (void*)evt.xmap.event, (void*)evt.xmap.window, (int)evt.xmap.override_redirect, + evt.xmap.event!=evt.xmap.window); + if( evt.xmap.event == evt.xmap.window ) { + // ignore child window notification + { + // update insets + int left, right, top, bottom; + NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); + } + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); + } + break; + + case UnmapNotify: + DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, from_configure %d, child-event: %d\n", + (void*)evt.xunmap.event, (void*)evt.xunmap.window, (int)evt.xunmap.from_configure, + evt.xunmap.event!=evt.xunmap.window); + if( evt.xunmap.event == evt.xunmap.window ) { + // ignore child window notification + (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_FALSE); + } + break; + + case ReparentNotify: + { + jlong parentResult; // 0 if root, otherwise proper value + Window winRoot, winTopParent; + #ifdef VERBOSE_ON + Window oldParentRoot, oldParentTopParent; + Window parentRoot, parentTopParent; + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) { + oldParentRoot=0; oldParentTopParent = 0; + } + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) { + parentRoot=0; parentTopParent = 0; + } + #endif + if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) { + winRoot=0; winTopParent = 0; + } + if(evt.xreparent.parent == winRoot) { + parentResult = 0; // our java indicator for root window + } else { + parentResult = (jlong) (intptr_t) evt.xreparent.parent; + } + #ifdef VERBOSE_ON + DBG_PRINT( "X11: event . ReparentNotify: call %d/%d OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n", + evt.xreparent.x, evt.xreparent.y, + (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent, + (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent, + (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent); + #endif + (*env)->CallVoidMethod(env, jwindow, reparentNotifyID, (jlong)evt.xreparent.parent); + } + break; + + // unhandled events .. yet .. + + default: + DBG_PRINT("X11: event . unhandled %d 0x%X call %p\n", (int)evt.type, (unsigned int)evt.type, (void*)evt.xunmap.window); + } + } +} + + diff --git a/src/newt/native/X11Screen.c b/src/newt/native/X11Screen.c new file mode 100644 index 000000000..1b7fea770 --- /dev/null +++ b/src/newt/native/X11Screen.c @@ -0,0 +1,469 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +#include "X11Common.h" + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: GetScreen + * Signature: (JI)J + */ +JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Screen_GetScreen0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_index) +{ + Display * dpy = (Display *)(intptr_t)display; + Screen * scrn= NULL; + + DBG_PRINT("X11: X11Screen_GetScreen0 dpy %p START\n", dpy); + + if(dpy==NULL) { + NewtCommon_FatalError(env, "invalid display connection.."); + } + + scrn = ScreenOfDisplay(dpy, screen_index); + if(scrn==NULL) { + fprintf(stderr, "couldn't get screen idx %d\n", screen_index); + } + DBG_PRINT("X11: X11Screen_GetScreen0 idx %d -> scrn %p DONE\n", screen_index, scrn); + return (jlong) (intptr_t) scrn; +} + +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getWidth0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display * dpy = (Display *) (intptr_t) display; + return (jint) DisplayWidth( dpy, scrn_idx); +} + +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getHeight0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display * dpy = (Display *) (intptr_t) display; + return (jint) DisplayHeight( dpy, scrn_idx); +} + +static int showedRandRVersion = 0; + +static Bool NewtScreen_getRANDRVersion(Display *dpy, int *major, int *minor) { + if( 0 == XRRQueryVersion(dpy, major, minor) ) { + return False; + } + if(0 == showedRandRVersion) { + fprintf(stderr, "X11 RandR Version %d.%d\n", *major, *minor); + showedRandRVersion = 1; + } + return True; +} + +static Bool NewtScreen_hasRANDR(Display *dpy) { + int major, minor; + return NewtScreen_getRANDRVersion(dpy, &major, &minor); +} + +static int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { + int rot; + if(xrotation == RR_Rotate_0) { + rot = 0; + } + else if(xrotation == RR_Rotate_90) { + rot = 90; + } + else if(xrotation == RR_Rotate_180) { + rot = 180; + } + else if(xrotation == RR_Rotate_270) { + rot = 270; + } else { + NewtCommon_throwNewRuntimeException(env, "invalid native rotation: %d", xrotation); + } + return rot; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getAvailableScreenModeRotations0 + * Signature: (JI)I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getAvailableScreenModeRotations0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + int num_rotations = 0; + Rotation cur_rotation, rotations_supported; + int rotations[4]; + int major, minor; + + if(False == NewtScreen_getRANDRVersion(dpy, &major, &minor)) { + fprintf(stderr, "RANDR not available\n"); + return (*env)->NewIntArray(env, 0); + } + + rotations_supported = XRRRotations (dpy, (int)scrn_idx, &cur_rotation); + + if(0 != (rotations_supported & RR_Rotate_0)) { + rotations[num_rotations++] = 0; + } + if(0 != (rotations_supported & RR_Rotate_90)) { + rotations[num_rotations++] = 90; + } + if(0 != (rotations_supported & RR_Rotate_180)) { + rotations[num_rotations++] = 180; + } + if(0 != (rotations_supported & RR_Rotate_270)) { + rotations[num_rotations++] = 270; + } + + jintArray properties = NULL; + + if(num_rotations>0) { + properties = (*env)->NewIntArray(env, num_rotations); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); + } + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getNumScreenModeResolution0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getNumScreenModeResolutions0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getNumScreenModeResolutions0: RANDR not available\n"); + return 0; + } + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + DBG_PRINT("getNumScreenModeResolutions0: %d\n", num_sizes); + + return num_sizes; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getScreenModeResolutions0 + * Signature: (JII)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getScreenModeResolution0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getScreenModeResolution0: RANDR not available\n"); + return (*env)->NewIntArray(env, 0); + } + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + // Fill the properties in temp jint array + int propIndex = 0; + jint prop[4]; + + prop[propIndex++] = xrrs[(int)resMode_idx].width; + prop[propIndex++] = xrrs[(int)resMode_idx].height; + prop[propIndex++] = xrrs[(int)resMode_idx].mwidth; + prop[propIndex++] = xrrs[(int)resMode_idx].mheight; + + jintArray properties = (*env)->NewIntArray(env, 4); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", 4); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, 4, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getScreenModeRates0 + * Signature: (JII)[I + */ +JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getScreenModeRates0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getScreenModeRates0: RANDR not available\n"); + return (*env)->NewIntArray(env, 0); + } + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + int num_rates; + short *rates = XRRRates(dpy, (int)scrn_idx, (int)resMode_idx, &num_rates); + + jint prop[num_rates]; + int i; + for(i=0; i<num_rates; i++) { + prop[i] = (int) rates[i]; + /** fprintf(stderr, "rate[%d, %d, %d/%d]: %d\n", (int)scrn_idx, resMode_idx, i, num_rates, prop[i]); */ + } + + jintArray properties = (*env)->NewIntArray(env, num_rates); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rates); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rates, prop); + + return properties; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getCurrentScreenRate0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRate0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRate0: RANDR not available\n"); + return -1; + } + + // get current resolutions and frequencies + XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); + short original_rate = XRRConfigCurrentRate(conf); + + //free + XRRFreeScreenConfigInfo(conf); + + DBG_PRINT("getCurrentScreenRate0: %d\n", (int)original_rate); + + return (jint) original_rate; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getCurrentScreenRotation0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRotation0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRotation0: RANDR not available\n"); + return -1; + } + + //get current resolutions and frequencies + XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); + + Rotation rotation; + XRRConfigCurrentConfiguration(conf, &rotation); + + //free + XRRFreeScreenConfigInfo(conf); + + return NewtScreen_XRotation2Degree(env, rotation); +} + + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: getCurrentScreenResolutionIndex0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenResolutionIndex0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenResolutionIndex0: RANDR not available\n"); + return -1; + } + + // get current resolutions and frequency configuration + XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); + short original_rate = XRRConfigCurrentRate(conf); + + Rotation original_rotation; + SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); + + //free + XRRFreeScreenConfigInfo(conf); + + DBG_PRINT("getCurrentScreenResolutionIndex0: %d\n", (int)original_size_id); + return (jint)original_size_id; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: setCurrentScreenModeStart0 + * Signature: (JIIII)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModeStart0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)screen_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModeStart0: RANDR not available\n"); + return JNI_FALSE; + } + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions + XRRScreenConfiguration *conf; + int rot; + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + conf = XRRGetScreenInfo(dpy, root); + + switch(rotation) { + case 0: + rot = RR_Rotate_0; + break; + case 90: + rot = RR_Rotate_90; + break; + case 180: + rot = RR_Rotate_180; + break; + case 270: + rot = RR_Rotate_270; + break; + default: + NewtCommon_throwNewRuntimeException(env, "Invalid rotation: %d", rotation); + } + + DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", + resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); + + XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); + + XSync(dpy, False); + XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, rot, (short)freq, CurrentTime); + XSync(dpy, False); + + //free + XRRFreeScreenConfigInfo(conf); + XSync(dpy, False); + + return JNI_TRUE; +} + +/* + * Class: jogamp_newt_driver_x11_X11Screen + * Method: setCurrentScreenModePollEnd0 + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModePollEnd0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) +{ + Display *dpy = (Display *) (intptr_t) display; + int randr_event_base, randr_error_base; + XEvent evt; + XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; + + if(False == NewtScreen_hasRANDR(dpy)) { + DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModePollEnd0: RANDR not available\n"); + return JNI_FALSE; + } + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions + XRRScreenConfiguration *conf; + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); + + int done = 0; + int rot; + do { + if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { + return; + } + XNextEvent(dpy, &evt); + + switch (evt.type - randr_event_base) { + case RRScreenChangeNotify: + rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call %p (root %p) resIdx %d rot %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, rot, + scn_event->width, scn_event->height); + // done = scn_event->size_index == resMode_idx; // not reliable .. + done = rot == rotation && + scn_event->width == xrrs[resMode_idx].width && + scn_event->height == xrrs[resMode_idx].height; + break; + default: + DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); + } + XRRUpdateConfiguration(&evt); + } while(!done); + + XSync(dpy, False); + +} + diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index f14138a0a..0a7e1cf77 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -32,40 +32,9 @@ * */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> - -#include <gluegen_stdint.h> - -#include <unistd.h> -#include <errno.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/keysym.h> -#include <X11/Xatom.h> - -#include <X11/extensions/Xrandr.h> - -#include "jogamp_newt_driver_x11_X11Screen.h" -#include "jogamp_newt_driver_x11_X11Display.h" -#include "jogamp_newt_driver_x11_X11Window.h" - -#include "Window.h" -#include "MouseEvent.h" -#include "InputEvent.h" -#include "KeyEvent.h" -#include "WindowEvent.h" -#include "ScreenMode.h" - -#include "NewtCommon.h" - -// #define VERBOSE_ON 1 +#include "X11Common.h" #ifdef VERBOSE_ON - #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) - #define DUMP_VISUAL_INFO(a,b) _dumpVisualInfo((a),(b)) static void _dumpVisualInfo(const char * msg, XVisualInfo *pVisualQuery) { @@ -90,259 +59,12 @@ #else - #define DBG_PRINT(...) - #define DUMP_VISUAL_INFO(a,b) #endif -/** - * Keycode - */ - -#define IS_WITHIN(k,a,b) ((a)<=(k)&&(k)<=(b)) - -static jint X11KeySym2NewtVKey(KeySym keySym) { - if(IS_WITHIN(keySym,XK_F1,XK_F12)) - return (keySym-XK_F1)+J_VK_F1; - - switch(keySym) { - case XK_Alt_L: - case XK_Alt_R: - return J_VK_ALT; - - case XK_Left: - return J_VK_LEFT; - case XK_Right: - return J_VK_RIGHT; - case XK_Up: - return J_VK_UP; - case XK_Down: - return J_VK_DOWN; - case XK_Page_Up: - return J_VK_PAGE_UP; - case XK_Page_Down: - return J_VK_PAGE_DOWN; - case XK_Shift_L: - case XK_Shift_R: - return J_VK_SHIFT; - case XK_Control_L: - case XK_Control_R: - return J_VK_CONTROL; - case XK_Escape: - return J_VK_ESCAPE; - case XK_Delete: - return J_VK_DELETE; - } - return keySym; -} - -static jint X11InputState2NewtModifiers(unsigned int xstate) { - jint modifiers = 0; - if ((ControlMask & xstate) != 0) { - modifiers |= EVENT_CTRL_MASK; - } - if ((ShiftMask & xstate) != 0) { - modifiers |= EVENT_SHIFT_MASK; - } - if ((Mod1Mask & xstate) != 0) { - modifiers |= EVENT_ALT_MASK; - } - if ((Button1Mask & xstate) != 0) { - modifiers |= EVENT_BUTTON1_MASK; - } - if ((Button2Mask & xstate) != 0) { - modifiers |= EVENT_BUTTON2_MASK; - } - if ((Button3Mask & xstate) != 0) { - modifiers |= EVENT_BUTTON3_MASK; - } - - return modifiers; -} - #define X11_MOUSE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask) -static const char * const ClazzNameNewtWindow = "com/jogamp/newt/Window"; - -static jclass newtWindowClz=NULL; - -static jmethodID insetsChangedID = NULL; -static jmethodID sizeChangedID = NULL; -static jmethodID positionChangedID = NULL; -static jmethodID focusChangedID = NULL; -static jmethodID visibleChangedID = NULL; -static jmethodID reparentNotifyID = NULL; -static jmethodID windowDestroyNotifyID = NULL; -static jmethodID windowRepaintID = NULL; -static jmethodID enqueueMouseEventID = NULL; -static jmethodID sendMouseEventID = NULL; -static jmethodID enqueueKeyEventID = NULL; -static jmethodID sendKeyEventID = NULL; -static jmethodID focusActionID = NULL; -static jmethodID enqueueRequestFocusID = NULL; - -static jmethodID displayCompletedID = NULL; - - -/** - * Display - */ - -static JavaVM *jvmHandle = NULL; -static int jvmVersion = 0; - -static void setupJVMVars(JNIEnv * env) { - if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { - jvmHandle = NULL; - } - jvmVersion = (*env)->GetVersion(env); -} - -static XErrorHandler origErrorHandler = NULL ; - -static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) -{ - fprintf(stderr, "Warning: NEWT X11 Error: DisplayDispatch %p, Code 0x%X, errno %s\n", dpy, e->error_code, strerror(errno)); - - if (e->error_code == BadAtom) { - fprintf(stderr, " BadAtom (%p): Atom probably already removed\n", (void*)e->resourceid); - } else if (e->error_code == BadWindow) { - fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid); - } else { - int shallBeDetached = 0; - JNIEnv *jniEnv = NULL; - const char * errStr = strerror(errno); - - fprintf(stderr, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s\n", dpy, e->error_code, errStr); - - jniEnv = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); - if(NULL==jniEnv) { - fprintf(stderr, "NEWT X11 Error: null JNIEnv"); - return; - } - - NewtCommon_throwNewRuntimeException(jniEnv, "Info: NEWT X11 Error: Display %p, Code 0x%X, errno %s", - dpy, e->error_code, errStr); - - if (shallBeDetached) { - (*jvmHandle)->DetachCurrentThread(jvmHandle); - } - } - - return 0; -} - -static void displayDispatchErrorHandlerEnable(int onoff, JNIEnv * env) { - if(onoff) { - if(NULL==origErrorHandler) { - setupJVMVars(env); - origErrorHandler = XSetErrorHandler(displayDispatchErrorHandler); - } - } else { - if(NULL!=origErrorHandler) { - XSetErrorHandler(origErrorHandler); - origErrorHandler = NULL; - } - } -} - -/* - * Class: jogamp_newt_driver_x11_X11Display - * Method: initIDs - * Signature: (Z)Z - */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Display_initIDs0 - (JNIEnv *env, jclass clazz) -{ - jclass c; - - NewtCommon_init(env); - - displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); - if (displayCompletedID == NULL) { - return JNI_FALSE; - } - - if(NULL==newtWindowClz) { - c = (*env)->FindClass(env, ClazzNameNewtWindow); - if(NULL==c) { - NewtCommon_FatalError(env, "NEWT X11Window: can't find %s", ClazzNameNewtWindow); - } - newtWindowClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==newtWindowClz) { - NewtCommon_FatalError(env, "NEWT X11Window: can't use %s", ClazzNameNewtWindow); - } - } - - return JNI_TRUE; -} - -/* - * Class: jogamp_newt_driver_x11_X11Display - * Method: CompleteDisplay - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_CompleteDisplay0 - (JNIEnv *env, jobject obj, jlong display) -{ - Display * dpy = (Display *)(intptr_t)display; - jlong javaObjectAtom; - jlong windowDeleteAtom; - - if(dpy==NULL) { - NewtCommon_FatalError(env, "invalid display connection.."); - } - - javaObjectAtom = (jlong) XInternAtom(dpy, "NEWT_JAVA_OBJECT", False); - if(None==javaObjectAtom) { - NewtCommon_throwNewRuntimeException(env, "could not create Atom NEWT_JAVA_OBJECT, bail out!"); - return; - } - - windowDeleteAtom = (jlong) XInternAtom(dpy, "WM_DELETE_WINDOW", False); - if(None==windowDeleteAtom) { - NewtCommon_throwNewRuntimeException(env, "could not create Atom WM_DELETE_WINDOW, bail out!"); - return; - } - - // XSetCloseDownMode(dpy, RetainTemporary); // Just a try .. - - DBG_PRINT("X11: X11Display_completeDisplay dpy %p\n", dpy); - - (*env)->CallVoidMethod(env, obj, displayCompletedID, javaObjectAtom, windowDeleteAtom); -} - -/* - * Class: jogamp_newt_driver_x11_X11Display - * Method: DisplayRelease0 - * Signature: (JJJ)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DisplayRelease0 - (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) -{ - Display * dpy = (Display *)(intptr_t)display; - Atom wm_javaobject_atom = (Atom)javaObjectAtom; - Atom wm_delete_atom = (Atom)windowDeleteAtom; - - if(dpy==NULL) { - NewtCommon_FatalError(env, "invalid display connection.."); - } - - // nothing to do to free the atoms ! - (void) wm_javaobject_atom; - (void) wm_delete_atom; - - XSync(dpy, True); // discard all pending events - DBG_PRINT("X11: X11Display_DisplayRelease dpy %p\n", dpy); -} - - -/** - * Window - */ - static int putPtrIn32Long(unsigned long * dst, uintptr_t src) { int i=0; dst[i++] = (unsigned long) ( ( src >> 0 ) & 0xFFFFFFFF ) ; @@ -375,7 +97,7 @@ static void setJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlon (unsigned char *)&jogl_java_object_data, nitems_32); } -static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning) { +jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, jlong javaObjectAtom, Bool showWarning) { Atom actual_type; int actual_format; int nitems_32 = ( sizeof(uintptr_t) == 8 ) ? 2 : 1 ; @@ -413,7 +135,7 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j XFree(jogl_java_object_data_pp); #ifdef VERBOSE_ON - if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, newtWindowClz)) { + if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, X11NewtWindowClazz)) { NewtCommon_throwNewRuntimeException(env, "fetched Atom NEWT_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !", jwindow); } #endif @@ -421,7 +143,7 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j } /** @return zero if fails, non zero if OK */ -static Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return) { +Status NewtWindows_getRootAndParent (Display *dpy, Window w, Window * root_return, Window * parent_return) { Window *children_return=NULL; unsigned int nchildren_return=0; @@ -502,7 +224,7 @@ static Status NewtWindows_getFrameExtends(Display *dpy, Window window, int *left return 1; // Ok } -static Status NewtWindows_updateInsets(JNIEnv *env, jobject jwindow, Display *dpy, Window window, int *left, int *right, int *top, int *bottom) { +Status NewtWindows_updateInsets(JNIEnv *env, jobject jwindow, Display *dpy, Window window, int *left, int *right, int *top, int *bottom) { if(0 != NewtWindows_getFrameExtends(dpy, window, left, right, top, bottom)) { DBG_PRINT( "NewtWindows_updateInsets: insets by _NET_FRAME_EXTENTS [ l %d, r %d, t %d, b %d ]\n", *left, *right, *top, *bottom); @@ -535,16 +257,14 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, Display *dpy, DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d, hasFocus %d\n", dpy, (void*)w, force, focus_return==w); if( JNI_TRUE==force || focus_return!=w) { - if( JNI_TRUE==force || JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - DBG_PRINT( "X11: XRaiseWindow dpy %p, win %p\n", dpy, (void*)w); - XRaiseWindow(dpy, w); - NewtWindows_setCWAbove(dpy, w); - // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable - XGetWindowAttributes(dpy, w, &xwa); - if(xwa.map_state == IsViewable) { - DBG_PRINT( "X11: XSetInputFocus dpy %p,win %pd\n", dpy, (void*)w); - XSetInputFocus(dpy, w, RevertToParent, CurrentTime); - } + DBG_PRINT( "X11: XRaiseWindow dpy %p, win %p\n", dpy, (void*)w); + XRaiseWindow(dpy, w); + NewtWindows_setCWAbove(dpy, w); + // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable + XGetWindowAttributes(dpy, w, &xwa); + if(xwa.map_state == IsViewable) { + DBG_PRINT( "X11: XSetInputFocus dpy %p,win %pd\n", dpy, (void*)w); + XSetInputFocus(dpy, w, RevertToParent, CurrentTime); } } DBG_PRINT( "X11: requestFocus dpy %p,win %p, force %d - FIN\n", dpy, (void*)w, force); @@ -710,752 +430,6 @@ static Bool NewtWindows_setFullscreenEWMH (Display *dpy, Window root, Window w, return res; } -#define USE_SENDIO_DIRECT 1 - -/* - * Class: jogamp_newt_driver_x11_X11Display - * Method: DispatchMessages - * Signature: (JIJJ)V - */ -JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Display_DispatchMessages0 - (JNIEnv *env, jobject obj, jlong display, jlong javaObjectAtom, jlong windowDeleteAtom) -{ - Display * dpy = (Display *) (intptr_t) display; - Atom wm_delete_atom = (Atom)windowDeleteAtom; - int num_events = 100; - - if ( NULL == dpy ) { - return; - } - - // Periodically take a break - while( num_events > 0 ) { - jobject jwindow = NULL; - XEvent evt; - KeySym keySym = 0; - jint modifiers = 0; - char keyChar = 0; - char text[255]; - - // XEventsQueued(dpy, X): - // QueuedAlready : No I/O Flush or system call doesn't work on some cards (eg ATI) ?) - // QueuedAfterFlush == XPending(): I/O Flush only if no already queued events are available - // QueuedAfterReading : QueuedAlready + if queue==0, attempt to read more .. - if ( 0 >= XPending(dpy) ) { - // DBG_PRINT( "X11: DispatchMessages 0x%X - Leave 1\n", dpy); - return; - } - - XNextEvent(dpy, &evt); - num_events--; - - if( 0==evt.xany.window ) { - NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); - return ; - } - - if(dpy!=evt.xany.display) { - NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); - return ; - } - - // DBG_PRINT( "X11: DispatchMessages dpy %p, win %p, Event %d\n", (void*)dpy, (void*)evt.xany.window, (int)evt.type); - - displayDispatchErrorHandlerEnable(1, env); - - jwindow = getJavaWindowProperty(env, dpy, evt.xany.window, javaObjectAtom, - #ifdef VERBOSE_ON - True - #else - False - #endif - ); - - displayDispatchErrorHandlerEnable(0, env); - - if(NULL==jwindow) { - fprintf(stderr, "Warning: NEWT X11 DisplayDispatch %p, Couldn't handle event %d for X11 window %p\n", - (void*)dpy, evt.type, (void*)evt.xany.window); - continue; - } - - switch(evt.type) { - case KeyRelease: - case KeyPress: - if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) { - KeySym lower_return = 0, upper_return = 0; - keyChar=text[0]; - XConvertCase(keySym, &lower_return, &upper_return); - // always return upper case, set modifier masks (SHIFT, ..) - keySym = upper_return; - modifiers = X11InputState2NewtModifiers(evt.xkey.state); - } else { - keyChar=0; - } - break; - - case ButtonPress: - case ButtonRelease: - case MotionNotify: - modifiers = X11InputState2NewtModifiers(evt.xbutton.state); - break; - - default: - break; - } - - switch(evt.type) { - case ButtonPress: - (*env)->CallVoidMethod(env, jwindow, enqueueRequestFocusID, JNI_FALSE); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_PRESSED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #endif - break; - case ButtonRelease: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_RELEASED, - modifiers, - (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button, 0 /*rotation*/); - #endif - break; - case MotionNotify: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_MOVED, - modifiers, - (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_MOVED, - modifiers, - (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0, 0 /*rotation*/); - #endif - break; - case EnterNotify: - DBG_PRINT( "X11: event . EnterNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_ENTERED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_ENTERED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #endif - break; - case LeaveNotify: - DBG_PRINT( "X11: event . LeaveNotify call %p %d/%d\n", (void*)evt.xcrossing.window, evt.xcrossing.x, evt.xcrossing.y); - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendMouseEventID, (jint) EVENT_MOUSE_EXITED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueMouseEventID, JNI_FALSE, (jint) EVENT_MOUSE_EXITED, - modifiers, - (jint) evt.xcrossing.x, (jint) evt.xcrossing.y, (jint) 0, 0 /*rotation*/); - #endif - break; - case KeyPress: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_PRESSED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); - #endif - - break; - case KeyRelease: - #ifdef USE_SENDIO_DIRECT - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); - - (*env)->CallVoidMethod(env, jwindow, sendKeyEventID, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); - #else - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_RELEASED, - modifiers, X11KeySym2NewtVKey(keySym), (jchar) keyChar); - - (*env)->CallVoidMethod(env, jwindow, enqueueKeyEventID, JNI_FALSE, (jint) EVENT_KEY_TYPED, - modifiers, (jint) -1, (jchar) keyChar); - #endif - - break; - case DestroyNotify: - DBG_PRINT( "X11: event . DestroyNotify call %p, parent %p, child-event: %d\n", - (void*)evt.xdestroywindow.window, (void*)evt.xdestroywindow.event, evt.xdestroywindow.window != evt.xdestroywindow.event); - if ( evt.xdestroywindow.window == evt.xdestroywindow.event ) { - // ignore child destroy notification - } - break; - case CreateNotify: - DBG_PRINT( "X11: event . CreateNotify call %p, parent %p, child-event: 1\n", - (void*)evt.xcreatewindow.window, (void*) evt.xcreatewindow.parent); - break; - case ConfigureNotify: - DBG_PRINT( "X11: event . ConfigureNotify call %p (parent %p, above %p) %d/%d %dx%d %d, child-event: %d\n", - (void*)evt.xconfigure.window, (void*)evt.xconfigure.event, (void*)evt.xconfigure.above, - evt.xconfigure.x, evt.xconfigure.y, evt.xconfigure.width, evt.xconfigure.height, - evt.xconfigure.override_redirect, evt.xconfigure.window != evt.xconfigure.event); - if ( evt.xconfigure.window == evt.xconfigure.event ) { - // ignore child window change notification - { - // update insets - int left, right, top, bottom; - NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); - } - (*env)->CallVoidMethod(env, jwindow, sizeChangedID, JNI_FALSE, - (jint) evt.xconfigure.width, (jint) evt.xconfigure.height, JNI_FALSE); - (*env)->CallVoidMethod(env, jwindow, positionChangedID, JNI_FALSE, - (jint) evt.xconfigure.x, (jint) evt.xconfigure.y); - } - break; - case ClientMessage: - if (evt.xclient.send_event==True && evt.xclient.data.l[0]==wm_delete_atom) { // windowDeleteAtom - DBG_PRINT( "X11: event . ClientMessage call %p type 0x%X !!!\n", - (void*)evt.xclient.window, (unsigned int)evt.xclient.message_type); - (*env)->CallVoidMethod(env, jwindow, windowDestroyNotifyID); - // Called by Window.java: CloseWindow(); - num_events = 0; // end loop in case of destroyed display - } - break; - - case FocusIn: - DBG_PRINT( "X11: event . FocusIn call %p\n", (void*)evt.xvisibility.window); - (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_TRUE); - break; - - case FocusOut: - DBG_PRINT( "X11: event . FocusOut call %p\n", (void*)evt.xvisibility.window); - (*env)->CallVoidMethod(env, jwindow, focusChangedID, JNI_FALSE, JNI_FALSE); - break; - - case Expose: - DBG_PRINT( "X11: event . Expose call %p %d/%d %dx%d count %d\n", (void*)evt.xexpose.window, - evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.count); - - if (evt.xexpose.count == 0 && evt.xexpose.width > 0 && evt.xexpose.height > 0) { - (*env)->CallVoidMethod(env, jwindow, windowRepaintID, JNI_FALSE, - evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height); - } - break; - - case MapNotify: - DBG_PRINT( "X11: event . MapNotify call Event %p, Window %p, override_redirect %d, child-event: %d\n", - (void*)evt.xmap.event, (void*)evt.xmap.window, (int)evt.xmap.override_redirect, - evt.xmap.event!=evt.xmap.window); - if( evt.xmap.event == evt.xmap.window ) { - // ignore child window notification - { - // update insets - int left, right, top, bottom; - NewtWindows_updateInsets(env, jwindow, dpy, evt.xany.window, &left, &right, &top, &bottom); - } - (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); - } - break; - - case UnmapNotify: - DBG_PRINT( "X11: event . UnmapNotify call Event %p, Window %p, from_configure %d, child-event: %d\n", - (void*)evt.xunmap.event, (void*)evt.xunmap.window, (int)evt.xunmap.from_configure, - evt.xunmap.event!=evt.xunmap.window); - if( evt.xunmap.event == evt.xunmap.window ) { - // ignore child window notification - (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_FALSE); - } - break; - - case ReparentNotify: - { - jlong parentResult; // 0 if root, otherwise proper value - Window winRoot, winTopParent; - #ifdef VERBOSE_ON - Window oldParentRoot, oldParentTopParent; - Window parentRoot, parentTopParent; - if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.event, &oldParentRoot, &oldParentTopParent) ) { - oldParentRoot=0; oldParentTopParent = 0; - } - if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.parent, &parentRoot, &parentTopParent) ) { - parentRoot=0; parentTopParent = 0; - } - #endif - if( 0 == NewtWindows_getRootAndParent(dpy, evt.xreparent.window, &winRoot, &winTopParent) ) { - winRoot=0; winTopParent = 0; - } - if(evt.xreparent.parent == winRoot) { - parentResult = 0; // our java indicator for root window - } else { - parentResult = (jlong) (intptr_t) evt.xreparent.parent; - } - #ifdef VERBOSE_ON - DBG_PRINT( "X11: event . ReparentNotify: call %d/%d OldParent %p (root %p, top %p), NewParent %p (root %p, top %p), Window %p (root %p, top %p)\n", - evt.xreparent.x, evt.xreparent.y, - (void*)evt.xreparent.event, (void*)oldParentRoot, (void*)oldParentTopParent, - (void*)evt.xreparent.parent, (void*)parentRoot, (void*)parentTopParent, - (void*)evt.xreparent.window, (void*)winRoot, (void*)winTopParent); - #endif - (*env)->CallVoidMethod(env, jwindow, reparentNotifyID, (jlong)evt.xreparent.parent); - } - break; - - // unhandled events .. yet .. - - default: - DBG_PRINT("X11: event . unhandled %d 0x%X call %p\n", (int)evt.type, (unsigned int)evt.type, (void*)evt.xunmap.window); - } - } -} - - -/** - * Screen - */ - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: GetScreen - * Signature: (JI)J - */ -JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Screen_GetScreen0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_index) -{ - Display * dpy = (Display *)(intptr_t)display; - Screen * scrn= NULL; - - DBG_PRINT("X11: X11Screen_GetScreen0 dpy %p START\n", dpy); - - if(dpy==NULL) { - NewtCommon_FatalError(env, "invalid display connection.."); - } - - scrn = ScreenOfDisplay(dpy, screen_index); - if(scrn==NULL) { - fprintf(stderr, "couldn't get screen idx %d\n", screen_index); - } - DBG_PRINT("X11: X11Screen_GetScreen0 idx %d -> scrn %p DONE\n", screen_index, scrn); - return (jlong) (intptr_t) scrn; -} - -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getWidth0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display * dpy = (Display *) (intptr_t) display; - return (jint) XDisplayWidth( dpy, scrn_idx); -} - -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getHeight0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display * dpy = (Display *) (intptr_t) display; - return (jint) XDisplayHeight( dpy, scrn_idx); -} - - -static Bool NewtScreen_getRANDRVersion(Display *dpy, int *major, int *minor) { - if( 0 == XRRQueryVersion(dpy, major, minor) ) { - return False; - } - return True; -} - -static Bool NewtScreen_hasRANDR(Display *dpy) { - int major, minor; - return NewtScreen_getRANDRVersion(dpy, &major, &minor); -} - -static int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { - int rot; - if(xrotation == RR_Rotate_0) { - rot = 0; - } - else if(xrotation == RR_Rotate_90) { - rot = 90; - } - else if(xrotation == RR_Rotate_180) { - rot = 180; - } - else if(xrotation == RR_Rotate_270) { - rot = 270; - } else { - NewtCommon_throwNewRuntimeException(env, "invalid native rotation: %d", xrotation); - } - return rot; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getAvailableScreenModeRotations0 - * Signature: (JI)I - */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getAvailableScreenModeRotations0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - int num_rotations = 0; - Rotation cur_rotation, rotations_supported; - int rotations[4]; - int major, minor; - - if(False == NewtScreen_getRANDRVersion(dpy, &major, &minor)) { - fprintf(stderr, "RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - rotations_supported = XRRRotations (dpy, (int)scrn_idx, &cur_rotation); - - if(0 != (rotations_supported & RR_Rotate_0)) { - rotations[num_rotations++] = 0; - } - if(0 != (rotations_supported & RR_Rotate_90)) { - rotations[num_rotations++] = 90; - } - if(0 != (rotations_supported & RR_Rotate_180)) { - rotations[num_rotations++] = 180; - } - if(0 != (rotations_supported & RR_Rotate_270)) { - rotations[num_rotations++] = 270; - } - - jintArray properties = NULL; - - if(num_rotations>0) { - properties = (*env)->NewIntArray(env, num_rotations); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); - } - - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); - } - - return properties; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getNumScreenModeResolution0 - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getNumScreenModeResolutions0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getNumScreenModeResolutions0: RANDR not available\n"); - return 0; - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - - DBG_PRINT("getNumScreenModeResolutions0: %d\n", num_sizes); - - return num_sizes; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getScreenModeResolutions0 - * Signature: (JII)[I - */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getScreenModeResolution0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getScreenModeResolution0: RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - // Fill the properties in temp jint array - int propIndex = 0; - jint prop[4]; - - prop[propIndex++] = xrrs[(int)resMode_idx].width; - prop[propIndex++] = xrrs[(int)resMode_idx].height; - prop[propIndex++] = xrrs[(int)resMode_idx].mwidth; - prop[propIndex++] = xrrs[(int)resMode_idx].mheight; - - jintArray properties = (*env)->NewIntArray(env, 4); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", 4); - } - - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, 4, prop); - - return properties; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getScreenModeRates0 - * Signature: (JII)[I - */ -JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_X11Screen_getScreenModeRates0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getScreenModeRates0: RANDR not available\n"); - return (*env)->NewIntArray(env, 0); - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - int num_rates; - short *rates = XRRRates(dpy, (int)scrn_idx, (int)resMode_idx, &num_rates); - - jint prop[num_rates]; - int i; - for(i=0; i<num_rates; i++) { - prop[i] = (int) rates[i]; - /** fprintf(stderr, "rate[%d, %d, %d/%d]: %d\n", (int)scrn_idx, resMode_idx, i, num_rates, prop[i]); */ - } - - jintArray properties = (*env)->NewIntArray(env, num_rates); - if (properties == NULL) { - NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rates); - } - - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, num_rates, prop); - - return properties; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getCurrentScreenRate0 - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRate0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRate0: RANDR not available\n"); - return -1; - } - - // get current resolutions and frequencies - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - short original_rate = XRRConfigCurrentRate(conf); - - //free - XRRFreeScreenConfigInfo(conf); - - DBG_PRINT("getCurrentScreenRate0: %d\n", (int)original_rate); - - return (jint) original_rate; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getCurrentScreenRotation0 - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRotation0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenRotation0: RANDR not available\n"); - return -1; - } - - //get current resolutions and frequencies - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - - Rotation rotation; - XRRConfigCurrentConfiguration(conf, &rotation); - - //free - XRRFreeScreenConfigInfo(conf); - - return NewtScreen_XRotation2Degree(env, rotation); -} - - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: getCurrentScreenResolutionIndex0 - * Signature: (JI)I - */ -JNIEXPORT jint JNICALL Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenResolutionIndex0 - (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_getCurrentScreenResolutionIndex0: RANDR not available\n"); - return -1; - } - - // get current resolutions and frequency configuration - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - short original_rate = XRRConfigCurrentRate(conf); - - Rotation original_rotation; - SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); - - //free - XRRFreeScreenConfigInfo(conf); - - DBG_PRINT("getCurrentScreenResolutionIndex0: %d\n", (int)original_size_id); - return (jint)original_size_id; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: setCurrentScreenModeStart0 - * Signature: (JIIII)Z - */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModeStart0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) -{ - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)screen_idx); - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModeStart0: RANDR not available\n"); - return JNI_FALSE; - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions - XRRScreenConfiguration *conf; - int rot; - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - conf = XRRGetScreenInfo(dpy, root); - - switch(rotation) { - case 0: - rot = RR_Rotate_0; - break; - case 90: - rot = RR_Rotate_90; - break; - case 180: - rot = RR_Rotate_180; - break; - case 270: - rot = RR_Rotate_270; - break; - default: - NewtCommon_throwNewRuntimeException(env, "Invalid rotation: %d", rotation); - } - - DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", - resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); - - XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); - - XSync(dpy, False); - XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, rot, (short)freq, CurrentTime); - XSync(dpy, False); - - //free - XRRFreeScreenConfigInfo(conf); - XSync(dpy, False); - - return JNI_TRUE; -} - -/* - * Class: jogamp_newt_driver_x11_X11Screen - * Method: setCurrentScreenModePollEnd0 - * Signature: (J)Z - */ -JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModePollEnd0 - (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) -{ - Display *dpy = (Display *) (intptr_t) display; - int randr_event_base, randr_error_base; - XEvent evt; - XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; - - if(False == NewtScreen_hasRANDR(dpy)) { - DBG_PRINT("Java_jogamp_newt_driver_x11_X11Screen_setCurrentScreenModePollEnd0: RANDR not available\n"); - return JNI_FALSE; - } - - int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions - XRRScreenConfiguration *conf; - - if( 0 > resMode_idx || resMode_idx >= num_sizes ) { - NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); - } - - XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); - - int done = 0; - int rot; - do { - if ( 0 >= XEventsQueued(dpy, QueuedAfterFlush) ) { - return; - } - XNextEvent(dpy, &evt); - - switch (evt.type - randr_event_base) { - case RRScreenChangeNotify: - rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); - DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call %p (root %p) resIdx %d rot %d %dx%d\n", - (void*)scn_event->window, (void*)scn_event->root, - (int)scn_event->size_index, rot, - scn_event->width, scn_event->height); - // done = scn_event->size_index == resMode_idx; // not reliable .. - done = rot == rotation && - scn_event->width == xrrs[resMode_idx].width && - scn_event->height == xrrs[resMode_idx].height; - break; - default: - DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); - } - XRRUpdateConfiguration(&evt); - } while(!done); - - XSync(dpy, False); - -} - /** * Window */ @@ -1468,37 +442,6 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Screen_setCurrentScree JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_x11_X11Window_initIDs0 (JNIEnv *env, jclass clazz) { - insetsChangedID = (*env)->GetMethodID(env, clazz, "insetsChanged", "(ZIIII)V"); - sizeChangedID = (*env)->GetMethodID(env, clazz, "sizeChanged", "(ZIIZ)V"); - positionChangedID = (*env)->GetMethodID(env, clazz, "positionChanged", "(ZII)V"); - focusChangedID = (*env)->GetMethodID(env, clazz, "focusChanged", "(ZZ)V"); - visibleChangedID = (*env)->GetMethodID(env, clazz, "visibleChanged", "(ZZ)V"); - reparentNotifyID = (*env)->GetMethodID(env, clazz, "reparentNotify", "(J)V"); - windowDestroyNotifyID = (*env)->GetMethodID(env, clazz, "windowDestroyNotify", "()V"); - windowRepaintID = (*env)->GetMethodID(env, clazz, "windowRepaint", "(ZIIII)V"); - enqueueMouseEventID = (*env)->GetMethodID(env, clazz, "enqueueMouseEvent", "(ZIIIIII)V"); - sendMouseEventID = (*env)->GetMethodID(env, clazz, "sendMouseEvent", "(IIIIII)V"); - enqueueKeyEventID = (*env)->GetMethodID(env, clazz, "enqueueKeyEvent", "(ZIIIC)V"); - sendKeyEventID = (*env)->GetMethodID(env, clazz, "sendKeyEvent", "(IIIC)V"); - enqueueRequestFocusID = (*env)->GetMethodID(env, clazz, "enqueueRequestFocus", "(Z)V"); - focusActionID = (*env)->GetMethodID(env, clazz, "focusAction", "()Z"); - - if (insetsChangedID == NULL || - sizeChangedID == NULL || - positionChangedID == NULL || - focusChangedID == NULL || - visibleChangedID == NULL || - reparentNotifyID == NULL || - windowDestroyNotifyID == NULL || - windowRepaintID == NULL || - enqueueMouseEventID == NULL || - sendMouseEventID == NULL || - enqueueKeyEventID == NULL || - sendKeyEventID == NULL || - focusActionID == NULL || - enqueueRequestFocusID == NULL) { - return JNI_FALSE; - } return JNI_TRUE; } @@ -1513,14 +456,12 @@ static Bool WaitForUnmapNotify( Display *dpy, XEvent *event, XPointer arg ) { static void NewtWindows_setPosSize(Display *dpy, Window w, jint x, jint y, jint width, jint height) { if(width>0 && height>0 || x>=0 && y>=0) { // resize/position if requested XWindowChanges xwc; - int flags = 0; + int flags = CWX | CWY; memset(&xwc, 0, sizeof(XWindowChanges)); - if(0<=x && 0<=y) { - flags |= CWX | CWY; - xwc.x=x; - xwc.y=y; - } + xwc.x=x; + xwc.y=y; + if(0<width && 0<height) { flags |= CWWidth | CWHeight; xwc.width=width; @@ -1534,13 +475,12 @@ static void NewtWindows_setPosSize(Display *dpy, Window w, jint x, jint y, jint /* * Class: jogamp_newt_driver_x11_X11Window * Method: CreateWindow - * Signature: (JJIJIIII)J */ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Window_CreateWindow0 (JNIEnv *env, jobject obj, jlong parent, jlong display, jint screen_index, jlong visualID, jlong javaObjectAtom, jlong windowDeleteAtom, - jint x, jint y, jint width, jint height, int flags) + jint x, jint y, jint width, jint height, jboolean autoPosition, int flags) { Display * dpy = (Display *)(intptr_t)display; Atom wm_delete_atom = (Atom)windowDeleteAtom; @@ -1576,9 +516,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Window_CreateWindow0 if(0==windowParent) { windowParent = root; } - DBG_PRINT( "X11: CreateWindow dpy %p, parent %p, %x/%d %dx%d, undeco %d, alwaysOnTop %d\n", + DBG_PRINT( "X11: CreateWindow dpy %p, parent %p, %d/%d %dx%d, undeco %d, alwaysOnTop %d, autoPosition %d\n", (void*)dpy, (void*)windowParent, x, y, width, height, - TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags)); + TST_FLAG_IS_UNDECORATED(flags), TST_FLAG_IS_ALWAYSONTOP(flags), autoPosition); // try given VisualID on screen memset(&visualTemplate, 0, sizeof(XVisualInfo)); @@ -1628,7 +568,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Window_CreateWindow0 { int _x = x, _y = y; // pos for CreateWindow, might be tweaked - if(0>_x || 0>_y) { + if(JNI_TRUE == autoPosition) { // user didn't requested specific position, use WM default _x = 0; _y = 0; @@ -1662,7 +602,6 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Window_CreateWindow0 { XEvent event; int left, right, top, bottom; - Bool userPos = 0<=x && 0<=y ; XMapWindow(dpy, window); XIfEvent( dpy, &event, WaitForMapNotify, (XPointer) window ); // wait to get proper insets values @@ -1671,19 +610,17 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_x11_X11Window_CreateWindow0 NewtWindows_updateInsets(env, jwindow, dpy, window, &left, &right, &top, &bottom); (*env)->CallVoidMethod(env, jwindow, visibleChangedID, JNI_FALSE, JNI_TRUE); - if(!userPos) { + if(JNI_TRUE == autoPosition) { // get position from WM int dest_x, dest_y; Window child; XTranslateCoordinates(dpy, window, windowParent, 0, 0, &dest_x, &dest_y, &child); x = (int)dest_x; y = (int)dest_y; } - DBG_PRINT("X11: [CreateWindow]: client: %d/%d %dx%d (is user-pos %d)\n", x, y, width, height, userPos); + DBG_PRINT("X11: [CreateWindow]: client: %d/%d %dx%d (autoPosition %d)\n", x, y, width, height, autoPosition); x -= left; // top-level y -= top; // top-level - if(0>x) { x = 0; } - if(0>y) { y = 0; } DBG_PRINT("X11: [CreateWindow]: top-level: %d/%d\n", x, y); NewtWindows_setPosSize(dpy, window, x, y, width, height); @@ -1774,7 +711,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 fsEWMHFlags |= _NET_WM_ABOVE; // toggle above only } - displayDispatchErrorHandlerEnable(1, env); + NewtDisplay_displayDispatchErrorHandlerEnable(1, env); DBG_PRINT( "X11: reconfigureWindow0 dpy %p, scrn %d, parent %p/%p, win %p, %d/%d %dx%d, parentChange %d, hasParent %d, decorationChange %d, undecorated %d, fullscreenChange %d, fullscreen %d, alwaysOnTopChange %d, alwaysOnTop %d, visibleChange %d, visible %d, tempInvisible %d, fsEWMHFlags %d\n", (void*)dpy, screen_index, (void*) jparent, (void*)parent, (void*)w, @@ -1792,7 +729,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 ( TST_FLAG_CHANGE_FULLSCREEN(flags) || TST_FLAG_CHANGE_ALWAYSONTOP(flags) ) ) { Bool enable = TST_FLAG_CHANGE_FULLSCREEN(flags) ? TST_FLAG_IS_FULLSCREEN(flags) : TST_FLAG_IS_ALWAYSONTOP(flags) ; if( NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, enable) ) { - displayDispatchErrorHandlerEnable(0, env); + NewtDisplay_displayDispatchErrorHandlerEnable(0, env); return; } } @@ -1856,7 +793,7 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_x11_X11Window_reconfigureWindow0 NewtWindows_setFullscreenEWMH(dpy, root, w, fsEWMHFlags, isVisible, True); } - displayDispatchErrorHandlerEnable(0, env); + NewtDisplay_displayDispatchErrorHandlerEnable(0, env); DBG_PRINT( "X11: reconfigureWindow0 X\n"); } diff --git a/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java index 21eb8af2d..74419e564 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTElektronActivity.java @@ -62,7 +62,7 @@ public class NEWTElektronActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new ElektronenMultiplizierer()); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java index 337dafc71..ba861d012 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES1Activity.java @@ -62,7 +62,7 @@ public class NEWTGearsES1Activity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GearsES1(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java index 6abb0b354..89ecf4cb9 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2Activity.java @@ -65,7 +65,7 @@ public class NEWTGearsES2Activity extends NewtBaseActivity { GearsES2 demo = new GearsES2(0); // demo.enableAndroidTrace(true); glWindow.addGLEventListener(demo); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java index 691151ef3..d6b7507a3 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGearsES2TransActivity.java @@ -61,7 +61,7 @@ public class NEWTGearsES2TransActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GearsES2(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java index 83f35879b..1efedcd6d 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI1pActivity.java @@ -61,7 +61,7 @@ public class NEWTGraphUI1pActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GPUUISceneGLListener0A(0)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java index 17924d43d..39fb5e2cc 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTGraphUI2pActivity.java @@ -62,7 +62,7 @@ public class NEWTGraphUI2pActivity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new GPUUISceneGLListener0A(Region.VBAA_RENDERING_BIT)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java index 24b4eaf0c..99d7fd723 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES1Activity.java @@ -61,7 +61,7 @@ public class NEWTRedSquareES1Activity extends NewtBaseActivity { setContentView(getWindow(), glWindow); glWindow.addGLEventListener(new RedSquareES1(1)); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java index 51cddd523..804e627a5 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2Activity.java @@ -64,7 +64,7 @@ public class NEWTRedSquareES2Activity extends NewtBaseActivity { final RedSquareES2 demo = new RedSquareES2(0); // demo.enableAndroidTrace(true); glWindow.addGLEventListener(demo); - glWindow.getWindow().getScreen().addScreenModeListener(new ScreenModeListener() { + glWindow.getScreen().addScreenModeListener(new ScreenModeListener() { public void screenModeChangeNotify(ScreenMode sm) { } public void screenModeChanged(ScreenMode sm, boolean success) { System.err.println("ScreenMode Changed: "+sm); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRendererNEWT01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRendererNEWT01.java index 55d3371c9..b6c3cc7fe 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRendererNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRendererNEWT01.java @@ -32,11 +32,6 @@ public class TestRegionRendererNEWT01 extends UITestCase { org.junit.runner.JUnitCore.main(tstname);
}
- @BeforeClass
- public static void initClass() {
- GLProfile.initSingleton(true);
- }
-
static void destroyWindow(GLWindow window) {
if(null!=window) {
window.destroy();
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java index 9fd0c05e7..8f03af7c9 100755 --- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT01.java @@ -35,11 +35,6 @@ public class TestTextRendererNEWT01 extends UITestCase { org.junit.runner.JUnitCore.main(tstname);
}
- @BeforeClass
- public static void initClass() {
- GLProfile.initSingleton(true);
- }
-
static void destroyWindow(GLWindow window) {
if(null!=window) {
window.destroy();
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java index 5e0c266e6..160dc0ffe 100755 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java @@ -55,7 +55,6 @@ public class GPURegionNewtDemo01 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java index f1db1ccdd..e7b5c73c5 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java @@ -52,7 +52,6 @@ public class GPURegionNewtDemo02 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java index bcd60d441..d257f78fc 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java @@ -49,7 +49,6 @@ public class GPUTextNewtDemo01 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java index 5981e7971..1b71cd781 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java @@ -57,7 +57,6 @@ public class GPUTextNewtDemo02 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java index 91f66875b..0563ab2cf 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java @@ -16,7 +16,6 @@ public class GPUUISceneNewtDemo01 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java index a6cd770d1..4c8da139e 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java @@ -17,7 +17,6 @@ public class GPUUISceneNewtDemo02 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UINewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UINewtDemo01.java index 27b7ecc13..0577c5ff0 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UINewtDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UINewtDemo01.java @@ -54,7 +54,6 @@ public class UINewtDemo01 { static final boolean TRACE = false; public static void main(String[] args) { - GLProfile.initSingleton(true); GLProfile glp = GLProfile.getGL2ES2(); GLCapabilities caps = new GLCapabilities(glp); caps.setAlphaBits(4); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java index a42247b12..62e74466f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug00NEWT.java @@ -55,11 +55,6 @@ public class TestGLDebug00NEWT extends UITestCase { static String dbgTstMsg0 = "Hello World"; static int dbgTstId0 = 42; - @BeforeClass - public static void initClass() { - // GLProfile.initSingleton(true); - } - public class WindowContext { public final Window window; public final GLContext context; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java index 6ab6714dc..f9b566c25 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLDebug01NEWT.java @@ -41,7 +41,6 @@ import javax.media.opengl.GLRunnable; import org.junit.Assert; import org.junit.Test; -import org.junit.BeforeClass; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -51,11 +50,6 @@ public class TestGLDebug01NEWT extends UITestCase { static String dbgTstMsg0 = "Hello World"; static int dbgTstId0 = 42; - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - GLWindow createWindow(GLProfile glp, boolean debugGL) { GLCapabilities caps = new GLCapabilities(glp); // diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java index 5af526364..e4245ef11 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLExtensionQueryOffscreen.java @@ -42,6 +42,8 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLProfile; +import jogamp.opengl.GLDrawableFactoryImpl; + import org.junit.Test; public class TestGLExtensionQueryOffscreen { @@ -52,9 +54,12 @@ public class TestGLExtensionQueryOffscreen { instance.testJogl2ExtensionCheck2(); } + /** + * @deprecated This test uses a non public API in jogamp.opengl.* and hence is not recommended + */ @Test public void testJogl2ExtensionCheck1() { - GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); + GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getDesktopFactory(); GLContext sharedContext = factory.getOrCreateSharedContext(null); sharedContext.makeCurrent(); String extensions; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java index 7813482e1..6a5f76ff9 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGLProfile01NEWT.java @@ -137,17 +137,6 @@ public class TestGLProfile01NEWT extends UITestCase { dumpVersion(glp); } - @Test - public void test06GLProfileShutdownRecreate() throws InterruptedException { - GLProfile.shutdown(); - GLProfile.initSingleton(true); - System.out.println("GLProfile.getDefault(): "+GLProfile.getDefault()); - System.out.println("GLProfile.getDefaultDesktopDevice(): "+GLProfile.getDefaultDesktopDevice()); - System.out.println("GLProfile.getDefaultEGLDevice(): "+GLProfile.getDefaultEGLDevice()); - System.out.println("GLProfile.getDefaultDevice(): "+GLProfile.getDefaultDevice()); - } - - protected void dumpVersion(GLProfile glp) throws InterruptedException { GLCapabilities caps = new GLCapabilities(glp); GLWindow glWindow = GLWindow.create(caps); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java new file mode 100644 index 000000000..fc025d023 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestInitConcurrentNEWT.java @@ -0,0 +1,230 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Window; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestInitConcurrentNEWT extends UITestCase { + + static final int demoSize = 128; + + static long duration = 300; // ms + + static InsetsImmutable insets = null; + static int scrnHeight, scrnWidth; + static int num_x, num_y; + + @BeforeClass + public static void initClass() { + Window dummyWindow = NewtFactory.createWindow(new Capabilities()); + dummyWindow.setSize(demoSize, demoSize); + dummyWindow.setVisible(true); + Assert.assertEquals(true, dummyWindow.isVisible()); + Assert.assertEquals(true, dummyWindow.isNativeValid()); + insets = dummyWindow.getInsets(); + scrnHeight = dummyWindow.getScreen().getHeight(); + scrnWidth = dummyWindow.getScreen().getWidth(); + num_x = scrnWidth / ( demoSize + insets.getTotalWidth() ) - 2; + num_y = scrnHeight / ( demoSize + insets.getTotalHeight() ) - 2; + dummyWindow.destroy(); + } + + public class JOGLTask implements Runnable { + private int id; + private Object postSync; + private boolean done = false; + + public JOGLTask(Object postSync, int id) { + this.postSync = postSync; + this.id = id; + } + public void run() { + int x = ( id % num_x ) * ( demoSize + insets.getTotalHeight() ); + int y = ( (id / num_x) % num_y ) * ( demoSize + insets.getTotalHeight() ); + + System.err.println("JOGLTask "+id+": START: "+x+"/"+y+" - "+Thread.currentThread().getName()); + GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glWindow); + glWindow.setTitle("Task "+id); + glWindow.setPosition(x + insets.getLeftWidth(), y + insets.getTopHeight() ); + + glWindow.addGLEventListener(new GearsES2(0)); + + Animator animator = new Animator(glWindow); + + glWindow.setSize(demoSize, demoSize); + glWindow.setVisible(true); + animator.setUpdateFPSFrames(60, null); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeValid()); + Assert.assertEquals(true, glWindow.isRealized()); + System.err.println("JOGLTask "+id+": RUNNING: "+Thread.currentThread().getName()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + animator.stop(); + glWindow.destroy(); + + System.err.println("JOGLTask "+id+": DONE/SYNC: "+Thread.currentThread().getName()); + synchronized (postSync) { + done = true; + System.err.println("JOGLTask "+id+": END: "+Thread.currentThread().getName()); + postSync.notifyAll(); + } + } + + public boolean done() { return done; } + } + + protected static boolean done(JOGLTask[] tasks) { + for(int i=tasks.length-1; i>=0; i--) { + if(!tasks[i].done()) { + return false; + } + } + return true; + } + protected static String doneDump(JOGLTask[] tasks) { + StringBuffer sb = new StringBuffer(); + sb.append("["); + for(int i=0; i<tasks.length; i++) { + if(i>0) { + sb.append(", "); + } + sb.append(i).append(": ").append(tasks[i].done()); + } + sb.append("]"); + return sb.toString(); + } + + protected static boolean isDead(Thread[] threads) { + for(int i=threads.length-1; i>=0; i--) { + if(threads[i].isAlive()) { + return false; + } + } + return true; + } + protected static String isAliveDump(Thread[] threads) { + StringBuffer sb = new StringBuffer(); + sb.append("["); + for(int i=0; i<threads.length; i++) { + if(i>0) { + sb.append(", "); + } + sb.append(i).append(": ").append(threads[i].isAlive()); + } + sb.append("]"); + return sb.toString(); + } + + protected void runJOGLTasks(int num) throws InterruptedException { + final String currentThreadName = Thread.currentThread().getName(); + final Object sync = new Object(); + final JOGLTask[] tasks = new JOGLTask[num]; + final Thread[] threads = new Thread[num]; + int i; + for(i=0; i<num; i++) { + tasks[i] = new JOGLTask(sync, i); + threads[i] = new Thread(tasks[i], currentThreadName+"-jt"+i); + } + for(i=0; i<num; i++) { + threads[i].start(); + } + synchronized (sync) { + while(!done(tasks)) { + try { + sync.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + Assert.assertTrue("Tasks are incomplete. Complete: "+doneDump(tasks), done(tasks)); + i=0; + while(i<30 && !isDead(threads)) { + Thread.sleep(100); + i++; + } + Assert.assertTrue("Threads are still alive after 3s. Alive: "+isAliveDump(threads), isDead(threads)); + } + + @Test + public void test01OneThread() throws InterruptedException { + runJOGLTasks(1); + } + + @Test + public void test02TwoThreads() throws InterruptedException { + runJOGLTasks(2); + } + + @Test + public void test16SixteenThreads() throws InterruptedException { + runJOGLTasks(16); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + String tstname = TestInitConcurrentNEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLCanvasAWT.java new file mode 100644 index 000000000..5523ce5ce --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLCanvasAWT.java @@ -0,0 +1,52 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import javax.media.opengl.awt.GLCanvas; + +import org.junit.Test; + +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestMainVersionGLCanvasAWT extends UITestCase { + + @Test + public void testMain() throws InterruptedException { + GLCanvas.main(null); + } + + + public static void main(String args[]) throws IOException { + String tstname = TestMainVersionGLCanvasAWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLWindowNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLWindowNEWT.java new file mode 100644 index 000000000..d178e34f4 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestMainVersionGLWindowNEWT.java @@ -0,0 +1,50 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; +import org.junit.Test; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestMainVersionGLWindowNEWT extends UITestCase { + + @Test + public void testMain() throws InterruptedException { + GLWindow.main(null); + } + + + public static void main(String args[]) throws IOException { + String tstname = TestMainVersionGLWindowNEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNVSwapGroupNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNVSwapGroupNEWT.java index 0f64738de..05f122bb4 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNVSwapGroupNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestNVSwapGroupNEWT.java @@ -52,7 +52,6 @@ public class TestNVSwapGroupNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestPBufferDeadlockAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestPBufferDeadlockAWT.java new file mode 100644 index 000000000..5f04ed616 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestPBufferDeadlockAWT.java @@ -0,0 +1,127 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.jawt.JAWTUtil; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.opengl.test.junit.util.UITestCase; + +public class TestPBufferDeadlockAWT extends UITestCase { + static GLProfile glp; + static int width, height; + + @BeforeClass + public static void initClass() { + glp = GLProfile.getDefault(); + Assert.assertNotNull( glp ); + width = 512; + height = 512; + } + + protected void runTestGL( GLCapabilities caps ) throws InterruptedException, InvocationTargetException { + final GLPbuffer pbuffer = GLDrawableFactory.getFactory( GLProfile.get( "GL2" ) ).createGLPbuffer( + null, + caps, new DefaultGLCapabilitiesChooser(), + 512, 512, + null + ); + + final boolean[] done = {false}; + final Runnable pbufferCreationAction = new Runnable() { + public void run() { + System.err.println("AA.1"); + pbuffer.display(); + done[ 0 ] = true; + System.err.println("AA.X"); + } + }; + + EventQueue.invokeAndWait(new Runnable() { + public void run() { + Assert.assertTrue(EventQueue.isDispatchThread()); + JAWTUtil.lockToolkit(); + try { + final RunnableTask rTask = new RunnableTask(pbufferCreationAction, new Object(), false); + System.err.println("BB.0: "+rTask.getSyncObject()); + synchronized (rTask.getSyncObject()) { + System.err.println("BB.1: "+rTask.getSyncObject()); + new Thread(rTask, Thread.currentThread().getName()+"-Pbuffer_Creation").start(); + try { + System.err.println("BB.2"); + rTask.getSyncObject().wait(); + System.err.println("BB.3"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.err.println("BB.X"); + } + } finally { + JAWTUtil.unlockToolkit(); + } + } + }); + Assert.assertTrue(done[0]); + } + + @Test(timeout = 2000) // 2s timeout + public void testDeadlock() throws InterruptedException, InvocationTargetException { + GLCapabilities caps = new GLCapabilities( glp ); + runTestGL( caps ); + } + + static long duration = 500; // ms + + public static void main( String args[] ) { + for ( int i = 0; i < args.length; i++ ) { + if ( args[ i ].equals( "-time" ) ) { + i++; + try { + duration = Integer.parseInt( args[ i ] ); + } + catch ( Exception ex ) { + ex.printStackTrace(); + } + } + } + org.junit.runner.JUnitCore.main( TestPBufferDeadlockAWT.class.getName() ); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT.java index f8f835c3b..308094720 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT.java @@ -56,7 +56,6 @@ public class TestSharedContextListNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT2.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT2.java new file mode 100644 index 000000000..4281572d7 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextListNEWT2.java @@ -0,0 +1,156 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import com.jogamp.newt.opengl.GLWindow; + +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import com.jogamp.opengl.util.Animator; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.UITestCase; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestSharedContextListNEWT2 extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + GLWindow sharedDrawable; + Gears sharedGears; + + @BeforeClass + public static void initClass() { + glp = GLProfile.get(GLProfile.GL2); + Assert.assertNotNull(glp); + caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + width = 256; + height = 256; + } + + private void initShared() { + sharedDrawable = GLWindow.create(caps); + Assert.assertNotNull(sharedDrawable); + sharedGears = new Gears(0); + Assert.assertNotNull(sharedGears); + sharedDrawable.addGLEventListener(sharedGears); + sharedDrawable.setSize(width, height); + sharedDrawable.setVisible(true); + // init and render one frame, which will setup the Gears display lists + sharedDrawable.display(); + } + + private void releaseShared() { + Assert.assertNotNull(sharedDrawable); + sharedDrawable.destroy(); + sharedDrawable = null; + } + + protected GLWindow runTestGL(Animator animator, int x, int y, boolean useShared, boolean vsync) throws InterruptedException { + GLWindow glWindow = GLWindow.create(caps); + + Assert.assertNotNull(glWindow); + glWindow.setTitle("Shared Gears NEWT Test: "+x+"/"+y+" shared "+useShared); + if(useShared) { + glWindow.setSharedContext(sharedDrawable.getContext()); + } + + glWindow.setSize(width, height); + + Gears gears = new Gears(vsync ? 1 : 0); + if(useShared) { + gears.setGears(sharedGears.getGear1(), sharedGears.getGear2(), sharedGears.getGear3()); + } + glWindow.addGLEventListener(gears); + + animator.add(glWindow); + animator.start(); + glWindow.setVisible(true); + + Assert.assertTrue(AWTRobotUtil.waitForRealized(glWindow, true)); + Assert.assertTrue(AWTRobotUtil.waitForVisible(glWindow, true)); + glWindow.setPosition(x, y); + + return glWindow; + } + + @Test + public void test01() throws InterruptedException { + initShared(); + GLWindow f1 = runTestGL(new Animator(), 0, 0, true, false); + InsetsImmutable insets = f1.getInsets(); + GLWindow f2 = runTestGL(new Animator(), f1.getX()+width+insets.getTotalWidth(), + f1.getY()+0, true, false); + GLWindow f3 = runTestGL(new Animator(), f1.getX()+0, + f1.getY()+height+insets.getTotalHeight(), true, false); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + + // here we go again: On AMD/X11 the create/destroy sequence must be the same + // even though this is against the chicken/egg logic here .. + releaseShared(); + + f1.destroy(); + f2.destroy(); + f3.destroy(); + + // see above .. + // releaseShared(); + } + + static long duration = 2000; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + /** + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + System.err.println(stdin.readLine()); */ + org.junit.runner.JUnitCore.main(TestSharedContextListNEWT2.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java new file mode 100644 index 000000000..60f46fe9e --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java @@ -0,0 +1,778 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +import javax.media.opengl.GL2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; +import javax.media.opengl.glu.GLU; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.GLBuffers; + + +/** + * TestSharedContextNewtAWTBug523 + * + * Opens a single JFrame with two OpenGL windows and sliders to adjust the view orientation. + * + * Each window renders a red triangle and a blue triangle. + * The red triangle is rendered using glBegin / glVertex / glEnd. + * The blue triangle is rendered using vertex buffer objects bound to a vertex array object. + * + * If static useNewt is true, then those windows are GLWindow objects in a NewtCanvasAWT. + * If static useNewt is false, then those windows are GLCanvas objects. + * + * If shareContext is true, then the two OpenGL windows are initialized with a shared context, + * so that they share the vertex buffer and array objects and display lists. + * If shareContext is false, then the two OpenGL windows each have their own context, and the blue + * triangle fails to render in one of the windows. + * + * The four test cases run through the four combinations of useNewt and shareContext. + * + * Similar test cases are {@link TestSharedContextListNEWT}, {@link TestSharedContextListAWT}, + * {@link TestSharedContextVBOES2NEWT} and {@link TestSharedContextVBOES1NEWT}. + * + */ +public class TestSharedContextNewtAWTBug523 extends UITestCase { + + static long durationPerTest = 1000; + + // counters for instances of event listener TwoTriangles + // private static int instanceCounter; + private static int initializationCounter; + + // This semaphore is released once each time a GLEventListener destroy method is called. + // The main thread waits twice on this semaphore to ensure both canvases have finished cleaning up. + private static Semaphore disposalCompleteSemaphore = new Semaphore(0); + + // Buffer objects can be shared across shared OpenGL context. + // If we run with sharedContext, then the tests will use these shared buffer objects, + // otherwise each event listener allocates its own buffer objects. + private static int [] sharedVertexBufferObjects = {0}; + private static int [] sharedIndexBufferObjects = {0}; + private static FloatBuffer sharedVertexBuffer; + private static IntBuffer sharedIndexBuffer; + + static private GLPbuffer initShared(GLCapabilities caps) { + GLPbuffer sharedDrawable = GLDrawableFactory.getFactory(caps.getGLProfile()).createGLPbuffer(null, caps, null, 64, 64, null); + Assert.assertNotNull(sharedDrawable); + // init and render one frame, which will setup the Gears display lists + sharedDrawable.display(); + return sharedDrawable; + } + + static private void releaseShared(GLPbuffer sharedDrawable) { + if(null != sharedDrawable) { + sharedDrawable.destroy(); + } + } + + // inner class that implements the event listener + static class TwoTriangles implements GLEventListener { + + boolean useShared; + int canvasWidth; + int canvasHeight; + private float boundsRadius = 2f; + private float viewDistance; + private float viewDistanceFactor = 1.0f; + private float xAxisRotation; + private float yAxisRotation; + private float viewFovDegrees = 15f; + + // vertex array objects cannot be shared across open gl canvases; + // + // However, display lists can be shared across GLCanvas instances (if those canvases are initialized with the same GLContext), + // including a display list created in one context that uses a VAO. + private int [] vertexArrayObjects = {0}; + + // Buffer objects can be shared across canvas instances, if those canvases are initialized with the same GLContext. + // If we run with sharedBufferObjects true, then the tests will use these shared buffer objects. + // If we run with sharedBufferObjects false, then each event listener allocates its own buffer objects. + private int [] privateVertexBufferObjects = {0}; + private int [] privateIndexBufferObjects = {0}; + private FloatBuffer privateVertexBuffer; + private IntBuffer privateIndexBuffer; + + TwoTriangles (int canvasWidth, int canvasHeight, boolean useShared) { + // instanceNum = instanceCounter++; + this.canvasWidth = canvasWidth; + this.canvasHeight = canvasHeight; + this.useShared = useShared; + } + + public void setXAxisRotation(float xRot) { + xAxisRotation = xRot; + } + + public void setYAxisRotation(float yRot) { + yAxisRotation = yRot; + } + + public void setViewDistanceFactor(float factor) { + viewDistanceFactor = factor; + } + + + public void init(GLAutoDrawable drawable) { + GL2 gl2 = drawable.getGL().getGL2(); + + System.err.println("INIT GL IS: " + gl2.getClass().getName()); + + // Disable VSync + gl2.setSwapInterval(0); + + // Setup the drawing area and shading mode + gl2.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + // the first instance of TwoTriangles initializes the shared buffer objects; + // synchronizing to deal with potential liveness issues if the data is intialized from one thread and used on another + synchronized (this) { + gl2.glGenVertexArrays(1, vertexArrayObjects, 0); + + gl2.glBindVertexArray(vertexArrayObjects[0]); + + // use either the shared or private vertex buffers, as + int [] vertexBufferObjects; + int [] indexBufferObjects; + FloatBuffer vertexBuffer; + IntBuffer indexBuffer; + // + if (useShared) { + vertexBufferObjects = sharedVertexBufferObjects; + indexBufferObjects = sharedIndexBufferObjects; + vertexBuffer = sharedVertexBuffer; + indexBuffer = sharedIndexBuffer; + } else { + vertexBufferObjects = privateVertexBufferObjects; + indexBufferObjects = privateIndexBufferObjects; + vertexBuffer = privateVertexBuffer; + indexBuffer = privateIndexBuffer; + } + + // if buffer sharing is enabled, then the first of the two event listeners to be + // initialized will allocate the buffers, and the other will re-use the allocated one + if (vertexBufferObjects[0] == 0) { + vertexBuffer = GLBuffers.newDirectFloatBuffer(18); + vertexBuffer.put(new float[]{ + 1.0f, -0.5f, 0f, // vertex 1 + 0f, 0f, 1f, // normal 1 + 1.5f, -0.5f, 0f, // vertex 2 + 0f, 0f, 1f, // normal 2 + 1.0f, 0.5f, 0f, // vertex 3 + 0f, 0f, 1f // normal 3 + }); + vertexBuffer.position(0); + + gl2.glGenBuffers(1, vertexBufferObjects, 0); + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexBufferObjects[0]); + gl2.glBufferData(GL2.GL_ARRAY_BUFFER, vertexBuffer.capacity() * Buffers.SIZEOF_FLOAT, vertexBuffer, GL2.GL_STATIC_DRAW); + } + + // A check in the case that buffer sharing is enabled but context sharing is not enabled -- in that + // case, the buffer objects are not shareable, and the blue triangle cannot be rendereds. + // Furthermore, although the calls to bind and draw elements do not cause an error from glGetError + // when this check is removed, true blue triangle is not rendered anyways, and more importantly, + // I found that with my system glDrawElements causes a runtime exception 50% of the time. Executing the binds + // to unshareable buffers sets up glDrawElements for unpredictable crashes -- sometimes it does, sometimes not. + if (gl2.glIsBuffer(vertexBufferObjects[0])) { + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexBufferObjects[0]); + // + gl2.glEnableClientState(GL2.GL_VERTEX_ARRAY); + gl2.glVertexPointer(3, GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 0); + // + gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY); + gl2.glNormalPointer(GL2.GL_FLOAT, 6 * GLBuffers.SIZEOF_FLOAT, 3 * GLBuffers.SIZEOF_FLOAT); + } + + if (indexBufferObjects[0] == 0) { + indexBuffer = GLBuffers.newDirectIntBuffer(3); + indexBuffer.put(new int[]{0, 1, 2}); + indexBuffer.position(0); + + gl2.glGenBuffers(1, indexBufferObjects, 0); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); + gl2.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * Buffers.SIZEOF_INT, indexBuffer, GL2.GL_STATIC_DRAW); + } + + // again, a check in the case that buffer sharing is enabled but context sharing is not enabled + if (gl2.glIsBuffer(indexBufferObjects[0])) { + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); + } + + gl2.glBindVertexArray(0); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); + gl2.glDisableClientState(GL2.GL_VERTEX_ARRAY); + gl2.glDisableClientState(GL2.GL_NORMAL_ARRAY); + + initializationCounter++; + } // synchronized (this) + + + viewDistance = setupViewFrustum(gl2, canvasWidth, canvasHeight, boundsRadius, 1.0f, viewFovDegrees); + + } + + public void dispose(GLAutoDrawable drawable) { + + synchronized (this) { + initializationCounter--; + + GL2 gl2 = drawable.getGL().getGL2(); + + gl2.glDeleteVertexArrays(1, vertexArrayObjects, 0); + vertexArrayObjects[0] = 0; + logAnyErrorCodes(gl2, "display"); + + // release shared resources + if (initializationCounter == 0 || !useShared) { + // use either the shared or private vertex buffers, as + int [] vertexBufferObjects; + int [] indexBufferObjects; + if (useShared) { + vertexBufferObjects = sharedVertexBufferObjects; + indexBufferObjects = sharedIndexBufferObjects; + } else { + vertexBufferObjects = privateVertexBufferObjects; + indexBufferObjects = privateIndexBufferObjects; + } + + gl2.glDeleteBuffers(1, vertexBufferObjects, 0); + gl2.glDeleteBuffers(1, indexBufferObjects, 0); + vertexBufferObjects[0] = 0; + indexBufferObjects[0] = 0; + logAnyErrorCodes(gl2, "display"); + } + + // release the main thread once for each disposal + disposalCompleteSemaphore.release(); + } // synchronized (this) + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + } + + public void display(GLAutoDrawable drawable) { + + // wait until all instances are initialized before attempting to draw using the + // vertex array object, because the buffers are allocated in init and when the + // buffers are shared, we need to ensure that they are allocated before trying to use thems + synchronized (this) { + if (initializationCounter != 2) { + return; + } + } + + GL2 gl2 = drawable.getGL().getGL2(); + GLU glu = new GLU(); + + // Clear the drawing area + gl2.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); + + gl2.glViewport(0, 0, canvasWidth, canvasHeight); + gl2.glMatrixMode(GL2.GL_PROJECTION); + gl2.glLoadIdentity(); + glu.gluPerspective(viewFovDegrees, (float)canvasWidth/(float)canvasHeight, + viewDistance*viewDistanceFactor-boundsRadius, viewDistance*viewDistanceFactor+boundsRadius); + + // Reset the current matrix to the "identity" + gl2.glMatrixMode(GL2.GL_MODELVIEW); + gl2.glLoadIdentity(); + + // draw the scene + gl2.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS); + gl2.glPushMatrix(); + + glu.gluLookAt(0, 0, 0 + viewDistance*viewDistanceFactor, 0, 0, 0, 0, 1, 0); + gl2.glRotatef(xAxisRotation, 1, 0, 0); + gl2.glRotatef(yAxisRotation, 0, 1, 0); + + gl2.glDisable(GL2.GL_CULL_FACE); + gl2.glEnable(GL2.GL_DEPTH_TEST); + + // draw the triangles + drawTwoTriangles(gl2); + + gl2.glPopMatrix(); + gl2.glPopAttrib(); + + // Flush all drawing operations to the graphics card + gl2.glFlush(); + + logAnyErrorCodes(gl2, "display"); + } + + public void drawTwoTriangles(GL2 gl2) { + + // draw a red triangle the old fashioned way + gl2.glColor3f(1f, 0f, 0f); + gl2.glBegin(GL2.GL_TRIANGLES); + gl2.glVertex3d(-1.5, -0.5, 0); + gl2.glNormal3d(0, 0, 1); + gl2.glVertex3d(-0.5, -0.5, 0); + gl2.glNormal3d(0, 0, 1); + gl2.glVertex3d(-0.75, 0.5, 0); + gl2.glNormal3d(0, 0, 1); + gl2.glEnd(); + + // draw the blue triangle using a vertex array object, sharing the vertex and index buffer objects across + // contexts; if context sharing is not initialized, then one window will simply have to live without a blue triangle + // + // synchronizing to deal with potential liveness issues if the data is intialized from one + // thread and used on another + boolean vaoBound = false; + // use either the shared or private vertex buffers, as + int [] vertexBufferObjects; + int [] indexBufferObjects; + synchronized (this) { + if (useShared) { + vertexBufferObjects = sharedVertexBufferObjects; + indexBufferObjects = sharedIndexBufferObjects; + } else { + vertexBufferObjects = privateVertexBufferObjects; + indexBufferObjects = privateIndexBufferObjects; + } + } // synchronized (this) + + // A check in the case that buffer sharing is enabled but context sharing is not enabled -- in that + // case, the buffer objects are not shareable, and the blue triangle cannot be rendereds. + // Furthermore, although the calls to bind and draw elements do not cause an error from glGetError + // when this check is removed, true blue triangle is not rendered anyways, and more importantly, + // I found that with my system glDrawElements causes a runtime exception 50% of the time. Executing the binds + // to unshareable buffers sets up glDrawElements for unpredictable crashes -- sometimes it does, sometimes not. + if (gl2.glIsVertexArray(vertexArrayObjects[0]) && + gl2.glIsBuffer(indexBufferObjects[0]) && gl2.glIsBuffer(vertexBufferObjects[0])) { + gl2.glBindVertexArray(vertexArrayObjects[0]); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indexBufferObjects[0]); + vaoBound = true; + } + + logAnyErrorCodes(gl2, "drawTwoTriangles"); + + if (vaoBound) { + gl2.glColor3f(0f, 0f, 1f); + gl2.glDrawElements(GL2.GL_TRIANGLES, 3, GL2.GL_UNSIGNED_INT, 0); + gl2.glBindVertexArray(0); + gl2.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, 0); + } + } + + public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { + } + + } // inner class TwoTriangles + + public static void logAnyErrorCodes(GL2 gl2, String prefix) { + int glError = gl2.glGetError(); + while (glError != GL2.GL_NO_ERROR) { + System.err.println(prefix + ", OpenGL error: 0x" + Integer.toHexString(glError)); + glError = gl2.glGetError(); + } + int status = gl2.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER); + if (status != GL2.GL_FRAMEBUFFER_COMPLETE) { + System.err.println(prefix + ", glCheckFramebufferStatus: 0x" + Integer.toHexString(status)); + } + } + + /** + * Sets the OpenGL projection matrix and front and back clipping planes for + * a viewport and returns the distance the camera should be placed from + * the center of the scene's bounding sphere such that the geometry is + * centered in the view frustum. + * + * @param gl2 current OpenGL context + * @param width width of GLDrawable + * @param height height of GLDrawable + * @param boundsRadius radius of a minimal bounding sphere of objects to be + * rendered in the viewport + * @param zoomFactor affects how far away the camera is placed from the scene; changing the + * zoom from 1.0 to 0.5 would make the scene appear half the size + * @param viewFovDegrees the desired field of vision for the viewport, + * higher is more fish-eye + * @return the distance the camera should be from the center of the scenes + * bounding sphere + */ + public static float setupViewFrustum(GL2 gl2, int width, int height, float boundsRadius, float zoomFactor, float viewFovDegrees) { + assert boundsRadius > 0.0f; + assert zoomFactor > 0.0f; + assert viewFovDegrees > 0.0f; + + GLU glu = new GLU(); + + final float aspectRatio = (float) width / (float) height; + final float boundRadiusAdjusted = boundsRadius / zoomFactor; + final float lowestFov = aspectRatio > 1.0f ? viewFovDegrees : aspectRatio * viewFovDegrees; + final float viewDist = (float) (boundRadiusAdjusted / Math.sin( (lowestFov / 2.0) * (Math.PI / 180.0) )); + + gl2.glMatrixMode(GL2.GL_PROJECTION); + gl2.glLoadIdentity(); + glu.gluPerspective(viewFovDegrees, aspectRatio, 0.1*viewDist, viewDist + boundRadiusAdjusted); + + return viewDist; + } + + @Test + public void testContextSharingCreateVisibleDestroy1() throws InterruptedException, InvocationTargetException { + testContextSharingCreateVisibleDestroy(false, false); + } + + @Test + public void testContextSharingCreateVisibleDestroy2() throws InterruptedException, InvocationTargetException { + testContextSharingCreateVisibleDestroy(false, true); + } + + @Test + public void testContextSharingCreateVisibleDestroy3() throws InterruptedException, InvocationTargetException { + testContextSharingCreateVisibleDestroy(true, false); + } + + @Test + public void testContextSharingCreateVisibleDestroy4() throws InterruptedException, InvocationTargetException { + testContextSharingCreateVisibleDestroy(true, true); + } + + /** + * Assemble the user interface and start the animator. + * It waits until the window is closed an then attempts orderly shutdown and resource deallocation. + */ + public void testContextSharingCreateVisibleDestroy(final boolean useNewt, final boolean shareContext) throws InterruptedException, InvocationTargetException { + final JFrame frame = new JFrame("Simple JOGL App for testing context sharing"); + // + // GLDrawableFactory factory = GLDrawableFactory.getFactory(GLProfile.get(GLProfile.GL2)); + // GLContext sharedContext = factory.getOrCreateSharedContext(factory.getDefaultDevice()); + // + GLCapabilities glCapabilities = new GLCapabilities(GLProfile.get(GLProfile.GL2)); + glCapabilities.setSampleBuffers(true); + glCapabilities.setNumSamples(4); + + final GLPbuffer sharedDrawable; + final GLContext sharedContext; + if(shareContext) { + sharedDrawable = initShared(glCapabilities); + sharedContext = sharedDrawable.getContext(); + } else { + sharedDrawable = null; + sharedContext = null; + } + + final TwoTriangles eventListener1 = new TwoTriangles(640, 480, shareContext); + final TwoTriangles eventListener2 = new TwoTriangles(320, 480, shareContext); + + final Component openGLComponent1; + final Component openGLComponent2; + final GLAutoDrawable openGLAutoDrawable1; + final GLAutoDrawable openGLAutoDrawable2; + + if (useNewt) { + GLWindow glWindow1 = GLWindow.create(glCapabilities); + glWindow1.setSharedContext(sharedContext); + NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setPreferredSize(new Dimension(eventListener1.canvasWidth, eventListener1.canvasHeight)); + glWindow1.addGLEventListener(eventListener1); + // + GLWindow glWindow2 = GLWindow.create(glCapabilities); + NewtCanvasAWT newtCanvasAWT2 = new NewtCanvasAWT(glWindow2); + newtCanvasAWT2.setPreferredSize(new Dimension(eventListener2.canvasWidth, eventListener2.canvasHeight)); + glWindow2.addGLEventListener(eventListener2); + + openGLComponent1 = newtCanvasAWT1; + openGLComponent2 = newtCanvasAWT2; + openGLAutoDrawable1 = glWindow1; + openGLAutoDrawable2 = glWindow2; + } else { + // Implementation using two GLCanvas instances; for GLCanvas context sharing to work, you must pass it in + // through the constructor; if you set it after it has no effect -- it does no harm if you initialized the ctor + // with the shared context, but if you didn't, it also doesn't trigger sharing + final GLCanvas canvas1; + final GLCanvas canvas2; + + if (shareContext) { + canvas1 = new GLCanvas(glCapabilities, sharedContext); + canvas2 = new GLCanvas(glCapabilities, sharedContext); + } else { + canvas1 = new GLCanvas(glCapabilities); + canvas2 = new GLCanvas(glCapabilities); + } + + canvas1.setSize(eventListener1.canvasWidth, eventListener1.canvasHeight); + canvas1.addGLEventListener(eventListener1); + // + canvas2.setSize(eventListener2.canvasWidth, eventListener2.canvasHeight); + canvas2.addGLEventListener(eventListener2); + + openGLComponent1 = canvas1; + openGLComponent2 = canvas2; + openGLAutoDrawable1 = canvas1; + openGLAutoDrawable2 = canvas2; + } + + // Create slider for x rotation. + // The vertically oriented slider rotates around the x axis + final JSlider xAxisRotationSlider = new JSlider(JSlider.VERTICAL, -180, 180, 1); + xAxisRotationSlider.setPaintTicks(false); + xAxisRotationSlider.setPaintLabels(false); + xAxisRotationSlider.setSnapToTicks(false); + xAxisRotationSlider.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + eventListener1.setXAxisRotation(xAxisRotationSlider.getValue()); + eventListener2.setXAxisRotation(xAxisRotationSlider.getValue()); + } + }); + JLabel xAxisRotationLabel = new JLabel("X-Axis Rotation"); + + // Create slider for y rotation. + // The horizontally oriented slider rotates around the y axis + final JSlider yAxisRotationSlider = new JSlider(JSlider.HORIZONTAL, -180, 180, 1); + yAxisRotationSlider.setPaintTicks(false); + yAxisRotationSlider.setPaintLabels(false); + yAxisRotationSlider.setSnapToTicks(false); + yAxisRotationSlider.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + eventListener1.setYAxisRotation(yAxisRotationSlider.getValue()); + eventListener2.setYAxisRotation(yAxisRotationSlider.getValue()); + } + }); + JLabel yAxisRotationLabel = new JLabel("Y-Axis Rotation"); + + // Create slider for view distance factor. + // We want a range of 0.0 to 10.0 with 0.1 increments (so we can scale down using 0.0 to 1.0). + // So, set JSlider to 0 to 100 and divide by 10.0 in stateChanged + final JSlider viewDistanceFactorSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, 10); + viewDistanceFactorSlider.setPaintTicks(false); + viewDistanceFactorSlider.setPaintLabels(false); + viewDistanceFactorSlider.setSnapToTicks(false); + viewDistanceFactorSlider.addChangeListener(new ChangeListener() { + + public void stateChanged(ChangeEvent e) { + eventListener1.setViewDistanceFactor((float) viewDistanceFactorSlider.getValue() / 10.0f); + eventListener2.setViewDistanceFactor((float) viewDistanceFactorSlider.getValue() / 10.0f); + } + }); + JLabel viewDistanceFactorLabel = new JLabel("View Distance Factor"); + + // group the view distance and label into a vertical panel + JPanel viewDistancePanel = new JPanel(); + viewDistancePanel.setLayout(new BoxLayout(viewDistancePanel, BoxLayout.PAGE_AXIS)); + viewDistancePanel.add(Box.createVerticalGlue()); + viewDistancePanel.add(viewDistanceFactorSlider); + viewDistancePanel.add(viewDistanceFactorLabel); + viewDistancePanel.add(Box.createVerticalGlue()); + + // group both OpenGL canvases / windows into a horizontal panel + JPanel openGLPanel = new JPanel(); + openGLPanel.setLayout(new BoxLayout(openGLPanel, BoxLayout.LINE_AXIS)); + openGLPanel.add(openGLComponent1); + openGLPanel.add(Box.createHorizontalStrut(5)); + openGLPanel.add(openGLComponent2); + + // group the open GL panel and the y-axis rotation slider into a vertical panel. + JPanel canvasAndYAxisPanel = new JPanel(); + canvasAndYAxisPanel.setLayout(new BoxLayout(canvasAndYAxisPanel, BoxLayout.PAGE_AXIS)); + canvasAndYAxisPanel.add(openGLPanel); + canvasAndYAxisPanel.add(Box.createVerticalGlue()); + canvasAndYAxisPanel.add(yAxisRotationSlider); + canvasAndYAxisPanel.add(yAxisRotationLabel); + + // group the X-axis rotation slider and label into a horizontal panel. + JPanel xAxisPanel = new JPanel(); + xAxisPanel.setLayout(new BoxLayout(xAxisPanel, BoxLayout.LINE_AXIS)); + xAxisPanel.add(xAxisRotationSlider); + xAxisPanel.add(xAxisRotationLabel); + + JPanel mainPanel = (JPanel) frame.getContentPane(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS)); + mainPanel.add(viewDistancePanel); + mainPanel.add(Box.createHorizontalGlue()); + mainPanel.add(canvasAndYAxisPanel); + mainPanel.add(Box.createHorizontalGlue()); + mainPanel.add(xAxisPanel); + + final Animator animator = new Animator(Thread.currentThread().getThreadGroup()); + animator.setUpdateFPSFrames(1, null); + animator.add(openGLAutoDrawable1); + animator.add(openGLAutoDrawable2); + + final Semaphore windowOpenSemaphore = new Semaphore(0); + final Semaphore closingSemaphore = new Semaphore(0); + + // signal the main thread when the frame is closed + frame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + closingSemaphore.release(); + } + }); + + // make the window visible using the EDT + SwingUtilities.invokeLater( new Runnable() { + public void run() { + frame.pack(); + frame.setVisible(true); + windowOpenSemaphore.release(); + } + }); + + // wait for the window to be visible and start the animation + try { + boolean windowOpened = windowOpenSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, windowOpened); + } catch (InterruptedException e) { + System.err.println("Closing wait interrupted: " + e.getMessage()); + } + animator.start(); + + // sleep for test duration, then request the window to close, wait for the window to close,s and stop the animation + try { + while(animator.isAnimating() && animator.getTotalFPSDuration() < durationPerTest) { + Thread.sleep(100); + } + AWTRobotUtil.closeWindow(frame, true); + boolean windowClosed = closingSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, windowClosed); + } catch (InterruptedException e) { + System.err.println("Closing wait interrupted: " + e.getMessage()); + } + animator.stop(); + + // ask the EDT to dispose of the frame; + // if using newt, explicitly dispose of the canvases because otherwise it seems our destroy methods are not called + SwingUtilities.invokeLater( new Runnable() { + public void run() { + frame.setVisible(false); + frame.dispose(); + if (useNewt) { + ((NewtCanvasAWT)openGLComponent1).destroy(); + ((NewtCanvasAWT)openGLComponent2).destroy(); + } + closingSemaphore.release(); + } + }); + + // wait for orderly destruction; it seems that if we share a GLContext across newt windows, bad things happen; + // I must be doing something wrong but I haven't figured it out yet + try { + boolean windowsDisposed = closingSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS); + Assert.assertEquals(true, windowsDisposed); + } catch (InterruptedException e) { + System.err.println("Closing wait interrupted: " + e.getMessage()); + } + + // ensure that the two OpenGL canvas' destroy methods completed successfully and released resources before we move on + int disposalSuccesses = 0; + try { + boolean acquired; + acquired = disposalCompleteSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS); + if (acquired){ + disposalSuccesses++; + } + acquired = disposalCompleteSemaphore.tryAcquire(5000, TimeUnit.MILLISECONDS); + if (acquired){ + disposalSuccesses++; + } + } catch (InterruptedException e) { + System.err.println("Clean exit interrupted: " + e.getMessage()); + } + + Assert.assertEquals(true, disposalSuccesses == 2); + + releaseShared(sharedDrawable); + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String[] args) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + if (++i < args.length) { + durationPerTest = atoi(args[i]); + } + } + } + + String testname = TestSharedContextNewtAWTBug523.class.getName(); + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + testname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+testname+".xml" } ); + } + +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES1NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES1NEWT.java index 5d76702ea..6e48e44fe 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES1NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES1NEWT.java @@ -54,7 +54,6 @@ public class TestSharedContextVBOES1NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT.java index dd3e1f347..022ef2142 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT.java @@ -54,7 +54,6 @@ public class TestSharedContextVBOES2NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java new file mode 100644 index 000000000..5b2cb25b3 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextVBOES2NEWT2.java @@ -0,0 +1,157 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.IOException; + +import com.jogamp.newt.opengl.GLWindow; + +import javax.media.nativewindow.util.InsetsImmutable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import com.jogamp.opengl.util.Animator; + +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestSharedContextVBOES2NEWT2 extends UITestCase { + static GLProfile glp; + static GLCapabilities caps; + static int width, height; + GLWindow sharedDrawable; + GearsES2 sharedGears; + + @BeforeClass + public static void initClass() { + glp = GLProfile.get(GLProfile.GL2); + Assert.assertNotNull(glp); + caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + width = 256; + height = 256; + } + + private void initShared() { + sharedDrawable = GLWindow.create(caps); + Assert.assertNotNull(sharedDrawable); + // sharedGears = new Gears(0); + sharedGears = new GearsES2(0); + Assert.assertNotNull(sharedGears); + sharedDrawable.addGLEventListener(sharedGears); + sharedDrawable.setSize(width, height); + sharedDrawable.setVisible(true); + // init and render one frame, which will setup the Gears display lists + sharedDrawable.display(); + } + + private void releaseShared() { + Assert.assertNotNull(sharedDrawable); + sharedDrawable.destroy(); + sharedDrawable = null; + } + + protected GLWindow runTestGL(Animator animator, int x, int y, boolean useShared, boolean vsync) throws InterruptedException { + GLWindow glWindow = GLWindow.create(caps); + + Assert.assertNotNull(glWindow); + glWindow.setTitle("Shared Gears NEWT Test: "+x+"/"+y+" shared "+useShared); + if(useShared) { + glWindow.setSharedContext(sharedDrawable.getContext()); + } + + glWindow.setSize(width, height); + + GearsES2 gears = new GearsES2(vsync ? 1 : 0); + if(useShared) { + gears.setGears(sharedGears.getGear1(), sharedGears.getGear2(), sharedGears.getGear3()); + } + glWindow.addGLEventListener(gears); + + animator.add(glWindow); + animator.start(); + glWindow.setVisible(true); + + Assert.assertTrue(AWTRobotUtil.waitForRealized(glWindow, true)); + Assert.assertTrue(AWTRobotUtil.waitForVisible(glWindow, true)); + glWindow.setPosition(x, y); + + return glWindow; + } + + @Test + public void test01() throws InterruptedException { + initShared(); + GLWindow f1 = runTestGL(new Animator(), 0, 0, true, false); + InsetsImmutable insets = f1.getInsets(); + GLWindow f2 = runTestGL(new Animator(), f1.getX()+width+insets.getTotalWidth(), + f1.getY()+0, true, false); + GLWindow f3 = runTestGL(new Animator(), f1.getX()+0, + f1.getY()+height+insets.getTotalHeight(), true, false); + + try { + Thread.sleep(duration); + } catch(Exception e) { + e.printStackTrace(); + } + + // here we go again: On AMD/X11 the create/destroy sequence must be the same + // even though this is against the chicken/egg logic here .. + releaseShared(); + + f1.destroy(); + f2.destroy(); + f3.destroy(); + + // see above .. + // releaseShared(); + } + + static long duration = 2000; // ms + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + /** + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + System.err.println(stdin.readLine()); */ + org.junit.runner.JUnitCore.main(TestSharedContextVBOES2NEWT2.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteAWT.java new file mode 100644 index 000000000..322ce36c4 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteAWT.java @@ -0,0 +1,125 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.awt.Frame; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestShutdownCompleteAWT extends UITestCase { + + static long duration = 300; // ms + + protected void runTestGL() throws InterruptedException, InvocationTargetException { + final Frame frame = new Frame("Gears AWT Test"); + Assert.assertNotNull(frame); + + final GLCanvas glCanvas = new GLCanvas(new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glCanvas); + frame.add(glCanvas); + frame.setSize(256, 256); + + glCanvas.addGLEventListener(new Gears(1)); + + Animator animator = new Animator(glCanvas); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); + + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glCanvas.isVisible()); + Assert.assertEquals(true, glCanvas.isDisplayable()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + Assert.assertEquals(true, glCanvas.isRealized()); + + animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); + frame.setVisible(false); + Assert.assertEquals(false, frame.isVisible()); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.remove(glCanvas); + frame.dispose(); + }}); + } + + protected void oneLife() throws InterruptedException, InvocationTargetException { + long t0 = System.nanoTime(); + GLProfile.initSingleton(); + long t1 = System.nanoTime(); + runTestGL(); + long t2 = System.nanoTime(); + GLProfile.shutdown(GLProfile.ShutdownType.COMPLETE); + long t3 = System.nanoTime(); + System.err.println("Total: "+ (t3-t0)/1e6 +"ms"); + System.err.println(" GLProfile.initSingleton(): "+ (t1-t0)/1e6 +"ms"); + System.err.println(" Demo Code: "+ (t2-t1)/1e6 +"ms"); + System.err.println(" GLProfile.shutdown(COMPLETE): "+ (t3-t2)/1e6 +"ms"); + } + + @Test + public void test01OneLife() throws InterruptedException, InvocationTargetException { + oneLife(); + } + + @Test + public void test01AnotherLife() throws InterruptedException, InvocationTargetException { + oneLife(); + } + + @Test + public void test01TwoLifes() throws InterruptedException, InvocationTargetException { + oneLife(); + oneLife(); + } + + public static void main(String args[]) throws IOException { + String tstname = TestShutdownCompleteAWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteNEWT.java new file mode 100644 index 000000000..1abac1094 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownCompleteNEWT.java @@ -0,0 +1,144 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestShutdownCompleteNEWT extends UITestCase { + + static long duration = 300; // ms + + protected void runTestGL() throws InterruptedException { + GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glWindow); + glWindow.setTitle("Gears NEWT Test"); + + glWindow.addGLEventListener(new Gears()); + + Animator animator = new Animator(glWindow); + + glWindow.setSize(256, 256); + glWindow.setVisible(true); + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeValid()); + Assert.assertEquals(true, glWindow.isRealized()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + + animator.stop(); + glWindow.destroy(); + } + + protected void oneLife() throws InterruptedException { + if(waitForEach) { + waitForEnter(); + } + long t0 = System.nanoTime(); + GLProfile.initSingleton(); + long t1 = System.nanoTime(); + if(!initOnly) { + runTestGL(); + } + long t2 = System.nanoTime(); + GLProfile.shutdown(GLProfile.ShutdownType.COMPLETE); + long t3 = System.nanoTime(); + System.err.println("Total: "+ (t3-t0)/1e6 +"ms"); + System.err.println(" GLProfile.initSingleton(): "+ (t1-t0)/1e6 +"ms"); + System.err.println(" Demo Code: "+ (t2-t1)/1e6 +"ms"); + System.err.println(" GLProfile.shutdown(COMPLETE): "+ (t3-t2)/1e6 +"ms"); + } + + @Test + public void test01OneLife() throws InterruptedException { + oneLife(); + } + + @Test + public void test01AnotherLife() throws InterruptedException { + oneLife(); + } + + @Test + public void test01TwoLifes() throws InterruptedException { + oneLife(); + oneLife(); + } + + static boolean initOnly = false; + static boolean waitForEach = false; + + static void waitForEnter() { + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (IOException e) { } + } + + public static void main(String args[]) throws IOException { + boolean waitForKey = false; + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-wait")) { + waitForKey = true; + } else if(args[i].equals("-waitForEach")) { + waitForEach = true; + waitForKey = true; + } else if(args[i].equals("-initOnly")) { + initOnly = true; + } + } + + if(waitForKey) { + waitForEnter(); + } + + String tstname = TestShutdownCompleteNEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedAWT.java new file mode 100644 index 000000000..a12ef2327 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedAWT.java @@ -0,0 +1,124 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.awt.Frame; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestShutdownSharedAWT extends UITestCase { + + static long duration = 300; // ms + + protected void runTestGL() throws InterruptedException, InvocationTargetException { + final Frame frame = new Frame("Gears AWT Test"); + Assert.assertNotNull(frame); + + final GLCanvas glCanvas = new GLCanvas(new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glCanvas); + frame.add(glCanvas); + frame.setSize(256, 256); + + glCanvas.addGLEventListener(new Gears(1)); + + Animator animator = new Animator(glCanvas); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glCanvas.isVisible()); + Assert.assertEquals(true, glCanvas.isDisplayable()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + Assert.assertEquals(true, glCanvas.isRealized()); + + animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); + frame.setVisible(false); + Assert.assertEquals(false, frame.isVisible()); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.remove(glCanvas); + frame.dispose(); + }}); + } + + protected void oneLife() throws InterruptedException, InvocationTargetException { + long t0 = System.nanoTime(); + GLProfile.initSingleton(); + long t1 = System.nanoTime(); + runTestGL(); + long t2 = System.nanoTime(); + GLProfile.shutdown(GLProfile.ShutdownType.SHARED_ONLY); + long t3 = System.nanoTime(); + System.err.println("Total: "+ (t3-t0)/1e6 +"ms"); + System.err.println(" GLProfile.initSingleton(): "+ (t1-t0)/1e6 +"ms"); + System.err.println(" Demo Code: "+ (t2-t1)/1e6 +"ms"); + System.err.println(" GLProfile.shutdown(SHARED): "+ (t3-t2)/1e6 +"ms"); + } + + @Test + public void test01OneLife() throws InterruptedException, InvocationTargetException { + oneLife(); + } + + @Test + public void test01AnotherLife() throws InterruptedException, InvocationTargetException { + oneLife(); + } + + @Test + public void test01TwoLifes() throws InterruptedException, InvocationTargetException { + oneLife(); + oneLife(); + } + + public static void main(String args[]) throws IOException { + String tstname = TestShutdownSharedAWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedNEWT.java new file mode 100644 index 000000000..99b5a6c48 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestShutdownSharedNEWT.java @@ -0,0 +1,127 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.acore; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Test; + +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestShutdownSharedNEWT extends UITestCase { + + static long duration = 300; // ms + + protected void runTestGL() throws InterruptedException { + GLWindow glWindow = GLWindow.create(new GLCapabilities(GLProfile.getDefault())); + Assert.assertNotNull(glWindow); + glWindow.setTitle("Gears NEWT Test"); + + glWindow.addGLEventListener(new Gears()); + + Animator animator = new Animator(glWindow); + + glWindow.setSize(256, 256); + glWindow.setVisible(true); + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + Assert.assertEquals(true, animator.isAnimating()); + Assert.assertEquals(true, glWindow.isVisible()); + Assert.assertEquals(true, glWindow.isNativeValid()); + Assert.assertEquals(true, glWindow.isRealized()); + + while(animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + + animator.stop(); + glWindow.destroy(); + } + + protected void oneLife() throws InterruptedException { + long t0 = System.nanoTime(); + GLProfile.initSingleton(); + long t1 = System.nanoTime(); + runTestGL(); + long t2 = System.nanoTime(); + GLProfile.shutdown(GLProfile.ShutdownType.SHARED_ONLY); + long t3 = System.nanoTime(); + System.err.println("Total: "+ (t3-t0)/1e6 +"ms"); + System.err.println(" GLProfile.initSingleton(): "+ (t1-t0)/1e6 +"ms"); + System.err.println(" Demo Code: "+ (t2-t1)/1e6 +"ms"); + System.err.println(" GLProfile.shutdown(SHARED): "+ (t3-t2)/1e6 +"ms"); + } + + @Test + public void test01OneLife() throws InterruptedException { + oneLife(); + } + + @Test + public void test01AnotherLife() throws InterruptedException { + oneLife(); + } + + @Test + public void test01TwoLifes() throws InterruptedException { + oneLife(); + oneLife(); + } + + public static void main(String args[]) throws IOException { + boolean waitForKey = false; + + for(int i=0; i<args.length; i++) { + if(args[i].equals("-wait")) { + waitForKey = true; + } + } + + if(waitForKey) { + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (IOException e) { } + } + + String tstname = TestShutdownSharedNEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestAWTCardLayoutAnimatorStartStopBug532.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestAWTCardLayoutAnimatorStartStopBug532.java new file mode 100644 index 000000000..5415ad159 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestAWTCardLayoutAnimatorStartStopBug532.java @@ -0,0 +1,229 @@ +package com.jogamp.opengl.test.junit.jogl.awt; + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Dimension; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.media.nativewindow.NativeWindow; +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLProfile; +import javax.media.opengl.awt.GLCanvas; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import jogamp.nativewindow.windows.GDI; + +import org.junit.Test; + +import com.jogamp.common.os.Platform; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.FPSAnimator; + +public class TestAWTCardLayoutAnimatorStartStopBug532 extends UITestCase { + static final String LABEL = "Label"; + static final String CANVAS = "GLCanvas"; + + public enum AnimatorControlBehavior { + StartStop, PauseResume, Continue; + } + + static long durationPerTest = 200*4; // ms + static boolean manual = false; + static volatile boolean shouldStop = false; + + private String selected = LABEL; + + @Test + public void testFPSAnimatorStartStop() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.StartStop, true); + } + + @Test + public void testFPSAnimatorResumePause() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.PauseResume, true); + } + + @Test + public void testFPSAnimatorContinue() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.Continue, true); + } + + @Test + public void testAnimatorStartStop() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.StartStop, false); + } + + @Test + public void testAnimatorResumePause() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.PauseResume, false); + } + + @Test + public void testAnimatorContinue() throws InterruptedException, InvocationTargetException { + testImpl(AnimatorControlBehavior.Continue, false); + } + + void testImpl(final AnimatorControlBehavior animCtrl, boolean useFPSAnimator) throws InterruptedException, InvocationTargetException { + final GLProfile glp = GLProfile.get(GLProfile.GL2); + final GLCapabilities caps = new GLCapabilities(glp); + final GLCanvas canvas = new GLCanvas(caps); + canvas.setPreferredSize(new Dimension(640, 480)); + + final GLAnimatorControl animatorCtrl = useFPSAnimator ? new FPSAnimator(canvas, 60) : new Animator(canvas); + animatorCtrl.setUpdateFPSFrames(60, System.err); + switch (animCtrl) { + case PauseResume: + animatorCtrl.start(); + animatorCtrl.pause(); + break; + case Continue: + animatorCtrl.start(); + break; + } + + canvas.addGLEventListener(new GearsES2(1)); + /* if(Platform.OS_TYPE == Platform.OSType.WINDOWS) { + canvas.addGLEventListener(new GLEventListener() { + public void init(GLAutoDrawable drawable) { } + public void dispose(GLAutoDrawable drawable) { } + public void display(GLAutoDrawable drawable) { + final NativeWindow win = (NativeWindow) drawable.getNativeSurface(); + long hdc = win.getSurfaceHandle(); + long hdw = win.getWindowHandle(); + long hdw_hdc = GDI.WindowFromDC(hdc); + System.err.println("*** hdc 0x"+Long.toHexString(hdc)+", hdw(hdc) 0x"+Long.toHexString(hdw_hdc)+", hdw 0x"+Long.toHexString(hdw) + " - " + Thread.currentThread().getName() + ", " + animatorCtrl); + // System.err.println(drawable.getNativeSurface().toString()); + } + public void reshape(GLAutoDrawable drawable, int x, int y, int width, + int height) { } + }); + } */ + + final JFrame frame = new JFrame(); + frame.setTitle(getSimpleTestName()); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + animatorCtrl.stop(); + shouldStop = true; + } + }); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + final JPanel cards = new JPanel(new CardLayout()); + final JPanel comboBoxPanel = new JPanel(); // nicer look .. + final JComboBox comboBox = new JComboBox(new String[] { LABEL, CANVAS }); + comboBox.setEditable(false); + comboBox.addItemListener(new ItemListener() { + public void itemStateChanged(final ItemEvent evt) { + final CardLayout cl = (CardLayout)(cards.getLayout()); + final String newSelection = (String)evt.getItem(); + if(!newSelection.equals(selected)) { + final String oldSelected = selected; + if(newSelection.equals(CANVAS)) { + cl.show(cards, CANVAS); + switch (animCtrl) { + case StartStop: + animatorCtrl.start(); + break; + case PauseResume: + animatorCtrl.resume(); + break; + } + selected = CANVAS; + } else if(newSelection.equals(LABEL)) { + switch (animCtrl) { + case StartStop: + animatorCtrl.stop(); + break; + case PauseResume: + animatorCtrl.pause(); + break; + } + cl.show(cards, LABEL); + selected = LABEL; + } else { + throw new RuntimeException("oops .. unexpected item: "+evt); + } + System.err.println("Item Change: "+oldSelected+" -> "+selected+", "+animatorCtrl); + } else { + System.err.println("Item Stays: "+selected+", "+animatorCtrl); + } + } + }); + comboBoxPanel.add(comboBox); + + cards.add(new JLabel("A label to cover the canvas"), LABEL); + cards.add(canvas, CANVAS); + + frame.add(comboBoxPanel, BorderLayout.PAGE_START); + frame.add(cards, BorderLayout.CENTER); + + frame.pack(); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); + + if(manual) { + for(long w=durationPerTest; !shouldStop && w>0; w-=100) { + Thread.sleep(100); + } + } else { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + comboBox.setSelectedItem(LABEL); + }}); + Thread.sleep(durationPerTest/4); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + comboBox.setSelectedItem(CANVAS); + }}); + Thread.sleep(durationPerTest/4); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + comboBox.setSelectedItem(LABEL); + }}); + Thread.sleep(durationPerTest/4); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + comboBox.setSelectedItem(CANVAS); + }}); + Thread.sleep(durationPerTest/4); + } + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(false); + frame.dispose(); + }}); + + } + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = MiscUtils.atoi(args[++i], (int)durationPerTest); + } else if(args[i].equals("-manual")) { + manual = true; + } + } + org.junit.runner.JUnitCore.main(TestAWTCardLayoutAnimatorStartStopBug532.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461OffscreenSupersamplingSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461OffscreenSupersamplingSwingAWT.java index 55c9c6812..284122be3 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461OffscreenSupersamplingSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/awt/TestBug461OffscreenSupersamplingSwingAWT.java @@ -30,35 +30,9 @@ package com.jogamp.opengl.test.junit.jogl.awt; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -/** - * Copyright 2011 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions 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. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; import javax.media.opengl.GL; import javax.media.opengl.GL2; @@ -123,12 +97,19 @@ public class TestBug461OffscreenSupersamplingSwingAWT extends UITestCase impleme /* @Override */ public void dispose(GLAutoDrawable drawable) { - jframe.setVisible(false); - jframe.dispose(); + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jframe.setVisible(false); + jframe.dispose(); + }}); + } catch (Exception e) { + e.printStackTrace(); + } } @Test - public void testOffscreenSupersampling() { + public void testOffscreenSupersampling() throws InterruptedException, InvocationTargetException { jframe = new JFrame("Offscreen Supersampling"); Assert.assertNotNull(jframe); jframe.setSize( 300, 300); @@ -163,7 +144,10 @@ public class TestBug461OffscreenSupersamplingSwingAWT extends UITestCase impleme Assert.assertNotNull(offScreenBuffer); offScreenBuffer.addGLEventListener(this); offScreenBuffer.display(); - jframe.setVisible( true ); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jframe.setVisible(true); + }}); } public static void main(String args[]) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/caps/MultisampleDemo01.java b/src/test/com/jogamp/opengl/test/junit/jogl/caps/MultisampleDemo01.java index b41501a9b..ab0171cb8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/caps/MultisampleDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/caps/MultisampleDemo01.java @@ -63,7 +63,7 @@ class MultisampleDemo01 implements GLEventListener { } public void init(GLAutoDrawable drawable) { - AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration(); System.err.println(); System.err.println("Info: " + config); System.err.println(); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyAWT.java index e22163847..8e720965c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyAWT.java @@ -51,6 +51,7 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.common.util.ReflectionUtil; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.Animator; @@ -80,8 +81,15 @@ public class TestTranslucencyAWT extends UITestCase { boolean capable1 = ( null != tcm ) ? tcm.getTransparency() == Transparency.TRANSLUCENT : false; boolean capable2 = false; try { - capable2 = com.sun.awt.AWTUtilities.isTranslucencyCapable(config); - } catch (Exception e) {} + capable2 = ((Boolean)ReflectionUtil.callStaticMethod( + "com.sun.awt.AWTUtilities", "isTranslucencyCapable", + new Class<?>[] { GraphicsConfiguration.class }, + new Object[] { config } , + GraphicsConfiguration.class.getClassLoader())).booleanValue(); + System.err.println("com.sun.awt.AWTUtilities.isTranslucencyCapable(config) passed: "+capable2); + } catch (RuntimeException re) { + System.err.println("com.sun.awt.AWTUtilities.isTranslucencyCapable(config) failed: "+re.getMessage()); + } System.err.println(i+":"+j+" "+config+", "+tcm+", capable "+capable1+"/"+capable2); if(capable1&&capable2) { gc=configs[j]; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyNEWT.java index a01cb593b..67e8524a3 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/caps/TestTranslucencyNEWT.java @@ -52,7 +52,6 @@ public class TestTranslucencyNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); /*if(GLProfile.isAvailable(GLProfile.getDefaultEGLDevice(), GLProfile.GLES2)) { // exact match glp = GLProfile.get(GLProfile.getDefaultEGLDevice(), GLProfile.GLES2); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java index 8d579ce5d..b5a729e02 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/GearsES1.java @@ -21,6 +21,7 @@ package com.jogamp.opengl.test.junit.jogl.demos.es1; +import javax.media.nativewindow.NativeWindow; import javax.media.opengl.GL; import javax.media.opengl.GL2ES1; import javax.media.opengl.GLAutoDrawable; @@ -181,8 +182,18 @@ public class GearsES1 implements GLEventListener { // Get the GL corresponding to the drawable we are animating GL2ES1 gl = drawable.getGL().getGL2ES1(); - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + final boolean hasFocus; + if(drawable.getNativeSurface() instanceof NativeWindow) { + hasFocus = ((NativeWindow)drawable.getNativeSurface()).hasFocus(); + } else { + hasFocus = true; + } + if(hasFocus) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } else { + gl.glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + } + // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java index 86f63cb2d..8b41141f1 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestGearsES1NEWT.java @@ -52,7 +52,6 @@ public class TestGearsES1NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); /* if(GLProfile.isAvailable(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1)) { // exact match glp = GLProfile.get(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestRedSquareES1NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestRedSquareES1NEWT.java index e73be50d6..13aafe48f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestRedSquareES1NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/newt/TestRedSquareES1NEWT.java @@ -52,7 +52,6 @@ public class TestRedSquareES1NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); /* if(GLProfile.isAvailable(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1)) { // exact match glp = GLProfile.get(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index 3fa61bf1d..51bc7d137 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -34,6 +34,8 @@ import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.util.glsl.ShaderState; import java.nio.FloatBuffer; + +import javax.media.nativewindow.NativeWindow; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLAutoDrawable; @@ -244,8 +246,18 @@ public class GearsES2 implements GLEventListener { // Get the GL corresponding to the drawable we are animating GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + final boolean hasFocus; + if(drawable.getNativeSurface() instanceof NativeWindow) { + hasFocus = ((NativeWindow)drawable.getNativeSurface()).hasFocus(); + } else { + hasFocus = true; + } + if(hasFocus) { + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } else { + gl.glClearColor(0.2f, 0.2f, 0.2f, 0.0f); + } + // Special handling for the case where the GLJPanel is translucent // and wants to be composited with other Java 2D content if (GLProfile.isAWTAvailable() && diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java index 01790de10..d645fb9f8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/RedSquareES2.java @@ -205,7 +205,7 @@ public class RedSquareES2 implements GLEventListener { class MyMouseAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { System.err.println(e); - if(null != glWindow && e.getSource() == glWindow.getWindow()) { + if(null != glWindow && e.getSource() == glWindow.getDelegatedWindow()) { if(e.getX() < glWindow.getWidth()/2) { glWindow.setFullscreen(!glWindow.isFullscreen()); System.err.println("setFullscreen: "+glWindow.isFullscreen()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestElektronenMultipliziererNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestElektronenMultipliziererNEWT.java index d9cee4fdf..fb6359093 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestElektronenMultipliziererNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestElektronenMultipliziererNEWT.java @@ -65,11 +65,6 @@ public class TestElektronenMultipliziererNEWT extends UITestCase { static int startFrame = 1700; static long duration = 5000; // ms - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - @AfterClass public static void releaseClass() { } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java index 18a5a5d31..faa7eb311 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java @@ -32,8 +32,13 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; import com.jogamp.newt.event.KeyAdapter; import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; @@ -42,6 +47,11 @@ import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.PointImmutable; +import javax.media.nativewindow.util.DimensionImmutable; + import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -55,11 +65,25 @@ import org.junit.Test; public class TestGearsES2NEWT extends UITestCase { static GLProfile glp; - static int width, height; + + static int screenIdx = 0; + static PointImmutable wpos; + static DimensionImmutable wsize; + static long duration = 500; // ms + static boolean opaque = true; + static boolean undecorated = false; + static boolean alwaysOnTop = false; + static boolean fullscreen = false; + static boolean pmvUseBackingArray = true; + static boolean vsync = false; + static boolean waitForKey = false; + static boolean mouseVisible = true; + static boolean mouseConfined = false; + static boolean showFPS = false; + @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); /*if(GLProfile.isAvailable(GLProfile.getDefaultEGLDevice(), GLProfile.GLES2)) { // exact match glp = GLProfile.get(GLProfile.getDefaultEGLDevice(), GLProfile.GLES2); @@ -68,10 +92,9 @@ public class TestGearsES2NEWT extends UITestCase { glp = GLProfile.getGL2ES2(); } Assert.assertNotNull(glp); - // width = 512; - // height = 512; - width = 200; - height = 200; + if(null == wsize) { + wsize = new Dimension(200, 200); + } } @AfterClass @@ -80,11 +103,15 @@ public class TestGearsES2NEWT extends UITestCase { protected void runTestGL(GLCapabilities caps, boolean undecorated) throws InterruptedException { System.err.println("requested: "+caps); - final GLWindow glWindow = GLWindow.create(caps); + Display dpy = NewtFactory.createDisplay(null); + Screen screen = NewtFactory.createScreen(dpy, screenIdx); + final GLWindow glWindow = GLWindow.create(screen, caps); Assert.assertNotNull(glWindow); - glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+")"); - glWindow.setSize(width, height); - glWindow.setPosition(100, 100); + glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), size "+wsize+", pos "+wpos); + glWindow.setSize(wsize.getWidth(), wsize.getHeight()); + if(null != wpos) { + glWindow.setPosition(wpos.getX(), wpos.getY()); + } glWindow.setUndecorated(undecorated); glWindow.setAlwaysOnTop(alwaysOnTop); glWindow.setFullscreen(fullscreen); @@ -123,6 +150,15 @@ public class TestGearsES2NEWT extends UITestCase { glWindow.addKeyListener(quitAdapter); glWindow.addWindowListener(quitAdapter); + glWindow.addWindowListener(new WindowAdapter() { + public void windowResized(WindowEvent e) { + System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()); + } + public void windowMoved(WindowEvent e) { + System.err.println("window moved: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()); + } + }); + glWindow.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { if(e.getKeyChar()=='f') { @@ -189,14 +225,14 @@ public class TestGearsES2NEWT extends UITestCase { } }); - animator.setUpdateFPSFrames(60, System.err); + animator.setUpdateFPSFrames(60, showFPS ? System.err : null); animator.start(); // glWindow.setSkipContextReleaseThread(animator.getThread()); glWindow.setVisible(true); - System.err.println("size/pos: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets()); System.err.println("chosen: "+glWindow.getChosenCapabilities()); + System.err.println("window pos/siz: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getWidth()+"x"+glWindow.getHeight()+", "+glWindow.getInsets()); while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { Thread.sleep(100); @@ -213,25 +249,22 @@ public class TestGearsES2NEWT extends UITestCase { runTestGL(caps, undecorated); } - static long duration = 500; // ms - static boolean opaque = true; - static boolean undecorated = false; - static boolean alwaysOnTop = false; - static boolean fullscreen = false; - static boolean pmvUseBackingArray = true; - static boolean vsync = false; - static boolean waitForKey = false; - static boolean mouseVisible = true; - static boolean mouseConfined = false; - + static int atoi(String a) { + try { + return Integer.parseInt(a); + } catch (Exception ex) { throw new RuntimeException(ex); } + } + public static void main(String args[]) throws IOException { + int x=0, y=0, w=200, h=200; + boolean useSize = false; + boolean usePos = false; + for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { i++; - try { - duration = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } + duration = atoi(args[i]); } else if(args[i].equals("-translucent")) { opaque = false; } else if(args[i].equals("-undecorated")) { @@ -250,8 +283,38 @@ public class TestGearsES2NEWT extends UITestCase { mouseVisible = false; } else if(args[i].equals("-mouseConfine")) { mouseConfined = true; + } else if(args[i].equals("-showFPS")) { + showFPS = true; + } else if(args[i].equals("-width")) { + i++; + w = atoi(args[i]); + useSize = true; + } else if(args[i].equals("-height")) { + i++; + h = atoi(args[i]); + useSize = true; + } else if(args[i].equals("-x")) { + i++; + x = atoi(args[i]); + usePos = true; + } else if(args[i].equals("-y")) { + i++; + y = atoi(args[i]); + usePos = true; + } else if(args[i].equals("-screen")) { + i++; + screenIdx = atoi(args[i]); } } + if(useSize) { + wsize = new Dimension(w, h); + } + if(usePos) { + wpos = new Point(x, y); + } + System.err.println("position "+wpos); + System.err.println("size "+wsize); + System.err.println("screen "+screenIdx); System.err.println("translucent "+(!opaque)); System.err.println("undecorated "+undecorated); System.err.println("atop "+alwaysOnTop); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestRedSquareES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestRedSquareES2NEWT.java index 63ec215fc..f3bad286b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestRedSquareES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestRedSquareES2NEWT.java @@ -52,7 +52,6 @@ public class TestRedSquareES2NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); /* if(GLProfile.isAvailable(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1)) { // exact match glp = GLProfile.get(GLProfile.getDefaultEGLDevice(), GLProfile.GLES1); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java index 8ab641267..f03269614 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWT.java @@ -41,6 +41,7 @@ import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; import org.junit.Assert; import org.junit.BeforeClass; @@ -50,6 +51,7 @@ import org.junit.Test; public class TestGearsAWT extends UITestCase { static GLProfile glp; static int width, height; + static boolean firstUIActionOnProcess = false; @BeforeClass public static void initClass() { @@ -63,16 +65,16 @@ public class TestGearsAWT extends UITestCase { public static void releaseClass() { } - protected void runTestGL(GLCapabilities caps) throws InterruptedException { - Frame frame = new Frame("Gears AWT Test"); + protected void runTestGL(GLCapabilities caps) throws InterruptedException, InvocationTargetException { + final Frame frame = new Frame("Gears AWT Test"); Assert.assertNotNull(frame); - GLCanvas glCanvas = new GLCanvas(caps); + final GLCanvas glCanvas = new GLCanvas(caps); Assert.assertNotNull(glCanvas); frame.add(glCanvas); frame.setSize(512, 512); - glCanvas.addGLEventListener(new Gears()); + glCanvas.addGLEventListener(new Gears(1)); Animator animator = new Animator(glCanvas); QuitAdapter quitAdapter = new QuitAdapter(); @@ -80,8 +82,11 @@ public class TestGearsAWT extends UITestCase { new AWTKeyAdapter(new TraceKeyAdapter(quitAdapter)).addTo(glCanvas); new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter)).addTo(frame); - frame.setVisible(true); - animator.setUpdateFPSFrames(1, null); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); + animator.setUpdateFPSFrames(60, System.err); animator.start(); while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { @@ -96,14 +101,15 @@ public class TestGearsAWT extends UITestCase { Assert.assertEquals(false, animator.isAnimating()); frame.setVisible(false); Assert.assertEquals(false, frame.isVisible()); - frame.remove(glCanvas); - frame.dispose(); - frame=null; - glCanvas=null; + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.remove(glCanvas); + frame.dispose(); + }}); } @Test - public void test01() throws InterruptedException { + public void test01() throws InterruptedException, InvocationTargetException { GLCapabilities caps = new GLCapabilities(glp); runTestGL(caps); } @@ -117,6 +123,8 @@ public class TestGearsAWT extends UITestCase { try { duration = Integer.parseInt(args[i]); } catch (Exception ex) { ex.printStackTrace(); } + } else if(args[i].equals("-firstUIAction")) { + firstUIActionOnProcess = true; } } org.junit.runner.JUnitCore.main(TestGearsAWT.class.getName()); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWTAnalyzeBug455.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWTAnalyzeBug455.java new file mode 100644 index 000000000..4b670f0e1 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/awt/TestGearsAWTAnalyzeBug455.java @@ -0,0 +1,171 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.jogl.demos.gl2.awt; + +import javax.media.opengl.*; + +import com.jogamp.opengl.util.Animator; +import javax.media.opengl.awt.GLCanvas; +import com.jogamp.newt.event.awt.AWTKeyAdapter; +import com.jogamp.newt.event.awt.AWTWindowAdapter; +import com.jogamp.newt.event.TraceKeyAdapter; +import com.jogamp.newt.event.TraceWindowAdapter; + +import com.jogamp.opengl.test.junit.jogl.demos.gl2.Gears; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.test.junit.util.QuitAdapter; +import java.awt.Frame; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.AfterClass; +import org.junit.Test; + +public class TestGearsAWTAnalyzeBug455 extends UITestCase { + static long duration = 500; // ms + static boolean waitForKey = false; // for manual profiling + static boolean altSwap = true; // using alternate GL swap method (copy pixel) no [auto-]swap + + static GLProfile glp; + static int width, height; + + @BeforeClass + public static void initClass() { + glp = GLProfile.getDefault(); + Assert.assertNotNull(glp); + width = 512; + height = 512; + } + + @AfterClass + public static void releaseClass() { + } + + static class Swapper implements GLEventListener { + public void init(GLAutoDrawable drawable) { + System.err.println("auto-swap: "+drawable.getAutoSwapBufferMode()); + } + public void dispose(GLAutoDrawable drawable) { + } + public void display(GLAutoDrawable drawable) { + if(!drawable.getAutoSwapBufferMode()) { + GL2 gl = drawable.getGL().getGL2(); + // copy the colored content of the back buffer into the front buffer + // gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT); + gl.glReadBuffer(GL.GL_BACK); // def. in dbl buff mode: GL_BACK + gl.glDrawBuffer(GL.GL_FRONT); // def. in dbl buff mode: GL_BACK + gl.glCopyPixels(0, 0, drawable.getWidth(), drawable.getHeight(), GL2.GL_COLOR); + // gl.glPopAttrib(); + gl.glDrawBuffer(GL.GL_BACK); // def. in dbl buff mode: GL_BACK + } + } + public void reshape(GLAutoDrawable drawable, int x, int y, int width, + int height) { + } + } + protected void runTestGL(GLCapabilities caps) throws InterruptedException, InvocationTargetException { + final Frame frame = new Frame("Gears AWT Test"); + Assert.assertNotNull(frame); + + final GLCanvas glCanvas = new GLCanvas(caps); + Assert.assertNotNull(glCanvas); + glCanvas.setAutoSwapBufferMode(!altSwap); + frame.add(glCanvas); + frame.setSize(512, 512); + + glCanvas.addGLEventListener(new Gears(0)); + glCanvas.addGLEventListener(new Swapper()); + + Animator animator = new Animator(glCanvas); + QuitAdapter quitAdapter = new QuitAdapter(); + + new AWTKeyAdapter(new TraceKeyAdapter(quitAdapter)).addTo(glCanvas); + new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter)).addTo(frame); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); + animator.setUpdateFPSFrames(60, System.err); + animator.start(); + + while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + Thread.sleep(100); + } + + Assert.assertNotNull(frame); + Assert.assertNotNull(glCanvas); + Assert.assertNotNull(animator); + + animator.stop(); + Assert.assertEquals(false, animator.isAnimating()); + frame.setVisible(false); + Assert.assertEquals(false, frame.isVisible()); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.remove(glCanvas); + frame.dispose(); + }}); + } + + @Test + public void test01() throws InterruptedException, InvocationTargetException { + GLCapabilities caps = new GLCapabilities(glp); + caps.setDoubleBuffered(true); // code assumes dbl buffer setup + runTestGL(caps); + } + + public static void main(String args[]) { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + i++; + try { + duration = Integer.parseInt(args[i]); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(args[i].equals("-wait")) { + waitForKey = true; + } else if(args[i].equals("-autoswap")) { + altSwap = false; + } + } + System.err.println("altSwap "+altSwap); + if(waitForKey) { + BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); + System.err.println("Press enter to continue"); + try { + System.err.println(stdin.readLine()); + } catch (IOException e) { } + } + org.junit.runner.JUnitCore.main(TestGearsAWTAnalyzeBug455.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java index 4b6f7999a..f410baf9d 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNEWT.java @@ -55,7 +55,6 @@ public class TestGearsNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); width = 512; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/drawable/TestDrawable01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/drawable/TestDrawable01NEWT.java index 5568b42f7..731f7c867 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/drawable/TestDrawable01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/drawable/TestDrawable01NEWT.java @@ -52,7 +52,6 @@ public class TestDrawable01NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glp = GLProfile.getDefault(); Assert.assertNotNull(glp); factory = GLDrawableFactory.getFactory(glp); @@ -99,7 +98,7 @@ public class TestDrawable01NEWT extends UITestCase { // Create native OpenGL resources .. XGL/WGL/CGL .. // equivalent to GLAutoDrawable methods: setVisible(true) // - GLCapabilities glCaps = (GLCapabilities) window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + GLCapabilities glCaps = (GLCapabilities) window.getGraphicsConfiguration().getChosenCapabilities(); Assert.assertNotNull(glCaps); Assert.assertTrue(glCaps.getGreenBits()>5); Assert.assertTrue(glCaps.getBlueBits()>5); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/GLSLMiscHelper.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/GLSLMiscHelper.java index ae08b640c..297cbbb90 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/GLSLMiscHelper.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/GLSLMiscHelper.java @@ -37,8 +37,8 @@ import javax.media.opengl.GLDrawable; import org.junit.Assert; public class GLSLMiscHelper { - public static final int frames_perftest = 10000; // frames - public static final int frames_warmup = 500; // frames + public static final int frames_perftest = 600; // frames + public static final int frames_warmup = 100; // frames public static void validateGLArrayDataServerState(GL2ES2 gl, GLArrayDataServer data) { final ShaderState st = ShaderState.getShaderState(gl); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java index 50d65e985..aca1e6607 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestFBOMRTNEWT01.java @@ -56,11 +56,6 @@ import org.junit.BeforeClass; public class TestFBOMRTNEWT01 extends UITestCase { static long durationPerTest = 10; // ms - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - @Test public void test01() throws InterruptedException { // preset .. diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState01NEWT.java index 672938310..ea290693c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState01NEWT.java @@ -54,15 +54,11 @@ import org.junit.BeforeClass; */ public class TestGLSLShaderState01NEWT extends UITestCase { static long durationPerTest = 10; // ms + static boolean firstUIActionOnProcess = false; static final int vertices0_loc = 0; // FIXME: AMD needs this to be location 0 ? hu ? static final int colors0_loc = 1; - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - @Test public void testShaderState01Validation() throws InterruptedException { // preset .. @@ -181,11 +177,11 @@ public class TestGLSLShaderState01NEWT extends UITestCase { NEWTGLContext.destroyWindow(winctx); } - @Test(timeout=120000) + @Test(timeout=240000) public void testShaderState00PerformanceSingleKeepEnabled() throws InterruptedException { testShaderState00PerformanceSingle(false); } - @Test(timeout=120000) + @Test(timeout=240000) public void testShaderState00PerformanceSingleToggleEnable() throws InterruptedException { testShaderState00PerformanceSingle(true); } @@ -278,7 +274,7 @@ public class TestGLSLShaderState01NEWT extends UITestCase { NEWTGLContext.destroyWindow(winctx); } - @Test(timeout=120000) + @Test(timeout=240000) public void testShaderState01PerformanceDouble() throws InterruptedException { // preset .. final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow(GLProfile.getGL2ES2(), 480, 480, false); @@ -386,9 +382,10 @@ public class TestGLSLShaderState01NEWT extends UITestCase { for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { durationPerTest = MiscUtils.atoi(args[++i], (int)durationPerTest); - } - if(args[i].equals("-wait")) { + } else if(args[i].equals("-wait")) { wait = true; + } else if(args[i].equals("-firstUIAction")) { + firstUIActionOnProcess = true; } } if(wait) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState02NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState02NEWT.java index 2bb825649..fb52ff04b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLShaderState02NEWT.java @@ -58,11 +58,6 @@ public class TestGLSLShaderState02NEWT extends UITestCase { static final int vertices0_loc = 0; // FIXME: AMD needs this to be location 0 ? hu ? static final int colors0_loc = 5; - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - @Test public void testShaderState01ValidationSP1Linked() throws InterruptedException { testShaderState01Validation(true); @@ -236,7 +231,7 @@ public class TestGLSLShaderState02NEWT extends UITestCase { NEWTGLContext.destroyWindow(winctx); } - @Test(timeout=120000) + @Test(timeout=240000) public void testShaderState01PerformanceDouble() throws InterruptedException { // preset .. final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow(GLProfile.getGL2ES2(), 480, 480, false); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLSimple01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLSimple01NEWT.java index b683cb2e7..672193946 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLSimple01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestGLSLSimple01NEWT.java @@ -54,19 +54,6 @@ import org.junit.AfterClass; public class TestGLSLSimple01NEWT extends UITestCase { static long durationPerTest = 100; // ms - @BeforeClass - public static void initClass() { - System.err.println("class init"); - GLProfile.initSingleton(true); - } - - @AfterClass - public static void tearDownClass() { - System.err.println("class tear down .."); - GLProfile.shutdown(); - System.err.println("class tear down end"); - } - @Test(timeout=60000) public void testGLSLCompilation01() { GLProfile glp = GLProfile.get(GLProfile.GL2ES2); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestRulerNEWT01.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestRulerNEWT01.java index fe1149f86..13780a7e5 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestRulerNEWT01.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestRulerNEWT01.java @@ -57,13 +57,11 @@ import org.junit.BeforeClass; public class TestRulerNEWT01 extends UITestCase { static long durationPerTest = 10; // ms - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - @Test public void test01() throws InterruptedException { + long t0 = System.nanoTime(); + GLProfile.initSingleton(); + long t1 = System.nanoTime(); // preset .. final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOnscreenWindow(GLProfile.getGL2ES2(), 640, 480, true); final GLDrawable drawable = winctx.context.getGLDrawable(); @@ -161,7 +159,15 @@ public class TestRulerNEWT01 extends UITestCase { Thread.sleep(durationPerTest/10); } + long t2 = System.nanoTime(); + NEWTGLContext.destroyWindow(winctx); + + long t3 = System.nanoTime(); + + System.err.println("t1-t0: "+ (t1-t0)/1e6 +"ms"); + System.err.println("t3-t0: "+ (t3-t0)/1e6 +"ms"); + System.err.println("t3-t2: "+ (t3-t2)/1e6 +"ms"); } public static void main(String args[]) throws IOException { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestTransformFeedbackVaryingsBug407NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestTransformFeedbackVaryingsBug407NEWT.java index a6d04cf24..a3059baae 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestTransformFeedbackVaryingsBug407NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/glsl/TestTransformFeedbackVaryingsBug407NEWT.java @@ -29,16 +29,6 @@ public class TestTransformFeedbackVaryingsBug407NEWT extends UITestCase { private String VERTEX_SHADER_TEXT; - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - } - - @AfterClass - public static void tearDownClass() { - GLProfile.shutdown(); - } - class MyShader { int shaderProgram; int vertShader; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java b/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java index 2809a138c..213d3ad05 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/newt/TestSwingAWTRobotUsageBeforeJOGLInitBug411.java @@ -112,9 +112,6 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { public static void setup() throws InterruptedException, InvocationTargetException, AWTException { System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.setup(): Start Pre-JOGL-Swing"); - // GLProfile.initSingleton(false); - // GLProfile.initSingleton(true); - // simulate AWT usage before JOGL's initialization of X11 threading windowClosing=false; border = BorderFactory.createLineBorder (Color.yellow, 2); @@ -166,8 +163,7 @@ public class TestSwingAWTRobotUsageBeforeJOGLInitBug411 extends UITestCase { System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.setup(): Before JOGL init"); // just to trigger JOGL initialization at a well defined point .. - // ofc it's not the first UI command - GLProfile.initSingleton(false); + GLProfile.initSingleton(); System.err.println("TestSwingAWTRobotUsageBeforeJOGLInitBug411.setup(): End Pre-JOGL-Swing"); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen01GLPBufferNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen01GLPBufferNEWT.java index 561819485..3f1fd144f 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen01GLPBufferNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen01GLPBufferNEWT.java @@ -56,7 +56,6 @@ public class TestOffscreen01GLPBufferNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glpDefault = GLProfile.getDefault(); Assert.assertNotNull(glpDefault); glDrawableFactory = GLDrawableFactory.getFactory(glpDefault); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen02BitmapNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen02BitmapNEWT.java index 1b43940cd..e2ce78b9b 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen02BitmapNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/TestOffscreen02BitmapNEWT.java @@ -61,7 +61,6 @@ public class TestOffscreen02BitmapNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); glpDefault = GLProfile.getDefault(); Assert.assertNotNull(glpDefault); glDrawableFactory = GLDrawableFactory.getFactory(glpDefault); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java index 199b094f2..1d1ee1e0c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/offscreen/WindowUtilNEWT.java @@ -103,7 +103,7 @@ public class WindowUtilNEWT { while ( windowOffScreen.getTotalFPSFrames() < frames) { windowOffScreen.display(); } - windowOffScreen.removeAllSurfaceUpdatedListener(); + windowOffScreen.removeSurfaceUpdatedListener(ul); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT01GLn.java index e6d937d0c..d302c3903 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT01GLn.java @@ -73,7 +73,6 @@ public class TestSWT01GLn extends UITestCase { @BeforeClass
public static void startup() {
- GLProfile.initSingleton(true);
System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() );
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java index 3e153214b..b8e45dfe1 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWT02GLn.java @@ -38,7 +38,6 @@ import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.opengl.GLCanvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; @@ -78,7 +77,6 @@ public class TestSWT02GLn extends UITestCase { @BeforeClass public static void startup() { - GLProfile.initSingleton( true ); System.out.println( "GLProfile " + GLProfile.glAvailabilityToString() ); } @@ -156,7 +154,7 @@ public class TestSWT02GLn extends UITestCase { ProxySurface proxySurface = factory.createProxySurface(device, nativeWindowHandle, caps, null); Assert.assertNotNull( proxySurface ); - proxySurface.setSize( 640, 480 ); + proxySurface.surfaceSizeChanged( 640, 480 ); System.err.println("*** ProxySurface: " + proxySurface); final GLDrawable drawable = factory.createGLDrawable(proxySurface); Assert.assertNotNull( drawable ); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAWT01GLn.java b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAWT01GLn.java index 595e6fb31..6139d816a 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAWT01GLn.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/swt/TestSWTAWT01GLn.java @@ -29,6 +29,7 @@ package com.jogamp.opengl.test.junit.jogl.swt;
import java.awt.Frame;
+import java.lang.reflect.InvocationTargetException;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
@@ -37,6 +38,8 @@ import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
+import jogamp.nativewindow.swt.SWTAccessor;
+
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.graphics.Rectangle;
@@ -76,46 +79,47 @@ public class TestSWTAWT01GLn extends UITestCase { }
@Before
- public void init() {
- display = new Display();
- Assert.assertNotNull( display );
- shell = new Shell( display );
- Assert.assertNotNull( shell );
- shell.setLayout( new FillLayout() );
- composite = new Composite( shell, SWT.EMBEDDED | SWT.NO_BACKGROUND );
- composite.setLayout( new FillLayout() );
- Assert.assertNotNull( composite );
- frame = SWT_AWT.new_Frame( composite );
- Assert.assertNotNull( frame );
+ public void init() throws InterruptedException, InvocationTargetException {
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ display = new Display();
+ Assert.assertNotNull( display );
+ shell = new Shell( display );
+ Assert.assertNotNull( shell );
+ shell.setLayout( new FillLayout() );
+ composite = new Composite( shell, SWT.EMBEDDED | SWT.NO_BACKGROUND );
+ composite.setLayout( new FillLayout() );
+ Assert.assertNotNull( composite );
+ frame = SWT_AWT.new_Frame( composite );
+ Assert.assertNotNull( frame );
+ }});
}
@After
- public void release() {
+ public void release() throws InterruptedException, InvocationTargetException {
Assert.assertNotNull( display );
Assert.assertNotNull( shell );
Assert.assertNotNull( composite );
Assert.assertNotNull( glcanvas );
- try {
- javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
- public void run() {
- frame.setVisible(false);
- frame.remove(glcanvas);
- frame.dispose();
- }});
- composite.dispose();
- shell.close();
- shell.dispose();
- display.dispose();
- }
- catch( Throwable throwable ) {
- throwable.printStackTrace();
- Assume.assumeNoException( throwable );
- }
- display = null;
- shell = null;
- composite = null;
- frame = null;
- glcanvas = null;
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame.setVisible(false);
+ frame.remove(glcanvas);
+ frame.dispose();
+ frame = null;
+ glcanvas = null;
+ }});
+
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ composite.dispose();
+ shell.close();
+ shell.dispose();
+ display.dispose();
+ display = null;
+ shell = null;
+ composite = null;
+ }});
}
protected void runTestGL( GLProfile glprofile ) throws InterruptedException {
@@ -148,18 +152,26 @@ public class TestSWTAWT01GLn extends UITestCase { }
});
- shell.setText( getClass().getName() );
- shell.setSize( 640, 480 );
- shell.open();
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ shell.setText( getClass().getName() );
+ shell.setSize( 640, 480 );
+ shell.open();
+ }});
long lStartTime = System.currentTimeMillis();
long lEndTime = lStartTime + duration;
try {
while( (System.currentTimeMillis() < lEndTime) && !composite.isDisposed() ) {
- if( !display.readAndDispatch() ) {
- // blocks on linux .. display.sleep();
- Thread.sleep(10);
- }
+ SWTAccessor.invoke(true, new Runnable() {
+ public void run() {
+ if( !display.readAndDispatch() ) {
+ // blocks on linux .. display.sleep();
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) { }
+ }
+ }});
}
}
catch( Throwable throwable ) {
diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java index adc885191..4ebb7dddd 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestCloseNewtAWT.java @@ -39,10 +39,9 @@ import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.util.Point; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLProfile; + import com.jogamp.newt.Window; import com.jogamp.newt.awt.NewtCanvasAWT; -import com.jogamp.newt.event.WindowAdapter; -import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; import com.jogamp.opengl.test.junit.util.UITestCase; @@ -53,6 +52,7 @@ public class TestCloseNewtAWT extends UITestCase { NewtCanvasAWT newtCanvas = null; JFrame frame = null; + @SuppressWarnings("serial") class MyCanvas extends NewtCanvasAWT { public MyCanvas(Window window) { super(window); @@ -78,7 +78,7 @@ public class TestCloseNewtAWT extends UITestCase { NativeWindow nw = MyCanvas.this.getNativeWindow(); if(null != nw) { Point p = nw.getLocationOnScreen(null); - System.err.println("MyCanvas On NEWT-EDT: position: "+p); + System.err.println("MyCanvas On NEWT-EDT: position: "+p); } else { System.err.println("MyCanvas On NEWT-EDT: position n/a, null NativeWindow"); } @@ -110,8 +110,6 @@ public class TestCloseNewtAWT extends UITestCase { Thread.sleep(500); Assert.assertEquals(true, AWTRobotUtil.closeWindow(frame, true)); - - GLProfile.shutdown(); } public static void main(String[] args) { diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java index d027460db..c9450c2d6 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle01NEWT.java @@ -51,7 +51,6 @@ public class TestDisplayLifecycle01NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle02NEWT.java index 4b3c5d506..bf509124b 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestDisplayLifecycle02NEWT.java @@ -51,7 +51,6 @@ public class TestDisplayLifecycle02NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java index 13653b907..fe7fef09f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus01SwingAWTRobot.java @@ -35,6 +35,7 @@ import org.junit.Assume; import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Button; +import java.awt.Color; import java.awt.Robot; import java.lang.reflect.InvocationTargetException; @@ -119,7 +120,7 @@ public class TestFocus01SwingAWTRobot extends UITestCase { AWTFocusAdapter frame1FA = new AWTFocusAdapter("frame1"); frame1.addFocusListener(frame1FA); frame1.getContentPane().add(newtCanvasAWT, BorderLayout.CENTER); - Button button = new Button("Click me .."); + final Button button = new Button("Click me .."); AWTFocusAdapter buttonFA = new AWTFocusAdapter("Button"); button.addFocusListener(buttonFA); AWTKeyAdapter buttonKA = new AWTKeyAdapter("Button"); @@ -127,7 +128,10 @@ public class TestFocus01SwingAWTRobot extends UITestCase { eventCountAdapters.add(buttonKA); frame1.getContentPane().add(button, BorderLayout.NORTH); frame1.setSize(width, height); - frame1.setVisible(true); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.setVisible(true); + } } ); Assert.assertTrue(AWTRobotUtil.toFront(robot, frame1)); Thread.sleep(durationPerTest); // manual testing @@ -162,7 +166,6 @@ public class TestFocus01SwingAWTRobot extends UITestCase { System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); AWTRobotUtil.assertRequestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonFA); - Assert.assertTrue(AWTRobotUtil.waitForFocusCount(false, newtCanvasAWTFA)); Assert.assertEquals(true, glWindow1FA.focusGained()); Assert.assertEquals(false, buttonFA.focusGained()); Assert.assertEquals(true, buttonFA.focusLost()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java index 56b08b52a..b9eb748b7 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestFocus02SwingAWTRobot.java @@ -145,14 +145,17 @@ public class TestFocus02SwingAWTRobot extends UITestCase { jPanel1.add(new Button("west"), BorderLayout.WEST); jPanel1.add(container1, BorderLayout.CENTER); - JFrame jFrame1 = new JFrame("Swing Parent JFrame"); + final JFrame jFrame1 = new JFrame("Swing Parent JFrame"); AWTFocusAdapter jFrame1FA = new AWTFocusAdapter("JFrame1"); jFrame1.addFocusListener(jFrame1FA); // jFrame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame1.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // equivalent to Frame, use windowClosing event! jFrame1.setContentPane(jPanel1); jFrame1.setSize(width, height); - jFrame1.setVisible(true); // from here on, we need to run modifications on EDT + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + jFrame1.setVisible(true); + } } ); Assert.assertTrue(AWTRobotUtil.toFront(robot, jFrame1)); int wait=0; @@ -192,7 +195,6 @@ public class TestFocus02SwingAWTRobot extends UITestCase { System.err.println("FOCUS NEWT Canvas/GLWindow request"); EventCountAdapterUtil.reset(eventCountAdapters); AWTRobotUtil.assertRequestFocusAndWait(robot, newtCanvasAWT, newtCanvasAWT.getNEWTChild(), glWindow1FA, buttonNorthOuterFA); - Assert.assertTrue(AWTRobotUtil.waitForFocusCount(false, newtCanvasAWTFA)); Assert.assertEquals(true, glWindow1FA.focusGained()); Assert.assertEquals(false, buttonNorthOuterFA.focusGained()); Assert.assertEquals(true, buttonNorthOuterFA.focusLost()); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java index 5c42f2b16..309d7c7cb 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows00NEWT.java @@ -50,8 +50,6 @@ public class TestGLWindows00NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); - // GLProfile.initSingleton(false); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java index 45a0b0b13..0c6f60b5f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows01NEWT.java @@ -50,8 +50,6 @@ public class TestGLWindows01NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); - // GLProfile.initSingleton(false); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows02NEWTAnimated.java b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows02NEWTAnimated.java index 3176d59e5..6f4ced53c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows02NEWTAnimated.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestGLWindows02NEWTAnimated.java @@ -52,7 +52,6 @@ public class TestGLWindows02NEWTAnimated extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java index 15151fa2c..fa7f0f915 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestListenerCom01AWT.java @@ -42,6 +42,7 @@ import com.jogamp.newt.opengl.*; import com.jogamp.newt.awt.NewtCanvasAWT; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import com.jogamp.opengl.test.junit.util.*; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; @@ -58,7 +59,7 @@ public class TestListenerCom01AWT extends UITestCase { } @Test - public void testListenerStringPassingAndOrder() throws InterruptedException { + public void testListenerStringPassingAndOrder() throws InterruptedException, InvocationTargetException { // setup NEWT GLWindow .. GLWindow glWindow = GLWindow.create(new GLCapabilities(null)); Assert.assertNotNull(glWindow); @@ -88,10 +89,13 @@ public class TestListenerCom01AWT extends UITestCase { // attach NEWT GLWindow to AWT Canvas NewtCanvasAWT newtCanvasAWT = new NewtCanvasAWT(glWindow); - Frame frame = new Frame("AWT Parent Frame"); + final Frame frame = new Frame("AWT Parent Frame"); frame.add(newtCanvasAWT); frame.setSize(width, height); - frame.setVisible(true); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.setVisible(true); + }}); Animator animator1 = new Animator(glWindow); animator1.setUpdateFPSFrames(1, null); @@ -104,14 +108,17 @@ public class TestListenerCom01AWT extends UITestCase { animator1.stop(); Assert.assertEquals(false, animator1.isAnimating()); - frame.dispose(); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame.dispose(); + }}); glWindow.destroy(); } public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteGLWindows01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteGLWindows01NEWT.java index ee21a8ded..35e24403f 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteGLWindows01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteGLWindows01NEWT.java @@ -48,17 +48,9 @@ import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; public class TestRemoteGLWindows01NEWT extends UITestCase { - static int width, height; + static int width = 640, height = 480; static long durationPerTest = 100; // ms - static String remoteDisplay = "nowhere:0.0"; - - @BeforeClass - public static void initClass() { - GLProfile.initSingleton(true); - // GLProfile.initSingleton(false); - width = 640; - height = 480; - } + static String remoteDisplay = "localhost:0.0"; static GLWindow createWindow(Screen screen, GLCapabilities caps, GLEventListener demo) throws InterruptedException diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteWindow01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteWindow01NEWT.java index 9c44545f2..eb652584c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteWindow01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestRemoteWindow01NEWT.java @@ -43,7 +43,7 @@ import com.jogamp.opengl.test.junit.util.UITestCase; public class TestRemoteWindow01NEWT extends UITestCase { static int width, height; - static String remoteDisplay = "nowhere:0.0"; + static String remoteDisplay = "localhost:0.0"; @BeforeClass public static void initClass() { @@ -77,7 +77,7 @@ public class TestRemoteWindow01NEWT extends UITestCase { // Create native OpenGL resources .. XGL/WGL/CGL .. // equivalent to GLAutoDrawable methods: setVisible(true) // - CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getChosenCapabilities(); Assert.assertNotNull(chosenCapabilities); Assert.assertTrue(chosenCapabilities.getGreenBits()>5); Assert.assertTrue(chosenCapabilities.getBlueBits()>5); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00NEWT.java index 985affa92..a5b7a76e7 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00NEWT.java @@ -35,21 +35,21 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.newt.Display; import com.jogamp.newt.NewtFactory; import com.jogamp.newt.Screen; -import com.jogamp.newt.Window; import com.jogamp.newt.ScreenMode; import com.jogamp.newt.util.MonitorMode; import com.jogamp.newt.util.ScreenModeUtil; import com.jogamp.opengl.test.junit.util.UITestCase; import java.util.Iterator; import java.util.List; -import javax.media.nativewindow.Capabilities; import javax.media.nativewindow.util.Dimension; import javax.media.nativewindow.util.DimensionImmutable; import javax.media.nativewindow.util.SurfaceSize; public class TestScreenMode00NEWT extends UITestCase { + static int screenIdx = 0; static int width, height; static int waitTimeShort = 4; //1 sec @@ -95,12 +95,12 @@ public class TestScreenMode00NEWT extends UITestCase { @Test public void testScreenModeInfo01() throws InterruptedException { - Capabilities caps = new Capabilities(); - Window window = NewtFactory.createWindow(caps); - window.setSize(width, height); - window.setVisible(true); - - Screen screen = window.getScreen(); + Display dpy = NewtFactory.createDisplay(null); + Screen screen = NewtFactory.createScreen(dpy, screenIdx); + screen.addReference(); + Assert.assertEquals(true,screen.isNativeValid()); + Assert.assertEquals(true,screen.getDisplay().isNativeValid()); + System.err.println("Screen: "+screen.toString()); List<ScreenMode> screenModes = screen.getScreenModes(); Assert.assertTrue(screenModes.size()>0); @@ -116,18 +116,26 @@ public class TestScreenMode00NEWT extends UITestCase { System.err.println("curr SM: "+sm_c); System.err.println("curr sz: "+screen.getWidth()+"x"+screen.getHeight()); Assert.assertEquals(sm_o, sm_c); - Assert.assertEquals(sm_c.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(sm_c.getRotatedHeight(), screen.getHeight()); - window.destroy(); + screen.removeReference(); - Assert.assertEquals(false,window.isVisible()); - Assert.assertEquals(false,window.isNativeValid()); Assert.assertEquals(false,screen.isNativeValid()); Assert.assertEquals(false,screen.getDisplay().isNativeValid()); } + static int atoi(String a) { + try { + return Integer.parseInt(a); + } catch (Exception ex) { throw new RuntimeException(ex); } + } + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-screen")) { + i++; + screenIdx = atoi(args[i]); + } + } String tstname = TestScreenMode00NEWT.class.getName(); org.junit.runner.JUnitCore.main(tstname); } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00bNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00bNEWT.java index 41bdfdfd7..e9e66da2c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00bNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode00bNEWT.java @@ -95,10 +95,10 @@ public class TestScreenMode00bNEWT extends UITestCase { System.err.println("orig: "+sm_o); System.err.println("curr: "+sm_c); - for(i=0; i<100; i++) { + for(i=0; i<50; i++) { sm_c = screen.getCurrentScreenMode(); Assert.assertNotNull(sm_c); - System.err.print("."); + System.err.print("."+i); } System.err.println("!"); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01NEWT.java index 5f14fc466..c3c68e46c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01NEWT.java @@ -68,7 +68,6 @@ public class TestScreenMode01NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glp = GLProfile.getDefault(); @@ -112,8 +111,8 @@ public class TestScreenMode01NEWT extends UITestCase { */ @After public void cleanupGL() throws InterruptedException { - GLProfile.shutdown(); - GLProfile.initSingleton(true); + GLProfile.shutdown(GLProfile.ShutdownType.COMPLETE); + GLProfile.initSingleton(); } static GLWindow createWindow(Screen screen, GLCapabilities caps, int width, int height, boolean onscreen, boolean undecorated) { @@ -201,8 +200,6 @@ public class TestScreenMode01NEWT extends UITestCase { Assert.assertNotNull(smOrig); Assert.assertEquals(smCurrent, smOrig); System.err.println("[0] current/orig: "+smCurrent); - Assert.assertEquals(smCurrent.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(smCurrent.getRotatedHeight(), screen.getHeight()); screenModes = ScreenModeUtil.filterByRate(screenModes, smOrig.getMonitorMode().getRefreshRate()); Assert.assertNotNull(screenModes); @@ -223,8 +220,6 @@ public class TestScreenMode01NEWT extends UITestCase { screen.setCurrentScreenMode(sm); Assert.assertEquals(sm, screen.getCurrentScreenMode()); Assert.assertNotSame(smOrig, screen.getCurrentScreenMode()); - Assert.assertEquals(sm.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(sm.getRotatedHeight(), screen.getHeight()); Thread.sleep(waitTimeLong); @@ -254,8 +249,6 @@ public class TestScreenMode01NEWT extends UITestCase { Assert.assertNotNull(smCurrent); Assert.assertEquals(smCurrent, smOrig); - Assert.assertEquals(smCurrent.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(smCurrent.getRotatedHeight(), screen.getHeight()); screen.destroy(); @@ -289,8 +282,6 @@ public class TestScreenMode01NEWT extends UITestCase { Assert.assertNotNull(smOrig); Assert.assertEquals(smCurrent, smOrig); System.err.println("[0] current/orig: "+smCurrent); - Assert.assertEquals(smCurrent.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(smCurrent.getRotatedHeight(), screen.getHeight()); List<ScreenMode> screenModes = screen.getScreenModes(); if(screenModes.size()==1) { @@ -317,8 +308,6 @@ public class TestScreenMode01NEWT extends UITestCase { System.err.println("[0] set current: "+screenMode); screen.setCurrentScreenMode(screenMode); - Assert.assertEquals(screenMode.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(screenMode.getRotatedHeight(), screen.getHeight()); if(!preFS) { System.err.println("[0] set FS post 0: "+window.isFullscreen()); @@ -355,8 +344,6 @@ public class TestScreenMode01NEWT extends UITestCase { Assert.assertNotNull(smCurrent); Assert.assertEquals(smCurrent, smOrig); - Assert.assertEquals(smCurrent.getRotatedWidth(), screen.getWidth()); - Assert.assertEquals(smCurrent.getRotatedHeight(), screen.getHeight()); screen.destroy(); } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01bNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01bNEWT.java index 4d7769669..38612faa8 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01bNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode01bNEWT.java @@ -65,7 +65,6 @@ public class TestScreenMode01bNEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 100; height = 100; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode02NEWT.java index 8c7f75e2b..1c9cb91f3 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestScreenMode02NEWT.java @@ -60,7 +60,6 @@ public class TestScreenMode02NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glp = GLProfile.getDefault(); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/TestWindows01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/TestWindows01NEWT.java index 827dd09fb..a99edfadb 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/TestWindows01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/TestWindows01NEWT.java @@ -90,7 +90,7 @@ public class TestWindows01NEWT extends UITestCase { Assert.assertEquals(y, window.getY()); } */ - CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + CapabilitiesImmutable chosenCapabilities = window.getGraphicsConfiguration().getChosenCapabilities(); Assert.assertNotNull(chosenCapabilities); Assert.assertTrue(chosenCapabilities.getGreenBits()>=5); Assert.assertTrue(chosenCapabilities.getBlueBits()>=5); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java index 46748cb52..473f2f584 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/NewtAWTReparentingKeyAdapter.java @@ -51,7 +51,11 @@ class NewtAWTReparentingKeyAdapter extends KeyAdapter { if(e.getKeyChar()=='d') { glWindow.setUndecorated(!glWindow.isUndecorated()); } else if(e.getKeyChar()=='f') { - glWindow.setFullscreen(!glWindow.isFullscreen()); + glWindow.setFullscreen(!glWindow.isFullscreen()); + } else if(e.getKeyChar()=='l') { + javax.media.nativewindow.util.Point p0 = newtCanvasAWT.getNativeWindow().getLocationOnScreen(null); + javax.media.nativewindow.util.Point p1 = glWindow.getLocationOnScreen(null); + System.err.println("NewtCanvasAWT position: "+p0+", "+p1); } else if(e.getKeyChar()=='p') { new Thread() { public void run() { diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java index 7f97be649..256868c6c 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01NEWT.java @@ -53,7 +53,6 @@ public class TestParenting01NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; glCaps = new GLCapabilities(null); @@ -654,7 +653,7 @@ public class TestParenting01NEWT extends UITestCase { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); } - if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getWindow())) { + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getDelegatedWindow())) { MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); } } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java index 674cf4a06..2040fb9b6 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01aAWT.java @@ -467,7 +467,7 @@ public class TestParenting01aAWT extends UITestCase { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); } - if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getWindow())) { + if(!MiscUtils.setFieldIfExists(demo, "window", glWindow.getDelegatedWindow())) { MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); } } diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java index 8571609a8..d98a540ec 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01bAWT.java @@ -173,7 +173,7 @@ public class TestParenting01bAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java index 3b40554d2..dfd0787e7 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cAWT.java @@ -228,7 +228,7 @@ public class TestParenting01cAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java index f505547d4..22ed7c6fd 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting01cSwingAWT.java @@ -319,7 +319,7 @@ public class TestParenting01cSwingAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java index f01468c2a..da689cea6 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02AWT.java @@ -118,7 +118,8 @@ public class TestParenting02AWT extends UITestCase { } } - frame.setSize(width, height); + // frame.setSize(width, height); + frame.setBounds(100, 100, width, height); javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -233,7 +234,7 @@ public class TestParenting02AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java index 13aad0c25..bc3988338 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting02NEWT.java @@ -54,7 +54,6 @@ public class TestParenting02NEWT extends UITestCase { @BeforeClass public static void initClass() { - GLProfile.initSingleton(true); width = 640; height = 480; } @@ -120,7 +119,7 @@ public class TestParenting02NEWT extends UITestCase { // glWindow1.addGLEventListener(demo1); glWindow1.setVisible(true); - CapabilitiesImmutable capsChosen = glWindow1.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + CapabilitiesImmutable capsChosen = glWindow1.getGraphicsConfiguration().getChosenCapabilities(); Assert.assertNotNull(capsChosen); Assert.assertTrue(capsChosen.isOnscreen()==true); @@ -142,7 +141,7 @@ public class TestParenting02NEWT extends UITestCase { // glWindow2.addGLEventListener(demo2); glWindow2.setVisible(true); - capsChosen = glWindow2.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + capsChosen = glWindow2.getGraphicsConfiguration().getChosenCapabilities(); Assert.assertNotNull(capsChosen); Assert.assertTrue(capsChosen.isOnscreen()==true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java index aded8f163..b33a40fae 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParenting03AWT.java @@ -35,10 +35,10 @@ import org.junit.BeforeClass; import org.junit.Test; import java.awt.BorderLayout; +import java.awt.Button; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; -import java.awt.Label; import javax.media.opengl.*; @@ -53,28 +53,34 @@ import com.jogamp.opengl.test.junit.util.*; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; public class TestParenting03AWT extends UITestCase { - static Dimension size; - static long durationPerTest = 800; + static Dimension glSize, fSize; + static long durationPerTest = 1100; static long waitAdd2nd = 500; static GLCapabilities glCaps; @BeforeClass public static void initClass() { - size = new Dimension(400,200); + glSize = new Dimension(400,200); + fSize = new Dimension(3*400,2*200); glCaps = new GLCapabilities(null); } @Test - public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { - testWindowParenting1AWTTwoNewtChilds(); + public void testWindowParenting1AWTOneNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(false); } - public void testWindowParenting1AWTTwoNewtChilds() throws InterruptedException, InvocationTargetException { + @Test + public void testWindowParenting1AWTTwoNewtChilds01() throws InterruptedException, InvocationTargetException { + testWindowParenting1AWT(true); + } + + public void testWindowParenting1AWT(boolean use2nd) throws InterruptedException, InvocationTargetException { final Frame frame1 = new Frame("AWT Parent Frame"); GLWindow glWindow1 = GLWindow.create(glCaps); glWindow1.setUpdateFPSFrames(1, null); final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); - newtCanvasAWT1.setPreferredSize(size); + newtCanvasAWT1.setPreferredSize(glSize); GLEventListener demo1 = new GearsES2(1); setDemoFields(demo1, glWindow1, false); @@ -83,7 +89,6 @@ public class TestParenting03AWT extends UITestCase { GLAnimatorControl animator1 = new Animator(glWindow1); animator1.start(); - final boolean use2nd = true; GLWindow glWindow2 = null; NewtCanvasAWT newtCanvasAWT2 = null; GLAnimatorControl animator2 = null; @@ -91,7 +96,7 @@ public class TestParenting03AWT extends UITestCase { glWindow2 = GLWindow.create(glCaps); glWindow2.setUpdateFPSFrames(1, null); newtCanvasAWT2 = new NewtCanvasAWT(glWindow2); - newtCanvasAWT2.setPreferredSize(size); + newtCanvasAWT2.setPreferredSize(glSize); GLEventListener demo2 = new GearsES2(1); setDemoFields(demo2, glWindow2, false); @@ -103,10 +108,10 @@ public class TestParenting03AWT extends UITestCase { final Container cont1 = new Container(); cont1.setLayout(new BorderLayout()); - cont1.add(new Label("iNORTH"), BorderLayout.NORTH); - cont1.add(new Label("iSOUTH"), BorderLayout.SOUTH); - cont1.add(new Label("iEAST"), BorderLayout.EAST); - cont1.add(new Label("iWEST"), BorderLayout.WEST); + cont1.add(new Button("NORTH"), BorderLayout.NORTH); + cont1.add(new Button("SOUTH"), BorderLayout.SOUTH); + cont1.add(new Button("EAST"), BorderLayout.EAST); + cont1.add(new Button("WEST"), BorderLayout.WEST); cont1.add(newtCanvasAWT1, BorderLayout.CENTER); System.err.println("******* Cont1 setVisible"); cont1.setVisible(true); @@ -114,34 +119,31 @@ public class TestParenting03AWT extends UITestCase { final Container cont2 = new Container(); cont2.setLayout(new BorderLayout()); if(use2nd) { - cont2.add(new Label("iNORTH"), BorderLayout.NORTH); - cont2.add(new Label("iSOUTH"), BorderLayout.SOUTH); - cont2.add(new Label("iEAST"), BorderLayout.EAST); - cont2.add(new Label("iWEST"), BorderLayout.WEST); + cont2.add(new Button("north"), BorderLayout.NORTH); + cont2.add(new Button("sourth"), BorderLayout.SOUTH); + cont2.add(new Button("east"), BorderLayout.EAST); + cont2.add(new Button("west"), BorderLayout.WEST); cont2.add(newtCanvasAWT2, BorderLayout.CENTER); } System.err.println("******* Cont2 setVisible"); cont2.setVisible(true); frame1.setLayout(new BorderLayout()); - frame1.add(new Label("NORTH"), BorderLayout.NORTH); - frame1.add(new Label("CENTER"), BorderLayout.CENTER); - frame1.add(new Label("SOUTH"), BorderLayout.SOUTH); + frame1.add(new Button("NORTH"), BorderLayout.NORTH); + frame1.add(new Button("CENTER"), BorderLayout.CENTER); + frame1.add(new Button("SOUTH"), BorderLayout.SOUTH); frame1.add(cont1, BorderLayout.EAST); frame1.setLocation(0, 0); - frame1.setSize((int)size.getWidth()*3, (int)size.getHeight()*2); + frame1.setSize(fSize); javax.swing.SwingUtilities.invokeAndWait(new Runnable() { public void run() { System.err.println("******* Frame setVisible"); + frame1.validate(); frame1.setVisible(true); }}); Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); - if(use2nd) { - Assert.assertEquals(newtCanvasAWT2.getNativeWindow(),glWindow2.getParent()); - } - Assert.assertEquals(true, animator1.isAnimating()); Assert.assertEquals(false, animator1.isPaused()); Assert.assertNotNull(animator1.getThread()); @@ -150,15 +152,17 @@ public class TestParenting03AWT extends UITestCase { Assert.assertEquals(true, animator2.isAnimating()); Assert.assertEquals(false, animator2.isPaused()); Assert.assertNotNull(animator2.getThread()); - } - Thread.sleep(waitAdd2nd); + Thread.sleep(waitAdd2nd); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.add(cont2, BorderLayout.WEST); + frame1.validate(); + }}); + Assert.assertEquals(newtCanvasAWT2.getNativeWindow(),glWindow2.getParent()); + } - javax.swing.SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - frame1.add(cont2, BorderLayout.WEST); - frame1.validate(); - }}); Thread.sleep(durationPerTest); @@ -187,7 +191,7 @@ public class TestParenting03AWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java new file mode 100644 index 000000000..b23c17022 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingFocusTraversal01AWT.java @@ -0,0 +1,334 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.newt.parenting; + +import java.lang.reflect.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.awt.AWTException; +import java.awt.AWTKeyStroke; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; + +import javax.media.opengl.*; + +import com.jogamp.opengl.util.Animator; +import com.jogamp.newt.*; +import com.jogamp.newt.opengl.*; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; + +import java.io.IOException; + +import jogamp.newt.driver.DriverClearFocus; + +import com.jogamp.opengl.test.junit.util.*; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; + +public class TestParentingFocusTraversal01AWT extends UITestCase { + static Dimension glSize, fSize; + static int numFocus = 8; + static long durationPerTest = numFocus * 100; + static GLCapabilities glCaps; + static boolean manual = false; + + @BeforeClass + public static void initClass() { + glSize = new Dimension(200,200); + fSize = new Dimension(300,300); + glCaps = new GLCapabilities(null); + } + + @Test + public void testWindowParentingAWTFocusTraversal01Onscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(true); + } + + @Test + public void testWindowParentingAWTFocusTraversal02Offscreen() throws InterruptedException, InvocationTargetException, AWTException { + testWindowParentingAWTFocusTraversal(false); + } + + public void testWindowParentingAWTFocusTraversal(boolean onscreen) throws InterruptedException, InvocationTargetException, AWTException { + Robot robot = new Robot(); + + // Bug 4908075 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4908075 + // Bug 6463168 - http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6463168 + { + final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + final AWTKeyStroke newBack = AWTKeyStroke.getAWTKeyStroke(java.awt.event.KeyEvent.VK_BACK_SPACE, 0, false); + Assert.assertNotNull(newBack); + final Set<AWTKeyStroke> bwdKeys2 = new HashSet<AWTKeyStroke>(bwdKeys); + bwdKeys2.add(newBack); + kfm.setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, bwdKeys2); + } + { + final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + final Set<AWTKeyStroke> fwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + final Set<AWTKeyStroke> bwdKeys = kfm.getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Iterator<AWTKeyStroke> iter; + for(iter = fwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.fwd-keys: "+iter.next()); + } + for(iter = bwdKeys.iterator(); iter.hasNext(); ) { + System.err.println("FTKL.bwd-keys: "+iter.next()); + } + } + + final Frame frame1 = new Frame("AWT Parent Frame"); + final Button cWest = new Button("WEST"); + final Button cEast = new Button("EAST"); + final GLWindow glWindow1 = GLWindow.create(glCaps); + glWindow1.setUpdateFPSFrames(1, null); + final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setPreferredSize(glSize); + newtCanvasAWT1.setShallUseOffscreenLayer(!onscreen); + newtCanvasAWT1.setFocusable(true); + + // Test FocusAdapter + NEWTFocusAdapter glWindow1FA = new NEWTFocusAdapter("GLWindow1"); + glWindow1.addWindowListener(glWindow1FA); + AWTFocusAdapter bWestFA = new AWTFocusAdapter("WEST"); + cWest.addFocusListener(bWestFA); + AWTFocusAdapter bEastFA = new AWTFocusAdapter("EAST"); + cEast.addFocusListener(bEastFA); + + // Test KeyAdapter + NEWTKeyAdapter glWindow1KA = new NEWTKeyAdapter("GLWindow1"); + glWindow1.addKeyListener(glWindow1KA); + AWTKeyAdapter bWestKA = new AWTKeyAdapter("West"); + cWest.addKeyListener(bWestKA); + AWTKeyAdapter bEastKA = new AWTKeyAdapter("East"); + cEast.addKeyListener(bEastKA); + + // demo .. + GLEventListener demo1 = new GearsES2(1); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + glWindow1.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + if(e.getKeyChar()=='c') { + System.err.println("Focus Clear"); + if(glWindow1.getDelegatedWindow() instanceof DriverClearFocus) { + ((DriverClearFocus)glWindow1.getDelegatedWindow()).clearFocus(); + } + } else if(e.getKeyChar()=='e') { + System.err.println("Focus East"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cEast.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } else if(e.getKeyChar()=='w') { + System.err.println("Focus West"); + try { + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + cWest.requestFocusInWindow(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + } + } + }); + GLAnimatorControl animator1 = new Animator(glWindow1); + animator1.start(); + + // make frame + frame1.setLayout(new BorderLayout()); + frame1.setLayout(new BorderLayout()); + frame1.add(cWest, BorderLayout.WEST); + frame1.add(newtCanvasAWT1, BorderLayout.CENTER); + frame1.add(cEast, BorderLayout.EAST); + + frame1.setLocation(0, 0); + frame1.setSize(fSize); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.validate(); + frame1.setVisible(true); + }}); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glWindow1, true)); + Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); + + Assert.assertEquals(true, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertNotNull(animator1.getThread()); + + if(manual) { + Thread.sleep(durationPerTest); + } else { + // + // initial focus on bWest + // + AWTRobotUtil.assertRequestFocusAndWait(robot, cWest, cWest, bWestFA, null); + Assert.assertEquals(true, bWestFA.focusGained()); + Thread.sleep(durationPerTest/numFocus); + + // + // forth + // + + // bWest -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, cWest, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // glWin -> bEast + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_TAB, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cEast, bEastFA, glWindow1FA)); + Assert.assertEquals(true, bEastFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // + // back (using custom back traversal key 'backspace') + // + // bEast -> glWin + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, cEast, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bEastFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bEastFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + AWTRobotUtil.keyType(0, robot, java.awt.event.KeyEvent.VK_BACK_SPACE, glWindow1, null); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + newtCanvasAWT1.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct AWT request focus + try { + java.awt.EventQueue.invokeAndWait(new Runnable() { + public void run() { + cWest.requestFocus(); + } + }); + } catch (Exception ex) { ex.printStackTrace(); } + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(cWest, bWestFA, glWindow1FA)); + Assert.assertEquals(true, bWestFA.focusGained()); + Assert.assertEquals(true, glWindow1FA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + + // direct NEWT request focus + glWindow1.requestFocus(); + Assert.assertTrue("Did not gain focus", AWTRobotUtil.waitForFocus(glWindow1, glWindow1FA, bWestFA)); + Assert.assertEquals(true, glWindow1FA.focusGained()); + Assert.assertEquals(true, bWestFA.focusLost()); + Thread.sleep(durationPerTest/numFocus); + } + + animator1.stop(); + Assert.assertEquals(false, animator1.isAnimating()); + Assert.assertEquals(false, animator1.isPaused()); + Assert.assertEquals(null, animator1.getThread()); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.dispose(); + } } ); + glWindow1.destroy(); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getDelegatedWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } else if(args[i].equals("-manual")) { + manual = true; + } + } + String tstname = TestParentingFocusTraversal01AWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01GLCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01GLCanvasAWT.java new file mode 100644 index 000000000..1367a27dd --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer01GLCanvasAWT.java @@ -0,0 +1,205 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.newt.parenting; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.awt.GLCanvas; + +import jogamp.nativewindow.jawt.JAWTUtil; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.newt.Window; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestParentingOffscreenLayer01GLCanvasAWT extends UITestCase { + static Dimension frameSize0; + static Dimension frameSize1; + static Dimension preferredGLSize; + static Dimension minGLSize; + static long durationPerTest = 1000; + + @BeforeClass + public static void initClass() { + frameSize0 = new Dimension(500,300); + frameSize1 = new Dimension(800,600); + preferredGLSize = new Dimension(400,200); + minGLSize = new Dimension(200,100); + } + + private void setupFrameAndShow(final Frame f, java.awt.Component comp) throws InterruptedException, InvocationTargetException { + + Container c = new Container(); + c.setLayout(new BorderLayout()); + c.add(new Button("north"), BorderLayout.NORTH); + c.add(new Button("south"), BorderLayout.SOUTH); + c.add(new Button("east"), BorderLayout.EAST); + c.add(new Button("west"), BorderLayout.WEST); + c.add(comp, BorderLayout.CENTER); + + f.setLayout(new BorderLayout()); + f.add(new Button("NORTH"), BorderLayout.NORTH); + f.add(new Button("SOUTH"), BorderLayout.SOUTH); + f.add(new Button("EAST"), BorderLayout.EAST); + f.add(new Button("WEST"), BorderLayout.WEST); + f.add(c, BorderLayout.CENTER); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.validate(); + f.setVisible(true); + }}); + } + private void end(GLAnimatorControl actrl, final Frame f, Window w) throws InterruptedException, InvocationTargetException { + actrl.stop(); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.dispose(); + } } ); + if(null != w) { + w.destroy(); + } + } + + @Test + public void testOnscreenLayerGLCanvas_Onscreen() throws InterruptedException, InvocationTargetException { + testOffscreenLayerGLCanvas_Impl(false, false); + } + + /** We have no GLCanvas OffscreenWindow as we have for NEWT .. test disabled. + @Test + public void testOffscreenLayerGLCanvas_OffscreenLayerWithOffscreenClass() throws InterruptedException, InvocationTargetException { + testOffscreenLayerGLCanvas_Impl(true, true); + } */ + + @Test + public void testOffscreenLayerGLCanvas_OffscreenLayerWithOnscreenClass() throws InterruptedException, InvocationTargetException { + testOffscreenLayerGLCanvas_Impl(true, false); + } + + private void testOffscreenLayerGLCanvas_Impl(boolean offscreenLayer, boolean offscreenClass) throws InterruptedException, InvocationTargetException { + final Frame frame1 = new Frame("AWT Parent Frame"); + + GLCapabilities glCaps = new GLCapabilities(null); + if(offscreenClass) { + glCaps.setOnscreen(false); + glCaps.setPBuffer(true); + } + + final GLCanvas glc = new GLCanvas(glCaps); + glc.setShallUseOffscreenLayer(offscreenLayer); // trigger offscreen layer - if supported + glc.setPreferredSize(preferredGLSize); + glc.setMinimumSize(minGLSize); + + GLEventListener demo1 = new GearsES2(1); + glc.addGLEventListener(demo1); + + frame1.setSize(frameSize0); + setupFrameAndShow(frame1, glc); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glc, true)); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glc, true)); + Assert.assertEquals(JAWTUtil.isOffscreenLayerSupported() && offscreenLayer, + glc.isOffscreenLayerSurfaceEnabled()); + + GLAnimatorControl animator1 = new Animator(glc); + animator1.start(); + + Thread.sleep(durationPerTest/2); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.setSize(frameSize1); + frame1.validate(); + }}); + + Thread.sleep(durationPerTest/2); + + end(animator1, frame1, null); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getDelegatedWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } + } + String tstname = TestParentingOffscreenLayer01GLCanvasAWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer02NewtCanvasAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer02NewtCanvasAWT.java new file mode 100644 index 000000000..bc59c7378 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestParentingOffscreenLayer02NewtCanvasAWT.java @@ -0,0 +1,209 @@ +/** + * Copyright 2011 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.newt.parenting; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; + +import jogamp.nativewindow.jawt.JAWTUtil; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.newt.Window; +import com.jogamp.newt.awt.NewtCanvasAWT; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; +import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.Animator; + +public class TestParentingOffscreenLayer02NewtCanvasAWT extends UITestCase { + static Dimension frameSize0; + static Dimension frameSize1; + static Dimension preferredGLSize; + static Dimension minGLSize; + static long durationPerTest = 1000; + + @BeforeClass + public static void initClass() { + frameSize0 = new Dimension(500,300); + frameSize1 = new Dimension(800,600); + preferredGLSize = new Dimension(400,200); + minGLSize = new Dimension(200,100); + } + + private void setupFrameAndShow(final Frame f, java.awt.Component comp) throws InterruptedException, InvocationTargetException { + + Container c = new Container(); + c.setLayout(new BorderLayout()); + c.add(new Button("north"), BorderLayout.NORTH); + c.add(new Button("south"), BorderLayout.SOUTH); + c.add(new Button("east"), BorderLayout.EAST); + c.add(new Button("west"), BorderLayout.WEST); + c.add(comp, BorderLayout.CENTER); + + f.setLayout(new BorderLayout()); + f.add(new Button("NORTH"), BorderLayout.NORTH); + f.add(new Button("SOUTH"), BorderLayout.SOUTH); + f.add(new Button("EAST"), BorderLayout.EAST); + f.add(new Button("WEST"), BorderLayout.WEST); + f.add(c, BorderLayout.CENTER); + + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.validate(); + f.setVisible(true); + }}); + } + private void end(GLAnimatorControl actrl, final Frame f, Window w) throws InterruptedException, InvocationTargetException { + actrl.stop(); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.dispose(); + } } ); + if(null != w) { + w.destroy(); + } + } + + @Test + public void testOnscreenLayerNewtCanvas_Onscreen() throws InterruptedException, InvocationTargetException { + testOffscreenLayerNewtCanvas_Impl(false, false); + } + + @Test + public void testOffscreenLayerNewtCanvas_OffscreenLayerWithOffscreenClass() throws InterruptedException, InvocationTargetException { + testOffscreenLayerNewtCanvas_Impl(true, true); + } + + @Test + public void testOffscreenLayerNewtCanvas_OffscreenLayerWithOnscreenClass() throws InterruptedException, InvocationTargetException { + testOffscreenLayerNewtCanvas_Impl(true, false); + } + + private void testOffscreenLayerNewtCanvas_Impl(boolean offscreenLayer, boolean offscreenClass) throws InterruptedException, InvocationTargetException { + final Frame frame1 = new Frame("AWT Parent Frame"); + + GLCapabilities glCaps = new GLCapabilities(null); + if(offscreenClass) { + glCaps.setOnscreen(false); + glCaps.setPBuffer(true); + } + + GLWindow glWindow1 = GLWindow.create(glCaps); + + final NewtCanvasAWT newtCanvasAWT1 = new NewtCanvasAWT(glWindow1); + newtCanvasAWT1.setShallUseOffscreenLayer(offscreenLayer); // trigger offscreen layer - if supported + newtCanvasAWT1.setPreferredSize(preferredGLSize); + newtCanvasAWT1.setMinimumSize(minGLSize); + + GLEventListener demo1 = new GearsES2(1); + setDemoFields(demo1, glWindow1, false); + glWindow1.addGLEventListener(demo1); + glWindow1.addKeyListener(new NewtAWTReparentingKeyAdapter(frame1, newtCanvasAWT1, glWindow1)); + + frame1.setSize(frameSize0); + setupFrameAndShow(frame1, newtCanvasAWT1); + Assert.assertEquals(true, AWTRobotUtil.waitForRealized(glWindow1, true)); + Assert.assertEquals(true, AWTRobotUtil.waitForVisible(glWindow1, true)); + Assert.assertEquals(newtCanvasAWT1.getNativeWindow(),glWindow1.getParent()); + Assert.assertEquals(JAWTUtil.isOffscreenLayerSupported() && offscreenLayer, + newtCanvasAWT1.isOffscreenLayerSurfaceEnabled()); + + GLAnimatorControl animator1 = new Animator(glWindow1); + animator1.start(); + + Thread.sleep(durationPerTest/2); + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame1.setSize(frameSize1); + frame1.validate(); + }}); + + Thread.sleep(durationPerTest/2); + + end(animator1, frame1, glWindow1); + } + + public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { + Assert.assertNotNull(demo); + Assert.assertNotNull(glWindow); + Window window = glWindow.getDelegatedWindow(); + if(debug) { + MiscUtils.setFieldIfExists(demo, "glDebug", true); + MiscUtils.setFieldIfExists(demo, "glTrace", true); + } + if(!MiscUtils.setFieldIfExists(demo, "window", window)) { + MiscUtils.setFieldIfExists(demo, "glWindow", glWindow); + } + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } + } + String tstname = TestParentingOffscreenLayer02NewtCanvasAWT.class.getName(); + /* + org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(new String[] { + tstname, + "filtertrace=true", + "haltOnError=false", + "haltOnFailure=false", + "showoutput=true", + "outputtoformatters=true", + "logfailedtests=true", + "logtestlistenerevents=true", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter", + "formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,TEST-"+tstname+".xml" } ); */ + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java index be812e6aa..57b8517a6 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/parenting/TestTranslucentParentingAWT.java @@ -50,6 +50,7 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import com.jogamp.common.util.ReflectionUtil; import com.jogamp.newt.Window; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; @@ -89,8 +90,15 @@ public class TestTranslucentParentingAWT extends UITestCase { boolean capable1 = ( null != tcm ) ? tcm.getTransparency() == Transparency.TRANSLUCENT : false; boolean capable2 = false; try { - capable2 = com.sun.awt.AWTUtilities.isTranslucencyCapable(config); - } catch (Exception e) {} + capable2 = ((Boolean)ReflectionUtil.callStaticMethod( + "com.sun.awt.AWTUtilities", "isTranslucencyCapable", + new Class<?>[] { GraphicsConfiguration.class }, + new Object[] { config } , + GraphicsConfiguration.class.getClassLoader())).booleanValue(); + System.err.println("com.sun.awt.AWTUtilities.isTranslucencyCapable(config) passed: "+capable2); + } catch (RuntimeException re) { + System.err.println("com.sun.awt.AWTUtilities.isTranslucencyCapable(config) failed: "+re.getMessage()); + } System.err.println(i+":"+j+" "+config+", "+tcm+", capable "+capable1+"/"+capable2); if(capable1&&capable2) { gc=configs[j]; @@ -157,7 +165,7 @@ public class TestTranslucentParentingAWT extends UITestCase { public static void setDemoFields(GLEventListener demo, GLWindow glWindow, boolean debug) { Assert.assertNotNull(demo); Assert.assertNotNull(glWindow); - Window window = glWindow.getWindow(); + Window window = glWindow.getDelegatedWindow(); if(debug) { MiscUtils.setFieldIfExists(demo, "glDebug", true); MiscUtils.setFieldIfExists(demo, "glTrace", true); diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java index 7df8645de..a27bdd7a2 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java @@ -67,7 +67,7 @@ public class AWTRobotUtil { int x0, y0; if(null!=comp) { - java.awt.Point p0 = comp.getLocationOnScreen(); + java.awt.Point p0 = comp.getLocationOnScreen(); java.awt.Rectangle r0 = comp.getBounds(); if( onTitleBarIfWindow && comp instanceof java.awt.Window) { java.awt.Window window = (java.awt.Window) comp; @@ -78,7 +78,7 @@ public class AWTRobotUtil { } x0 = (int) ( p0.getX() + r0.getWidth() / 2.0 + .5 ) ; } else { - javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); + javax.media.nativewindow.util.Point p0 = win.getLocationOnScreen(null); if( onTitleBarIfWindow ) { javax.media.nativewindow.util.InsetsImmutable insets = win.getInsets(); p0.translate(win.getWidth()/2, insets.getTopHeight()/2); @@ -102,6 +102,9 @@ public class AWTRobotUtil { public static boolean toFront(Robot robot, final java.awt.Window window) throws AWTException, InterruptedException, InvocationTargetException { + AWTWindowFocusAdapter winFA = new AWTWindowFocusAdapter("window"); + window.addWindowFocusListener(winFA); + if(null == robot) { robot = new Robot(); robot.setAutoWaitForIdle(true); @@ -119,11 +122,11 @@ public class AWTRobotUtil { }}); robot.delay(ROBOT_DELAY); - KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); int wait; - for (wait=0; wait<POLL_DIVIDER && window != kfm.getFocusedWindow(); wait++) { + for (wait=0; wait<POLL_DIVIDER && !winFA.focusGained(); wait++) { Thread.sleep(TIME_SLICE); } + window.removeWindowFocusListener(winFA); return wait<POLL_DIVIDER; } @@ -280,8 +283,8 @@ public class AWTRobotUtil { Assert.assertTrue("Did not gain focus", hasFocus); } - static int keyType(int i, Robot robot, int keyCode, - Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException + public static int keyType(int i, Robot robot, int keyCode, + Object obj, InputEventCountAdapter counter) throws InterruptedException, AWTException, InvocationTargetException { int tc = 0; int j; @@ -293,13 +296,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" KC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null!=counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" KC1.1: "+counter); } robot.waitForIdle(); robot.keyPress(keyCode); robot.keyRelease(keyCode); if(DEBUG) { System.err.println(i+":"+j+" KC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null!=counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; @@ -355,13 +358,13 @@ public class AWTRobotUtil { if(DEBUG) { System.err.println(i+":"+j+" MC1.0: "+counter+" - regain focus"); } requestFocus(null, obj); } - final int c0 = counter.getCount(); + final int c0 = null != counter ? counter.getCount() : 0; if(DEBUG) { System.err.println(i+":"+j+" MC1.1: "+counter); } robot.waitForIdle(); robot.mousePress(mouseButton); robot.mouseRelease(mouseButton); if(DEBUG) { System.err.println(i+":"+j+" MC1.2: "+counter); } - tc = counter.getCount() - c0; + tc = ( null != counter ? counter.getCount() : 1 ) - c0; for (int wait=0; wait<POLL_DIVIDER && 1 > tc; wait++) { robot.delay(TIME_SLICE); tc = counter.getCount() - c0; diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java new file mode 100644 index 000000000..16aacd2fd --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTWindowFocusAdapter.java @@ -0,0 +1,71 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.opengl.test.junit.util; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +public class AWTWindowFocusAdapter implements FocusEventCountAdapter, WindowFocusListener { + + String prefix; + int focusCount; + + public AWTWindowFocusAdapter(String prefix) { + this.prefix = prefix; + reset(); + } + + public boolean focusLost() { + return focusCount<0; + } + + public boolean focusGained() { + return focusCount>0; + } + + public void reset() { + focusCount = 0; + } + + /* @Override */ + public void windowGainedFocus(WindowEvent e) { + if(focusCount<0) { focusCount=0; } + focusCount++; + System.err.println("FOCUS AWT GAINED (Window) [fc "+focusCount+"]: "+prefix+", "+e); + } + + /* @Override */ + public void windowLostFocus(WindowEvent e) { + if(focusCount>0) { focusCount=0; } + focusCount--; + System.err.println("FOCUS AWT LOST (Window) [fc "+focusCount+"]: "+prefix+", "+e); + } + + public String toString() { return prefix+"[focusCount "+focusCount +"]"; } +} diff --git a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java index 6a6cf390f..c74d2eaa7 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java +++ b/src/test/com/jogamp/opengl/test/junit/util/NEWTGLContext.java @@ -78,6 +78,7 @@ public class NEWTGLContext { Assert.assertNotNull(drawable); drawable.setRealized(true); + Assert.assertTrue(drawable.isRealized()); GLContext context = drawable.createContext(null); Assert.assertNotNull(context); diff --git a/src/test/jogamp/newt/WindowImplAccess.java b/src/test/jogamp/newt/WindowImplAccess.java index 76d0dc050..e8be5f68a 100644 --- a/src/test/jogamp/newt/WindowImplAccess.java +++ b/src/test/jogamp/newt/WindowImplAccess.java @@ -29,26 +29,16 @@ package jogamp.newt; import com.jogamp.newt.Window; -import com.jogamp.newt.opengl.GLWindow; /** * Allows access to protected methods of WindowImpl */ public class WindowImplAccess { public static final void windowDestroyNotify(Window win) { - WindowImpl winImpl = null; - if(win instanceof GLWindow) { - GLWindow glwin = (GLWindow) win; - winImpl = (WindowImpl) glwin.getWindow(); - } else if(win instanceof WindowImpl) { - winImpl = (WindowImpl) win; - } else { - throw new RuntimeException("Given Window not a GLWindow, not WindowImpl, but "+win.getClass()); - } - final WindowImpl winImplF = winImpl; - winImplF.runOnEDTIfAvail(true, new Runnable() { + final WindowImpl winImpl = (WindowImpl) win.getDelegatedWindow(); + winImpl.runOnEDTIfAvail(true, new Runnable() { public void run() { - winImplF.windowDestroyNotify(); + winImpl.windowDestroyNotify(); } }); } diff --git a/src/test/native/displayMultiple02.c b/src/test/native/displayMultiple02.c index 1bfe95b95..df6666aff 100644 --- a/src/test/native/displayMultiple02.c +++ b/src/test/native/displayMultiple02.c @@ -11,7 +11,21 @@ static void testOrder(int reverseDestroyOrder, const char * msg); +static int useXLockDisplay = 0; + int main(int nargs, char **vargs) { + int arg=1; + while(arg<nargs) { + if(0 == strcmp(vargs[arg], "-xlock")) { + useXLockDisplay = 1; + } + arg++; + } + fprintf(stderr, "-xlock (XLockDisplay): %d\n", useXLockDisplay); + + if( useXLockDisplay ) { + XInitThreads(); + } testOrder(0, "Normal order"); testOrder(1, "Reverse order"); return 0; @@ -20,6 +34,17 @@ int main(int nargs, char **vargs) { static void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx); static void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height); +static void XLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XLockDisplay(dpy); + } +} +static void XUNLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XUnlockDisplay(dpy); + } +} + void testOrder(int reverseDestroyOrder, const char * msg) { int major, minor; Display *disp1; @@ -32,35 +57,58 @@ void testOrder(int reverseDestroyOrder, const char * msg) { fprintf(stderr, "%s: Create #1\n", msg); disp1 = XOpenDisplay(NULL); - createGLWin(disp1, 200, 200, &win1, &ctx1); - useGL(disp1, win1, ctx1, 200, 200); + XLOCKDISPLAY(disp1); + createGLWin(disp1, 200, 200, &win1, &ctx1); + useGL(disp1, win1, ctx1, 200, 200); + XUNLOCKDISPLAY(disp1); fprintf(stderr, "%s: Create #2\n", msg); disp2 = XOpenDisplay(NULL); - createGLWin(disp2, 300, 300, &win2, &ctx2); - useGL(disp2, win2, ctx2, 300, 300); + XLOCKDISPLAY(disp2); + createGLWin(disp2, 300, 300, &win2, &ctx2); + useGL(disp2, win2, ctx2, 300, 300); + XUNLOCKDISPLAY(disp2); if(reverseDestroyOrder) { - fprintf(stderr, "%s: Destroy #2\n", msg); - glXMakeCurrent(disp2, 0, 0); - glXDestroyContext(disp2, ctx2); + fprintf(stderr, "%s: Destroy #2.0\n", msg); + XLOCKDISPLAY(disp2); + glXMakeCurrent(disp2, 0, 0); + glXDestroyContext(disp2, ctx2); + XUNLOCKDISPLAY(disp2); XCloseDisplay(disp2); - - fprintf(stderr, "%s: Destroy #1\n", msg); - glXMakeCurrent(disp1, 0, 0); - glXDestroyContext(disp1, ctx1); + fprintf(stderr, "%s: Destroy #2.X\n", msg); + + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.1\n", msg); + glXMakeCurrent(disp1, 0, 0); + fprintf(stderr, "%s: Destroy #1.2\n", msg); + glXDestroyContext(disp1, ctx1); + fprintf(stderr, "%s: Destroy #1.3\n", msg); + XUNLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.4\n", msg); XCloseDisplay(disp1); + fprintf(stderr, "%s: Destroy #1.X\n", msg); } else { - fprintf(stderr, "%s: Destroy #1\n", msg); - glXMakeCurrent(disp1, 0, 0); - glXDestroyContext(disp1, ctx1); + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + glXMakeCurrent(disp1, 0, 0); + glXDestroyContext(disp1, ctx1); + XUNLOCKDISPLAY(disp1); XCloseDisplay(disp1); - - fprintf(stderr, "%s: Destroy #2\n", msg); - glXMakeCurrent(disp2, 0, 0); - glXDestroyContext(disp2, ctx2); + fprintf(stderr, "%s: Destroy #1.X\n", msg); + + fprintf(stderr, "%s: Destroy #2.0\n", msg); + XLOCKDISPLAY(disp2); + fprintf(stderr, "%s: Destroy #2.1\n", msg); + glXMakeCurrent(disp2, 0, 0); + fprintf(stderr, "%s: Destroy #2.2\n", msg); + glXDestroyContext(disp2, ctx2); + fprintf(stderr, "%s: Destroy #2.3\n", msg); + XUNLOCKDISPLAY(disp2); + fprintf(stderr, "%s: Destroy #2.4\n", msg); XCloseDisplay(disp2); - + fprintf(stderr, "%s: Destroy #2.X\n", msg); } fprintf(stderr, "%s: Success - no bug\n", msg); |